From 1307d4727c9ee4284278941395556701961d1067 Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 27 Sep 2023 15:08:36 +0200 Subject: [PATCH 1/9] refs #6254 feat(collection): add getTickets --- back/methods/collection/getTickets.js | 179 ++++++++++++++++++ .../collection/spec/getTickets.spec.js | 11 ++ back/models/collection.js | 1 + .../234001/00-collectionGetTicketsACL.sql | 3 + loopback/locale/en.json | 3 +- loopback/locale/es.json | 8 +- 6 files changed, 201 insertions(+), 4 deletions(-) create mode 100644 back/methods/collection/getTickets.js create mode 100644 back/methods/collection/spec/getTickets.spec.js create mode 100644 db/changes/234001/00-collectionGetTicketsACL.sql diff --git a/back/methods/collection/getTickets.js b/back/methods/collection/getTickets.js new file mode 100644 index 0000000000..196ff0ce6e --- /dev/null +++ b/back/methods/collection/getTickets.js @@ -0,0 +1,179 @@ + +module.exports = Self => { + Self.remoteMethodCtx('getTickets', { + description: 'Make a new collection of tickets', + accessType: 'WRITE', + accepts: [{ + arg: 'paramId', + type: 'number', + description: 'The collection or ticket id', + required: true + }, { + arg: 'print', + type: 'boolean', + description: 'True if you want to print' + }], + returns: { + type: ['object'], + root: true + }, + http: { + path: `/getTickets`, + verb: 'POST' + } + }); + + Self.getTickets = async(ctx, paramId, print, options) => { + const userId = ctx.req.accessToken.userId; + const origin = ctx.req.headers.origin; + const $t = ctx.req.__; // $translate + const myOptions = {}; + + let tx; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } + myOptions.userId = userId; + + const promises = []; + try { + const [tickets] = await Self.rawSql(`CALL vn.collection_getTickets(?)`, [paramId], myOptions); + const sales = await Self.rawSql(` + SELECT + s.ticketFk, + sgd.saleGroupFk, + s.id saleFk, + s.itemFk, + i.longName, + i.size, + IFNULL(sub2.semaphore,st.semaphore) semaphore, + ic.color, + ip.productor, + o.code origin, + s.concept, + b.packing, + b.grouping, + s.isAdded, + c.workerFk, + i.packingShelve, + sm.id hasMistake, + s.originalQuantity, + s.quantity saleQuantity, + IF(p2.code IS NOT NULL, s.quantity, iss.quantity) reservedQuantity, + sh.code, + IFNULL(p2.code, p.code) parkingCode, + IFNULL(p2.pickingOrder, p.pickingOrder) pickingOrder, + iss.id itemShelvingSaleFk + FROM ticketCollection tc + LEFT JOIN collection c ON c.id = tc.collectionFk + JOIN ticket t ON t.id = tc.ticketFk + JOIN sale s ON s.ticketFk = t.id + LEFT JOIN saleGroupDetail sgd ON sgd.saleFk = s.id + LEFT JOIN saleGroup sg ON sg.id = sgd.saleGroupFk + LEFT JOIN parking p2 ON p2.id = sg.parkingFk + LEFT JOIN cache.last_buy lb ON lb.item_id = s.itemFk AND lb.warehouse_id = t.warehouseFk + LEFT JOIN buy b ON b.id = lb.buy_id + JOIN item i ON i.id = s.itemFk + LEFT JOIN itemShelvingSale iss ON iss.saleFk = s.id + LEFT JOIN itemShelving ish ON ish.id = iss.itemShelvingFk + LEFT JOIN shelving sh ON sh.code = ish.shelvingFk + LEFT JOIN parking p ON p.id = sh.parkingFk + LEFT JOIN ( + SELECT sub.saleFk, sub.isChecked, sub.stateFk, sub.originalQuantity, sub.semaphore + FROM ( + SELECT DISTINCT st.id, + st.saleFk, st.isChecked, st.stateFk, st.originalQuantity ,sta.semaphore + FROM ticketCollection tc + JOIN sale s ON s.ticketFk = tc.ticketFk + JOIN saleTracking st ON st.saleFk = s.id + JOIN state sta ON sta.id = st.stateFk + WHERE tc.collectionFk = ? + ORDER BY st.id DESC + LIMIT 10000000000000000000) sub + GROUP BY sub.saleFk, sub.stateFK + ) sub2 ON sub2.saleFk = s.id AND sub2.isChecked = 1 + LEFT JOIN state st ON st.id = sub2.stateFk + LEFT JOIN itemColor ic ON ic.itemFk = s.itemFk + LEFT JOIN itemProductor ip ON ip.itemFk = s.itemFk + LEFT JOIN origin o ON o.id = i.originFk + LEFT JOIN saleMistake sm ON sm.saleFk = s.id + WHERE tc.collectionFk = ? + GROUP BY s.id, p.code, p2.code + ORDER BY pickingOrder`, [paramId, paramId], myOptions); + + if (print) + await Self.rawSql(`CALL vn.collection_printSticker(?, ?)`, [paramId, null], myOptions); + + const collection = {collectionFk: paramId, tickets: []}; + if (tickets && tickets.length) { + for (let ticket of tickets) { + const ticketId = ticket.ticketFk; + + // SEND ROCKET + if (ticket.observaciones != '') { + for (observation of ticket.observaciones.split(' ')) { + if (['#', '@'].includes(observation.charAt(0))) { + promises.push(Self.app.models.Chat.send(ctx, observation, + $t('The ticket is in preparation', { + ticketId: ticketId, + ticketUrl: `${origin}/#!/ticket/${ticketId}/summary`, + salesPersonId: ticket.salesPersonFk + }))); + } + } + } + + // SET COLLECTION + if (sales && sales.length) { + // GET BARCODES + const barcodes = await Self.rawSql(` + SELECT s.id saleFk, b.code, c.id + FROM vn.sale s + LEFT JOIN vn.itemBarcode b ON b.itemFk = s.itemFk + LEFT JOIN vn.buy c ON c.itemFk = s.itemFk + LEFT JOIN vn.entry e ON e.id = c.entryFk + LEFT JOIN vn.travel tr ON tr.id = e.travelFk + WHERE s.ticketFk = ? AND tr.landed >= DATE_SUB(util.VN_CURDATE(), INTERVAL 1 YEAR)`, + [ticketId], myOptions); + + // BINDINGS + ticket.sales = sales.reduce((acc, sale) => { + if (sale.ticketFk == ticketId) { + sale.Barcodes = []; + if (barcodes && barcodes.length) { + sale.Barcodes = barcodes.reduce((bacc, barcode) => { + if (barcode.saleFk == sale.saleFk) { + for (let prop in barcode) { + if (['id', 'code'].includes(prop) && barcode[prop]) { + bacc.push(barcode[prop].toString()); + bacc.push('0' + barcode[prop]); + } + } + } + return bacc; + }, []); + } + acc.push(sale); + } + return acc; + }, []); + } + collection.tickets.push(ticket); + } + } + + if (tx) await tx.commit(); + await Promise.all(promises); + + return collection; + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } + }; +}; diff --git a/back/methods/collection/spec/getTickets.spec.js b/back/methods/collection/spec/getTickets.spec.js new file mode 100644 index 0000000000..eddbb21b13 --- /dev/null +++ b/back/methods/collection/spec/getTickets.spec.js @@ -0,0 +1,11 @@ +const models = require('vn-loopback/server/server').models; + +describe('collection getTickets()', () => { + it('should return a list of tickets from a collection', async() => { + let ctx = {req: {accessToken: {userId: 1107}}}; + let response = await models.Collection.getCollection(ctx); + + expect(response.length).toBeGreaterThan(0); + expect(response[0].collectionFk).toEqual(3); + }); +}); diff --git a/back/models/collection.js b/back/models/collection.js index a41742ee77..bfa906af60 100644 --- a/back/models/collection.js +++ b/back/models/collection.js @@ -4,4 +4,5 @@ module.exports = Self => { require('../methods/collection/getSectors')(Self); require('../methods/collection/setSaleQuantity')(Self); require('../methods/collection/previousLabel')(Self); + require('../methods/collection/getTickets')(Self); }; diff --git a/db/changes/234001/00-collectionGetTicketsACL.sql b/db/changes/234001/00-collectionGetTicketsACL.sql new file mode 100644 index 0000000000..06b584386f --- /dev/null +++ b/db/changes/234001/00-collectionGetTicketsACL.sql @@ -0,0 +1,3 @@ +INSERT INTO `salix`.`ACL`(model, property, accessType, permission, principalType, principalId) + VALUES + ('Collection', 'getTickets', 'WRITE', 'ALLOW', 'ROLE', 'employee'); diff --git a/loopback/locale/en.json b/loopback/locale/en.json index fb4e72bd64..3ce4761a15 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -187,5 +187,6 @@ "This ticket is not editable.": "This ticket is not editable.", "The ticket doesn't exist.": "The ticket doesn't exist.", "The sales do not exists": "The sales do not exists", - "Ticket without Route": "Ticket without route" + "Ticket without Route": "Ticket without route", + "The ticket is in preparation": "The ticket [{{ticketId}}]({{{ticketUrl}}}) of the sales person {{salesPersonId}} is in preparation" } diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 756ce301a9..71a01f91af 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -314,8 +314,10 @@ "This ticket is locked.": "Este ticket está bloqueado.", "This ticket is not editable.": "Este ticket no es editable.", "The ticket doesn't exist.": "No existe el ticket.", - "Social name should be uppercase": "La razón social debe ir en mayúscula", + "Social name should be uppercase": "La razón social debe ir en mayúscula", "Street should be uppercase": "La dirección fiscal debe ir en mayúscula", "The response is not a PDF": "La respuesta no es un PDF", - "Ticket without Route": "Ticket sin ruta" -} + "Ticket without Route": "Ticket sin ruta", + "The ticket is in preparation": "El ticket [{{ticketId}}]({{{ticketUrl}}}) del comercial {{salesPersonId}} està en preparación", + "Invalid collection or ticket": "Invalid collection or ticket" +} \ No newline at end of file From d4e5815d417122c905e7583ef314311d21793fcf Mon Sep 17 00:00:00 2001 From: alexm Date: Thu, 28 Sep 2023 08:30:50 +0200 Subject: [PATCH 2/9] refs #6254 feat(collection_getTickets): refactor code and add test --- back/methods/collection/getTickets.js | 46 +++++++++---------- .../collection/spec/getTickets.spec.js | 38 +++++++++++++-- db/changes/233802/.gitkeep | 0 .../00-collectionGetTicketsACL.sql | 0 4 files changed, 56 insertions(+), 28 deletions(-) create mode 100644 db/changes/233802/.gitkeep rename db/changes/{234001 => 233802}/00-collectionGetTicketsACL.sql (100%) diff --git a/back/methods/collection/getTickets.js b/back/methods/collection/getTickets.js index 196ff0ce6e..1d0daa43aa 100644 --- a/back/methods/collection/getTickets.js +++ b/back/methods/collection/getTickets.js @@ -4,10 +4,11 @@ module.exports = Self => { description: 'Make a new collection of tickets', accessType: 'WRITE', accepts: [{ - arg: 'paramId', + arg: 'id', type: 'number', - description: 'The collection or ticket id', - required: true + description: 'The collection id', + required: true, + http: {source: 'path'} }, { arg: 'print', type: 'boolean', @@ -18,12 +19,12 @@ module.exports = Self => { root: true }, http: { - path: `/getTickets`, + path: `/:id/getTickets`, verb: 'POST' } }); - Self.getTickets = async(ctx, paramId, print, options) => { + Self.getTickets = async(ctx, id, print, options) => { const userId = ctx.req.accessToken.userId; const origin = ctx.req.headers.origin; const $t = ctx.req.__; // $translate @@ -42,7 +43,7 @@ module.exports = Self => { const promises = []; try { - const [tickets] = await Self.rawSql(`CALL vn.collection_getTickets(?)`, [paramId], myOptions); + const [tickets] = await Self.rawSql(`CALL vn.collection_getTickets(?)`, [id], myOptions); const sales = await Self.rawSql(` SELECT s.ticketFk, @@ -104,14 +105,14 @@ module.exports = Self => { LEFT JOIN saleMistake sm ON sm.saleFk = s.id WHERE tc.collectionFk = ? GROUP BY s.id, p.code, p2.code - ORDER BY pickingOrder`, [paramId, paramId], myOptions); + ORDER BY pickingOrder`, [id, id], myOptions); if (print) - await Self.rawSql(`CALL vn.collection_printSticker(?, ?)`, [paramId, null], myOptions); + await Self.rawSql(`CALL vn.collection_printSticker(?, ?)`, [id, null], myOptions); - const collection = {collectionFk: paramId, tickets: []}; + const collection = {collectionFk: id, tickets: []}; if (tickets && tickets.length) { - for (let ticket of tickets) { + for (const ticket of tickets) { const ticketId = ticket.ticketFk; // SEND ROCKET @@ -142,26 +143,25 @@ module.exports = Self => { [ticketId], myOptions); // BINDINGS - ticket.sales = sales.reduce((acc, sale) => { - if (sale.ticketFk == ticketId) { + ticket.sales = []; + for (const sale of sales) { + if (sale.ticketFk === ticketId) { sale.Barcodes = []; + if (barcodes && barcodes.length) { - sale.Barcodes = barcodes.reduce((bacc, barcode) => { - if (barcode.saleFk == sale.saleFk) { + for (const barcode of barcodes) { + if (barcode.saleFk === sale.saleFk) { for (let prop in barcode) { - if (['id', 'code'].includes(prop) && barcode[prop]) { - bacc.push(barcode[prop].toString()); - bacc.push('0' + barcode[prop]); - } + if (['id', 'code'].includes(prop) && barcode[prop]) + sale.Barcodes.push(barcode[prop].toString(), '0' + barcode[prop]); } } - return bacc; - }, []); + } } - acc.push(sale); + + ticket.sales.push(sale); } - return acc; - }, []); + } } collection.tickets.push(ticket); } diff --git a/back/methods/collection/spec/getTickets.spec.js b/back/methods/collection/spec/getTickets.spec.js index eddbb21b13..e6b9e6a17f 100644 --- a/back/methods/collection/spec/getTickets.spec.js +++ b/back/methods/collection/spec/getTickets.spec.js @@ -1,11 +1,39 @@ const models = require('vn-loopback/server/server').models; describe('collection getTickets()', () => { - it('should return a list of tickets from a collection', async() => { - let ctx = {req: {accessToken: {userId: 1107}}}; - let response = await models.Collection.getCollection(ctx); + let ctx; + beforeAll(async() => { + ctx = { + req: { + accessToken: {userId: 9}, + headers: {origin: 'http://localhost'} + } + }; + }); - expect(response.length).toBeGreaterThan(0); - expect(response[0].collectionFk).toEqual(3); + it('should get tickets, sales and barcodes from collection', async() => { + const tx = await models.Collection.beginTransaction({}); + + try { + const options = {transaction: tx}; + const collectionId = 1; + + const collectionTickets = await models.Collection.getTickets(ctx, collectionId, null, options); + + expect(collectionTickets.collectionFk).toEqual(collectionId); + expect(collectionTickets.tickets.length).toEqual(3); + expect(collectionTickets.tickets[0].ticketFk).toEqual(1); + expect(collectionTickets.tickets[1].ticketFk).toEqual(2); + expect(collectionTickets.tickets[2].ticketFk).toEqual(23); + expect(collectionTickets.tickets[0].sales[0].ticketFk).toEqual(1); + expect(collectionTickets.tickets[0].sales[1].ticketFk).toEqual(1); + expect(collectionTickets.tickets[0].sales[2].ticketFk).toEqual(1); + expect(collectionTickets.tickets[0].sales[0].Barcodes.length).toBeTruthy(); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/db/changes/233802/.gitkeep b/db/changes/233802/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/db/changes/234001/00-collectionGetTicketsACL.sql b/db/changes/233802/00-collectionGetTicketsACL.sql similarity index 100% rename from db/changes/234001/00-collectionGetTicketsACL.sql rename to db/changes/233802/00-collectionGetTicketsACL.sql From f3c55cdee989fa8256bc7c19d83f3bc70d511b27 Mon Sep 17 00:00:00 2001 From: alexm Date: Thu, 28 Sep 2023 16:00:09 +0200 Subject: [PATCH 3/9] refs #5929 fix(isEditable): can edit if is weekly --- db/dump/fixtures.sql | 2 -- modules/ticket/back/methods/ticket/isEditableOrThrow.js | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 9187e2871e..c10b5665a9 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -1409,10 +1409,8 @@ INSERT INTO `cache`.`cache_calc`(`id`, `cache_id`, `cacheName`, `params`, `last_ INSERT INTO `vn`.`ticketWeekly`(`ticketFk`, `weekDay`) VALUES - (1, 0), (2, 1), (3, 2), - (4, 4), (5, 6), (15, 6); diff --git a/modules/ticket/back/methods/ticket/isEditableOrThrow.js b/modules/ticket/back/methods/ticket/isEditableOrThrow.js index 6a8bafa2cb..f8285cecd8 100644 --- a/modules/ticket/back/methods/ticket/isEditableOrThrow.js +++ b/modules/ticket/back/methods/ticket/isEditableOrThrow.js @@ -40,7 +40,7 @@ module.exports = Self => { if (!isEditable && !isRoleAdvanced) throw new ForbiddenError(`This ticket is not editable.`); - if (isLocked) + if (isLocked && !isWeekly) throw new ForbiddenError(`This ticket is locked.`); if (isWeekly && !canEditWeeklyTicket) From 542119983b303a093e8cec7caaad2c9818ddce42 Mon Sep 17 00:00:00 2001 From: alexm Date: Fri, 29 Sep 2023 09:28:23 +0200 Subject: [PATCH 4/9] refs #5929 test: fix test after fix ticket_isEditable --- e2e/helpers/selectors.js | 3 +-- e2e/paths/05-ticket/09_weekly.spec.js | 10 ++++++---- .../methods/ticket-request/specs/filter.spec.js | 10 +++++----- .../methods/ticket-weekly/specs/filter.spec.js | 14 +++++++------- .../back/methods/ticket/specs/isEditable.spec.js | 2 +- 5 files changed, 20 insertions(+), 19 deletions(-) diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index 1b18eb8668..6f78d7c4e5 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -520,8 +520,7 @@ export default { searchResultDate: 'vn-ticket-summary [label=Landed] span', topbarSearch: 'vn-searchbar', moreMenu: 'vn-ticket-index vn-icon-button[icon=more_vert]', - fourthWeeklyTicket: 'vn-ticket-weekly-index vn-card smart-table slot-table tr:nth-child(5)', - fiveWeeklyTicket: 'vn-ticket-weekly-index vn-card smart-table slot-table tr:nth-child(6)', + thirdWeeklyTicket: 'vn-ticket-weekly-index vn-card smart-table slot-table tr:nth-child(4)', weeklyTicket: 'vn-ticket-weekly-index vn-card smart-table slot-table table tbody tr', firstWeeklyTicketDeleteIcon: 'vn-ticket-weekly-index vn-card smart-table slot-table tr:nth-child(2) vn-icon-button[icon="delete"]', firstWeeklyTicketAgency: 'vn-ticket-weekly-index vn-card smart-table slot-table tr:nth-child(2) [ng-model="weekly.agencyModeFk"]', diff --git a/e2e/paths/05-ticket/09_weekly.spec.js b/e2e/paths/05-ticket/09_weekly.spec.js index a9cce2ead1..74febfd014 100644 --- a/e2e/paths/05-ticket/09_weekly.spec.js +++ b/e2e/paths/05-ticket/09_weekly.spec.js @@ -19,7 +19,7 @@ describe('Ticket descriptor path', () => { it('should count the amount of tickets in the turns section', async() => { const result = await page.countElement(selectors.ticketsIndex.weeklyTicket); - expect(result).toEqual(7); + expect(result).toEqual(5); }); it('should go back to the ticket index then search and access a ticket summary', async() => { @@ -45,7 +45,7 @@ describe('Ticket descriptor path', () => { it('should confirm the ticket 11 was added to thursday', async() => { await page.accessToSection('ticket.weekly.index'); - const result = await page.waitToGetProperty(selectors.ticketsIndex.fourthWeeklyTicket, 'value'); + const result = await page.waitToGetProperty(selectors.ticketsIndex.thirdWeeklyTicket, 'value'); expect(result).toEqual('Thursday'); }); @@ -80,7 +80,9 @@ describe('Ticket descriptor path', () => { it('should confirm the ticket 11 was added on saturday', async() => { await page.accessToSection('ticket.weekly.index'); - const result = await page.waitToGetProperty(selectors.ticketsIndex.fiveWeeklyTicket, 'value'); + await page.waitForTimeout(5000); + + const result = await page.waitToGetProperty(selectors.ticketsIndex.thirdWeeklyTicket, 'value'); expect(result).toEqual('Saturday'); }); @@ -104,7 +106,7 @@ describe('Ticket descriptor path', () => { await page.doSearch(); const nResults = await page.countElement(selectors.ticketsIndex.searchWeeklyResult); - expect(nResults).toEqual(7); + expect(nResults).toEqual(5); }); it('should update the agency then remove it afterwards', async() => { diff --git a/modules/ticket/back/methods/ticket-request/specs/filter.spec.js b/modules/ticket/back/methods/ticket-request/specs/filter.spec.js index ae004a024a..9ab89f0099 100644 --- a/modules/ticket/back/methods/ticket-request/specs/filter.spec.js +++ b/modules/ticket/back/methods/ticket-request/specs/filter.spec.js @@ -14,7 +14,7 @@ describe('ticket-request filter()', () => { const result = await models.TicketRequest.filter(ctx, options); - expect(result.length).toEqual(3); + expect(result.length).toEqual(5); await tx.rollback(); } catch (e) { @@ -93,7 +93,7 @@ describe('ticket-request filter()', () => { const result = await models.TicketRequest.filter(ctx, options); const requestId = result[0].id; - expect(requestId).toEqual(3); + expect(requestId).toEqual(1); await tx.rollback(); } catch (e) { @@ -113,7 +113,7 @@ describe('ticket-request filter()', () => { const result = await models.TicketRequest.filter(ctx, options); const requestId = result[0].id; - expect(requestId).toEqual(3); + expect(requestId).toEqual(1); await tx.rollback(); } catch (e) { @@ -153,7 +153,7 @@ describe('ticket-request filter()', () => { const result = await models.TicketRequest.filter(ctx, {order: 'id'}, options); const requestId = result[0].id; - expect(requestId).toEqual(3); + expect(requestId).toEqual(1); await tx.rollback(); } catch (e) { @@ -173,7 +173,7 @@ describe('ticket-request filter()', () => { const result = await models.TicketRequest.filter(ctx, options); const requestId = result[0].id; - expect(requestId).toEqual(3); + expect(requestId).toEqual(1); await tx.rollback(); } catch (e) { diff --git a/modules/ticket/back/methods/ticket-weekly/specs/filter.spec.js b/modules/ticket/back/methods/ticket-weekly/specs/filter.spec.js index 2587b66576..453b7924f1 100644 --- a/modules/ticket/back/methods/ticket-weekly/specs/filter.spec.js +++ b/modules/ticket/back/methods/ticket-weekly/specs/filter.spec.js @@ -16,8 +16,8 @@ describe('ticket-weekly filter()', () => { const firstRow = result[0]; - expect(firstRow.ticketFk).toEqual(1); - expect(result.length).toEqual(6); + expect(firstRow.ticketFk).toEqual(2); + expect(result.length).toEqual(4); await tx.rollback(); } catch (e) { @@ -52,12 +52,12 @@ describe('ticket-weekly filter()', () => { try { const options = {transaction: tx}; - const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 'bruce'}}; + const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 'max'}}; const result = await models.TicketWeekly.filter(ctx, null, options); const firstRow = result[0]; - expect(firstRow.clientName).toEqual('Bruce Wayne'); + expect(firstRow.clientName).toEqual('Max Eisenhardt'); await tx.rollback(); } catch (e) { @@ -72,13 +72,13 @@ describe('ticket-weekly filter()', () => { try { const options = {transaction: tx}; - const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 1101}}; + const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 1105}}; const result = await models.TicketWeekly.filter(ctx, null, options); const firstRow = result[0]; - expect(firstRow.clientFk).toEqual(1101); - expect(firstRow.clientName).toEqual('Bruce Wayne'); + expect(firstRow.clientFk).toEqual(1105); + expect(firstRow.clientName).toEqual('Max Eisenhardt'); await tx.rollback(); } catch (e) { diff --git a/modules/ticket/back/methods/ticket/specs/isEditable.spec.js b/modules/ticket/back/methods/ticket/specs/isEditable.spec.js index 301745ed34..9dd1f85442 100644 --- a/modules/ticket/back/methods/ticket/specs/isEditable.spec.js +++ b/modules/ticket/back/methods/ticket/specs/isEditable.spec.js @@ -8,7 +8,7 @@ describe('isEditable()', () => { try { const options = {transaction: tx}; const ctx = {req: {accessToken: {userId: 35}}}; - result = await models.Ticket.isEditable(ctx, 5, options); + result = await models.Ticket.isEditable(ctx, 19, options); await tx.rollback(); } catch (error) { await tx.rollback(); From a0a59b672f81ec0a58224da567375829cd28ff15 Mon Sep 17 00:00:00 2001 From: alexm Date: Fri, 29 Sep 2023 10:04:57 +0200 Subject: [PATCH 5/9] =?UTF-8?q?refs=20#6271=20hotFix(email):=20clientCredi?= =?UTF-8?q?tEmail=20=E2=86=92=20creditRequestEmail?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/client/back/methods/client/creditRequestEmail.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/client/back/methods/client/creditRequestEmail.js b/modules/client/back/methods/client/creditRequestEmail.js index 0255949e0d..60047de771 100644 --- a/modules/client/back/methods/client/creditRequestEmail.js +++ b/modules/client/back/methods/client/creditRequestEmail.js @@ -1,5 +1,5 @@ module.exports = Self => { - Self.remoteMethodCtx('clientCreditEmail', { + Self.remoteMethodCtx('creditRequestEmail', { description: 'Sends the credit request email with an attached PDF', accessType: 'WRITE', accepts: [ @@ -40,5 +40,5 @@ module.exports = Self => { }, }); - Self.clientCreditEmail = ctx => Self.sendTemplate(ctx, 'credit-request'); + Self.creditRequestEmail = ctx => Self.sendTemplate(ctx, 'credit-request'); }; From 9a7cb3ef7b7074f1a6316197a3894b72406fb0bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Andr=C3=A9s?= Date: Fri, 29 Sep 2023 12:30:05 +0200 Subject: [PATCH 6/9] refs #6254 collection_getTickets --- back/methods/collection/getTickets.js | 155 ++++++++++---------------- loopback/locale/es.json | 3 +- 2 files changed, 62 insertions(+), 96 deletions(-) diff --git a/back/methods/collection/getTickets.js b/back/methods/collection/getTickets.js index 1d0daa43aa..f39a71cdbd 100644 --- a/back/methods/collection/getTickets.js +++ b/back/methods/collection/getTickets.js @@ -30,46 +30,37 @@ module.exports = Self => { const $t = ctx.req.__; // $translate const myOptions = {}; - let tx; - if (typeof options == 'object') Object.assign(myOptions, options); - if (!myOptions.transaction) { - tx = await Self.beginTransaction({}); - myOptions.transaction = tx; - } myOptions.userId = userId; const promises = []; - try { - const [tickets] = await Self.rawSql(`CALL vn.collection_getTickets(?)`, [id], myOptions); - const sales = await Self.rawSql(` - SELECT - s.ticketFk, + + const [tickets] = await Self.rawSql(`CALL vn.collection_getTickets(?)`, [id], myOptions); + const sales = await Self.rawSql(` + SELECT s.ticketFk, sgd.saleGroupFk, s.id saleFk, s.itemFk, i.longName, i.size, - IFNULL(sub2.semaphore,st.semaphore) semaphore, ic.color, - ip.productor, o.code origin, - s.concept, - b.packing, - b.grouping, + ish.packing, + ish.grouping, s.isAdded, - c.workerFk, - i.packingShelve, - sm.id hasMistake, - s.originalQuantity, + s.originalQuantity, s.quantity saleQuantity, - IF(p2.code IS NOT NULL, s.quantity, iss.quantity) reservedQuantity, + iss.quantity reservedQuantity, + SUM(iss.quantity) OVER (PARTITION BY s.id ORDER BY ish.id) accumulatedQuantity, + ROW_NUMBER () OVER (PARTITION BY s.id ORDER BY pickingOrder) currentItemShelving, + COUNT(*) OVER (PARTITION BY s.id ORDER BY s.id) totalItemShelving, sh.code, IFNULL(p2.code, p.code) parkingCode, IFNULL(p2.pickingOrder, p.pickingOrder) pickingOrder, iss.id itemShelvingSaleFk + iss.isChecked FROM ticketCollection tc LEFT JOIN collection c ON c.id = tc.collectionFk JOIN ticket t ON t.id = tc.ticketFk @@ -77,103 +68,79 @@ module.exports = Self => { LEFT JOIN saleGroupDetail sgd ON sgd.saleFk = s.id LEFT JOIN saleGroup sg ON sg.id = sgd.saleGroupFk LEFT JOIN parking p2 ON p2.id = sg.parkingFk - LEFT JOIN cache.last_buy lb ON lb.item_id = s.itemFk AND lb.warehouse_id = t.warehouseFk - LEFT JOIN buy b ON b.id = lb.buy_id JOIN item i ON i.id = s.itemFk LEFT JOIN itemShelvingSale iss ON iss.saleFk = s.id LEFT JOIN itemShelving ish ON ish.id = iss.itemShelvingFk LEFT JOIN shelving sh ON sh.code = ish.shelvingFk LEFT JOIN parking p ON p.id = sh.parkingFk - LEFT JOIN ( - SELECT sub.saleFk, sub.isChecked, sub.stateFk, sub.originalQuantity, sub.semaphore - FROM ( - SELECT DISTINCT st.id, - st.saleFk, st.isChecked, st.stateFk, st.originalQuantity ,sta.semaphore - FROM ticketCollection tc - JOIN sale s ON s.ticketFk = tc.ticketFk - JOIN saleTracking st ON st.saleFk = s.id - JOIN state sta ON sta.id = st.stateFk - WHERE tc.collectionFk = ? - ORDER BY st.id DESC - LIMIT 10000000000000000000) sub - GROUP BY sub.saleFk, sub.stateFK - ) sub2 ON sub2.saleFk = s.id AND sub2.isChecked = 1 - LEFT JOIN state st ON st.id = sub2.stateFk LEFT JOIN itemColor ic ON ic.itemFk = s.itemFk - LEFT JOIN itemProductor ip ON ip.itemFk = s.itemFk LEFT JOIN origin o ON o.id = i.originFk - LEFT JOIN saleMistake sm ON sm.saleFk = s.id WHERE tc.collectionFk = ? - GROUP BY s.id, p.code, p2.code - ORDER BY pickingOrder`, [id, id], myOptions); + GROUP BY ish.id, p.code, p2.code + ORDER BY pickingOrder;`, [id], myOptions); - if (print) - await Self.rawSql(`CALL vn.collection_printSticker(?, ?)`, [id, null], myOptions); + if (print) + await Self.rawSql(`CALL vn.collection_printSticker(?, ?)`, [id, null], myOptions); - const collection = {collectionFk: id, tickets: []}; - if (tickets && tickets.length) { - for (const ticket of tickets) { - const ticketId = ticket.ticketFk; + const collection = {collectionFk: id, tickets: []}; + if (tickets && tickets.length) { + for (const ticket of tickets) { + const ticketId = ticket.ticketFk; - // SEND ROCKET - if (ticket.observaciones != '') { - for (observation of ticket.observaciones.split(' ')) { - if (['#', '@'].includes(observation.charAt(0))) { - promises.push(Self.app.models.Chat.send(ctx, observation, - $t('The ticket is in preparation', { - ticketId: ticketId, - ticketUrl: `${origin}/#!/ticket/${ticketId}/summary`, - salesPersonId: ticket.salesPersonFk - }))); - } + // SEND ROCKET + if (ticket.observaciones != '') { + for (observation of ticket.observaciones.split(' ')) { + if (['#', '@'].includes(observation.charAt(0))) { + promises.push(Self.app.models.Chat.send(ctx, observation, + $t('The ticket is in preparation', { + ticketId: ticketId, + ticketUrl: `${origin}/#!/ticket/${ticketId}/summary`, + salesPersonId: ticket.salesPersonFk + }))); } } + } - // SET COLLECTION - if (sales && sales.length) { - // GET BARCODES - const barcodes = await Self.rawSql(` - SELECT s.id saleFk, b.code, c.id - FROM vn.sale s - LEFT JOIN vn.itemBarcode b ON b.itemFk = s.itemFk - LEFT JOIN vn.buy c ON c.itemFk = s.itemFk - LEFT JOIN vn.entry e ON e.id = c.entryFk - LEFT JOIN vn.travel tr ON tr.id = e.travelFk - WHERE s.ticketFk = ? AND tr.landed >= DATE_SUB(util.VN_CURDATE(), INTERVAL 1 YEAR)`, - [ticketId], myOptions); + // SET COLLECTION + if (sales && sales.length) { + // GET BARCODES + const barcodes = await Self.rawSql(` + SELECT s.id saleFk, b.code, c.id + FROM vn.sale s + LEFT JOIN vn.itemBarcode b ON b.itemFk = s.itemFk + LEFT JOIN vn.buy c ON c.itemFk = s.itemFk + LEFT JOIN vn.entry e ON e.id = c.entryFk + LEFT JOIN vn.travel tr ON tr.id = e.travelFk + WHERE s.ticketFk = ? + AND tr.landed >= util.VN_CURDATE() - INTERVAL 1 YEAR`, + [ticketId], myOptions); - // BINDINGS - ticket.sales = []; - for (const sale of sales) { - if (sale.ticketFk === ticketId) { - sale.Barcodes = []; + // BINDINGS + ticket.sales = []; + for (const sale of sales) { + if (sale.ticketFk === ticketId) { + sale.Barcodes = []; - if (barcodes && barcodes.length) { - for (const barcode of barcodes) { - if (barcode.saleFk === sale.saleFk) { - for (let prop in barcode) { - if (['id', 'code'].includes(prop) && barcode[prop]) - sale.Barcodes.push(barcode[prop].toString(), '0' + barcode[prop]); - } + if (barcodes && barcodes.length) { + for (const barcode of barcodes) { + if (barcode.saleFk === sale.saleFk) { + for (const prop in barcode) { + if (['id', 'code'].includes(prop) && barcode[prop]) + sale.Barcodes.push(barcode[prop].toString(), '0' + barcode[prop]); } } } - - ticket.sales.push(sale); } + + ticket.sales.push(sale); } } - collection.tickets.push(ticket); } + collection.tickets.push(ticket); } - - if (tx) await tx.commit(); - await Promise.all(promises); - - return collection; - } catch (e) { - if (tx) await tx.rollback(); - throw e; } + await Promise.all(promises); + + return collection; }; }; diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 71a01f91af..87a41fcf60 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -318,6 +318,5 @@ "Street should be uppercase": "La dirección fiscal debe ir en mayúscula", "The response is not a PDF": "La respuesta no es un PDF", "Ticket without Route": "Ticket sin ruta", - "The ticket is in preparation": "El ticket [{{ticketId}}]({{{ticketUrl}}}) del comercial {{salesPersonId}} està en preparación", - "Invalid collection or ticket": "Invalid collection or ticket" + "The ticket is in preparation": "El ticket [{{ticketId}}]({{{ticketUrl}}}) del comercial {{salesPersonId}} està en preparación" } \ No newline at end of file From 17e6cffa3d1970462c43d6cf3961ca3e4b2e0395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Andr=C3=A9s?= Date: Fri, 29 Sep 2023 13:47:29 +0200 Subject: [PATCH 7/9] refs #6254 collection getTickets --- back/methods/collection/getTickets.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/back/methods/collection/getTickets.js b/back/methods/collection/getTickets.js index 70c3eb3510..445fc070d3 100644 --- a/back/methods/collection/getTickets.js +++ b/back/methods/collection/getTickets.js @@ -27,7 +27,7 @@ module.exports = Self => { Self.getTickets = async(ctx, id, print, options) => { const userId = ctx.req.accessToken.userId; const origin = ctx.req.headers.origin; - const $t = ctx.req.__; // $translate + const $t = ctx.req.__; const myOptions = {}; if (typeof options == 'object') @@ -59,11 +59,7 @@ module.exports = Self => { sh.code, IFNULL(p2.code, p.code) parkingCode, IFNULL(p2.pickingOrder, p.pickingOrder) pickingOrder, -<<<<<<< Updated upstream - iss.id itemShelvingSaleFk -======= iss.id itemShelvingSaleFk, ->>>>>>> Stashed changes iss.isPicked FROM ticketCollection tc LEFT JOIN collection c ON c.id = tc.collectionFk From 0e5a7bbb85e55bd4c9ad8634ba528a325835a853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Andr=C3=A9s?= Date: Fri, 29 Sep 2023 14:11:11 +0200 Subject: [PATCH 8/9] refs #6254 --- loopback/locale/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loopback/locale/en.json b/loopback/locale/en.json index 3380d3dde9..3ce4761a15 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -187,6 +187,6 @@ "This ticket is not editable.": "This ticket is not editable.", "The ticket doesn't exist.": "The ticket doesn't exist.", "The sales do not exists": "The sales do not exists", - "Ticket without Route": "Ticket sin ruta", + "Ticket without Route": "Ticket without route", "The ticket is in preparation": "The ticket [{{ticketId}}]({{{ticketUrl}}}) of the sales person {{salesPersonId}} is in preparation" } From c469a221c711dc055d93e051b73a7a70361ffb40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Andr=C3=A9s?= Date: Fri, 29 Sep 2023 14:16:35 +0200 Subject: [PATCH 9/9] refs #6254 --- loopback/locale/en.json | 1 + 1 file changed, 1 insertion(+) diff --git a/loopback/locale/en.json b/loopback/locale/en.json index 3ce4761a15..645a874e89 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -188,5 +188,6 @@ "The ticket doesn't exist.": "The ticket doesn't exist.", "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" }