diff --git a/Dockerfile b/Dockerfile index 5a65b9b18..a574e61fd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ RUN apt-get update \ ca-certificates \ gnupg2 \ libfontconfig \ - && curl -sL https://deb.nodesource.com/setup_10.x | bash - \ + && curl -sL https://deb.nodesource.com/setup_12.x | bash - \ && apt-get install -y --no-install-recommends \ nodejs \ && apt-get purge -y --auto-remove \ diff --git a/README.md b/README.md index 8960c8d00..52f854b6e 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Salix is also the scientific name of a beautifull tree! :) Required applications. * Visual Studio Code -* Node.js = 10.15.3 LTS +* Node.js = 12.17.0 LTS * Docker In Visual Studio Code we use the ESLint extension. Open Visual Studio Code, press Ctrl+P and paste the following command. diff --git a/db/changes/10180-holyWeek/00-ACL.sql b/db/changes/10180-holyWeek/00-ACL.sql new file mode 100644 index 000000000..b0ab68a97 --- /dev/null +++ b/db/changes/10180-holyWeek/00-ACL.sql @@ -0,0 +1 @@ +INSERT IGNORE INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('WorkerLog', '*', 'READ', 'ALLOW', 'ROLE', 'hr'); \ No newline at end of file diff --git a/db/changes/10190-PostErte/00-ACL.sql b/db/changes/10190-PostErte/00-ACL.sql new file mode 100644 index 000000000..2a2673fcc --- /dev/null +++ b/db/changes/10190-PostErte/00-ACL.sql @@ -0,0 +1,4 @@ +UPDATE `salix`.`ACL` SET `accessType`='WRITE' WHERE `id`='213'; + +INSERT IGNORE INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('CustomsAgent', '*', '*', 'ALLOW', 'ROLE', 'employee'); + diff --git a/db/changes/10190-PostErte/00-itemLastEntry.sql b/db/changes/10190-PostErte/00-itemLastEntry.sql new file mode 100644 index 000000000..b293c234e --- /dev/null +++ b/db/changes/10190-PostErte/00-itemLastEntry.sql @@ -0,0 +1,42 @@ + +DROP procedure IF EXISTS `vn`.`itemLastEntries`; + +DELIMITER $$ +CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`itemLastEntries`(IN `vItem` INT, IN `vDays` DATE) +BEGIN + SELECT + w.id AS warehouseFk, + w.name AS warehouse, + tr.landed, + b.entryFk, + b.isIgnored, + b.price2, + b.price3, + b.stickers, + b.packing, + b.`grouping`, + b.groupingMode, + b.weight, + i.stems, + b.quantity, + b.buyingValue, + b.packageFk , + s.id AS supplierFk, + s.name AS supplier + FROM itemType it + RIGHT JOIN (entry e + LEFT JOIN supplier s ON s.id = e.supplierFk + RIGHT JOIN buy b ON b.entryFk = e.id + LEFT JOIN item i ON i.id = b.itemFk + LEFT JOIN ink ON ink.id = i.inkFk + LEFT JOIN travel tr ON tr.id = e.travelFk + LEFT JOIN warehouse w ON w.id = tr.warehouseInFk + LEFT JOIN origin o ON o.id = i.originFk + ) ON it.id = i.typeFk + LEFT JOIN edi.ekt ek ON b.ektFk = ek.id + WHERE b.itemFk = vItem And tr.shipped BETWEEN vDays AND DATE_ADD(CURDATE(), INTERVAl + 10 DAY) + ORDER BY tr.landed DESC , b.id DESC; +END$$ + +DELIMITER ; + diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 21f9a5234..13ac2bcb3 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -1216,23 +1216,23 @@ INSERT INTO `bs`.`waste`(`buyer`, `year`, `week`, `family`, `saleTotal`, `saleWa ('HankPym', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 WEEK)), WEEK(DATE_ADD(CURDATE(), INTERVAL -1 WEEK), 1), 'Miscellaneous Accessories', '186', '0', '0.0'), ('HankPym', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 WEEK)), WEEK(DATE_ADD(CURDATE(), INTERVAL -1 WEEK), 1), 'Adhesives', '277', '0', '0.0'); -INSERT INTO `vn`.`buy`(`id`,`entryFk`,`itemFk`,`buyingValue`,`quantity`,`packageFk`,`stickers`,`freightValue`,`packageValue`,`comissionValue`,`packing`,`grouping`,`groupingMode`,`location`,`price1`,`price2`,`price3`,`minPrice`,`producer`,`printedStickers`,`isChecked`,`isIgnored`, `created`) +INSERT INTO `vn`.`buy`(`id`,`entryFk`,`itemFk`,`buyingValue`,`quantity`,`packageFk`,`stickers`,`freightValue`,`packageValue`,`comissionValue`,`packing`,`grouping`,`groupingMode`,`location`,`price1`,`price2`,`price3`,`minPrice`,`producer`,`printedStickers`,`isChecked`,`isIgnored`,`weight`, `created`) VALUES - (1, 1, 1, 50, 5000, 4, 1, 1.500, 1.500, 0.000, 1, 1, 1, NULL, 0.00, 99.6, 99.4, 0.00, NULL, 0, 1, 0, DATE_ADD(CURDATE(), INTERVAL -2 MONTH)), - (2, 2, 1, 50, 100, 4, 1, 1.500, 1.500, 0.000, 1, 1, 1, NULL, 0.00, 99.6, 99.4, 0.00, NULL, 0, 1, 0, DATE_ADD(CURDATE(), INTERVAL -1 MONTH)), - (3, 3, 1, 50, 100, 4, 1, 1.500, 1.500, 0.000, 1, 1, 0, NULL, 0.00, 99.6, 99.4, 0.00, NULL, 0, 1, 0, CURDATE()), - (4, 2, 2, 5, 450, 3, 1, 1.000, 1.000, 0.000, 10, 10, 0, NULL, 0.00, 7.30, 7.00, 0.00, NULL, 0, 1, 0, CURDATE()), - (5, 3, 3, 55, 500, 5, 1, 1.000, 1.000, 0.000, 1, 1, 0, NULL, 0.00, 78.3, 75.6, 0.00, NULL, 0, 1, 0, CURDATE()), - (6, 4, 8, 50, 1000, 4, 1, 1.000, 1.000, 0.000, 1, 1, 1, NULL, 0.00, 99.6, 99.4, 0.00, NULL, 0, 1, 0, CURDATE()), - (7, 4, 9, 20, 1000, 3, 1, 0.500, 0.500, 0.000, 10, 10, 1, NULL, 0.00, 30.50, 29.00, 0.00, NULL, 0, 1, 0, CURDATE()), - (8, 4, 4, 1.25, 1000, 3, 1, 0.500, 0.500, 0.000, 10, 10, 1, NULL, 0.00, 1.75, 1.67, 0.00, NULL, 0, 1, 0, CURDATE()), - (9, 4, 4, 1.25, 1000, 3, 1, 0.500, 0.500, 0.000, 10, 10, 1, NULL, 0.00, 1.75, 1.67, 0.00, NULL, 0, 1, 0, CURDATE()), - (10, 5, 1, 50, 10, 4, 1, 2.500, 2.500, 0.000, 1, 1, 1, NULL, 0.00, 99.6, 99.4, 0.00, NULL, 0, 1, 0, CURDATE()), - (11, 5, 4, 1.25, 10, 3, 1, 2.500, 2.500, 0.000, 10, 10, 1, NULL, 0.00, 1.75, 1.67, 0.00, NULL, 0, 1, 0, CURDATE()), - (12, 6, 4, 1.25, 0, 3, 1, 2.500, 2.500, 0.000, 10, 10, 1, NULL, 0.00, 1.75, 1.67, 0.00, NULL, 0, 1, 0, CURDATE()), - (13, 7, 1, 50, 0, 3, 1, 2.000, 2.000, 0.000, 1, 1, 1, NULL, 0.00, 99.6, 99.4, 0.00, NULL, 0, 1, 0, CURDATE()), - (14, 7, 2, 5, 0, 3, 1, 2.000, 2.000, 0.000, 10, 10, 1, NULL, 0.00, 7.30, 7.00, 0.00, NULL, 0, 1, 0, CURDATE()), - (15, 7, 4, 1.25, 0, 3, 1, 2.000, 2.000, 0.000, 10, 10, 1, NULL, 0.00, 1.75, 1.67, 0.00, NULL, 0, 1, 0, CURDATE()); + (1, 1, 1, 50, 5000, 4, 1, 1.500, 1.500, 0.000, 1, 1, 1, NULL, 0.00, 99.6, 99.4, 0.00, NULL, 0, 1, 0, 1, DATE_ADD(CURDATE(), INTERVAL -2 MONTH)), + (2, 2, 1, 50, 100, 4, 1, 1.500, 1.500, 0.000, 1, 1, 1, NULL, 0.00, 99.6, 99.4, 0.00, NULL, 0, 1, 0, 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH)), + (3, 3, 1, 50, 100, 4, 1, 1.500, 1.500, 0.000, 1, 1, 0, NULL, 0.00, 99.6, 99.4, 0.00, NULL, 0, 1, 0, 1, CURDATE()), + (4, 2, 2, 5, 450, 3, 1, 1.000, 1.000, 0.000, 10, 10, 0, NULL, 0.00, 7.30, 7.00, 0.00, NULL, 0, 1, 0, 2.5, CURDATE()), + (5, 3, 3, 55, 500, 5, 1, 1.000, 1.000, 0.000, 1, 1, 0, NULL, 0.00, 78.3, 75.6, 0.00, NULL, 0, 1, 0, 2.5, CURDATE()), + (6, 4, 8, 50, 1000, 4, 1, 1.000, 1.000, 0.000, 1, 1, 1, NULL, 0.00, 99.6, 99.4, 0.00, NULL, 0, 1, 0, 2.5, CURDATE()), + (7, 4, 9, 20, 1000, 3, 1, 0.500, 0.500, 0.000, 10, 10, 1, NULL, 0.00, 30.50, 29.00, 0.00, NULL, 0, 1, 0, 2.5, CURDATE()), + (8, 4, 4, 1.25, 1000, 3, 1, 0.500, 0.500, 0.000, 10, 10, 1, NULL, 0.00, 1.75, 1.67, 0.00, NULL, 0, 1, 0, 2.5, CURDATE()), + (9, 4, 4, 1.25, 1000, 3, 1, 0.500, 0.500, 0.000, 10, 10, 1, NULL, 0.00, 1.75, 1.67, 0.00, NULL, 0, 1, 0, 4, CURDATE()), + (10, 5, 1, 50, 10, 4, 1, 2.500, 2.500, 0.000, 1, 1, 1, NULL, 0.00, 99.6, 99.4, 0.00, NULL, 0, 1, 0, 4, CURDATE()), + (11, 5, 4, 1.25, 10, 3, 1, 2.500, 2.500, 0.000, 10, 10, 1, NULL, 0.00, 1.75, 1.67, 0.00, NULL, 0, 1, 0, 4, CURDATE()), + (12, 6, 4, 1.25, 0, 3, 1, 2.500, 2.500, 0.000, 10, 10, 1, NULL, 0.00, 1.75, 1.67, 0.00, NULL, 0, 1, 0, 4, CURDATE()), + (13, 7, 1, 50, 0, 3, 1, 2.000, 2.000, 0.000, 1, 1, 1, NULL, 0.00, 99.6, 99.4, 0.00, NULL, 0, 1, 0, 4, CURDATE()), + (14, 7, 2, 5, 0, 3, 1, 2.000, 2.000, 0.000, 10, 10, 1, NULL, 0.00, 7.30, 7.00, 0.00, NULL, 0, 1, 0, 4, CURDATE()), + (15, 7, 4, 1.25, 0, 3, 1, 2.000, 2.000, 0.000, 10, 10, 1, NULL, 0.00, 1.75, 1.67, 0.00, NULL, 0, 1, 0, 4, CURDATE()); INSERT INTO `hedera`.`order`(`id`, `date_send`, `customer_id`, `delivery_method_id`, `agency_id`, `address_id`, `company_id`, `note`, `source_app`, `confirmed`, `date_make`, `first_row_stamp`, `confirm_date`) VALUES diff --git a/db/tests/vn/ticket_componentMakeUpdate.spec.js b/db/tests/vn/ticket_componentMakeUpdate.spec.js new file mode 100644 index 000000000..4954c44f4 --- /dev/null +++ b/db/tests/vn/ticket_componentMakeUpdate.spec.js @@ -0,0 +1,123 @@ +const app = require('vn-loopback/server/server'); +const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; + +// 2277 solucionar problema al testear procedimiento con start transaction / rollback +xdescribe('ticket_componentMakeUpdate()', () => { + it('should recalculate the ticket components without make modifications', async() => { + let stmts = []; + let stmt; + + let params = { + ticketId: 11, + clientId: 102, + agencyModeId: 2, + addressId: 122, + zoneId: 3, + warehouseId: 1, + companyId: 442, + isDeleted: 0, + hasToBeUnrouted: 0, + componentOption: 1 + }; + + stmts.push('START TRANSACTION'); + + stmt = new ParameterizedSQL('SELECT * FROM vn.ticket WHERE id = ?', [ + params.ticketId + ]); + stmts.push(stmt); + + let originalTicketIndex = stmts.push(stmt) - 1; + + stmt = new ParameterizedSQL('CALL vn.ticket_componentMakeUpdate(?, ?, ?, ?, ?, ?, ?, DATE_ADD(CURDATE(), INTERVAL +1 DAY), DATE_ADD(CURDATE(), INTERVAL +1 DAY), ?, ?, ?)', [ + params.ticketId, + params.clientId, + params.agencyModeId, + params.addressId, + params.zoneId, + params.warehouseId, + params.companyId, + params.isDeleted, + params.hasToBeUnrouted, + params.componentOption + ]); + stmts.push(stmt); + + stmt = new ParameterizedSQL('SELECT * FROM vn.ticket WHERE id = ?', [ + params.ticketId + ]); + stmts.push(stmt); + + let updatedTicketIndex = stmts.push(stmt) - 1; + + stmts.push('ROLLBACK'); + + let sql = ParameterizedSQL.join(stmts, ';'); + let result = await app.models.Ticket.rawStmt(sql); + + let originalTicketData = result[originalTicketIndex]; + let updatedTicketData = result[updatedTicketIndex]; + + expect(originalTicketData[0].isDeleted).toEqual(updatedTicketData[0].isDeleted); + expect(originalTicketData[0].routeFk).toEqual(updatedTicketData[0].routeFk); + }); + + it('should delete and unroute a ticket and recalculate the components', async() => { + let stmts = []; + let stmt; + + let params = { + ticketId: 11, + clientId: 102, + agencyModeId: 2, + addressId: 122, + zoneId: 3, + warehouseId: 1, + companyId: 442, + isDeleted: 1, + hasToBeUnrouted: 1, + componentOption: 1 + }; + + stmts.push('START TRANSACTION'); + + stmt = new ParameterizedSQL('SELECT * FROM vn.ticket WHERE id = ?', [ + params.ticketId + ]); + stmts.push(stmt); + + let originalTicketIndex = stmts.push(stmt) - 1; + + stmt = new ParameterizedSQL('CALL vn.ticket_componentMakeUpdate(?, ?, ?, ?, ?, ?, ?, DATE_ADD(CURDATE(), INTERVAL +1 DAY), DATE_ADD(CURDATE(), INTERVAL +1 DAY), ?, ?, ?)', [ + params.ticketId, + params.clientId, + params.agencyModeId, + params.addressId, + params.zoneId, + params.warehouseId, + params.companyId, + params.isDeleted, + params.hasToBeUnrouted, + params.componentOption + ]); + stmts.push(stmt); + + stmt = new ParameterizedSQL('SELECT * FROM vn.ticket WHERE id = ?', [ + params.ticketId + ]); + stmts.push(stmt); + + let updatedTicketIndex = stmts.push(stmt) - 1; + + stmts.push('ROLLBACK'); + + let sql = ParameterizedSQL.join(stmts, ';'); + let result = await app.models.Ticket.rawStmt(sql); + + let originalTicketData = result[originalTicketIndex]; + let updatedTicketData = result[updatedTicketIndex]; + + expect(originalTicketData[0].isDeleted).not.toEqual(updatedTicketData[0].isDeleted); + expect(originalTicketData[0].routeFk).not.toEqual(updatedTicketData[0].routeFk); + }); +}); diff --git a/db/tests/vn/zone_getEvents.spec.js b/db/tests/vn/zone_getEvents.spec.js new file mode 100644 index 000000000..d31e97c2c --- /dev/null +++ b/db/tests/vn/zone_getEvents.spec.js @@ -0,0 +1,33 @@ +const app = require('vn-loopback/server/server'); +const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; + +describe('zone zone_getEvents()', () => { + it(`should return data for a agencyMode with deliveryMethod pickup`, async() => { + let stmts = []; + let stmt; + + stmts.push('START TRANSACTION'); + + let params = { + zoneGeoFk: 1, + agencyModeFk: 1}; + + stmt = new ParameterizedSQL('CALL zone_getEvents(?, ?)', [ + params.zoneGeoFk, + params.agencyModeFk, + + ]); + stmts.push(stmt); + let firstResultIndex = stmts.push(stmt) - 1; + let secondResultIndex = firstResultIndex + 1; + + stmts.push('ROLLBACK'); + + let sql = ParameterizedSQL.join(stmts, ';'); + let result = await app.models.Ticket.rawStmt(sql); + + let zonesEvents = result[secondResultIndex]; + + expect(zonesEvents.length).toBeGreaterThan(0); + }); +}); diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index ecf0d37e3..b12c470f5 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -122,6 +122,12 @@ export default { mobileInput: 'vn-textfield[ng-model="$ctrl.address.mobile"]', defaultAddress: 'vn-client-address-index div:nth-child(1) div[name="street"]', incoterms: 'vn-autocomplete[ng-model="$ctrl.address.incotermsId"]', + addNewCustomsAgent: 'vn-client-address-create vn-autocomplete[ng-model="$ctrl.address.customsAgentId"] vn-icon-button[icon="add_circle"]', + newCustomsAgentFiscalID: 'vn-textfield[ng-model="$ctrl.newCustomsAgent.nif"]', + newCustomsAgentFiscalName: 'vn-textfield[ng-model="$ctrl.newCustomsAgent.fiscalName"]', + newCustomsAgentStreet: 'vn-textfield[ng-model="$ctrl.newCustomsAgent.street"]', + newCustomsAgentPhone: 'vn-textfield[ng-model="$ctrl.newCustomsAgent.phone"]', + saveNewCustomsAgentButton: 'button[response="accept"]', customsAgent: 'vn-autocomplete[ng-model="$ctrl.address.customsAgentId"]', secondMakeDefaultStar: 'vn-client-address-index vn-card div:nth-child(2) vn-icon-button[icon="star_border"]', firstEditAddress: 'vn-client-address-index div:nth-child(1) > a', @@ -828,6 +834,12 @@ export default { }, travelThermograph: { add: 'vn-travel-thermograph-index vn-float-button[icon="add"]', + addThermographIcon: 'vn-travel-thermograph-create vn-autocomplete vn-icon[icon="add_circle"]', + newThermographId: 'vn-textfield[ng-model="$ctrl.newThermograph.thermographId"]', + newThermographModel: 'vn-autocomplete[ng-model="$ctrl.newThermograph.model"]', + newThermographWarehouse: 'vn-autocomplete[ng-model="$ctrl.newThermograph.warehouseId"]', + newThermographTemperature: 'vn-autocomplete[ng-model="$ctrl.newThermograph.temperature"]', + createThermographButton: 'form button[response="accept"]', thermographID: 'vn-travel-thermograph-create vn-autocomplete[ng-model="$ctrl.dms.thermographId"]', uploadIcon: 'vn-travel-thermograph-create vn-icon[icon="icon-attach"]', createdThermograph: 'vn-travel-thermograph-index vn-tbody > vn-tr', diff --git a/e2e/paths/02-client/05_add_address.spec.js b/e2e/paths/02-client/05_add_address.spec.js index 2fe238fea..f16408b34 100644 --- a/e2e/paths/02-client/05_add_address.spec.js +++ b/e2e/paths/02-client/05_add_address.spec.js @@ -61,12 +61,18 @@ describe('Client Add address path', () => { expect(message.text).toBe('Customs agent is required for a non UEE member'); }); - it(`should create a new address with all it's data`, async() => { - await page.autocompleteSearch(selectors.clientAddresses.customsAgent, 'Agent one'); + it(`should create a new custom agent and then save the address`, async() => { + await page.waitToClick(selectors.clientAddresses.addNewCustomsAgent); + await page.write(selectors.clientAddresses.newCustomsAgentFiscalID, 'ID'); + await page.write(selectors.clientAddresses.newCustomsAgentFiscalName, 'name'); + await page.write(selectors.clientAddresses.newCustomsAgentStreet, 'street'); + await page.write(selectors.clientAddresses.newCustomsAgentPhone, '555555555'); + await page.waitToClick(selectors.clientAddresses.saveNewCustomsAgentButton); + await page.waitToClick(selectors.clientAddresses.saveButton); const message = await page.waitForSnackbar(); - expect(message.type).toBe('success'); + expect(message.text).toBe('Data saved!'); }); it(`should navigate back to the addresses index`, async() => { diff --git a/e2e/paths/10-travel/01_thermograph.spec.js b/e2e/paths/10-travel/01_thermograph.spec.js index 67a62381a..e7f1e234d 100644 --- a/e2e/paths/10-travel/01_thermograph.spec.js +++ b/e2e/paths/10-travel/01_thermograph.spec.js @@ -2,6 +2,7 @@ import selectors from '../../helpers/selectors.js'; import getBrowser from '../../helpers/puppeteer'; describe('Travel thermograph path', () => { + const thermographName = '7H3-37H3RN4L-FL4M3'; let browser; let page; @@ -26,10 +27,18 @@ describe('Travel thermograph path', () => { await page.waitForState('travel.card.thermograph.create'); }); - it('should select the thermograph and then the file to upload', async() => { + it('should click on the add thermograph icon of the thermograph autocomplete', async() => { + await page.waitToClick(selectors.travelThermograph.addThermographIcon); + await page.write(selectors.travelThermograph.newThermographId, thermographName); + await page.autocompleteSearch(selectors.travelThermograph.newThermographModel, 'TEMPMATE'); + await page.autocompleteSearch(selectors.travelThermograph.newThermographWarehouse, 'Warehouse Two'); + await page.autocompleteSearch(selectors.travelThermograph.newThermographTemperature, 'WARM'); + await page.waitToClick(selectors.travelThermograph.createThermographButton); + }); + + it('should select the file to upload', async() => { let currentDir = process.cwd(); let filePath = `${currentDir}/e2e/dms/ecc/3.jpeg`; - await page.autocompleteSearch(selectors.travelThermograph.thermographID, '138350-0'); const [fileChooser] = await Promise.all([ page.waitForFileChooser(), @@ -38,11 +47,17 @@ describe('Travel thermograph path', () => { await fileChooser.accept([filePath]); await page.waitToClick(selectors.travelThermograph.upload); + + const message = await page.waitForSnackbar(); + const state = await page.getState(); + + expect(message.type).toBe('success'); + expect(state).toBe('travel.card.thermograph.index'); }); - it('should reload the section and check everything was saved', async() => { - let createdThermograph = await page.waitToGetProperty(selectors.travelThermograph.createdThermograph, 'innerText'); + it('should check everything was saved correctly', async() => { + const result = await page.waitToGetProperty(selectors.travelThermograph.createdThermograph, 'innerText'); - expect(createdThermograph).toContain('138350-0'); + expect(result).toContain(thermographName); }); }); diff --git a/loopback/common/methods/vn-model/getEnumValues.js b/loopback/common/methods/vn-model/getEnumValues.js new file mode 100644 index 000000000..0bc8f8eb6 --- /dev/null +++ b/loopback/common/methods/vn-model/getEnumValues.js @@ -0,0 +1,55 @@ +const UserError = require('vn-loopback/util/user-error'); + +module.exports = Self => { + /** + * Returns a set of allowed values defined on table scheme + * @param {String} column - Model or Table column name + * @return {Array} - Array of set values + */ + Self.getEnumValues = async function(column) { + let model = this.app.models[this.modelName].definition; + let properties = model.properties; + let tableName = this.modelName; + let schema = null; + + if (model.settings && model.settings.mysql) { + let tableSplit = model.settings.mysql.table.split('.'); + tableName = tableSplit.pop(); + schema = tableSplit.pop() || null; + } + + let property = properties[column]; + + if (!property) + throw new UserError(`Column does not exist`); + + let columnName = property.mysql + ? property.mysql.columnName + : column; + + let columnInfo = await this.rawSql( + `SELECT column_type columnType + FROM information_schema.columns + WHERE table_name = ? + AND table_schema = IFNULL(?, DATABASE()) + AND column_name = ?`, + [tableName, schema, columnName] + ); + + if (!columnInfo || !columnInfo[0]) + throw new UserError(`Cannot fetch column values`); + + let setValues; + setValues = columnInfo[0].columnType + .replace(/^enum\((.*)\)$/i, '$1') + .replace(/'/g, '') + .match(new RegExp(/(\w+)+/, 'ig')); + + let values = []; + setValues.forEach(setValue => { + values.push({value: setValue}); + }); + + return values; + }; +}; diff --git a/loopback/common/methods/vn-model/specs/getEnumValues.spec.js b/loopback/common/methods/vn-model/specs/getEnumValues.spec.js new file mode 100644 index 000000000..b49a952e4 --- /dev/null +++ b/loopback/common/methods/vn-model/specs/getEnumValues.spec.js @@ -0,0 +1,18 @@ +const app = require('vn-loopback/server/server'); + +describe('Model getEnumValues()', () => { + it('should extend getEnumValues properties to any model passed', () => { + let exampleModel = app.models.TravelThermograph; + + expect(exampleModel.getEnumValues).toBeDefined(); + }); + + it('should return an array of enum values from a given column', async() => { + let result = await app.models.TravelThermograph.getSetValues('temperature'); + + expect(result.length).toEqual(3); + expect(result[0].value).toEqual('enum'); + expect(result[1].value).toEqual('COOL'); + expect(result[2].value).toEqual('WARM'); + }); +}); diff --git a/loopback/common/models/loggable.js b/loopback/common/models/loggable.js index d9116a0de..ec6989717 100644 --- a/loopback/common/models/loggable.js +++ b/loopback/common/models/loggable.js @@ -12,23 +12,34 @@ module.exports = function(Self) { }); Self.observe('before save', async function(ctx) { - let options = {}; + const appModels = ctx.Model.app.models; + const definition = ctx.Model.definition; + const options = {}; + + // Check for transactions if (ctx.options && ctx.options.transaction) options.transaction = ctx.options.transaction; let oldInstance; - let oldInstanceFk; let newInstance; if (ctx.data) { - oldInstanceFk = pick(ctx.currentInstance, Object.keys(ctx.data)); + const changes = pick(ctx.currentInstance, Object.keys(ctx.data)); newInstance = await fkToValue(ctx.data, ctx); - oldInstance = await fkToValue(oldInstanceFk, ctx); + oldInstance = await fkToValue(changes, ctx); + if (ctx.where && !ctx.currentInstance) { - let fields = Object.keys(ctx.data); - ctx.oldInstances = await ctx.Model.app.models[ctx.Model.definition.name].find({where: ctx.where, fields: fields}, options); + const fields = Object.keys(ctx.data); + const modelName = definition.name; + + ctx.oldInstances = await appModels[modelName].find({ + where: ctx.where, + fields: fields + }, options); } } + + // Get changes from created instance if (ctx.isNewInstance) newInstance = await fkToValue(ctx.instance.__data, ctx); @@ -37,18 +48,24 @@ module.exports = function(Self) { }); Self.observe('before delete', async function(ctx) { + const appModels = ctx.Model.app.models; + const definition = ctx.Model.definition; + const relations = ctx.Model.relations; + let options = {}; if (ctx.options && ctx.options.transaction) options.transaction = ctx.options.transaction; if (ctx.where) { - let affectedModel = ctx.Model.definition.name; - let definition = ctx.Model.definition; - let deletedInstances = await ctx.Model.app.models[affectedModel].find({where: ctx.where}, options); + let affectedModel = definition.name; + let deletedInstances = await appModels[affectedModel].find({ + where: ctx.where + }, options); + let relation = definition.settings.log.relation; if (relation) { - let primaryKey = ctx.Model.relations[relation].keyFrom; + let primaryKey = relations[relation].keyFrom; let arrangedDeletedInstances = []; for (let i = 0; i < deletedInstances.length; i++) { @@ -69,6 +86,8 @@ module.exports = function(Self) { }); async function logDeletedInstances(ctx, loopBackContext) { + const appModels = ctx.Model.app.models; + const definition = ctx.Model.definition; let options = {}; if (ctx.options && ctx.options.transaction) options.transaction = ctx.options.transaction; @@ -78,14 +97,12 @@ module.exports = function(Self) { if (loopBackContext) userFk = loopBackContext.active.accessToken.userId; - let definition = ctx.Model.definition; - let changedModelValue = definition.settings.log.changedModelValue; let logRecord = { originFk: instance.originFk, userFk: userFk, action: 'delete', - changedModel: ctx.Model.definition.name, + changedModel: definition.name, changedModelId: instance.id, changedModelValue: instance[changedModelValue], oldInstance: instance, @@ -95,26 +112,44 @@ module.exports = function(Self) { delete instance.originFk; let logModel = definition.settings.log.model; - await ctx.Model.app.models[logModel].create(logRecord, options); + await appModels[logModel].create(logRecord, options); }); } + // Get log values from a foreign key async function fkToValue(instance, ctx) { + const appModels = ctx.Model.app.models; + const relations = ctx.Model.relations; let options = {}; + + // Check for transactions if (ctx.options && ctx.options.transaction) options.transaction = ctx.options.transaction; - let cleanInstance = JSON.parse(JSON.stringify(instance)); - let result = {}; - for (let key in cleanInstance) { - let val = cleanInstance[key]; - if (val === undefined || val === null) continue; - for (let key1 in ctx.Model.relations) { - let val1 = ctx.Model.relations[key1]; - if (val1.keyFrom == key && key != 'id') { - let recordSet = await ctx.Model.app.models[val1.modelTo.modelName].findById(val, null, options); + const instanceCopy = JSON.parse(JSON.stringify(instance)); + const result = {}; + for (const key in instanceCopy) { + let value = instanceCopy[key]; + + if (value instanceof Object) + continue; + + if (value === undefined || value === null) continue; + + for (let relationName in relations) { + const relation = relations[relationName]; + if (relation.keyFrom == key && key != 'id') { + const model = relation.modelTo; + const modelName = relation.modelTo.modelName; + const properties = model && model.definition.properties; + const settings = model && model.definition.settings; + + const recordSet = await appModels[modelName].findById(value, null, options); + + const hasShowField = settings.log && settings.log.showField; + let showField = hasShowField && recordSet + && recordSet[settings.log.showField]; - let showField = val1.modelTo && val1.modelTo.definition.settings.log && val1.modelTo.definition.settings.log.showField && recordSet && recordSet[val1.modelTo.definition.settings.log.showField]; if (!showField) { const showFieldNames = [ 'name', @@ -122,7 +157,10 @@ module.exports = function(Self) { 'code' ]; for (field of showFieldNames) { - if (val1.modelTo.definition.properties && val1.modelTo.definition.properties[field] && recordSet && recordSet[field]) { + const propField = properties && properties[field]; + const recordField = recordSet && recordSet[field]; + + if (propField && recordField) { showField = field; break; } @@ -130,25 +168,29 @@ module.exports = function(Self) { } if (showField && recordSet && recordSet[showField]) { - val = recordSet[showField]; + value = recordSet[showField]; break; } - val = recordSet && recordSet.id || val; + value = recordSet && recordSet.id || value; break; } } - result[key] = val; + result[key] = value; } return result; } async function logInModel(ctx, loopBackContext) { - let options = {}; + const appModels = ctx.Model.app.models; + const definition = ctx.Model.definition; + const defSettings = ctx.Model.definition.settings; + const relations = ctx.Model.relations; + + const options = {}; if (ctx.options && ctx.options.transaction) options.transaction = ctx.options.transaction; - let definition = ctx.Model.definition; let primaryKey; for (let property in definition.properties) { if (definition.properties[property].id) { @@ -163,11 +205,11 @@ module.exports = function(Self) { // RELATIONS LOG let changedModelId; - if (ctx.instance && !definition.settings.log.relation) { + if (ctx.instance && !defSettings.log.relation) { originId = ctx.instance.id; changedModelId = ctx.instance.id; - } else if (definition.settings.log.relation) { - primaryKey = ctx.Model.relations[definition.settings.log.relation].keyFrom; + } else if (defSettings.log.relation) { + primaryKey = relations[defSettings.log.relation].keyFrom; if (ctx.where && ctx.where[primaryKey]) originId = ctx.where[primaryKey]; @@ -181,12 +223,16 @@ module.exports = function(Self) { } // Sets the changedModelValue to save and the instances changed in case its an updateAll - let showField = definition.settings.log.showField; + let showField = defSettings.log.showField; let where; if (showField && (!ctx.instance || !ctx.instance[showField]) && ctx.where) { changedModelId = []; where = []; - let changedInstances = await ctx.Model.app.models[definition.name].find({where: ctx.where, fields: ['id', showField, primaryKey]}, options); + let changedInstances = await appModels[definition.name].find({ + where: ctx.where, + fields: ['id', showField, primaryKey] + }, options); + changedInstances.forEach(element => { where.push(element[showField]); changedModelId.push(element.id); @@ -195,7 +241,6 @@ module.exports = function(Self) { } else if (ctx.hookState.oldInstance) where = ctx.instance[showField]; - // Set oldInstance, newInstance, userFk and action let oldInstance = {}; if (ctx.hookState.oldInstance) @@ -211,14 +256,14 @@ module.exports = function(Self) { let action = setActionType(ctx); - removeUnloggableProperties(definition, oldInstance); - removeUnloggableProperties(definition, newInstance); + removeUnloggable(definition, oldInstance); + removeUnloggable(definition, newInstance); let logRecord = { originFk: originId, userFk: userFk, action: action, - changedModel: ctx.Model.definition.name, + changedModel: definition.name, changedModelId: changedModelId, // Model property with an different data type will throw a NaN error changedModelValue: where, oldInstance: oldInstance, @@ -226,9 +271,9 @@ module.exports = function(Self) { }; let logsToSave = setLogsToSave(where, changedModelId, logRecord, ctx); - let logModel = definition.settings.log.model; + let logModel = defSettings.log.model; - await ctx.Model.app.models[logModel].create(logsToSave, options); + await appModels[logModel].create(logsToSave, options); } /** @@ -236,7 +281,7 @@ module.exports = function(Self) { * @param {*} definition Model definition * @param {*} properties Modified object properties */ - function removeUnloggableProperties(definition, properties) { + function removeUnloggable(definition, properties) { const propList = Object.keys(properties); const propDefs = new Map(); diff --git a/loopback/common/models/vn-model.js b/loopback/common/models/vn-model.js index d65ca71df..f56183df2 100644 --- a/loopback/common/models/vn-model.js +++ b/loopback/common/models/vn-model.js @@ -6,6 +6,7 @@ module.exports = function(Self) { Self.ParameterizedSQL = ParameterizedSQL; require('../methods/vn-model/getSetValues')(Self); + require('../methods/vn-model/getEnumValues')(Self); Object.assign(Self, { setup() { diff --git a/loopback/locale/es.json b/loopback/locale/es.json index eeb18fb73..d77b6d290 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -132,5 +132,5 @@ "Distance must be lesser than 1000": "La distancia debe ser inferior a 1000", "This ticket is deleted": "Este ticket está eliminado", "A travel with this data already exists": "Ya existe un travel con estos datos", - "AMOUNT_NOT_MATCH_GROUPING": "AMOUNT_NOT_MATCH_GROUPING" + "This thermograph id already exists": "La id del termógrafo ya existe" } \ No newline at end of file diff --git a/modules/claim/front/descriptor/index.html b/modules/claim/front/descriptor/index.html index 52561b1d0..dcd103247 100644 --- a/modules/claim/front/descriptor/index.html +++ b/modules/claim/front/descriptor/index.html @@ -2,11 +2,11 @@ module="claim" description="$ctrl.claim.client.name"> - Show Pickup order - + diff --git a/modules/claim/front/descriptor/index.js b/modules/claim/front/descriptor/index.js index ea7784f72..5b09b1886 100644 --- a/modules/claim/front/descriptor/index.js +++ b/modules/claim/front/descriptor/index.js @@ -12,7 +12,7 @@ class Controller extends Descriptor { showPickupOrder() { this.showReport('claim-pickup-order', { - clientId: this.claim.clientFk, + recipientId: this.claim.clientFk, claimId: this.claim.id }); } @@ -20,7 +20,7 @@ class Controller extends Descriptor { sendPickupOrder() { return this.sendEmail('claim-pickup-order', { recipient: this.claim.client.email, - clientId: this.claim.clientFk, + recipientId: this.claim.clientFk, claimId: this.claim.id }); } diff --git a/modules/claim/front/descriptor/index.spec.js b/modules/claim/front/descriptor/index.spec.js index 1a18141ca..7cdca1b82 100644 --- a/modules/claim/front/descriptor/index.spec.js +++ b/modules/claim/front/descriptor/index.spec.js @@ -23,7 +23,7 @@ describe('Item Component vnClaimDescriptor', () => { controller.showReport = jest.fn(); const params = { - clientId: claim.clientFk, + recipientId: claim.clientFk, claimId: claim.id }; controller.showPickupOrder(); @@ -38,7 +38,7 @@ describe('Item Component vnClaimDescriptor', () => { const params = { recipient: claim.client.email, - clientId: claim.clientFk, + recipientId: claim.clientFk, claimId: claim.id }; controller.sendPickupOrder(); diff --git a/modules/client/back/methods/client/lastActiveTickets.js b/modules/client/back/methods/client/lastActiveTickets.js index 0337857a9..5f8ef1393 100644 --- a/modules/client/back/methods/client/lastActiveTickets.js +++ b/modules/client/back/methods/client/lastActiveTickets.js @@ -26,11 +26,12 @@ module.exports = Self => { Self.lastActiveTickets = async(id, ticketId) => { const ticket = await Self.app.models.Ticket.findById(ticketId); const query = ` - SELECT t.id, t.shipped, a.name AS agencyName, w.name AS warehouseName + SELECT t.id, t.shipped, a.name AS agencyName, w.name AS warehouseName, ad.city AS address FROM vn.ticket t JOIN vn.ticketState ts ON t.id = ts.ticketFk JOIN vn.agencyMode a ON t.agencyModeFk = a.id JOIN vn.warehouse w ON t.warehouseFk = w.id + JOIN vn.address ad ON t.addressFk = ad.id WHERE t.shipped >= CURDATE() AND t.clientFk = ? AND ts.alertLevel = 0 AND t.id <> ? AND t.warehouseFk = ? ORDER BY t.shipped diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js index 417370e9e..cf3ded2f8 100644 --- a/modules/client/back/models/client.js +++ b/modules/client/back/models/client.js @@ -257,7 +257,7 @@ module.exports = Self => { if (!instance.email) return; const params = { authorization: authorization, - clientId: instance.id, + recipientId: instance.id, recipient: instance.email }; await request.get(`${origin}/api/email/payment-update`, { diff --git a/modules/client/front/address/create/index.js b/modules/client/front/address/create/index.js index b1629073d..79774cf93 100644 --- a/modules/client/front/address/create/index.js +++ b/modules/client/front/address/create/index.js @@ -29,7 +29,7 @@ export default class Controller extends Section { onCustomAgentAccept() { return this.$http.post(`CustomsAgents`, this.newCustomsAgent) - .then(res => this.address.customsAgentFk = res.data.id); + .then(res => this.address.customsAgentId = res.data.id); } get town() { diff --git a/modules/client/front/address/create/index.spec.js b/modules/client/front/address/create/index.spec.js index fb6567dce..4f332e75e 100644 --- a/modules/client/front/address/create/index.spec.js +++ b/modules/client/front/address/create/index.spec.js @@ -123,7 +123,7 @@ describe('Client', () => { controller.onCustomAgentAccept(); $httpBackend.flush(); - expect(controller.address.customsAgentFk).toEqual(1); + expect(controller.address.customsAgentId).toEqual(1); }); }); }); diff --git a/modules/client/front/address/edit/index.spec.js b/modules/client/front/address/edit/index.spec.js index b67138b6d..c4c1a78b5 100644 --- a/modules/client/front/address/edit/index.spec.js +++ b/modules/client/front/address/edit/index.spec.js @@ -64,7 +64,7 @@ describe('Client', () => { }); describe('onCustomAgentAccept()', () => { - it(`should create a new customs agent and then set the customsAgentFk property on the address`, () => { + it(`should now create a new customs agent and then set the customsAgentFk property on the address`, () => { const expectedResult = {id: 1, fiscalName: 'Customs agent one'}; $httpBackend.when('POST', 'CustomsAgents').respond(200, expectedResult); controller.onCustomAgentAccept(); diff --git a/modules/client/front/descriptor/index.js b/modules/client/front/descriptor/index.js index 9948eab43..d079b38da 100644 --- a/modules/client/front/descriptor/index.js +++ b/modules/client/front/descriptor/index.js @@ -42,7 +42,7 @@ class Controller extends Descriptor { onConsumerReportAccept() { this.showReport('campaign-metrics', { - clientId: this.id, + recipientId: this.id, from: this.from, to: this.to, }); diff --git a/modules/client/front/sample/create/index.js b/modules/client/front/sample/create/index.js index bfb0fd287..d1dfd3ff5 100644 --- a/modules/client/front/sample/create/index.js +++ b/modules/client/front/sample/create/index.js @@ -61,7 +61,7 @@ class Controller extends Section { send(isPreview, cb) { const sampleType = this.$.sampleType.selection; const params = { - clientId: this.$params.id, + recipientId: this.$params.id, recipient: this.clientSample.recipient }; diff --git a/modules/client/front/sample/create/index.spec.js b/modules/client/front/sample/create/index.spec.js index 6acf9e960..af7f2f3ff 100644 --- a/modules/client/front/sample/create/index.spec.js +++ b/modules/client/front/sample/create/index.spec.js @@ -68,7 +68,7 @@ describe('Client', () => { code: 'MyReport' }; controller.clientSample = { - clientId: 101 + recipientId: 101 }; controller.send(false, () => {}); @@ -81,7 +81,7 @@ describe('Client', () => { controller.$.sampleType.selection = null; controller.clientSample = { - clientId: 101, + recipientId: 101, recipient: 'client@email.com' }; @@ -98,7 +98,7 @@ describe('Client', () => { code: 'MyReport' }; controller.clientSample = { - clientId: 101, + recipientId: 101, recipient: 'client@email.com' }; @@ -113,11 +113,11 @@ describe('Client', () => { code: 'MyReport' }; controller.clientSample = { - clientId: 101, + recipientId: 101, recipient: 'client@email.com' }; const expectedParams = { - clientId: 101, + recipientId: 101, recipient: 'client@email.com' }; const serializedParams = $httpParamSerializer(expectedParams); @@ -133,12 +133,12 @@ describe('Client', () => { code: 'MyReport' }; controller.clientSample = { - clientId: 101, + recipientId: 101, recipient: 'client@email.com', companyFk: 442 }; const expectedParams = { - clientId: 101, + recipientId: 101, recipient: 'client@email.com', companyId: 442 }; diff --git a/modules/entry/front/descriptor/index.js b/modules/entry/front/descriptor/index.js index 81b7946d1..c84d0144d 100644 --- a/modules/entry/front/descriptor/index.js +++ b/modules/entry/front/descriptor/index.js @@ -37,7 +37,6 @@ class Controller extends Descriptor { showEntryReport() { this.showReport('entry-order', { - clientId: this.vnConfig.storage.currentUserWorkerId, entryId: this.entry.id }); } diff --git a/modules/item/back/methods/item/getSummary.js b/modules/item/back/methods/item/getSummary.js index 4fb9d9ed1..fd52951d7 100644 --- a/modules/item/back/methods/item/getSummary.js +++ b/modules/item/back/methods/item/getSummary.js @@ -22,6 +22,7 @@ module.exports = Self => { Self.getSummary = async id => { let promises = []; let summary = {}; + const models = Self.app.models; // Item basic data and taxes let filter = { @@ -66,7 +67,7 @@ module.exports = Self => { } ] }; - promises.push(Self.app.models.Item.find(filter)); + promises.push(models.Item.find(filter)); // Tags filter = { @@ -78,21 +79,21 @@ module.exports = Self => { relation: 'tag' } }; - promises.push(Self.app.models.ItemTag.find(filter)); + promises.push(models.ItemTag.find(filter)); // Botanical filter = { where: {itemFk: id}, include: [{relation: 'genus'}, {relation: 'specie'}] }; - promises.push(Self.app.models.ItemBotanical.find(filter)); + promises.push(models.ItemBotanical.find(filter)); // Niches filter = { where: {itemFk: id}, include: {relation: 'warehouse'} }; - promises.push(Self.app.models.ItemNiche.find(filter)); + promises.push(models.ItemNiche.find(filter)); let res = await Promise.all(promises); @@ -101,15 +102,10 @@ module.exports = Self => { [summary.botanical] = res[2]; summary.niches = res[3]; - // Visible Avaible - let query = ` - CALL vn.item_getVisibleAvailable(?,curdate(),?,?)`; + res = await models.Item.getVisibleAvailable(summary.item.id, summary.item.itemType().warehouseFk); - let options = [summary.item.id, summary.item.itemType().warehouseFk, false]; - [res] = await Self.rawSql(query, options); - - summary.available = res[0].available ? res[0].available : '-'; - summary.visible = res[0].visible ? res[0].visible : '-'; + summary.available = res.available; + summary.visible = res.visible; return summary; }; }; diff --git a/modules/item/back/methods/item/getVisibleAvailable.js b/modules/item/back/methods/item/getVisibleAvailable.js index 7f0855740..0dd578733 100644 --- a/modules/item/back/methods/item/getVisibleAvailable.js +++ b/modules/item/back/methods/item/getVisibleAvailable.js @@ -1,3 +1,4 @@ +const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; module.exports = Self => { Self.remoteMethod('getVisibleAvailable', { description: 'Returns visible and available for params', @@ -11,6 +12,11 @@ module.exports = Self => { arg: 'warehouseFk', type: 'Number', required: true, + }, + { + arg: 'dated', + type: 'Date', + required: false, }], returns: { type: ['object'], @@ -22,15 +28,35 @@ module.exports = Self => { } }); - Self.getVisibleAvailable = async(id, warehouseFk) => { - let query = ` - CALL vn.item_getVisibleAvailable(?,curdate(),?,?)`; + Self.getVisibleAvailable = async(id, warehouseFk, dated = new Date()) => { + let stmts = []; - let options = [id, warehouseFk, false]; - [res] = await Self.rawSql(query, options); + stmts.push(new ParameterizedSQL( + 'CALL cache.available_refresh(@availableCalc, FALSE, ?, ?)', [ + warehouseFk, + dated + ] + )); + stmts.push(new ParameterizedSQL( + 'CALL cache.visible_refresh(@visibleCalc, FALSE,?)', [ + warehouseFk + ] + )); + const visibleIndex = stmts.push(new ParameterizedSQL( + 'SELECT visible FROM cache.visible WHERE calc_id = @visibleCalc AND item_id = ?', [ + id + ] + )) - 1; + const availableIndex = stmts.push(new ParameterizedSQL( + 'SELECT available FROM cache.available WHERE calc_id = @availableCalc AND item_id = ?', [ + id + ] + )) - 1; + const sql = ParameterizedSQL.join(stmts, ';'); + let res = await Self.rawStmt(sql); return { - available: res[0].available, - visible: res[0].visible}; + available: res[availableIndex][0] ? res[availableIndex][0].available : 0, + visible: res[visibleIndex][0] ? res[visibleIndex][0].visible : 0}; }; }; diff --git a/modules/item/back/methods/item/regularize.js b/modules/item/back/methods/item/regularize.js index bfbc1e28c..bd908c2b7 100644 --- a/modules/item/back/methods/item/regularize.js +++ b/modules/item/back/methods/item/regularize.js @@ -61,13 +61,9 @@ module.exports = Self => { }, options); } - let query = ` - CALL vn.item_getVisibleAvailable(?,curdate(),?,?)`; + res = await models.Item.getVisibleAvailable(itemFk, warehouseFk); - let params = [itemFk, warehouseFk, true]; - let [res] = await Self.rawSql(query, params, options); - - let newQuantity = res[0].visible - quantity; + let newQuantity = res.visible - quantity; await models.Sale.create({ ticketFk: ticketFk, diff --git a/modules/item/back/methods/item/specs/getVisibleAvailable.spec.js b/modules/item/back/methods/item/specs/getVisibleAvailable.spec.js new file mode 100644 index 000000000..77e6cea8f --- /dev/null +++ b/modules/item/back/methods/item/specs/getVisibleAvailable.spec.js @@ -0,0 +1,33 @@ +const app = require('vn-loopback/server/server'); + +describe('item getVisibleAvailable()', () => { + it('should check available visible for today', async() => { + const itemFk = 1; + const warehouseFk = 1; + const dated = new Date(); + let result = await app.models.Item.getVisibleAvailable(itemFk, warehouseFk, dated); + + expect(result.available).toEqual(187); + expect(result.visible).toEqual(92); + }); + + it('should check available visible for no dated', async() => { + const itemFk = 1; + const warehouseFk = 1; + let result = await app.models.Item.getVisibleAvailable(itemFk, warehouseFk); + + expect(result.available).toEqual(187); + expect(result.visible).toEqual(92); + }); + + it('should check available visible for yesterday', async() => { + const itemFk = 1; + const warehouseFk = 1; + let dated = new Date(); + dated.setDate(dated.getDate() - 1); + let result = await app.models.Item.getVisibleAvailable(itemFk, warehouseFk, dated); + + expect(result.available).toEqual(0); + expect(result.visible).toEqual(92); + }); +}); diff --git a/modules/item/back/methods/item/specs/regularize.spec.js b/modules/item/back/methods/item/specs/regularize.spec.js index b285c15e1..d34dca25f 100644 --- a/modules/item/back/methods/item/specs/regularize.spec.js +++ b/modules/item/back/methods/item/specs/regularize.spec.js @@ -14,13 +14,8 @@ describe('regularize()', () => { it('should create a new ticket and add a line', async() => { let ctx = {req: {accessToken: {userId: 18}}}; - - let query = `CALL vn.item_getVisibleAvailable(?,curdate(),?,?)`; - - let options = [itemFk, warehouseFk, true]; - - let [res] = await app.models.Item.rawSql(query, options); - let visible = res[0].visible; + let res = await app.models.Item.getVisibleAvailable(itemFk, warehouseFk); + let visible = res.visible; let saleQuantity = visible - 11; let ticketFk = await app.models.Item.regularize(ctx, itemFk, 11, warehouseFk); diff --git a/modules/item/front/descriptor-popover/index.html b/modules/item/front/descriptor-popover/index.html index d4d8035b9..7a401a076 100644 --- a/modules/item/front/descriptor-popover/index.html +++ b/modules/item/front/descriptor-popover/index.html @@ -1,5 +1,5 @@ - + Regularize stock + + Clone +
@@ -83,4 +89,10 @@ - \ No newline at end of file + + + diff --git a/modules/item/front/descriptor/index.js b/modules/item/front/descriptor/index.js index ab901faf5..2791e960a 100644 --- a/modules/item/front/descriptor/index.js +++ b/modules/item/front/descriptor/index.js @@ -31,7 +31,8 @@ class Controller extends Descriptor { if (!this.item) return; const params = { - warehouseFk: this.item.itemType.warehouseFk + warehouseFk: this.item.itemType.warehouseFk, + dated: this.dated }; return this.$http.get(`Items/${this.id}/getVisibleAvailable`, {params}) @@ -59,12 +60,18 @@ class Controller extends Descriptor { this.warehouseFk = null; this.quantity = null; } + + onCloneAccept() { + this.$http.post(`Items/${this.item.id}/clone`) + .then(res => this.$state.go('item.card.tags', {id: res.data.id})); + } } ngModule.vnComponent('vnItemDescriptor', { template: require('./index.html'), controller: Controller, bindings: { - item: '<' + item: '<', + dated: '<' } }); diff --git a/modules/item/front/descriptor/index.spec.js b/modules/item/front/descriptor/index.spec.js index 7406d1800..23053432e 100644 --- a/modules/item/front/descriptor/index.spec.js +++ b/modules/item/front/descriptor/index.spec.js @@ -33,4 +33,14 @@ describe('vnItemDescriptor', () => { expect(controller.item).toEqual(item); }); }); + + describe('updateStock()', () => { + it(`should perform a get query to store the item data into the controller`, () => { + $httpBackend.expectGET(`Items/${item.id}/getCard`).respond(item); + controller.id = item.id; + $httpBackend.flush(); + + expect(controller.item).toEqual(item); + }); + }); }); diff --git a/modules/item/front/last-entries/index.html b/modules/item/front/last-entries/index.html index 28ba9989b..6f2dba989 100644 --- a/modules/item/front/last-entries/index.html +++ b/modules/item/front/last-entries/index.html @@ -31,6 +31,7 @@ Stems Quantity Cost + Kg. Cube Provider @@ -62,6 +63,7 @@ {{::entry.stems | dashIfEmpty}} {{::entry.quantity}} {{::entry.buyingValue | dashIfEmpty}} + {{::entry.weight | dashIfEmpty}} {{::entry.packageFk | dashIfEmpty}} {{::entry.supplier | dashIfEmpty}} diff --git a/modules/order/back/methods/order/getSourceValues.js b/modules/order/back/methods/order/getSourceValues.js index da3685c62..5e9f0e6dc 100644 --- a/modules/order/back/methods/order/getSourceValues.js +++ b/modules/order/back/methods/order/getSourceValues.js @@ -12,7 +12,7 @@ module.exports = Self => { } }); - Self.getSourceValues = async () => { + Self.getSourceValues = async() => { return Self.getSetValues('sourceApp'); }; }; diff --git a/modules/order/front/catalog/index.html b/modules/order/front/catalog/index.html index ab51e66fc..a13274484 100644 --- a/modules/order/front/catalog/index.html +++ b/modules/order/front/catalog/index.html @@ -11,7 +11,7 @@ data="$ctrl.items"> - diff --git a/modules/order/front/catalog/index.js b/modules/order/front/catalog/index.js index 69a0429ca..7d73a4dea 100644 --- a/modules/order/front/catalog/index.js +++ b/modules/order/front/catalog/index.js @@ -206,7 +206,7 @@ class Controller extends Section { removeItemId() { this.itemId = null; - this.applyFilters(); + this.$.searchbar.doSearch({}, 'bar'); } removeItemName() { diff --git a/modules/route/front/descriptor/index.js b/modules/route/front/descriptor/index.js index 0fbc3a5e6..c14035015 100644 --- a/modules/route/front/descriptor/index.js +++ b/modules/route/front/descriptor/index.js @@ -12,19 +12,16 @@ class Controller extends Descriptor { showRouteReport() { this.showReport('driver-route', { - clientId: this.vnConfig.storage.currentUserWorkerId, routeId: this.id }); } sendRouteReport() { - const params = { - recipient: user.emailUser.email, - clientId: this.vnConfig.storage.currentUserWorkerId, + const workerUser = this.route.worker.user; + this.sendEmail('driver-route', { + recipient: workerUser.emailUser.email, routeId: this.id - }; - return this.$http.get(`email/driver-route`, {params}) - .then(() => this.vnApp.showSuccess(this.$t('Report sent'))); + }); } updateVolume() { diff --git a/modules/ticket/back/methods/ticket-request/confirm.js b/modules/ticket/back/methods/ticket-request/confirm.js index fe08794f1..15050ba00 100644 --- a/modules/ticket/back/methods/ticket-request/confirm.js +++ b/modules/ticket/back/methods/ticket-request/confirm.js @@ -47,14 +47,9 @@ module.exports = Self => { include: {relation: 'ticket'} }, options); - let [[stock]] = await Self.rawSql(`CALL vn.item_getVisibleAvailable(?,?,?,?)`, [ - ctx.args.itemFk, - request.ticket().shipped, - request.ticket().warehouseFk, - false - ], options); + const res = await models.Item.getVisibleAvailable(ctx.args.itemFk, request.ticket().warehouseFk, request.ticket().shipped); - if (stock.available < 0) + if (res.available < 0) throw new UserError(`This item is not available`); if (request.saleFk) { diff --git a/modules/ticket/back/methods/ticket/addSale.js b/modules/ticket/back/methods/ticket/addSale.js index c1081c4be..c48b04e92 100644 --- a/modules/ticket/back/methods/ticket/addSale.js +++ b/modules/ticket/back/methods/ticket/addSale.js @@ -42,15 +42,9 @@ module.exports = Self => { const item = await models.Item.findById(itemId); const ticket = await models.Ticket.findById(id); - const shouldRefresh = false; - const [[stock]] = await Self.rawSql(`CALL vn.item_getVisibleAvailable(?, ?, ?, ?)`, [ - itemId, - ticket.shipped, - ticket.warehouseFk, - shouldRefresh - ]); + const res = await models.Item.getVisibleAvailable(itemId, ticket.warehouseFk, ticket.shipped); - if (stock.available < quantity) + if (res.available < quantity) throw new UserError(`This item is not available`); const newSale = await models.Sale.create({ diff --git a/modules/ticket/back/methods/ticket/setDeleted.js b/modules/ticket/back/methods/ticket/setDeleted.js index 0f7e0b57f..06e443e94 100644 --- a/modules/ticket/back/methods/ticket/setDeleted.js +++ b/modules/ticket/back/methods/ticket/setDeleted.js @@ -83,7 +83,7 @@ module.exports = Self => { } const ticket = await models.Ticket.findById(id, { - include: { + include: [{ relation: 'client', scope: { fields: ['id', 'salesPersonFk'], @@ -97,9 +97,27 @@ module.exports = Self => { } } } - } + }, { + relation: 'ship' + }, { + relation: 'stowaway' + }] }); + // Change state to "fixing" if contains an stowaway + let otherTicketId; + if (ticket.stowaway()) + otherTicketId = ticket.stowaway().shipFk; + else if (ticket.ship()) + otherTicketId = ticket.ship().id; + + if (otherTicketId) { + await models.TicketTracking.changeState(ctx, { + ticketFk: otherTicketId, + code: 'FIXING' + }); + } + // Send notification to salesPerson const salesPerson = ticket.client().salesPerson(); if (salesPerson) { diff --git a/modules/ticket/back/methods/ticket/specs/setDeleted.spec.js b/modules/ticket/back/methods/ticket/specs/setDeleted.spec.js index 2713bd700..8c94f012e 100644 --- a/modules/ticket/back/methods/ticket/specs/setDeleted.spec.js +++ b/modules/ticket/back/methods/ticket/specs/setDeleted.spec.js @@ -4,6 +4,7 @@ const models = app.models; describe('ticket deleted()', () => { let ticket; let sale; + let deletedClaim; beforeAll(async done => { let originalTicket = await models.Ticket.findOne({where: {id: 16}}); @@ -27,8 +28,36 @@ describe('ticket deleted()', () => { }); afterAll(async done => { + const ticketId = 16; + const stowawayTicketId = 17; + const ctx = { + req: { + accessToken: {userId: 106}, + headers: { + origin: 'http://localhost:5000' + }, + __: () => {} + } + }; await models.Ticket.destroyById(ticket.id); - + const stowaway = await models.Stowaway.findOne({ + where: { + id: stowawayTicketId, + shipFk: ticketId + } + }); + await stowaway.destroy(); + await models.Claim.create(deletedClaim); + await models.TicketTracking.changeState(ctx, { + ticketFk: ticketId, + code: 'OK' + }); + await models.TicketTracking.changeState(ctx, { + ticketFk: stowawayTicketId, + code: 'OK' + }); + const orgTicket = await models.Ticket.findById(ticketId); + await orgTicket.updateAttribute('isDeleted', false); done(); }); @@ -103,4 +132,35 @@ describe('ticket deleted()', () => { expect(error.translateArgs[0]).toEqual(2); expect(error.message).toEqual('You must delete the claim id %d first'); }); + + it('should delete the ticket and change the state to "FIXING" to the stowaway ticket', async() => { + const ticketId = 16; + const claimIdToRemove = 2; + const stowawayTicketId = 17; + const ctx = { + req: { + accessToken: {userId: 106}, + headers: { + origin: 'http://localhost:5000' + }, + __: () => {} + } + }; + + await app.models.Stowaway.rawSql(` + INSERT INTO vn.stowaway(id, shipFk) + VALUES (?, ?)`, [stowawayTicketId, ticketId]); + + deletedClaim = await app.models.Claim.findById(claimIdToRemove); + await app.models.Claim.destroyById(claimIdToRemove); + await app.models.Ticket.setDeleted(ctx, ticketId); + + const stowawayTicket = await app.models.TicketState.findOne({ + where: { + ticketFk: stowawayTicketId + } + }); + + expect(stowawayTicket.code).toEqual('FIXING'); + }); }); diff --git a/modules/ticket/back/models/ticket-state.json b/modules/ticket/back/models/ticket-state.json index e53c4d0f5..a7f0f8242 100644 --- a/modules/ticket/back/models/ticket-state.json +++ b/modules/ticket/back/models/ticket-state.json @@ -17,6 +17,9 @@ }, "alertLevel": { "type": "Number" + }, + "code": { + "type": "string" } }, "relations": { diff --git a/modules/ticket/front/descriptor/index.js b/modules/ticket/front/descriptor/index.js index 1b9048bd7..546c5bec7 100644 --- a/modules/ticket/front/descriptor/index.js +++ b/modules/ticket/front/descriptor/index.js @@ -102,15 +102,15 @@ class Controller extends Descriptor { showDeliveryNote() { this.showReport('delivery-note', { - clientId: this.ticket.client.id, + recipientId: this.ticket.client.id, ticketId: this.id, }); } sendDeliveryNote() { return this.sendEmail('delivery-note', { + recipientId: this.ticket.client.id, recipient: this.ticket.client.email, - clientId: this.ticket.client.id, ticketId: this.id }); } diff --git a/modules/ticket/front/sale/index.html b/modules/ticket/front/sale/index.html index 8cfe19451..fa569161e 100644 --- a/modules/ticket/front/sale/index.html +++ b/modules/ticket/front/sale/index.html @@ -306,9 +306,10 @@ Id - F. envio - Agencia - Almacen + Shipped + Agency + Warehouse + Address @@ -323,6 +324,7 @@ {{::ticket.shipped | date: 'dd/MM/yyyy'}} {{::ticket.agencyName}} {{::ticket.warehouseName}} + {{::ticket.address}} diff --git a/modules/ticket/front/sale/locale/es.yml b/modules/ticket/front/sale/locale/es.yml index 8de8427b9..908b76bc6 100644 --- a/modules/ticket/front/sale/locale/es.yml +++ b/modules/ticket/front/sale/locale/es.yml @@ -29,4 +29,8 @@ Product not available: "Verdnatura le comunica:\rPedido {{ticketFk}} día {{crea Continue anyway?: ¿Continuar de todas formas? This ticket is now empty: El ticket ha quedado vacio Do you want to delete it?: ¿Quieres eliminarlo? -Recalculate price: Recalcular precio \ No newline at end of file +Recalculate price: Recalcular precio +Address: Dirección +Warehouse: Almacen +Agency: Agencia +Shipped: F. envio \ No newline at end of file diff --git a/modules/ticket/front/summary/index.html b/modules/ticket/front/summary/index.html index 3ea2b7234..901e089db 100644 --- a/modules/ticket/front/summary/index.html +++ b/modules/ticket/front/summary/index.html @@ -121,7 +121,7 @@ {{sale.itemFk | zeroFill:6}} diff --git a/modules/ticket/front/summary/index.js b/modules/ticket/front/summary/index.js index b8511a662..864f118d2 100644 --- a/modules/ticket/front/summary/index.js +++ b/modules/ticket/front/summary/index.js @@ -37,6 +37,11 @@ class Controller extends Section { return true; } + showInvoiceOutDescriptor(event, refFk) { + if (!refFk) return; + this.$.invoiceOutDescriptor.show(event.target, this.summary.invoiceOut.id); + } + setOkState() { let params = {}; diff --git a/modules/travel/back/methods/thermograph/createThermograph.js b/modules/travel/back/methods/thermograph/createThermograph.js new file mode 100644 index 000000000..bfca208fe --- /dev/null +++ b/modules/travel/back/methods/thermograph/createThermograph.js @@ -0,0 +1,60 @@ +module.exports = Self => { + Self.remoteMethod('createThermograph', { + description: 'Creates a new thermograph', + accessType: 'WRITE', + accepts: [{ + arg: 'thermographId', + type: 'String', + description: 'The thermograph id', + required: true + }, { + arg: 'model', + type: 'String', + description: 'The thermograph model', + required: true + }, { + arg: 'temperature', + type: 'String', + description: 'The thermograph temperature', + required: true + }, { + arg: 'warehouseId', + type: 'Number', + description: 'The warehouse id', + required: true + }], + returns: { + type: 'Object', + root: true + }, + http: { + path: `/createThermograph`, + verb: 'POST' + } + }); + + Self.createThermograph = async(thermographId, model, temperature, warehouseId) => { + const models = Self.app.models; + const tx = await Self.beginTransaction({}); + + try { + const options = {transaction: tx}; + const thermograph = await models.Thermograph.create({ + id: thermographId, + model: model + }, options); + + await Self.rawSql(` + INSERT INTO travelThermograph(thermographFk, warehouseFk, temperature, created) + VALUES (?, ?,?, NOW()) + `, [thermograph.id, warehouseId, temperature], options); + + await tx.commit(); + + return thermograph; + } catch (err) { + await tx.rollback(); + throw err; + } + }; +}; diff --git a/modules/travel/back/methods/thermograph/getThermographModels.js b/modules/travel/back/methods/thermograph/getThermographModels.js new file mode 100644 index 000000000..188c3a530 --- /dev/null +++ b/modules/travel/back/methods/thermograph/getThermographModels.js @@ -0,0 +1,18 @@ +module.exports = Self => { + Self.remoteMethod('getThermographModels', { + description: 'Gets the thermograph models', + accessType: 'READ', + returns: { + type: ['String'], + root: true + }, + http: { + path: `/getThermographModels`, + verb: 'GET' + } + }); + + Self.getThermographModels = async() => { + return Self.getEnumValues('model'); + }; +}; diff --git a/modules/travel/back/methods/thermograph/specs/createThermograph.spec.js b/modules/travel/back/methods/thermograph/specs/createThermograph.spec.js new file mode 100644 index 000000000..733b713f0 --- /dev/null +++ b/modules/travel/back/methods/thermograph/specs/createThermograph.spec.js @@ -0,0 +1,49 @@ +const app = require('vn-loopback/server/server'); + +describe('Termograph createThermograph()', () => { + const models = app.models; + const thermographId = '99999-1'; + const model = 'DISPOSABLE'; + const temperature = 'COOL'; + const warehouseId = 1; + let createdThermograph; + + afterAll(async done => { + let travelThermograpToDelete = await models.TravelThermograph.findOne({where: {thermographFk: createdThermograph.id}}); + let thermograpToDelete = await models.Thermograph.findById(createdThermograph.id); + + await travelThermograpToDelete.destroy(); + await thermograpToDelete.destroy(); + + done(); + }); + + it(`should create a thermograph which is saved in both thermograph and travelThermograph`, async() => { + let createdTravelThermograpth = await models.TravelThermograph.findOne({where: {thermographFk: thermographId}}); + + expect(createdTravelThermograpth).toBeNull(); + + createdThermograph = await models.Thermograph.createThermograph(thermographId, model, temperature, warehouseId); + + expect(createdThermograph.id).toEqual(thermographId); + expect(createdThermograph.model).toEqual(model); + + createdTravelThermograpth = await models.TravelThermograph.findOne({where: {thermographFk: thermographId}}); + + expect(createdTravelThermograpth.warehouseFk).toEqual(warehouseId); + expect(createdTravelThermograpth.temperature).toEqual(temperature); + }); + + it(`should not be able to created duplicated entries`, async() => { + let error; + + try { + await models.Thermograph.createThermograph(thermographId, model, temperature, warehouseId); + } catch (e) { + error = e; + } + + expect(error).toBeDefined(); + expect(error.message).toBe('This thermograph id already exists'); + }); +}); diff --git a/modules/travel/back/methods/travel-thermograph/getThermographTemperatures.js b/modules/travel/back/methods/travel-thermograph/getThermographTemperatures.js new file mode 100644 index 000000000..1d510b513 --- /dev/null +++ b/modules/travel/back/methods/travel-thermograph/getThermographTemperatures.js @@ -0,0 +1,18 @@ +module.exports = Self => { + Self.remoteMethod('getThermographTemperatures', { + description: 'Gets the thermograph temperatures', + accessType: 'READ', + returns: { + type: ['String'], + root: true + }, + http: { + path: `/getThermographTemperatures`, + verb: 'GET' + } + }); + + Self.getThermographTemperatures = async() => { + return Self.getEnumValues('temperature'); + }; +}; diff --git a/modules/travel/back/models/thermograph.js b/modules/travel/back/models/thermograph.js new file mode 100644 index 000000000..3f95a0670 --- /dev/null +++ b/modules/travel/back/models/thermograph.js @@ -0,0 +1,12 @@ +let UserError = require('vn-loopback/util/user-error'); + +module.exports = Self => { + require('../methods/thermograph/createThermograph')(Self); + require('../methods/thermograph/getThermographModels')(Self); + + Self.rewriteDbError(function(err) { + if (err.code === 'ER_DUP_ENTRY') + return new UserError(`This thermograph id already exists`); + return err; + }); +}; diff --git a/modules/travel/back/models/thermograph.json b/modules/travel/back/models/thermograph.json index 421ae4341..2519fffc4 100644 --- a/modules/travel/back/models/thermograph.json +++ b/modules/travel/back/models/thermograph.json @@ -10,10 +10,12 @@ "id": { "type": "String", "id": true, - "description": "Identifier" + "description": "Identifier", + "required": true }, "model": { - "type": "String" + "type": "String", + "required": true } } } diff --git a/modules/travel/back/models/travel-thermograph.js b/modules/travel/back/models/travel-thermograph.js index 0d70edd7e..a16e68b98 100644 --- a/modules/travel/back/models/travel-thermograph.js +++ b/modules/travel/back/models/travel-thermograph.js @@ -1,4 +1,5 @@ module.exports = Self => { require('../methods/travel-thermograph/allowedContentTypes')(Self); + require('../methods/travel-thermograph/getThermographTemperatures')(Self); }; diff --git a/modules/travel/back/models/travel-thermograph.json b/modules/travel/back/models/travel-thermograph.json index b8f7fa41a..70ee0de07 100644 --- a/modules/travel/back/models/travel-thermograph.json +++ b/modules/travel/back/models/travel-thermograph.json @@ -21,10 +21,15 @@ "type": "Date" }, "temperature": { - "type": "String" + "type": "String", + "required": true }, "result": { "type": "String" + }, + "warehouseFk": { + "type": "Number", + "required": true } }, "relations": { diff --git a/modules/travel/front/thermograph/create/index.html b/modules/travel/front/thermograph/create/index.html index 4b1fc8cf4..0232c1b12 100644 --- a/modules/travel/front/thermograph/create/index.html +++ b/modules/travel/front/thermograph/create/index.html @@ -17,6 +17,18 @@ where="{travelFk: null}" show-field="thermographFk" value-field="thermographFk"> + + {{thermographFk}} + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/modules/travel/front/thermograph/create/index.js b/modules/travel/front/thermograph/create/index.js index 6c0464991..d398febf1 100644 --- a/modules/travel/front/thermograph/create/index.js +++ b/modules/travel/front/thermograph/create/index.js @@ -55,6 +55,28 @@ class Controller extends Section { }); } + onAddThermographClick(event) { + const defaultTemperature = 'COOL'; + const defaultModel = 'DISPOSABLE'; + + event.preventDefault(); + this.newThermograph = { + thermographId: this.thermographId, + warehouseId: this.warehouseId, + temperature: defaultTemperature, + model: defaultModel + }; + + this.$.modelsModel.refresh(); + this.$.temperaturesModel.refresh(); + this.$.newThermographDialog.show(); + } + + onNewThermographAccept() { + return this.$http.post(`Thermographs/createThermograph`, this.newThermograph) + .then(res => this.dms.thermographId = res.data.id); + } + onSubmit() { const query = `Travels/${this.travel.id}/createThermograph`; const options = { diff --git a/modules/travel/front/thermograph/create/index.spec.js b/modules/travel/front/thermograph/create/index.spec.js index 58fbe3991..23976fc96 100644 --- a/modules/travel/front/thermograph/create/index.spec.js +++ b/modules/travel/front/thermograph/create/index.spec.js @@ -63,5 +63,32 @@ describe('Ticket', () => { expect(controller.allowedContentTypes).toEqual('application/pdf, image/png, image/jpg'); }); }); + + describe('onAddThermographClick()', () => { + it('should call the show() function of the create thermograph dialog', () => { + controller.$.newThermographDialog = {show: jest.fn()}; + controller.$.modelsModel = {refresh: jest.fn()}; + controller.$.temperaturesModel = {refresh: jest.fn()}; + + const event = new Event('click'); + jest.spyOn(event, 'preventDefault'); + + controller.onAddThermographClick(event); + + expect(event.preventDefault).toHaveBeenCalledTimes(1); + expect(controller.$.newThermographDialog.show).toHaveBeenCalledTimes(1); + }); + }); + + describe('onNewThermographAccept()', () => { + it('should set the created thermograph id on to the controller for the autocomplete to use it', () => { + const response = {id: 'the created id'}; + $httpBackend.when('POST', `Thermographs/createThermograph`).respond(response); + controller.onNewThermographAccept(); + $httpBackend.flush(); + + expect(controller.dms.thermographId).toEqual(response.id); + }); + }); }); }); diff --git a/modules/travel/front/thermograph/locale/es.yml b/modules/travel/front/thermograph/locale/es.yml index 9f9be564b..0e3bc99fc 100644 --- a/modules/travel/front/thermograph/locale/es.yml +++ b/modules/travel/front/thermograph/locale/es.yml @@ -15,4 +15,6 @@ Add thermograph: Añadir termógrafo Edit thermograph: Editar termógrafo Thermograph deleted: Termógrafo eliminado Thermograph: Termógrafo -Are you sure you want to remove the thermograph?: ¿Seguro que quieres quitar el termógrafo? \ No newline at end of file +New thermograph: Nuevo termógrafo +Are you sure you want to remove the thermograph?: ¿Seguro que quieres quitar el termógrafo? +Identifier: Identificador \ No newline at end of file diff --git a/modules/worker/front/log/locale/es.yml b/modules/worker/front/log/locale/es.yml index d9c204e55..c48c571ac 100644 --- a/modules/worker/front/log/locale/es.yml +++ b/modules/worker/front/log/locale/es.yml @@ -1,3 +1,4 @@ +Date: Fecha Model: Modelo Action: Acción Author: Autor diff --git a/modules/worker/front/routes.json b/modules/worker/front/routes.json index 8447ef9c4..7825e9735 100644 --- a/modules/worker/front/routes.json +++ b/modules/worker/front/routes.json @@ -62,7 +62,8 @@ "url" : "/log", "state": "worker.card.workerLog", "component": "vn-worker-log", - "description": "Log" + "description": "Log", + "acl": ["hr"] }, { "url": "/pbx", "state": "worker.card.pbx", diff --git a/modules/zone/front/delivery-days/index.spec.js b/modules/zone/front/delivery-days/index.spec.js index 156407420..db99add2c 100644 --- a/modules/zone/front/delivery-days/index.spec.js +++ b/modules/zone/front/delivery-days/index.spec.js @@ -61,8 +61,8 @@ describe('Zone Component vnZoneDeliveryDays', () => { expect(controller.$.data).toEqual(expectedData); }); }); - // Petición #2259 cread - xdescribe('onSelection()', () => { + + describe('onSelection()', () => { it('should not call the show popover method if events array is empty', () => { jest.spyOn(controller.$.zoneEvents, 'show'); diff --git a/package-lock.json b/package-lock.json index b46d40dcc..4a597175a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3244,7 +3244,7 @@ }, "util": { "version": "0.10.3", - "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", "dev": true, "requires": { @@ -4060,7 +4060,7 @@ "base": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", "dev": true, "requires": { "cache-base": "^1.0.1", @@ -4577,7 +4577,7 @@ "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", "dev": true, "requires": { "collection-visit": "^1.0.0", @@ -4754,7 +4754,7 @@ "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=", "dev": true, "requires": { "arr-union": "^3.1.0", @@ -5816,7 +5816,7 @@ "dot-prop": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", - "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "integrity": "sha1-HxngwuGqDjJ5fEl5nyg3rGr2nFc=", "requires": { "is-obj": "^1.0.0" } @@ -6751,7 +6751,7 @@ }, "file-loader": { "version": "1.1.11", - "resolved": "http://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz", "integrity": "sha512-TGR4HU7HUsGg6GCOPJnFk06RhWgEWFLAGWiT6rcD+GRC2keU3s9RGJ+b3Z6/U73jwwNb2gKLJ7YCrp+jvU4ALg==", "dev": true, "requires": { @@ -7918,7 +7918,7 @@ "global-modules": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "integrity": "sha1-bXcPDrUjrHgWTXK15xqIdyZcw+o=", "dev": true, "requires": { "global-prefix": "^1.0.1", @@ -8500,7 +8500,7 @@ "dependencies": { "es6-promise": { "version": "3.3.1", - "resolved": "http://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=", "dev": true }, @@ -9579,7 +9579,7 @@ "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", "dev": true, "requires": { "isobject": "^3.0.1" @@ -9935,7 +9935,7 @@ "jasmine-spec-reporter": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-4.2.1.tgz", - "integrity": "sha512-FZBoZu7VE5nR7Nilzy+Np8KuVIOxF4oXDPDknehCYBDE080EnlPu0afdZNmpGDBRCUBv3mj5qgqCRmk6W/K8vg==", + "integrity": "sha1-HWMq7ANBZwrTJPkrqEtLMrNeniI=", "dev": true, "requires": { "colors": "1.1.2" @@ -11932,7 +11932,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" }, "mississippi": { @@ -12972,7 +12972,7 @@ "dependencies": { "minimist": { "version": "0.0.10", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", "dev": true }, @@ -14180,7 +14180,7 @@ "dependencies": { "jsesc": { "version": "0.5.0", - "resolved": "http://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", "dev": true } @@ -14558,7 +14558,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { @@ -14648,7 +14648,7 @@ "dependencies": { "source-map": { "version": "0.4.4", - "resolved": "http://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, "requires": { @@ -15006,7 +15006,7 @@ "snapdragon-node": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", "dev": true, "requires": { "define-property": "^1.0.0", @@ -15057,7 +15057,7 @@ "snapdragon-util": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", "dev": true, "requires": { "kind-of": "^3.2.0" @@ -15332,7 +15332,7 @@ "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=", "dev": true, "requires": { "extend-shallow": "^3.0.0" @@ -16409,7 +16409,7 @@ "touch": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "integrity": "sha1-/jZfX3XsntTlaCXgu3bSSrdK+Ds=", "dev": true, "requires": { "nopt": "~1.0.10" diff --git a/print/core/component.js b/print/core/component.js index 836b8c9d9..4f439f1a9 100644 --- a/print/core/component.js +++ b/print/core/component.js @@ -87,17 +87,29 @@ class Component { return component; } - async render() { + component() { + if (this._component) + return this._component; + const component = this.build(); const i18n = new VueI18n(config.i18n); - const app = new Vue({ + this._component = new Vue({ i18n: i18n, render: h => h(component, { props: this.args }) }); - return renderer.renderToString(app); + return this._component; + } + + /** + * @return {Promise} Rendered component + */ + async render() { + return renderer.renderToString( + this.component() + ); } } diff --git a/print/core/components/attachment/attachment.js b/print/core/components/attachment/attachment.js index 2d4e74cdc..0f2a6d103 100755 --- a/print/core/components/attachment/attachment.js +++ b/print/core/components/attachment/attachment.js @@ -15,9 +15,10 @@ module.exports = { const props = this.args; let query = ''; for (let param in props) { - if (query != '') - query += '&'; - query += `${param}=${props[param]}`; + if (!(props[param] instanceof Object)) { + if (query != '') query += '&'; + query += `${param}=${props[param]}`; + } } return query; diff --git a/print/core/email.js b/print/core/email.js index faf744e77..cf6f8b663 100644 --- a/print/core/email.js +++ b/print/core/email.js @@ -1,9 +1,8 @@ const path = require('path'); const smtp = require('./smtp'); +const config = require('./config'); const Component = require('./component'); const Report = require('./report'); -const db = require('./database'); -const config = require('./config'); if (!process.env.OPENSSL_CONF) process.env.OPENSSL_CONF = '/etc/ssl/'; @@ -20,27 +19,22 @@ class Email extends Component { } async getSubject() { - if (!this.lang) await this.getLang(); - const locale = this.locale.messages; - const userLocale = locale[this.lang]; + const component = await this.component(); + let locale = this.args.auth.locale; - if (!userLocale) { + if (this.args.recipientId) + locale = await component.getLocale(this.args.recipientId); + + const messages = this.locale.messages; + const userTranslations = messages[locale]; + + if (!userTranslations) { const fallbackLocale = config.i18n.fallbackLocale; - return locale[fallbackLocale].subject; + return messages[fallbackLocale].subject; } - return userLocale.subject; - } - - async getLang() { - const clientId = this.args.clientId; - const lang = await db.findOne(` - SELECT lang FROM account.user - WHERE id = ?`, [clientId]).then(rows => { - return rows.lang; - }); - this.lang = lang; + return userTranslations.subject; } async send() { @@ -80,6 +74,7 @@ class Email extends Component { const localeSubject = await this.getSubject(); const options = { to: this.args.recipient, + replyTo: this.args.auth.email, subject: localeSubject, html: rendered, attachments: attachments diff --git a/print/core/mixins/prop-validator.js b/print/core/mixins/prop-validator.js index a73197ebf..16c71a6db 100644 --- a/print/core/mixins/prop-validator.js +++ b/print/core/mixins/prop-validator.js @@ -19,8 +19,7 @@ const validator = { throw new Error(`Required properties not found [${required}]`); } }, - props: ['isPreview'] + props: ['isPreview', 'authorization'] }; - Vue.mixin(validator); diff --git a/print/core/mixins/user-locale.js b/print/core/mixins/user-locale.js index f30bc0b28..0e4727334 100644 --- a/print/core/mixins/user-locale.js +++ b/print/core/mixins/user-locale.js @@ -4,28 +4,27 @@ const config = require('../config'); const fallbackLocale = config.i18n.fallbackLocale; const userLocale = { async serverPrefetch() { - if (this.clientId) - this.locale = await this.getLocale(this.clientId); + if (this.auth) + this.$i18n.locale = this.auth.locale; - if (this.locale) - this.$i18n.locale = this.locale; + if (this.recipientId) + this.$i18n.locale = await this.getLocale(this.recipientId); }, methods: { - getLocale(clientId) { + getLocale(recipientId) { return db.findOne(` SELECT IF(u.lang IS NOT NULL, u.lang, LOWER(ct.code)) lang FROM client c JOIN country ct ON ct.id = c.countryFk JOIN account.user u ON u.id = c.id - WHERE c.id = ?`, [clientId]).then(rows => { + WHERE c.id = ?`, [recipientId]).then(rows => { if (rows) return rows.lang; else return fallbackLocale; }); } }, - props: ['clientId'] + props: ['auth', 'recipientId'] }; - Vue.mixin(userLocale); diff --git a/print/core/router.js b/print/core/router.js index 3be6cdd35..feaea214b 100644 --- a/print/core/router.js +++ b/print/core/router.js @@ -17,17 +17,32 @@ module.exports = app => { for (let method of methods) paths.push(`/api/${method}/*`); - app.use(paths, async function(request, response, next) { - const authorization = getToken(request); - const query = `SELECT userId, ttl, created - FROM salix.AccessToken WHERE id = ?`; + app.use(paths, async function(req, res, next) { + const token = getToken(req); + const query = `SELECT at.id, at.userId, eu.email, u.lang, at.ttl, at.created + FROM salix.AccessToken at + JOIN account.user u ON u.id = at.userid + JOIN account.emailUser eu ON eu.userFk = u.id + WHERE at.id = ?`; try { - const authToken = await db.findOne(query, [authorization]); + const auth = await db.findOne(query, [token]); - if (!authToken || isTokenExpired(authToken.created, authToken.ttl)) + if (!auth || isTokenExpired(auth.created, auth.ttl)) throw new Error('Invalid authorization token'); + const args = Object.assign({}, req.query); + const props = Object.assign(args, req.body); + props.authorization = auth.id; + + req.args = props; + req.args.auth = { + userId: auth.userId, + token: auth.id, + email: auth.email, + locale: auth.lang + }; + next(); } catch (error) { next(error); @@ -36,12 +51,9 @@ module.exports = app => { function getToken(request) { const headers = request.headers; - const params = request.query; + const queryParams = request.query; - if (headers.authorization) - params.authorization = headers.authorization; - - return headers.authorization || params.authorization; + return headers.authorization || queryParams.authorization; } function isTokenExpired(created, ttl) { diff --git a/print/core/smtp.js b/print/core/smtp.js index b274eafa3..23d19cabc 100644 --- a/print/core/smtp.js +++ b/print/core/smtp.js @@ -27,7 +27,7 @@ module.exports = { await db.rawSql(` INSERT INTO vn.mail (sender, replyTo, sent, subject, body, status) VALUES (:recipient, :sender, 1, :subject, :body, :status)`, { - sender: config.app.senderEmail, + sender: options.replyTo, recipient: options.to, subject: options.subject, body: options.text || options.html, diff --git a/print/methods/closure.js b/print/methods/closure.js index 05490609d..b3ccb6430 100644 --- a/print/methods/closure.js +++ b/print/methods/closure.js @@ -23,13 +23,13 @@ module.exports = app => { for (const ticket of tickets) { try { - await db.rawSql(`CALL vn.ticketClosureTicket(:ticketId)`, { + await db.rawSql(`CALL vn.ticket_closeByTicket(:ticketId)`, { ticketId: ticket.id }); const args = { ticketId: ticket.id, - clientId: ticket.clientFk, + recipientId: ticket.clientFk, recipient: ticket.recipient }; const email = new Email('delivery-note-link', args); diff --git a/print/methods/email.js b/print/methods/email.js index a56798820..69f880a0a 100644 --- a/print/methods/email.js +++ b/print/methods/email.js @@ -2,19 +2,11 @@ const Email = require('../core/email'); module.exports = app => { app.get(`/api/email/:name`, async(req, res, next) => { - const args = req.query; - const requiredArgs = ['clientId', 'recipient']; - const argList = requiredArgs.join(','); - const hasRequiredArgs = requiredArgs.every(arg => { - return args[arg]; - }); - try { - if (!hasRequiredArgs) - throw new Error(`Required properties not found [${argList}]`); + const reportName = req.params.name; + const email = new Email(reportName, req.args); - const email = new Email(req.params.name, args); - if (args.isPreview === 'true') { + if (req.args.isPreview === 'true') { const rendered = await email.render(); res.send(rendered); diff --git a/print/methods/report.js b/print/methods/report.js index 117462d9e..348c05ff3 100644 --- a/print/methods/report.js +++ b/print/methods/report.js @@ -2,20 +2,10 @@ const Report = require('../core/report'); module.exports = app => { app.get(`/api/report/:name`, async(req, res, next) => { - const args = req.query; - const requiredArgs = ['clientId']; - const argList = requiredArgs.join(','); - const hasRequiredArgs = requiredArgs.every(arg => { - return args[arg]; - }); - try { - if (!hasRequiredArgs) - throw new Error(`Required properties not found [${argList}]`); - const reportName = req.params.name; - const fileName = getFileName(reportName, args); - const report = new Report(reportName, args); + const fileName = getFileName(reportName, req.args); + const report = new Report(reportName, req.args); const stream = await report.toPdfStream(); res.setHeader('Content-type', 'application/pdf'); @@ -38,8 +28,7 @@ module.exports = app => { const keys = Object.keys(args); for (let arg of keys) { - // FIXME: #2197 - Remove clientId as a required param - if (arg != 'clientId' && arg.endsWith('Id')) + if (arg.endsWith('Id')) identifiers.push(arg); } diff --git a/print/templates/email/buyer-week-waste/buyer-week-waste.html b/print/templates/email/buyer-week-waste/buyer-week-waste.html index b9ebd6175..9f6b22968 100644 --- a/print/templates/email/buyer-week-waste/buyer-week-waste.html +++ b/print/templates/email/buyer-week-waste/buyer-week-waste.html @@ -1,5 +1,5 @@ - + @@ -43,9 +43,9 @@ {{waste.buyer}} - {{(waste.percentage / 100) | percentage(2, 2, locale)}} - {{waste.dwindle | currency('EUR', locale)}} - {{waste.total | currency('EUR', locale)}} + {{(waste.percentage / 100) | percentage(2, 2, $i18n.locale)}} + {{waste.dwindle | currency('EUR', $i18n.locale)}} + {{waste.total | currency('EUR', $i18n.locale)}} diff --git a/print/templates/email/campaign-metrics/campaign-metrics.html b/print/templates/email/campaign-metrics/campaign-metrics.html index 238d80d4a..4ba95adb9 100644 --- a/print/templates/email/campaign-metrics/campaign-metrics.html +++ b/print/templates/email/campaign-metrics/campaign-metrics.html @@ -1,5 +1,5 @@ - + diff --git a/print/templates/email/campaign-metrics/campaign-metrics.js b/print/templates/email/campaign-metrics/campaign-metrics.js index cb01ca09e..51d2ebb44 100755 --- a/print/templates/email/campaign-metrics/campaign-metrics.js +++ b/print/templates/email/campaign-metrics/campaign-metrics.js @@ -10,7 +10,7 @@ module.exports = { 'email-footer': emailFooter.build() }, props: { - clientId: { + recipientId: { required: true }, from: { diff --git a/print/templates/email/claim-pickup-order/claim-pickup-order.html b/print/templates/email/claim-pickup-order/claim-pickup-order.html index b00338467..cdde0dd92 100644 --- a/print/templates/email/claim-pickup-order/claim-pickup-order.html +++ b/print/templates/email/claim-pickup-order/claim-pickup-order.html @@ -1,5 +1,5 @@ - + diff --git a/print/templates/email/client-welcome/client-welcome.html b/print/templates/email/client-welcome/client-welcome.html index c5f203621..1d21846d7 100644 --- a/print/templates/email/client-welcome/client-welcome.html +++ b/print/templates/email/client-welcome/client-welcome.html @@ -1,5 +1,5 @@ - + diff --git a/print/templates/email/client-welcome/client-welcome.js b/print/templates/email/client-welcome/client-welcome.js index 35b373bc4..194c133bd 100755 --- a/print/templates/email/client-welcome/client-welcome.js +++ b/print/templates/email/client-welcome/client-welcome.js @@ -6,7 +6,7 @@ const emailFooter = new Component('email-footer'); module.exports = { name: 'client-welcome', async serverPrefetch() { - this.client = await this.fetchClient(this.clientId); + this.client = await this.fetchClient(this.recipientId); }, methods: { fetchClient(clientId) { @@ -29,7 +29,7 @@ module.exports = { 'email-footer': emailFooter.build() }, props: { - clientId: { + recipientId: { required: true } } diff --git a/print/templates/email/delivery-note-link/delivery-note-link.html b/print/templates/email/delivery-note-link/delivery-note-link.html index 28dbc7922..78fa2c922 100644 --- a/print/templates/email/delivery-note-link/delivery-note-link.html +++ b/print/templates/email/delivery-note-link/delivery-note-link.html @@ -1,5 +1,5 @@ - + diff --git a/print/templates/email/delivery-note-link/locale/en.yml b/print/templates/email/delivery-note-link/locale/en.yml new file mode 100644 index 000000000..f2d789364 --- /dev/null +++ b/print/templates/email/delivery-note-link/locale/en.yml @@ -0,0 +1,10 @@ +subject: Your delivery note +title: "Here is your delivery note!" +dear: Dear client +description: The delivery note from the order {0} is now available.
+ You can download it by clicking this link. +copyLink: 'As an alternative, you can copy the following link in your browser:' +poll: If you wish, you can answer our satisfaction survey to +   help us provide better service. Your opinion is very important for us! +help: Any questions that arise, do not hesitate to consult it, we are here to assist you! +conclusion: Thanks for your attention! diff --git a/print/templates/email/delivery-note/delivery-note.html b/print/templates/email/delivery-note/delivery-note.html index 0ee59a26f..71de29a3e 100644 --- a/print/templates/email/delivery-note/delivery-note.html +++ b/print/templates/email/delivery-note/delivery-note.html @@ -1,5 +1,5 @@ - + diff --git a/print/templates/email/delivery-note/locale/en.yml b/print/templates/email/delivery-note/locale/en.yml new file mode 100644 index 000000000..2cc05c5f2 --- /dev/null +++ b/print/templates/email/delivery-note/locale/en.yml @@ -0,0 +1,9 @@ +subject: Your delivery note +title: "Here is your delivery note!" +dear: Dear client +description: The delivery note from the order {0} is now available.
+ You can download it by clicking on the attachment of this email. +poll: If you wish, you can answer our satisfaction survey to +   help us provide better service. Your opinion is very important for us! +help: Any questions that arise, do not hesitate to consult it, we are here to assist you! +conclusion: Thanks for your attention! diff --git a/print/templates/email/driver-route/driver-route.html b/print/templates/email/driver-route/driver-route.html index b9d0aeab5..815b28b8c 100644 --- a/print/templates/email/driver-route/driver-route.html +++ b/print/templates/email/driver-route/driver-route.html @@ -1,5 +1,5 @@ - + diff --git a/print/templates/email/letter-debtor-nd/letter-debtor-nd.html b/print/templates/email/letter-debtor-nd/letter-debtor-nd.html index c7a6faebc..630cce8a2 100644 --- a/print/templates/email/letter-debtor-nd/letter-debtor-nd.html +++ b/print/templates/email/letter-debtor-nd/letter-debtor-nd.html @@ -1,5 +1,5 @@ - + diff --git a/print/templates/email/letter-debtor-nd/letter-debtor-nd.js b/print/templates/email/letter-debtor-nd/letter-debtor-nd.js index b2809ac28..be7768608 100755 --- a/print/templates/email/letter-debtor-nd/letter-debtor-nd.js +++ b/print/templates/email/letter-debtor-nd/letter-debtor-nd.js @@ -8,7 +8,7 @@ const attachments = require('./attachments.json'); module.exports = { name: 'letter-debtor-nd', async serverPrefetch() { - this.debtor = await this.fetchDebtor(this.clientId, this.companyId); + this.debtor = await this.fetchDebtor(this.recipientId, this.companyId); if (!this.debtor) throw new Error('Something went wrong'); @@ -40,7 +40,7 @@ module.exports = { authorization: { required: true }, - clientId: { + recipientId: { required: true }, companyId: { diff --git a/print/templates/email/letter-debtor-st/letter-debtor-st.html b/print/templates/email/letter-debtor-st/letter-debtor-st.html index d277d363a..1fc61a478 100644 --- a/print/templates/email/letter-debtor-st/letter-debtor-st.html +++ b/print/templates/email/letter-debtor-st/letter-debtor-st.html @@ -1,5 +1,5 @@ - + @@ -23,7 +23,7 @@
-

{{ $t('title') }}

+

{{ $t('title') }} {{$i18n.locale}}

{{ $t('sections.introduction.title') }},

{{ $t('sections.introduction.description') }}

diff --git a/print/templates/email/letter-debtor-st/letter-debtor-st.js b/print/templates/email/letter-debtor-st/letter-debtor-st.js index 61f3c01ad..51ed8b2ff 100755 --- a/print/templates/email/letter-debtor-st/letter-debtor-st.js +++ b/print/templates/email/letter-debtor-st/letter-debtor-st.js @@ -8,7 +8,7 @@ const attachments = require('./attachments.json'); module.exports = { name: 'letter-debtor-st', async serverPrefetch() { - this.debtor = await this.fetchDebtor(this.clientId, this.companyId); + this.debtor = await this.fetchDebtor(this.recipientId, this.companyId); if (!this.debtor) throw new Error('Something went wrong'); @@ -37,10 +37,7 @@ module.exports = { 'attachment': attachment.build() }, props: { - authorization: { - required: true - }, - clientId: { + recipientId: { required: true }, companyId: { diff --git a/print/templates/email/payment-update/payment-update.html b/print/templates/email/payment-update/payment-update.html index 6bba77308..0838d6efb 100644 --- a/print/templates/email/payment-update/payment-update.html +++ b/print/templates/email/payment-update/payment-update.html @@ -1,5 +1,5 @@ - + diff --git a/print/templates/email/payment-update/payment-update.js b/print/templates/email/payment-update/payment-update.js index 4479deb81..c74cf8694 100755 --- a/print/templates/email/payment-update/payment-update.js +++ b/print/templates/email/payment-update/payment-update.js @@ -6,7 +6,7 @@ const emailFooter = new Component('email-footer'); module.exports = { name: 'payment-update', async serverPrefetch() { - this.payMethod = await this.fetchPayMethod(this.clientId); + this.payMethod = await this.fetchPayMethod(this.recipientId); if (!this.payMethod) throw new Error('Something went wrong'); @@ -34,7 +34,7 @@ module.exports = { 'email-footer': emailFooter.build() }, props: { - clientId: { + recipientId: { required: true } } diff --git a/print/templates/email/printer-setup/printer-setup.html b/print/templates/email/printer-setup/printer-setup.html index 6b295bd8f..df0b43f0c 100644 --- a/print/templates/email/printer-setup/printer-setup.html +++ b/print/templates/email/printer-setup/printer-setup.html @@ -1,5 +1,5 @@ - + diff --git a/print/templates/email/printer-setup/printer-setup.js b/print/templates/email/printer-setup/printer-setup.js index 86ae0044a..4aa63587f 100755 --- a/print/templates/email/printer-setup/printer-setup.js +++ b/print/templates/email/printer-setup/printer-setup.js @@ -8,7 +8,7 @@ const attachments = require('./attachments.json'); module.exports = { name: 'printer-setup', async serverPrefetch() { - this.client = await this.fetchClient(this.clientId); + this.client = await this.fetchClient(this.recipientId); }, data() { return {attachments}; @@ -16,19 +16,19 @@ module.exports = { methods: { fetchClient(clientId) { return db.findOne(` - SELECT - c.id, - u.lang locale, - u.name AS userName, - c.email recipient, - CONCAT(w.lastName, ' ', w.firstName) salesPersonName, - w.phone AS salesPersonPhone, - CONCAT(wu.name, '@verdnatura.es') AS salesPersonEmail - FROM client c - JOIN account.user u ON u.id = c.id - LEFT JOIN worker w ON w.id = c.salesPersonFk - LEFT JOIN account.user wu ON wu.id = w.userFk - WHERE c.id = ?`, [clientId]); + SELECT + c.id, + u.lang locale, + u.name AS userName, + c.email recipient, + CONCAT(w.lastName, ' ', w.firstName) salesPersonName, + w.phone AS salesPersonPhone, + CONCAT(wu.name, '@verdnatura.es') AS salesPersonEmail + FROM client c + JOIN account.user u ON u.id = c.id + LEFT JOIN worker w ON w.id = c.salesPersonFk + LEFT JOIN account.user wu ON wu.id = w.userFk + WHERE c.id = ?`, [clientId]); } }, components: { @@ -37,7 +37,7 @@ module.exports = { 'attachment': attachment.build() }, props: { - clientId: { + recipientId: { required: true } } diff --git a/print/templates/email/sepa-core/sepa-core.html b/print/templates/email/sepa-core/sepa-core.html index b71c8e10f..853597bf8 100644 --- a/print/templates/email/sepa-core/sepa-core.html +++ b/print/templates/email/sepa-core/sepa-core.html @@ -1,5 +1,5 @@ - + diff --git a/print/templates/email/sepa-core/sepa-core.js b/print/templates/email/sepa-core/sepa-core.js index 31afb1115..76f8d842f 100755 --- a/print/templates/email/sepa-core/sepa-core.js +++ b/print/templates/email/sepa-core/sepa-core.js @@ -15,7 +15,7 @@ module.exports = { 'attachment': attachment.build() }, props: { - clientId: { + recipientId: { required: true }, companyId: { diff --git a/print/templates/reports/campaign-metrics/campaign-metrics.html b/print/templates/reports/campaign-metrics/campaign-metrics.html index ee1908164..d125ab7e2 100644 --- a/print/templates/reports/campaign-metrics/campaign-metrics.html +++ b/print/templates/reports/campaign-metrics/campaign-metrics.html @@ -1,5 +1,5 @@ - + diff --git a/print/templates/reports/campaign-metrics/campaign-metrics.js b/print/templates/reports/campaign-metrics/campaign-metrics.js index f72069260..ef1d735de 100755 --- a/print/templates/reports/campaign-metrics/campaign-metrics.js +++ b/print/templates/reports/campaign-metrics/campaign-metrics.js @@ -9,9 +9,8 @@ module.exports = { this.to = new Date(this.to); this.from = new Date(this.from); - this.client = await this.fetchClient(this.clientId); - - this.sales = await this.fetchSales(this.clientId, this.from, this.to); + this.client = await this.fetchClient(this.recipientId); + this.sales = await this.fetchSales(this.recipientId, this.from, this.to); if (!this.client) throw new Error('Something went wrong'); @@ -63,7 +62,7 @@ module.exports = { 'report-footer': reportFooter.build() }, props: { - clientId: { + recipientId: { required: true }, from: { diff --git a/print/templates/reports/claim-pickup-order/claim-pickup-order.html b/print/templates/reports/claim-pickup-order/claim-pickup-order.html index f23ee3401..59647cf9a 100644 --- a/print/templates/reports/claim-pickup-order/claim-pickup-order.html +++ b/print/templates/reports/claim-pickup-order/claim-pickup-order.html @@ -1,5 +1,5 @@ - +
diff --git a/print/templates/reports/delivery-note/delivery-note.html b/print/templates/reports/delivery-note/delivery-note.html index 719397c08..913946196 100644 --- a/print/templates/reports/delivery-note/delivery-note.html +++ b/print/templates/reports/delivery-note/delivery-note.html @@ -1,5 +1,5 @@ - +
@@ -88,10 +88,10 @@ - + - + - +
{{sale.itemFk}} {{sale.quantity}} {{sale.concept}}{{sale.price | currency('EUR', locale)}}{{sale.price | currency('EUR', $i18n.locale)}} {{(sale.discount / 100) | percentage}} {{sale.vatType}}{{sale.price * sale.quantity * (1 - sale.discount / 100) | currency('EUR', locale)}}{{sale.price * sale.quantity * (1 - sale.discount / 100) | currency('EUR', $i18n.locale)}}
@@ -125,7 +125,7 @@ {{$t('subtotal')}} {{getSubTotal() | currency('EUR', locale)}}{{getSubTotal() | currency('EUR', $i18n.locale)}}
@@ -149,13 +149,13 @@ {{service.description}} {{service.quantity}} {{service.taxDescription}} - {{service.price | currency('EUR', locale)}} + {{service.price | currency('EUR', $i18n.locale)}} - {{$t('total')}} {{serviceTotal | currency('EUR', locale)}} + {{$t('total')}} {{serviceTotal | currency('EUR', $i18n.locale)}} @@ -180,24 +180,24 @@ {{tax.name}} - {{tax.Base | currency('EUR', locale)}} + {{tax.Base | currency('EUR', $i18n.locale)}} {{tax.vatPercent | percentage}} - {{tax.tax | currency('EUR', locale)}} + {{tax.tax | currency('EUR', $i18n.locale)}} {{$t('subtotal')}} - {{getTotalBase() | currency('EUR', locale)}} + {{getTotalBase() | currency('EUR', $i18n.locale)}} - {{getTotalTax()| currency('EUR', locale)}} + {{getTotalTax()| currency('EUR', $i18n.locale)}} {{$t('total')}} - {{getTotal() | currency('EUR', locale)}} + {{getTotal() | currency('EUR', $i18n.locale)}} diff --git a/print/templates/reports/driver-route/driver-route.html b/print/templates/reports/driver-route/driver-route.html index ba9a339da..919ed0679 100644 --- a/print/templates/reports/driver-route/driver-route.html +++ b/print/templates/reports/driver-route/driver-route.html @@ -1,5 +1,5 @@ - + @@ -141,7 +141,7 @@ - +
{{$t('import')}}{{ticket.import | currency('EUR', locale)}}{{ticket.import | currency('EUR', $i18n.locale)}}
diff --git a/print/templates/reports/entry-order/entry-order.html b/print/templates/reports/entry-order/entry-order.html index 5ee45787c..3c1cdbd33 100644 --- a/print/templates/reports/entry-order/entry-order.html +++ b/print/templates/reports/entry-order/entry-order.html @@ -1,5 +1,5 @@ - + @@ -77,8 +77,8 @@ - - + + - +
{{buy.packing}} {{buy.itemName}} {{buy.quantity | number}}{{buy.buyingValue | currency('EUR', locale)}}{{buy.buyingValue * buy.quantity | currency('EUR', locale)}}{{buy.buyingValue | currency('EUR', $i18n.locale)}}{{buy.buyingValue * buy.quantity | currency('EUR', $i18n.locale)}}
@@ -106,7 +106,7 @@ {{$t('total')}} {{getTotal() | currency('EUR', locale)}}{{getTotal() | currency('EUR', $i18n.locale)}}
diff --git a/print/templates/reports/item-label/item-label.html b/print/templates/reports/item-label/item-label.html index 0cb351b27..3f2d7ce69 100644 --- a/print/templates/reports/item-label/item-label.html +++ b/print/templates/reports/item-label/item-label.html @@ -1,5 +1,5 @@ - + diff --git a/print/templates/reports/letter-debtor/letter-debtor.html b/print/templates/reports/letter-debtor/letter-debtor.html index 534798f5e..81a001765 100644 --- a/print/templates/reports/letter-debtor/letter-debtor.html +++ b/print/templates/reports/letter-debtor/letter-debtor.html @@ -1,5 +1,5 @@ - +
diff --git a/print/templates/reports/letter-debtor/letter-debtor.js b/print/templates/reports/letter-debtor/letter-debtor.js index f099c1869..7da1b438c 100755 --- a/print/templates/reports/letter-debtor/letter-debtor.js +++ b/print/templates/reports/letter-debtor/letter-debtor.js @@ -6,8 +6,8 @@ const reportFooter = new Component('report-footer'); module.exports = { name: 'letter-debtor', async serverPrefetch() { - this.client = await this.fetchClient(this.clientId); - this.sales = await this.fetchSales(this.clientId, this.companyId); + this.client = await this.fetchClient(this.recipientId); + this.sales = await this.fetchSales(this.recipientId, this.companyId); if (!this.client) throw new Error('Something went wrong'); @@ -79,7 +79,7 @@ module.exports = { 'report-footer': reportFooter.build() }, props: { - clientId: { + recipientId: { required: true }, companyId: { diff --git a/print/templates/reports/receipt/receipt.html b/print/templates/reports/receipt/receipt.html index 5538b7c3f..9a4e1964c 100644 --- a/print/templates/reports/receipt/receipt.html +++ b/print/templates/reports/receipt/receipt.html @@ -1,5 +1,5 @@ - +
diff --git a/print/templates/reports/sepa-core/sepa-core.html b/print/templates/reports/sepa-core/sepa-core.html index 720f70058..d14a3ce6e 100644 --- a/print/templates/reports/sepa-core/sepa-core.html +++ b/print/templates/reports/sepa-core/sepa-core.html @@ -1,5 +1,5 @@ - +
diff --git a/print/templates/reports/sepa-core/sepa-core.js b/print/templates/reports/sepa-core/sepa-core.js index de3a2983d..a63b5b704 100755 --- a/print/templates/reports/sepa-core/sepa-core.js +++ b/print/templates/reports/sepa-core/sepa-core.js @@ -6,8 +6,8 @@ const reportFooter = new Component('report-footer'); const rptSepaCore = { name: 'sepa-core', async serverPrefetch() { - this.client = await this.fetchClient(this.clientId, this.companyId); - this.supplier = await this.fetchSupplier(this.clientId, this.companyId); + this.client = await this.fetchClient(this.recipientId, this.companyId); + this.supplier = await this.fetchSupplier(this.recipientId, this.companyId); if (!this.client) throw new Error('Something went wrong'); @@ -67,7 +67,7 @@ const rptSepaCore = { 'report-footer': reportFooter.build() }, props: { - clientId: { + recipientId: { required: true }, companyId: { @@ -76,5 +76,4 @@ const rptSepaCore = { } }; - module.exports = rptSepaCore; diff --git a/print/templates/reports/zone/zone.html b/print/templates/reports/zone/zone.html index 8e6406ad4..c1e8d1ec1 100644 --- a/print/templates/reports/zone/zone.html +++ b/print/templates/reports/zone/zone.html @@ -1,5 +1,5 @@ - +