From 549235429c06bfb12cd7fa9a67f7b91baa2da00e Mon Sep 17 00:00:00 2001 From: carlossa Date: Tue, 27 Jun 2023 07:18:36 +0200 Subject: [PATCH 01/32] refs #5640 oldBranch --- e2e/paths/02-client/03_edit_fiscal_data.spec.js | 4 ++-- e2e/paths/02-client/12_lock_of_verified_data.spec.js | 6 +++--- modules/client/front/fiscal-data/index.html | 2 ++ modules/client/front/fiscal-data/index.js | 6 ++++++ 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/e2e/paths/02-client/03_edit_fiscal_data.spec.js b/e2e/paths/02-client/03_edit_fiscal_data.spec.js index 0babb5396..9098e816f 100644 --- a/e2e/paths/02-client/03_edit_fiscal_data.spec.js +++ b/e2e/paths/02-client/03_edit_fiscal_data.spec.js @@ -61,7 +61,7 @@ describe('Client Edit fiscalData path', () => { await page.clearInput(selectors.clientFiscalData.fiscalId); await page.write(selectors.clientFiscalData.fiscalId, 'INVALID!'); await page.clearInput(selectors.clientFiscalData.address); - await page.write(selectors.clientFiscalData.address, 'Somewhere edited'); + await page.write(selectors.clientFiscalData.address, 'SOMEWHERE EDITED'); await page.autocompleteSearch(selectors.clientFiscalData.country, 'España'); await page.autocompleteSearch(selectors.clientFiscalData.province, 'Province one'); await page.clearInput(selectors.clientFiscalData.city); @@ -190,7 +190,7 @@ describe('Client Edit fiscalData path', () => { const verifiedData = await page.checkboxState(selectors.clientFiscalData.verifiedDataCheckbox); expect(fiscalId).toEqual('94980061C'); - expect(address).toEqual('Somewhere edited'); + expect(address).toEqual('SOMEWHERE EDITED'); expect(postcode).toContain('46000'); expect(sageTax).toEqual('Operaciones no sujetas'); expect(sageTransaction).toEqual('Regularización de inversiones'); diff --git a/e2e/paths/02-client/12_lock_of_verified_data.spec.js b/e2e/paths/02-client/12_lock_of_verified_data.spec.js index 139af0cea..7abe15460 100644 --- a/e2e/paths/02-client/12_lock_of_verified_data.spec.js +++ b/e2e/paths/02-client/12_lock_of_verified_data.spec.js @@ -39,7 +39,7 @@ describe('Client lock verified data path', () => { await page.reloadSection('client.card.fiscalData'); const result = await page.waitToGetProperty(selectors.clientFiscalData.socialName, 'value'); - expect(result).toEqual('Captain America Civil War'); + expect(result).toEqual('CAPTAIN AMERICA CIVIL WAR'); }); }); @@ -88,7 +88,7 @@ describe('Client lock verified data path', () => { await page.reloadSection('client.card.fiscalData'); const result = await page.waitToGetProperty(selectors.clientFiscalData.socialName, 'value'); - expect(result).toEqual('Ant man and the Wasp'); + expect(result).toEqual('ANT MAN AND THE WASP'); }); }); @@ -142,7 +142,7 @@ describe('Client lock verified data path', () => { await page.reloadSection('client.card.fiscalData'); const result = await page.waitToGetProperty(selectors.clientFiscalData.socialName, 'value'); - expect(result).toEqual('new social name edition'); + expect(result).toEqual('NEW SOCIAL NAME EDITION'); }); }); diff --git a/modules/client/front/fiscal-data/index.html b/modules/client/front/fiscal-data/index.html index d232d6dab..4d001e226 100644 --- a/modules/client/front/fiscal-data/index.html +++ b/modules/client/front/fiscal-data/index.html @@ -33,6 +33,7 @@ ng-model="$ctrl.client.socialName" info="Only letters, numbers and spaces can be used" required="true" + ng-keyup="$ctrl.mayus($event)" rule> diff --git a/modules/client/front/fiscal-data/index.js b/modules/client/front/fiscal-data/index.js index acad38185..1599c917b 100644 --- a/modules/client/front/fiscal-data/index.js +++ b/modules/client/front/fiscal-data/index.js @@ -177,6 +177,12 @@ export default class Controller extends Section { this.client.provinceFk = response.provinceFk; this.client.countryFk = response.countryFk; } + + mayus(event) { + let input = event.target; + let inputValue = input.value; + input.value = inputValue.toUpperCase(); + } } ngModule.vnComponent('vnClientFiscalData', { From d03df4c5ccd1821c9576ba8f708e4c3b1e4bad18 Mon Sep 17 00:00:00 2001 From: carlossa Date: Mon, 3 Jul 2023 11:38:38 +0200 Subject: [PATCH 02/32] refs #5690 ticketproblems --- modules/ticket/back/methods/ticket/filter.js | 3 ++- modules/ticket/back/methods/ticket/getTicketsFuture.js | 3 ++- modules/ticket/front/future/index.html | 5 +++++ modules/ticket/front/index/index.html | 5 +++++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/modules/ticket/back/methods/ticket/filter.js b/modules/ticket/back/methods/ticket/filter.js index 262b3fd74..ea77b7677 100644 --- a/modules/ticket/back/methods/ticket/filter.js +++ b/modules/ticket/back/methods/ticket/filter.js @@ -339,7 +339,8 @@ module.exports = Self => { {'tp.isFreezed': hasProblem}, {'tp.risk': hasProblem}, {'tp.hasTicketRequest': hasProblem}, - {'tp.itemShortage': range} + {'tp.itemShortage': range}, + {'tp.hasRounding': hasProblem} ]}; if (hasWhere) diff --git a/modules/ticket/back/methods/ticket/getTicketsFuture.js b/modules/ticket/back/methods/ticket/getTicketsFuture.js index 901e546f7..fa24cc379 100644 --- a/modules/ticket/back/methods/ticket/getTicketsFuture.js +++ b/modules/ticket/back/methods/ticket/getTicketsFuture.js @@ -194,7 +194,8 @@ module.exports = Self => { {'tp.hasTicketRequest': hasProblem}, {'tp.itemShortage': range}, {'tp.hasComponentLack': hasProblem}, - {'tp.isTooLittle': hasProblem} + {'tp.isTooLittle': hasProblem}, + {'tp.hasRounding': hasProblem} ] }; diff --git a/modules/ticket/front/future/index.html b/modules/ticket/front/future/index.html index 78b0f9864..742143b27 100644 --- a/modules/ticket/front/future/index.html +++ b/modules/ticket/front/future/index.html @@ -123,6 +123,11 @@ class="bright" icon="icon-components"> + + + + {{::ticket.id}} From 87f125453d976fbaf9382f0f3a6aaaf484660b35 Mon Sep 17 00:00:00 2001 From: carlossa Date: Fri, 14 Jul 2023 13:35:13 +0200 Subject: [PATCH 03/32] refs #5640 fix mayus quit function --- loopback/locale/es.json | 6 ++++-- modules/client/back/models/client.js | 14 ++++++++++++++ modules/client/front/fiscal-data/index.html | 4 ++-- modules/client/front/fiscal-data/index.js | 6 ------ 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 784ff5e6e..55a7e2f82 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -305,5 +305,7 @@ "The renew period has not been exceeded": "El periodo de renovación no ha sido superado", "Valid priorities": "Prioridades válidas: %d", "Negative basis of tickets": "Base negativa para los tickets: {{ticketsIds}}", - "You cannot assign an alias that you are not assigned to": "No puede asignar un alias que no tenga asignado" -} + "You cannot assign an alias that you are not assigned to": "No puede asignar un alias que no tenga asignado", + "Social name should be uppercase": "Social name should be uppercase", + "Street should be uppercase": "Street should be uppercase" +} \ No newline at end of file diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js index ca279ef71..9302d81c7 100644 --- a/modules/client/back/models/client.js +++ b/modules/client/back/models/client.js @@ -36,6 +36,20 @@ module.exports = Self => { min: 3, max: 10 }); + Self.validatesFormatOf('street', { + message: 'Street should be uppercase', + allowNull: false, + allowBlank: false, + with: /^[^a-z]*$/ + }); + + Self.validatesFormatOf('socialName', { + message: 'Social name should be uppercase', + allowNull: false, + allowBlank: false, + with: /^[^a-z]*$/ + }); + Self.validateAsync('socialName', socialNameIsUnique, { message: 'The company name must be unique' }); diff --git a/modules/client/front/fiscal-data/index.html b/modules/client/front/fiscal-data/index.html index 4d001e226..d1de87309 100644 --- a/modules/client/front/fiscal-data/index.html +++ b/modules/client/front/fiscal-data/index.html @@ -33,7 +33,7 @@ ng-model="$ctrl.client.socialName" info="Only letters, numbers and spaces can be used" required="true" - ng-keyup="$ctrl.mayus($event)" + ng-keyup="$ctrl.client.socialName = $ctrl.client.socialName.toUpperCase()" rule> diff --git a/modules/client/front/fiscal-data/index.js b/modules/client/front/fiscal-data/index.js index 1599c917b..acad38185 100644 --- a/modules/client/front/fiscal-data/index.js +++ b/modules/client/front/fiscal-data/index.js @@ -177,12 +177,6 @@ export default class Controller extends Section { this.client.provinceFk = response.provinceFk; this.client.countryFk = response.countryFk; } - - mayus(event) { - let input = event.target; - let inputValue = input.value; - input.value = inputValue.toUpperCase(); - } } ngModule.vnComponent('vnClientFiscalData', { From b113052b5c631d1582160deb71f0e6d8388bc81e Mon Sep 17 00:00:00 2001 From: carlossa Date: Fri, 14 Jul 2023 13:48:36 +0200 Subject: [PATCH 04/32] refs #5640 fixtures and test fix --- db/dump/fixtures.sql | 4 ++-- e2e/paths/03-worker/06_create.spec.js | 2 +- .../client/back/methods/client/specs/createWithUser.spec.js | 4 ++-- modules/worker/back/methods/worker/specs/new.spec.js | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index fe11d5b64..2e3122c89 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -360,8 +360,8 @@ INSERT INTO `vn`.`contactChannel`(`id`, `name`) INSERT INTO `vn`.`client`(`id`,`name`,`fi`,`socialName`,`contact`,`street`,`city`,`postcode`,`phone`,`mobile`,`isRelevant`,`email`,`iban`,`dueDay`,`accountingAccount`,`isEqualizated`,`provinceFk`,`hasToInvoice`,`credit`,`countryFk`,`isActive`,`gestdocFk`,`quality`,`payMethodFk`,`created`,`isToBeMailed`,`contactChannelFk`,`hasSepaVnl`,`hasCoreVnl`,`hasCoreVnh`,`riskCalculated`,`clientTypeFk`, `hasToInvoiceByAddress`,`isTaxDataChecked`,`isFreezed`,`creditInsurance`,`isCreatedAsServed`,`hasInvoiceSimplified`,`salesPersonFk`,`isVies`,`eypbc`, `businessTypeFk`) VALUES - (1101, 'Bruce Wayne', '84612325V', 'Batman', 'Alfred', '1007 Mountain Drive, Gotham', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'), - (1102, 'Petter Parker', '87945234L', 'Spider man', 'Aunt May', '20 Ingram Street, Queens, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'), + (1101, 'Bruce Wayne', '84612325V', 'BATMAN', 'Alfred', '1007 MOUNTAIN DRIVE, GOTHAM', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'), + (1102, 'Petter Parker', '87945234L', 'SPIDER MAN', 'Aunt May', '20 INGRAM STREET, QUEENS, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'), (1103, 'Clark Kent', '06815934E', 'Super man', 'lois lane', '344 Clinton Street, Apartament 3-D', 'Gotham', 46460, 1111111111, 222222222, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 0, 19, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'), (1104, 'Tony Stark', '06089160W', 'Iron man', 'Pepper Potts', '10880 Malibu Point, 90265', 'Gotham', 46460, 1111111111, 222222222, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'), (1105, 'Max Eisenhardt', '251628698', 'Magneto', 'Rogue', 'Unknown Whereabouts', 'Gotham', 46460, 1111111111, 222222222, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 300, 8, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, NULL, 0, 0, 18, 0, 1, 'florist'), diff --git a/e2e/paths/03-worker/06_create.spec.js b/e2e/paths/03-worker/06_create.spec.js index 11d36b3cf..07eb57fe4 100644 --- a/e2e/paths/03-worker/06_create.spec.js +++ b/e2e/paths/03-worker/06_create.spec.js @@ -23,7 +23,7 @@ describe('Worker create path', () => { await page.write(selectors.workerCreate.fi, '78457139E'); await page.write(selectors.workerCreate.phone, '12356789'); await page.write(selectors.workerCreate.postcode, '46680'); - await page.write(selectors.workerCreate.street, 'S/ Doomstadt'); + await page.write(selectors.workerCreate.street, 'S/ DOOMSTADT'); await page.write(selectors.workerCreate.email, 'doctorDoom@marvel.com'); await page.write(selectors.workerCreate.iban, 'ES9121000418450200051332'); diff --git a/modules/client/back/methods/client/specs/createWithUser.spec.js b/modules/client/back/methods/client/specs/createWithUser.spec.js index 69440c1d1..03106acc1 100644 --- a/modules/client/back/methods/client/specs/createWithUser.spec.js +++ b/modules/client/back/methods/client/specs/createWithUser.spec.js @@ -7,8 +7,8 @@ describe('Client Create', () => { email: 'Deadpool@marvel.com', fi: '16195279J', name: 'Wade', - socialName: 'Deadpool Marvel', - street: 'Wall Street', + socialName: 'DEADPOOL MARVEL', + street: 'WALL STREET', city: 'New York', businessTypeFk: 'florist', provinceFk: 1 diff --git a/modules/worker/back/methods/worker/specs/new.spec.js b/modules/worker/back/methods/worker/specs/new.spec.js index b2804c203..1c41d666b 100644 --- a/modules/worker/back/methods/worker/specs/new.spec.js +++ b/modules/worker/back/methods/worker/specs/new.spec.js @@ -24,7 +24,7 @@ describe('Worker new', () => { firstName: 'default', lastNames: 'worker', email: 'defaultWorker@mydomain.com', - street: 'S/ defaultWorkerStreet', + street: 'S/ DEFAULTWORKERSTREET', city: 'defaultWorkerCity', provinceFk: 1, companyFk: 442, From 6f3cdd3508566050b73c691f29edd92e951b62a7 Mon Sep 17 00:00:00 2001 From: carlossa Date: Mon, 17 Jul 2023 12:30:48 +0200 Subject: [PATCH 05/32] refs #5640 fix e2e back --- db/dump/fixtures.sql | 4 ++-- e2e/paths/02-client/01_create_client.spec.js | 4 ++-- e2e/paths/02-client/12_lock_of_verified_data.spec.js | 2 +- e2e/paths/02-client/19_summary.spec.js | 2 +- loopback/locale/en.json | 6 ++++-- modules/worker/back/methods/worker/specs/new.spec.js | 2 +- 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 2e3122c89..b1e7888a8 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -365,8 +365,8 @@ INSERT INTO `vn`.`client`(`id`,`name`,`fi`,`socialName`,`contact`,`street`,`city (1103, 'Clark Kent', '06815934E', 'Super man', 'lois lane', '344 Clinton Street, Apartament 3-D', 'Gotham', 46460, 1111111111, 222222222, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 0, 19, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'), (1104, 'Tony Stark', '06089160W', 'Iron man', 'Pepper Potts', '10880 Malibu Point, 90265', 'Gotham', 46460, 1111111111, 222222222, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'), (1105, 'Max Eisenhardt', '251628698', 'Magneto', 'Rogue', 'Unknown Whereabouts', 'Gotham', 46460, 1111111111, 222222222, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 300, 8, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, NULL, 0, 0, 18, 0, 1, 'florist'), - (1106, 'DavidCharlesHaller', '53136686Q', 'Legion', 'Charles Xavier', 'City of New York, New York, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 19, 0, 1, 'florist'), - (1107, 'Hank Pym', '09854837G', 'Ant man', 'Hawk', 'Anthill, San Francisco, California', 'Gotham', 46460, 1111111111, 222222222, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1, 'florist'), + (1106, 'DavidCharlesHaller', '53136686Q', 'LEGION', 'Charles Xavier', 'CITY OF NEW YORK, NEW YORK, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 19, 0, 1, 'florist'), + (1107, 'Hank Pym', '09854837G', 'ANT MAN', 'Hawk', 'ANTHILL, SAN FRANCISCO, CALIFORNIA', 'Gotham', 46460, 1111111111, 222222222, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1, 'florist'), (1108, 'Charles Xavier', '22641921P', 'Professor X', 'Beast', '3800 Victory Pkwy, Cincinnati, OH 45207, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'CharlesXavier@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, NULL, 0, 0, 19, 0, 1, 'florist'), (1109, 'Bruce Banner', '16104829E', 'Hulk', 'Black widow', 'Somewhere in New York', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceBanner@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, 0, NULL, 0, 0, 9, 0, 1, 'florist'), (1110, 'Jessica Jones', '58282869H', 'Jessica Jones', 'Luke Cage', 'NYCC 2015 Poster', 'Gotham', 46460, 1111111111, 222222222, 1, 'JessicaJones@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, 0, NULL, 0, 0, NULL, 0, 1, 'florist'), diff --git a/e2e/paths/02-client/01_create_client.spec.js b/e2e/paths/02-client/01_create_client.spec.js index ff2aac6b9..3274ae8f1 100644 --- a/e2e/paths/02-client/01_create_client.spec.js +++ b/e2e/paths/02-client/01_create_client.spec.js @@ -73,8 +73,8 @@ describe('Client create path', () => { it(`should attempt to create a new user with all it's data but wrong email`, async() => { await page.write(selectors.createClientView.name, 'Carol Danvers'); - await page.write(selectors.createClientView.socialName, 'AVG tax'); - await page.write(selectors.createClientView.street, 'Many places'); + await page.write(selectors.createClientView.socialName, 'AVG TAX'); + await page.write(selectors.createClientView.street, 'MANY PLACES'); await page.clearInput(selectors.createClientView.email); await page.write(selectors.createClientView.email, 'incorrect email format'); await page.waitToClick(selectors.createClientView.createButton); diff --git a/e2e/paths/02-client/12_lock_of_verified_data.spec.js b/e2e/paths/02-client/12_lock_of_verified_data.spec.js index 7abe15460..2d7ab7541 100644 --- a/e2e/paths/02-client/12_lock_of_verified_data.spec.js +++ b/e2e/paths/02-client/12_lock_of_verified_data.spec.js @@ -28,7 +28,7 @@ describe('Client lock verified data path', () => { it('should edit the social name', async() => { await page.waitForSelector(selectors.clientFiscalData.socialName); await page.clearInput(selectors.clientFiscalData.socialName); - await page.write(selectors.clientFiscalData.socialName, 'Captain America Civil War'); + await page.write(selectors.clientFiscalData.socialName, 'CAPTAIN AMERICA CIVIL WAR'); await page.waitToClick(selectors.clientFiscalData.saveButton); const message = await page.waitForSnackbar(); diff --git a/e2e/paths/02-client/19_summary.spec.js b/e2e/paths/02-client/19_summary.spec.js index ab39154cf..b3bf43c5c 100644 --- a/e2e/paths/02-client/19_summary.spec.js +++ b/e2e/paths/02-client/19_summary.spec.js @@ -36,7 +36,7 @@ describe('Client summary path', () => { it('should display fiscal address details', async() => { const result = await page.waitToGetProperty(selectors.clientSummary.street, 'innerText'); - expect(result).toContain('20 Ingram Street'); + expect(result).toContain('20 INGRAM STREET'); }); it('should display some fiscal data', async() => { diff --git a/loopback/locale/en.json b/loopback/locale/en.json index 030afbe9e..6f1f72ffb 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -178,5 +178,7 @@ "The renew period has not been exceeded": "The renew period has not been exceeded", "You can not use the same password": "You can not use the same password", "Valid priorities": "Valid priorities: %d", - "Negative basis of tickets": "Negative basis of tickets: {{ticketsIds}}" -} + "Negative basis of tickets": "Negative basis of tickets: {{ticketsIds}}", + "Social name should be uppercase": "Social name should be uppercase", + "Street should be uppercase": "Street should be uppercase" +} \ No newline at end of file diff --git a/modules/worker/back/methods/worker/specs/new.spec.js b/modules/worker/back/methods/worker/specs/new.spec.js index 1c41d666b..4dc6c5540 100644 --- a/modules/worker/back/methods/worker/specs/new.spec.js +++ b/modules/worker/back/methods/worker/specs/new.spec.js @@ -20,7 +20,7 @@ describe('Worker new', () => { const employeeId = 1; const defaultWorker = { fi: '78457139E', - name: 'defaultWorker', + name: 'DEFAULTERWORKER', firstName: 'default', lastNames: 'worker', email: 'defaultWorker@mydomain.com', From d2120cdc3d772e49346a4855827b8ff102efbeee Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 17 Jul 2023 14:24:50 +0200 Subject: [PATCH 06/32] refs #5762 feat: multiplatform recover-password and change-password --- back/methods/vn-user/recover-password.js | 9 +++++++-- back/methods/vn-user/sign-in.js | 10 ++-------- back/models/vn-user.js | 11 +++++++---- front/salix/components/change-password/index.js | 14 +++----------- front/salix/components/login/index.js | 2 +- front/salix/routes.js | 2 +- .../back/methods/account/change-password.js | 13 +++++++------ .../methods/account/specs/change-password.spec.js | 14 +++++++------- 8 files changed, 35 insertions(+), 40 deletions(-) diff --git a/back/methods/vn-user/recover-password.js b/back/methods/vn-user/recover-password.js index b87bb14d4..b5d183ba3 100644 --- a/back/methods/vn-user/recover-password.js +++ b/back/methods/vn-user/recover-password.js @@ -7,6 +7,11 @@ module.exports = Self => { type: 'string', description: 'The user name or email', required: true + }, + { + arg: 'directory', + type: 'string', + description: 'The directory for mail' } ], http: { @@ -15,7 +20,7 @@ module.exports = Self => { } }); - Self.recoverPassword = async function(user) { + Self.recoverPassword = async function(user, directory) { const models = Self.app.models; const usesEmail = user.indexOf('@') !== -1; @@ -29,7 +34,7 @@ module.exports = Self => { } try { - await Self.resetPassword({email: user, emailTemplate: 'recover-password'}); + await Self.resetPassword({email: user, emailTemplate: 'recover-password', directory}); } catch (err) { if (err.code === 'EMAIL_NOT_FOUND') return; diff --git a/back/methods/vn-user/sign-in.js b/back/methods/vn-user/sign-in.js index 73cc705de..b9e0d2f70 100644 --- a/back/methods/vn-user/sign-in.js +++ b/back/methods/vn-user/sign-in.js @@ -53,19 +53,13 @@ module.exports = Self => { return Self.validateLogin(user, password); }; - Self.passExpired = async(vnUser, myOptions) => { + Self.passExpired = async vnUser => { const today = Date.vnNew(); today.setHours(0, 0, 0, 0); if (vnUser.passExpired && vnUser.passExpired.getTime() <= today.getTime()) { - const $ = Self.app.models; - const changePasswordToken = await $.AccessToken.create({ - scopes: ['changePassword'], - userId: vnUser.id - }, myOptions); const err = new UserError('Pass expired', 'passExpired'); - changePasswordToken.twoFactor = vnUser.twoFactor ? true : false; - err.details = {token: changePasswordToken}; + err.details = {userId: vnUser.id, twoFactor: vnUser.twoFactor ? true : false}; throw err; } }; diff --git a/back/models/vn-user.js b/back/models/vn-user.js index 11d4bf250..f47dc47e2 100644 --- a/back/models/vn-user.js +++ b/back/models/vn-user.js @@ -99,10 +99,13 @@ module.exports = function(Self) { const origin = headers.origin; const user = await Self.app.models.VnUser.findById(info.user.id); + let directory = info.options?.directory ?? '/#!/reset-password?access_token=$token$'; + directory = directory.replace('$token$', info.accessToken.id); + const params = { recipient: info.email, lang: user.lang, - url: `${origin}/#!/reset-password?access_token=${info.accessToken.id}` + url: origin + directory }; const options = Object.assign({}, info.options); @@ -158,9 +161,9 @@ module.exports = function(Self) { } }; - Self.sharedClass._methods.find(method => method.name == 'changePassword').ctor.settings.acls = - Self.sharedClass._methods.find(method => method.name == 'changePassword').ctor.settings.acls - .filter(acl => acl.property != 'changePassword'); + // Self.sharedClass._methods.find(method => method.name == 'changePassword').ctor.settings.acls = + // Self.sharedClass._methods.find(method => method.name == 'changePassword').ctor.settings.acls + // .filter(acl => acl.property != 'changePassword'); // FIXME: https://redmine.verdnatura.es/issues/5761 // Self.afterRemote('prototype.patchAttributes', async(ctx, instance) => { diff --git a/front/salix/components/change-password/index.js b/front/salix/components/change-password/index.js index 797d4dc96..7e30bf54e 100644 --- a/front/salix/components/change-password/index.js +++ b/front/salix/components/change-password/index.js @@ -15,9 +15,6 @@ export default class Controller { } $onInit() { - if (!this.$state.params.id) - this.$state.go('login'); - this.$http.get('UserPasswords/findOne') .then(res => { this.passRequirements = res.data; @@ -25,7 +22,7 @@ export default class Controller { } submit() { - const userId = this.$state.params.userId; + const userId = parseInt(this.$state.params.userId); const oldPassword = this.oldPassword; const newPassword = this.newPassword; const repeatPassword = this.repeatPassword; @@ -36,18 +33,13 @@ export default class Controller { if (newPassword != this.repeatPassword) throw new UserError(`Passwords don't match`); - const headers = { - Authorization: this.$state.params.id - }; - this.$http.patch('Accounts/change-password', { - id: userId, + userId, oldPassword, newPassword, code - }, - {headers} + } ).then(() => { this.vnApp.showSuccess(this.$translate.instant('Password updated!')); this.$state.go('login'); diff --git a/front/salix/components/login/index.js b/front/salix/components/login/index.js index be4fb3926..7d8cd2049 100644 --- a/front/salix/components/login/index.js +++ b/front/salix/components/login/index.js @@ -36,7 +36,7 @@ export default class Controller { const err = req.data?.error; if (err?.code == 'passExpired') - this.$state.go('change-password', err.details.token); + this.$state.go('change-password', err.details); this.loading = false; this.password = ''; diff --git a/front/salix/routes.js b/front/salix/routes.js index 5a2c030bc..8621f83c7 100644 --- a/front/salix/routes.js +++ b/front/salix/routes.js @@ -45,7 +45,7 @@ function config($stateProvider, $urlRouterProvider) { }) .state('change-password', { parent: 'outLayout', - url: '/change-password?id&userId&twoFactor', + url: '/change-password?userId&twoFactor', description: 'Change password', template: '' }) diff --git a/modules/account/back/methods/account/change-password.js b/modules/account/back/methods/account/change-password.js index a739f37d0..49af93110 100644 --- a/modules/account/back/methods/account/change-password.js +++ b/modules/account/back/methods/account/change-password.js @@ -1,12 +1,15 @@ const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { - Self.remoteMethodCtx('changePassword', { + Self.remoteMethod('changePassword', { description: 'Changes the user password', - accessType: 'WRITE', - accessScopes: ['changePassword'], accepts: [ { + arg: 'userId', + type: 'integer', + description: 'The user id', + required: true + }, { arg: 'oldPassword', type: 'string', description: 'The old password', @@ -28,9 +31,7 @@ module.exports = Self => { } }); - Self.changePassword = async function(ctx, oldPassword, newPassword, code, options) { - const userId = ctx.req.accessToken.userId; - + Self.changePassword = async function(userId, oldPassword, newPassword, code, options) { const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/account/back/methods/account/specs/change-password.spec.js b/modules/account/back/methods/account/specs/change-password.spec.js index 045f98493..2fa3010af 100644 --- a/modules/account/back/methods/account/specs/change-password.spec.js +++ b/modules/account/back/methods/account/specs/change-password.spec.js @@ -1,7 +1,7 @@ const {models} = require('vn-loopback/server/server'); describe('account changePassword()', () => { - const ctx = {req: {accessToken: {userId: 70}}}; + const userId = 70; const unauthCtx = { req: { headers: {}, @@ -20,7 +20,7 @@ describe('account changePassword()', () => { try { const options = {transaction: tx}; - await models.Account.changePassword(ctx, 'wrongPassword', 'nightmare.9999', null, options); + await models.Account.changePassword(userId, 'wrongPassword', 'nightmare.9999', null, options); await tx.rollback(); } catch (e) { await tx.rollback(); @@ -37,8 +37,8 @@ describe('account changePassword()', () => { try { const options = {transaction: tx}; - await models.Account.changePassword(ctx, 'nightmare', 'nightmare.9999', null, options); - await models.Account.changePassword(ctx, 'nightmare.9999', 'nightmare.9999', null, options); + await models.Account.changePassword(userId, 'nightmare', 'nightmare.9999', null, options); + await models.Account.changePassword(userId, 'nightmare.9999', 'nightmare.9999', null, options); await tx.rollback(); } catch (e) { await tx.rollback(); @@ -54,7 +54,7 @@ describe('account changePassword()', () => { try { const options = {transaction: tx}; - await models.Account.changePassword(ctx, 'nightmare', 'nightmare.9999', null, options); + await models.Account.changePassword(userId, 'nightmare', 'nightmare.9999', null, options); await tx.rollback(); } catch (e) { await tx.rollback(); @@ -86,8 +86,8 @@ describe('account changePassword()', () => { } try { - const authCode = await models.AuthCode.findOne({where: {userFk: 70}}, options); - await models.Account.changePassword(ctx, 'nightmare', 'nightmare.9999', authCode.code, options); + const authCode = await models.AuthCode.findOne({where: {userFk: userId}}, options); + await models.Account.changePassword(userId, 'nightmare', 'nightmare.9999', authCode.code, options); await tx.rollback(); } catch (e) { await tx.rollback(); From 125d908c5d5395a5ed48900cae4ba062ce17b739 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 17 Jul 2023 14:41:15 +0200 Subject: [PATCH 07/32] refs #5762 uncomment --- back/models/vn-user.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/back/models/vn-user.js b/back/models/vn-user.js index f47dc47e2..163649718 100644 --- a/back/models/vn-user.js +++ b/back/models/vn-user.js @@ -161,9 +161,9 @@ module.exports = function(Self) { } }; - // Self.sharedClass._methods.find(method => method.name == 'changePassword').ctor.settings.acls = - // Self.sharedClass._methods.find(method => method.name == 'changePassword').ctor.settings.acls - // .filter(acl => acl.property != 'changePassword'); + Self.sharedClass._methods.find(method => method.name == 'changePassword').ctor.settings.acls = + Self.sharedClass._methods.find(method => method.name == 'changePassword').ctor.settings.acls + .filter(acl => acl.property != 'changePassword'); // FIXME: https://redmine.verdnatura.es/issues/5761 // Self.afterRemote('prototype.patchAttributes', async(ctx, instance) => { From 15dee8bef442e17c56375e382c6c5d6ba5f19316 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 17 Jul 2023 15:19:36 +0200 Subject: [PATCH 08/32] refs #5976 refactor: transaferSale call setDeleted --- db/changes/233001/00-setDeleted_acl.sql | 6 ++++++ .../ticket/back/methods/ticket/specs/transferSales.spec.js | 2 ++ modules/ticket/back/methods/ticket/transferSales.js | 7 ++----- 3 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 db/changes/233001/00-setDeleted_acl.sql diff --git a/db/changes/233001/00-setDeleted_acl.sql b/db/changes/233001/00-setDeleted_acl.sql new file mode 100644 index 000000000..1030965dd --- /dev/null +++ b/db/changes/233001/00-setDeleted_acl.sql @@ -0,0 +1,6 @@ +UPDATE `salix`.`ACL` + SET principalId='salesperson' + WHERE + model='Ticket' + AND property='setDeleted' + AND accessType='WRITE'; diff --git a/modules/ticket/back/methods/ticket/specs/transferSales.spec.js b/modules/ticket/back/methods/ticket/specs/transferSales.spec.js index 562688917..61c788b64 100644 --- a/modules/ticket/back/methods/ticket/specs/transferSales.spec.js +++ b/modules/ticket/back/methods/ticket/specs/transferSales.spec.js @@ -5,6 +5,8 @@ describe('sale transferSales()', () => { const userId = 1101; const activeCtx = { accessToken: {userId: userId}, + headers: {origin: ''}, + __: value => value }; const ctx = {req: activeCtx}; diff --git a/modules/ticket/back/methods/ticket/transferSales.js b/modules/ticket/back/methods/ticket/transferSales.js index 0eee50d5f..00fc02f38 100644 --- a/modules/ticket/back/methods/ticket/transferSales.js +++ b/modules/ticket/back/methods/ticket/transferSales.js @@ -96,11 +96,8 @@ module.exports = Self => { } const isTicketEmpty = await models.Ticket.isEmpty(id, myOptions); - if (isTicketEmpty) { - await originalTicket.updateAttributes({ - isDeleted: true - }, myOptions); - } + if (isTicketEmpty) + await models.Ticket.setDeleted(ctx, id, myOptions); if (tx) await tx.commit(); From f07ac89cb6ea7b68033b702a36e13b2b2ec5d32a Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 18 Jul 2023 15:01:04 +0200 Subject: [PATCH 09/32] refs #5976 add custom error --- loopback/locale/es.json | 3 ++- .../ticket/back/methods/ticket/setDeleted.js | 4 +-- .../back/methods/ticket/transferSales.js | 27 +++++++++++++++---- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 784ff5e6e..16b0af7f5 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -305,5 +305,6 @@ "The renew period has not been exceeded": "El periodo de renovación no ha sido superado", "Valid priorities": "Prioridades válidas: %d", "Negative basis of tickets": "Base negativa para los tickets: {{ticketsIds}}", - "You cannot assign an alias that you are not assigned to": "No puede asignar un alias que no tenga asignado" + "You cannot assign an alias that you are not assigned to": "No puede asignar un alias que no tenga asignado", + "This ticket cannot be left empty.": "Este ticket no se puede dejar vacío. %d" } diff --git a/modules/ticket/back/methods/ticket/setDeleted.js b/modules/ticket/back/methods/ticket/setDeleted.js index 878cce056..46c0add6b 100644 --- a/modules/ticket/back/methods/ticket/setDeleted.js +++ b/modules/ticket/back/methods/ticket/setDeleted.js @@ -41,8 +41,8 @@ module.exports = Self => { const isEditable = await Self.isEditable(ctx, id, myOptions); - if (!isEditable) - throw new UserError(`The sales of this ticket can't be modified`); + throw new UserError(`The sales of this ticket can't be modified`); + // if (!isEditable) // Check if ticket has refunds const ticketRefunds = await models.TicketRefund.find({ diff --git a/modules/ticket/back/methods/ticket/transferSales.js b/modules/ticket/back/methods/ticket/transferSales.js index 00fc02f38..2e4bf023d 100644 --- a/modules/ticket/back/methods/ticket/transferSales.js +++ b/modules/ticket/back/methods/ticket/transferSales.js @@ -37,6 +37,7 @@ module.exports = Self => { const userId = ctx.req.accessToken.userId; const models = Self.app.models; const myOptions = {userId}; + const $t = ctx.req.__; // $translate let tx; if (typeof options == 'object') @@ -78,9 +79,9 @@ module.exports = Self => { const saleIds = sales.map(sale => sale.id); - const hasClaimedSales = await models.ClaimBeginning.findOne({where: {saleFk: {inq: saleIds}}}); - if (ticketId != id && hasClaimedSales) - throw new UserError(`Can't transfer claimed sales`); + // const hasClaimedSales = await models.ClaimBeginning.findOne({where: {saleFk: {inq: saleIds}}}); + // if (ticketId != id && hasClaimedSales) + // throw new UserError(`Can't transfer claimed sales`); for (const sale of sales) { const originalSale = map.get(sale.id); @@ -96,14 +97,30 @@ module.exports = Self => { } const isTicketEmpty = await models.Ticket.isEmpty(id, myOptions); - if (isTicketEmpty) - await models.Ticket.setDeleted(ctx, id, myOptions); + if (isTicketEmpty) { + try { + await models.Ticket.setDeleted(ctx, id, myOptions); + } catch (e) { + console.log('e:', e); + console.log('e.message:', e.message); + console.log('e translation:', $t(e.message, {})); + if (e.statusCode === 400) { + throw new UserError( + `This ticket cannot be left empty.`, + 'TRANSFER_SET_DELETED', + $t(e.message) + ); + } + throw e; + } + } if (tx) await tx.commit(); return {id: ticketId}; } catch (e) { if (tx) await tx.rollback(); + console.log('e.UserError:', e); throw e; } }; From 36c31af455bff82604fd29fee0a397051172de47 Mon Sep 17 00:00:00 2001 From: carlossa Date: Wed, 19 Jul 2023 12:38:13 +0200 Subject: [PATCH 10/32] refs #5690 rounding translate --- modules/ticket/front/future/index.html | 1 + modules/ticket/front/index/index.html | 1 + 2 files changed, 2 insertions(+) diff --git a/modules/ticket/front/future/index.html b/modules/ticket/front/future/index.html index 742143b27..5119d103b 100644 --- a/modules/ticket/front/future/index.html +++ b/modules/ticket/front/future/index.html @@ -125,6 +125,7 @@ diff --git a/modules/ticket/front/index/index.html b/modules/ticket/front/index/index.html index 3b490a3a9..26e5553ed 100644 --- a/modules/ticket/front/index/index.html +++ b/modules/ticket/front/index/index.html @@ -77,6 +77,7 @@ From 2c79056f3464b4f526a72143567f948e7e4a831f Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 19 Jul 2023 13:44:04 +0200 Subject: [PATCH 11/32] refs #5976 error extended --- loopback/locale/en.json | 3 ++- loopback/locale/es.json | 2 +- modules/route/front/roadmap/index/index.js | 2 -- modules/ticket/back/methods/ticket/setDeleted.js | 4 ++-- modules/ticket/back/methods/ticket/transferSales.js | 12 ++++-------- 5 files changed, 9 insertions(+), 14 deletions(-) diff --git a/loopback/locale/en.json b/loopback/locale/en.json index 030afbe9e..dde24ddc6 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -178,5 +178,6 @@ "The renew period has not been exceeded": "The renew period has not been exceeded", "You can not use the same password": "You can not use the same password", "Valid priorities": "Valid priorities: %d", - "Negative basis of tickets": "Negative basis of tickets: {{ticketsIds}}" + "Negative basis of tickets": "Negative basis of tickets: {{ticketsIds}}", + "This ticket cannot be left empty.": "This ticket cannot be left empty. %s" } diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 16b0af7f5..c12b980fa 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -306,5 +306,5 @@ "Valid priorities": "Prioridades válidas: %d", "Negative basis of tickets": "Base negativa para los tickets: {{ticketsIds}}", "You cannot assign an alias that you are not assigned to": "No puede asignar un alias que no tenga asignado", - "This ticket cannot be left empty.": "Este ticket no se puede dejar vacío. %d" + "This ticket cannot be left empty.": "Este ticket no se puede dejar vacío. %s" } diff --git a/modules/route/front/roadmap/index/index.js b/modules/route/front/roadmap/index/index.js index 3ffc5b4b1..c5f5ef9d1 100644 --- a/modules/route/front/roadmap/index/index.js +++ b/modules/route/front/roadmap/index/index.js @@ -46,8 +46,6 @@ class Controller extends Section { } deleteRoadmaps() { - console.log(this.checked); - for (const roadmap of this.checked) { this.$http.delete(`Roadmaps/${roadmap.id}`) .then(() => this.$.model.refresh()) diff --git a/modules/ticket/back/methods/ticket/setDeleted.js b/modules/ticket/back/methods/ticket/setDeleted.js index 46c0add6b..878cce056 100644 --- a/modules/ticket/back/methods/ticket/setDeleted.js +++ b/modules/ticket/back/methods/ticket/setDeleted.js @@ -41,8 +41,8 @@ module.exports = Self => { const isEditable = await Self.isEditable(ctx, id, myOptions); - throw new UserError(`The sales of this ticket can't be modified`); - // if (!isEditable) + if (!isEditable) + throw new UserError(`The sales of this ticket can't be modified`); // Check if ticket has refunds const ticketRefunds = await models.TicketRefund.find({ diff --git a/modules/ticket/back/methods/ticket/transferSales.js b/modules/ticket/back/methods/ticket/transferSales.js index 2e4bf023d..de52e2f18 100644 --- a/modules/ticket/back/methods/ticket/transferSales.js +++ b/modules/ticket/back/methods/ticket/transferSales.js @@ -79,9 +79,9 @@ module.exports = Self => { const saleIds = sales.map(sale => sale.id); - // const hasClaimedSales = await models.ClaimBeginning.findOne({where: {saleFk: {inq: saleIds}}}); - // if (ticketId != id && hasClaimedSales) - // throw new UserError(`Can't transfer claimed sales`); + const hasClaimedSales = await models.ClaimBeginning.findOne({where: {saleFk: {inq: saleIds}}}); + if (ticketId != id && hasClaimedSales) + throw new UserError(`Can't transfer claimed sales`); for (const sale of sales) { const originalSale = map.get(sale.id); @@ -101,14 +101,11 @@ module.exports = Self => { try { await models.Ticket.setDeleted(ctx, id, myOptions); } catch (e) { - console.log('e:', e); - console.log('e.message:', e.message); - console.log('e translation:', $t(e.message, {})); if (e.statusCode === 400) { throw new UserError( `This ticket cannot be left empty.`, 'TRANSFER_SET_DELETED', - $t(e.message) + $t(e.message, ...e.translateArgs) ); } throw e; @@ -120,7 +117,6 @@ module.exports = Self => { return {id: ticketId}; } catch (e) { if (tx) await tx.rollback(); - console.log('e.UserError:', e); throw e; } }; From b188ae6f570d406cf01664dc9e98706f2ae3c1f1 Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 19 Jul 2023 14:14:35 +0200 Subject: [PATCH 12/32] refs #5976 fix: e2e --- db/changes/233001/00-setDeleted_acl.sql | 2 +- e2e/paths/05-ticket/14_create_ticket.spec.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/db/changes/233001/00-setDeleted_acl.sql b/db/changes/233001/00-setDeleted_acl.sql index 1030965dd..cdeff9522 100644 --- a/db/changes/233001/00-setDeleted_acl.sql +++ b/db/changes/233001/00-setDeleted_acl.sql @@ -1,5 +1,5 @@ UPDATE `salix`.`ACL` - SET principalId='salesperson' + SET principalId='salesPerson' WHERE model='Ticket' AND property='setDeleted' diff --git a/e2e/paths/05-ticket/14_create_ticket.spec.js b/e2e/paths/05-ticket/14_create_ticket.spec.js index 80c288a01..1f9c0c40a 100644 --- a/e2e/paths/05-ticket/14_create_ticket.spec.js +++ b/e2e/paths/05-ticket/14_create_ticket.spec.js @@ -10,7 +10,7 @@ describe('Ticket create path', () => { beforeAll(async() => { browser = await getBrowser(); page = browser.page; - await page.loginAndModule('employee', 'ticket'); + await page.loginAndModule('salesPerson', 'ticket'); }); afterAll(async() => { From 16353dfddc1fab62c3b3e16a7b1aa040af632486 Mon Sep 17 00:00:00 2001 From: guillermo Date: Wed, 2 Aug 2023 07:35:40 +0200 Subject: [PATCH 13/32] refs #5995 First commit --- modules/route/back/methods/route/cmr.js | 36 ++ modules/route/back/models/route.js | 1 + modules/ticket/back/methods/ticket/closure.js | 319 ++++++++++-------- .../reports/cmr/assets/css/import.js | 12 + .../reports/cmr/assets/css/style.css | 101 ++++++ .../reports/cmr/assets/images/signature.png | Bin 0 -> 27129 bytes print/templates/reports/cmr/cmr.html | 212 ++++++++++++ print/templates/reports/cmr/cmr.js | 38 +++ print/templates/reports/cmr/locale/es.yml | 1 + print/templates/reports/cmr/options.json | 3 + print/templates/reports/cmr/sql/data.sql | 49 +++ .../templates/reports/cmr/sql/merchandise.sql | 11 + .../templates/reports/cmr/sql/signatures.sql | 7 + 13 files changed, 646 insertions(+), 144 deletions(-) create mode 100644 modules/route/back/methods/route/cmr.js create mode 100644 print/templates/reports/cmr/assets/css/import.js create mode 100644 print/templates/reports/cmr/assets/css/style.css create mode 100644 print/templates/reports/cmr/assets/images/signature.png create mode 100644 print/templates/reports/cmr/cmr.html create mode 100644 print/templates/reports/cmr/cmr.js create mode 100644 print/templates/reports/cmr/locale/es.yml create mode 100644 print/templates/reports/cmr/options.json create mode 100644 print/templates/reports/cmr/sql/data.sql create mode 100644 print/templates/reports/cmr/sql/merchandise.sql create mode 100644 print/templates/reports/cmr/sql/signatures.sql diff --git a/modules/route/back/methods/route/cmr.js b/modules/route/back/methods/route/cmr.js new file mode 100644 index 000000000..cd7ef57ce --- /dev/null +++ b/modules/route/back/methods/route/cmr.js @@ -0,0 +1,36 @@ +module.exports = Self => { + Self.remoteMethodCtx('cmr', { + description: 'Returns the cmr', + accessType: 'READ', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The cmr id', + http: {source: 'path'} + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/:id/cmr', + verb: 'GET' + } + }); + + Self.cmr = (ctx, id) => Self.printReport(ctx, id, 'cmr'); +}; diff --git a/modules/route/back/models/route.js b/modules/route/back/models/route.js index 883f4597e..96e7ed04f 100644 --- a/modules/route/back/models/route.js +++ b/modules/route/back/models/route.js @@ -14,6 +14,7 @@ module.exports = Self => { require('../methods/route/driverRouteEmail')(Self); require('../methods/route/sendSms')(Self); require('../methods/route/downloadZip')(Self); + require('../methods/route/cmr')(Self); Self.validate('kmStart', validateDistance, { message: 'Distance must be lesser than 1000' diff --git a/modules/ticket/back/methods/ticket/closure.js b/modules/ticket/back/methods/ticket/closure.js index eee5e28e2..493a2c3a0 100644 --- a/modules/ticket/back/methods/ticket/closure.js +++ b/modules/ticket/back/methods/ticket/closure.js @@ -5,177 +5,208 @@ const config = require('vn-print/core/config'); const storage = require('vn-print/core/storage'); module.exports = async function(ctx, Self, tickets, reqArgs = {}) { - const userId = ctx.req.accessToken.userId; - if (tickets.length == 0) return; + const userId = ctx.req.accessToken.userId; + if (tickets.length == 0) return; - const failedtickets = []; - for (const ticket of tickets) { - try { - await Self.rawSql(`CALL vn.ticket_closeByTicket(?)`, [ticket.id], {userId}); + const failedtickets = []; + for (const ticket of tickets) { + try { + await Self.rawSql(`CALL vn.ticket_closeByTicket(?)`, [ticket.id], {userId}); - const [invoiceOut] = await Self.rawSql(` - SELECT io.id, io.ref, io.serial, cny.code companyCode, io.issued - FROM ticket t - JOIN invoiceOut io ON io.ref = t.refFk - JOIN company cny ON cny.id = io.companyFk - WHERE t.id = ? - `, [ticket.id]); + const [invoiceOut] = await Self.rawSql(` + SELECT io.id, io.ref, io.serial, cny.code companyCode, io.issued + FROM ticket t + JOIN invoiceOut io ON io.ref = t.refFk + JOIN company cny ON cny.id = io.companyFk + WHERE t.id = ? + `, [ticket.id]); - const mailOptions = { - overrideAttachments: true, - attachments: [] - }; + const mailOptions = { + overrideAttachments: true, + attachments: [] + }; - const isToBeMailed = ticket.recipient && ticket.salesPersonFk && ticket.isToBeMailed; + const isToBeMailed = ticket.recipient && ticket.salesPersonFk && ticket.isToBeMailed; - if (invoiceOut) { - const args = { - reference: invoiceOut.ref, - recipientId: ticket.clientFk, - recipient: ticket.recipient, - replyTo: ticket.salesPersonEmail - }; + if (invoiceOut) { + const args = { + reference: invoiceOut.ref, + recipientId: ticket.clientFk, + recipient: ticket.recipient, + replyTo: ticket.salesPersonEmail + }; - const invoiceReport = new Report('invoice', args); - const stream = await invoiceReport.toPdfStream(); + const invoiceReport = new Report('invoice', args); + const stream = await invoiceReport.toPdfStream(); - const issued = invoiceOut.issued; - const year = issued.getFullYear().toString(); - const month = (issued.getMonth() + 1).toString(); - const day = issued.getDate().toString(); + const issued = invoiceOut.issued; + const year = issued.getFullYear().toString(); + const month = (issued.getMonth() + 1).toString(); + const day = issued.getDate().toString(); - const fileName = `${year}${invoiceOut.ref}.pdf`; + const fileName = `${year}${invoiceOut.ref}.pdf`; - // Store invoice - await storage.write(stream, { - type: 'invoice', - path: `${year}/${month}/${day}`, - fileName: fileName - }); + // Store invoice + await storage.write(stream, { + type: 'invoice', + path: `${year}/${month}/${day}`, + fileName: fileName + }); - await Self.rawSql('UPDATE invoiceOut SET hasPdf = true WHERE id = ?', [invoiceOut.id], {userId}); + await Self.rawSql('UPDATE invoiceOut SET hasPdf = true WHERE id = ?', [invoiceOut.id], {userId}); - if (isToBeMailed) { - const invoiceAttachment = { - filename: fileName, - content: stream - }; + if (isToBeMailed) { + const invoiceAttachment = { + filename: fileName, + content: stream + }; - if (invoiceOut.serial == 'E' && invoiceOut.companyCode == 'VNL') { - const exportation = new Report('exportation', args); - const stream = await exportation.toPdfStream(); - const fileName = `CITES-${invoiceOut.ref}.pdf`; + if (invoiceOut.serial == 'E' && invoiceOut.companyCode == 'VNL') { + const exportation = new Report('exportation', args); + const stream = await exportation.toPdfStream(); + const fileName = `CITES-${invoiceOut.ref}.pdf`; - mailOptions.attachments.push({ - filename: fileName, - content: stream - }); - } + mailOptions.attachments.push({ + filename: fileName, + content: stream + }); + } - mailOptions.attachments.push(invoiceAttachment); + mailOptions.attachments.push(invoiceAttachment); - const email = new Email('invoice', args); - await email.send(mailOptions); - } - } else if (isToBeMailed) { - const args = { - id: ticket.id, - recipientId: ticket.clientFk, - recipient: ticket.recipient, - replyTo: ticket.salesPersonEmail - }; + const email = new Email('invoice', args); + await email.send(mailOptions); + } + } else if (isToBeMailed) { + const args = { + id: ticket.id, + recipientId: ticket.clientFk, + recipient: ticket.recipient, + replyTo: ticket.salesPersonEmail + }; - const email = new Email('delivery-note-link', args); - await email.send(); - } + const email = new Email('delivery-note-link', args); + await email.send(); + } - // Incoterms authorization - const [{firstOrder}] = await Self.rawSql(` - SELECT COUNT(*) as firstOrder - FROM ticket t - JOIN client c ON c.id = t.clientFk - WHERE t.clientFk = ? - AND NOT t.isDeleted - AND c.isVies - `, [ticket.clientFk]); + // Incoterms authorization + const [{firstOrder}] = await Self.rawSql(` + SELECT COUNT(*) as firstOrder + FROM ticket t + JOIN client c ON c.id = t.clientFk + WHERE t.clientFk = ? + AND NOT t.isDeleted + AND c.isVies + `, [ticket.clientFk]); - if (firstOrder == 1) { - const args = { - id: ticket.clientFk, - companyId: ticket.companyFk, - recipientId: ticket.clientFk, - recipient: ticket.recipient, - replyTo: ticket.salesPersonEmail - }; + if (firstOrder == 1) { + const args = { + id: ticket.clientFk, + companyId: ticket.companyFk, + recipientId: ticket.clientFk, + recipient: ticket.recipient, + replyTo: ticket.salesPersonEmail + }; - const email = new Email('incoterms-authorization', args); - await email.send(); + const email = new Email('incoterms-authorization', args); + await email.send(); - const [sample] = await Self.rawSql( - `SELECT id - FROM sample - WHERE code = 'incoterms-authorization' - `); + const [sample] = await Self.rawSql( + `SELECT id + FROM sample + WHERE code = 'incoterms-authorization' + `); - await Self.rawSql(` - INSERT INTO clientSample (clientFk, typeFk, companyFk) VALUES(?, ?, ?) - `, [ticket.clientFk, sample.id, ticket.companyFk], {userId}); - } - } catch (error) { - // Domain not found - if (error.responseCode == 450) - return invalidEmail(ticket); + await Self.rawSql(` + INSERT INTO clientSample (clientFk, typeFk, companyFk) VALUES(?, ?, ?) + `, [ticket.clientFk, sample.id, ticket.companyFk], {userId}); + } - // Save tickets on a list of failed ids - failedtickets.push({ - id: ticket.id, - stacktrace: error - }); - } - } + await Self.rawSql(` + INSERT INTO cmr (ticketFk, companyFk, addressToFk, addressFromFk, supplierFk, ead) + SELECT t.id, + com.id, + a.id, + c2.defaultAddressFk, + su.id, + t.landed + FROM ticket t + JOIN ticketState ts ON ts.ticketFk = t.id + JOIN state s ON s.id = ts.stateFk + JOIN alertLevel al ON al.id = s.alertLevel + JOIN client c ON c.id = t.clientFk + JOIN address a ON a.id = t.addressFk + JOIN province p ON p.id = a.provinceFk + JOIN country co ON co.id = p.countryFk + JOIN agencyMode am ON am.id = t.agencyModeFk + JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk + JOIN warehouse w ON w.id = t.warehouseFk + JOIN company com ON com.id = t.companyFk + JOIN client c2 ON c2.id = com.clientFk + JOIN supplierAccount sa ON sa.id = com.supplierAccountFk + JOIN supplier su ON su.id = sa.supplierFk + WHERE shipped BETWEEN util.yesterday() AND util.dayEnd(util.yesterday()) + AND al.code IN ('PACKED', 'DELIVERED') + AND co.code <> 'ES' + AND am.name <> 'ABONO' + AND w.code = 'ALG' + AND dm.code = 'DELIVERY' + `); + } catch (error) { + // Domain not found + if (error.responseCode == 450) + return invalidEmail(ticket); - // Send email with failed tickets - if (failedtickets.length > 0) { - let body = 'This following tickets have failed:

