From e01d676bb13b9d6ac178d75b6a53f21b8635ca1c Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 15 Dec 2021 14:45:45 +0100 Subject: [PATCH 01/24] feat(ticket_basic-data_step-two): show visible and option withoutNegatives --- .../back/methods/ticket/priceDifference.js | 15 ++++++++--- .../front/basic-data/step-two/index.html | 14 ++++++++++ .../ticket/front/basic-data/step-two/index.js | 27 +++++++++++++++++-- .../front/basic-data/step-two/locale/es.yml | 3 ++- 4 files changed, 52 insertions(+), 7 deletions(-) diff --git a/modules/ticket/back/methods/ticket/priceDifference.js b/modules/ticket/back/methods/ticket/priceDifference.js index 2456d3de0..56f6ad7d2 100644 --- a/modules/ticket/back/methods/ticket/priceDifference.js +++ b/modules/ticket/back/methods/ticket/priceDifference.js @@ -100,19 +100,25 @@ module.exports = Self => { totalDifference: 0.00, }; - const query = `CALL vn.ticket_priceDifference(?, ?, ?, ?, ?)`; + // Get items visible + let query = `CALL ticketGetVisibleAvailable(?)`; + const [salesVisible] = await Self.rawSql(query, [args.id], myOptions); + + const itemVisible = new Map(); + for (sale of salesVisible) + itemVisible.set(sale.id, sale.visible); + + // Sale price component, one per sale + query = `CALL vn.ticket_priceDifference(?, ?, ?, ?, ?)`; const params = [args.id, args.landed, args.addressId, args.zoneId, args.warehouseId]; const [difComponents] = await Self.rawSql(query, params, myOptions); const map = new Map(); - - // Sale price component, one per sale for (difComponent of difComponents) map.set(difComponent.saleFk, difComponent); for (sale of salesObj.items) { const difComponent = map.get(sale.id); - if (difComponent) { sale.component = difComponent; @@ -125,6 +131,7 @@ module.exports = Self => { salesObj.totalUnitPrice += sale.price; salesObj.totalUnitPrice = round(salesObj.totalUnitPrice); + sale.visible = itemVisible.get(sale.id); } if (tx) await tx.commit(); diff --git a/modules/ticket/front/basic-data/step-two/index.html b/modules/ticket/front/basic-data/step-two/index.html index 439f2b527..324133578 100644 --- a/modules/ticket/front/basic-data/step-two/index.html +++ b/modules/ticket/front/basic-data/step-two/index.html @@ -9,6 +9,7 @@ Item Description + Visible Quantity Price (PPU) New (PPU) @@ -31,6 +32,13 @@ tabindex="-1"> + + + {{::sale.visible}} + + {{::sale.quantity}} {{::sale.price | currency: 'EUR': 2}} {{::sale.component.newPrice | currency: 'EUR': 2}} @@ -66,6 +74,12 @@ +
+ + +
diff --git a/modules/ticket/front/basic-data/step-two/index.js b/modules/ticket/front/basic-data/step-two/index.js index 7ffdb8315..fbaa52a7e 100644 --- a/modules/ticket/front/basic-data/step-two/index.js +++ b/modules/ticket/front/basic-data/step-two/index.js @@ -20,6 +20,7 @@ class Controller extends Component { this.getTotalNewPrice(); this.getTotalDifferenceOfPrice(); this.loadDefaultTicketAction(); + this.ticketHaveNegatives(); } loadDefaultTicketAction() { @@ -63,15 +64,37 @@ class Controller extends Component { this.totalPriceDifference = totalPriceDifference; } + ticketHaveNegatives() { + let haveNegatives = false; + this.ticket.sale.items.forEach(item => { + if (item.quantity > item.visible) + haveNegatives = true; + }); + this.haveNegatives = haveNegatives; + } + onSubmit() { if (!this.ticket.option) { return this.vnApp.showError( this.$t('Choose an option') ); } + if (this.ticket.withoutNegatives) { + let salesNewTicket = []; + this.ticket.sale.items.forEach(item => { + if (item.visible >= item.quantity) + salesNewTicket.push(item); + }); - let query = `tickets/${this.ticket.id}/componentUpdate`; - let params = { + const params = { + sales: salesNewTicket + }; + + const query = `tickets/${this.ticket.id}/transferSales`; + this.$http.post(query, params); + } + const query = `tickets/${this.ticket.id}/componentUpdate`; + const params = { clientFk: this.ticket.clientFk, nickname: this.ticket.nickname, agencyModeFk: this.ticket.agencyModeFk, diff --git a/modules/ticket/front/basic-data/step-two/locale/es.yml b/modules/ticket/front/basic-data/step-two/locale/es.yml index a2a07991b..4f68d33e2 100644 --- a/modules/ticket/front/basic-data/step-two/locale/es.yml +++ b/modules/ticket/front/basic-data/step-two/locale/es.yml @@ -5,4 +5,5 @@ Charge difference to: Cargar diferencia a The ticket has been unrouted: El ticket ha sido desenrutado Price: Precio New price: Nuevo precio -Price difference: Diferencia de precio \ No newline at end of file +Price difference: Diferencia de precio +Without create negatives: Sin crear negativos \ No newline at end of file From 3e91929d0d8aa02e2ffc765cae725fc6ab98cdcc Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 15 Dec 2021 15:16:21 +0100 Subject: [PATCH 02/24] half test --- .../ticket/specs/priceDifference.spec.js | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js index fed899d77..173bad2fd 100644 --- a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js +++ b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js @@ -59,4 +59,36 @@ describe('sale priceDifference()', () => { expect(error).toEqual(new UserError(`The sales of this ticket can't be modified`)); }); + + it('should return ticket visible', async() => { + const tx = await models.Ticket.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const tomorrow = new Date(); + tomorrow.setDate(tomorrow.getDate() + 1); + + const ctx = {req: {accessToken: {userId: 1106}}}; + ctx.args = { + id: 11, + landed: tomorrow, + addressId: 122, + agencyModeId: 7, + zoneId: 3, + warehouseId: 1 + }; + + const result = await models.Ticket.priceDifference(ctx, options); + console.log(result.items[0]); + + expect(result.totalUnitPrice).toEqual(result.totalNewPrice); + expect(result.totalDifference).toEqual(0); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); }); From 87f994aa7786065d40875961ea883bf53a8ea9b1 Mon Sep 17 00:00:00 2001 From: alexm Date: Thu, 16 Dec 2021 08:14:27 +0100 Subject: [PATCH 03/24] test(ticket_basci-data_step-two): back and front --- .../ticket/specs/priceDifference.spec.js | 7 ++++--- .../front/basic-data/step-two/index.spec.js | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js index 173bad2fd..e9648cebe 100644 --- a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js +++ b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js @@ -80,10 +80,11 @@ describe('sale priceDifference()', () => { }; const result = await models.Ticket.priceDifference(ctx, options); - console.log(result.items[0]); + const firstItem = result.items[0]; + const secondtItem = result.items[1]; - expect(result.totalUnitPrice).toEqual(result.totalNewPrice); - expect(result.totalDifference).toEqual(0); + expect(firstItem.visible).toEqual(445); + expect(secondtItem.visible).toEqual(1980); await tx.rollback(); } catch (e) { diff --git a/modules/ticket/front/basic-data/step-two/index.spec.js b/modules/ticket/front/basic-data/step-two/index.spec.js index ea8268716..556176d05 100644 --- a/modules/ticket/front/basic-data/step-two/index.spec.js +++ b/modules/ticket/front/basic-data/step-two/index.spec.js @@ -64,5 +64,22 @@ describe('Ticket', () => { expect(controller.totalPriceDifference).toEqual(0.3); }); }); + + fdescribe('ticketHaveNegatives()', () => { + it('should show if ticket have any negative', () => { + controller.ticket = { + sale: { + items: [{ + quantity: 2, + visible: 1 + }] + } + }; + + controller.ticketHaveNegatives(); + + expect(controller.haveNegatives).toEqual(true); + }); + }); }); }); From 850ea2ef39a701f31aac0ac01c73328d1a7f36fa Mon Sep 17 00:00:00 2001 From: alexm Date: Fri, 17 Dec 2021 12:38:56 +0100 Subject: [PATCH 04/24] getVisible sql --- .../00-ticket_getVisibleAvailable .sql | 50 +++++++++++++++++++ .../01-ticketGetVisibleAvailable .sql | 9 ++++ db/changes/10400-christmas/delete.keep | 1 - .../back/methods/ticket/priceDifference.js | 22 ++++++-- .../ticket/front/basic-data/step-one/index.js | 3 +- .../ticket/front/basic-data/step-two/index.js | 2 + 6 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 db/changes/10400-christmas/00-ticket_getVisibleAvailable .sql create mode 100644 db/changes/10400-christmas/01-ticketGetVisibleAvailable .sql delete mode 100644 db/changes/10400-christmas/delete.keep diff --git a/db/changes/10400-christmas/00-ticket_getVisibleAvailable .sql b/db/changes/10400-christmas/00-ticket_getVisibleAvailable .sql new file mode 100644 index 000000000..79a9b922a --- /dev/null +++ b/db/changes/10400-christmas/00-ticket_getVisibleAvailable .sql @@ -0,0 +1,50 @@ +DROP PROCEDURE IF EXISTS `vn`.`ticket_getVisibleAvailable`; + +DELIMITER $$ +$$ +CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticket_getVisibleAvailable`(vTicket INT, vDate DATE) +BEGIN + DECLARE vVisibleCalc INT; + DECLARE vAvailableCalc INT; + DECLARE vShipped DATE; + DECLARE vWarehouse TINYINT; + DECLARE vAlertLevel INT; + + SELECT t.warehouseFk, t.shipped, ts.alertLevel + INTO vWarehouse, vShipped, vAlertLevel + FROM ticket t + LEFT JOIN ticketState ts ON ts.ticketFk = vTicket + WHERE t.id = vTicket; + + IF vDate IS NULL THEN + SET vDate = vShipped; + END IF; + + IF vAlertLevel IS NULL OR vAlertLevel = 0 THEN + IF vDate >= CURDATE() THEN + CALL cache.available_refresh(vAvailableCalc, FALSE, vWarehouse, vDate); + END IF; + IF vDate = CURDATE() THEN + CALL cache.visible_refresh(vVisibleCalc, FALSE, vWarehouse); + END IF; + END IF; + + SELECT s.id, + s.itemFk, + s.quantity, + s.concept, + s.price, + s.reserved, + s.discount, + v.visible, + av.available, + it.image, + it.subName + FROM sale s + LEFT JOIN cache.visible v ON v.item_id = s.itemFk AND v.calc_id = vVisibleCalc + LEFT JOIN cache.available av ON av.item_id = s.itemFk AND av.calc_id = vAvailableCalc + LEFT JOIN item it ON it.id = s.itemFk + WHERE s.ticketFk = vTicket + ORDER BY s.concept; +END$$ +DELIMITER ; diff --git a/db/changes/10400-christmas/01-ticketGetVisibleAvailable .sql b/db/changes/10400-christmas/01-ticketGetVisibleAvailable .sql new file mode 100644 index 000000000..84c4db8d5 --- /dev/null +++ b/db/changes/10400-christmas/01-ticketGetVisibleAvailable .sql @@ -0,0 +1,9 @@ +DROP PROCEDURE IF EXISTS vn.ticketGetVisibleAvailable; + +DELIMITER $$ +$$ +CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticketGetVisibleAvailable`(vTicket INT) +BEGIN + CALL `ticket_getVisibleAvailable`(vTicket, null); +END$$ +DELIMITER ; diff --git a/db/changes/10400-christmas/delete.keep b/db/changes/10400-christmas/delete.keep deleted file mode 100644 index 603d82d74..000000000 --- a/db/changes/10400-christmas/delete.keep +++ /dev/null @@ -1 +0,0 @@ -Delete me! \ No newline at end of file diff --git a/modules/ticket/back/methods/ticket/priceDifference.js b/modules/ticket/back/methods/ticket/priceDifference.js index 56f6ad7d2..3448af17b 100644 --- a/modules/ticket/back/methods/ticket/priceDifference.js +++ b/modules/ticket/back/methods/ticket/priceDifference.js @@ -40,6 +40,12 @@ module.exports = Self => { type: 'number', description: 'The warehouse id', required: true + }, + { + arg: 'shipped', + type: 'date', + description: 'shipped', + required: true }], returns: { type: ['object'], @@ -101,16 +107,22 @@ module.exports = Self => { }; // Get items visible - let query = `CALL ticketGetVisibleAvailable(?)`; - const [salesVisible] = await Self.rawSql(query, [args.id], myOptions); + let query = `CALL ticket_getVisibleAvailable(?,?)`; + let params = [args.id, args.shipped]; + const [salesVisible] = await Self.rawSql(query, params, myOptions); const itemVisible = new Map(); - for (sale of salesVisible) - itemVisible.set(sale.id, sale.visible); + for (sale of salesVisible) { + let visible = sale.available; + if (visible == null) + visible = 0; + + itemVisible.set(sale.id, visible); + } // Sale price component, one per sale query = `CALL vn.ticket_priceDifference(?, ?, ?, ?, ?)`; - const params = [args.id, args.landed, args.addressId, args.zoneId, args.warehouseId]; + params = [args.id, args.landed, args.addressId, args.zoneId, args.warehouseId]; const [difComponents] = await Self.rawSql(query, params, myOptions); const map = new Map(); diff --git a/modules/ticket/front/basic-data/step-one/index.js b/modules/ticket/front/basic-data/step-one/index.js index 215f36a46..f532265e2 100644 --- a/modules/ticket/front/basic-data/step-one/index.js +++ b/modules/ticket/front/basic-data/step-one/index.js @@ -201,7 +201,8 @@ class Controller extends Component { addressId: this.ticket.addressFk, agencyModeId: this.ticket.agencyModeFk, zoneId: this.ticket.zoneFk, - warehouseId: this.ticket.warehouseFk + warehouseId: this.ticket.warehouseFk, + shipped: this.ticket.shipped }; return this.$http.post(query, params).then(res => { diff --git a/modules/ticket/front/basic-data/step-two/index.js b/modules/ticket/front/basic-data/step-two/index.js index fbaa52a7e..4a6a0302e 100644 --- a/modules/ticket/front/basic-data/step-two/index.js +++ b/modules/ticket/front/basic-data/step-two/index.js @@ -79,6 +79,7 @@ class Controller extends Component { this.$t('Choose an option') ); } + if (this.ticket.withoutNegatives) { let salesNewTicket = []; this.ticket.sale.items.forEach(item => { @@ -93,6 +94,7 @@ class Controller extends Component { const query = `tickets/${this.ticket.id}/transferSales`; this.$http.post(query, params); } + const query = `tickets/${this.ticket.id}/componentUpdate`; const params = { clientFk: this.ticket.clientFk, From b0019d09ad4f8688bde8f79ccfae9063c1c99ad3 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 20 Dec 2021 13:50:31 +0100 Subject: [PATCH 05/24] feat(ticket_basic-data_step-two): adapted for available and transfer sales in back --- ....sql => 00-ticket_getVisibleAvailable.sql} | 4 +-- ... .sql => 01-ticketGetVisibleAvailable.sql} | 5 ++-- loopback/locale/es.json | 3 ++- .../back/methods/ticket/componentUpdate.js | 25 ++++++++++++++++- .../back/methods/ticket/priceDifference.js | 18 ++++++------- .../front/basic-data/step-two/index.html | 6 ++--- .../ticket/front/basic-data/step-two/index.js | 27 +++++++------------ 7 files changed, 52 insertions(+), 36 deletions(-) rename db/changes/10400-christmas/{00-ticket_getVisibleAvailable .sql => 00-ticket_getVisibleAvailable.sql} (95%) rename db/changes/10400-christmas/{01-ticketGetVisibleAvailable .sql => 01-ticketGetVisibleAvailable.sql} (66%) diff --git a/db/changes/10400-christmas/00-ticket_getVisibleAvailable .sql b/db/changes/10400-christmas/00-ticket_getVisibleAvailable.sql similarity index 95% rename from db/changes/10400-christmas/00-ticket_getVisibleAvailable .sql rename to db/changes/10400-christmas/00-ticket_getVisibleAvailable.sql index 79a9b922a..6151b786d 100644 --- a/db/changes/10400-christmas/00-ticket_getVisibleAvailable .sql +++ b/db/changes/10400-christmas/00-ticket_getVisibleAvailable.sql @@ -2,13 +2,13 @@ DROP PROCEDURE IF EXISTS `vn`.`ticket_getVisibleAvailable`; DELIMITER $$ $$ -CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticket_getVisibleAvailable`(vTicket INT, vDate DATE) +CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticket_getVisibleAvailable`(`vTicket` INT, `vDate` DATE) BEGIN DECLARE vVisibleCalc INT; DECLARE vAvailableCalc INT; DECLARE vShipped DATE; DECLARE vWarehouse TINYINT; - DECLARE vAlertLevel INT; + DECLARE vAlertLevel INT; SELECT t.warehouseFk, t.shipped, ts.alertLevel INTO vWarehouse, vShipped, vAlertLevel diff --git a/db/changes/10400-christmas/01-ticketGetVisibleAvailable .sql b/db/changes/10400-christmas/01-ticketGetVisibleAvailable.sql similarity index 66% rename from db/changes/10400-christmas/01-ticketGetVisibleAvailable .sql rename to db/changes/10400-christmas/01-ticketGetVisibleAvailable.sql index 84c4db8d5..fc2429e72 100644 --- a/db/changes/10400-christmas/01-ticketGetVisibleAvailable .sql +++ b/db/changes/10400-christmas/01-ticketGetVisibleAvailable.sql @@ -1,9 +1,10 @@ -DROP PROCEDURE IF EXISTS vn.ticketGetVisibleAvailable; +DROP PROCEDURE IF EXISTS `vn`.`ticketGetVisibleAvailable`; DELIMITER $$ $$ -CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticketGetVisibleAvailable`(vTicket INT) +CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticketGetVisibleAvailable`(`vTicket` INT) BEGIN CALL `ticket_getVisibleAvailable`(vTicket, null); END$$ DELIMITER ; + \ No newline at end of file diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 2611ee0dd..aa60f975e 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -216,5 +216,6 @@ "The type of business must be filled in basic data": "El tipo de negocio debe estar rellenado en datos básicos", "You can't create a claim from a ticket delivered more than seven days ago": "No puedes crear una reclamación de un ticket entregado hace más de siete días", "The worker has hours recorded that day": "El trabajador tiene horas fichadas ese día", - "The worker has a marked absence that day": "El trabajador tiene marcada una ausencia ese día" + "The worker has a marked absence that day": "El trabajador tiene marcada una ausencia ese día", + "isWithoutNegatives": "Tiene Negativos" } \ No newline at end of file diff --git a/modules/ticket/back/methods/ticket/componentUpdate.js b/modules/ticket/back/methods/ticket/componentUpdate.js index 515689649..f620adb45 100644 --- a/modules/ticket/back/methods/ticket/componentUpdate.js +++ b/modules/ticket/back/methods/ticket/componentUpdate.js @@ -77,6 +77,12 @@ module.exports = Self => { type: 'number', description: 'Action id', required: true + }, + { + arg: 'isWithoutNegatives', + type: 'boolean', + description: 'Is whithout negatives', + required: true }], returns: { type: ['object'], @@ -112,11 +118,28 @@ module.exports = Self => { const isProductionBoss = await models.Account.hasRole(userId, 'productionBoss', myOptions); if (!isProductionBoss) { - const zoneShipped = await models.Agency.getShipped(args.landed, args.addressFk, args.agencyModeFk, args.warehouseFk, myOptions); + const params = [args.landed, args.addressFk, args.agencyModeFk, args.warehouseFk]; + const zoneShipped = await models.Agency.getShipped(params, myOptions); if (!zoneShipped || zoneShipped.zoneFk != args.zoneFk) throw new UserError(`You don't have privileges to change the zone`); } + if (args.isWithoutNegatives) { + let query = `CALL ticket_getVisibleAvailable(?,?)`; + let params = [args.id, args.shipped]; + const [salesAvailable] = await Self.rawSql(query, params, myOptions); + + let salesNewTicket = []; + salesAvailable.forEach(sale => { + if (sale.available >= sale.quantity) + salesNewTicket.push(sale); + }); + + if (salesNewTicket.length) { + const newTicket = await models.Ticket.transferSales(ctx, args.id, null, salesNewTicket, myOptions); + args.id = newTicket.id; + } + } const originalTicket = await models.Ticket.findOne({ where: {id: args.id}, diff --git a/modules/ticket/back/methods/ticket/priceDifference.js b/modules/ticket/back/methods/ticket/priceDifference.js index 3448af17b..d933e9c22 100644 --- a/modules/ticket/back/methods/ticket/priceDifference.js +++ b/modules/ticket/back/methods/ticket/priceDifference.js @@ -106,18 +106,18 @@ module.exports = Self => { totalDifference: 0.00, }; - // Get items visible + // Get items available let query = `CALL ticket_getVisibleAvailable(?,?)`; let params = [args.id, args.shipped]; - const [salesVisible] = await Self.rawSql(query, params, myOptions); + const [salesAvailable] = await Self.rawSql(query, params, myOptions); - const itemVisible = new Map(); - for (sale of salesVisible) { - let visible = sale.available; - if (visible == null) - visible = 0; + const itemAvailable = new Map(); + for (sale of salesAvailable) { + let available = sale.available; + if (available == null) + available = 0; - itemVisible.set(sale.id, visible); + itemAvailable.set(sale.id, available); } // Sale price component, one per sale @@ -143,7 +143,7 @@ module.exports = Self => { salesObj.totalUnitPrice += sale.price; salesObj.totalUnitPrice = round(salesObj.totalUnitPrice); - sale.visible = itemVisible.get(sale.id); + sale.available = itemAvailable.get(sale.id); } if (tx) await tx.commit(); diff --git a/modules/ticket/front/basic-data/step-two/index.html b/modules/ticket/front/basic-data/step-two/index.html index 324133578..27569b909 100644 --- a/modules/ticket/front/basic-data/step-two/index.html +++ b/modules/ticket/front/basic-data/step-two/index.html @@ -9,7 +9,7 @@ Item Description - Visible + Available Quantity Price (PPU) New (PPU) @@ -35,8 +35,8 @@ - {{::sale.visible}} + ng-class="{'alert': sale.quantity>sale.available}"> + {{::sale.available}} {{::sale.quantity}} diff --git a/modules/ticket/front/basic-data/step-two/index.js b/modules/ticket/front/basic-data/step-two/index.js index 4a6a0302e..ec527abf0 100644 --- a/modules/ticket/front/basic-data/step-two/index.js +++ b/modules/ticket/front/basic-data/step-two/index.js @@ -66,11 +66,16 @@ class Controller extends Component { ticketHaveNegatives() { let haveNegatives = false; + let haveNotNegatives = false; + this.ticket.sale.items.forEach(item => { - if (item.quantity > item.visible) + if (item.quantity > item.available) haveNegatives = true; + else + haveNotNegatives = true; }); - this.haveNegatives = haveNegatives; + + this.haveNegatives = (haveNegatives && haveNotNegatives); } onSubmit() { @@ -80,21 +85,6 @@ class Controller extends Component { ); } - if (this.ticket.withoutNegatives) { - let salesNewTicket = []; - this.ticket.sale.items.forEach(item => { - if (item.visible >= item.quantity) - salesNewTicket.push(item); - }); - - const params = { - sales: salesNewTicket - }; - - const query = `tickets/${this.ticket.id}/transferSales`; - this.$http.post(query, params); - } - const query = `tickets/${this.ticket.id}/componentUpdate`; const params = { clientFk: this.ticket.clientFk, @@ -107,7 +97,8 @@ class Controller extends Component { shipped: this.ticket.shipped, landed: this.ticket.landed, isDeleted: this.ticket.isDeleted, - option: parseInt(this.ticket.option) + option: parseInt(this.ticket.option), + isWithoutNegatives: this.ticket.withoutNegatives }; this.$http.post(query, params).then(res => { From 18b6efe8f16886be023d476934e298c48269fb4a Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 21 Dec 2021 20:58:58 +0100 Subject: [PATCH 06/24] test(ticket_basic-data): test and fixtures --- db/dump/fixtures.sql | 9 ++- e2e/helpers/selectors.js | 4 ++ .../05-ticket/06_basic_data_steps.spec.js | 61 +++++++++++++++++++ loopback/locale/en.json | 3 +- .../back/methods/ticket/componentUpdate.js | 7 +-- .../ticket/specs/componentUpdate.spec.js | 6 +- .../ticket/specs/priceDifference.spec.js | 6 +- .../front/basic-data/step-two/index.html | 3 +- .../ticket/front/basic-data/step-two/index.js | 1 + .../front/basic-data/step-two/index.spec.js | 20 ++++-- .../front/basic-data/step-two/locale/es.yml | 3 +- 11 files changed, 103 insertions(+), 20 deletions(-) diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 3e99bd39e..ed50225b9 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -622,6 +622,7 @@ INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeF (25 ,NULL, 8, 1, NULL, CURDATE(), CURDATE(), 1101, 'Bruce Wayne', 1, NULL, 0, 1, 5, 1, CURDATE()), (26 ,NULL, 8, 1, NULL, CURDATE(), CURDATE(), 1101, 'An incredibly long alias for testing purposes', 1, NULL, 0, 1, 5, 1, CURDATE()), (27 ,NULL, 8, 1, NULL, CURDATE(), CURDATE(), 1101, 'Wolverine', 1, NULL, 0, 1, 5, 1, CURDATE()); + INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `description`) VALUES (1, 11, 1, 'ready'), @@ -665,7 +666,9 @@ INSERT INTO `vn`.`ticketTracking`(`ticketFk`, `stateFk`, `workerFk`, `created`) (21, 1, 19, DATE_ADD(NOW(), INTERVAL +1 MONTH)), (22, 1, 19, DATE_ADD(NOW(), INTERVAL +1 MONTH)), (23, 16, 21, NOW()), - (24, 16, 21, NOW()); + (24, 16, 21, NOW()), + (27, 3, 21, NOW()); + INSERT INTO `vn`.`stowaway`(`id`, `shipFk`, `created`) VALUES @@ -896,7 +899,9 @@ INSERT INTO `vn`.`sale`(`id`, `itemFk`, `ticketFk`, `concept`, `quantity`, `pric (29, 4, 17, 'Melee weapon heavy shield 1x0.5m', 20, 1.72, 0, 0, 0, CURDATE()), (30, 4, 18, 'Melee weapon heavy shield 1x0.5m', 20, 1.72, 0, 0, 0, CURDATE()), (31, 2, 23, 'Melee weapon combat fist 15cm', -5, 7.08, 0, 0, 0, CURDATE()), - (32, 1, 24, 'Ranged weapon longbow 2m', -1, 8.07, 0, 0, 0, CURDATE()); + (32, 1, 24, 'Ranged weapon longbow 2m', -1, 8.07, 0, 0, 0, CURDATE()), + (33, 4, 27, 'Melee weapon combat fist 15cm', 1, 8.07, 0, 0, 0, CURDATE()), + (34, 5, 27, 'Ranged weapon pistol 9mm', 50, 1.79, 0, 0, 0, CURDATE()); INSERT INTO `vn`.`saleChecked`(`saleFk`, `isChecked`) VALUES diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index 8675797e7..b4720f4c7 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -525,6 +525,7 @@ export default { acceptDialog: '.vn-dialog.shown button[response="accept"]', acceptChangeHourButton: '.vn-dialog.shown button[response="accept"]', descriptorDeliveryDate: 'vn-ticket-descriptor slot-body > .attributes > vn-label-value:nth-child(4) > section > span', + descriptorDeliveryAgency: 'vn-ticket-descriptor slot-body > .attributes > vn-label-value:nth-child(5) > section > span', acceptInvoiceOutButton: '.vn-confirm.shown button[response="accept"]', acceptDeleteStowawayButton: '.vn-dialog.shown button[response="accept"]' }, @@ -562,6 +563,7 @@ export default { transferQuantityInput: '.vn-popover.shown vn-table > div > vn-tbody > vn-tr > vn-td-editable > span > text', transferQuantityCell: '.vn-popover.shown vn-table > div > vn-tbody > vn-tr > vn-td-editable', firstSaleId: 'vn-ticket-sale vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(6) > span', + firstSaleText: 'vn-table div > vn-tbody > vn-tr:nth-child(1)', firstSaleClaimIcon: 'vn-ticket-sale vn-table vn-tbody > vn-tr:nth-child(1) vn-icon[icon="icon-claims"]', firstSaleDescriptorImage: '.vn-popover.shown vn-item-descriptor img', firstSaleThumbnailImage: 'vn-ticket-sale:nth-child(1) vn-tr:nth-child(1) vn-td:nth-child(3) > img', @@ -601,10 +603,12 @@ export default { ticketBasicData: { agency: 'vn-autocomplete[ng-model="$ctrl.agencyModeId"]', zone: 'vn-autocomplete[ng-model="$ctrl.zoneId"]', + shipped: 'vn-date-picker[ng-model="$ctrl.shipped"]', nextStepButton: 'vn-step-control .buttons > section:last-child vn-button', finalizeButton: 'vn-step-control .buttons > section:last-child button[type=submit]', stepTwoTotalPriceDif: 'vn-ticket-basic-data-step-two > vn-side-menu div:nth-child(4)', chargesReason: 'vn-ticket-basic-data-step-two div:nth-child(3) > vn-radio', + withoutNegatives: 'vn-check[ng-model="$ctrl.ticket.withoutNegatives"]', }, ticketComponents: { base: 'vn-ticket-components > vn-side-menu div:nth-child(1) > div:nth-child(2)' diff --git a/e2e/paths/05-ticket/06_basic_data_steps.spec.js b/e2e/paths/05-ticket/06_basic_data_steps.spec.js index a5f9a60cf..cca63cd6f 100644 --- a/e2e/paths/05-ticket/06_basic_data_steps.spec.js +++ b/e2e/paths/05-ticket/06_basic_data_steps.spec.js @@ -83,4 +83,65 @@ describe('Ticket Edit basic data path', () => { await page.waitToClick(selectors.ticketBasicData.finalizeButton); await page.waitForState('ticket.card.summary'); }); + + it(`should not find ticket`, async() => { + await page.doSearch('28'); + const count = await page.countElement(selectors.ticketsIndex.searchResult); + + expect(count).toEqual(0); + }); + + it(`should split ticket without negatives`, async() => { + const tomorrow = new Date(); + tomorrow.setDate(tomorrow.getDate() + 1); + + await page.accessToSearchResult('14'); + await page.accessToSection('ticket.card.basicData.stepOne'); + + const originalDate = await page + .waitToGetProperty(selectors.ticketDescriptor.descriptorDeliveryDate, 'innerText'); + const originalAgency = await page + .waitToGetProperty(selectors.ticketDescriptor.descriptorDeliveryAgency, 'innerText'); + + await page.autocompleteSearch(selectors.ticketBasicData.agency, 'Silla247'); + await page.pickDate(selectors.ticketBasicData.shipped, tomorrow); + await page.waitToClick(selectors.ticketBasicData.nextStepButton); + + await page.waitToClick(selectors.ticketBasicData.withoutNegatives); + await page.waitToClick(selectors.ticketBasicData.finalizeButton); + + const resultDate = await page + .waitToGetProperty(selectors.ticketDescriptor.descriptorDeliveryDate, 'innerText'); + const resultAgency = await page + .waitToGetProperty(selectors.ticketDescriptor.descriptorDeliveryAgency, 'innerText'); + + expect(resultDate).toEqual(originalDate); + expect(resultAgency).toEqual(originalAgency); + }); + + it(`should new ticket have one line from splited ticket`, async() => { + const tomorrow = new Date(); + tomorrow.setDate(tomorrow.getDate() + 1); + const expectedDay = tomorrow.getDate(); + const expectedMonth = tomorrow.getMonth() + 1; + const expectedYear = tomorrow.getFullYear(); + + await page.accessToSearchResult('28'); + await page.accessToSection('ticket.card.sale'); + + const item = await page.waitToGetProperty(selectors.ticketSales.firstSaleId, 'innerText'); + const agency = await page + .waitToGetProperty(selectors.ticketDescriptor.descriptorDeliveryAgency, 'innerText'); + let date = await page + .waitToGetProperty(selectors.ticketDescriptor.descriptorDeliveryDate, 'innerText'); + + date = date.split(' '); + date = date[0].split('/'); + + expect(item).toEqual('4'); + expect(agency).toEqual('Silla247'); + expect(date[0]).toContain(expectedDay); + expect(date[1]).toContain(expectedMonth); + expect(date[2]).toContain(expectedYear); + }); }); diff --git a/loopback/locale/en.json b/loopback/locale/en.json index 15c65fd89..7f3e18d72 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -119,5 +119,6 @@ "The PDF document does not exists": "The PDF document does not exists. Try regenerating it from 'Regenerate invoice PDF' option", "This item is not available": "This item is not available", "Deny buy request": "Purchase request for ticket id [{{ticketId}}]({{{url}}}) has been rejected. Reason: {{observation}}", - "The type of business must be filled in basic data": "The type of business must be filled in basic data" + "The type of business must be filled in basic data": "The type of business must be filled in basic data", + "isWithoutNegatives": "isWithoutNegatives" } \ No newline at end of file diff --git a/modules/ticket/back/methods/ticket/componentUpdate.js b/modules/ticket/back/methods/ticket/componentUpdate.js index f620adb45..3bccebdfe 100644 --- a/modules/ticket/back/methods/ticket/componentUpdate.js +++ b/modules/ticket/back/methods/ticket/componentUpdate.js @@ -118,15 +118,14 @@ module.exports = Self => { const isProductionBoss = await models.Account.hasRole(userId, 'productionBoss', myOptions); if (!isProductionBoss) { - const params = [args.landed, args.addressFk, args.agencyModeFk, args.warehouseFk]; - const zoneShipped = await models.Agency.getShipped(params, myOptions); + const zoneShipped = await models.Agency.getShipped(args.landed, args.addressFk, args.agencyModeFk, args.warehouseFk, myOptions); if (!zoneShipped || zoneShipped.zoneFk != args.zoneFk) throw new UserError(`You don't have privileges to change the zone`); } if (args.isWithoutNegatives) { - let query = `CALL ticket_getVisibleAvailable(?,?)`; - let params = [args.id, args.shipped]; + const query = `CALL ticket_getVisibleAvailable(?,?)`; + const params = [args.id, args.shipped]; const [salesAvailable] = await Self.rawSql(query, params, myOptions); let salesNewTicket = []; diff --git a/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js b/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js index 9fa69b595..38e6ce6a7 100644 --- a/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js +++ b/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js @@ -45,7 +45,8 @@ describe('ticket componentUpdate()', () => { shipped: today, landed: tomorrow, isDeleted: false, - option: 1 + option: 1, + isWithoutNegatives: false }; let ctx = { @@ -94,7 +95,8 @@ describe('ticket componentUpdate()', () => { shipped: today, landed: tomorrow, isDeleted: false, - option: 1 + option: 1, + isWithoutNegatives: false }; const ctx = { diff --git a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js index e9648cebe..8fe906bcf 100644 --- a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js +++ b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js @@ -60,7 +60,7 @@ describe('sale priceDifference()', () => { expect(error).toEqual(new UserError(`The sales of this ticket can't be modified`)); }); - it('should return ticket visible', async() => { + it('should return ticket available', async() => { const tx = await models.Ticket.beginTransaction({}); try { @@ -83,8 +83,8 @@ describe('sale priceDifference()', () => { const firstItem = result.items[0]; const secondtItem = result.items[1]; - expect(firstItem.visible).toEqual(445); - expect(secondtItem.visible).toEqual(1980); + expect(firstItem.available).toEqual(410); + expect(secondtItem.available).toEqual(1870); await tx.rollback(); } catch (e) { diff --git a/modules/ticket/front/basic-data/step-two/index.html b/modules/ticket/front/basic-data/step-two/index.html index 27569b909..74b160fda 100644 --- a/modules/ticket/front/basic-data/step-two/index.html +++ b/modules/ticket/front/basic-data/step-two/index.html @@ -77,7 +77,8 @@
+ label="Without create negatives" + info="Clone this ticket with the changes and only sales availables">
diff --git a/modules/ticket/front/basic-data/step-two/index.js b/modules/ticket/front/basic-data/step-two/index.js index ec527abf0..d77090781 100644 --- a/modules/ticket/front/basic-data/step-two/index.js +++ b/modules/ticket/front/basic-data/step-two/index.js @@ -75,6 +75,7 @@ class Controller extends Component { haveNotNegatives = true; }); + this.ticket.withoutNegatives = false; this.haveNegatives = (haveNegatives && haveNotNegatives); } diff --git a/modules/ticket/front/basic-data/step-two/index.spec.js b/modules/ticket/front/basic-data/step-two/index.spec.js index 556176d05..fcd1d7e49 100644 --- a/modules/ticket/front/basic-data/step-two/index.spec.js +++ b/modules/ticket/front/basic-data/step-two/index.spec.js @@ -65,14 +65,22 @@ describe('Ticket', () => { }); }); - fdescribe('ticketHaveNegatives()', () => { - it('should show if ticket have any negative', () => { + describe('ticketHaveNegatives()', () => { + it('should show if ticket have any negative and any not negative', () => { controller.ticket = { sale: { - items: [{ - quantity: 2, - visible: 1 - }] + items: [ + { + item: 1, + quantity: 2, + available: 1 + }, + { + item: 2, + quantity: 1, + available: 5 + } + ] } }; diff --git a/modules/ticket/front/basic-data/step-two/locale/es.yml b/modules/ticket/front/basic-data/step-two/locale/es.yml index 4f68d33e2..08bef3b09 100644 --- a/modules/ticket/front/basic-data/step-two/locale/es.yml +++ b/modules/ticket/front/basic-data/step-two/locale/es.yml @@ -6,4 +6,5 @@ The ticket has been unrouted: El ticket ha sido desenrutado Price: Precio New price: Nuevo precio Price difference: Diferencia de precio -Without create negatives: Sin crear negativos \ No newline at end of file +Without create negatives: Sin crear negativos +Clone this ticket with the changes and only sales availables: Clona este ticket con los cambios y solo las ventas disponibles. \ No newline at end of file From 67dc5c2cbc885f3c2f5b3669b61c26cbe0459d9f Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 22 Dec 2021 08:11:33 +0100 Subject: [PATCH 07/24] refactor(ticket_basic-data): test e2e --- db/dump/fixtures.sql | 1 - e2e/helpers/selectors.js | 1 - e2e/paths/05-ticket/06_basic_data_steps.spec.js | 12 +++++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 8dfd6c8a8..d5bd7d879 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -669,7 +669,6 @@ INSERT INTO `vn`.`ticketTracking`(`ticketFk`, `stateFk`, `workerFk`, `created`) (24, 16, 21, NOW()), (27, 3, 21, NOW()); - INSERT INTO `vn`.`stowaway`(`id`, `shipFk`, `created`) VALUES (12, 13, CURDATE()); diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index b4720f4c7..e088f5682 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -563,7 +563,6 @@ export default { transferQuantityInput: '.vn-popover.shown vn-table > div > vn-tbody > vn-tr > vn-td-editable > span > text', transferQuantityCell: '.vn-popover.shown vn-table > div > vn-tbody > vn-tr > vn-td-editable', firstSaleId: 'vn-ticket-sale vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(6) > span', - firstSaleText: 'vn-table div > vn-tbody > vn-tr:nth-child(1)', firstSaleClaimIcon: 'vn-ticket-sale vn-table vn-tbody > vn-tr:nth-child(1) vn-icon[icon="icon-claims"]', firstSaleDescriptorImage: '.vn-popover.shown vn-item-descriptor img', firstSaleThumbnailImage: 'vn-ticket-sale:nth-child(1) vn-tr:nth-child(1) vn-td:nth-child(3) > img', diff --git a/e2e/paths/05-ticket/06_basic_data_steps.spec.js b/e2e/paths/05-ticket/06_basic_data_steps.spec.js index cca63cd6f..af68eefca 100644 --- a/e2e/paths/05-ticket/06_basic_data_steps.spec.js +++ b/e2e/paths/05-ticket/06_basic_data_steps.spec.js @@ -8,7 +8,7 @@ describe('Ticket Edit basic data path', () => { beforeAll(async() => { browser = await getBrowser(); page = browser.page; - await page.loginAndModule('employee', 'ticket'); + await page.loginAndModule('employee', 'ticket'); await page.accessToSearchResult('11'); await page.accessToSection('ticket.card.basicData.stepOne'); }); @@ -95,7 +95,7 @@ describe('Ticket Edit basic data path', () => { const tomorrow = new Date(); tomorrow.setDate(tomorrow.getDate() + 1); - await page.accessToSearchResult('14'); + await page.accessToSearchResult('27'); await page.accessToSection('ticket.card.basicData.stepOne'); const originalDate = await page @@ -105,6 +105,7 @@ describe('Ticket Edit basic data path', () => { await page.autocompleteSearch(selectors.ticketBasicData.agency, 'Silla247'); await page.pickDate(selectors.ticketBasicData.shipped, tomorrow); + await page.waitToClick(selectors.ticketBasicData.nextStepButton); await page.waitToClick(selectors.ticketBasicData.withoutNegatives); @@ -122,6 +123,7 @@ describe('Ticket Edit basic data path', () => { it(`should new ticket have one line from splited ticket`, async() => { const tomorrow = new Date(); tomorrow.setDate(tomorrow.getDate() + 1); + const expectedDay = tomorrow.getDate(); const expectedMonth = tomorrow.getMonth() + 1; const expectedYear = tomorrow.getFullYear(); @@ -140,8 +142,8 @@ describe('Ticket Edit basic data path', () => { expect(item).toEqual('4'); expect(agency).toEqual('Silla247'); - expect(date[0]).toContain(expectedDay); - expect(date[1]).toContain(expectedMonth); - expect(date[2]).toContain(expectedYear); + expect(parseInt(date[0])).toEqual(expectedDay); + expect(parseInt(date[1])).toEqual(expectedMonth); + expect(parseInt(date[2])).toEqual(expectedYear); }); }); From 1e6355cddef280e686ade6d6001b026e17c6705d Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 22 Dec 2021 08:37:50 +0100 Subject: [PATCH 08/24] fixtures --- db/dump/fixtures.sql | 6 ++---- e2e/paths/05-ticket/06_basic_data_steps.spec.js | 3 ++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index d5bd7d879..bb18ec223 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -666,8 +666,7 @@ INSERT INTO `vn`.`ticketTracking`(`ticketFk`, `stateFk`, `workerFk`, `created`) (21, 1, 19, DATE_ADD(NOW(), INTERVAL +1 MONTH)), (22, 1, 19, DATE_ADD(NOW(), INTERVAL +1 MONTH)), (23, 16, 21, NOW()), - (24, 16, 21, NOW()), - (27, 3, 21, NOW()); + (24, 16, 21, NOW()); INSERT INTO `vn`.`stowaway`(`id`, `shipFk`, `created`) VALUES @@ -899,8 +898,7 @@ INSERT INTO `vn`.`sale`(`id`, `itemFk`, `ticketFk`, `concept`, `quantity`, `pric (30, 4, 18, 'Melee weapon heavy shield 1x0.5m', 20, 1.72, 0, 0, 0, CURDATE()), (31, 2, 23, 'Melee weapon combat fist 15cm', -5, 7.08, 0, 0, 0, CURDATE()), (32, 1, 24, 'Ranged weapon longbow 2m', -1, 8.07, 0, 0, 0, CURDATE()), - (33, 4, 27, 'Melee weapon combat fist 15cm', 1, 8.07, 0, 0, 0, CURDATE()), - (34, 5, 27, 'Ranged weapon pistol 9mm', 50, 1.79, 0, 0, 0, CURDATE()); + (33, 5, 14, 'Ranged weapon pistol 9mm', 50, 1.79, 0, 0, 0, CURDATE()); INSERT INTO `vn`.`saleChecked`(`saleFk`, `isChecked`) VALUES diff --git a/e2e/paths/05-ticket/06_basic_data_steps.spec.js b/e2e/paths/05-ticket/06_basic_data_steps.spec.js index af68eefca..6ae702979 100644 --- a/e2e/paths/05-ticket/06_basic_data_steps.spec.js +++ b/e2e/paths/05-ticket/06_basic_data_steps.spec.js @@ -95,7 +95,7 @@ describe('Ticket Edit basic data path', () => { const tomorrow = new Date(); tomorrow.setDate(tomorrow.getDate() + 1); - await page.accessToSearchResult('27'); + await page.accessToSearchResult('14'); await page.accessToSection('ticket.card.basicData.stepOne'); const originalDate = await page @@ -128,6 +128,7 @@ describe('Ticket Edit basic data path', () => { const expectedMonth = tomorrow.getMonth() + 1; const expectedYear = tomorrow.getFullYear(); + await page.loginAndModule('employee', 'ticket'); await page.accessToSearchResult('28'); await page.accessToSection('ticket.card.sale'); From c90a2b6e5cfb9dd54ad2672585ae03b8f40837d6 Mon Sep 17 00:00:00 2001 From: alexm Date: Thu, 13 Jan 2022 07:24:46 +0100 Subject: [PATCH 09/24] update folder changes --- db/changes/{10410-noname => 10410-january}/00-smsConfig.sql | 0 .../00-ticket_getVisibleAvailable.sql | 0 .../{10410-noname => 10410-january}/01-smsConfig_update.sql | 0 .../01-ticketGetVisibleAvailable.sql | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename db/changes/{10410-noname => 10410-january}/00-smsConfig.sql (100%) rename db/changes/{10400-christmas => 10410-january}/00-ticket_getVisibleAvailable.sql (100%) rename db/changes/{10410-noname => 10410-january}/01-smsConfig_update.sql (100%) rename db/changes/{10400-christmas => 10410-january}/01-ticketGetVisibleAvailable.sql (100%) diff --git a/db/changes/10410-noname/00-smsConfig.sql b/db/changes/10410-january/00-smsConfig.sql similarity index 100% rename from db/changes/10410-noname/00-smsConfig.sql rename to db/changes/10410-january/00-smsConfig.sql diff --git a/db/changes/10400-christmas/00-ticket_getVisibleAvailable.sql b/db/changes/10410-january/00-ticket_getVisibleAvailable.sql similarity index 100% rename from db/changes/10400-christmas/00-ticket_getVisibleAvailable.sql rename to db/changes/10410-january/00-ticket_getVisibleAvailable.sql diff --git a/db/changes/10410-noname/01-smsConfig_update.sql b/db/changes/10410-january/01-smsConfig_update.sql similarity index 100% rename from db/changes/10410-noname/01-smsConfig_update.sql rename to db/changes/10410-january/01-smsConfig_update.sql diff --git a/db/changes/10400-christmas/01-ticketGetVisibleAvailable.sql b/db/changes/10410-january/01-ticketGetVisibleAvailable.sql similarity index 100% rename from db/changes/10400-christmas/01-ticketGetVisibleAvailable.sql rename to db/changes/10410-january/01-ticketGetVisibleAvailable.sql From 61859a23c9f6a044efcc5f63350ca3f9b475913b Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 17 Jan 2022 07:14:29 +0100 Subject: [PATCH 10/24] feat(ticket): getAdvanceable --- .../10410-january/00-ticket_getAdvancable.sql | 44 ++++ .../00-ticket_getVisibleAvailable.sql | 50 ---- .../01-ticketGetVisibleAvailable.sql | 10 - loopback/locale/es.json | 239 ++---------------- .../back/methods/ticket/componentUpdate.js | 8 +- .../back/methods/ticket/priceDifference.js | 20 +- .../front/basic-data/step-two/index.html | 6 +- .../ticket/front/basic-data/step-two/index.js | 2 +- .../front/basic-data/step-two/locale/es.yml | 3 +- 9 files changed, 83 insertions(+), 299 deletions(-) create mode 100644 db/changes/10410-january/00-ticket_getAdvancable.sql delete mode 100644 db/changes/10410-january/00-ticket_getVisibleAvailable.sql delete mode 100644 db/changes/10410-january/01-ticketGetVisibleAvailable.sql diff --git a/db/changes/10410-january/00-ticket_getAdvancable.sql b/db/changes/10410-january/00-ticket_getAdvancable.sql new file mode 100644 index 000000000..599e431b3 --- /dev/null +++ b/db/changes/10410-january/00-ticket_getAdvancable.sql @@ -0,0 +1,44 @@ +DROP PROCEDURE IF EXISTS `vn`.`ticket_getAdvanceable`; + +DELIMITER $$ +$$ +CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticket_getAdvanceable`(vTicketFk INT, vDatedNew DATETIME) +BEGIN +/** + * Cálcula el stock avanzable para los artículos de un ticket + * + * @param vTicketFk -> Ticket + * @param vDatedNew -> Nueva fecha + * @return Sales con Avanzable +*/ + DECLARE vWarehouseFk INT; + DECLARE vDatedOld DATETIME; + + SELECT t.warehouseFk, t.shipped INTO vWarehouseFk, vDatedOld + FROM ticket t + WHERE t.id = vTicketFk; + + CALL itemStock(vWarehouseFk, DATE_SUB(vDatedNew, INTERVAL 1 DAY), NULL); + CALL item_getMinacum(vWarehouseFk, vDatedNew, DATEDIFF(vDatedOld, vDatedNew), NULL); + + SELECT s.id, + s.itemFk, + s.quantity, + s.concept, + s.price, + s.reserved, + s.discount, + i.image, + i.subName, + il.stock + IFNULL(im.amount, 0) AS advanceable + FROM ticket t + JOIN sale s ON s.ticketFk = t.id + JOIN item i ON i.id = s.itemFk + LEFT JOIN tmp.itemMinacum im ON im.itemFk = s.itemFk AND im.warehouseFk = vWarehouseFk + LEFT JOIN tmp.itemList il ON il.itemFk = s.itemFk + WHERE t.id = vTicketFk; + + DROP TEMPORARY TABLE IF EXISTS tmp.itemList; + DROP TEMPORARY TABLE IF EXISTS tmp.itemMinacum; +END$$ +DELIMITER ; diff --git a/db/changes/10410-january/00-ticket_getVisibleAvailable.sql b/db/changes/10410-january/00-ticket_getVisibleAvailable.sql deleted file mode 100644 index 6151b786d..000000000 --- a/db/changes/10410-january/00-ticket_getVisibleAvailable.sql +++ /dev/null @@ -1,50 +0,0 @@ -DROP PROCEDURE IF EXISTS `vn`.`ticket_getVisibleAvailable`; - -DELIMITER $$ -$$ -CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticket_getVisibleAvailable`(`vTicket` INT, `vDate` DATE) -BEGIN - DECLARE vVisibleCalc INT; - DECLARE vAvailableCalc INT; - DECLARE vShipped DATE; - DECLARE vWarehouse TINYINT; - DECLARE vAlertLevel INT; - - SELECT t.warehouseFk, t.shipped, ts.alertLevel - INTO vWarehouse, vShipped, vAlertLevel - FROM ticket t - LEFT JOIN ticketState ts ON ts.ticketFk = vTicket - WHERE t.id = vTicket; - - IF vDate IS NULL THEN - SET vDate = vShipped; - END IF; - - IF vAlertLevel IS NULL OR vAlertLevel = 0 THEN - IF vDate >= CURDATE() THEN - CALL cache.available_refresh(vAvailableCalc, FALSE, vWarehouse, vDate); - END IF; - IF vDate = CURDATE() THEN - CALL cache.visible_refresh(vVisibleCalc, FALSE, vWarehouse); - END IF; - END IF; - - SELECT s.id, - s.itemFk, - s.quantity, - s.concept, - s.price, - s.reserved, - s.discount, - v.visible, - av.available, - it.image, - it.subName - FROM sale s - LEFT JOIN cache.visible v ON v.item_id = s.itemFk AND v.calc_id = vVisibleCalc - LEFT JOIN cache.available av ON av.item_id = s.itemFk AND av.calc_id = vAvailableCalc - LEFT JOIN item it ON it.id = s.itemFk - WHERE s.ticketFk = vTicket - ORDER BY s.concept; -END$$ -DELIMITER ; diff --git a/db/changes/10410-january/01-ticketGetVisibleAvailable.sql b/db/changes/10410-january/01-ticketGetVisibleAvailable.sql deleted file mode 100644 index fc2429e72..000000000 --- a/db/changes/10410-january/01-ticketGetVisibleAvailable.sql +++ /dev/null @@ -1,10 +0,0 @@ -DROP PROCEDURE IF EXISTS `vn`.`ticketGetVisibleAvailable`; - -DELIMITER $$ -$$ -CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticketGetVisibleAvailable`(`vTicket` INT) -BEGIN - CALL `ticket_getVisibleAvailable`(vTicket, null); -END$$ -DELIMITER ; - \ No newline at end of file diff --git a/loopback/locale/es.json b/loopback/locale/es.json index a096a773d..3d5c205bd 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -1,220 +1,23 @@ { - "Phone format is invalid": "El formato del teléfono no es correcto", - "You are not allowed to change the credit": "No tienes privilegios para modificar el crédito", - "Unable to mark the equivalence surcharge": "No se puede marcar el recargo de equivalencia", - "The default consignee can not be unchecked": "No se puede desmarcar el consignatario predeterminado", - "Unable to default a disabled consignee": "No se puede poner predeterminado un consignatario desactivado", - "Can't be blank": "No puede estar en blanco", - "Invalid TIN": "NIF/CIF invalido", - "TIN must be unique": "El NIF/CIF debe ser único", - "A client with that Web User name already exists": "Ya existe un cliente con ese Usuario Web", - "Is invalid": "Is invalid", - "Quantity cannot be zero": "La cantidad no puede ser cero", - "Enter an integer different to zero": "Introduce un entero distinto de cero", - "Package cannot be blank": "El embalaje no puede estar en blanco", - "The company name must be unique": "La razón social debe ser única", - "Invalid email": "Correo electrónico inválido", - "The IBAN does not have the correct format": "El IBAN no tiene el formato correcto", - "That payment method requires an IBAN": "El método de pago seleccionado requiere un IBAN", - "That payment method requires a BIC": "El método de pago seleccionado requiere un BIC", - "State cannot be blank": "El estado no puede estar en blanco", - "Worker cannot be blank": "El trabajador no puede estar en blanco", - "Cannot change the payment method if no salesperson": "No se puede cambiar la forma de pago si no hay comercial asignado", - "can't be blank": "El campo no puede estar vacío", - "Observation type must be unique": "El tipo de observación no puede repetirse", + "Name cannot be blank": "Name cannot be blank", + "Swift / BIC cannot be empty": "Swift / BIC cannot be empty", + "Street cannot be empty": "Street cannot be empty", + "City cannot be empty": "City cannot be empty", + "Invalid email": "Invalid email", + "Phone cannot be blank": "Phone cannot be blank", "The credit must be an integer greater than or equal to zero": "The credit must be an integer greater than or equal to zero", - "The grade must be similar to the last one": "El grade debe ser similar al último", - "Only manager can change the credit": "Solo el gerente puede cambiar el credito de este cliente", - "Name cannot be blank": "El nombre no puede estar en blanco", - "Phone cannot be blank": "El teléfono no puede estar en blanco", - "Period cannot be blank": "El periodo no puede estar en blanco", - "Choose a company": "Selecciona una empresa", - "Se debe rellenar el campo de texto": "Se debe rellenar el campo de texto", - "Description should have maximum of 45 characters": "La descripción debe tener maximo 45 caracteres", - "Cannot be blank": "El campo no puede estar en blanco", - "The grade must be an integer greater than or equal to zero": "El grade debe ser un entero mayor o igual a cero", - "Sample type cannot be blank": "El tipo de plantilla no puede quedar en blanco", - "Description cannot be blank": "Se debe rellenar el campo de texto", - "The new quantity should be smaller than the old one": "La nueva cantidad debe de ser menor que la anterior", - "The value should not be greater than 100%": "El valor no debe de ser mayor de 100%", - "The value should be a number": "El valor debe ser un numero", - "This order is not editable": "Esta orden no se puede modificar", - "You can't create an order for a frozen client": "No puedes crear una orden para un cliente congelado", - "You can't create an order for a client that has a debt": "No puedes crear una orden para un cliente con deuda", - "is not a valid date": "No es una fecha valida", - "Barcode must be unique": "El código de barras debe ser único", - "The warehouse can't be repeated": "El almacén no puede repetirse", - "The tag can't be repeated": "El tag no puede repetirse", - "The observation type can't be repeated": "El tipo de observación no puede repetirse", - "A claim with that sale already exists": "Ya existe una reclamación para esta línea", - "You don't have enough privileges to change that field": "No tienes permisos para cambiar ese campo", - "Warehouse cannot be blank": "El almacén no puede quedar en blanco", - "Agency cannot be blank": "La agencia no puede quedar en blanco", - "You can't make changes on a client with verified data": "No puedes hacer cambios en un cliente con datos comprobados", - "This address doesn't exist": "Este consignatario no existe", - "You must delete the claim id %d first": "Antes debes borrar la reclamación %d", - "You don't have enough privileges": "No tienes suficientes permisos", - "Cannot check Equalization Tax in this NIF/CIF": "No se puede marcar RE en este NIF/CIF", - "You can't make changes on the basic data of an confirmed order or with rows": "No puedes cambiar los datos basicos de una orden con artículos", - "INVALID_USER_NAME": "El nombre de usuario solo debe contener letras minúsculas o, a partir del segundo carácter, números o subguiones, no esta permitido el uso de la letra ñ", - "You can't create a ticket for a frozen client": "No puedes crear un ticket para un cliente congelado", - "You can't create a ticket for a inactive client": "No puedes crear un ticket para un cliente inactivo", - "Tag value cannot be blank": "El valor del tag no puede quedar en blanco", - "ORDER_EMPTY": "Cesta vacía", - "You don't have enough privileges to do that": "No tienes permisos para cambiar esto", - "NO SE PUEDE DESACTIVAR EL CONSIGNAT": "NO SE PUEDE DESACTIVAR EL CONSIGNAT", - "Error. El NIF/CIF está repetido": "Error. El NIF/CIF está repetido", - "Street cannot be empty": "Dirección no puede estar en blanco", - "City cannot be empty": "Cuidad no puede estar en blanco", - "Code cannot be blank": "Código no puede estar en blanco", - "You cannot remove this department": "No puedes eliminar este departamento", - "The extension must be unique": "La extensión debe ser unica", - "The secret can't be blank": "La contraseña no puede estar en blanco", - "We weren't able to send this SMS": "No hemos podido enviar el SMS", - "This client can't be invoiced": "Este cliente no puede ser facturado", - "This ticket can't be invoiced": "Este ticket no puede ser facturado", - "You cannot add or modify services to an invoiced ticket": "No puedes añadir o modificar servicios a un ticket facturado", - "This ticket can not be modified": "Este ticket no puede ser modificado", - "The introduced hour already exists": "Esta hora ya ha sido introducida", - "INFINITE_LOOP": "Existe una dependencia entre dos Jefes", - "The sales of the current ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas", - "The sales of the receiver ticket can't be modified": "Las lineas del ticket al que envias no pueden ser modificadas", - "NO_AGENCY_AVAILABLE": "No hay una zona de reparto disponible con estos parámetros", - "ERROR_PAST_SHIPMENT": "No puedes seleccionar una fecha de envío en pasado", - "The current ticket can't be modified": "El ticket actual no puede ser modificado", - "The current claim can't be modified": "La reclamación actual no puede ser modificada", - "The sales of this ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas", - "Sale(s) blocked, contact production": "Linea(s) bloqueada(s), contacte con produccion", - "Please select at least one sale": "Por favor selecciona al menos una linea", - "All sales must belong to the same ticket": "Todas las lineas deben pertenecer al mismo ticket", - "NO_ZONE_FOR_THIS_PARAMETERS": "Para este día no hay ninguna zona configurada", - "This item doesn't exists": "El artículo no existe", - "NOT_ZONE_WITH_THIS_PARAMETERS": "Para este día no hay ninguna zona configurada", - "Extension format is invalid": "El formato de la extensión es inválido", - "Invalid parameters to create a new ticket": "Parámetros inválidos para crear un nuevo ticket", - "This item is not available": "Este artículo no está disponible", - "This postcode already exists": "Este código postal ya existe", - "Concept cannot be blank": "El concepto no puede quedar en blanco", - "File doesn't exists": "El archivo no existe", - "You don't have privileges to change the zone or for these parameters there are more than one shipping options, talk to agencies": "No tienes permisos para cambiar la zona o para esos parámetros hay más de una opción de envío, hable con las agencias", - "This ticket is already on weekly tickets": "Este ticket ya está en tickets programados", - "Ticket id cannot be blank": "El id de ticket no puede quedar en blanco", - "Weekday cannot be blank": "El día de la semana no puede quedar en blanco", - "You can't delete a confirmed order": "No puedes borrar un pedido confirmado", - "Can't create stowaway for this ticket": "No se puede crear un polizon para este ticket", - "The social name has an invalid format": "El nombre fiscal tiene un formato incorrecto", - "Invalid quantity": "Cantidad invalida", - "This postal code is not valid": "This postal code is not valid", - "is invalid": "is invalid", - "The postcode doesn't exist. Please enter a correct one": "El código postal no existe. Por favor, introduce uno correcto", - "The department name can't be repeated": "El nombre del departamento no puede repetirse", - "This phone already exists": "Este teléfono ya existe", - "You cannot move a parent to its own sons": "No puedes mover un elemento padre a uno de sus hijos", - "You can't create a claim for a removed ticket": "No puedes crear una reclamación para un ticket eliminado", - "You cannot delete a ticket that part of it is being prepared": "No puedes eliminar un ticket en el que una parte que está siendo preparada", - "You must delete all the buy requests first": "Debes eliminar todas las peticiones de compra primero", - "You should specify a date": "Debes especificar una fecha", - "You should specify at least a start or end date": "Debes especificar al menos una fecha de inicio o de fín", - "Start date should be lower than end date": "La fecha de inicio debe ser menor que la fecha de fín", - "You should mark at least one week day": "Debes marcar al menos un día de la semana", - "Swift / BIC can't be empty": "Swift / BIC no puede estar vacío", - "Customs agent is required for a non UEE member": "El agente de aduanas es requerido para los clientes extracomunitarios", - "Incoterms is required for a non UEE member": "El incoterms es requerido para los clientes extracomunitarios", - "Deleted sales from ticket": "He eliminado las siguientes lineas del ticket [{{ticketId}}]({{{ticketUrl}}}): {{{deletions}}}", - "Added sale to ticket": "He añadido la siguiente linea al ticket [{{ticketId}}]({{{ticketUrl}}}): {{{addition}}}", - "Changed sale discount": "He cambiado el descuento de las siguientes lineas al ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}", - "Created claim": "He creado la reclamación [{{claimId}}]({{{claimUrl}}}) de las siguientes lineas del ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}", - "Changed sale price": "He cambiado el precio de [{{itemId}} {{concept}}]({{{itemUrl}}}) ({{quantity}}) de {{oldPrice}}€ ➔ *{{newPrice}}€* del ticket [{{ticketId}}]({{{ticketUrl}}})", - "Changed sale quantity": "He cambiado la cantidad de [{{itemId}} {{concept}}]({{{itemUrl}}}) de {{oldQuantity}} ➔ *{{newQuantity}}* del ticket [{{ticketId}}]({{{ticketUrl}}})", - "State": "Estado", - "regular": "normal", - "reserved": "reservado", - "Changed sale reserved state": "He cambiado el estado reservado de las siguientes lineas al ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}", - "Bought units from buy request": "Se ha comprado {{quantity}} unidades de [{{itemId}} {{concept}}]({{{urlItem}}}) para el ticket id [{{ticketId}}]({{{url}}})", - "Deny buy request": "Se ha rechazado la petición de compra para el ticket id [{{ticketId}}]({{{url}}}). Motivo: {{observation}}", - "MESSAGE_INSURANCE_CHANGE": "He cambiado el crédito asegurado del cliente [{{clientName}} ({{clientId}})]({{{url}}}) a *{{credit}} €*", - "Changed client paymethod": "He cambiado la forma de pago del cliente [{{clientName}} ({{clientId}})]({{{url}}})", - "Sent units from ticket": "Envio *{{quantity}}* unidades de [{{concept}} ({{itemId}})]({{{itemUrl}}}) a *\"{{nickname}}\"* provenientes del ticket id [{{ticketId}}]({{{ticketUrl}}})", - "Claim will be picked": "Se recogerá el género de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}*", - "Claim state has changed to incomplete": "Se ha cambiado el estado de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}* a *incompleta*", - "This ticket is not an stowaway anymore": "El ticket id [{{ticketId}}]({{{ticketUrl}}}) ha dejado de ser un polizón", - "Client checked as validated despite of duplication": "Cliente comprobado a pesar de que existe el cliente id {{clientId}}", - "ORDER_ROW_UNAVAILABLE": "No hay disponibilidad de este producto", - "Distance must be lesser than 1000": "La distancia debe ser inferior a 1000", - "This ticket is deleted": "Este ticket está eliminado", - "Unable to clone this travel": "No ha sido posible clonar este travel", - "This thermograph id already exists": "La id del termógrafo ya existe", - "Choose a date range or days forward": "Selecciona un rango de fechas o días en adelante", - "ORDER_ALREADY_CONFIRMED": "ORDER_ALREADY_CONFIRMED", - "Invalid password": "Invalid password", - "Password does not meet requirements": "Password does not meet requirements", - "Role already assigned": "Role already assigned", - "Invalid role name": "Invalid role name", - "Role name must be written in camelCase": "Role name must be written in camelCase", - "Email already exists": "Email already exists", - "User already exists": "User already exists", - "Absence change notification on the labour calendar": "Notificacion de cambio de ausencia en el calendario laboral", - "Created absence": "El empleado {{author}} ha añadido una ausencia de tipo '{{absenceType}}' a {{employee}} para el día {{dated}}.", - "Deleted absence": "El empleado {{author}} ha eliminado una ausencia de tipo '{{absenceType}}' a {{employee}} del día {{dated}}.", - "I have deleted the ticket id": "He eliminado el ticket id [{{id}}]({{{url}}})", - "I have restored the ticket id": "He restaurado el ticket id [{{id}}]({{{url}}})", - "You can only restore a ticket within the first hour after deletion": "Únicamente puedes restaurar el ticket dentro de la primera hora después de su eliminación", - "Changed this data from the ticket": "He cambiado estos datos del ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}", - "agencyModeFk": "Agencia", - "clientFk": "Cliente", - "zoneFk": "Zona", - "warehouseFk": "Almacén", - "shipped": "F. envío", - "landed": "F. entrega", - "addressFk": "Consignatario", - "companyFk": "Empresa", - "The social name cannot be empty": "La razón social no puede quedar en blanco", - "The nif cannot be empty": "El NIF no puede quedar en blanco", - "You need to fill sage information before you check verified data": "Debes rellenar la información de sage antes de marcar datos comprobados", - "ASSIGN_ZONE_FIRST": "Asigna una zona primero", - "Amount cannot be zero": "El importe no puede ser cero", - "Company has to be official": "Empresa inválida", - "You can not select this payment method without a registered bankery account": "No se puede utilizar este método de pago si no has registrado una cuenta bancaria", - "Action not allowed on the test environment": "Esta acción no está permitida en el entorno de pruebas", - "The selected ticket is not suitable for this route": "El ticket seleccionado no es apto para esta ruta", - "Sorts whole route": "Reordena ruta entera", - "New ticket request has been created with price": "Se ha creado una nueva petición de compra '{{description}}' para el día *{{shipped}}*, con una cantidad de *{{quantity}}* y un precio de *{{price}} €*", - "New ticket request has been created": "Se ha creado una nueva petición de compra '{{description}}' para el día *{{shipped}}*, con una cantidad de *{{quantity}}*", - "Swift / BIC cannot be empty": "Swift / BIC no puede estar vacío", - "This BIC already exist.": "Este BIC ya existe.", - "That item doesn't exists": "Ese artículo no existe", - "There's a new urgent ticket:": "Hay un nuevo ticket urgente:", - "Invalid account": "Cuenta inválida", - "Compensation account is empty": "La cuenta para compensar está vacia", - "This genus already exist": "Este genus ya existe", - "This specie already exist": "Esta especie ya existe", - "Client assignment has changed": "He cambiado el comercial ~*\"<{{previousWorkerName}}>\"*~ por *\"<{{currentWorkerName}}>\"* del cliente [{{clientName}} ({{clientId}})]({{{url}}})", - "None": "Ninguno", - "The contract was not active during the selected date": "El contrato no estaba activo durante la fecha seleccionada", - "Cannot add more than one '1/2 day vacation'": "No puedes añadir más de un 'Vacaciones 1/2 dia'", - "This document already exists on this ticket": "Este documento ya existe en el ticket", - "Some of the selected tickets are not billable": "Algunos de los tickets seleccionados no son facturables", - "You can't invoice tickets from multiple clients": "No puedes facturar tickets de multiples clientes", - "nickname": "nickname", - "INACTIVE_PROVIDER": "Proveedor inactivo", - "This client is not invoiceable": "Este cliente no es facturable", - "serial non editable": "Esta serie no permite asignar la referencia", - "Max shipped required": "La fecha límite es requerida", - "Can't invoice to future": "No se puede facturar a futuro", - "Can't invoice to past": "No se puede facturar a pasado", - "This ticket is already invoiced": "Este ticket ya está facturado", - "A ticket with an amount of zero can't be invoiced": "No se puede facturar un ticket con importe cero", - "A ticket with a negative base can't be invoiced": "No se puede facturar un ticket con una base negativa", - "Global invoicing failed": "[Facturación global] No se han podido facturar algunos clientes", - "Wasn't able to invoice the following clients": "No se han podido facturar los siguientes clientes", - "Can't verify data unless the client has a business type": "No se puede verificar datos de un cliente que no tiene tipo de negocio", - "You don't have enough privileges to set this credit amount": "No tienes suficientes privilegios para establecer esta cantidad de crédito", - "You can't change the credit set to zero from a manager": "No puedes cambiar el cŕedito establecido a cero por un gerente", - "The PDF document does not exists": "El documento PDF no existe. Prueba a regenerarlo desde la opción 'Regenerar PDF factura'", - "The type of business must be filled in basic data": "El tipo de negocio debe estar rellenado en datos básicos", - "You can't create a claim from a ticket delivered more than seven days ago": "No puedes crear una reclamación de un ticket entregado hace más de siete días", - "The worker has hours recorded that day": "El trabajador tiene horas fichadas ese día", - "The worker has a marked absence that day": "El trabajador tiene marcada una ausencia ese día", - "You can not modify is pay method checked": "No se puede modificar el campo método de pago validado", - "Can't transfer claimed sales": "No puedes transferir lineas reclamadas", - "isWithoutNegatives": "Tiene Negativos" + "The grade must be an integer greater than or equal to zero": "The grade must be an integer greater than or equal to zero", + "Description should have maximum of 45 characters": "Description should have maximum of 45 characters", + "Amount cannot be zero": "Amount cannot be zero", + "Period cannot be blank": "Period cannot be blank", + "Sample type cannot be blank": "Sample type cannot be blank", + "Cannot be blank": "Cannot be blank", + "The social name cannot be empty": "The social name cannot be empty", + "The nif cannot be empty": "The nif cannot be empty", + "Concept cannot be blank": "Concept cannot be blank", + "Enter an integer different to zero": "Enter an integer different to zero", + "Package cannot be blank": "Package cannot be blank", + "State cannot be blank": "State cannot be blank", + "Worker cannot be blank": "Worker cannot be blank", + "Agency cannot be blank": "Agency cannot be blank" +} \ No newline at end of file diff --git a/modules/ticket/back/methods/ticket/componentUpdate.js b/modules/ticket/back/methods/ticket/componentUpdate.js index 2575bfdbe..59cf1a38a 100644 --- a/modules/ticket/back/methods/ticket/componentUpdate.js +++ b/modules/ticket/back/methods/ticket/componentUpdate.js @@ -133,13 +133,13 @@ module.exports = Self => { } } if (args.isWithoutNegatives) { - const query = `CALL ticket_getVisibleAvailable(?,?)`; + const query = `CALL ticket_getAdvanceable(?,?)`; const params = [args.id, args.shipped]; - const [salesAvailable] = await Self.rawSql(query, params, myOptions); + const [salesAdvanceable] = await Self.rawSql(query, params, myOptions); let salesNewTicket = []; - salesAvailable.forEach(sale => { - if (sale.available >= sale.quantity) + salesAdvanceable.forEach(sale => { + if (sale.advanceable >= sale.quantity) salesNewTicket.push(sale); }); diff --git a/modules/ticket/back/methods/ticket/priceDifference.js b/modules/ticket/back/methods/ticket/priceDifference.js index 9bcea8e7c..f0b112dee 100644 --- a/modules/ticket/back/methods/ticket/priceDifference.js +++ b/modules/ticket/back/methods/ticket/priceDifference.js @@ -110,19 +110,15 @@ module.exports = Self => { totalDifference: 0.00, }; - // Get items available - let query = `CALL ticket_getVisibleAvailable(?,?)`; + // Get items advanceable + let query = `CALL ticket_getAdvanceable(?,?)`; let params = [args.id, args.shipped]; - const [salesAvailable] = await Self.rawSql(query, params, myOptions); + const [salesAdvanceable] = await Self.rawSql(query, params, myOptions); - const itemAvailable = new Map(); - for (sale of salesAvailable) { - let available = sale.available; - if (available == null) - available = 0; - - itemAvailable.set(sale.id, available); - } + const itemAdvanceable = new Map(); + console.log(salesAdvanceable); + for (sale of salesAdvanceable) + itemAdvanceable.set(sale.id, sale.advanceable); // Sale price component, one per sale query = `CALL vn.ticket_priceDifference(?, ?, ?, ?, ?)`; @@ -147,7 +143,7 @@ module.exports = Self => { salesObj.totalUnitPrice += sale.price; salesObj.totalUnitPrice = round(salesObj.totalUnitPrice); - sale.available = itemAvailable.get(sale.id); + sale.advanceable = itemAdvanceable.get(sale.id); } if (tx) await tx.commit(); diff --git a/modules/ticket/front/basic-data/step-two/index.html b/modules/ticket/front/basic-data/step-two/index.html index 74b160fda..298725189 100644 --- a/modules/ticket/front/basic-data/step-two/index.html +++ b/modules/ticket/front/basic-data/step-two/index.html @@ -9,7 +9,7 @@ Item Description - Available + Advanceable Quantity Price (PPU) New (PPU) @@ -35,8 +35,8 @@ - {{::sale.available}} + ng-class="{'alert': sale.quantity>sale.advanceable}"> + {{::sale.advanceable}} {{::sale.quantity}} diff --git a/modules/ticket/front/basic-data/step-two/index.js b/modules/ticket/front/basic-data/step-two/index.js index d77090781..db0bb6d44 100644 --- a/modules/ticket/front/basic-data/step-two/index.js +++ b/modules/ticket/front/basic-data/step-two/index.js @@ -69,7 +69,7 @@ class Controller extends Component { let haveNotNegatives = false; this.ticket.sale.items.forEach(item => { - if (item.quantity > item.available) + if (item.quantity > item.advanceable) haveNegatives = true; else haveNotNegatives = true; diff --git a/modules/ticket/front/basic-data/step-two/locale/es.yml b/modules/ticket/front/basic-data/step-two/locale/es.yml index 08bef3b09..ccf1f5572 100644 --- a/modules/ticket/front/basic-data/step-two/locale/es.yml +++ b/modules/ticket/front/basic-data/step-two/locale/es.yml @@ -7,4 +7,5 @@ Price: Precio New price: Nuevo precio Price difference: Diferencia de precio Without create negatives: Sin crear negativos -Clone this ticket with the changes and only sales availables: Clona este ticket con los cambios y solo las ventas disponibles. \ No newline at end of file +Clone this ticket with the changes and only sales availables: Clona este ticket con los cambios y solo las ventas disponibles. +Advanceable: Avanzable \ No newline at end of file From 5824acf3bca08bd586e7639511d57d281a758816 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 17 Jan 2022 10:12:13 +0100 Subject: [PATCH 11/24] change tests to advanceable --- loopback/locale/en.json | 3 ++- loopback/locale/es.json | 7 ++++++- modules/ticket/back/methods/ticket/priceDifference.js | 1 - .../back/methods/ticket/specs/priceDifference.spec.js | 4 ++-- modules/ticket/front/basic-data/step-two/index.spec.js | 4 ++-- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/loopback/locale/en.json b/loopback/locale/en.json index 7f3e18d72..d0f818426 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -120,5 +120,6 @@ "This item is not available": "This item is not available", "Deny buy request": "Purchase request for ticket id [{{ticketId}}]({{{url}}}) has been rejected. Reason: {{observation}}", "The type of business must be filled in basic data": "The type of business must be filled in basic data", - "isWithoutNegatives": "isWithoutNegatives" + "isWithoutNegatives": "isWithoutNegatives", + "The worker has hours recorded that day": "The worker has hours recorded that day" } \ No newline at end of file diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 3d5c205bd..18552a96c 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -19,5 +19,10 @@ "Package cannot be blank": "Package cannot be blank", "State cannot be blank": "State cannot be blank", "Worker cannot be blank": "Worker cannot be blank", - "Agency cannot be blank": "Agency cannot be blank" + "Agency cannot be blank": "Agency cannot be blank", + "nickname": "nickname", + "shipped": "shipped", + "landed": "landed", + "isWithoutNegatives": "isWithoutNegatives", + "Changed this data from the ticket": "Changed this data from the ticket" } \ No newline at end of file diff --git a/modules/ticket/back/methods/ticket/priceDifference.js b/modules/ticket/back/methods/ticket/priceDifference.js index f0b112dee..807c17f00 100644 --- a/modules/ticket/back/methods/ticket/priceDifference.js +++ b/modules/ticket/back/methods/ticket/priceDifference.js @@ -116,7 +116,6 @@ module.exports = Self => { const [salesAdvanceable] = await Self.rawSql(query, params, myOptions); const itemAdvanceable = new Map(); - console.log(salesAdvanceable); for (sale of salesAdvanceable) itemAdvanceable.set(sale.id, sale.advanceable); diff --git a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js index 8fe906bcf..bc37e33cb 100644 --- a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js +++ b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js @@ -83,8 +83,8 @@ describe('sale priceDifference()', () => { const firstItem = result.items[0]; const secondtItem = result.items[1]; - expect(firstItem.available).toEqual(410); - expect(secondtItem.available).toEqual(1870); + expect(firstItem.advanceable).toEqual(440); + expect(secondtItem.advanceable).toEqual(1980); await tx.rollback(); } catch (e) { diff --git a/modules/ticket/front/basic-data/step-two/index.spec.js b/modules/ticket/front/basic-data/step-two/index.spec.js index fcd1d7e49..0567785e9 100644 --- a/modules/ticket/front/basic-data/step-two/index.spec.js +++ b/modules/ticket/front/basic-data/step-two/index.spec.js @@ -73,12 +73,12 @@ describe('Ticket', () => { { item: 1, quantity: 2, - available: 1 + advanceable: 1 }, { item: 2, quantity: 1, - available: 5 + advanceable: 5 } ] } From 8e1c3e107c229d26b53cfbcc1d175a55b568ac22 Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 18 Jan 2022 12:48:39 +0100 Subject: [PATCH 12/24] refactor(ticket): advanceable code --- db/changes/10410-january/00-ticket_getAdvancable.sql | 5 ++--- .../ticket/back/methods/ticket/componentUpdate.js | 12 ++++-------- .../ticket/back/methods/ticket/priceDifference.js | 6 +++--- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/db/changes/10410-january/00-ticket_getAdvancable.sql b/db/changes/10410-january/00-ticket_getAdvancable.sql index 599e431b3..b8d9337e3 100644 --- a/db/changes/10410-january/00-ticket_getAdvancable.sql +++ b/db/changes/10410-january/00-ticket_getAdvancable.sql @@ -2,7 +2,7 @@ DROP PROCEDURE IF EXISTS `vn`.`ticket_getAdvanceable`; DELIMITER $$ $$ -CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticket_getAdvanceable`(vTicketFk INT, vDatedNew DATETIME) +CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticket_getAdvanceable`(vTicketFk INT, vDatedNew DATETIME, vWarehouseFk INT) BEGIN /** * Cálcula el stock avanzable para los artículos de un ticket @@ -11,10 +11,9 @@ BEGIN * @param vDatedNew -> Nueva fecha * @return Sales con Avanzable */ - DECLARE vWarehouseFk INT; DECLARE vDatedOld DATETIME; - SELECT t.warehouseFk, t.shipped INTO vWarehouseFk, vDatedOld + SELECT t.shipped INTO vDatedOld FROM ticket t WHERE t.id = vTicketFk; diff --git a/modules/ticket/back/methods/ticket/componentUpdate.js b/modules/ticket/back/methods/ticket/componentUpdate.js index 59cf1a38a..64b02e2f2 100644 --- a/modules/ticket/back/methods/ticket/componentUpdate.js +++ b/modules/ticket/back/methods/ticket/componentUpdate.js @@ -132,17 +132,13 @@ module.exports = Self => { throw new UserError(error); } } + if (args.isWithoutNegatives) { - const query = `CALL ticket_getAdvanceable(?,?)`; - const params = [args.id, args.shipped]; + const query = `CALL ticket_getAdvanceable(?,?,?)`; + const params = [args.id, args.shipped, args.warehouseFk]; const [salesAdvanceable] = await Self.rawSql(query, params, myOptions); - let salesNewTicket = []; - salesAdvanceable.forEach(sale => { - if (sale.advanceable >= sale.quantity) - salesNewTicket.push(sale); - }); - + const salesNewTicket = salesAdvanceable.filter(sale => (sale.advanceable ?? 0) >= sale.quantity); if (salesNewTicket.length) { const newTicket = await models.Ticket.transferSales(ctx, args.id, null, salesNewTicket, myOptions); args.id = newTicket.id; diff --git a/modules/ticket/back/methods/ticket/priceDifference.js b/modules/ticket/back/methods/ticket/priceDifference.js index 807c17f00..e6688da96 100644 --- a/modules/ticket/back/methods/ticket/priceDifference.js +++ b/modules/ticket/back/methods/ticket/priceDifference.js @@ -111,13 +111,13 @@ module.exports = Self => { }; // Get items advanceable - let query = `CALL ticket_getAdvanceable(?,?)`; - let params = [args.id, args.shipped]; + let query = `CALL ticket_getAdvanceable(?,?,?)`; + let params = [args.id, args.shipped, args.warehouseId]; const [salesAdvanceable] = await Self.rawSql(query, params, myOptions); const itemAdvanceable = new Map(); for (sale of salesAdvanceable) - itemAdvanceable.set(sale.id, sale.advanceable); + itemAdvanceable.set(sale.id, sale.advanceable ?? 0); // Sale price component, one per sale query = `CALL vn.ticket_priceDifference(?, ?, ?, ?, ?)`; From 9ddf11c6bc1305ad3289431a56f9c9f66556d72a Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 18 Jan 2022 12:49:16 +0100 Subject: [PATCH 13/24] test(ticket): update to advanceable --- .../05-ticket/06_basic_data_steps.spec.js | 8 +-- .../ticket/specs/componentUpdate.spec.js | 56 +++++++++++++++++++ .../ticket/specs/priceDifference.spec.js | 2 +- 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/e2e/paths/05-ticket/06_basic_data_steps.spec.js b/e2e/paths/05-ticket/06_basic_data_steps.spec.js index 6ae702979..93c6bba65 100644 --- a/e2e/paths/05-ticket/06_basic_data_steps.spec.js +++ b/e2e/paths/05-ticket/06_basic_data_steps.spec.js @@ -8,7 +8,7 @@ describe('Ticket Edit basic data path', () => { beforeAll(async() => { browser = await getBrowser(); page = browser.page; - await page.loginAndModule('employee', 'ticket'); + await page.loginAndModule('employee', 'ticket'); await page.accessToSearchResult('11'); await page.accessToSection('ticket.card.basicData.stepOne'); }); @@ -85,7 +85,7 @@ describe('Ticket Edit basic data path', () => { }); it(`should not find ticket`, async() => { - await page.doSearch('28'); + await page.doSearch('29'); const count = await page.countElement(selectors.ticketsIndex.searchResult); expect(count).toEqual(0); @@ -128,8 +128,8 @@ describe('Ticket Edit basic data path', () => { const expectedMonth = tomorrow.getMonth() + 1; const expectedYear = tomorrow.getFullYear(); - await page.loginAndModule('employee', 'ticket'); - await page.accessToSearchResult('28'); + await page.loginAndModule('employee', 'ticket'); + await page.accessToSearchResult('29'); await page.accessToSection('ticket.card.sale'); const item = await page.waitToGetProperty(selectors.ticketSales.firstSaleId, 'innerText'); diff --git a/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js b/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js index 38e6ce6a7..2aa2a07c4 100644 --- a/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js +++ b/modules/ticket/back/methods/ticket/specs/componentUpdate.spec.js @@ -136,4 +136,60 @@ describe('ticket componentUpdate()', () => { throw e; } }); + + it('should change warehouse and without negatives', async() => { + const tx = await models.SaleComponent.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const saleToTransfer = 27; + const originDate = today; + const newDate = tomorrow; + const ticketID = 14; + newDate.setHours(0, 0, 0, 0, 0); + originDate.setHours(0, 0, 0, 0, 0); + + const args = { + id: ticketID, + clientFk: 1104, + agencyModeFk: 2, + addressFk: 4, + zoneFk: 9, + warehouseFk: 1, + companyFk: 442, + shipped: newDate, + landed: tomorrow, + isDeleted: false, + option: 1, + isWithoutNegatives: true + }; + + const ctx = { + args: args, + req: { + accessToken: {userId: 9}, + headers: {origin: 'http://localhost'}, + __: value => { + return value; + } + } + }; + await models.Ticket.componentUpdate(ctx, options); + + const [newTicketID] = await models.Ticket.rawSql('SELECT MAX(id) as id FROM ticket', null, options); + const oldTicket = await models.Ticket.findById(ticketID, null, options); + const newTicket = await models.Ticket.findById(newTicketID.id, null, options); + const newTicketSale = await models.Sale.findOne({where: {ticketFk: args.id}}, options); + + expect(oldTicket.shipped).toEqual(originDate); + expect(newTicket.shipped).toEqual(newDate); + expect(newTicketSale.id).toEqual(saleToTransfer); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); }); diff --git a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js index bc37e33cb..362c3e923 100644 --- a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js +++ b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js @@ -60,7 +60,7 @@ describe('sale priceDifference()', () => { expect(error).toEqual(new UserError(`The sales of this ticket can't be modified`)); }); - it('should return ticket available', async() => { + it('should return ticket advanceable', async() => { const tx = await models.Ticket.beginTransaction({}); try { From 2455a24b68b916b2a8d841ef60a5e5d68c4fb3c6 Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 25 Jan 2022 14:27:30 +0100 Subject: [PATCH 14/24] feat(client_defaulter): section and test --- db/dump/fixtures.sql | 10 +- e2e/helpers/selectors.js | 10 ++ e2e/paths/02-client/21_defaulter.spec.js | 73 ++++++++ .../client/back/methods/defaulter/filter.js | 87 +++++++++ .../methods/defaulter/specs/filter.spec.js | 63 +++++++ modules/client/back/models/defaulter.js | 3 + modules/client/back/models/defaulter.json | 3 + modules/client/front/defaulter/index.html | 169 ++++++++++++++++++ modules/client/front/defaulter/index.js | 62 +++++++ modules/client/front/defaulter/index.spec.js | 88 +++++++++ modules/client/front/defaulter/locale/es.yml | 5 + modules/client/front/index.js | 1 + modules/client/front/locale/es.yml | 1 + modules/client/front/routes.json | 15 +- 14 files changed, 588 insertions(+), 2 deletions(-) create mode 100644 e2e/paths/02-client/21_defaulter.spec.js create mode 100644 modules/client/back/methods/defaulter/filter.js create mode 100644 modules/client/back/methods/defaulter/specs/filter.spec.js create mode 100644 modules/client/back/models/defaulter.js create mode 100644 modules/client/front/defaulter/index.html create mode 100644 modules/client/front/defaulter/index.js create mode 100644 modules/client/front/defaulter/index.spec.js create mode 100644 modules/client/front/defaulter/locale/es.yml diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index efe7906ce..83ba89937 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -2432,4 +2432,12 @@ INSERT INTO `vn`.`expeditionScan` (`id`, `expeditionFk`, `scanned`, `palletFk`) CALL `cache`.`last_buy_refresh`(FALSE); UPDATE `vn`.`item` SET `genericFk` = 9 - WHERE `id` = 2; \ No newline at end of file + WHERE `id` = 2; + +INSERT INTO `bs`.`defaulter` (`clientFk`, `amount`, `created`, `defaulterSinced`) + VALUES + (1101, 500, CURDATE(), CURDATE()), + (1102, 500, CURDATE(), CURDATE()), + (1103, 500, CURDATE(), CURDATE()), + (1107, 500, CURDATE(), CURDATE()), + (1109, 500, CURDATE(), CURDATE()); diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index 2900a285b..0172ca4e0 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -304,6 +304,16 @@ export default { saveNewInsuranceCredit: 'vn-client-credit-insurance-insurance-create button[type="submit"]', anyCreditInsuranceLine: 'vn-client-credit-insurance-insurance-index vn-tbody > vn-tr', }, + clientDefaulter: { + anyClient: 'vn-client-defaulter-index vn-tbody > vn-tr', + firstClientName: 'vn-client-defaulter-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(2) > span', + firstSalesPersonName: 'vn-client-defaulter-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(3) > span', + firstObservation: 'vn-client-defaulter-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(5) > vn-textarea[ng-model="defaulter.observation"]', + allDefaulterCheckbox: 'vn-client-defaulter-index vn-thead vn-multi-check', + addObservationButton: 'vn-client-defaulter-index vn-button[icon="icon-notes"]', + observation: '.vn-dialog.shown vn-textarea[ng-model="$ctrl.defaulter.observation"]', + saveButton: 'button[response="accept"]' + }, clientContacts: { addContactButton: 'vn-client-contact vn-icon[icon="add_circle"]', name: 'vn-client-contact vn-textfield[ng-model="contact.name"]', diff --git a/e2e/paths/02-client/21_defaulter.spec.js b/e2e/paths/02-client/21_defaulter.spec.js new file mode 100644 index 000000000..406c802ab --- /dev/null +++ b/e2e/paths/02-client/21_defaulter.spec.js @@ -0,0 +1,73 @@ +import selectors from '../../helpers/selectors.js'; +import getBrowser from '../../helpers/puppeteer'; + +describe('Client defaulter path', () => { + let browser; + let page; + + beforeAll(async() => { + browser = await getBrowser(); + page = browser.page; + await page.loginAndModule('insurance', 'client'); + await page.accessToSection('client.defaulter.index'); + }); + + afterAll(async() => { + await browser.close(); + }); + + it('should count the amount of clients in the turns section', async() => { + const result = await page.countElement(selectors.clientDefaulter.anyClient); + + expect(result).toEqual(5); + }); + + it('should check contain expected client', async() => { + const clientName = + await page.waitToGetProperty(selectors.clientDefaulter.firstClientName, 'innerText'); + const salesPersonName = + await page.waitToGetProperty(selectors.clientDefaulter.firstSalesPersonName, 'innerText'); + + expect(clientName).toEqual('Ororo Munroe'); + expect(salesPersonName).toEqual('salesPerson'); + }); + + it('should first observation not changed', async() => { + const expectedObservation = 'Madness, as you know, is like gravity, all it takes is a little push'; + const result = await page.waitToGetProperty(selectors.clientDefaulter.firstObservation, 'value'); + + expect(result).toEqual(expectedObservation); + }); + + it('should not add empty observation', async() => { + await page.waitToClick(selectors.clientDefaulter.allDefaulterCheckbox); + + await page.waitToClick(selectors.clientDefaulter.addObservationButton); + await page.write(selectors.clientDefaulter.observation, ''); + await page.waitToClick(selectors.clientDefaulter.saveButton); + const message = await page.waitForSnackbar(); + + expect(message.text).toContain(`The message can't be empty`); + }); + + it('shoul checked all defaulters', async() => { + await page.loginAndModule('insurance', 'client'); + await page.accessToSection('client.defaulter.index'); + + await page.waitToClick(selectors.clientDefaulter.allDefaulterCheckbox); + }); + + it('should add observation for all clients', async() => { + await page.waitToClick(selectors.clientDefaulter.addObservationButton); + await page.write(selectors.clientDefaulter.observation, 'My new observation'); + await page.waitToClick(selectors.clientDefaulter.saveButton); + }); + + it('should first observation changed', async() => { + const result = await page.waitToGetProperty(selectors.clientDefaulter.firstObservation, 'value'); + const message = await page.waitForSnackbar(); + + expect(message.text).toContain('Observation saved!'); + expect(result).toEqual('My new observation'); + }); +}); diff --git a/modules/client/back/methods/defaulter/filter.js b/modules/client/back/methods/defaulter/filter.js new file mode 100644 index 000000000..95e75040e --- /dev/null +++ b/modules/client/back/methods/defaulter/filter.js @@ -0,0 +1,87 @@ + +const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; +const buildFilter = require('vn-loopback/util/filter').buildFilter; +const mergeFilters = require('vn-loopback/util/filter').mergeFilters; + +module.exports = Self => { + Self.remoteMethodCtx('filter', { + description: 'Find all instances of the model matched by filter from the data source.', + accessType: 'READ', + accepts: [ + { + arg: 'filter', + type: 'object', + description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string', + http: {source: 'query'} + }, + { + arg: 'search', + type: 'string', + description: `If it's and integer searchs by id, otherwise it searchs by name` + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: `/filter`, + verb: 'GET' + } + }); + + Self.filter = async(ctx, filter, options) => { + const conn = Self.dataSource.connector; + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + const where = buildFilter(ctx.args, (param, value) => { + switch (param) { + case 'search': + return {or: [ + {'d.clientFk': value}, + {'d.clientName': {like: `%${value}%`}} + ]}; + } + }); + + filter = mergeFilters(ctx.args.filter, {where}); + + const stmts = []; + + const stmt = new ParameterizedSQL( + `SELECT * + FROM ( + SELECT + DISTINCT c.id clientFk, + c.name clientName, + c.salesPersonFk, + u.name salesPersonName, + d.amount, + co.created, + co.text observation, + c.creditInsurance, + d.defaulterSinced + FROM vn.defaulter d + JOIN vn.client c ON c.id = d.clientFk + LEFT JOIN vn.clientObservation co ON co.clientFk = c.id + LEFT JOIN account.user u ON u.id = c.salesPersonFk + WHERE + d.created = CURDATE() + AND d.amount > 0 + ORDER BY co.created DESC) d` + ); + + stmt.merge(conn.makeWhere(filter.where)); + stmt.merge(`GROUP BY d.clientFk`); + stmt.merge(conn.makeOrderBy(filter.order)); + + const itemsIndex = stmts.push(stmt) - 1; + const sql = ParameterizedSQL.join(stmts, ';'); + const result = await conn.executeStmt(sql, myOptions); + + return itemsIndex === 0 ? result : result[itemsIndex]; + }; +}; diff --git a/modules/client/back/methods/defaulter/specs/filter.spec.js b/modules/client/back/methods/defaulter/specs/filter.spec.js new file mode 100644 index 000000000..145bb5132 --- /dev/null +++ b/modules/client/back/methods/defaulter/specs/filter.spec.js @@ -0,0 +1,63 @@ +const models = require('vn-loopback/server/server').models; + +describe('defaulter filter()', () => { + const authUserId = 9; + it('should all return the tickets matching the filter', async() => { + const tx = await models.Defaulter.beginTransaction({}); + + try { + const options = {transaction: tx}; + const filter = {}; + const ctx = {req: {accessToken: {userId: authUserId}}, args: {filter: filter}}; + + const result = await models.Defaulter.filter(ctx, null, options); + const firstRow = result[0]; + + expect(firstRow.clientFk).toEqual(1101); + expect(result.length).toEqual(5); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should return the defaulter with id', async() => { + const tx = await models.Defaulter.beginTransaction({}); + + try { + const options = {transaction: tx}; + const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 1101}}; + + const result = await models.Defaulter.filter(ctx, null, options); + const firstRow = result[0]; + + expect(firstRow.clientFk).toEqual(1101); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should return the defaulter matching the client name', async() => { + const tx = await models.Defaulter.beginTransaction({}); + + try { + const options = {transaction: tx}; + const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 'bruce'}}; + + const result = await models.Defaulter.filter(ctx, null, options); + const firstRow = result[0]; + + expect(firstRow.clientName).toEqual('Bruce Wayne'); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); +}); diff --git a/modules/client/back/models/defaulter.js b/modules/client/back/models/defaulter.js new file mode 100644 index 000000000..13bb1a614 --- /dev/null +++ b/modules/client/back/models/defaulter.js @@ -0,0 +1,3 @@ +module.exports = Self => { + require('../methods/defaulter/filter')(Self); +}; diff --git a/modules/client/back/models/defaulter.json b/modules/client/back/models/defaulter.json index 8d50356f1..829326435 100644 --- a/modules/client/back/models/defaulter.json +++ b/modules/client/back/models/defaulter.json @@ -8,6 +8,9 @@ } }, "properties": { + "id": { + "type": "Number" + }, "created": { "type": "Date" }, diff --git a/modules/client/front/defaulter/index.html b/modules/client/front/defaulter/index.html new file mode 100644 index 000000000..6ab52dd4f --- /dev/null +++ b/modules/client/front/defaulter/index.html @@ -0,0 +1,169 @@ + + + + + + + +
+
+
Balance due
+ + +
+
+
+ + + + + + + + + + + + + + + + Client + Comercial + Credit + Last observation + Credit insurance + From + + + + + + + + + + + {{::defaulter.clientName}} + + + + + {{::defaulter.salesPersonName | dashIfEmpty}} + + + {{::defaulter.amount}} + + + + + {{::defaulter.creditInsurance}} + {{::defaulter.defaulterSinced | date: 'dd/MM/yyyy'}} + + + + + + + + + + + + + + + + + + + Filter by selection + + + Exclude selection + + + Remove filter + + + Remove all filters + + + Copy value + + + + + + + +
+
{{$ctrl.$t('Add observation to all selected clients', {total: $ctrl.checked.length})}}
+ + + + +
+
+ + + + +
diff --git a/modules/client/front/defaulter/index.js b/modules/client/front/defaulter/index.js new file mode 100644 index 000000000..0cb029992 --- /dev/null +++ b/modules/client/front/defaulter/index.js @@ -0,0 +1,62 @@ +import ngModule from '../module'; +import Section from 'salix/components/section'; +import UserError from 'core/lib/user-error'; + +export default class Controller extends Section { + constructor($element, $) { + super($element, $); + this.defaulter = {}; + } + + get balanceDueTotal() { + let balanceDueTotal = 0; + + if (this.checked.length > 0) { + for (let defaulter of this.checked) + balanceDueTotal += defaulter.amount; + + return balanceDueTotal; + } + + return balanceDueTotal; + } + + get checked() { + const clients = this.$.model.data || []; + const checkedLines = []; + for (let defaulter of clients) { + if (defaulter.checked) + checkedLines.push(defaulter); + } + + return checkedLines; + } + + onResponse() { + if (!this.defaulter.observation) + throw new UserError(`The message can't be empty`); + + for (let defaulter of this.checked) { + const params = { + text: this.defaulter.observation, + clientFk: defaulter.clientFk + }; + this.$http.post(`ClientObservations`, params); + } + this.vnApp.showMessage(this.$t('Observation saved!')); + this.$state.reload(); + } + + exprBuilder(param, value) { + switch (param) { + case 'clientName': + case 'salesPersonFk': + return {[`d.${param}`]: value}; + } + } +} + +ngModule.vnComponent('vnClientDefaulterIndex', { + template: require('./index.html'), + controller: Controller +}); diff --git a/modules/client/front/defaulter/index.spec.js b/modules/client/front/defaulter/index.spec.js new file mode 100644 index 000000000..e0e758906 --- /dev/null +++ b/modules/client/front/defaulter/index.spec.js @@ -0,0 +1,88 @@ +import './index'; +import crudModel from 'core/mocks/crud-model'; + +describe('client defaulter', () => { + describe('Component vnClientDefaulterIndex', () => { + let controller; + + beforeEach(ngModule('client')); + + beforeEach(inject($componentController => { + const $element = angular.element(''); + controller = $componentController('vnClientDefaulterIndex', {$element}); + controller.$.model = crudModel; + controller.$.model.data = [ + {clientFk: 1101, amount: 125}, + {clientFk: 1102, amount: 500}, + {clientFk: 1103, amount: 250} + ]; + })); + + describe('checked() getter', () => { + it('should return the checked lines', () => { + const data = controller.$.model.data; + data[1].checked = true; + data[2].checked = true; + + const checkedRows = controller.checked; + + const firstCheckedRow = checkedRows[0]; + const secondCheckedRow = checkedRows[1]; + + expect(firstCheckedRow.clientFk).toEqual(1102); + expect(secondCheckedRow.clientFk).toEqual(1103); + }); + }); + + describe('balanceDueTotal() getter', () => { + it('should return balance due total', () => { + const data = controller.$.model.data; + data[1].checked = true; + data[2].checked = true; + + const checkedRows = controller.checked; + const expectedAmount = checkedRows[0].amount + checkedRows[1].amount; + + const result = controller.balanceDueTotal; + + expect(result).toEqual(expectedAmount); + }); + }); + + describe('onResponse()', () => { + it('should return error for empty message', () => { + let error; + try { + controller.onResponse(); + } catch (e) { + error = e; + } + + expect(error).toBeDefined(); + expect(error.message).toBe(`The message can't be empty`); + }); + + it('should return saved message', () => { + controller.defaulter = {observation: 'asdasd'}; + jest.spyOn(controller.vnApp, 'showMessage'); + controller.onResponse(); + + expect(controller.vnApp.showMessage).toHaveBeenCalledWith('Observation saved!'); + }); + }); + + describe('exprBuilder()', () => { + it('should search by sales person', () => { + let expr = controller.exprBuilder('salesPersonFk', '5'); + + expect(expr).toEqual({'d.salesPersonFk': '5'}); + }); + + it('should search by client name', () => { + let expr = controller.exprBuilder('clientName', '1foo'); + + expect(expr).toEqual({'d.clientName': '1foo'}); + }); + }); + }); +}); diff --git a/modules/client/front/defaulter/locale/es.yml b/modules/client/front/defaulter/locale/es.yml new file mode 100644 index 000000000..95184d06d --- /dev/null +++ b/modules/client/front/defaulter/locale/es.yml @@ -0,0 +1,5 @@ +Last observation: Última observación +Add observation: Añadir observación +Balance due total: Saldo vencido total +Search client: Buscar clientes +Add observation to all selected clients: Añadir observación a {{total}} cliente(s) seleccionado(s) \ No newline at end of file diff --git a/modules/client/front/index.js b/modules/client/front/index.js index 758b94e3f..6b35d392a 100644 --- a/modules/client/front/index.js +++ b/modules/client/front/index.js @@ -44,3 +44,4 @@ import './dms/create'; import './dms/edit'; import './consumption'; import './consumption-search-panel'; +import './defaulter'; diff --git a/modules/client/front/locale/es.yml b/modules/client/front/locale/es.yml index 1a5a570a7..107931377 100644 --- a/modules/client/front/locale/es.yml +++ b/modules/client/front/locale/es.yml @@ -33,6 +33,7 @@ Search client by id or name: Buscar clientes por identificador o nombre # Sections Clients: Clientes +Defaulter: Morosos New client: Nuevo cliente Fiscal data: Datos fiscales Billing data: Forma de pago diff --git a/modules/client/front/routes.json b/modules/client/front/routes.json index 765fbc637..31a699e55 100644 --- a/modules/client/front/routes.json +++ b/modules/client/front/routes.json @@ -6,7 +6,8 @@ "dependencies": ["worker", "invoiceOut"], "menus": { "main": [ - {"state": "client.index", "icon": "person"} + {"state": "client.index", "icon": "person"}, + {"state": "client.defaulter.index", "icon": "person"} ], "card": [ {"state": "client.card.basicData", "icon": "settings"}, @@ -360,6 +361,18 @@ "params": { "client": "$ctrl.client" } + }, + { + "url": "/defaulter", + "state": "client.defaulter", + "component": "ui-view", + "description": "Defaulter" + }, + { + "url": "/index?q", + "state": "client.defaulter.index", + "component": "vn-client-defaulter-index", + "description": "Defaulter" } ] } From f8a00943216a0b37f58829f95415a2fa4a3db396 Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 26 Jan 2022 08:54:48 +0100 Subject: [PATCH 15/24] word movible --- .../10410-january/00-ticket_getAdvancable.sql | 10 +++++----- .../ticket/back/methods/ticket/componentUpdate.js | 6 +++--- .../ticket/back/methods/ticket/priceDifference.js | 14 +++++++------- .../methods/ticket/specs/priceDifference.spec.js | 6 +++--- .../ticket/front/basic-data/step-two/index.html | 6 +++--- modules/ticket/front/basic-data/step-two/index.js | 2 +- .../ticket/front/basic-data/step-two/index.spec.js | 4 ++-- .../ticket/front/basic-data/step-two/locale/es.yml | 2 +- 8 files changed, 25 insertions(+), 25 deletions(-) diff --git a/db/changes/10410-january/00-ticket_getAdvancable.sql b/db/changes/10410-january/00-ticket_getAdvancable.sql index b8d9337e3..5f5b0a93a 100644 --- a/db/changes/10410-january/00-ticket_getAdvancable.sql +++ b/db/changes/10410-january/00-ticket_getAdvancable.sql @@ -1,15 +1,15 @@ -DROP PROCEDURE IF EXISTS `vn`.`ticket_getAdvanceable`; +DROP PROCEDURE IF EXISTS `vn`.`ticket_getMovable`; DELIMITER $$ $$ -CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticket_getAdvanceable`(vTicketFk INT, vDatedNew DATETIME, vWarehouseFk INT) +CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticket_getMovable`(vTicketFk INT, vDatedNew DATETIME, vWarehouseFk INT) BEGIN /** - * Cálcula el stock avanzable para los artículos de un ticket + * Cálcula el stock movible para los artículos de un ticket * * @param vTicketFk -> Ticket * @param vDatedNew -> Nueva fecha - * @return Sales con Avanzable + * @return Sales con Movible */ DECLARE vDatedOld DATETIME; @@ -29,7 +29,7 @@ BEGIN s.discount, i.image, i.subName, - il.stock + IFNULL(im.amount, 0) AS advanceable + il.stock + IFNULL(im.amount, 0) AS movable FROM ticket t JOIN sale s ON s.ticketFk = t.id JOIN item i ON i.id = s.itemFk diff --git a/modules/ticket/back/methods/ticket/componentUpdate.js b/modules/ticket/back/methods/ticket/componentUpdate.js index 64b02e2f2..e01798887 100644 --- a/modules/ticket/back/methods/ticket/componentUpdate.js +++ b/modules/ticket/back/methods/ticket/componentUpdate.js @@ -134,11 +134,11 @@ module.exports = Self => { } if (args.isWithoutNegatives) { - const query = `CALL ticket_getAdvanceable(?,?,?)`; + const query = `CALL ticket_getMovable(?,?,?)`; const params = [args.id, args.shipped, args.warehouseFk]; - const [salesAdvanceable] = await Self.rawSql(query, params, myOptions); + const [salesMovable] = await Self.rawSql(query, params, myOptions); - const salesNewTicket = salesAdvanceable.filter(sale => (sale.advanceable ?? 0) >= sale.quantity); + const salesNewTicket = salesMovable.filter(sale => (sale.movable ?? 0) >= sale.quantity); if (salesNewTicket.length) { const newTicket = await models.Ticket.transferSales(ctx, args.id, null, salesNewTicket, myOptions); args.id = newTicket.id; diff --git a/modules/ticket/back/methods/ticket/priceDifference.js b/modules/ticket/back/methods/ticket/priceDifference.js index e6688da96..ffcdc19ef 100644 --- a/modules/ticket/back/methods/ticket/priceDifference.js +++ b/modules/ticket/back/methods/ticket/priceDifference.js @@ -110,14 +110,14 @@ module.exports = Self => { totalDifference: 0.00, }; - // Get items advanceable - let query = `CALL ticket_getAdvanceable(?,?,?)`; + // Get items movable + let query = `CALL ticket_getMovable(?,?,?)`; let params = [args.id, args.shipped, args.warehouseId]; - const [salesAdvanceable] = await Self.rawSql(query, params, myOptions); + const [salesMovable] = await Self.rawSql(query, params, myOptions); - const itemAdvanceable = new Map(); - for (sale of salesAdvanceable) - itemAdvanceable.set(sale.id, sale.advanceable ?? 0); + const itemMovable = new Map(); + for (sale of salesMovable) + itemMovable.set(sale.id, sale.movable ?? 0); // Sale price component, one per sale query = `CALL vn.ticket_priceDifference(?, ?, ?, ?, ?)`; @@ -142,7 +142,7 @@ module.exports = Self => { salesObj.totalUnitPrice += sale.price; salesObj.totalUnitPrice = round(salesObj.totalUnitPrice); - sale.advanceable = itemAdvanceable.get(sale.id); + sale.movable = itemMovable.get(sale.id); } if (tx) await tx.commit(); diff --git a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js index 362c3e923..6659ed26e 100644 --- a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js +++ b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js @@ -60,7 +60,7 @@ describe('sale priceDifference()', () => { expect(error).toEqual(new UserError(`The sales of this ticket can't be modified`)); }); - it('should return ticket advanceable', async() => { + it('should return ticket movable', async() => { const tx = await models.Ticket.beginTransaction({}); try { @@ -83,8 +83,8 @@ describe('sale priceDifference()', () => { const firstItem = result.items[0]; const secondtItem = result.items[1]; - expect(firstItem.advanceable).toEqual(440); - expect(secondtItem.advanceable).toEqual(1980); + expect(firstItem.movable).toEqual(440); + expect(secondtItem.movable).toEqual(1980); await tx.rollback(); } catch (e) { diff --git a/modules/ticket/front/basic-data/step-two/index.html b/modules/ticket/front/basic-data/step-two/index.html index 298725189..88475daa2 100644 --- a/modules/ticket/front/basic-data/step-two/index.html +++ b/modules/ticket/front/basic-data/step-two/index.html @@ -9,7 +9,7 @@ Item Description - Advanceable + Movable Quantity Price (PPU) New (PPU) @@ -35,8 +35,8 @@ - {{::sale.advanceable}} + ng-class="{'alert': sale.quantity>sale.movable}"> + {{::sale.movable}} {{::sale.quantity}} diff --git a/modules/ticket/front/basic-data/step-two/index.js b/modules/ticket/front/basic-data/step-two/index.js index db0bb6d44..2daa98af9 100644 --- a/modules/ticket/front/basic-data/step-two/index.js +++ b/modules/ticket/front/basic-data/step-two/index.js @@ -69,7 +69,7 @@ class Controller extends Component { let haveNotNegatives = false; this.ticket.sale.items.forEach(item => { - if (item.quantity > item.advanceable) + if (item.quantity > item.movable) haveNegatives = true; else haveNotNegatives = true; diff --git a/modules/ticket/front/basic-data/step-two/index.spec.js b/modules/ticket/front/basic-data/step-two/index.spec.js index 0567785e9..0c299521b 100644 --- a/modules/ticket/front/basic-data/step-two/index.spec.js +++ b/modules/ticket/front/basic-data/step-two/index.spec.js @@ -73,12 +73,12 @@ describe('Ticket', () => { { item: 1, quantity: 2, - advanceable: 1 + movable: 1 }, { item: 2, quantity: 1, - advanceable: 5 + movable: 5 } ] } diff --git a/modules/ticket/front/basic-data/step-two/locale/es.yml b/modules/ticket/front/basic-data/step-two/locale/es.yml index ccf1f5572..1a7427d2e 100644 --- a/modules/ticket/front/basic-data/step-two/locale/es.yml +++ b/modules/ticket/front/basic-data/step-two/locale/es.yml @@ -8,4 +8,4 @@ New price: Nuevo precio Price difference: Diferencia de precio Without create negatives: Sin crear negativos Clone this ticket with the changes and only sales availables: Clona este ticket con los cambios y solo las ventas disponibles. -Advanceable: Avanzable \ No newline at end of file +Movable: Movible \ No newline at end of file From 5970a6dfde331c525741dd4d32645bd7e26d2cac Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 26 Jan 2022 14:05:33 +0100 Subject: [PATCH 16/24] refactor(client_defaulter): title of columns --- .../client/back/methods/defaulter/filter.js | 2 ++ modules/client/front/defaulter/index.html | 22 +++++++++++-------- modules/client/front/defaulter/locale/es.yml | 5 +++-- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/modules/client/back/methods/defaulter/filter.js b/modules/client/back/methods/defaulter/filter.js index 95e75040e..15a56fb63 100644 --- a/modules/client/back/methods/defaulter/filter.js +++ b/modules/client/back/methods/defaulter/filter.js @@ -62,12 +62,14 @@ module.exports = Self => { d.amount, co.created, co.text observation, + uw.name workerName, c.creditInsurance, d.defaulterSinced FROM vn.defaulter d JOIN vn.client c ON c.id = d.clientFk LEFT JOIN vn.clientObservation co ON co.clientFk = c.id LEFT JOIN account.user u ON u.id = c.salesPersonFk + LEFT JOIN account.user uw ON uw.id = co.workerFk WHERE d.created = CURDATE() AND d.amount > 0 diff --git a/modules/client/front/defaulter/index.html b/modules/client/front/defaulter/index.html index 6ab52dd4f..ed50ebad9 100644 --- a/modules/client/front/defaulter/index.html +++ b/modules/client/front/defaulter/index.html @@ -18,9 +18,9 @@
-
Balance due
+
Total
@@ -51,17 +51,21 @@ Client Comercial - Credit + + Balance D + Last observation - Credit insurance + + Credit I + From - + diff --git a/modules/client/front/defaulter/locale/es.yml b/modules/client/front/defaulter/locale/es.yml index 95184d06d..d0cca6e2a 100644 --- a/modules/client/front/defaulter/locale/es.yml +++ b/modules/client/front/defaulter/locale/es.yml @@ -1,5 +1,6 @@ Last observation: Última observación Add observation: Añadir observación -Balance due total: Saldo vencido total Search client: Buscar clientes -Add observation to all selected clients: Añadir observación a {{total}} cliente(s) seleccionado(s) \ No newline at end of file +Add observation to all selected clients: Añadir observación a {{total}} cliente(s) seleccionado(s) +Credit I: Crédito A +Balance D: Saldo V \ No newline at end of file From b25ffa8feb80a1f3fd1d844356433fe7c746d3e6 Mon Sep 17 00:00:00 2001 From: alexm Date: Fri, 28 Jan 2022 09:15:41 +0100 Subject: [PATCH 17/24] feat(ticket_step-two): redirect to new ticket --- ...dvancable.sql => 00-ticket_getMovable.sql} | 0 .../05-ticket/06_basic_data_steps.spec.js | 66 +++--- loopback/locale/es.json | 222 ++++++++++++++++-- .../back/methods/ticket/componentUpdate.js | 5 +- .../back/methods/ticket/priceDifference.js | 8 +- .../ticket/specs/priceDifference.spec.js | 3 + .../front/basic-data/step-two/index.html | 4 +- .../ticket/front/basic-data/step-two/index.js | 20 +- .../front/basic-data/step-two/index.spec.js | 77 +++++- 9 files changed, 329 insertions(+), 76 deletions(-) rename db/changes/10410-january/{00-ticket_getAdvancable.sql => 00-ticket_getMovable.sql} (100%) diff --git a/db/changes/10410-january/00-ticket_getAdvancable.sql b/db/changes/10410-january/00-ticket_getMovable.sql similarity index 100% rename from db/changes/10410-january/00-ticket_getAdvancable.sql rename to db/changes/10410-january/00-ticket_getMovable.sql diff --git a/e2e/paths/05-ticket/06_basic_data_steps.spec.js b/e2e/paths/05-ticket/06_basic_data_steps.spec.js index 93c6bba65..7a09edf06 100644 --- a/e2e/paths/05-ticket/06_basic_data_steps.spec.js +++ b/e2e/paths/05-ticket/06_basic_data_steps.spec.js @@ -92,59 +92,53 @@ describe('Ticket Edit basic data path', () => { }); it(`should split ticket without negatives`, async() => { - const tomorrow = new Date(); - tomorrow.setDate(tomorrow.getDate() + 1); + const newAgency = 'Silla247'; + const newDate = new Date(); + newDate.setDate(newDate.getDate() + 1); await page.accessToSearchResult('14'); await page.accessToSection('ticket.card.basicData.stepOne'); - const originalDate = await page - .waitToGetProperty(selectors.ticketDescriptor.descriptorDeliveryDate, 'innerText'); - const originalAgency = await page - .waitToGetProperty(selectors.ticketDescriptor.descriptorDeliveryAgency, 'innerText'); - - await page.autocompleteSearch(selectors.ticketBasicData.agency, 'Silla247'); - await page.pickDate(selectors.ticketBasicData.shipped, tomorrow); + await page.autocompleteSearch(selectors.ticketBasicData.agency, newAgency); + await page.pickDate(selectors.ticketBasicData.shipped, newDate); await page.waitToClick(selectors.ticketBasicData.nextStepButton); await page.waitToClick(selectors.ticketBasicData.withoutNegatives); await page.waitToClick(selectors.ticketBasicData.finalizeButton); - const resultDate = await page - .waitToGetProperty(selectors.ticketDescriptor.descriptorDeliveryDate, 'innerText'); - const resultAgency = await page - .waitToGetProperty(selectors.ticketDescriptor.descriptorDeliveryAgency, 'innerText'); + await page.waitForState('ticket.card.summary'); - expect(resultDate).toEqual(originalDate); - expect(resultAgency).toEqual(originalAgency); + const newTicketAgency = await page + .waitToGetProperty(selectors.ticketDescriptor.descriptorDeliveryAgency, 'innerText'); + const newTicketDate = await page + .waitToGetProperty(selectors.ticketDescriptor.descriptorDeliveryDate, 'innerText'); + + expect(newAgency).toEqual(newTicketAgency); + expect(newTicketDate).toContain(newDate.getDate()); }); - it(`should new ticket have one line from splited ticket`, async() => { - const tomorrow = new Date(); - tomorrow.setDate(tomorrow.getDate() + 1); - - const expectedDay = tomorrow.getDate(); - const expectedMonth = tomorrow.getMonth() + 1; - const expectedYear = tomorrow.getFullYear(); - - await page.loginAndModule('employee', 'ticket'); - await page.accessToSearchResult('29'); + it(`should new ticket have sale of old ticket`, async() => { await page.accessToSection('ticket.card.sale'); + await page.waitForState('ticket.card.sale'); const item = await page.waitToGetProperty(selectors.ticketSales.firstSaleId, 'innerText'); - const agency = await page - .waitToGetProperty(selectors.ticketDescriptor.descriptorDeliveryAgency, 'innerText'); - let date = await page - .waitToGetProperty(selectors.ticketDescriptor.descriptorDeliveryDate, 'innerText'); - - date = date.split(' '); - date = date[0].split('/'); expect(item).toEqual('4'); - expect(agency).toEqual('Silla247'); - expect(parseInt(date[0])).toEqual(expectedDay); - expect(parseInt(date[1])).toEqual(expectedMonth); - expect(parseInt(date[2])).toEqual(expectedYear); + }); + + it(`should old ticket have old date and agency`, async() => { + const oldDate = new Date(); + const oldAgency = 'Super-Man delivery'; + + await page.accessToSearchResult('14'); + + const oldTicketAgency = await page + .waitToGetProperty(selectors.ticketDescriptor.descriptorDeliveryAgency, 'innerText'); + const oldTicketDate = await page + .waitToGetProperty(selectors.ticketDescriptor.descriptorDeliveryDate, 'innerText'); + + expect(oldTicketAgency).toEqual(oldAgency); + expect(oldTicketDate).toContain(oldDate.getDate()); }); }); diff --git a/loopback/locale/es.json b/loopback/locale/es.json index c8be37d63..493b45c32 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -1,30 +1,201 @@ { - "Name cannot be blank": "Name cannot be blank", - "Swift / BIC cannot be empty": "Swift / BIC cannot be empty", - "Street cannot be empty": "Street cannot be empty", - "City cannot be empty": "City cannot be empty", - "Invalid email": "Invalid email", - "Phone cannot be blank": "Phone cannot be blank", + "Phone format is invalid": "El formato del teléfono no es correcto", + "You are not allowed to change the credit": "No tienes privilegios para modificar el crédito", + "Unable to mark the equivalence surcharge": "No se puede marcar el recargo de equivalencia", + "The default consignee can not be unchecked": "No se puede desmarcar el consignatario predeterminado", + "Unable to default a disabled consignee": "No se puede poner predeterminado un consignatario desactivado", + "Can't be blank": "No puede estar en blanco", + "Invalid TIN": "NIF/CIF invalido", + "TIN must be unique": "El NIF/CIF debe ser único", + "A client with that Web User name already exists": "Ya existe un cliente con ese Usuario Web", + "Is invalid": "Is invalid", + "Quantity cannot be zero": "La cantidad no puede ser cero", + "Enter an integer different to zero": "Introduce un entero distinto de cero", + "Package cannot be blank": "El embalaje no puede estar en blanco", + "The company name must be unique": "La razón social debe ser única", + "Invalid email": "Correo electrónico inválido", + "The IBAN does not have the correct format": "El IBAN no tiene el formato correcto", + "That payment method requires an IBAN": "El método de pago seleccionado requiere un IBAN", + "That payment method requires a BIC": "El método de pago seleccionado requiere un BIC", + "State cannot be blank": "El estado no puede estar en blanco", + "Worker cannot be blank": "El trabajador no puede estar en blanco", + "Cannot change the payment method if no salesperson": "No se puede cambiar la forma de pago si no hay comercial asignado", + "can't be blank": "El campo no puede estar vacío", + "Observation type must be unique": "El tipo de observación no puede repetirse", "The credit must be an integer greater than or equal to zero": "The credit must be an integer greater than or equal to zero", - "The grade must be an integer greater than or equal to zero": "The grade must be an integer greater than or equal to zero", - "Description should have maximum of 45 characters": "Description should have maximum of 45 characters", - "Amount cannot be zero": "Amount cannot be zero", - "Period cannot be blank": "Period cannot be blank", - "Sample type cannot be blank": "Sample type cannot be blank", - "Cannot be blank": "Cannot be blank", - "The social name cannot be empty": "The social name cannot be empty", - "The nif cannot be empty": "The nif cannot be empty", - "Concept cannot be blank": "Concept cannot be blank", - "Enter an integer different to zero": "Enter an integer different to zero", - "Package cannot be blank": "Package cannot be blank", - "State cannot be blank": "State cannot be blank", - "Worker cannot be blank": "Worker cannot be blank", - "Agency cannot be blank": "Agency cannot be blank", + "The grade must be similar to the last one": "El grade debe ser similar al último", + "Only manager can change the credit": "Solo el gerente puede cambiar el credito de este cliente", + "Name cannot be blank": "El nombre no puede estar en blanco", + "Phone cannot be blank": "El teléfono no puede estar en blanco", + "Period cannot be blank": "El periodo no puede estar en blanco", + "Choose a company": "Selecciona una empresa", + "Se debe rellenar el campo de texto": "Se debe rellenar el campo de texto", + "Description should have maximum of 45 characters": "La descripción debe tener maximo 45 caracteres", + "Cannot be blank": "El campo no puede estar en blanco", + "The grade must be an integer greater than or equal to zero": "El grade debe ser un entero mayor o igual a cero", + "Sample type cannot be blank": "El tipo de plantilla no puede quedar en blanco", + "Description cannot be blank": "Se debe rellenar el campo de texto", + "The new quantity should be smaller than the old one": "La nueva cantidad debe de ser menor que la anterior", + "The value should not be greater than 100%": "El valor no debe de ser mayor de 100%", + "The value should be a number": "El valor debe ser un numero", + "This order is not editable": "Esta orden no se puede modificar", + "You can't create an order for a frozen client": "No puedes crear una orden para un cliente congelado", + "You can't create an order for a client that has a debt": "No puedes crear una orden para un cliente con deuda", + "is not a valid date": "No es una fecha valida", + "Barcode must be unique": "El código de barras debe ser único", + "The warehouse can't be repeated": "El almacén no puede repetirse", + "The tag can't be repeated": "El tag no puede repetirse", + "The observation type can't be repeated": "El tipo de observación no puede repetirse", + "A claim with that sale already exists": "Ya existe una reclamación para esta línea", + "You don't have enough privileges to change that field": "No tienes permisos para cambiar ese campo", + "Warehouse cannot be blank": "El almacén no puede quedar en blanco", + "Agency cannot be blank": "La agencia no puede quedar en blanco", + "You can't make changes on a client with verified data": "No puedes hacer cambios en un cliente con datos comprobados", + "This address doesn't exist": "Este consignatario no existe", + "You must delete the claim id %d first": "Antes debes borrar la reclamación %d", + "You don't have enough privileges": "No tienes suficientes permisos", + "Cannot check Equalization Tax in this NIF/CIF": "No se puede marcar RE en este NIF/CIF", + "You can't make changes on the basic data of an confirmed order or with rows": "No puedes cambiar los datos basicos de una orden con artículos", + "INVALID_USER_NAME": "El nombre de usuario solo debe contener letras minúsculas o, a partir del segundo carácter, números o subguiones, no esta permitido el uso de la letra ñ", + "You can't create a ticket for a frozen client": "No puedes crear un ticket para un cliente congelado", + "You can't create a ticket for a inactive client": "No puedes crear un ticket para un cliente inactivo", + "Tag value cannot be blank": "El valor del tag no puede quedar en blanco", + "ORDER_EMPTY": "Cesta vacía", + "You don't have enough privileges to do that": "No tienes permisos para cambiar esto", + "NO SE PUEDE DESACTIVAR EL CONSIGNAT": "NO SE PUEDE DESACTIVAR EL CONSIGNAT", + "Error. El NIF/CIF está repetido": "Error. El NIF/CIF está repetido", + "Street cannot be empty": "Dirección no puede estar en blanco", + "City cannot be empty": "Cuidad no puede estar en blanco", + "Code cannot be blank": "Código no puede estar en blanco", + "You cannot remove this department": "No puedes eliminar este departamento", + "The extension must be unique": "La extensión debe ser unica", + "The secret can't be blank": "La contraseña no puede estar en blanco", + "We weren't able to send this SMS": "No hemos podido enviar el SMS", + "This client can't be invoiced": "Este cliente no puede ser facturado", + "This ticket can't be invoiced": "Este ticket no puede ser facturado", + "You cannot add or modify services to an invoiced ticket": "No puedes añadir o modificar servicios a un ticket facturado", + "This ticket can not be modified": "Este ticket no puede ser modificado", + "The introduced hour already exists": "Esta hora ya ha sido introducida", + "INFINITE_LOOP": "Existe una dependencia entre dos Jefes", + "The sales of the current ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas", + "The sales of the receiver ticket can't be modified": "Las lineas del ticket al que envias no pueden ser modificadas", + "NO_AGENCY_AVAILABLE": "No hay una zona de reparto disponible con estos parámetros", + "ERROR_PAST_SHIPMENT": "No puedes seleccionar una fecha de envío en pasado", + "The current ticket can't be modified": "El ticket actual no puede ser modificado", + "The current claim can't be modified": "La reclamación actual no puede ser modificada", + "The sales of this ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas", + "Sale(s) blocked, contact production": "Linea(s) bloqueada(s), contacte con produccion", + "Please select at least one sale": "Por favor selecciona al menos una linea", + "All sales must belong to the same ticket": "Todas las lineas deben pertenecer al mismo ticket", + "NO_ZONE_FOR_THIS_PARAMETERS": "Para este día no hay ninguna zona configurada", + "This item doesn't exists": "El artículo no existe", + "NOT_ZONE_WITH_THIS_PARAMETERS": "Para este día no hay ninguna zona configurada", + "Extension format is invalid": "El formato de la extensión es inválido", + "Invalid parameters to create a new ticket": "Parámetros inválidos para crear un nuevo ticket", + "This item is not available": "Este artículo no está disponible", + "This postcode already exists": "Este código postal ya existe", + "Concept cannot be blank": "El concepto no puede quedar en blanco", + "File doesn't exists": "El archivo no existe", + "You don't have privileges to change the zone or for these parameters there are more than one shipping options, talk to agencies": "No tienes permisos para cambiar la zona o para esos parámetros hay más de una opción de envío, hable con las agencias", + "This ticket is already on weekly tickets": "Este ticket ya está en tickets programados", + "Ticket id cannot be blank": "El id de ticket no puede quedar en blanco", + "Weekday cannot be blank": "El día de la semana no puede quedar en blanco", + "You can't delete a confirmed order": "No puedes borrar un pedido confirmado", + "Can't create stowaway for this ticket": "No se puede crear un polizon para este ticket", + "The social name has an invalid format": "El nombre fiscal tiene un formato incorrecto", + "Invalid quantity": "Cantidad invalida", + "This postal code is not valid": "This postal code is not valid", + "is invalid": "is invalid", + "The postcode doesn't exist. Please enter a correct one": "El código postal no existe. Por favor, introduce uno correcto", + "The department name can't be repeated": "El nombre del departamento no puede repetirse", + "This phone already exists": "Este teléfono ya existe", + "You cannot move a parent to its own sons": "No puedes mover un elemento padre a uno de sus hijos", + "You can't create a claim for a removed ticket": "No puedes crear una reclamación para un ticket eliminado", + "You cannot delete a ticket that part of it is being prepared": "No puedes eliminar un ticket en el que una parte que está siendo preparada", + "You must delete all the buy requests first": "Debes eliminar todas las peticiones de compra primero", + "You should specify a date": "Debes especificar una fecha", + "You should specify at least a start or end date": "Debes especificar al menos una fecha de inicio o de fín", + "Start date should be lower than end date": "La fecha de inicio debe ser menor que la fecha de fín", + "You should mark at least one week day": "Debes marcar al menos un día de la semana", + "Swift / BIC can't be empty": "Swift / BIC no puede estar vacío", + "Customs agent is required for a non UEE member": "El agente de aduanas es requerido para los clientes extracomunitarios", + "Incoterms is required for a non UEE member": "El incoterms es requerido para los clientes extracomunitarios", + "Deleted sales from ticket": "He eliminado las siguientes lineas del ticket [{{ticketId}}]({{{ticketUrl}}}): {{{deletions}}}", + "Added sale to ticket": "He añadido la siguiente linea al ticket [{{ticketId}}]({{{ticketUrl}}}): {{{addition}}}", + "Changed sale discount": "He cambiado el descuento de las siguientes lineas al ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}", + "Created claim": "He creado la reclamación [{{claimId}}]({{{claimUrl}}}) de las siguientes lineas del ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}", + "Changed sale price": "He cambiado el precio de [{{itemId}} {{concept}}]({{{itemUrl}}}) ({{quantity}}) de {{oldPrice}}€ ➔ *{{newPrice}}€* del ticket [{{ticketId}}]({{{ticketUrl}}})", + "Changed sale quantity": "He cambiado la cantidad de [{{itemId}} {{concept}}]({{{itemUrl}}}) de {{oldQuantity}} ➔ *{{newQuantity}}* del ticket [{{ticketId}}]({{{ticketUrl}}})", + "State": "Estado", + "regular": "normal", + "reserved": "reservado", + "Changed sale reserved state": "He cambiado el estado reservado de las siguientes lineas al ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}", + "Bought units from buy request": "Se ha comprado {{quantity}} unidades de [{{itemId}} {{concept}}]({{{urlItem}}}) para el ticket id [{{ticketId}}]({{{url}}})", + "Deny buy request": "Se ha rechazado la petición de compra para el ticket id [{{ticketId}}]({{{url}}}). Motivo: {{observation}}", + "MESSAGE_INSURANCE_CHANGE": "He cambiado el crédito asegurado del cliente [{{clientName}} ({{clientId}})]({{{url}}}) a *{{credit}} €*", + "Changed client paymethod": "He cambiado la forma de pago del cliente [{{clientName}} ({{clientId}})]({{{url}}})", + "Sent units from ticket": "Envio *{{quantity}}* unidades de [{{concept}} ({{itemId}})]({{{itemUrl}}}) a *\"{{nickname}}\"* provenientes del ticket id [{{ticketId}}]({{{ticketUrl}}})", + "Claim will be picked": "Se recogerá el género de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}*", + "Claim state has changed to incomplete": "Se ha cambiado el estado de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}* a *incompleta*", + "This ticket is not an stowaway anymore": "El ticket id [{{ticketId}}]({{{ticketUrl}}}) ha dejado de ser un polizón", + "Client checked as validated despite of duplication": "Cliente comprobado a pesar de que existe el cliente id {{clientId}}", + "ORDER_ROW_UNAVAILABLE": "No hay disponibilidad de este producto", + "Distance must be lesser than 1000": "La distancia debe ser inferior a 1000", + "This ticket is deleted": "Este ticket está eliminado", + "Unable to clone this travel": "No ha sido posible clonar este travel", + "This thermograph id already exists": "La id del termógrafo ya existe", + "Choose a date range or days forward": "Selecciona un rango de fechas o días en adelante", + "ORDER_ALREADY_CONFIRMED": "ORDER_ALREADY_CONFIRMED", + "Invalid password": "Invalid password", + "Password does not meet requirements": "Password does not meet requirements", + "Role already assigned": "Role already assigned", + "Invalid role name": "Invalid role name", + "Role name must be written in camelCase": "Role name must be written in camelCase", + "Email already exists": "Email already exists", + "User already exists": "User already exists", + "Absence change notification on the labour calendar": "Notificacion de cambio de ausencia en el calendario laboral", + "Created absence": "El empleado {{author}} ha añadido una ausencia de tipo '{{absenceType}}' a {{employee}} para el día {{dated}}.", + "Deleted absence": "El empleado {{author}} ha eliminado una ausencia de tipo '{{absenceType}}' a {{employee}} del día {{dated}}.", + "I have deleted the ticket id": "He eliminado el ticket id [{{id}}]({{{url}}})", + "I have restored the ticket id": "He restaurado el ticket id [{{id}}]({{{url}}})", + "You can only restore a ticket within the first hour after deletion": "Únicamente puedes restaurar el ticket dentro de la primera hora después de su eliminación", + "Changed this data from the ticket": "He cambiado estos datos del ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}", + "agencyModeFk": "Agencia", + "clientFk": "Cliente", + "zoneFk": "Zona", + "warehouseFk": "Almacén", + "shipped": "F. envío", + "landed": "F. entrega", + "addressFk": "Consignatario", + "companyFk": "Empresa", + "The social name cannot be empty": "La razón social no puede quedar en blanco", + "The nif cannot be empty": "El NIF no puede quedar en blanco", + "You need to fill sage information before you check verified data": "Debes rellenar la información de sage antes de marcar datos comprobados", + "ASSIGN_ZONE_FIRST": "Asigna una zona primero", + "Amount cannot be zero": "El importe no puede ser cero", + "Company has to be official": "Empresa inválida", + "You can not select this payment method without a registered bankery account": "No se puede utilizar este método de pago si no has registrado una cuenta bancaria", + "Action not allowed on the test environment": "Esta acción no está permitida en el entorno de pruebas", + "The selected ticket is not suitable for this route": "El ticket seleccionado no es apto para esta ruta", + "Sorts whole route": "Reordena ruta entera", + "New ticket request has been created with price": "Se ha creado una nueva petición de compra '{{description}}' para el día *{{shipped}}*, con una cantidad de *{{quantity}}* y un precio de *{{price}} €*", + "New ticket request has been created": "Se ha creado una nueva petición de compra '{{description}}' para el día *{{shipped}}*, con una cantidad de *{{quantity}}*", + "Swift / BIC cannot be empty": "Swift / BIC no puede estar vacío", + "This BIC already exist.": "Este BIC ya existe.", + "That item doesn't exists": "Ese artículo no existe", + "There's a new urgent ticket:": "Hay un nuevo ticket urgente:", + "Invalid account": "Cuenta inválida", + "Compensation account is empty": "La cuenta para compensar está vacia", + "This genus already exist": "Este genus ya existe", + "This specie already exist": "Esta especie ya existe", + "Client assignment has changed": "He cambiado el comercial ~*\"<{{previousWorkerName}}>\"*~ por *\"<{{currentWorkerName}}>\"* del cliente [{{clientName}} ({{clientId}})]({{{url}}})", + "None": "Ninguno", + "The contract was not active during the selected date": "El contrato no estaba activo durante la fecha seleccionada", + "Cannot add more than one '1/2 day vacation'": "No puedes añadir más de un 'Vacaciones 1/2 dia'", + "This document already exists on this ticket": "Este documento ya existe en el ticket", + "Some of the selected tickets are not billable": "Algunos de los tickets seleccionados no son facturables", + "You can't invoice tickets from multiple clients": "No puedes facturar tickets de multiples clientes", "nickname": "nickname", - "shipped": "shipped", - "landed": "landed", - "isWithoutNegatives": "isWithoutNegatives", - "Changed this data from the ticket": "Changed this data from the ticket", "INACTIVE_PROVIDER": "Proveedor inactivo", "This client is not invoiceable": "Este cliente no es facturable", "serial non editable": "Esta serie no permite asignar la referencia", @@ -47,5 +218,6 @@ "The worker has a marked absence that day": "El trabajador tiene marcada una ausencia ese día", "You can not modify is pay method checked": "No se puede modificar el campo método de pago validado", "Can't transfer claimed sales": "No puedes transferir lineas reclamadas", - "You don't have privileges to create pay back": "No tienes permisos para crear un abono" + "You don't have privileges to create pay back": "No tienes permisos para crear un abono", + "isWithoutNegatives": "isWithoutNegatives" } \ No newline at end of file diff --git a/modules/ticket/back/methods/ticket/componentUpdate.js b/modules/ticket/back/methods/ticket/componentUpdate.js index e01798887..083abc47d 100644 --- a/modules/ticket/back/methods/ticket/componentUpdate.js +++ b/modules/ticket/back/methods/ticket/componentUpdate.js @@ -175,7 +175,7 @@ module.exports = Self => { // Force to unroute ticket const hasToBeUnrouted = true; const query = 'CALL vn.ticket_componentMakeUpdate(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; - const res = await Self.rawSql(query, [ + let res = await Self.rawSql(query, [ args.id, args.clientFk, args.nickname, @@ -248,8 +248,9 @@ module.exports = Self => { await models.Chat.sendCheckingPresence(ctx, salesPersonId, message); } + res.id = args.id; if (tx) await tx.commit(); - + return res; } catch (e) { if (tx) await tx.rollback(); diff --git a/modules/ticket/back/methods/ticket/priceDifference.js b/modules/ticket/back/methods/ticket/priceDifference.js index ffcdc19ef..c91956ece 100644 --- a/modules/ticket/back/methods/ticket/priceDifference.js +++ b/modules/ticket/back/methods/ticket/priceDifference.js @@ -111,6 +111,12 @@ module.exports = Self => { }; // Get items movable + const ticketOrigin = await models.Ticket.findById(args.id, null, myOptions); + const differenceShipped = ticketOrigin.shipped.getTime() != args.shipped.getTime(); + const differenceWarehouse = ticketOrigin.warehouseFk != args.warehouseId; + + salesObj.haveDifferences = differenceShipped || differenceWarehouse; + let query = `CALL ticket_getMovable(?,?,?)`; let params = [args.id, args.shipped, args.warehouseId]; const [salesMovable] = await Self.rawSql(query, params, myOptions); @@ -146,7 +152,7 @@ module.exports = Self => { } if (tx) await tx.commit(); - + return salesObj; } catch (e) { if (tx) await tx.rollback(); diff --git a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js index 6659ed26e..e9aa5030a 100644 --- a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js +++ b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js @@ -15,6 +15,7 @@ describe('sale priceDifference()', () => { ctx.args = { id: 16, landed: tomorrow, + shipped: tomorrow, addressId: 126, agencyModeId: 7, zoneId: 3, @@ -45,6 +46,7 @@ describe('sale priceDifference()', () => { ctx.args = { id: 1, landed: new Date(), + shipped: new Date(), addressId: 121, zoneId: 3, warehouseId: 1 @@ -72,6 +74,7 @@ describe('sale priceDifference()', () => { const ctx = {req: {accessToken: {userId: 1106}}}; ctx.args = { id: 11, + shipped: tomorrow, landed: tomorrow, addressId: 122, agencyModeId: 7, diff --git a/modules/ticket/front/basic-data/step-two/index.html b/modules/ticket/front/basic-data/step-two/index.html index 88475daa2..93012c720 100644 --- a/modules/ticket/front/basic-data/step-two/index.html +++ b/modules/ticket/front/basic-data/step-two/index.html @@ -9,7 +9,7 @@ Item Description - Movable + Movable Quantity Price (PPU) New (PPU) @@ -32,7 +32,7 @@ tabindex="-1"> - + diff --git a/modules/ticket/front/basic-data/step-two/index.js b/modules/ticket/front/basic-data/step-two/index.js index 2daa98af9..c12647aa5 100644 --- a/modules/ticket/front/basic-data/step-two/index.js +++ b/modules/ticket/front/basic-data/step-two/index.js @@ -67,6 +67,7 @@ class Controller extends Component { ticketHaveNegatives() { let haveNegatives = false; let haveNotNegatives = false; + const haveDifferences = this.ticket.sale.haveDifferences; this.ticket.sale.items.forEach(item => { if (item.quantity > item.movable) @@ -76,7 +77,7 @@ class Controller extends Component { }); this.ticket.withoutNegatives = false; - this.haveNegatives = (haveNegatives && haveNotNegatives); + this.haveNegatives = (haveNegatives && haveNotNegatives && haveDifferences); } onSubmit() { @@ -102,13 +103,16 @@ class Controller extends Component { isWithoutNegatives: this.ticket.withoutNegatives }; - this.$http.post(query, params).then(res => { - this.vnApp.showMessage( - this.$t(`The ticket has been unrouted`) - ); - this.card.reload(); - this.$state.go('ticket.card.summary', {id: this.$params.id}); - }); + this.$http.post(query, params) + .then(res => { + this.ticketToMove = res.data.id; + this.vnApp.showMessage( + this.$t(`The ticket has been unrouted`) + ); + }) + .finally(() => { + this.$state.go('ticket.card.summary', {id: this.ticketToMove}); + }); } } diff --git a/modules/ticket/front/basic-data/step-two/index.spec.js b/modules/ticket/front/basic-data/step-two/index.spec.js index 0c299521b..ac85a7818 100644 --- a/modules/ticket/front/basic-data/step-two/index.spec.js +++ b/modules/ticket/front/basic-data/step-two/index.spec.js @@ -66,7 +66,7 @@ describe('Ticket', () => { }); describe('ticketHaveNegatives()', () => { - it('should show if ticket have any negative and any not negative', () => { + it('should show if ticket have any negative, have differences, but not all sale are negative', () => { controller.ticket = { sale: { items: [ @@ -80,7 +80,8 @@ describe('Ticket', () => { quantity: 1, movable: 5 } - ] + ], + haveDifferences: true } }; @@ -88,6 +89,78 @@ describe('Ticket', () => { expect(controller.haveNegatives).toEqual(true); }); + + it('should not show if ticket not have any negative', () => { + controller.ticket = { + sale: { + items: [ + { + item: 1, + quantity: 2, + movable: 1 + }, + { + item: 2, + quantity: 2, + movable: 1 + } + ], + haveDifferences: true + } + }; + + controller.ticketHaveNegatives(); + + expect(controller.haveNegatives).toEqual(false); + }); + + it('should not show if all sale are negative', () => { + controller.ticket = { + sale: { + items: [ + { + item: 1, + quantity: 2, + movable: 1 + }, + { + item: 2, + quantity: 2, + movable: 1 + } + ], + haveDifferences: true + } + }; + + controller.ticketHaveNegatives(); + + expect(controller.haveNegatives).toEqual(false); + }); + + it('should not show if ticket not have differences', () => { + controller.ticket = { + sale: { + items: [ + { + item: 1, + quantity: 2, + movable: 1 + }, + { + item: 2, + quantity: 1, + movable: 2 + } + ], + haveDifferences: false + } + }; + + controller.ticketHaveNegatives(); + + expect(controller.haveNegatives).toEqual(false); + }); }); }); }); From 44e6219df519a51dfb3bd2fde30cd06fb3b0d8a8 Mon Sep 17 00:00:00 2001 From: vicent Date: Fri, 28 Jan 2022 09:30:54 +0100 Subject: [PATCH 18/24] update table companyGroup --- db/changes/10410-january/00-companyGroup.sql | 12 ++++++++++++ db/dump/fixtures.sql | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 db/changes/10410-january/00-companyGroup.sql diff --git a/db/changes/10410-january/00-companyGroup.sql b/db/changes/10410-january/00-companyGroup.sql new file mode 100644 index 000000000..2c5477e63 --- /dev/null +++ b/db/changes/10410-january/00-companyGroup.sql @@ -0,0 +1,12 @@ +UPDATE `vn`.`companyGroup` + SET `code`='verdnatura' + WHERE `id`=1; +UPDATE `vn`.`companyGroup` + SET `code`='ornamental' + WHERE `id`=2; +UPDATE `vn`.`companyGroup` + SET `code`='other' + WHERE `id`=3; +UPDATE `vn`.`companyGroup` + SET `code`='provisional' + WHERE `id`=4; diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index efe7906ce..ed03cba1e 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -456,7 +456,7 @@ INSERT INTO `vn`.`creditInsurance`(`id`, `creditClassification`, `credit`, `crea INSERT INTO `vn`.`companyGroup`(`id`, `code`) VALUES (1, 'wayneIndustries'), - (2, 'Verdnatura'); + (2, 'verdnatura'); INSERT INTO `vn`.`bankEntity`(`id`, `countryFk`, `name`, `bic`) VALUES From 2480f37e247ee88a4f89a63a7a16be161eb67d5d Mon Sep 17 00:00:00 2001 From: joan Date: Fri, 28 Jan 2022 14:20:54 +0100 Subject: [PATCH 19/24] Renamed version number (olrder version already applied on production) --- db/changes/{10410-january => 10411-january}/00-acl.sql | 0 db/changes/{10410-january => 10411-january}/00-booking.sql | 0 db/changes/{10410-january => 10411-january}/00-saleVolume.sql | 0 db/changes/{10410-january => 10411-january}/00-smsConfig.sql | 0 db/changes/{10410-january => 10411-january}/00-workerLabour.sql | 0 .../{10410-january => 10411-january}/01-smsConfig_update.sql | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename db/changes/{10410-january => 10411-january}/00-acl.sql (100%) rename db/changes/{10410-january => 10411-january}/00-booking.sql (100%) rename db/changes/{10410-january => 10411-january}/00-saleVolume.sql (100%) rename db/changes/{10410-january => 10411-january}/00-smsConfig.sql (100%) rename db/changes/{10410-january => 10411-january}/00-workerLabour.sql (100%) rename db/changes/{10410-january => 10411-january}/01-smsConfig_update.sql (100%) diff --git a/db/changes/10410-january/00-acl.sql b/db/changes/10411-january/00-acl.sql similarity index 100% rename from db/changes/10410-january/00-acl.sql rename to db/changes/10411-january/00-acl.sql diff --git a/db/changes/10410-january/00-booking.sql b/db/changes/10411-january/00-booking.sql similarity index 100% rename from db/changes/10410-january/00-booking.sql rename to db/changes/10411-january/00-booking.sql diff --git a/db/changes/10410-january/00-saleVolume.sql b/db/changes/10411-january/00-saleVolume.sql similarity index 100% rename from db/changes/10410-january/00-saleVolume.sql rename to db/changes/10411-january/00-saleVolume.sql diff --git a/db/changes/10410-january/00-smsConfig.sql b/db/changes/10411-january/00-smsConfig.sql similarity index 100% rename from db/changes/10410-january/00-smsConfig.sql rename to db/changes/10411-january/00-smsConfig.sql diff --git a/db/changes/10410-january/00-workerLabour.sql b/db/changes/10411-january/00-workerLabour.sql similarity index 100% rename from db/changes/10410-january/00-workerLabour.sql rename to db/changes/10411-january/00-workerLabour.sql diff --git a/db/changes/10410-january/01-smsConfig_update.sql b/db/changes/10411-january/01-smsConfig_update.sql similarity index 100% rename from db/changes/10410-january/01-smsConfig_update.sql rename to db/changes/10411-january/01-smsConfig_update.sql From d30e8d9bcc3f3d3630361c7e17c7cf814ec6e8d3 Mon Sep 17 00:00:00 2001 From: joan Date: Fri, 28 Jan 2022 14:50:19 +0100 Subject: [PATCH 20/24] Removed already uploaded changes --- db/changes/10411-january/00-smsConfig.sql | 5 ----- db/changes/10411-january/01-smsConfig_update.sql | 7 ------- 2 files changed, 12 deletions(-) delete mode 100644 db/changes/10411-january/00-smsConfig.sql delete mode 100644 db/changes/10411-january/01-smsConfig_update.sql diff --git a/db/changes/10411-january/00-smsConfig.sql b/db/changes/10411-january/00-smsConfig.sql deleted file mode 100644 index b3f1610d4..000000000 --- a/db/changes/10411-january/00-smsConfig.sql +++ /dev/null @@ -1,5 +0,0 @@ -ALTER TABLE `vn`.`smsConfig` ADD apiKey varchar(50) NULL; -ALTER TABLE `vn`.`smsConfig` CHANGE `user` user__ varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL; -ALTER TABLE `vn`.`smsConfig` CHANGE password password__ varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL; -ALTER TABLE `vn`.`sms` MODIFY COLUMN statusCode smallint(9) DEFAULT 0 NULL; -ALTER TABLE `vn`.`sms` MODIFY COLUMN status varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT 'OK' NULL; diff --git a/db/changes/10411-january/01-smsConfig_update.sql b/db/changes/10411-january/01-smsConfig_update.sql deleted file mode 100644 index c4b4c895e..000000000 --- a/db/changes/10411-january/01-smsConfig_update.sql +++ /dev/null @@ -1,7 +0,0 @@ -UPDATE `vn`.`smsConfig` - SET `uri` = 'https://api.gateway360.com/api/3.0/sms/send' - WHERE `id` = 1; - -UPDATE `vn`.`smsConfig` - SET `apiKey` = '5715476da95b46d686a5a255e6459523' - WHERE `id` = 1; \ No newline at end of file From 746cbede4bb37c0c4ca28c0f27a81373e1f617a0 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 31 Jan 2022 08:17:15 +0100 Subject: [PATCH 21/24] feat(client_defaulter): move tool-bar up , add column author --- e2e/helpers/selectors.js | 2 +- e2e/paths/02-client/21_defaulter.spec.js | 4 +- .../client/back/methods/defaulter/filter.js | 3 +- modules/client/front/defaulter/index.html | 61 +++++++++++-------- modules/client/front/defaulter/locale/es.yml | 5 +- 5 files changed, 45 insertions(+), 30 deletions(-) diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index 0172ca4e0..e757ca385 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -308,7 +308,7 @@ export default { anyClient: 'vn-client-defaulter-index vn-tbody > vn-tr', firstClientName: 'vn-client-defaulter-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(2) > span', firstSalesPersonName: 'vn-client-defaulter-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(3) > span', - firstObservation: 'vn-client-defaulter-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(5) > vn-textarea[ng-model="defaulter.observation"]', + firstObservation: 'vn-client-defaulter-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(6) > vn-textarea[ng-model="defaulter.observation"]', allDefaulterCheckbox: 'vn-client-defaulter-index vn-thead vn-multi-check', addObservationButton: 'vn-client-defaulter-index vn-button[icon="icon-notes"]', observation: '.vn-dialog.shown vn-textarea[ng-model="$ctrl.defaulter.observation"]', diff --git a/e2e/paths/02-client/21_defaulter.spec.js b/e2e/paths/02-client/21_defaulter.spec.js index 406c802ab..1d5fc8efb 100644 --- a/e2e/paths/02-client/21_defaulter.spec.js +++ b/e2e/paths/02-client/21_defaulter.spec.js @@ -36,7 +36,7 @@ describe('Client defaulter path', () => { const expectedObservation = 'Madness, as you know, is like gravity, all it takes is a little push'; const result = await page.waitToGetProperty(selectors.clientDefaulter.firstObservation, 'value'); - expect(result).toEqual(expectedObservation); + expect(result).toContain(expectedObservation); }); it('should not add empty observation', async() => { @@ -68,6 +68,6 @@ describe('Client defaulter path', () => { const message = await page.waitForSnackbar(); expect(message.text).toContain('Observation saved!'); - expect(result).toEqual('My new observation'); + expect(result).toContain('My new observation'); }); }); diff --git a/modules/client/back/methods/defaulter/filter.js b/modules/client/back/methods/defaulter/filter.js index 15a56fb63..c06d1c51b 100644 --- a/modules/client/back/methods/defaulter/filter.js +++ b/modules/client/back/methods/defaulter/filter.js @@ -61,7 +61,8 @@ module.exports = Self => { u.name salesPersonName, d.amount, co.created, - co.text observation, + CONCAT(DATE(co.created), ' ', co.text) observation, + uw.id workerFk, uw.name workerName, c.creditInsurance, d.defaulterSinced diff --git a/modules/client/front/defaulter/index.html b/modules/client/front/defaulter/index.html index ed50ebad9..121556df2 100644 --- a/modules/client/front/defaulter/index.html +++ b/modules/client/front/defaulter/index.html @@ -15,23 +15,21 @@ model="model"> - -
-
-
Total
- - -
-
-
+ class="vn-w-xl"> - - + +
+
+
Total
+ + +
+
+
- - +
+
@@ -53,20 +51,27 @@ Comercial - Balance D + vn-tooltip="Balance due" + number> + Balance D. - Last observation - Credit I + vn-tooltip="Worker who made the last observation" + shrink> + Author - From + Last observation + + Credit I. + + From - + @@ -89,11 +94,19 @@
{{::defaulter.amount}} + + + {{::defaulter.workerName | dashIfEmpty}} + + diff --git a/modules/client/front/defaulter/locale/es.yml b/modules/client/front/defaulter/locale/es.yml index d0cca6e2a..172a3125d 100644 --- a/modules/client/front/defaulter/locale/es.yml +++ b/modules/client/front/defaulter/locale/es.yml @@ -2,5 +2,6 @@ Last observation: Última observación Add observation: Añadir observación Search client: Buscar clientes Add observation to all selected clients: Añadir observación a {{total}} cliente(s) seleccionado(s) -Credit I: Crédito A -Balance D: Saldo V \ No newline at end of file +Credit I.: Crédito A. +Balance D.: Saldo V. +Worker who made the last observation: Trabajador que ha realizado la última observación \ No newline at end of file From f21cdeb3b6943c50b45ab08e2d3a0f083f1e7b02 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 31 Jan 2022 13:27:33 +0100 Subject: [PATCH 22/24] fix(item_waste): title background dark --- modules/item/front/waste/index/style.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/item/front/waste/index/style.scss b/modules/item/front/waste/index/style.scss index 09e3a2a4c..faac46139 100644 --- a/modules/item/front/waste/index/style.scss +++ b/modules/item/front/waste/index/style.scss @@ -11,7 +11,7 @@ vn-item-waste-detail { padding-bottom: 7px; padding-bottom: 4px; font-weight: lighter; - background-color: #fde6ca; + background-color: $color-bg; border-bottom: 1px solid #f7931e; white-space: nowrap; overflow: hidden; From 60adb6f37c859b4c1d65d4f002b614c1ca5bd885 Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 1 Feb 2022 07:21:34 +0100 Subject: [PATCH 23/24] translations --- loopback/locale/en.json | 1 - loopback/locale/es.json | 3 +-- modules/ticket/back/methods/ticket/componentUpdate.js | 2 +- modules/ticket/front/basic-data/step-two/index.html | 2 +- modules/ticket/front/basic-data/step-two/locale/es.yml | 2 +- 5 files changed, 4 insertions(+), 6 deletions(-) diff --git a/loopback/locale/en.json b/loopback/locale/en.json index d0f818426..7d675cb13 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -120,6 +120,5 @@ "This item is not available": "This item is not available", "Deny buy request": "Purchase request for ticket id [{{ticketId}}]({{{url}}}) has been rejected. Reason: {{observation}}", "The type of business must be filled in basic data": "The type of business must be filled in basic data", - "isWithoutNegatives": "isWithoutNegatives", "The worker has hours recorded that day": "The worker has hours recorded that day" } \ No newline at end of file diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 493b45c32..4c11611e3 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -218,6 +218,5 @@ "The worker has a marked absence that day": "El trabajador tiene marcada una ausencia ese día", "You can not modify is pay method checked": "No se puede modificar el campo método de pago validado", "Can't transfer claimed sales": "No puedes transferir lineas reclamadas", - "You don't have privileges to create pay back": "No tienes permisos para crear un abono", - "isWithoutNegatives": "isWithoutNegatives" + "You don't have privileges to create pay back": "No tienes permisos para crear un abono" } \ No newline at end of file diff --git a/modules/ticket/back/methods/ticket/componentUpdate.js b/modules/ticket/back/methods/ticket/componentUpdate.js index 083abc47d..de06212c7 100644 --- a/modules/ticket/back/methods/ticket/componentUpdate.js +++ b/modules/ticket/back/methods/ticket/componentUpdate.js @@ -175,7 +175,7 @@ module.exports = Self => { // Force to unroute ticket const hasToBeUnrouted = true; const query = 'CALL vn.ticket_componentMakeUpdate(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; - let res = await Self.rawSql(query, [ + const res = await Self.rawSql(query, [ args.id, args.clientFk, args.nickname, diff --git a/modules/ticket/front/basic-data/step-two/index.html b/modules/ticket/front/basic-data/step-two/index.html index 93012c720..092c9e746 100644 --- a/modules/ticket/front/basic-data/step-two/index.html +++ b/modules/ticket/front/basic-data/step-two/index.html @@ -77,7 +77,7 @@
diff --git a/modules/ticket/front/basic-data/step-two/locale/es.yml b/modules/ticket/front/basic-data/step-two/locale/es.yml index 1a7427d2e..e1f1e0bfc 100644 --- a/modules/ticket/front/basic-data/step-two/locale/es.yml +++ b/modules/ticket/front/basic-data/step-two/locale/es.yml @@ -6,6 +6,6 @@ The ticket has been unrouted: El ticket ha sido desenrutado Price: Precio New price: Nuevo precio Price difference: Diferencia de precio -Without create negatives: Sin crear negativos +Create without negatives: Crear sin negativos Clone this ticket with the changes and only sales availables: Clona este ticket con los cambios y solo las ventas disponibles. Movable: Movible \ No newline at end of file From 368498d7639d3650a45817eeab6761ec3d7a1d70 Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 1 Feb 2022 08:49:56 +0100 Subject: [PATCH 24/24] refactor(defaulter): array request --- e2e/paths/02-client/21_defaulter.spec.js | 2 +- modules/client/front/defaulter/index.js | 13 ++++++++----- modules/client/front/defaulter/index.spec.js | 14 ++++++++++++-- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/e2e/paths/02-client/21_defaulter.spec.js b/e2e/paths/02-client/21_defaulter.spec.js index 1d5fc8efb..89b5c5761 100644 --- a/e2e/paths/02-client/21_defaulter.spec.js +++ b/e2e/paths/02-client/21_defaulter.spec.js @@ -64,8 +64,8 @@ describe('Client defaulter path', () => { }); it('should first observation changed', async() => { - const result = await page.waitToGetProperty(selectors.clientDefaulter.firstObservation, 'value'); const message = await page.waitForSnackbar(); + const result = await page.waitToGetProperty(selectors.clientDefaulter.firstObservation, 'value'); expect(message.text).toContain('Observation saved!'); expect(result).toContain('My new observation'); diff --git a/modules/client/front/defaulter/index.js b/modules/client/front/defaulter/index.js index 0cb029992..76afeb160 100644 --- a/modules/client/front/defaulter/index.js +++ b/modules/client/front/defaulter/index.js @@ -36,15 +36,18 @@ export default class Controller extends Section { if (!this.defaulter.observation) throw new UserError(`The message can't be empty`); + const params = []; for (let defaulter of this.checked) { - const params = { + params.push({ text: this.defaulter.observation, clientFk: defaulter.clientFk - }; - this.$http.post(`ClientObservations`, params); + }); } - this.vnApp.showMessage(this.$t('Observation saved!')); - this.$state.reload(); + + this.$http.post(`ClientObservations`, params) .then(() => { + this.vnApp.showMessage(this.$t('Observation saved!')); + this.$state.reload(); + }); } exprBuilder(param, value) { diff --git a/modules/client/front/defaulter/index.spec.js b/modules/client/front/defaulter/index.spec.js index e0e758906..6428952ec 100644 --- a/modules/client/front/defaulter/index.spec.js +++ b/modules/client/front/defaulter/index.spec.js @@ -4,10 +4,12 @@ import crudModel from 'core/mocks/crud-model'; describe('client defaulter', () => { describe('Component vnClientDefaulterIndex', () => { let controller; + let $httpBackend; beforeEach(ngModule('client')); - beforeEach(inject($componentController => { + beforeEach(inject(($componentController, _$httpBackend_) => { + $httpBackend = _$httpBackend_; const $element = angular.element(''); controller = $componentController('vnClientDefaulterIndex', {$element}); controller.$.model = crudModel; @@ -63,9 +65,17 @@ describe('client defaulter', () => { }); it('should return saved message', () => { - controller.defaulter = {observation: 'asdasd'}; + const data = controller.$.model.data; + data[1].checked = true; + controller.defaulter = {observation: 'My new observation'}; + + const params = [{text: controller.defaulter.observation, clientFk: data[1].clientFk}]; + jest.spyOn(controller.vnApp, 'showMessage'); + $httpBackend.expect('POST', `ClientObservations`, params).respond(200, params); + controller.onResponse(); + $httpBackend.flush(); expect(controller.vnApp.showMessage).toHaveBeenCalledWith('Observation saved!'); });