diff --git a/db/changes/231601/00-aclClientInforma.sql b/db/changes/231601/00-aclClientInforma.sql
new file mode 100644
index 000000000..6222d2632
--- /dev/null
+++ b/db/changes/231601/00-aclClientInforma.sql
@@ -0,0 +1,3 @@
+INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
+VALUES ('ClientInforma', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
+ ('ClientInforma', '*', 'WRITE', 'ALLOW', 'ROLE', 'financial');
diff --git a/db/changes/231601/00-clientInforma.sql b/db/changes/231601/00-clientInforma.sql
new file mode 100644
index 000000000..9bf757fc3
--- /dev/null
+++ b/db/changes/231601/00-clientInforma.sql
@@ -0,0 +1,16 @@
+ALTER TABLE `vn`.`client` ADD rating INT UNSIGNED DEFAULT NULL NULL COMMENT 'información proporcionada por Informa';
+ALTER TABLE `vn`.`client` ADD recommendedCredit INT UNSIGNED DEFAULT NULL NULL COMMENT 'información proporcionada por Informa';
+
+CREATE TABLE `vn`.`clientInforma` (
+ `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+ `clientFk` int(11) NOT NULL,
+ `rating` int(10) unsigned DEFAULT NULL,
+ `recommendedCredit` int(10) unsigned DEFAULT NULL,
+ `workerFk` int(10) unsigned NOT NULL,
+ `created` timestamp NOT NULL DEFAULT current_timestamp(),
+ PRIMARY KEY (`id`),
+ KEY `informaWorkers_fk_idx` (`workerFk`),
+ KEY `informaClientFk` (`clientFk`),
+ CONSTRAINT `informa_ClienteFk` FOREIGN KEY (`clientFk`) REFERENCES `client` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT `informa_workers_fk` FOREIGN KEY (`workerFk`) REFERENCES `worker` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
+) ENGINE=InnoDB CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci COMMENT='información proporcionada por Informa, se actualiza desde el hook de client (salix)';
diff --git a/db/changes/231601/00-client_setRatingAcl.sql b/db/changes/231601/00-client_setRatingAcl.sql
new file mode 100644
index 000000000..b041b131a
--- /dev/null
+++ b/db/changes/231601/00-client_setRatingAcl.sql
@@ -0,0 +1,64 @@
+DELETE FROM `salix`.`ACL` WHERE id=7;
+
+INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
+ VALUES
+ ('Client', 'setRating', 'WRITE', 'ALLOW', 'ROLE', 'financial');
+
+INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
+ VALUES
+ ('Client', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'addressesPropagateRe', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'canBeInvoiced', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'canCreateTicket', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'consumption', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'createAddress', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'createWithUser', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'extendedListFilter', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'getAverageInvoiced', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'getCard', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'getDebt', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'getMana', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'transactions', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'hasCustomerRole', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'isValidClient', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'lastActiveTickets', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'sendSms', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'setPassword', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'summary', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'updateAddress', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'updateFiscalData', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'updateUser', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'uploadFile', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'campaignMetricsPdf', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'campaignMetricsEmail', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'clientWelcomeHtml', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'clientWelcomeEmail', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'printerSetupHtml', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'printerSetupEmail', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'sepaCoreEmail', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'letterDebtorPdf', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'letterDebtorStHtml', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'letterDebtorStEmail', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'letterDebtorNdHtml', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'letterDebtorNdEmail', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'clientDebtStatementPdf', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'clientDebtStatementHtml', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'clientDebtStatementEmail', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'creditRequestPdf', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'creditRequestHtml', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'creditRequestEmail', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'incotermsAuthorizationPdf', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'incotermsAuthorizationHtml', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'incotermsAuthorizationEmail', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'consumptionSendQueued', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'filter', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'getClientOrSupplierReference', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'upsert', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'create', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'replaceById', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'updateAttributes', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'updateAttributes', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'deleteById', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'replaceOrCreate', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'updateAll', '*', 'ALLOW', 'ROLE', 'employee'),
+ ('Client', 'upsertWithWhere', '*', 'ALLOW', 'ROLE', 'employee');
diff --git a/e2e/helpers/extensions.js b/e2e/helpers/extensions.js
index 7d80c69ee..1fcbfd616 100644
--- a/e2e/helpers/extensions.js
+++ b/e2e/helpers/extensions.js
@@ -156,14 +156,14 @@ let actions = {
await this.waitForSpinnerLoad();
},
- accessToSection: async function(state) {
+ accessToSection: async function(state, name = 'Others') {
await this.waitForSelector('vn-left-menu');
let nested = await this.evaluate(state => {
return document.querySelector(`vn-left-menu li li > a[ui-sref="${state}"]`) != null;
}, state);
if (nested) {
- let selector = 'vn-left-menu vn-item-section > vn-icon[icon=keyboard_arrow_down]';
+ let selector = `vn-left-menu li[name="${name}"]`;
await this.evaluate(selector => {
document.querySelector(selector).scrollIntoViewIfNeeded();
}, selector);
diff --git a/modules/client/back/methods/client/setRating.js b/modules/client/back/methods/client/setRating.js
new file mode 100644
index 000000000..21ac0c914
--- /dev/null
+++ b/modules/client/back/methods/client/setRating.js
@@ -0,0 +1,55 @@
+module.exports = Self => {
+ Self.remoteMethodCtx('setRating', {
+ description: 'Change rating and recommendedCredit of a client',
+ accessType: 'WRITE',
+ accepts: [
+ {
+ arg: 'id',
+ type: 'number',
+ required: true,
+ description: 'The user id',
+ http: {source: 'path'}
+ },
+ {
+ arg: 'rating',
+ type: 'number'
+ },
+ {
+ arg: 'recommendedCredit',
+ type: 'number'
+ }
+ ],
+ http: {
+ path: `/:id/setRating`,
+ verb: 'POST'
+ }
+ });
+
+ Self.setRating = async function(ctx, id, rating, recommendedCredit, options) {
+ let tx;
+ const myOptions = {};
+
+ if (typeof options == 'object')
+ Object.assign(myOptions, options);
+
+ if (!myOptions.transaction) {
+ tx = await Self.beginTransaction({});
+ myOptions.transaction = tx;
+ }
+
+ try {
+ const client = await Self.findById(id, null, myOptions);
+ const clientUpdated = await client.updateAttributes({
+ rating: rating,
+ recommendedCredit: recommendedCredit
+ }, myOptions);
+
+ if (tx) await tx.commit();
+
+ return clientUpdated;
+ } catch (e) {
+ if (tx) await tx.rollback();
+ throw e;
+ }
+ };
+};
diff --git a/modules/client/back/methods/client/specs/setRating.spec.js b/modules/client/back/methods/client/specs/setRating.spec.js
new file mode 100644
index 000000000..a7d0fb03a
--- /dev/null
+++ b/modules/client/back/methods/client/specs/setRating.spec.js
@@ -0,0 +1,43 @@
+const models = require('vn-loopback/server/server').models;
+const LoopBackContext = require('loopback-context');
+
+describe('Client setRating()', () => {
+ const financialId = 73;
+ const activeCtx = {
+ accessToken: {userId: financialId},
+ http: {
+ req: {
+ headers: {origin: 'http://localhost'}
+ }
+ }
+ };
+ const ctx = {req: activeCtx};
+
+ beforeAll(async() => {
+ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
+ active: activeCtx
+ });
+ });
+
+ it('should change rating and recommendedCredit', async() => {
+ const tx = await models.Ticket.beginTransaction({});
+
+ try {
+ const options = {transaction: tx};
+
+ const clientId = 1101;
+ const newRating = 10;
+ const newRecommendedCredit = 20;
+
+ const updatedClient = await models.Client.setRating(ctx, clientId, newRating, newRecommendedCredit, options);
+
+ expect(updatedClient.rating).toEqual(newRating);
+ expect(updatedClient.recommendedCredit).toEqual(newRecommendedCredit);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
+ });
+});
diff --git a/modules/client/back/model-config.json b/modules/client/back/model-config.json
index b466aa5a1..1e06ea1c0 100644
--- a/modules/client/back/model-config.json
+++ b/modules/client/back/model-config.json
@@ -32,6 +32,9 @@
"ClientConsumptionQueue": {
"dataSource": "vn"
},
+ "ClientInforma": {
+ "dataSource": "vn"
+ },
"ClientLog": {
"dataSource": "vn"
},
diff --git a/modules/client/back/models/client-informa.json b/modules/client/back/models/client-informa.json
new file mode 100644
index 000000000..0c652484e
--- /dev/null
+++ b/modules/client/back/models/client-informa.json
@@ -0,0 +1,42 @@
+{
+ "name": "ClientInforma",
+ "base": "Loggable",
+ "log": {
+ "model":"ClientLog",
+ "relation": "client",
+ "showField": "clientFk"
+ },
+ "options": {
+ "mysql": {
+ "table": "clientInforma"
+ }
+ },
+ "properties": {
+ "id": {
+ "type": "number",
+ "id": true,
+ "description": "Identifier"
+ },
+ "rating": {
+ "type": "number"
+ },
+ "recommendedCredit": {
+ "type": "number"
+ },
+ "created": {
+ "type": "date"
+ }
+ },
+ "relations": {
+ "worker": {
+ "type": "belongsTo",
+ "model": "Worker",
+ "foreignKey": "workerFk"
+ },
+ "client": {
+ "type": "belongsTo",
+ "model": "Client",
+ "foreignKey": "clientFk"
+ }
+ }
+}
diff --git a/modules/client/back/models/client-methods.js b/modules/client/back/models/client-methods.js
index 3538dbeb8..3b1a588ac 100644
--- a/modules/client/back/models/client-methods.js
+++ b/modules/client/back/models/client-methods.js
@@ -47,4 +47,5 @@ module.exports = Self => {
require('../methods/client/consumptionSendQueued')(Self);
require('../methods/client/filter')(Self);
require('../methods/client/getClientOrSupplierReference')(Self);
+ require('../methods/client/setRating')(Self);
};
diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js
index 7933f2f42..a86a782e4 100644
--- a/modules/client/back/models/client.js
+++ b/modules/client/back/models/client.js
@@ -280,6 +280,10 @@ module.exports = Self => {
if (changes.credit !== undefined)
await Self.changeCredit(ctx, finalState, changes);
+ // Credit management changes
+ if (orgData?.rating != changes.rating || orgData?.recommendedCredit != changes.recommendedCredit)
+ await Self.changeCreditManagement(ctx, finalState, changes);
+
const oldInstance = {};
if (!ctx.isNewInstance) {
const newProps = Object.keys(changes);
@@ -441,6 +445,19 @@ module.exports = Self => {
}, ctx.options);
};
+ Self.changeCreditManagement = async function changeCreditManagement(ctx, finalState, changes) {
+ const models = Self.app.models;
+ const loopBackContext = LoopBackContext.getCurrentContext();
+ const userId = loopBackContext.active.accessToken.userId;
+
+ await models.ClientInforma.create({
+ clientFk: finalState.id,
+ rating: changes.rating,
+ recommendedCredit: changes.recommendedCredit,
+ workerFk: userId
+ }, ctx.options);
+ };
+
const app = require('vn-loopback/server/server');
app.on('started', function() {
const VnUser = app.models.VnUser;
diff --git a/modules/client/back/models/client.json b/modules/client/back/models/client.json
index e8ce12453..5f56a1ed2 100644
--- a/modules/client/back/models/client.json
+++ b/modules/client/back/models/client.json
@@ -141,6 +141,12 @@
},
"hasElectronicInvoice": {
"type": "boolean"
+ },
+ "rating": {
+ "type": "number"
+ },
+ "recommendedCredit": {
+ "type": "number"
}
},
diff --git a/modules/client/front/credit-management/index.html b/modules/client/front/credit-management/index.html
new file mode 100644
index 000000000..d7456fd06
--- /dev/null
+++ b/modules/client/front/credit-management/index.html
@@ -0,0 +1,79 @@
+