'; + // Save tickets on a list of failed ids + failedtickets.push({ + id: ticket.id, + stacktrace: error + }); + } + } - for (const ticket of failedtickets) { - body += `Ticket: ${ticket.id} -
${ticket.stacktrace}

`; - } + // Send email with failed tickets + if (failedtickets.length > 0) { + let body = 'This following tickets have failed:

'; - smtp.send({ - to: config.app.reportEmail, - subject: '[API] Nightly ticket closure report', - html: body - }); - } + for (const ticket of failedtickets) { + body += `Ticket: ${ticket.id} +
${ticket.stacktrace}

`; + } - async function invalidEmail(ticket) { - await Self.rawSql(`UPDATE client SET email = NULL WHERE id = ?`, [ - ticket.clientFk - ], {userId}); + smtp.send({ + to: config.app.reportEmail, + subject: '[API] Nightly ticket closure report', + html: body + }); + } - const oldInstance = `{"email": "${ticket.recipient}"}`; - const newInstance = `{"email": ""}`; - await Self.rawSql(` - INSERT INTO clientLog (originFk, userFk, action, changedModel, oldInstance, newInstance) - VALUES (?, NULL, 'UPDATE', 'Client', ?, ?)`, [ - ticket.clientFk, - oldInstance, - newInstance - ], {userId}); + async function invalidEmail(ticket) { + await Self.rawSql(`UPDATE client SET email = NULL WHERE id = ?`, [ + ticket.clientFk + ], {userId}); - const body = `No se ha podido enviar el albarán ${ticket.id} - al cliente ${ticket.clientFk} - ${ticket.clientName} - porque la dirección de email "${ticket.recipient}" no es correcta - o no está disponible.

