From 1adfa33a9a893b8ed17b3a815290598249e3ce0b Mon Sep 17 00:00:00 2001 From: carlossa Date: Fri, 6 Oct 2023 14:52:30 +0200 Subject: [PATCH 01/19] hotfix length sales --- modules/ticket/back/methods/sale/refund.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/modules/ticket/back/methods/sale/refund.js b/modules/ticket/back/methods/sale/refund.js index 67172f3ac..03302550e 100644 --- a/modules/ticket/back/methods/sale/refund.js +++ b/modules/ticket/back/methods/sale/refund.js @@ -55,7 +55,7 @@ module.exports = Self => { const refoundZoneId = refundAgencyMode.zones()[0].id; - if (salesIds) { + if (salesIds.length) { const salesFilter = { where: {id: {inq: salesIds}}, include: { @@ -91,16 +91,14 @@ module.exports = Self => { await models.SaleComponent.create(components, myOptions); } } - if (!refundTicket) { const servicesFilter = { where: {id: {inq: servicesIds}} }; const services = await models.TicketService.find(servicesFilter, myOptions); - const ticketsIds = [...new Set(services.map(service => service.ticketFk))]; + const firstTicketId = services[0].ticketFk; const now = Date.vnNew(); - const [firstTicketId] = ticketsIds; // eslint-disable-next-line max-len refundTicket = await createTicketRefund(firstTicketId, now, refundAgencyMode, refoundZoneId, withWarehouse, myOptions); From 03afea3b8e633ed668a7d38bb299054bf4f056f1 Mon Sep 17 00:00:00 2001 From: guillermo Date: Tue, 10 Oct 2023 10:51:02 +0200 Subject: [PATCH 02/19] refs #6199 Added minQuantity in item --- modules/item/back/models/item.json | 3 +++ modules/item/front/basic-data/index.html | 9 +++++++++ modules/item/front/summary/index.html | 3 +++ 3 files changed, 15 insertions(+) diff --git a/modules/item/back/models/item.json b/modules/item/back/models/item.json index e99dcd996..8a635ea7e 100644 --- a/modules/item/back/models/item.json +++ b/modules/item/back/models/item.json @@ -131,6 +131,9 @@ "nonRecycledPlastic": { "type": "number" }, + "minQuantity": { + "type": "number" + }, "packingOut": { "type": "number" }, diff --git a/modules/item/front/basic-data/index.html b/modules/item/front/basic-data/index.html index fba4d679c..d3b30a7c2 100644 --- a/modules/item/front/basic-data/index.html +++ b/modules/item/front/basic-data/index.html @@ -183,6 +183,15 @@ rule> + + + + + +

From d2ce920f13ea8aa2e7857de2951b43a38654fad3 Mon Sep 17 00:00:00 2001 From: guillermo Date: Tue, 10 Oct 2023 13:49:11 +0200 Subject: [PATCH 03/19] refs #6199 Added minQuantity in catalog and more --- modules/item/front/basic-data/index.html | 2 +- modules/item/front/basic-data/locale/es.yml | 3 +- modules/item/front/summary/locale/es.yml | 1 + .../order/back/methods/order/catalogFilter.js | 43 ++++++++++--------- modules/order/front/catalog-view/index.html | 13 ++++++ .../order/front/catalog-view/locale/es.yml | 1 + 6 files changed, 40 insertions(+), 23 deletions(-) diff --git a/modules/item/front/basic-data/index.html b/modules/item/front/basic-data/index.html index d3b30a7c2..f412626bf 100644 --- a/modules/item/front/basic-data/index.html +++ b/modules/item/front/basic-data/index.html @@ -185,7 +185,7 @@ { )); stmt = new ParameterizedSQL(` - SELECT - i.id, - i.name, - i.subName, - i.image, - i.tag5, - i.value5, - i.tag6, - i.value6, - i.tag7, - i.value7, - i.tag8, - i.value8, - i.stars, - tci.price, - tci.available, - w.lastName AS lastName, - w.firstName, - tci.priceKg, - ink.hex + SELECT i.id, + i.name, + i.subName, + i.image, + i.tag5, + i.value5, + i.tag6, + i.value6, + i.tag7, + i.value7, + i.tag8, + i.value8, + i.stars, + tci.price, + tci.available, + w.lastName lastName, + w.firstName, + tci.priceKg, + ink.hex, + i.minQuantity FROM tmp.ticketCalculateItem tci JOIN vn.item i ON i.id = tci.itemFk JOIN vn.itemType it ON it.id = i.typeFk JOIN vn.worker w on w.id = it.workerFk - LEFT JOIN vn.ink ON ink.id = i.inkFk`); + LEFT JOIN vn.ink ON ink.id = i.inkFk + `); // Apply order by tag if (orderBy.isTag) { diff --git a/modules/order/front/catalog-view/index.html b/modules/order/front/catalog-view/index.html index fca728855..9333e923b 100644 --- a/modules/order/front/catalog-view/index.html +++ b/modules/order/front/catalog-view/index.html @@ -37,6 +37,19 @@ value="{{::item.value7}}"> +
+ + + {{::item.minQuantity}} +
diff --git a/modules/order/front/catalog-view/locale/es.yml b/modules/order/front/catalog-view/locale/es.yml index 82fe5e9e8..8fb3c7896 100644 --- a/modules/order/front/catalog-view/locale/es.yml +++ b/modules/order/front/catalog-view/locale/es.yml @@ -1 +1,2 @@ Order created: Orden creada +Minimal quantity: Cantidad mínima \ No newline at end of file From 2b41bf7eb14744a618119e878f9ca302633e7c74 Mon Sep 17 00:00:00 2001 From: guillermo Date: Wed, 11 Oct 2023 07:39:41 +0200 Subject: [PATCH 04/19] refs #6199 Requested changes --- modules/item/front/basic-data/locale/es.yml | 2 +- modules/order/back/methods/order/catalogFilter.js | 2 +- modules/order/front/catalog-view/index.html | 12 +++++------- modules/order/front/catalog-view/style.scss | 10 ++++++++++ 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/modules/item/front/basic-data/locale/es.yml b/modules/item/front/basic-data/locale/es.yml index 51cbdabd9..fc490e448 100644 --- a/modules/item/front/basic-data/locale/es.yml +++ b/modules/item/front/basic-data/locale/es.yml @@ -15,5 +15,5 @@ Generic: Genérico This item does need a photo: Este artículo necesita una foto Do photo: Hacer foto Recycled Plastic: Plástico reciclado -Non recycled plastic: Plástico no +Non recycled plastic: Plástico no reciclado Minimum sales quantity: Cantidad mínima de venta diff --git a/modules/order/back/methods/order/catalogFilter.js b/modules/order/back/methods/order/catalogFilter.js index dca82322a..722f3e096 100644 --- a/modules/order/back/methods/order/catalogFilter.js +++ b/modules/order/back/methods/order/catalogFilter.js @@ -115,7 +115,7 @@ module.exports = Self => { i.stars, tci.price, tci.available, - w.lastName lastName, + w.lastName, w.firstName, tci.priceKg, ink.hex, diff --git a/modules/order/front/catalog-view/index.html b/modules/order/front/catalog-view/index.html index 9333e923b..c9375aab5 100644 --- a/modules/order/front/catalog-view/index.html +++ b/modules/order/front/catalog-view/index.html @@ -37,16 +37,14 @@ value="{{::item.value7}}"> -
+
+ ng-class="'min-quantity-icon'"> {{::item.minQuantity}}
diff --git a/modules/order/front/catalog-view/style.scss b/modules/order/front/catalog-view/style.scss index 87f70cde5..8288855a4 100644 --- a/modules/order/front/catalog-view/style.scss +++ b/modules/order/front/catalog-view/style.scss @@ -44,4 +44,14 @@ vn-order-catalog { height: 30px; position: relative; } + .text-caption-reduced { + display: flex; + align-items: center; + justify-content: flex-end; + color: tomato; + } + .min-quantity-icon { + font-size: 18px; + margin-right: 3px; + } } \ No newline at end of file From d41233efaf9da5fb7b8065085ede26fe38c4ecee Mon Sep 17 00:00:00 2001 From: guillermo Date: Wed, 11 Oct 2023 07:59:05 +0200 Subject: [PATCH 05/19] refs #6199 Requested change, name of color --- modules/order/front/catalog-view/style.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/order/front/catalog-view/style.scss b/modules/order/front/catalog-view/style.scss index 8288855a4..abfde3589 100644 --- a/modules/order/front/catalog-view/style.scss +++ b/modules/order/front/catalog-view/style.scss @@ -48,7 +48,7 @@ vn-order-catalog { display: flex; align-items: center; justify-content: flex-end; - color: tomato; + color: $color-alert; } .min-quantity-icon { font-size: 18px; From 6b1dded2225645da60e45cda1a8be567af8cb4a1 Mon Sep 17 00:00:00 2001 From: guillermo Date: Wed, 11 Oct 2023 08:28:52 +0200 Subject: [PATCH 06/19] refs #6199 Requested change, position of input --- modules/item/front/basic-data/index.html | 66 ++++++++++++------------ 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/modules/item/front/basic-data/index.html b/modules/item/front/basic-data/index.html index f412626bf..426c17800 100644 --- a/modules/item/front/basic-data/index.html +++ b/modules/item/front/basic-data/index.html @@ -33,6 +33,8 @@ rule info="Full name calculates based on tags 1-3. Is not recommended to change it manually"> + + + + +
{{::name}}
+
+ #{{::id}} +
+
+ + + + +
- - -
{{::name}}
-
- #{{::id}} -
-
- - - - -
+ +
- - - - Date: Wed, 11 Oct 2023 12:04:12 +0200 Subject: [PATCH 07/19] =?UTF-8?q?refs=20#6293=20traducci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/ticket/front/index/locale/es.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/ticket/front/index/locale/es.yml b/modules/ticket/front/index/locale/es.yml index afa3d654e..89828d4d9 100644 --- a/modules/ticket/front/index/locale/es.yml +++ b/modules/ticket/front/index/locale/es.yml @@ -18,3 +18,4 @@ Multiple invoice: Factura múltiple Make invoice...: Crear factura... Invoice selected tickets: Facturar tickets seleccionados Are you sure to invoice tickets: ¿Seguro que quieres facturar {{ticketsAmount}} tickets? +Rounding: Redondeo From 7367656a354d7e1e53305782d62b59f1b2c861f2 Mon Sep 17 00:00:00 2001 From: guillermo Date: Fri, 13 Oct 2023 09:02:40 +0200 Subject: [PATCH 08/19] refs #6199 Requested changes --- modules/order/front/catalog-view/index.html | 21 +++++++++++---------- modules/order/front/catalog-view/style.scss | 6 +----- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/modules/order/front/catalog-view/index.html b/modules/order/front/catalog-view/index.html index c9375aab5..907882a06 100644 --- a/modules/order/front/catalog-view/index.html +++ b/modules/order/front/catalog-view/index.html @@ -37,17 +37,18 @@ value="{{::item.value7}}">
-
- - - {{::item.minQuantity}} -
+ ng-if="::item.minQuantity"> +
+ + + {{::item.minQuantity}} +
+
diff --git a/modules/order/front/catalog-view/style.scss b/modules/order/front/catalog-view/style.scss index abfde3589..a7a2a815c 100644 --- a/modules/order/front/catalog-view/style.scss +++ b/modules/order/front/catalog-view/style.scss @@ -45,13 +45,9 @@ vn-order-catalog { position: relative; } .text-caption-reduced { + color: $color-alert; display: flex; align-items: center; justify-content: flex-end; - color: $color-alert; - } - .min-quantity-icon { - font-size: 18px; - margin-right: 3px; } } \ No newline at end of file From fa901329347b91d04c5c430aae6fdbe4eb424c2a Mon Sep 17 00:00:00 2001 From: alexm Date: Fri, 13 Oct 2023 10:23:48 +0200 Subject: [PATCH 09/19] refs #6199 fix(orderCatalogView): html and css --- modules/order/front/catalog-view/index.html | 41 +++++++++++---------- modules/order/front/catalog-view/style.scss | 7 +--- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/modules/order/front/catalog-view/index.html b/modules/order/front/catalog-view/index.html index 907882a06..5d60211ed 100644 --- a/modules/order/front/catalog-view/index.html +++ b/modules/order/front/catalog-view/index.html @@ -8,12 +8,12 @@
- @@ -37,25 +37,28 @@ value="{{::item.value7}}">
- -
- - - {{::item.minQuantity}} -
+ + + + + + + + + + {{::item.minQuantity}} + - - @@ -81,4 +84,4 @@ - \ No newline at end of file + diff --git a/modules/order/front/catalog-view/style.scss b/modules/order/front/catalog-view/style.scss index a7a2a815c..1e48745ca 100644 --- a/modules/order/front/catalog-view/style.scss +++ b/modules/order/front/catalog-view/style.scss @@ -44,10 +44,7 @@ vn-order-catalog { height: 30px; position: relative; } - .text-caption-reduced { + .alert { color: $color-alert; - display: flex; - align-items: center; - justify-content: flex-end; } -} \ No newline at end of file +} From 9c0334619d628ff419780642c77b335231f1c9e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Andr=C3=A9s?= Date: Fri, 13 Oct 2023 11:56:50 +0200 Subject: [PATCH 10/19] refs #6199 --- loopback/locale/es.json | 3 ++- modules/item/back/models/item.json | 4 ++++ modules/ticket/back/methods/sale/updateQuantity.js | 9 +++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 8c50cd9d8..d34c97d21 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -319,5 +319,6 @@ "The response is not a PDF": "La respuesta no es un PDF", "Ticket without Route": "Ticket sin ruta", "Booking completed": "Reserva completada", - "The ticket is in preparation": "El ticket [{{ticketId}}]({{{ticketUrl}}}) del comercial {{salesPersonId}} está en preparación" + "The ticket is in preparation": "El ticket [{{ticketId}}]({{{ticketUrl}}}) del comercial {{salesPersonId}} está en preparación", + "The amount cannot be less than the minimum": "La cantidad no puede ser menor que la cantidad mímina" } diff --git a/modules/item/back/models/item.json b/modules/item/back/models/item.json index e99dcd996..28f9648fb 100644 --- a/modules/item/back/models/item.json +++ b/modules/item/back/models/item.json @@ -154,6 +154,10 @@ "mysql":{ "columnName": "doPhoto" } + }, + "minQuantity": { + "type": "number", + "description": "Min quantity" } }, "relations": { diff --git a/modules/ticket/back/methods/sale/updateQuantity.js b/modules/ticket/back/methods/sale/updateQuantity.js index edbc34e42..375928506 100644 --- a/modules/ticket/back/methods/sale/updateQuantity.js +++ b/modules/ticket/back/methods/sale/updateQuantity.js @@ -72,6 +72,15 @@ module.exports = Self => { where: {refundTicketFk: sale.ticketFk}, fields: ['id']} , myOptions); + + const item = await models.Item.findOne({ + where: {id: sale.itemFk}, + fields: ['minQuantity']} + , myOptions); + + if (newQuantity < item.minQuantity && !ticketRefund) + throw new UserError('The amount cannot be less than the minimum'); + if (newQuantity < 0 && !ticketRefund) throw new UserError('You can only add negative amounts in refund tickets'); From e1c1d1a556e62ebcf94e9e62026e45e772697910 Mon Sep 17 00:00:00 2001 From: guillermo Date: Fri, 13 Oct 2023 12:33:39 +0200 Subject: [PATCH 11/19] refs #6199 Fixed tests --- db/dump/structure.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/db/dump/structure.sql b/db/dump/structure.sql index 08df0541c..b242821fc 100644 --- a/db/dump/structure.sql +++ b/db/dump/structure.sql @@ -30434,6 +30434,7 @@ CREATE TABLE `item` ( `editorFk` int(10) unsigned DEFAULT NULL, `recycledPlastic` int(11) DEFAULT NULL, `nonRecycledPlastic` int(11) DEFAULT NULL, + `minQuantity` int(10) unsigned DEFAULT NULL COMMENT 'Cantidad mínima para una línea de venta', PRIMARY KEY (`id`), UNIQUE KEY `item_supplyResponseFk_idx` (`supplyResponseFk`), KEY `Color` (`inkFk`), From 03687cb48279acf4777b6554ba59bc4cd09838f7 Mon Sep 17 00:00:00 2001 From: alexm Date: Fri, 13 Oct 2023 14:56:56 +0200 Subject: [PATCH 12/19] hotFix: delete getCurrentWorkerMana --- modules/ticket/front/sale/index.html | 2 +- modules/ticket/front/sale/index.js | 8 ------ modules/ticket/front/sale/index.spec.js | 2 -- .../worker-mana/getCurrentWorkerMana.js | 26 ------------------- .../specs/getCurrentWorkerMana.spec.js | 15 ----------- modules/worker/back/models/worker-mana.js | 3 --- 6 files changed, 1 insertion(+), 55 deletions(-) delete mode 100644 modules/worker/back/methods/worker-mana/getCurrentWorkerMana.js delete mode 100644 modules/worker/back/methods/worker-mana/specs/getCurrentWorkerMana.spec.js delete mode 100644 modules/worker/back/models/worker-mana.js diff --git a/modules/ticket/front/sale/index.html b/modules/ticket/front/sale/index.html index be9e81964..b8e64cf28 100644 --- a/modules/ticket/front/sale/index.html +++ b/modules/ticket/front/sale/index.html @@ -318,7 +318,7 @@ clear-disabled="true" suffix="%"> - + { - this.currentWorkerMana = res.data; - }); } getUsesMana() { diff --git a/modules/ticket/front/sale/index.spec.js b/modules/ticket/front/sale/index.spec.js index 9da8e6e7c..b36e78893 100644 --- a/modules/ticket/front/sale/index.spec.js +++ b/modules/ticket/front/sale/index.spec.js @@ -120,12 +120,10 @@ describe('Ticket', () => { const expectedAmount = 250; $httpBackend.expect('GET', 'Tickets/1/getSalesPersonMana').respond(200, expectedAmount); $httpBackend.expect('GET', 'Sales/usesMana').respond(200); - $httpBackend.expect('GET', 'WorkerManas/getCurrentWorkerMana').respond(200, expectedAmount); controller.getMana(); $httpBackend.flush(); expect(controller.edit.mana).toEqual(expectedAmount); - expect(controller.currentWorkerMana).toEqual(expectedAmount); }); }); diff --git a/modules/worker/back/methods/worker-mana/getCurrentWorkerMana.js b/modules/worker/back/methods/worker-mana/getCurrentWorkerMana.js deleted file mode 100644 index fa34af475..000000000 --- a/modules/worker/back/methods/worker-mana/getCurrentWorkerMana.js +++ /dev/null @@ -1,26 +0,0 @@ -module.exports = Self => { - Self.remoteMethodCtx('getCurrentWorkerMana', { - description: 'Returns the mana of the logged worker', - accessType: 'READ', - accepts: [], - returns: { - type: 'number', - root: true - }, - http: { - path: `/getCurrentWorkerMana`, - verb: 'GET' - } - }); - - Self.getCurrentWorkerMana = async ctx => { - let userId = ctx.req.accessToken.userId; - - let workerMana = await Self.app.models.WorkerMana.findOne({ - where: {workerFk: userId}, - fields: 'amount' - }); - - return workerMana ? workerMana.amount : 0; - }; -}; diff --git a/modules/worker/back/methods/worker-mana/specs/getCurrentWorkerMana.spec.js b/modules/worker/back/methods/worker-mana/specs/getCurrentWorkerMana.spec.js deleted file mode 100644 index 8d626e720..000000000 --- a/modules/worker/back/methods/worker-mana/specs/getCurrentWorkerMana.spec.js +++ /dev/null @@ -1,15 +0,0 @@ -const app = require('vn-loopback/server/server'); - -describe('workerMana getCurrentWorkerMana()', () => { - it('should get the mana of the logged worker', async() => { - let mana = await app.models.WorkerMana.getCurrentWorkerMana({req: {accessToken: {userId: 18}}}); - - expect(mana).toEqual(124); - }); - - it('should return 0 if the user doesnt uses mana', async() => { - let mana = await app.models.WorkerMana.getCurrentWorkerMana({req: {accessToken: {userId: 9}}}); - - expect(mana).toEqual(0); - }); -}); diff --git a/modules/worker/back/models/worker-mana.js b/modules/worker/back/models/worker-mana.js deleted file mode 100644 index 99a0f7694..000000000 --- a/modules/worker/back/models/worker-mana.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = Self => { - require('../methods/worker-mana/getCurrentWorkerMana')(Self); -}; From ab1cc34015686624bcb53a8b7eac620191cd52ca Mon Sep 17 00:00:00 2001 From: alexm Date: Fri, 13 Oct 2023 15:14:48 +0200 Subject: [PATCH 13/19] refs #6199 feat(sale): best quantity restriction --- .../back/methods/sale/updateQuantity.js | 22 +--------- modules/ticket/back/models/sale.js | 41 +++++++++++++++++++ 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/modules/ticket/back/methods/sale/updateQuantity.js b/modules/ticket/back/methods/sale/updateQuantity.js index 375928506..ce7db5ffd 100644 --- a/modules/ticket/back/methods/sale/updateQuantity.js +++ b/modules/ticket/back/methods/sale/updateQuantity.js @@ -1,4 +1,4 @@ -let UserError = require('vn-loopback/util/user-error'); +const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { Self.remoteMethodCtx('updateQuantity', { @@ -64,26 +64,6 @@ module.exports = Self => { const sale = await models.Sale.findById(id, filter, myOptions); - const isRoleAdvanced = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*'); - if (newQuantity > sale.quantity && !isRoleAdvanced) - throw new UserError('The new quantity should be smaller than the old one'); - - const ticketRefund = await models.TicketRefund.findOne({ - where: {refundTicketFk: sale.ticketFk}, - fields: ['id']} - , myOptions); - - const item = await models.Item.findOne({ - where: {id: sale.itemFk}, - fields: ['minQuantity']} - , myOptions); - - if (newQuantity < item.minQuantity && !ticketRefund) - throw new UserError('The amount cannot be less than the minimum'); - - if (newQuantity < 0 && !ticketRefund) - throw new UserError('You can only add negative amounts in refund tickets'); - const oldQuantity = sale.quantity; const result = await sale.updateAttributes({quantity: newQuantity}, myOptions); diff --git a/modules/ticket/back/models/sale.js b/modules/ticket/back/models/sale.js index ae247fc24..556f35d60 100644 --- a/modules/ticket/back/models/sale.js +++ b/modules/ticket/back/models/sale.js @@ -1,3 +1,5 @@ +const UserError = require('vn-loopback/util/user-error'); + module.exports = Self => { require('../methods/sale/getClaimableFromTicket')(Self); require('../methods/sale/reserve')(Self); @@ -13,4 +15,43 @@ module.exports = Self => { Self.validatesPresenceOf('concept', { message: `Concept cannot be blank` }); + + Self.observe('before save', async ctx => { + const models = Self.app.models; + const changes = ctx.data || ctx.instance; + const instance = ctx.currentInstance; + console.log(ctx?.req?.accessToken, instance, changes); + const newQuantity = changes?.quantity; + if (newQuantity === null) return; + + const canEditQuantity = await models.ACL.checkAccessAcl(ctx, 'Sale', 'canForceQuantity', 'WRITE'); + if (canEditQuantity) return; + + const ticketId = changes?.ticketFk || instance?.ticketFk; + const itemId = changes?.itemFk || instance?.itemFk; + + const ticketRefund = await models.TicketRefund.findOne({ + where: {refundTicketFk: ticketId}, + fields: ['id']} + , ctx.options); + + const item = await models.Item.findOne({ + where: {id: itemId}, + fields: ['minQuantity']} + , ctx.options); + + if (newQuantity < item.minQuantity && !ticketRefund) + throw new UserError('The amount cannot be less than the minimum'); + + if (newQuantity < 0 && !ticketRefund) + throw new UserError('You can only add negative amounts in refund tickets'); + + const oldQuantity = instance?.quantity; + if (oldQuantity === null) return; + + const isRoleAdvanced = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*'); + if (newQuantity > oldQuantity && !isRoleAdvanced) + throw new UserError('The new quantity should be smaller than the old one'); + }); }; + From b769fa9bcf5ad8c99d2365742c78918783758c0d Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 16 Oct 2023 10:10:57 +0200 Subject: [PATCH 14/19] refs #6199 fix(sale_updateQuantity): if clientType is loses skip test: fix updateQuantity activeCtx and add test for minQuantity --- loopback/locale/en.json | 5 +- .../claim/specs/regularizeClaim.spec.js | 2 +- .../methods/sale/specs/updateQuantity.spec.js | 62 ++++++++++++++----- .../back/methods/sale/updateQuantity.js | 1 - modules/ticket/back/models/sale.js | 35 +++++++++-- 5 files changed, 81 insertions(+), 24 deletions(-) diff --git a/loopback/locale/en.json b/loopback/locale/en.json index 645a874e8..f61226e9e 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -189,5 +189,6 @@ "The sales do not exists": "The sales do not exists", "Ticket without Route": "Ticket without route", "Booking completed": "Booking complete", - "The ticket is in preparation": "The ticket [{{ticketId}}]({{{ticketUrl}}}) of the sales person {{salesPersonId}} is in preparation" -} + "The ticket is in preparation": "The ticket [{{ticketId}}]({{{ticketUrl}}}) of the sales person {{salesPersonId}} is in preparation", + "You can only add negative amounts in refund tickets": "You can only add negative amounts in refund tickets" +} \ No newline at end of file diff --git a/modules/claim/back/methods/claim/specs/regularizeClaim.spec.js b/modules/claim/back/methods/claim/specs/regularizeClaim.spec.js index 276843c32..95c356374 100644 --- a/modules/claim/back/methods/claim/specs/regularizeClaim.spec.js +++ b/modules/claim/back/methods/claim/specs/regularizeClaim.spec.js @@ -64,7 +64,7 @@ describe('claim regularizeClaim()', () => { claimEnds = await importTicket(ticketId, claimId, userId, options); - for (claimEnd of claimEnds) + for (const claimEnd of claimEnds) await claimEnd.updateAttributes({claimDestinationFk: trashDestination}, options); let claimBefore = await models.Claim.findById(claimId, null, options); diff --git a/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js b/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js index 8064ea30b..bb58780e3 100644 --- a/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js +++ b/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js @@ -2,20 +2,6 @@ const models = require('vn-loopback/server/server').models; const LoopBackContext = require('loopback-context'); describe('sale updateQuantity()', () => { - beforeAll(async() => { - const activeCtx = { - accessToken: {userId: 9}, - http: { - req: { - headers: {origin: 'http://localhost'} - } - } - }; - spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ - active: activeCtx - }); - }); - const ctx = { req: { accessToken: {userId: 9}, @@ -23,6 +9,18 @@ describe('sale updateQuantity()', () => { __: () => {} } }; + function getActiveCtx(userId) { + return { + active: { + accessToken: {userId}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + } + }; + } it('should throw an error if the quantity is greater than it should be', async() => { const ctx = { @@ -32,6 +30,8 @@ describe('sale updateQuantity()', () => { __: () => {} } }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(1)); + const tx = await models.Sale.beginTransaction({}); let error; @@ -50,6 +50,8 @@ describe('sale updateQuantity()', () => { }); it('should add quantity if the quantity is greater than it should be and is role advanced', async() => { + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(9)); + const tx = await models.Sale.beginTransaction({}); const saleId = 17; const buyerId = 35; @@ -87,6 +89,8 @@ describe('sale updateQuantity()', () => { }); it('should update the quantity of a given sale current line', async() => { + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(9)); + const tx = await models.Sale.beginTransaction({}); const saleId = 25; const newQuantity = 4; @@ -119,6 +123,8 @@ describe('sale updateQuantity()', () => { __: () => {} } }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(1)); + const saleId = 17; const newQuantity = -10; @@ -140,6 +146,8 @@ describe('sale updateQuantity()', () => { }); it('should update a negative quantity when is a ticket refund', async() => { + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(9)); + const tx = await models.Sale.beginTransaction({}); const saleId = 13; const newQuantity = -10; @@ -159,4 +167,30 @@ describe('sale updateQuantity()', () => { throw e; } }); + + it('should throw an error if the quantity is less than the minimum quantity of the item', async() => { + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(9)); + + const tx = await models.Sale.beginTransaction({}); + const itemId = 2; + const saleId = 17; + const newQuantity = 29; + + let error; + try { + const options = {transaction: tx}; + + const item = await models.Item.findById(itemId, null, options); + await item.updateAttribute('minQuantity', 30, options); + + await models.Sale.updateQuantity(ctx, saleId, newQuantity, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error).toEqual(new Error('The amount cannot be less than the minimum')); + }); }); diff --git a/modules/ticket/back/methods/sale/updateQuantity.js b/modules/ticket/back/methods/sale/updateQuantity.js index ce7db5ffd..55106f053 100644 --- a/modules/ticket/back/methods/sale/updateQuantity.js +++ b/modules/ticket/back/methods/sale/updateQuantity.js @@ -1,4 +1,3 @@ -const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { Self.remoteMethodCtx('updateQuantity', { diff --git a/modules/ticket/back/models/sale.js b/modules/ticket/back/models/sale.js index 556f35d60..bacc5ef44 100644 --- a/modules/ticket/back/models/sale.js +++ b/modules/ticket/back/models/sale.js @@ -1,4 +1,5 @@ const UserError = require('vn-loopback/util/user-error'); +const LoopBackContext = require('loopback-context'); module.exports = Self => { require('../methods/sale/getClaimableFromTicket')(Self); @@ -20,21 +21,46 @@ module.exports = Self => { const models = Self.app.models; const changes = ctx.data || ctx.instance; const instance = ctx.currentInstance; - console.log(ctx?.req?.accessToken, instance, changes); - const newQuantity = changes?.quantity; - if (newQuantity === null) return; + const newQuantity = changes?.quantity; + if (newQuantity == null) return; + + const loopBackContext = LoopBackContext.getCurrentContext(); + ctx.req = loopBackContext.active; const canEditQuantity = await models.ACL.checkAccessAcl(ctx, 'Sale', 'canForceQuantity', 'WRITE'); if (canEditQuantity) return; const ticketId = changes?.ticketFk || instance?.ticketFk; const itemId = changes?.itemFk || instance?.itemFk; + const ticket = await models.Ticket.findById( + ticketId, + { + fields: ['id', 'clientFk'], + include: { + relation: 'client', + scope: { + fields: ['id', 'clientTypeFk'], + include: { + relation: 'type', + scope: { + fields: ['code', 'description'] + } + } + } + } + }, + ctx.options); + if (ticket.client().type().code === 'loses') return; + const ticketRefund = await models.TicketRefund.findOne({ where: {refundTicketFk: ticketId}, fields: ['id']} , ctx.options); + if (newQuantity < 0 && !ticketRefund) + throw new UserError('You can only add negative amounts in refund tickets'); + const item = await models.Item.findOne({ where: {id: itemId}, fields: ['minQuantity']} @@ -43,9 +69,6 @@ module.exports = Self => { if (newQuantity < item.minQuantity && !ticketRefund) throw new UserError('The amount cannot be less than the minimum'); - if (newQuantity < 0 && !ticketRefund) - throw new UserError('You can only add negative amounts in refund tickets'); - const oldQuantity = instance?.quantity; if (oldQuantity === null) return; From f79e71161744cce480b88b1e07ec3cd1946ebe17 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 16 Oct 2023 10:19:33 +0200 Subject: [PATCH 15/19] refs #6199 test: updateQuantity refactor --- .../ticket/back/methods/sale/specs/updateQuantity.spec.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js b/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js index bb58780e3..6bf0a0d7e 100644 --- a/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js +++ b/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js @@ -174,14 +174,15 @@ describe('sale updateQuantity()', () => { const tx = await models.Sale.beginTransaction({}); const itemId = 2; const saleId = 17; - const newQuantity = 29; + const minQuantity = 30; + const newQuantity = minQuantity - 1; let error; try { const options = {transaction: tx}; const item = await models.Item.findById(itemId, null, options); - await item.updateAttribute('minQuantity', 30, options); + await item.updateAttribute('minQuantity', minQuantity, options); await models.Sale.updateQuantity(ctx, saleId, newQuantity, options); From 9e39e96cf4c43cf6e3810e2e85771947103bd94a Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 16 Oct 2023 15:22:33 +0200 Subject: [PATCH 16/19] hotFix: workerTimeControl --- .../methods/worker-time-control/sendMail.js | 64 ++++++++----------- 1 file changed, 27 insertions(+), 37 deletions(-) diff --git a/modules/worker/back/methods/worker-time-control/sendMail.js b/modules/worker/back/methods/worker-time-control/sendMail.js index 2c5143612..6f67bbea3 100644 --- a/modules/worker/back/methods/worker-time-control/sendMail.js +++ b/modules/worker/back/methods/worker-time-control/sendMail.js @@ -66,46 +66,36 @@ module.exports = Self => { stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.timeControlCalculate'); stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.timeBusinessCalculate'); + const destroyAllWhere = { + timed: {between: [started, ended]}, + isSendMail: true + }; + const updateAllWhere = { + year: args.year, + week: args.week + }; + + const tmpUserSQL = ` + CREATE OR REPLACE TEMPORARY TABLE tmp.user + SELECT id as userFk + FROM vn.worker`; + let tmpUser = new ParameterizedSQL(tmpUserSQL); + if (args.workerId) { - await models.WorkerTimeControl.destroyAll({ - userFk: args.workerId, - timed: {between: [started, ended]}, - isSendMail: true - }, myOptions); - - const where = { - workerFk: args.workerId, - year: args.year, - week: args.week - }; - await models.WorkerTimeControlMail.updateAll(where, { - updated: Date.vnNew(), state: 'SENDED' - }, myOptions); - - stmt = new ParameterizedSQL('DROP TEMPORARY TABLE IF EXISTS tmp.`user`'); - stmts.push(stmt); - stmt = new ParameterizedSQL('CREATE TEMPORARY TABLE tmp.`user` SELECT id userFk FROM account.user WHERE id = ?', [args.workerId]); - stmts.push(stmt); - } else { - await models.WorkerTimeControl.destroyAll({ - timed: {between: [started, ended]}, - isSendMail: true - }, myOptions); - - const where = { - year: args.year, - week: args.week - }; - await models.WorkerTimeControlMail.updateAll(where, { - updated: Date.vnNew(), state: 'SENDED' - }, myOptions); - - stmt = new ParameterizedSQL('DROP TEMPORARY TABLE IF EXISTS tmp.`user`'); - stmts.push(stmt); - stmt = new ParameterizedSQL('CREATE TEMPORARY TABLE IF NOT EXISTS tmp.`user` SELECT id as userFk FROM vn.worker w JOIN account.`user` u ON u.id = w.id WHERE id IS NOT NULL'); - stmts.push(stmt); + destroyAllWhere.userFk = args.workerId; + updateAllWhere.workerFk = args.workerId; + tmpUser = new ParameterizedSQL(tmpUserSQL + ' WHERE id = ?', [args.workerId]); } + await models.WorkerTimeControl.destroyAll(destroyAllWhere, myOptions); + + await models.WorkerTimeControlMail.updateAll(updateAllWhere, { + updated: Date.vnNew(), + state: 'SENDED' + }, myOptions); + + stmts.push(tmpUser); + stmt = new ParameterizedSQL( `CALL vn.timeControl_calculate(?, ?) `, [started, ended]); From 093431ecdfb84f306e4a833c7b908782452130fd Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 16 Oct 2023 15:27:10 +0200 Subject: [PATCH 17/19] refs #6119 fix(sale_hook): fix quantity case --- modules/ticket/back/methods/ticket/addSale.js | 11 ----- modules/ticket/back/models/sale.js | 44 ++++++++++++------- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/modules/ticket/back/methods/ticket/addSale.js b/modules/ticket/back/methods/ticket/addSale.js index cbf884273..21fea1c81 100644 --- a/modules/ticket/back/methods/ticket/addSale.js +++ b/modules/ticket/back/methods/ticket/addSale.js @@ -63,17 +63,6 @@ module.exports = Self => { } }, myOptions); - const itemInfo = await models.Item.getVisibleAvailable( - itemId, - ticket.warehouseFk, - ticket.shipped, - myOptions - ); - - const isPackaging = item.family == 'EMB'; - if (!isPackaging && itemInfo.available < quantity) - throw new UserError(`This item is not available`); - const newSale = await models.Sale.create({ ticketFk: id, itemFk: item.id, diff --git a/modules/ticket/back/models/sale.js b/modules/ticket/back/models/sale.js index bacc5ef44..378ff3490 100644 --- a/modules/ticket/back/models/sale.js +++ b/modules/ticket/back/models/sale.js @@ -27,8 +27,7 @@ module.exports = Self => { const loopBackContext = LoopBackContext.getCurrentContext(); ctx.req = loopBackContext.active; - const canEditQuantity = await models.ACL.checkAccessAcl(ctx, 'Sale', 'canForceQuantity', 'WRITE'); - if (canEditQuantity) return; + if (await models.ACL.checkAccessAcl(ctx, 'Sale', 'canForceQuantity', 'WRITE')) return; const ticketId = changes?.ticketFk || instance?.ticketFk; const itemId = changes?.itemFk || instance?.itemFk; @@ -36,7 +35,7 @@ module.exports = Self => { const ticket = await models.Ticket.findById( ticketId, { - fields: ['id', 'clientFk'], + fields: ['id', 'clientFk', 'warehouseFk', 'shipped'], include: { relation: 'client', scope: { @@ -51,29 +50,42 @@ module.exports = Self => { } }, ctx.options); - if (ticket.client().type().code === 'loses') return; + if (ticket?.client()?.type()?.code === 'loses') return; - const ticketRefund = await models.TicketRefund.findOne({ - where: {refundTicketFk: ticketId}, - fields: ['id']} - , ctx.options); + const isRefund = await models.TicketRefund.findOne({ + fields: ['id'], + where: {refundTicketFk: ticketId} + }, ctx.options); + if (isRefund) return; - if (newQuantity < 0 && !ticketRefund) + if (newQuantity < 0) throw new UserError('You can only add negative amounts in refund tickets'); const item = await models.Item.findOne({ + fields: ['family', 'minQuantity'], where: {id: itemId}, - fields: ['minQuantity']} - , ctx.options); + }, ctx.options); - if (newQuantity < item.minQuantity && !ticketRefund) - throw new UserError('The amount cannot be less than the minimum'); + if (item.family == 'EMB') return; + + const itemInfo = await models.Item.getVisibleAvailable( + itemId, + ticket.warehouseFk, + ticket.shipped, + ctx.options + ); const oldQuantity = instance?.quantity; - if (oldQuantity === null) return; + const quantityAdded = newQuantity - oldQuantity; + if (itemInfo.available < quantityAdded) + throw new UserError(`This item is not available`); - const isRoleAdvanced = await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*'); - if (newQuantity > oldQuantity && !isRoleAdvanced) + if (await models.ACL.checkAccessAcl(ctx, 'Ticket', 'isRoleAdvanced', '*')) return; + + if (newQuantity < item.minQuantity && itemInfo.available != newQuantity) + throw new UserError('The amount cannot be less than the minimum'); + + if (!ctx.isNewInstance && newQuantity > oldQuantity) throw new UserError('The new quantity should be smaller than the old one'); }); }; From d4770c525ef1d0e27095cbe46e64fca3c58b7c7d Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 17 Oct 2023 11:00:41 +0200 Subject: [PATCH 18/19] refs #6199 test(sale): fix test --- .../collection/spec/setSaleQuantity.spec.js | 1 + .../methods/sale/specs/updateQuantity.spec.js | 52 +++++++++++++++++-- modules/ticket/back/models/sale.js | 2 +- 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/back/methods/collection/spec/setSaleQuantity.spec.js b/back/methods/collection/spec/setSaleQuantity.spec.js index fdc1bce1a..8cd73205f 100644 --- a/back/methods/collection/spec/setSaleQuantity.spec.js +++ b/back/methods/collection/spec/setSaleQuantity.spec.js @@ -18,6 +18,7 @@ describe('setSaleQuantity()', () => { it('should change quantity sale', async() => { const tx = await models.Ticket.beginTransaction({}); + spyOn(models.Item, 'getVisibleAvailable').and.returnValue((new Promise(resolve => resolve({available: 100})))); try { const options = {transaction: tx}; diff --git a/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js b/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js index 6bf0a0d7e..0fde997fa 100644 --- a/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js +++ b/modules/ticket/back/methods/sale/specs/updateQuantity.spec.js @@ -1,3 +1,5 @@ +/* eslint max-len: ["error", { "code": 150 }]*/ + const models = require('vn-loopback/server/server').models; const LoopBackContext = require('loopback-context'); @@ -31,6 +33,7 @@ describe('sale updateQuantity()', () => { } }; spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(1)); + spyOn(models.Item, 'getVisibleAvailable').and.returnValue((new Promise(resolve => resolve({available: 100})))); const tx = await models.Sale.beginTransaction({}); @@ -38,7 +41,7 @@ describe('sale updateQuantity()', () => { try { const options = {transaction: tx}; - await models.Sale.updateQuantity(ctx, 17, 99, options); + await models.Sale.updateQuantity(ctx, 17, 31, options); await tx.rollback(); } catch (e) { @@ -50,9 +53,6 @@ describe('sale updateQuantity()', () => { }); it('should add quantity if the quantity is greater than it should be and is role advanced', async() => { - spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(9)); - - const tx = await models.Sale.beginTransaction({}); const saleId = 17; const buyerId = 35; const ctx = { @@ -62,6 +62,9 @@ describe('sale updateQuantity()', () => { __: () => {} } }; + const tx = await models.Sale.beginTransaction({}); + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(buyerId)); + spyOn(models.Item, 'getVisibleAvailable').and.returnValue((new Promise(resolve => resolve({available: 100})))); try { const options = {transaction: tx}; @@ -169,7 +172,14 @@ describe('sale updateQuantity()', () => { }); it('should throw an error if the quantity is less than the minimum quantity of the item', async() => { - spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(9)); + const ctx = { + req: { + accessToken: {userId: 1}, + headers: {origin: 'localhost:5000'}, + __: () => {} + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(1)); const tx = await models.Sale.beginTransaction({}); const itemId = 2; @@ -194,4 +204,36 @@ describe('sale updateQuantity()', () => { expect(error).toEqual(new Error('The amount cannot be less than the minimum')); }); + + it('should change quantity if has minimum quantity and new quantity is equal than item available', async() => { + const ctx = { + req: { + accessToken: {userId: 1}, + headers: {origin: 'localhost:5000'}, + __: () => {} + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue(getActiveCtx(1)); + + const tx = await models.Sale.beginTransaction({}); + const itemId = 2; + const saleId = 17; + const minQuantity = 30; + const newQuantity = minQuantity - 1; + + try { + const options = {transaction: tx}; + + const item = await models.Item.findById(itemId, null, options); + await item.updateAttribute('minQuantity', minQuantity, options); + spyOn(models.Item, 'getVisibleAvailable').and.returnValue((new Promise(resolve => resolve({available: newQuantity})))); + + await models.Sale.updateQuantity(ctx, saleId, newQuantity, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); }); diff --git a/modules/ticket/back/models/sale.js b/modules/ticket/back/models/sale.js index 378ff3490..fe6307270 100644 --- a/modules/ticket/back/models/sale.js +++ b/modules/ticket/back/models/sale.js @@ -75,7 +75,7 @@ module.exports = Self => { ctx.options ); - const oldQuantity = instance?.quantity; + const oldQuantity = instance?.quantity ?? null; const quantityAdded = newQuantity - oldQuantity; if (itemInfo.available < quantityAdded) throw new UserError(`This item is not available`); From 002329b0a1e575e07c38cdfb0b60a63482f0033e Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 18 Oct 2023 12:04:37 +0200 Subject: [PATCH 19/19] refs 6199 add quantityLessThanMin translation --- loopback/locale/es.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/loopback/locale/es.json b/loopback/locale/es.json index d34c97d21..dd3c92378 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -320,5 +320,6 @@ "Ticket without Route": "Ticket sin ruta", "Booking completed": "Reserva completada", "The ticket is in preparation": "El ticket [{{ticketId}}]({{{ticketUrl}}}) del comercial {{salesPersonId}} está en preparación", - "The amount cannot be less than the minimum": "La cantidad no puede ser menor que la cantidad mímina" + "The amount cannot be less than the minimum": "La cantidad no puede ser menor que la cantidad mímina", + "quantityLessThanMin": "La cantidad no puede ser menor que la cantidad mímina" }