refs #4632 saveSign refactored, working on tests, check if dmsRecover is needed
gitea/salix/pipeline/head There was a failure building this commit Details

This commit is contained in:
Alexandre Riera 2023-02-24 14:41:02 +01:00
parent 335f259eba
commit 2a4d41cbca
10 changed files with 350 additions and 224 deletions

View File

@ -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;
}
};
};

View File

@ -44,6 +44,9 @@
"DmsType": {
"dataSource": "vn"
},
"DmsRecover": {
"dataSource": "vn"
},
"Docuware": {
"dataSource": "vn"
},

View File

@ -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"
}
}
}

View File

@ -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"
}
}
}

View File

@ -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;

View File

@ -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 ;

View File

@ -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;
}
};
};

View File

@ -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;
}
});
});

View File

@ -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')

View File

@ -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"
}
}
}
}