- Para evitar que se repita este error, se ha eliminado la dirección de email de la ficha del cliente. - Actualiza la dirección de email con una correcta.`; + const oldInstance = `{"email": "${ticket.recipient}"}`; + const newInstance = `{"email": ""}`; + await Self.rawSql(` + INSERT INTO clientLog (originFk, userFk, action, changedModel, oldInstance, newInstance) + VALUES (?, NULL, 'UPDATE', 'Client', ?, ?)`, [ + ticket.clientFk, + oldInstance, + newInstance + ], {userId}); - smtp.send({ - to: ticket.salesPersonEmail, - subject: 'No se ha podido enviar el albarán', - html: body - }); - } + const body = `No se ha podido enviar el albarán ${ticket.id} + al cliente ${ticket.clientFk} - ${ticket.clientName} + porque la dirección de email "${ticket.recipient}" no es correcta + o no está disponible.

+ Para evitar que se repita este error, se ha eliminado la dirección de email de la ficha del cliente. + Actualiza la dirección de email con una correcta.`; + + smtp.send({ + to: ticket.salesPersonEmail, + subject: 'No se ha podido enviar el albarán', + html: body + }); + } }; diff --git a/print/templates/reports/cmr/assets/css/import.js b/print/templates/reports/cmr/assets/css/import.js new file mode 100644 index 000000000..37a98dfdd --- /dev/null +++ b/print/templates/reports/cmr/assets/css/import.js @@ -0,0 +1,12 @@ +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); + +module.exports = new Stylesheet([ + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/report.css`, + `${__dirname}/style.css`]) + .mergeStyles(); diff --git a/print/templates/reports/cmr/assets/css/style.css b/print/templates/reports/cmr/assets/css/style.css new file mode 100644 index 000000000..201afc3b6 --- /dev/null +++ b/print/templates/reports/cmr/assets/css/style.css @@ -0,0 +1,101 @@ +html { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + margin: 10px; + font-size: 22px; +} +.mainTable, .specialTable, .categoryTable { + width: 100%; + border-collapse: collapse; + font-size: inherit; +} +.mainTable td { + width: 50%; + border: 1px solid black; + vertical-align: top; + padding: 15px; + font-size: inherit; +} +.signTable { + height: 12%; +} +.signTable td { + width: calc(100% / 3); + border: 1px solid black; + vertical-align: top; + font-size: inherit; + padding: 15px; + border-top: none; +} +#title { + font-weight: bold; + font-size: 85px; +} +hr { + border: 1px solid #cccccc; + height: 0px; + border-radius: 25px; +} +#cellHeader { + border: 0px; + text-align: center; + vertical-align: middle; +} +#label, #merchandiseLabels { + font-size: 13px; +} +#merchandiseLabels { + border: none; +} +.imgSection { + text-align: center; + height: 200px; + overflow: hidden; +} +img { + object-fit: contain; + width: 100%; + height: 100%; +} +#lineBreak { + white-space: pre-line; +} +.specialTable td { + border: 1px solid black; + vertical-align: top; + padding: 15px; + font-size: inherit; + border-top: none; + border-bottom: none; +} +.specialTable #itemCategoryList { + width: 70%; + padding-top: 10px; +} +.categoryTable { + padding-bottom: none; +} +.categoryTable td { + vertical-align: top; + font-size: inherit; + border: none; + padding: 5px; + overflow: hidden; +} +.categoryTable #merchandiseLabels { + border-bottom: 4px solid #cccccc; + padding: none; +} +#merchandiseDetail { + font-weight: bold; + padding-top: 10px; +} +#merchandiseData { + font-weight: bold; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +#merchandiseLabels td { + padding-bottom: 11px; + max-width: 300px; +} \ No newline at end of file diff --git a/print/templates/reports/cmr/assets/images/signature.png b/print/templates/reports/cmr/assets/images/signature.png new file mode 100644 index 0000000000000000000000000000000000000000..0961df764f5e038b0c61620b60ba0c601d41ae93 GIT binary patch literal 27129 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 + + + + + + + + + + + + + + + + + + + + + + + +
+ 1. Remitente / Expediteur / Sender +
+ {{data.senderName}}
+ {{data.senderStreet}}
+ {{data.senderPostCode}} {{data.senderCity}} {{(data.senderCountry) ? `(${data.senderCountry})` : null}} +
+ CMR
+ {{data.cmrFk}} +
+ 2. Consignatario / Destinataire / Consignee +
+ {{data.deliveryAddressFk}}
+ {{data.deliveryName}}
+ {{data.deliveryPhone || data.clientPhone}} + {{((data.deliveryPhone || data.clientPhone) && data.deliveryMobile) ? '/' : null}} + {{data.deliveryMobile}}
+
+ 16. Transportista / Transporteur / Carrier +
+ {{data.carrierName}}
+ {{data.carrierStreet}}
+ {{data.carrierPostalCode}} {{data.carrierCity}} {{(data.carrierCountry) ? `(${data.carrierCountry})` : null}} +
+ + 3. Lugar y fecha de entrega / + Lieu et date de livraison / + Place and date of delivery + +
+ {{data.deliveryStreet}}
+ {{data.deliveryPostalCode}} {{data.deliveryCity}} {{(data.deliveryCountry) ? `(${data.deliveryCountry})` : null}}
+ {{(data.ead) ? formatDate(data.ead, '%d/%m/%Y') : null}}
+ +
+ 17. Porteadores sucesivos / Transporteurs succesifs / Succesive Carriers +
+
+ + 4. Lugar y fecha de carga / + Lieu et date del prise en charge de la merchandise / + Place and date of taking over the goods + +
+ {{data.loadStreet}}
+ {{data.loadPostalCode}} {{data.loadCity}} {{(data.loadCountry) ? `(${data.loadCountry})` : null}}
+ {{formatDate(data.created, '%d/%m/%Y')}}
+
+ + 18. Obervaciones del transportista / + Reserves et observations du transporteur / + Carrier's reservations and observations + +
+ {{data.truckPlate}}
+ {{data.observations}} +
+ 5. Documentos anexos / Documents annexes / Documents attached +
+
+ + + + + +
+ + 7 & 8. Número de bultos y clase de embalage / + Number of packages and packaging class / + Nombre de colis et classe d'emballage + +
+
+ {{data.packagesList}} +
+
+ + + + + + + + + + + + + + + +
6. Marcas y números / Brands and numbers / Marques et numéros9. Naturaleza de la merc. / Nature of goods / Nature des marchandises10. nº Estadístico / Statistical no. / n° statistique11. Peso bruto / Gross weight / Poids brut (kg)12. Volumen / Volume (m3)
{{merchandise.ticketFk}}{{merchandise.name}}N/A{{merchandise.weight}}{{merchandise.volume}}
+
+ {{data.merchandiseDetail}} +
+
+ + + + + + + + + + + + + +
+ + 13. Instrucciones del remitente / + Instrunstions de l'expèditeur / Sender + instruccions + +
+ {{data.senderInstruccions}} +
+ + 19. Estipulaciones particulares / + Conventions particulieres / + Special agreements + +
+ {{data.specialAgreements}} +
+ + 14. Forma de pago / + Prescriptions d'affranchissement / + Instruction as to payment for carriage + +
+ {{data.paymentInstruccions}} +
+ 20. A pagar por / Être payé pour / To be paid by +
+
+ 21. Formalizado en / Etabile a / Estabilshed in +
+ {{data.loadStreet}}
+ {{data.loadPostalCode}} {{data.loadCity}} {{(data.loadCountry) ? `(${data.loadCountry})` : null}}
+
+ 15. Reembolso / Remboursement / Cash on delivery +
+
+ + + + + + + + + +
+ + 22. Firma y sello del remitente / + Signature et timbre de l'expèditeur / + Signature and stamp of the sender + +
+
+ +
+
+ + 23. Firma y sello del transportista / + Signature et timbre du transporteur / + Signature and stamp of the carrier + +
+
+ +
+
+ + 24. Firma y sello del consignatario / + Signature et timbre du destinataire / + Signature and stamp of the consignee + +
+
+ +
+
+ + + \ No newline at end of file diff --git a/print/templates/reports/cmr/cmr.js b/print/templates/reports/cmr/cmr.js new file mode 100644 index 000000000..cfb3dd360 --- /dev/null +++ b/print/templates/reports/cmr/cmr.js @@ -0,0 +1,38 @@ +const config = require(`vn-print/core/config`); +const vnReport = require('../../../core/mixins/vn-report.js'); +const md5 = require('md5'); +const fs = require('fs-extra'); + +module.exports = { + name: 'cmr', + mixins: [vnReport], + async serverPrefetch() { + this.data = await this.findOneFromDef('data', [this.id]); + if (this.data.ticketFk) { + this.merchandises = await this.rawSqlFromDef('merchandise', [this.data.ticketFk]); + this.signatures = await this.findOneFromDef('signatures', [this.data.ticketFk]); + } + }, + props: { + id: { + type: Number, + required: true, + description: 'The cmr id' + }, + }, + methods: { + dmsPath(isClient) { + if (!this.signatures) return; + + const signatureName = (isClient) + ? this.signatures.clientSignature + : this.signatures.deliverySignature; + const hash = md5(signatureName.toString()).substring(0, 3); + const file = `${config.storage.root}/${hash}/${signatureName}.png`; + + if (!fs.existsSync(file)) return null; + + return `data:image/png;base64, ${Buffer.from(fs.readFileSync(file), 'utf8').toString('base64')}`; + } + } +}; \ No newline at end of file diff --git a/print/templates/reports/cmr/locale/es.yml b/print/templates/reports/cmr/locale/es.yml new file mode 100644 index 000000000..79f481b35 --- /dev/null +++ b/print/templates/reports/cmr/locale/es.yml @@ -0,0 +1 @@ +reportName: cmr \ No newline at end of file diff --git a/print/templates/reports/cmr/options.json b/print/templates/reports/cmr/options.json new file mode 100644 index 000000000..9151ca63b --- /dev/null +++ b/print/templates/reports/cmr/options.json @@ -0,0 +1,3 @@ +{ + "format": "A4" +} \ No newline at end of file diff --git a/print/templates/reports/cmr/sql/data.sql b/print/templates/reports/cmr/sql/data.sql new file mode 100644 index 000000000..e66ab7154 --- /dev/null +++ b/print/templates/reports/cmr/sql/data.sql @@ -0,0 +1,49 @@ +SELECT c.id cmrFk, + c.ticketFk, + c.truckPlate, + c.observations, + c.senderInstruccions, + c.paymentInstruccions, + c.specialAgreements, + c.created, + c.packagesList, + c.merchandiseDetail, + c.ead, + s.name carrierName, + s.street carrierStreet, + s.postCode carrierPostCode, + s.city carrierCity, + cou.country carrierCountry, + s2.name senderName, + s2.street senderStreet, + s2.postCode senderPostCode, + s2.city senderCity, + cou2.country senderCountry, + a.street deliveryStreet, + a.id deliveryAddressFk, + a.postalCode deliveryPostalCode, + a.city deliveryCity, + a.nickname deliveryName, + a.phone deliveryPhone, + a.mobile deliveryMobile, + cou3.country deliveryCountry, + cl.phone clientPhone, + a2.street loadStreet, + a2.postalCode loadPostalCode, + a2.city loadCity, + cou4.country loadCountry + FROM cmr c + LEFT JOIN supplier s ON s.id = c.supplierFk + LEFT JOIN country cou ON cou.id = s.countryFk + LEFT JOIN company co ON co.id = c.companyFk + LEFT JOIN supplierAccount sa ON sa.id = co.supplierAccountFk + LEFT JOIN supplier s2 ON s2.id = sa.supplierFk + LEFT JOIN country cou2 ON cou2.id = s2.countryFk + LEFT JOIN `address` a ON a.id = c.addressToFk + LEFT JOIN province p ON p.id = a.provinceFk + LEFT JOIN country cou3 ON cou3.id = p.countryFk + LEFT JOIN client cl ON cl.id = a.clientFk + LEFT JOIN `address` a2 ON a2.id = c.addressFromFk + LEFT JOIN province p2 ON p2.id = a2.provinceFk + LEFT JOIN country cou4 ON cou4.id = p2.countryFk + WHERE c.id = ? \ No newline at end of file diff --git a/print/templates/reports/cmr/sql/merchandise.sql b/print/templates/reports/cmr/sql/merchandise.sql new file mode 100644 index 000000000..cab597caa --- /dev/null +++ b/print/templates/reports/cmr/sql/merchandise.sql @@ -0,0 +1,11 @@ +SELECT s.ticketFk, + ic.name, + CAST(SUM(sv.weight) AS DECIMAL(10,2)) `weight`, + CAST(SUM(sv.volume) AS DECIMAL(10,3)) volume + FROM sale s + JOIN saleVolume sv ON sv.saleFk = s.id + JOIN item i ON i.id = s.itemFk + JOIN itemType it ON it.id = i.typeFk + JOIN itemCategory ic ON ic.id = it.categoryFk + WHERE sv.ticketFk = ? + GROUP BY ic.id \ No newline at end of file diff --git a/print/templates/reports/cmr/sql/signatures.sql b/print/templates/reports/cmr/sql/signatures.sql new file mode 100644 index 000000000..c90d4c91c --- /dev/null +++ b/print/templates/reports/cmr/sql/signatures.sql @@ -0,0 +1,7 @@ +SELECT dc.id clientSignature, dd.id deliverySignature + FROM ticket t + JOIN ticketDms dt ON dt.ticketFk = t.id + LEFT JOIN dms dc ON dc.id = dt.dmsFk + JOIN `route` r ON r.id = t.routeFk + LEFT JOIN dms dd ON dd.id = r.deliverySignFk + WHERE t.id = ? \ No newline at end of file From 84624935d6d2c08155ba6baa324b74d8787e2a9f Mon Sep 17 00:00:00 2001 From: guillermo Date: Wed, 2 Aug 2023 09:09:50 +0200 Subject: [PATCH 14/32] refs #5995 Load blob --- .../reports/cmr/assets/images/signature.png | Bin 27129 -> 0 bytes print/templates/reports/cmr/cmr.html | 6 ++--- print/templates/reports/cmr/cmr.js | 22 ++++++++++-------- print/templates/reports/cmr/sql/data.sql | 3 ++- print/templates/reports/cmr/sql/signature.sql | 5 ++++ .../templates/reports/cmr/sql/signatures.sql | 7 ------ 6 files changed, 22 insertions(+), 21 deletions(-) delete mode 100644 print/templates/reports/cmr/assets/images/signature.png create mode 100644 print/templates/reports/cmr/sql/signature.sql delete mode 100644 print/templates/reports/cmr/sql/signatures.sql diff --git a/print/templates/reports/cmr/assets/images/signature.png b/print/templates/reports/cmr/assets/images/signature.png deleted file mode 100644 index 0961df764f5e038b0c61620b60ba0c601d41ae93..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27129 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
- +
@@ -191,7 +191,7 @@

