From 2a4d41cbca3e4ecfbb80389e00610b8fc8bcc926 Mon Sep 17 00:00:00 2001 From: alexandre Date: Fri, 24 Feb 2023 14:41:02 +0100 Subject: [PATCH 1/9] refs #4632 saveSign refactored, working on tests, check if dmsRecover is needed --- back/methods/dms/saveSign.js | 215 ------------------ back/model-config.json | 3 + back/models/delivery.json | 24 +- back/models/dms-recover.json | 37 +++ back/models/dms.js | 1 - db/changes/230801/00-delivery.sql | 72 ++++++ .../back/methods/ticket-dms/saveSign.js | 157 +++++++++++++ .../methods/ticket-dms/specs/saveSign.spec.js | 57 +++++ modules/ticket/back/models/ticket-dms.js | 1 + modules/ticket/back/models/ticket.json | 7 +- 10 files changed, 350 insertions(+), 224 deletions(-) delete mode 100644 back/methods/dms/saveSign.js create mode 100644 back/models/dms-recover.json create mode 100644 db/changes/230801/00-delivery.sql create mode 100644 modules/ticket/back/methods/ticket-dms/saveSign.js create mode 100644 modules/ticket/back/methods/ticket-dms/specs/saveSign.spec.js diff --git a/back/methods/dms/saveSign.js b/back/methods/dms/saveSign.js deleted file mode 100644 index ed462a301..000000000 --- a/back/methods/dms/saveSign.js +++ /dev/null @@ -1,215 +0,0 @@ -const md5 = require('md5'); -const fs = require('fs-extra'); - -module.exports = Self => { - Self.remoteMethodCtx('saveSign', { - description: 'Save sign', - accessType: 'WRITE', - accepts: - [ - { - arg: 'signContent', - type: 'string', - required: true, - description: 'The sign content' - }, { - arg: 'tickets', - type: ['number'], - required: true, - description: 'The tickets' - }, { - arg: 'signedTime', - type: 'date', - description: 'The signed time' - }, { - arg: 'addressFk', - type: 'number', - required: true, - description: 'The address fk' - } - ], - returns: { - type: 'Object', - root: true - }, - http: { - path: `/saveSign`, - verb: 'POST' - } - }); - - async function createGestDoc(ticketId, userFk) { - const models = Self.app.models; - if (!await gestDocExists(ticketId)) { - const result = await models.Ticket.findOne({ - where: { - id: ticketId - }, - include: [ - { - relation: 'warehouse', - scope: { - fields: ['id'] - } - }, { - relation: 'client', - scope: { - fields: ['name'] - } - }, { - relation: 'route', - scope: { - fields: ['id'] - } - } - ] - }); - - const warehouseFk = result.warehouseFk; - const companyFk = result.companyFk; - const client = result.client.name; - const route = result.route.id; - - const resultDmsType = await models.DmsType.findOne({ - where: { - code: 'Ticket' - } - }); - - const resultDms = await models.Dms.create({ - dmsTypeFk: resultDmsType.id, - reference: ticketId, - description: `Ticket ${ticketId} Cliente ${client} Ruta ${route}`, - companyFk: companyFk, - warehouseFk: warehouseFk, - workerFk: userFk - }); - - return resultDms.insertId; - } - } - - async function gestDocExists(ticket) { - const models = Self.app.models; - const result = await models.TicketDms.findOne({ - where: { - ticketFk: ticket - }, - fields: ['dmsFk'] - }); - - if (result == null) - return false; - - const isSigned = await models.Ticket.findOne({ - where: { - id: ticket - }, - fields: ['isSigned'] - }); - - if (isSigned) - return true; - else - await models.Dms.destroyById(ticket); - } - - async function dmsRecover(ticket, signContent) { - const models = Self.app.models; - await models.DmsRecover.create({ - ticketFk: ticket, - sign: signContent - }); - } - - async function ticketGestdoc(ticket, dmsFk) { - const models = Self.app.models; - models.TicketDms.replaceOrCreate({ - ticketFk: ticket, - dmsFk: dmsFk - }); - - const queryVnTicketSetState = `CALL vn.ticket_setState(?, ?)`; - - await Self.rawSql(queryVnTicketSetState, [ticket, 'DELIVERED']); - } - - async function updateGestdoc(file, ticket) { - const models = Self.app.models; - models.Dms.updateOne({ - where: { - id: ticket - }, - file: file, - contentType: 'image/png' - }); - } - - Self.saveSign = async(ctx, signContent, tickets, signedTime) => { - const models = Self.app.models; - let tx = await Self.beginTransaction({}); - try { - const userId = ctx.req.accessToken.userId; - - const dmsDir = `storage/dms`; - - let image = null; - - for (let i = 0; i < tickets.length; i++) { - const alertLevel = await models.TicketState.findOne({ - where: { - ticketFk: tickets[i] - }, - fields: ['alertLevel'] - }); - - signedTime ? signedTime != undefined : signedTime = Date.vnNew(); - - if (alertLevel >= 2) { - let dir; - let id = null; - let fileName = null; - - if (!await gestDocExists(tickets[i])) { - id = await createGestDoc(tickets[i], userId); - - const hashDir = md5(id).substring(0, 3); - dir = `${dmsDir}/${hashDir}`; - - if (!fs.existsSync(dir)) - fs.mkdirSync(dir); - - fileName = `${id}.png`; - image = `${dir}/${fileName}`; - } else - - if (image != null) { - if (!fs.existsSync(dir)) - dmsRecover(tickets[i], signContent); - else { - fs.writeFile(image, signContent, 'base64', async function(err) { - if (err) { - await tx.rollback(); - return err.message; - } - }); - } - } else - dmsRecover(tickets[i], signContent); - - if (id != null && fileName.length > 0) { - ticketGestdoc(tickets[i], id); - updateGestdoc(id, fileName); - } - } - } - - if (tx) await tx.commit(); - - return 'OK'; - } catch (err) { - await tx.rollback(); - throw err.message; - } - }; -}; diff --git a/back/model-config.json b/back/model-config.json index 29676e979..6724db151 100644 --- a/back/model-config.json +++ b/back/model-config.json @@ -44,6 +44,9 @@ "DmsType": { "dataSource": "vn" }, + "DmsRecover": { + "dataSource": "vn" + }, "Docuware": { "dataSource": "vn" }, diff --git a/back/models/delivery.json b/back/models/delivery.json index 65a0eef1b..c66c31b45 100644 --- a/back/models/delivery.json +++ b/back/models/delivery.json @@ -9,17 +9,29 @@ "properties": { "id": { "id": true, - "type": "number", - "forceId": false + "type": "number" }, - "date": { + "created": { "type": "date" }, - "m3":{ + "longitude":{ "type": "number" }, - "warehouseFk":{ + "latitude":{ + "type": "number" + }, + "dated":{ + "type": "date" + }, + "ticketFk":{ "type": "number" } - } + }, + "relations": { + "ticket": { + "type": "belongsTo", + "model": "Ticket", + "foreignKey": "ticketFk" + } + } } diff --git a/back/models/dms-recover.json b/back/models/dms-recover.json new file mode 100644 index 000000000..3449347a7 --- /dev/null +++ b/back/models/dms-recover.json @@ -0,0 +1,37 @@ + +{ + "name": "DmsRecover", + "description": "Documental Managment System Recover", + "base": "VnModel", + "log": { + "showField": "ticketFk" + }, + "options": { + "mysql": { + "table": "dmsRecover" + } + }, + "properties": { + "id": { + "type": "number", + "id": true, + "description": "Identifier" + }, + "ticketFk": { + "type": "number" + }, + "sign": { + "type": "string" + }, + "created": { + "type": "date" + } + }, + "relations": { + "ticket": { + "type": "belongsTo", + "model": "Ticket", + "foreignKey": "ticketFk" + } + } +} diff --git a/back/models/dms.js b/back/models/dms.js index fc586201f..24c072f56 100644 --- a/back/models/dms.js +++ b/back/models/dms.js @@ -6,7 +6,6 @@ module.exports = Self => { require('../methods/dms/removeFile')(Self); require('../methods/dms/updateFile')(Self); require('../methods/dms/deleteTrashFiles')(Self); - require('../methods/dms/saveSign')(Self); Self.checkRole = async function(ctx, id) { const models = Self.app.models; diff --git a/db/changes/230801/00-delivery.sql b/db/changes/230801/00-delivery.sql new file mode 100644 index 000000000..38c0a7971 --- /dev/null +++ b/db/changes/230801/00-delivery.sql @@ -0,0 +1,72 @@ +ALTER TABLE `vn`.`delivery` DROP FOREIGN KEY delivery_FK; +ALTER TABLE `vn`.`delivery` DROP COLUMN addressFk; +ALTER TABLE `vn`.`delivery` ADD ticketFk INT NOT NULL; +ALTER TABLE `vn`.`delivery` ADD CONSTRAINT delivery_ticketFk_FK FOREIGN KEY (`ticketFk`) REFERENCES `vn`.`ticket`(`id`); + +DELETE FROM `salix`.`ACL` WHERE `property` = 'saveSign'; +INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalId`) + VALUES + ('TicketDms','saveSign','WRITE','ALLOW','employee'); + +DROP PROCEDURE IF EXISTS vn.route_getTickets; + +DELIMITER $$ +$$ +CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`route_getTickets`(vRouteFk INT) +BEGIN +/** + * Pasado un RouteFk devuelve la información + * de sus tickets. + * + * @param vRouteFk + * + * @select Información de los tickets + */ + + SELECT + t.id Id, + t.clientFk Client, + a.id Address, + t.packages Packages, + a.street AddressName, + a.postalCode PostalCode, + a.city City, + sub2.itemPackingTypeFk PackingType, + c.phone ClientPhone, + c.mobile ClientMobile, + a.phone AddressPhone, + a.mobile AddressMobile, + d.longitude Longitude, + d.latitude Latitude, + wm.mediaValue SalePersonPhone, + tob.Note Note, + t.isSigned Signed + FROM ticket t + JOIN client c ON t.clientFk = c.id + JOIN address a ON t.addressFk = a.id + LEFT JOIN delivery d ON t.id = d.ticketFk + LEFT JOIN workerMedia wm ON wm.workerFk = c.salesPersonFk + LEFT JOIN + (SELECT tob.description Note, t.id + FROM ticketObservation tob + JOIN ticket t ON tob.ticketFk = t.id + JOIN observationType ot ON ot.id = tob.observationTypeFk + WHERE t.routeFk = vRouteFk + AND ot.code = 'delivery' + )tob ON tob.id = t.id + LEFT JOIN + (SELECT sub.ticketFk, + CONCAT('(', GROUP_CONCAT(DISTINCT sub.itemPackingTypeFk ORDER BY sub.items DESC SEPARATOR ','), ') ') itemPackingTypeFk + FROM (SELECT s.ticketFk , i.itemPackingTypeFk, COUNT(*) items + FROM ticket t + JOIN sale s ON s.ticketFk = t.id + JOIN item i ON i.id = s.itemFk + WHERE t.routeFk = vRouteFk + GROUP BY t.id,i.itemPackingTypeFk)sub + GROUP BY sub.ticketFk + ) sub2 ON sub2.ticketFk = t.id + WHERE t.routeFk = vRouteFk + GROUP BY t.id + ORDER BY t.priority; +END$$ +DELIMITER ; diff --git a/modules/ticket/back/methods/ticket-dms/saveSign.js b/modules/ticket/back/methods/ticket-dms/saveSign.js new file mode 100644 index 000000000..725abfe67 --- /dev/null +++ b/modules/ticket/back/methods/ticket-dms/saveSign.js @@ -0,0 +1,157 @@ +module.exports = Self => { + Self.remoteMethodCtx('saveSign', { + description: 'Save sign', + accessType: 'WRITE', + accepts: + [ + { + arg: 'tickets', + type: ['number'], + required: true, + description: 'The tickets' + }, + { + arg: 'location', + type: 'object', + description: 'The employee location the moment the sign is saved' + }, + { + arg: 'signedTime', + type: 'date', + description: 'The signed time' + } + ], + returns: { + type: 'string', + root: true + }, + http: { + path: `/saveSign`, + verb: 'POST' + } + }); + + Self.saveSign = async(ctx, options) => { + const args = Object.assign({}, ctx.args); + const models = Self.app.models; + const myOptions = {}; + let tx; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } + + async function setLocation(ticketId) { + if (args.signedTime) { + await models.Delivery.create({ + ticketFk: ticketId, + longitude: args.location.Longitude, + latitude: args.location.Latitude, + dated: args.signedTime + }, myOptions); + } + } + + async function gestDocExists(ticketId) { + const ticketDms = await models.TicketDms.findOne({ + where: { + ticketFk: ticketId + }, + fields: ['dmsFk'] + }, myOptions); + + if (!ticketDms) return false; + + const ticket = await models.Ticket.findById(ticketId, {fields: ['isSigned']}, myOptions); + if (ticket.isSigned == true) return true; + else + await models.Dms.destroyAll({where: {reference: ticketId}}, myOptions); + + return false; + } + + async function createGestDoc(id) { + const ticket = await models.Ticket.findById(id, + {include: [ + { + relation: 'warehouse', + scope: { + fields: ['id'] + } + }, { + relation: 'client', + scope: { + fields: ['name'] + } + }, { + relation: 'route', + scope: { + fields: ['id'] + } + } + ] + }, myOptions); + const dmsType = await models.DmsType.findOne({where: {code: 'Ticket'}, fields: ['id']}, myOptions); + const ctxUploadFile = Object.assign({}, ctx); + ctxUploadFile.args = { + warehouseId: ticket.warehouseFk, + companyId: ticket.companyFk, + dmsTypeId: dmsType.id, + reference: id, + description: `Ticket ${id} Cliente ${ticket.client().name} Ruta ${ticket.route().id}`, + hasFile: true + }; + await models.Ticket.uploadFile(ctxUploadFile, id, myOptions); + } + + // async function dmsRecover(ticketFk, sign) { + // await models.DmsRecover.create({ticketFk, sign}, myOptions); + // } + + try { + for (let i = 0; i < args.tickets.length; i++) { + const ticketState = await models.TicketState.findOne( + {where: {ticketFk: args.tickets[i]}, + fields: ['alertLevel'] + }, myOptions); + + if (ticketState.alertLevel >= 2 && !await gestDocExists(args.tickets[i])) { + if (!args.signedTime) args.signedTime = Date.vnNew(); + if (args.location) setLocation(args.tickets[i]); + await createGestDoc(args.tickets[i]); + + // if (image) { + // if (!fs.existsSync(dir)) + // dmsRecover(args.tickets[i], args.signContent); + // else { + // fs.writeFile(image, args.signContent, 'base64', async function(err) { + // if (err) { + // await tx.rollback(); + // throw err.message; + // } + // }); + // } + // } else + // dmsRecover(args.tickets[i], args.signContent); + + // if (id && fileName) { + // await models.TicketDms.replaceOrCreate({ticketFk: args.tickets[i], dmsFk: id}, myOptions); + await Self.rawSql(`CALL vn.ticket_setState(?, ?)`, [args.tickets[i], 'DELIVERED'], myOptions); + // await models.Dms.updateAll({id}, {file: fileName, contentType: 'image/png'}, myOptions); + // } + } + } + + if (tx) await tx.commit(); + + return 'Sign uploaded correctly'; + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } + }; +}; diff --git a/modules/ticket/back/methods/ticket-dms/specs/saveSign.spec.js b/modules/ticket/back/methods/ticket-dms/specs/saveSign.spec.js new file mode 100644 index 000000000..b640fefb8 --- /dev/null +++ b/modules/ticket/back/methods/ticket-dms/specs/saveSign.spec.js @@ -0,0 +1,57 @@ +const models = require('vn-loopback/server/server').models; + +fdescribe('TicketDms saveSign()', () => { + const FormData = require('form-data'); + const data = new FormData(); + let ctx = {req: { + accessToken: {userId: 9}, + headers: { + ...data.getHeaders() + }, + on: (param, cb) => {} + }}; + + it(`should not save sign if the ticket's alert level is lower than 2`, async() => { + const tx = await models.TicketDms.beginTransaction({}); + const ticketWithOkState = 12; + + try { + const options = {transaction: tx}; + ctx.args = {tickets: [ticketWithOkState]}; + + await models.TicketDms.saveSign(ctx, options); + const ticket = await models.Ticket.findById(ticketWithOkState, {fields: ['isSigned']}, options); + const ticketDms = await models.TicketDms.findOne({where: {ticketFk: ticketWithOkState}}, options); + + expect(ticket.isSigned).toEqual(false); + expect(ticketDms).toEqual(null); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it(`should save sign if the ticket's alert level is greater than 2`, async() => { + const tx = await models.TicketDms.beginTransaction({}); + const ticketWithPackedState = 7; + + try { + const options = {transaction: tx}; + ctx.args = {tickets: [ticketWithPackedState]}; + + await models.TicketDms.saveSign(ctx, options); + const ticket = await models.Ticket.findById(ticketWithPackedState, {fields: ['isSigned']}, options); + const ticketDms = await models.TicketDms.findOne({where: {ticketFk: ticketWithPackedState}}, options); + + expect(ticket.isSigned).toEqual(true); + expect(ticketDms).toBeDefined(); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); +}); diff --git a/modules/ticket/back/models/ticket-dms.js b/modules/ticket/back/models/ticket-dms.js index 9bceaae6e..13d960270 100644 --- a/modules/ticket/back/models/ticket-dms.js +++ b/modules/ticket/back/models/ticket-dms.js @@ -2,6 +2,7 @@ const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { require('../methods/ticket-dms/removeFile')(Self); + require('../methods/ticket-dms/saveSign')(Self); Self.rewriteDbError(function(err) { if (err.code === 'ER_DUP_ENTRY') diff --git a/modules/ticket/back/models/ticket.json b/modules/ticket/back/models/ticket.json index 09b01d213..1cf2642a5 100644 --- a/modules/ticket/back/models/ticket.json +++ b/modules/ticket/back/models/ticket.json @@ -36,7 +36,7 @@ "type": "number" }, "updated": { - "type": "date", + "type": "date", "mysql": { "columnName": "created" } @@ -44,6 +44,9 @@ "isDeleted": { "type": "boolean" }, + "isSigned": { + "type": "boolean" + }, "priority": { "type": "number" }, @@ -136,4 +139,4 @@ "foreignKey": "zoneFk" } } -} \ No newline at end of file +} From 423ae852128fef840382044e056e2f704f9872b2 Mon Sep 17 00:00:00 2001 From: alexandre Date: Wed, 8 Mar 2023 12:29:09 +0100 Subject: [PATCH 2/9] refs #4632 dmsRecover deprecated --- back/model-config.json | 3 -- back/models/dms-recover.json | 37 ------------------- db/changes/231001/.gitkeep | 0 db/changes/{230801 => 231001}/00-delivery.sql | 2 + .../back/methods/ticket-dms/saveSign.js | 31 ++-------------- 5 files changed, 6 insertions(+), 67 deletions(-) delete mode 100644 back/models/dms-recover.json delete mode 100644 db/changes/231001/.gitkeep rename db/changes/{230801 => 231001}/00-delivery.sql (98%) diff --git a/back/model-config.json b/back/model-config.json index 6724db151..29676e979 100644 --- a/back/model-config.json +++ b/back/model-config.json @@ -44,9 +44,6 @@ "DmsType": { "dataSource": "vn" }, - "DmsRecover": { - "dataSource": "vn" - }, "Docuware": { "dataSource": "vn" }, diff --git a/back/models/dms-recover.json b/back/models/dms-recover.json deleted file mode 100644 index 3449347a7..000000000 --- a/back/models/dms-recover.json +++ /dev/null @@ -1,37 +0,0 @@ - -{ - "name": "DmsRecover", - "description": "Documental Managment System Recover", - "base": "VnModel", - "log": { - "showField": "ticketFk" - }, - "options": { - "mysql": { - "table": "dmsRecover" - } - }, - "properties": { - "id": { - "type": "number", - "id": true, - "description": "Identifier" - }, - "ticketFk": { - "type": "number" - }, - "sign": { - "type": "string" - }, - "created": { - "type": "date" - } - }, - "relations": { - "ticket": { - "type": "belongsTo", - "model": "Ticket", - "foreignKey": "ticketFk" - } - } -} diff --git a/db/changes/231001/.gitkeep b/db/changes/231001/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/db/changes/230801/00-delivery.sql b/db/changes/231001/00-delivery.sql similarity index 98% rename from db/changes/230801/00-delivery.sql rename to db/changes/231001/00-delivery.sql index 38c0a7971..06464b80f 100644 --- a/db/changes/230801/00-delivery.sql +++ b/db/changes/231001/00-delivery.sql @@ -1,3 +1,5 @@ +DROP TABLE `vn`.`dmsRecover`; + ALTER TABLE `vn`.`delivery` DROP FOREIGN KEY delivery_FK; ALTER TABLE `vn`.`delivery` DROP COLUMN addressFk; ALTER TABLE `vn`.`delivery` ADD ticketFk INT NOT NULL; diff --git a/modules/ticket/back/methods/ticket-dms/saveSign.js b/modules/ticket/back/methods/ticket-dms/saveSign.js index 725abfe67..9f1684539 100644 --- a/modules/ticket/back/methods/ticket-dms/saveSign.js +++ b/modules/ticket/back/methods/ticket-dms/saveSign.js @@ -51,7 +51,7 @@ module.exports = Self => { ticketFk: ticketId, longitude: args.location.Longitude, latitude: args.location.Latitude, - dated: args.signedTime + dated: args.signedTime || new Date() }, myOptions); } } @@ -67,7 +67,8 @@ module.exports = Self => { if (!ticketDms) return false; const ticket = await models.Ticket.findById(ticketId, {fields: ['isSigned']}, myOptions); - if (ticket.isSigned == true) return true; + if (ticket.isSigned == true) + return true; else await models.Dms.destroyAll({where: {reference: ticketId}}, myOptions); @@ -108,10 +109,6 @@ module.exports = Self => { await models.Ticket.uploadFile(ctxUploadFile, id, myOptions); } - // async function dmsRecover(ticketFk, sign) { - // await models.DmsRecover.create({ticketFk, sign}, myOptions); - // } - try { for (let i = 0; i < args.tickets.length; i++) { const ticketState = await models.TicketState.findOne( @@ -120,35 +117,15 @@ module.exports = Self => { }, myOptions); if (ticketState.alertLevel >= 2 && !await gestDocExists(args.tickets[i])) { - if (!args.signedTime) args.signedTime = Date.vnNew(); if (args.location) setLocation(args.tickets[i]); await createGestDoc(args.tickets[i]); - - // if (image) { - // if (!fs.existsSync(dir)) - // dmsRecover(args.tickets[i], args.signContent); - // else { - // fs.writeFile(image, args.signContent, 'base64', async function(err) { - // if (err) { - // await tx.rollback(); - // throw err.message; - // } - // }); - // } - // } else - // dmsRecover(args.tickets[i], args.signContent); - - // if (id && fileName) { - // await models.TicketDms.replaceOrCreate({ticketFk: args.tickets[i], dmsFk: id}, myOptions); await Self.rawSql(`CALL vn.ticket_setState(?, ?)`, [args.tickets[i], 'DELIVERED'], myOptions); - // await models.Dms.updateAll({id}, {file: fileName, contentType: 'image/png'}, myOptions); - // } } } if (tx) await tx.commit(); - return 'Sign uploaded correctly'; + return 'Signs uploaded correctly'; } catch (e) { if (tx) await tx.rollback(); throw e; From 7c3c3a2d66ff836ccaa2f93e9f71ca4fb4763cb1 Mon Sep 17 00:00:00 2001 From: alexandre Date: Thu, 9 Mar 2023 08:31:38 +0100 Subject: [PATCH 3/9] refs #4632 added userError --- loopback/locale/es.json | 3 +- .../back/methods/ticket-dms/saveSign.js | 25 ++++++------ .../methods/ticket-dms/specs/saveSign.spec.js | 39 ++++--------------- 3 files changed, 21 insertions(+), 46 deletions(-) diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 507cc9003..0c624ed3d 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -266,5 +266,6 @@ "There is no assigned email for this client": "No hay correo asignado para este cliente", "This locker has already been assigned": "Esta taquilla ya ha sido asignada", "Tickets with associated refunds": "No se pueden borrar tickets con abonos asociados. Este ticket está asociado al abono Nº {{id}}", - "Not exist this branch": "La rama no existe" + "Not exist this branch": "La rama no existe", + "This ticket cannot be signed because it has not been boxed": "Este ticket no puede firmarse porque no ha sido encajado" } diff --git a/modules/ticket/back/methods/ticket-dms/saveSign.js b/modules/ticket/back/methods/ticket-dms/saveSign.js index 9f1684539..60dd03be1 100644 --- a/modules/ticket/back/methods/ticket-dms/saveSign.js +++ b/modules/ticket/back/methods/ticket-dms/saveSign.js @@ -1,3 +1,5 @@ +const UserError = require('vn-loopback/util/user-error'); + module.exports = Self => { Self.remoteMethodCtx('saveSign', { description: 'Save sign', @@ -46,21 +48,17 @@ module.exports = Self => { } async function setLocation(ticketId) { - if (args.signedTime) { - await models.Delivery.create({ - ticketFk: ticketId, - longitude: args.location.Longitude, - latitude: args.location.Latitude, - dated: args.signedTime || new Date() - }, myOptions); - } + await models.Delivery.create({ + ticketFk: ticketId, + longitude: args.location.Longitude, + latitude: args.location.Latitude, + dated: args.signedTime || new Date() + }, myOptions); } async function gestDocExists(ticketId) { const ticketDms = await models.TicketDms.findOne({ - where: { - ticketFk: ticketId - }, + where: {ticketFk: ticketId}, fields: ['dmsFk'] }, myOptions); @@ -120,12 +118,13 @@ module.exports = Self => { if (args.location) setLocation(args.tickets[i]); await createGestDoc(args.tickets[i]); await Self.rawSql(`CALL vn.ticket_setState(?, ?)`, [args.tickets[i], 'DELIVERED'], myOptions); - } + } else if (ticketState.alertLevel < 2) + throw new UserError('This ticket cannot be signed because it has not been boxed'); } if (tx) await tx.commit(); - return 'Signs uploaded correctly'; + return 'Signs uploaded successfully'; } catch (e) { if (tx) await tx.rollback(); throw e; diff --git a/modules/ticket/back/methods/ticket-dms/specs/saveSign.spec.js b/modules/ticket/back/methods/ticket-dms/specs/saveSign.spec.js index b640fefb8..47902e257 100644 --- a/modules/ticket/back/methods/ticket-dms/specs/saveSign.spec.js +++ b/modules/ticket/back/methods/ticket-dms/specs/saveSign.spec.js @@ -1,57 +1,32 @@ const models = require('vn-loopback/server/server').models; -fdescribe('TicketDms saveSign()', () => { +describe('TicketDms saveSign()', () => { const FormData = require('form-data'); const data = new FormData(); let ctx = {req: { accessToken: {userId: 9}, headers: { ...data.getHeaders() - }, - on: (param, cb) => {} + } + }}; - it(`should not save sign if the ticket's alert level is lower than 2`, async() => { + it(`should throw error if the ticket's alert level is lower than 2`, async() => { const tx = await models.TicketDms.beginTransaction({}); const ticketWithOkState = 12; - + let error; try { const options = {transaction: tx}; ctx.args = {tickets: [ticketWithOkState]}; await models.TicketDms.saveSign(ctx, options); - const ticket = await models.Ticket.findById(ticketWithOkState, {fields: ['isSigned']}, options); - const ticketDms = await models.TicketDms.findOne({where: {ticketFk: ticketWithOkState}}, options); - - expect(ticket.isSigned).toEqual(false); - expect(ticketDms).toEqual(null); await tx.rollback(); } catch (e) { + error = e; await tx.rollback(); - throw e; } - }); - it(`should save sign if the ticket's alert level is greater than 2`, async() => { - const tx = await models.TicketDms.beginTransaction({}); - const ticketWithPackedState = 7; - - try { - const options = {transaction: tx}; - ctx.args = {tickets: [ticketWithPackedState]}; - - await models.TicketDms.saveSign(ctx, options); - const ticket = await models.Ticket.findById(ticketWithPackedState, {fields: ['isSigned']}, options); - const ticketDms = await models.TicketDms.findOne({where: {ticketFk: ticketWithPackedState}}, options); - - expect(ticket.isSigned).toEqual(true); - expect(ticketDms).toBeDefined(); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } + expect(error).toBeDefined(); }); }); From a99bd2577afe0f18084e527dc74324c095a0c73f Mon Sep 17 00:00:00 2001 From: alexandre Date: Thu, 16 Mar 2023 08:24:34 +0100 Subject: [PATCH 4/9] refs #4632 changed route from TicketDms to Ticket --- db/changes/231001/00-delivery.sql | 2 +- .../ticket/back/methods/{ticket-dms => ticket}/saveSign.js | 0 .../methods/{ticket-dms => ticket}/specs/saveSign.spec.js | 4 ++-- modules/ticket/back/models/ticket-dms.js | 1 - modules/ticket/back/models/ticket-methods.js | 1 + 5 files changed, 4 insertions(+), 4 deletions(-) rename modules/ticket/back/methods/{ticket-dms => ticket}/saveSign.js (100%) rename modules/ticket/back/methods/{ticket-dms => ticket}/specs/saveSign.spec.js (88%) diff --git a/db/changes/231001/00-delivery.sql b/db/changes/231001/00-delivery.sql index 06464b80f..3a9269183 100644 --- a/db/changes/231001/00-delivery.sql +++ b/db/changes/231001/00-delivery.sql @@ -8,7 +8,7 @@ ALTER TABLE `vn`.`delivery` ADD CONSTRAINT delivery_ticketFk_FK FOREIGN KEY (`ti DELETE FROM `salix`.`ACL` WHERE `property` = 'saveSign'; INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalId`) VALUES - ('TicketDms','saveSign','WRITE','ALLOW','employee'); + ('Ticket','saveSign','WRITE','ALLOW','employee'); DROP PROCEDURE IF EXISTS vn.route_getTickets; diff --git a/modules/ticket/back/methods/ticket-dms/saveSign.js b/modules/ticket/back/methods/ticket/saveSign.js similarity index 100% rename from modules/ticket/back/methods/ticket-dms/saveSign.js rename to modules/ticket/back/methods/ticket/saveSign.js diff --git a/modules/ticket/back/methods/ticket-dms/specs/saveSign.spec.js b/modules/ticket/back/methods/ticket/specs/saveSign.spec.js similarity index 88% rename from modules/ticket/back/methods/ticket-dms/specs/saveSign.spec.js rename to modules/ticket/back/methods/ticket/specs/saveSign.spec.js index 47902e257..6b532a5d1 100644 --- a/modules/ticket/back/methods/ticket-dms/specs/saveSign.spec.js +++ b/modules/ticket/back/methods/ticket/specs/saveSign.spec.js @@ -1,6 +1,6 @@ const models = require('vn-loopback/server/server').models; -describe('TicketDms saveSign()', () => { +describe('Ticket saveSign()', () => { const FormData = require('form-data'); const data = new FormData(); let ctx = {req: { @@ -19,7 +19,7 @@ describe('TicketDms saveSign()', () => { const options = {transaction: tx}; ctx.args = {tickets: [ticketWithOkState]}; - await models.TicketDms.saveSign(ctx, options); + await models.Ticket.saveSign(ctx, options); await tx.rollback(); } catch (e) { diff --git a/modules/ticket/back/models/ticket-dms.js b/modules/ticket/back/models/ticket-dms.js index 13d960270..9bceaae6e 100644 --- a/modules/ticket/back/models/ticket-dms.js +++ b/modules/ticket/back/models/ticket-dms.js @@ -2,7 +2,6 @@ const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { require('../methods/ticket-dms/removeFile')(Self); - require('../methods/ticket-dms/saveSign')(Self); Self.rewriteDbError(function(err) { if (err.code === 'ER_DUP_ENTRY') diff --git a/modules/ticket/back/models/ticket-methods.js b/modules/ticket/back/models/ticket-methods.js index 73df0579c..3992e7307 100644 --- a/modules/ticket/back/models/ticket-methods.js +++ b/modules/ticket/back/models/ticket-methods.js @@ -39,4 +39,5 @@ module.exports = function(Self) { require('../methods/ticket/isRoleAdvanced')(Self); require('../methods/ticket/collectionLabel')(Self); require('../methods/ticket/expeditionPalletLabel')(Self); + require('../methods/ticket/saveSign')(Self); }; From 6e2269b428c0e847b50630f0271d9be08523cb92 Mon Sep 17 00:00:00 2001 From: alexandre Date: Thu, 16 Mar 2023 09:04:57 +0100 Subject: [PATCH 5/9] refs #4632 removed alert level id from code --- modules/ticket/back/methods/ticket/saveSign.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/ticket/back/methods/ticket/saveSign.js b/modules/ticket/back/methods/ticket/saveSign.js index 60dd03be1..177cb9b46 100644 --- a/modules/ticket/back/methods/ticket/saveSign.js +++ b/modules/ticket/back/methods/ticket/saveSign.js @@ -114,12 +114,17 @@ module.exports = Self => { fields: ['alertLevel'] }, myOptions); - if (ticketState.alertLevel >= 2 && !await gestDocExists(args.tickets[i])) { + const boxedAlertLevel = await models.AlertLevel.findOne({where: {code: 'PACKED'}, + fields: ['id'] + }, myOptions); + + if (ticketState.alertLevel < boxedAlertLevel.id) + throw new UserError('This ticket cannot be signed because it has not been boxed'); + else if (!await gestDocExists(args.tickets[i])) { if (args.location) setLocation(args.tickets[i]); await createGestDoc(args.tickets[i]); await Self.rawSql(`CALL vn.ticket_setState(?, ?)`, [args.tickets[i], 'DELIVERED'], myOptions); - } else if (ticketState.alertLevel < 2) - throw new UserError('This ticket cannot be signed because it has not been boxed'); + } } if (tx) await tx.commit(); From a0be5c50fcffdffc91f4924b0987fea9b52b8399 Mon Sep 17 00:00:00 2001 From: alexandre Date: Thu, 16 Mar 2023 09:07:19 +0100 Subject: [PATCH 6/9] refs #4632 changed packed from boxed --- modules/ticket/back/methods/ticket/saveSign.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ticket/back/methods/ticket/saveSign.js b/modules/ticket/back/methods/ticket/saveSign.js index 177cb9b46..c3d6e4baa 100644 --- a/modules/ticket/back/methods/ticket/saveSign.js +++ b/modules/ticket/back/methods/ticket/saveSign.js @@ -114,11 +114,11 @@ module.exports = Self => { fields: ['alertLevel'] }, myOptions); - const boxedAlertLevel = await models.AlertLevel.findOne({where: {code: 'PACKED'}, + const packedAlertLevel = await models.AlertLevel.findOne({where: {code: 'PACKED'}, fields: ['id'] }, myOptions); - if (ticketState.alertLevel < boxedAlertLevel.id) + if (ticketState.alertLevel < packedAlertLevel.id) throw new UserError('This ticket cannot be signed because it has not been boxed'); else if (!await gestDocExists(args.tickets[i])) { if (args.location) setLocation(args.tickets[i]); From 60162fe71fe4ea9a1c5a5c1644acc2acbf09431b Mon Sep 17 00:00:00 2001 From: alexandre Date: Thu, 16 Mar 2023 10:30:53 +0100 Subject: [PATCH 7/9] refs #4632 removed return --- modules/ticket/back/methods/ticket/saveSign.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/ticket/back/methods/ticket/saveSign.js b/modules/ticket/back/methods/ticket/saveSign.js index c3d6e4baa..79ed01361 100644 --- a/modules/ticket/back/methods/ticket/saveSign.js +++ b/modules/ticket/back/methods/ticket/saveSign.js @@ -128,8 +128,6 @@ module.exports = Self => { } if (tx) await tx.commit(); - - return 'Signs uploaded successfully'; } catch (e) { if (tx) await tx.rollback(); throw e; From 668fa733869f9c579f36674b81af704b38c16bfc Mon Sep 17 00:00:00 2001 From: alexandre Date: Thu, 16 Mar 2023 10:32:00 +0100 Subject: [PATCH 8/9] refs #4632 deleted return in definition --- modules/ticket/back/methods/ticket/saveSign.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/ticket/back/methods/ticket/saveSign.js b/modules/ticket/back/methods/ticket/saveSign.js index 79ed01361..ab1c32d1b 100644 --- a/modules/ticket/back/methods/ticket/saveSign.js +++ b/modules/ticket/back/methods/ticket/saveSign.js @@ -23,10 +23,6 @@ module.exports = Self => { description: 'The signed time' } ], - returns: { - type: 'string', - root: true - }, http: { path: `/saveSign`, verb: 'POST' From 1d697e1ac577e0678f380691a7dc08bd47327823 Mon Sep 17 00:00:00 2001 From: robert Date: Fri, 17 Mar 2023 08:46:01 +0100 Subject: [PATCH 9/9] refs #4357 add operator model --- db/changes/231201/00-ACL.sql | 3 + db/changes/231201/00-operator.sql | 159 +++++++++++++++++++++++ db/dump/fixtures.sql | 4 + modules/worker/back/model-config.json | 3 + modules/worker/back/models/operator.json | 44 +++++++ 5 files changed, 213 insertions(+) create mode 100644 db/changes/231201/00-ACL.sql create mode 100644 db/changes/231201/00-operator.sql create mode 100644 modules/worker/back/models/operator.json diff --git a/db/changes/231201/00-ACL.sql b/db/changes/231201/00-ACL.sql new file mode 100644 index 000000000..47a818977 --- /dev/null +++ b/db/changes/231201/00-ACL.sql @@ -0,0 +1,3 @@ +INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) +VALUES ('Operator', '*', 'READ', 'ALLOW', 'ROLE', 'employee'), + ('Operator', '*', 'WRITE', 'ALLOW', 'ROLE', 'employee'); diff --git a/db/changes/231201/00-operator.sql b/db/changes/231201/00-operator.sql new file mode 100644 index 000000000..9b7815b41 --- /dev/null +++ b/db/changes/231201/00-operator.sql @@ -0,0 +1,159 @@ +ALTER TABLE `vn`.`operator` ADD sectorFk int(11) NULL; +ALTER TABLE `vn`.`operator` ADD labelerFk tinyint(3) unsigned NULL; +ALTER TABLE `vn`.`operator` ADD CONSTRAINT operator_FK_5 FOREIGN KEY (labelerFk) REFERENCES `vn`.`printer`(id) ON DELETE CASCADE ON UPDATE CASCADE; + +UPDATE `vn`.`operator` o +JOIN (SELECT id, sectorFk, labelerFk + FROM `vn`.`worker`) sub ON sub.id = o.workerFk + SET o.sectorFk = sub.sectorFk, + o.labelerFk = sub.labelerFk; + +DELIMITER $$ +CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`collection_printSticker`( + vSelf INT, + vLabelCount INT +) +BEGIN +/** + * Prints a yellow label from a collection or a ticket + * + * @param vSelf collection or ticket + * @param vLabelCount number of times the collection has been printed + */ + DECLARE vPrintArgs JSON DEFAULT JSON_OBJECT('collectionOrTicketFk', vSelf); + + IF vLabelCount IS NULL THEN + INSERT INTO ticketTrolley + SELECT ticketFk, 1 + FROM ticketCollection + WHERE collectionFk = vSelf + ON DUPLICATE KEY UPDATE labelCount = labelCount + 1; + ELSE + SET vPrintArgs = JSON_MERGE_PATCH(vPrintArgs, JSON_OBJECT('labelCount', vLabelCount)); + END IF; + + CALL report_print( + 'LabelCollection', + (SELECT o.labelerFk FROM operator o WHERE o.workerFk = account.myUser_getId()), + account.myUser_getId(), + vPrintArgs, + 'high' + ); +END$$ +DELIMITER ; + +DELIMITER $$ +CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`expeditionPallet_printLabel`(vSelf INT) +BEGIN +/** + * Calls the report_print procedure and passes it + * the necessary parameters for printing. + * + * @param vSelf expeditioPallet id. + */ + DECLARE vPrinterFk INT; + DECLARE vUserFk INT DEFAULT account.myUser_getId(); + + SELECT o.labelerFk INTO vPrinterFk + FROM operator o + WHERE o.workerFk = vUserFk; + + CALL vn.report_print( + 'LabelPalletExpedition', + vPrinterFk, + account.myUser_getId(), + JSON_OBJECT('palletFk', vSelf, 'userFk', vUserFk), + 'high' + ); + + UPDATE vn.expeditionPallet + SET isPrint = TRUE + WHERE id = vSelf; +END$$ +DELIMITER ; + +DELIMITER $$ +CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`itemShelving_getAlternatives`(vShelvingFk VARCHAR(10)) +BEGIN +/** + * Devuelve un listado de posibles ubicaciones alternativas a ubicar los item de la matricula + * del carro que se le ha pasado. + * + * @param vShelvingFk matricula del carro + */ + SELECT is2.id,is2.shelvingFk , p.code, is2.itemFk , is2.visible, p.pickingOrder + FROM itemShelving is2 + JOIN shelving sh ON sh.code = is2.shelvingFk + JOIN parking p ON p.id = sh.parkingFk + JOIN sector s ON s.id = p.sectorFk + LEFT JOIN operator o ON o.sectorFk = s.id + LEFT JOIN worker w ON w.sectorFk = s.id AND w.id = account.myUser_getId() + JOIN warehouse wh ON wh.id = s.warehouseFk + JOIN itemShelving is3 ON is3.itemFk = is2.itemFk AND is3.shelvingFk = vShelvingFk COLLATE utf8_unicode_ci + WHERE is2.shelvingFk <> vShelvingFk COLLATE utf8_unicode_ci + GROUP BY is2.id + ORDER BY p.pickingOrder DESC; +END$$ +DELIMITER ; + +DELIMITER $$ +CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`operator_beforeInsert` + BEFORE INSERT ON `operator` + FOR EACH ROW +BEGIN + CALL vn.printer_checkSector(NEW.labelerFk, NEW.sectorFk); +END$$ +DELIMITER ; + +DELIMITER $$ +CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`operator_beforeUpdate` + BEFORE UPDATE ON `operator` + FOR EACH ROW +BEGIN + IF NOT (NEW.labelerFk <=> OLD.labelerFk AND NEW.sectorFk <=> OLD.sectorFk) THEN + CALL vn.printer_checkSector(NEW.labelerFk, NEW.sectorFk); + END IF; +END$$ +DELIMITER ; + +DELIMITER $$ +CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`worker_beforeUpdate` + BEFORE UPDATE ON `worker` + FOR EACH ROW +BEGIN + IF NOT (NEW.labelerFk <=> OLD.labelerFk AND NEW.sectorFk <=> OLD.sectorFk) THEN + CALL vn.printer_checkSector(NEW.labelerFk, NEW.sectorFk); + + INSERT IGNORE INTO vn.operator (workerFk) + VALUES (NEW.id); + + UPDATE operator + SET labelerFk = NEW.labelerFk, + sectorFk = NEW.sectorFk + WHERE workerFk = NEW.id; + END IF; +END$$ +DELIMITER ; + +CREATE OR REPLACE DEFINER=`root`@`localhost` + SQL SECURITY DEFINER + VIEW `vn`.`operatorWorkerCode` +AS SELECT `o`.`workerFk` AS `workerFk`, + concat(`w`.`firstName`, ' ', `w`.`lastName`) AS `fullName`, + `w`.`code` AS `code`, + `o`.`numberOfWagons` AS `numberOfWagons` +FROM ( + ( + `vn`.`worker` `w` + JOIN `vn`.`operator` `o` ON(`o`.`workerFk` = `w`.`id`) + ) + JOIN `vn`.`sector` `s` ON(`o`.`sectorFk` = `s`.`id`) + ) +WHERE `o`.`sectorFk` IS NOT NULL + AND `s`.`code` IN ( + 'H2', + 'H2', + 'PEQUES_H', + 'ALTILLO COMP', + 'ALTILLO ARTI' + ) \ No newline at end of file diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 3ab34e1d5..c4df3e84f 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -173,6 +173,10 @@ INSERT INTO `vn`.`sector`(`id`, `description`, `warehouseFk`, `isPreviousPrepare (1, 'First sector', 1, 1, 'FIRST'), (2, 'Second sector', 2, 0, 'SECOND'); +INSERT INTO `vn`.`operator` (`workerFk`, `numberOfWagons`, `trainFk`, `itemPackingTypeFk`, `warehouseFk`, `sectorFk`, `labelerFk`) + VALUES ('1106', '1', '1', 'H', '1', '1', '1'), + ('1107', '1', '1', 'V', '1', '2', '1'); + INSERT INTO `vn`.`printer` (`id`, `name`, `path`, `isLabeler`, `sectorFk`, `ipAddress`) VALUES (1, 'printer1', 'path1', 0, 1 , NULL), diff --git a/modules/worker/back/model-config.json b/modules/worker/back/model-config.json index 8079bd165..63fc65827 100644 --- a/modules/worker/back/model-config.json +++ b/modules/worker/back/model-config.json @@ -94,6 +94,9 @@ }, "WorkerTimeControlMail": { "dataSource": "vn" + }, + "Operator": { + "dataSource": "vn" } } diff --git a/modules/worker/back/models/operator.json b/modules/worker/back/models/operator.json new file mode 100644 index 000000000..db8a8c451 --- /dev/null +++ b/modules/worker/back/models/operator.json @@ -0,0 +1,44 @@ +{ + "name": "Operator", + "base": "VnModel", + "options": { + "mysql": { + "table": "operator" + } + }, + "properties": { + "workerFk": { + "id": true, + "type": "number", + "required": true + }, + "numberOfWagons": { + "type": "number" + }, + "trainFk": { + "type": "number", + "required": true + }, + "itemPackingTypeFk": { + "type": "string", + "required": true + }, + "warehouseFk": { + "type": "number", + "required": true + }, + "sectorFk ": { + "type": "number" + }, + "labelerFk ": { + "type": "number" + } + }, + "relations": { + "sector": { + "type": "belongsTo", + "model": "Sector", + "foreignKey": "sectorFk" + } + } +} \ No newline at end of file