- + Aquí va la el stamp
@@ -202,7 +202,7 @@
- +
diff --git a/print/templates/reports/cmr/cmr.js b/print/templates/reports/cmr/cmr.js index cfb3dd360..ea9dc2a70 100644 --- a/print/templates/reports/cmr/cmr.js +++ b/print/templates/reports/cmr/cmr.js @@ -10,8 +10,9 @@ module.exports = { this.data = await this.findOneFromDef('data', [this.id]); if (this.data.ticketFk) { this.merchandises = await this.rawSqlFromDef('merchandise', [this.data.ticketFk]); - this.signatures = await this.findOneFromDef('signatures', [this.data.ticketFk]); - } + this.signature = await this.findOneFromDef('signature', [this.data.ticketFk]); + } else + this.merchandises = null; }, props: { id: { @@ -20,19 +21,20 @@ module.exports = { description: 'The cmr id' }, }, - methods: { - dmsPath(isClient) { - if (!this.signatures) return; + computed: { + signPath() { + if (!this.signature) return; - const signatureName = (isClient) - ? this.signatures.clientSignature - : this.signatures.deliverySignature; + const signatureName = this.signature.signature const hash = md5(signatureName.toString()).substring(0, 3); const file = `${config.storage.root}/${hash}/${signatureName}.png`; - if (!fs.existsSync(file)) return null; return `data:image/png;base64, ${Buffer.from(fs.readFileSync(file), 'utf8').toString('base64')}`; + }, + async getStamp() { + const data = this.data.stamp.toString('base64'); + return `data:image/png;base64, ${data}`; } - } + }, }; \ No newline at end of file diff --git a/print/templates/reports/cmr/sql/data.sql b/print/templates/reports/cmr/sql/data.sql index e66ab7154..41ebee4bb 100644 --- a/print/templates/reports/cmr/sql/data.sql +++ b/print/templates/reports/cmr/sql/data.sql @@ -31,7 +31,8 @@ SELECT c.id cmrFk, a2.street loadStreet, a2.postalCode loadPostalCode, a2.city loadCity, - cou4.country loadCountry + cou4.country loadCountry, + co.stamp FROM cmr c LEFT JOIN supplier s ON s.id = c.supplierFk LEFT JOIN country cou ON cou.id = s.countryFk diff --git a/print/templates/reports/cmr/sql/signature.sql b/print/templates/reports/cmr/sql/signature.sql new file mode 100644 index 000000000..7ec7380a5 --- /dev/null +++ b/print/templates/reports/cmr/sql/signature.sql @@ -0,0 +1,5 @@ +SELECT dc.id `signature` + FROM ticket t + JOIN ticketDms dt ON dt.ticketFk = t.id + LEFT JOIN dms dc ON dc.id = dt.dmsFk + WHERE t.id = ? \ No newline at end of file diff --git a/print/templates/reports/cmr/sql/signatures.sql b/print/templates/reports/cmr/sql/signatures.sql deleted file mode 100644 index c90d4c91c..000000000 --- a/print/templates/reports/cmr/sql/signatures.sql +++ /dev/null @@ -1,7 +0,0 @@ -SELECT dc.id clientSignature, dd.id deliverySignature - FROM ticket t - JOIN ticketDms dt ON dt.ticketFk = t.id - LEFT JOIN dms dc ON dc.id = dt.dmsFk - JOIN `route` r ON r.id = t.routeFk - LEFT JOIN dms dd ON dd.id = r.deliverySignFk - WHERE t.id = ? \ No newline at end of file From 3e8bb221e036e66add3b0b09a107d489ec0ad526 Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Wed, 2 Aug 2023 09:29:09 +0200 Subject: [PATCH 15/32] refs #5762 Securify fix for recovery url --- back/models/vn-user.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/back/models/vn-user.js b/back/models/vn-user.js index 163649718..3e4a08b6e 100644 --- a/back/models/vn-user.js +++ b/back/models/vn-user.js @@ -98,14 +98,22 @@ module.exports = function(Self) { const headers = httpRequest.headers; const origin = headers.origin; + const defaultHash = '/reset-password?access_token=$token$'; + const recoverHashes = { + hedera: 'verificationToken=$token$' + }; + + // FIXME: Change with: info.options?.app + const app = info.options?.directory; + let recoverHash = app ? recoverHashes[app] : defaultHash; + recoverHash = recoverHash.replace('$token$', info.accessToken.id); + const user = await Self.app.models.VnUser.findById(info.user.id); - let directory = info.options?.directory ?? '/#!/reset-password?access_token=$token$'; - directory = directory.replace('$token$', info.accessToken.id); const params = { recipient: info.email, lang: user.lang, - url: origin + directory + url: origin + '/#!' + recoverHash }; const options = Object.assign({}, info.options); From 4a0b8f37cd02b23637cc9eebb255e949196633ab Mon Sep 17 00:00:00 2001 From: guillermo Date: Wed, 2 Aug 2023 13:41:44 +0200 Subject: [PATCH 16/32] refs #5995 Load blob --- modules/route/back/models/route.js | 2 +- print/templates/reports/cmr/cmr.html | 4 ++-- print/templates/reports/cmr/cmr.js | 17 +++++++++++------ print/templates/reports/cmr/sql/data.sql | 3 ++- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/modules/route/back/models/route.js b/modules/route/back/models/route.js index 96e7ed04f..a8d44cd05 100644 --- a/modules/route/back/models/route.js +++ b/modules/route/back/models/route.js @@ -29,5 +29,5 @@ module.exports = Self => { const routeMaxKm = 1000; if (routeTotalKm > routeMaxKm || this.kmStart > this.kmEnd) err(); - } + }; }; diff --git a/print/templates/reports/cmr/cmr.html b/print/templates/reports/cmr/cmr.html index b403cc6d8..ba0f8bfab 100644 --- a/print/templates/reports/cmr/cmr.html +++ b/print/templates/reports/cmr/cmr.html @@ -180,7 +180,7 @@
- +
@@ -191,7 +191,7 @@
- Aquí va la el stamp +
diff --git a/print/templates/reports/cmr/cmr.js b/print/templates/reports/cmr/cmr.js index ea9dc2a70..c939e5152 100644 --- a/print/templates/reports/cmr/cmr.js +++ b/print/templates/reports/cmr/cmr.js @@ -3,6 +3,8 @@ const vnReport = require('../../../core/mixins/vn-report.js'); const md5 = require('md5'); const fs = require('fs-extra'); +const prefixBase64 = 'data:image/png;base64,'; + module.exports = { name: 'cmr', mixins: [vnReport], @@ -13,6 +15,13 @@ module.exports = { this.signature = await this.findOneFromDef('signature', [this.data.ticketFk]); } else this.merchandises = null; + + this.senderStamp = (this.data.senderStamp) + ? `${prefixBase64} ${this.data.senderStamp.toString('base64')}` + : null; + this.deliveryStamp = (this.data.deliveryStamp) + ? `${prefixBase64} ${this.data.deliveryStamp.toString('base64')}` + : null; }, props: { id: { @@ -30,11 +39,7 @@ module.exports = { const file = `${config.storage.root}/${hash}/${signatureName}.png`; if (!fs.existsSync(file)) return null; - return `data:image/png;base64, ${Buffer.from(fs.readFileSync(file), 'utf8').toString('base64')}`; + return `${prefixBase64} ${Buffer.from(fs.readFileSync(file), 'utf8').toString('base64')}`; }, - async getStamp() { - const data = this.data.stamp.toString('base64'); - return `data:image/png;base64, ${data}`; - } - }, + } }; \ No newline at end of file diff --git a/print/templates/reports/cmr/sql/data.sql b/print/templates/reports/cmr/sql/data.sql index 41ebee4bb..d7c585f22 100644 --- a/print/templates/reports/cmr/sql/data.sql +++ b/print/templates/reports/cmr/sql/data.sql @@ -32,7 +32,8 @@ SELECT c.id cmrFk, a2.postalCode loadPostalCode, a2.city loadCity, cou4.country loadCountry, - co.stamp + co.stamp senderStamp, + s.stamp deliveryStamp FROM cmr c LEFT JOIN supplier s ON s.id = c.supplierFk LEFT JOIN country cou ON cou.id = s.countryFk From aab0771e6ed5fe2e8393bf1b91ad0c4fcf8e4eb0 Mon Sep 17 00:00:00 2001 From: guillermo Date: Wed, 2 Aug 2023 14:37:38 +0200 Subject: [PATCH 17/32] refs #5995 Removed my code in closure.js --- modules/ticket/back/methods/ticket/closure.js | 33 +------------------ 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/modules/ticket/back/methods/ticket/closure.js b/modules/ticket/back/methods/ticket/closure.js index 493a2c3a0..9f9aec9bd 100644 --- a/modules/ticket/back/methods/ticket/closure.js +++ b/modules/ticket/back/methods/ticket/closure.js @@ -120,38 +120,7 @@ module.exports = async function(ctx, Self, tickets, reqArgs = {}) { await Self.rawSql(` INSERT INTO clientSample (clientFk, typeFk, companyFk) VALUES(?, ?, ?) `, [ticket.clientFk, sample.id, ticket.companyFk], {userId}); - } - - await Self.rawSql(` - INSERT INTO cmr (ticketFk, companyFk, addressToFk, addressFromFk, supplierFk, ead) - SELECT t.id, - com.id, - a.id, - c2.defaultAddressFk, - su.id, - t.landed - FROM ticket t - JOIN ticketState ts ON ts.ticketFk = t.id - JOIN state s ON s.id = ts.stateFk - JOIN alertLevel al ON al.id = s.alertLevel - JOIN client c ON c.id = t.clientFk - JOIN address a ON a.id = t.addressFk - JOIN province p ON p.id = a.provinceFk - JOIN country co ON co.id = p.countryFk - JOIN agencyMode am ON am.id = t.agencyModeFk - JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk - JOIN warehouse w ON w.id = t.warehouseFk - JOIN company com ON com.id = t.companyFk - JOIN client c2 ON c2.id = com.clientFk - JOIN supplierAccount sa ON sa.id = com.supplierAccountFk - JOIN supplier su ON su.id = sa.supplierFk - WHERE shipped BETWEEN util.yesterday() AND util.dayEnd(util.yesterday()) - AND al.code IN ('PACKED', 'DELIVERED') - AND co.code <> 'ES' - AND am.name <> 'ABONO' - AND w.code = 'ALG' - AND dm.code = 'DELIVERY' - `); + }; } catch (error) { // Domain not found if (error.responseCode == 450) From 688a72ddb300f0fb2c8be3d9b944da29173674f9 Mon Sep 17 00:00:00 2001 From: guillermo Date: Thu, 3 Aug 2023 08:39:37 +0200 Subject: [PATCH 18/32] refs #5995 Modify sql --- print/templates/reports/cmr/cmr.html | 2 +- print/templates/reports/cmr/sql/data.sql | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/print/templates/reports/cmr/cmr.html b/print/templates/reports/cmr/cmr.html index ba0f8bfab..c6a9e79d6 100644 --- a/print/templates/reports/cmr/cmr.html +++ b/print/templates/reports/cmr/cmr.html @@ -202,7 +202,7 @@
- +
diff --git a/print/templates/reports/cmr/sql/data.sql b/print/templates/reports/cmr/sql/data.sql index d7c585f22..9708c4483 100644 --- a/print/templates/reports/cmr/sql/data.sql +++ b/print/templates/reports/cmr/sql/data.sql @@ -1,5 +1,5 @@ SELECT c.id cmrFk, - c.ticketFk, + t.id ticketFk, c.truckPlate, c.observations, c.senderInstruccions, @@ -48,4 +48,5 @@ SELECT c.id cmrFk, LEFT JOIN `address` a2 ON a2.id = c.addressFromFk LEFT JOIN province p2 ON p2.id = a2.provinceFk LEFT JOIN country cou4 ON cou4.id = p2.countryFk + LEFT JOIN ticket t ON t.cmrFk = c.id WHERE c.id = ? \ No newline at end of file From 9b114796756bc2509e17337105dbb7931a2d1c82 Mon Sep 17 00:00:00 2001 From: carlossa Date: Thu, 3 Aug 2023 10:10:53 +0200 Subject: [PATCH 19/32] refs #5640 traducciones --- loopback/locale/es.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 784ff5e6e..7be7e3c34 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -305,5 +305,14 @@ "The renew period has not been exceeded": "El periodo de renovación no ha sido superado", "Valid priorities": "Prioridades válidas: %d", "Negative basis of tickets": "Base negativa para los tickets: {{ticketsIds}}", - "You cannot assign an alias that you are not assigned to": "No puede asignar un alias que no tenga asignado" + "You cannot assign an alias that you are not assigned to": "No puede asignar un alias que no tenga asignado", + "The company has not informed the supplier account for bank transfers": "La empresa no tiene informado la cuenta de proveedor para transferencias bancarias", + "You cannot assign/remove an alias that you are not assigned to": "No puede asignar/eliminar un alias que no tenga asignado", + "This invoice has a linked vehicle.": "Esta factura tiene un vehiculo vinculado", + "You don't have enough privileges.": "No tienes suficientes permisos.", + "This ticket is locked.": "Este ticket está bloqueado.", + "This ticket is not editable.": "Este ticket no es editable.", + "The ticket doesn't exist.": "No existe el ticket.", + "Social name should be uppercase": "La razón social debe ir en mayuscula", + "Street should be uppercase": "La dirección fiscal debe ir en mayúscula" } From b85023b46d0f5fae9cf09eb41f371c0784092ce8 Mon Sep 17 00:00:00 2001 From: carlossa Date: Thu, 3 Aug 2023 10:11:17 +0200 Subject: [PATCH 20/32] accent --- loopback/locale/es.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 7be7e3c34..b69eb1574 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -313,6 +313,6 @@ "This ticket is locked.": "Este ticket está bloqueado.", "This ticket is not editable.": "Este ticket no es editable.", "The ticket doesn't exist.": "No existe el ticket.", - "Social name should be uppercase": "La razón social debe ir en mayuscula", + "Social name should be uppercase": "La razón social debe ir en mayúscula", "Street should be uppercase": "La dirección fiscal debe ir en mayúscula" } From 3388fd7c59249a08635bac6268352e17417a9557 Mon Sep 17 00:00:00 2001 From: carlossa Date: Thu, 3 Aug 2023 10:26:29 +0200 Subject: [PATCH 21/32] fix test back --- modules/worker/back/methods/worker/specs/new.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/worker/back/methods/worker/specs/new.spec.js b/modules/worker/back/methods/worker/specs/new.spec.js index 4dc6c5540..d0830b00f 100644 --- a/modules/worker/back/methods/worker/specs/new.spec.js +++ b/modules/worker/back/methods/worker/specs/new.spec.js @@ -21,8 +21,8 @@ describe('Worker new', () => { const defaultWorker = { fi: '78457139E', name: 'DEFAULTERWORKER', - firstName: 'default', - lastNames: 'worker', + firstName: 'DEFAULT', + lastNames: 'WORKER', email: 'defaultWorker@mydomain.com', street: 'S/ DEFAULTWORKERSTREET', city: 'defaultWorkerCity', From 83d0a394e359a976d286b0ab6c72bdbbd1cc7033 Mon Sep 17 00:00:00 2001 From: alexm Date: Thu, 3 Aug 2023 15:59:09 +0200 Subject: [PATCH 22/32] refs #5973 refactor(item_fetched-tags): restyle empty tags --- modules/item/front/fetched-tags/index.html | 28 +++++++++++----------- modules/item/front/fetched-tags/style.scss | 14 +++++------ 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/modules/item/front/fetched-tags/index.html b/modules/item/front/fetched-tags/index.html index 472fa676b..df5936871 100644 --- a/modules/item/front/fetched-tags/index.html +++ b/modules/item/front/fetched-tags/index.html @@ -1,40 +1,40 @@ - -
+
{{::$ctrl.item.value5}}
-
{{::$ctrl.item.value6}}
-
{{::$ctrl.item.value7}}
-
{{::$ctrl.item.value8}}
-
{{::$ctrl.item.value9}}
-
{{::$ctrl.item.value10}}
- \ No newline at end of file + diff --git a/modules/item/front/fetched-tags/style.scss b/modules/item/front/fetched-tags/style.scss index 2cd7afbb2..250ca07ab 100644 --- a/modules/item/front/fetched-tags/style.scss +++ b/modules/item/front/fetched-tags/style.scss @@ -28,7 +28,7 @@ vn-fetched-tags { & > vn-horizontal { align-items: center; - + max-width: 210px; & > vn-auto { flex-wrap: wrap; @@ -43,19 +43,19 @@ vn-fetched-tags { & > .inline-tag { color: $color-font-secondary; text-align: center; - font-size: .75rem; - height: 12px; + font-size: .8rem; + height: 13px; padding: 1px; width: 64px; min-width: 64px; max-width: 64px; flex: 1; - border: 1px solid $color-spacer; - + border: 1px solid $color-font-secondary; + &.empty { - border: 1px solid $color-spacer-light; + border: 1px solid darken($color-font-secondary, 30%); } } } } -} \ No newline at end of file +} From 4c199f66b2641d76c8154844551d07c98cf61fe3 Mon Sep 17 00:00:00 2001 From: alexm Date: Fri, 4 Aug 2023 14:33:38 +0200 Subject: [PATCH 23/32] refs #5762 refactor: recoverPassword use app param --- back/methods/vn-user/recover-password.js | 6 +++--- back/models/vn-user.js | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/back/methods/vn-user/recover-password.js b/back/methods/vn-user/recover-password.js index b5d183ba3..b0f7122b4 100644 --- a/back/methods/vn-user/recover-password.js +++ b/back/methods/vn-user/recover-password.js @@ -9,7 +9,7 @@ module.exports = Self => { required: true }, { - arg: 'directory', + arg: 'app', type: 'string', description: 'The directory for mail' } @@ -20,7 +20,7 @@ module.exports = Self => { } }); - Self.recoverPassword = async function(user, directory) { + Self.recoverPassword = async function(user, app) { const models = Self.app.models; const usesEmail = user.indexOf('@') !== -1; @@ -34,7 +34,7 @@ module.exports = Self => { } try { - await Self.resetPassword({email: user, emailTemplate: 'recover-password', directory}); + await Self.resetPassword({email: user, emailTemplate: 'recover-password', app}); } catch (err) { if (err.code === 'EMAIL_NOT_FOUND') return; diff --git a/back/models/vn-user.js b/back/models/vn-user.js index 7b919ec29..cf210b61b 100644 --- a/back/models/vn-user.js +++ b/back/models/vn-user.js @@ -101,8 +101,7 @@ module.exports = function(Self) { hedera: 'verificationToken=$token$' }; - // FIXME: Change with: info.options?.app - const app = info.options?.directory; + const app = info.options?.app; let recoverHash = app ? recoverHashes[app] : defaultHash; recoverHash = recoverHash.replace('$token$', info.accessToken.id); From 4191d2529d10ca3b40771801f06349b6d6cf698c Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 7 Aug 2023 07:57:38 +0200 Subject: [PATCH 24/32] refs #5712 warnFix: getById condition --- modules/worker/back/methods/worker-dms/filter.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/worker/back/methods/worker-dms/filter.js b/modules/worker/back/methods/worker-dms/filter.js index 5f55f1bd7..9d8554484 100644 --- a/modules/worker/back/methods/worker-dms/filter.js +++ b/modules/worker/back/methods/worker-dms/filter.js @@ -71,8 +71,9 @@ module.exports = Self => { 'Stored on': 'created', 'Document ID': 'id' }; + workerDocuware = - await models.Docuware.getById('hr', worker.lastName + worker.firstName, docuwareParse) ?? []; + await models.Docuware.getById('hr', worker.lastName + ' ' + worker.firstName, docuwareParse) ?? []; for (document of workerDocuware) { const defaultData = { file: 'dw' + document.id + '.png', From 26d6bbff4cb792592dc18973ca856433715acbf3 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 7 Aug 2023 10:04:46 +0200 Subject: [PATCH 25/32] refs #5929 hotFix: add UserError --- modules/ticket/back/methods/ticket/componentUpdate.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/modules/ticket/back/methods/ticket/componentUpdate.js b/modules/ticket/back/methods/ticket/componentUpdate.js index b5ff50d59..8aad8959b 100644 --- a/modules/ticket/back/methods/ticket/componentUpdate.js +++ b/modules/ticket/back/methods/ticket/componentUpdate.js @@ -1,4 +1,5 @@ const loggable = require('vn-loopback/util/log'); +const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { Self.remoteMethodCtx('componentUpdate', { @@ -112,7 +113,6 @@ module.exports = Self => { } try { - const userId = ctx.req.accessToken.userId; const models = Self.app.models; const $t = ctx.req.__; // $translate await models.Ticket.isEditableOrThrow(ctx, args.id, myOptions); @@ -127,11 +127,8 @@ module.exports = Self => { args.warehouseFk, myOptions); - if (!zoneShipped || zoneShipped.zoneFk != args.zoneFk) { - const error = `You don't have privileges to change the zone`; - - throw new UserError(error); - } + if (!zoneShipped || zoneShipped.zoneFk != args.zoneFk) + throw new UserError(`You don't have privileges to change the zone`); } if (args.isWithoutNegatives) { From abd6045bf681127d29506a62642fd863cef3039a Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 7 Aug 2023 13:52:46 +0200 Subject: [PATCH 26/32] warnFix: revert(version): remove changelog and change package.json --- CHANGELOG.md | 8 -------- db/changes/233401/.gitkeep | 0 package.json | 2 +- 3 files changed, 1 insertion(+), 9 deletions(-) delete mode 100644 db/changes/233401/.gitkeep diff --git a/CHANGELOG.md b/CHANGELOG.md index 80d8517de..6399235de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,14 +5,6 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [2334.01] - 2023-08-24 - -### Added - -### Changed - -### Fixed - ## [2332.01] - 2023-08-09 diff --git a/db/changes/233401/.gitkeep b/db/changes/233401/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/package.json b/package.json index 2aa37379e..37e39d5a5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "salix-back", - "version": "23.34.01", + "version": "23.32.01", "author": "Verdnatura Levante SL", "description": "Salix backend", "license": "GPL-3.0", From bf5b421a4312d5473082fd68c5c847303d4a2d63 Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 8 Aug 2023 08:39:13 +0200 Subject: [PATCH 27/32] refs #5976 warnFix(client_create): socialName to upperCase --- db/changes/233202/00-client_create_upper.sql | 87 ++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 db/changes/233202/00-client_create_upper.sql diff --git a/db/changes/233202/00-client_create_upper.sql b/db/changes/233202/00-client_create_upper.sql new file mode 100644 index 000000000..d5d7258a1 --- /dev/null +++ b/db/changes/233202/00-client_create_upper.sql @@ -0,0 +1,87 @@ +DELIMITER $$ +CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`client_create`( + vFirstname VARCHAR(50), + vSurnames VARCHAR(50), + vFi VARCHAR(9), + vAddress TEXT, + vPostcode CHAR(5), + vCity VARCHAR(25), + vProvinceFk SMALLINT(5), + vCompanyFk SMALLINT(5), + vPhone VARCHAR(11), + vEmail VARCHAR(255), + vUserFk INT +) +BEGIN +/** + * Create new client + * + * @params vFirstname firstName + * @params vSurnames surnames + * @params vFi company code from accounting transactions + * @params vAddress address + * @params vPostcode postCode + * @params vCity city + * @params vProvinceFk province + * @params vCompanyFk company in which he has become a client + * @params vPhone telephone number + * @params vEmail email address + * @params vUserFk user id + */ + DECLARE vPayMethodFk INT; + DECLARE vDueDay INT; + DECLARE vDefaultCredit DECIMAL(10, 2); + DECLARE vIsTaxDataChecked TINYINT(1); + DECLARE vHasCoreVnl BOOLEAN; + DECLARE vMandateTypeFk INT; + + SELECT defaultPayMethodFk, + defaultDueDay, + defaultCredit, + defaultIsTaxDataChecked, + defaultHasCoreVnl, + defaultMandateTypeFk + INTO vPayMethodFk, + vDueDay, + vDefaultCredit, + vIsTaxDataChecked, + vHasCoreVnl, + vMandateTypeFk + FROM clientConfig; + + INSERT INTO `client` + SET id = vUserFk, + name = CONCAT(vFirstname, ' ', vSurnames), + street = vAddress, + fi = TRIM(vFi), + phone = vPhone, + email = vEmail, + provinceFk = vProvinceFk, + city = vCity, + postcode = vPostcode, + socialName = UPPER(CONCAT(vSurnames, ' ', vFirstname)), + payMethodFk = vPayMethodFk, + dueDay = vDueDay, + credit = vDefaultCredit, + isTaxDataChecked = vIsTaxDataChecked, + hasCoreVnl = vHasCoreVnl, + isEqualizated = FALSE + ON duplicate KEY UPDATE + payMethodFk = vPayMethodFk, + dueDay = vDueDay, + credit = vDefaultCredit, + isTaxDataChecked = vIsTaxDataChecked, + hasCoreVnl = vHasCoreVnl, + isActive = TRUE; + + INSERT INTO mandate (clientFk, companyFk, mandateTypeFk) + SELECT vUserFk, vCompanyFk, vMandateTypeFk + WHERE NOT EXISTS ( + SELECT id + FROM mandate + WHERE clientFk = vUserFk + AND companyFk = vCompanyFk + AND mandateTypeFk = vMandateTypeFk + ); +END$$ +DELIMITER ; From 61e3b71bbf7f51b22686f6e49c46b2a5a7069687 Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 8 Aug 2023 08:51:03 +0200 Subject: [PATCH 28/32] init version 233401 after revert(version) in test --- CHANGELOG.md | 9 +++++++++ db/changes/233401/.gitkeep | 0 package.json | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 db/changes/233401/.gitkeep diff --git a/CHANGELOG.md b/CHANGELOG.md index 6399235de..15fe58d7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2334.01] - 2023-08-24 + +### Added + +### Changed + +### Fixed + + ## [2332.01] - 2023-08-09 ### Added diff --git a/db/changes/233401/.gitkeep b/db/changes/233401/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/package.json b/package.json index 37e39d5a5..2aa37379e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "salix-back", - "version": "23.32.01", + "version": "23.34.01", "author": "Verdnatura Levante SL", "description": "Salix backend", "license": "GPL-3.0", From c5e853b028651db9c94d1467e479cae317c6e91d Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 8 Aug 2023 13:35:36 +0200 Subject: [PATCH 29/32] refs #5976 correct sql folder --- db/changes/{233001 => 233401}/00-setDeleted_acl.sql | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename db/changes/{233001 => 233401}/00-setDeleted_acl.sql (100%) diff --git a/db/changes/233001/00-setDeleted_acl.sql b/db/changes/233401/00-setDeleted_acl.sql similarity index 100% rename from db/changes/233001/00-setDeleted_acl.sql rename to db/changes/233401/00-setDeleted_acl.sql From 19c09d60a237377f337be9e98483663d0962c049 Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 8 Aug 2023 15:04:21 +0200 Subject: [PATCH 30/32] refs #5986 feat(ticket_filter): add classColor column --- modules/ticket/back/methods/ticket/filter.js | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/ticket/back/methods/ticket/filter.js b/modules/ticket/back/methods/ticket/filter.js index ea77b7677..eb3da39af 100644 --- a/modules/ticket/back/methods/ticket/filter.js +++ b/modules/ticket/back/methods/ticket/filter.js @@ -248,6 +248,7 @@ module.exports = Self => { am.name AS agencyMode, am.id AS agencyModeFk, st.name AS state, + st.classColor, wk.lastName AS salesPerson, ts.stateFk AS stateFk, ts.alertLevel AS alertLevel, From ce78fc8e5dd383b3c6457fe5f78a45b21b246858 Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 8 Aug 2023 15:06:28 +0200 Subject: [PATCH 31/32] refs #5986 feat: state model add classColor properties --- modules/ticket/back/models/state.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/ticket/back/models/state.json b/modules/ticket/back/models/state.json index 9d4dd4f5d..8b7eb69c6 100644 --- a/modules/ticket/back/models/state.json +++ b/modules/ticket/back/models/state.json @@ -27,6 +27,9 @@ "code": { "type": "string", "required": false + }, + "classColor": { + "type": "string" } } } From afc0c980650db7633ad07477dd504dffd2d14d1b Mon Sep 17 00:00:00 2001 From: alexm Date: Thu, 10 Aug 2023 11:05:37 +0200 Subject: [PATCH 32/32] Merge branch 'test' of https://gitea.verdnatura.es/verdnatura/salix into dev --- CHANGELOG.md | 5 +- db/changes/233202/00-ticketSmsACL.sql | 3 + modules/client/front/sms/index.html | 4 +- .../back/methods/route/getExternalCmrs.js | 133 ++++++++++++++++++ modules/route/back/models/route.js | 1 + modules/ticket/front/index.js | 1 + modules/ticket/front/routes.json | 12 +- modules/ticket/front/sms/index.html | 2 + modules/ticket/front/sms/index.js | 21 +++ package-lock.json | 2 +- 10 files changed, 179 insertions(+), 5 deletions(-) create mode 100644 db/changes/233202/00-ticketSmsACL.sql create mode 100644 modules/route/back/methods/route/getExternalCmrs.js create mode 100644 modules/ticket/front/sms/index.html create mode 100644 modules/ticket/front/sms/index.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 15fe58d7f..1f3570932 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,17 +15,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -## [2332.01] - 2023-08-09 +## [2332.01] - 2023-08-10 ### Added - (Trabajadores -> Gestión documental) Soporte para Docuware - (General -> Agencia) Soporte para Viaexpress +- (Tickets -> SMS) Nueva sección en Lilium ### Changed - (General -> Tickets) Devuelve el motivo por el cual no es editable - (Desplegables -> Trabajadores) Mejorados +- (General -> Clientes) Razón social y dirección en mayúsculas ### Fixed +- (Clientes -> SMS) Al pasar el ratón por encima muestra el mensaje completo ## [2330.01] - 2023-07-27 diff --git a/db/changes/233202/00-ticketSmsACL.sql b/db/changes/233202/00-ticketSmsACL.sql new file mode 100644 index 000000000..a25a876f8 --- /dev/null +++ b/db/changes/233202/00-ticketSmsACL.sql @@ -0,0 +1,3 @@ +INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId) + VALUES + ('TicketSms', 'find', 'READ', 'ALLOW', 'ROLE', 'salesPerson'); diff --git a/modules/client/front/sms/index.html b/modules/client/front/sms/index.html index 9abadd312..e2bc0785e 100644 --- a/modules/client/front/sms/index.html +++ b/modules/client/front/sms/index.html @@ -8,7 +8,7 @@ auto-load="true"> - + @@ -27,7 +27,7 @@ {{::clientSms.sms.destination}} - {{::clientSms.sms.message}} + {{::clientSms.sms.message}} {{::clientSms.sms.status}} {{::clientSms.sms.created | date:'dd/MM/yyyy HH:mm'}} diff --git a/modules/route/back/methods/route/getExternalCmrs.js b/modules/route/back/methods/route/getExternalCmrs.js new file mode 100644 index 000000000..5b08cf34a --- /dev/null +++ b/modules/route/back/methods/route/getExternalCmrs.js @@ -0,0 +1,133 @@ +const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; +const buildFilter = require('vn-loopback/util/filter').buildFilter; +const mergeFilters = require('vn-loopback/util/filter').mergeFilters; + +module.exports = Self => { + Self.remoteMethod('getExternalCmrs', { + description: 'Returns an array of external cmrs', + accessType: 'READ', + accepts: [ + { + arg: 'filter', + type: 'object', + description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string', + }, + { + arg: 'cmrFk', + type: 'integer', + description: 'Searchs the route by id', + }, + { + arg: 'ticketFk', + type: 'integer', + description: 'The worker id', + }, + { + arg: 'country', + type: 'string', + description: 'The agencyMode id', + }, + { + arg: 'clientFk', + type: 'integer', + description: 'The vehicle id', + }, + { + arg: 'hasCmrDms', + type: 'boolean', + description: 'The vehicle id', + }, + { + arg: 'shipped', + type: 'date', + description: 'The to date filter', + }, + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: `/getExternalCmrs`, + verb: 'GET' + } + }); + + Self.getExternalCmrs = async( + filter, + cmrFk, + ticketFk, + country, + clientFk, + hasCmrDms, + shipped, + options + ) => { + const params = { + cmrFk, + ticketFk, + country, + clientFk, + hasCmrDms, + shipped, + }; + const conn = Self.dataSource.connector; + + let where = buildFilter(params, (param, value) => {return {[param]: value}}); + filter = mergeFilters(filter, {where}); + + if (!filter.where) { + const yesterday = new Date(); + yesterday.setDate(yesterday.getDate() - 1); + filter.where = {'shipped': yesterday.toISOString().split('T')[0]} + } + + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + let stmts = []; + const stmt = new ParameterizedSQL(` + SELECT * + FROM ( + SELECT t.cmrFk, + t.id ticketFk, + co.country, + t.clientFk, + sub.id hasCmrDms, + DATE(t.shipped) shipped + FROM ticket t + JOIN ticketState ts ON ts.ticketFk = t.id + JOIN state s ON s.id = ts.stateFk + JOIN alertLevel al ON al.id = s.alertLevel + JOIN client c ON c.id = t.clientFk + JOIN address a ON a.id = t.addressFk + JOIN province p ON p.id = a.provinceFk + JOIN country co ON co.id = p.countryFk + JOIN agencyMode am ON am.id = t.agencyModeFk + JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk + JOIN warehouse w ON w.id = t.warehouseFk + LEFT JOIN ( + SELECT td.ticketFk, d.id + FROM ticketDms td + JOIN dms d ON d.id = td.dmsFk + JOIN dmsType dt ON dt.id = d.dmsTypeFk + WHERE dt.name = 'cmr' + ) sub ON sub.ticketFk = t.id + WHERE co.code <> 'ES' + AND am.name <> 'ABONO' + AND w.code = 'ALG' + AND dm.code = 'DELIVERY' + AND t.cmrFk + ) sub + `); + + stmt.merge(conn.makeSuffix(filter)); + const itemsIndex = stmts.push(stmt) - 1; + + const sql = ParameterizedSQL.join(stmts, ';'); + const result = await conn.executeStmt(sql); + return itemsIndex === 0 ? result : result[itemsIndex]; + }; +}; diff --git a/modules/route/back/models/route.js b/modules/route/back/models/route.js index a8d44cd05..7e61acf25 100644 --- a/modules/route/back/models/route.js +++ b/modules/route/back/models/route.js @@ -15,6 +15,7 @@ module.exports = Self => { require('../methods/route/sendSms')(Self); require('../methods/route/downloadZip')(Self); require('../methods/route/cmr')(Self); + require('../methods/route/getExternalCmrs')(Self); Self.validate('kmStart', validateDistance, { message: 'Distance must be lesser than 1000' diff --git a/modules/ticket/front/index.js b/modules/ticket/front/index.js index 029dc16a4..d805cb0f8 100644 --- a/modules/ticket/front/index.js +++ b/modules/ticket/front/index.js @@ -36,3 +36,4 @@ import './future'; import './future-search-panel'; import './advance'; import './advance-search-panel'; +import './sms'; diff --git a/modules/ticket/front/routes.json b/modules/ticket/front/routes.json index c86b3a1ef..e403ab02d 100644 --- a/modules/ticket/front/routes.json +++ b/modules/ticket/front/routes.json @@ -26,7 +26,8 @@ {"state": "ticket.card.components", "icon": "icon-components"}, {"state": "ticket.card.saleTracking", "icon": "assignment"}, {"state": "ticket.card.dms.index", "icon": "cloud_download"}, - {"state": "ticket.card.boxing", "icon": "science"} + {"state": "ticket.card.boxing", "icon": "science"}, + {"state": "ticket.card.sms", "icon": "sms"} ] }, "keybindings": [ @@ -287,6 +288,15 @@ "state": "ticket.advance", "component": "vn-ticket-advance", "description": "Advance tickets" + }, + { + "url": "/sms", + "state": "ticket.card.sms", + "component": "vn-ticket-sms", + "description": "Sms", + "params": { + "ticket": "$ctrl.ticket" + } } ] } diff --git a/modules/ticket/front/sms/index.html b/modules/ticket/front/sms/index.html new file mode 100644 index 000000000..7fb3b870e --- /dev/null +++ b/modules/ticket/front/sms/index.html @@ -0,0 +1,2 @@ + + diff --git a/modules/ticket/front/sms/index.js b/modules/ticket/front/sms/index.js new file mode 100644 index 000000000..69d54aafe --- /dev/null +++ b/modules/ticket/front/sms/index.js @@ -0,0 +1,21 @@ +import ngModule from '../module'; +import Section from 'salix/components/section'; + +class Controller extends Section { + constructor($element, $) { + super($element, $); + } + + async $onInit() { + this.$state.go('ticket.card.summary', {id: this.$params.id}); + window.location.href = await this.vnApp.getUrl(`ticket/${this.$params.id}/sms`); + } +} + +ngModule.vnComponent('vnTicketSms', { + template: require('./index.html'), + controller: Controller, + bindings: { + ticket: '<' + } +}); diff --git a/package-lock.json b/package-lock.json index f87e3f64b..10b5e6b02 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "salix-back", - "version": "23.34.01", + "version": "23.32.02", "lockfileVersion": 2, "requires": true, "packages": {