Merge branch 'dev' into 5640-fixtures_clientSocialNameUPPER
gitea/salix/pipeline/pr-dev This commit looks good Details

This commit is contained in:
Carlos Satorres 2024-02-27 08:31:43 +00:00
commit c5e66f1862
30 changed files with 494 additions and 98 deletions

View File

@ -2409,7 +2409,8 @@ INSERT INTO `vn`.`dmsType`(`id`, `name`, `readRoleFk`, `writeRoleFk`, `code`)
(17, 'cmr', 1, 1, 'cmr'),
(18, 'dua', NULL, NULL, 'dua'),
(19, 'inmovilizado', NULL, NULL, 'fixedAssets'),
(20, 'Reclamación', 1, 1, 'claim');
(20, 'Reclamación', 1, 1, 'claim'),
(21, 'Entrada', 1, 1, 'entry');
INSERT INTO `vn`.`dms`(`id`, `dmsTypeFk`, `file`, `contentType`, `workerFk`, `warehouseFk`, `companyFk`, `hardCopyNumber`, `hasFile`, `reference`, `description`, `created`)
VALUES
@ -2420,7 +2421,8 @@ INSERT INTO `vn`.`dms`(`id`, `dmsTypeFk`, `file`, `contentType`, `workerFk`, `wa
(5, 5, '5.txt', 'text/plain', 5, 1, 442, NULL, TRUE, 'travel: 1', 'dmsForThermograph', util.VN_CURDATE()),
(6, 5, '6.txt', 'text/plain', 5, 1, 442, NULL, TRUE, 'NotExists', 'DoesNotExists', util.VN_CURDATE()),
(7, 20, '7.jpg', 'image/jpeg', 9, 1, 442, NULL, FALSE, '1', 'TICKET ID DEL CLIENTE BRUCE WAYNE ID 1101', util.VN_CURDATE()),
(8, 20, '8.mp4', 'video/mp4', 9, 1, 442, NULL, FALSE, '1', 'TICKET ID DEL CLIENTE BRUCE WAYNE ID 1101', util.VN_CURDATE());
(8, 20, '8.mp4', 'video/mp4', 9, 1, 442, NULL, FALSE, '1', 'TICKET ID DEL CLIENTE BRUCE WAYNE ID 1101', util.VN_CURDATE()),
(9, 21, '7.jpg', 'image/jpeg', 9, 1, 442, NULL, FALSE, '1', 'ENTRADA ID 1', util.VN_CURDATE());
INSERT INTO `vn`.`claimDms`(`claimFk`, `dmsFk`)
VALUES
@ -3064,6 +3066,10 @@ INSERT INTO `vn`.`clientSms` (`id`, `clientFk`, `smsFk`, `ticketFk`)
(13, 1101, 1, NULL),
(14, 1101, 4, 27);
INSERT INTO `vn`.`entryDms`(`entryFk`, `dmsFk`, `editorFk`)
VALUES
(1, 9, 9);
INSERT INTO `vn`.`cmr` (id,truckPlate,observations,senderInstruccions,paymentInstruccions,specialAgreements,companyFk,addressToFk,addressFromFk,supplierFk,packagesList,merchandiseDetail,state)
VALUES (1,'123456A','Lorem ipsum dolor sit amet','Lorem ipsum dolor sit amet','Lorem ipsum dolor sit amet','Lorem ipsum dolor sit amet',442,1,2,1,'Lorem ipsum dolor sit amet','Lorem ipsum dolor sit amet','Lorem ipsum dolor sit amet'),
(2,'123456N','Lorem ipsum dolor sit amet','Lorem ipsum dolor sit amet','Lorem ipsum dolor sit amet','Lorem ipsum dolor sit amet',69,3,4,2,'Lorem ipsum dolor sit amet','Lorem ipsum dolor sit amet','Lorem ipsum dolor sit amet'),

View File

@ -38,7 +38,8 @@ BEGIN
DELETE FROM saleTracking WHERE created < vOneYearAgo;
DELETE FROM ticketTracking WHERE created < v18Month;
DELETE tobs FROM ticketObservation tobs
JOIN ticket t ON tobs.ticketFk = t.id WHERE t.shipped < TIMESTAMPADD(YEAR,-2,util.VN_CURDATE());
JOIN ticket t ON tobs.ticketFk = t.id
WHERE t.shipped < v5Years;
DELETE sc.* FROM saleCloned sc JOIN sale s ON s.id = sc.saleClonedFk JOIN ticket t ON t.id = s.ticketFk WHERE t.shipped < vOneYearAgo;
DELETE FROM sharingCart where ended < vDateShort;
DELETE FROM sharingClient where ended < vDateShort;

View File

@ -75,7 +75,7 @@ BEGIN
SET vDated = DATE(vTimed);
SELECT IF(pc.code = 'driveCE',
SELECT IF(pc.code = 'driverCE',
wc.dayBreakDriver,
wc.dayBreak),
wc.shortWeekBreak,

View File

@ -23,6 +23,12 @@ BEGIN
IF vOldBusinessFk IS NULL THEN
CALL account.account_enable(vSelf);
UPDATE client c
JOIN payMethod pm ON pm.code = 'bankDraft'
SET c.payMethodFk = pm.id
WHERE c.id = vSelf
AND c.iban;
END IF;
END$$
DELIMITER ;

View File

@ -0,0 +1,12 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`entryDms_afterDelete`
AFTER DELETE ON `entryDms`
FOR EACH ROW
BEGIN
INSERT INTO entryLog
SET `action` = 'delete',
`changedModel` = 'EntryDms',
`changedModelId` = OLD.entryFk,
`userFk` = account.myUser_getId();
END$$
DELIMITER ;

View File

@ -0,0 +1,8 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`entryDms_beforeInsert`
BEFORE INSERT ON `entryDms`
FOR EACH ROW
BEGIN
SET NEW.editorFk = account.myUser_getId();
END$$
DELIMITER ;

View File

@ -0,0 +1,8 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`entryDms_beforeUpdate`
BEFORE UPDATE ON `entryDms`
FOR EACH ROW
BEGIN
SET NEW.editorFk = account.myUser_getId();
END$$
DELIMITER ;

View File

@ -0,0 +1,12 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`supplierDms_afterDelete`
AFTER DELETE ON `supplierDms`
FOR EACH ROW
BEGIN
INSERT INTO clientLog
SET `action` = 'delete',
`changedModel` = 'supplierDms',
`changedModelId` = OLD.dmsFk,
`userFk` = account.myUser_getId();
END$$
DELIMITER ;

View File

@ -0,0 +1,8 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`supplierDms_beforeInsert`
BEFORE INSERT ON `supplierDms`
FOR EACH ROW
BEGIN
SET NEW.editorFk = account.myUser_getId();
END$$
DELIMITER ;

View File

@ -0,0 +1,8 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`supplierDms_beforeUpdate`
BEFORE UPDATE ON `supplierDms`
FOR EACH ROW
BEGIN
SET NEW.editorFk = account.myUser_getId();
END$$
DELIMITER ;

View File

@ -3,6 +3,8 @@ CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`travel_beforeUpdate`
BEFORE UPDATE ON `travel`
FOR EACH ROW
BEGIN
DECLARE vHasAnyInvoiceBooked BOOL;
SET NEW.editorFk = account.myUser_getId();
IF NOT (NEW.landed <=> OLD.landed)
@ -17,5 +19,18 @@ BEGIN
IF NOT (NEW.warehouseInFk <=> OLD.warehouseInFk) THEN
CALL travel_checkWarehouseIsFeedStock(NEW.warehouseInFk);
END IF;
IF NOT (NEW.awbFk <=> OLD.awbFk)THEN
SELECT COUNT(*) INTO vHasAnyInvoiceBooked
FROM travel t
JOIN entry e ON e.travelFk = t.id
JOIN invoiceIn ii ON ii.id = e.invoiceInFk
WHERE t.id = NEW.id
AND ii.isBooked;
IF vHasAnyInvoiceBooked THEN
CALL util.throw('The travel has entries with booked invoices');
END IF;
END IF;
END$$
DELIMITER ;

View File

@ -25,11 +25,6 @@ proc: BEGIN
DELETE FROM Movimientos_mark WHERE odbc_date < vDate;
DELETE FROM Splits WHERE Fecha < vDate18;
DELETE tobs
FROM ticket_observation tobs
JOIN Tickets t ON tobs.Id_Ticket = t.Id_Ticket
WHERE t.Fecha < vDate;
DELETE tobs
FROM movement_label tobs
JOIN Movimientos m ON tobs.Id_Movimiento = m.Id_Movimiento

View File

@ -0,0 +1,15 @@
CREATE OR REPLACE TABLE `vn`.`entryDms` (
`entryFk` int(11) NOT NULL,
`dmsFk` int(11) NOT NULL,
`editorFk` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`entryFk`,`dmsFk`),
KEY `gestdoc_id` (`dmsFk`),
KEY `entryDms_editor` (`editorFk`),
CONSTRAINT `entryDms_dms` FOREIGN KEY (`dmsFk`) REFERENCES `dms` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `entryDms_editor` FOREIGN KEY (`editorFk`) REFERENCES `account`.`user` (`id`),
CONSTRAINT `entryDms_entry` FOREIGN KEY (`entryFk`) REFERENCES `entry` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('EntryDms', '*', '*', 'ALLOW', 'ROLE', 'employee');

View File

@ -0,0 +1,2 @@
INSERT INTO `vn`.`dmsType` (code, name, path__, writeRoleFk, readRoleFk, monthToDelete)
VALUES('entry', 'Entrada', '', 1, 1, NULL);

View File

@ -0,0 +1,6 @@
ALTER TABLE vn.professionalCategory DROP COLUMN IF EXISTS code;
ALTER TABLE IF EXISTS vn.professionalCategory ADD COLUMN code VARCHAR(25) UNIQUE DEFAULT NULL;
UPDATE vn.professionalCategory
SET code = 'driverCE'
WHERE name = 'Conductor C + E';

View File

@ -0,0 +1,9 @@
ALTER TABLE `vn`.`supplierDms`
MODIFY COLUMN supplierFk int(10) unsigned NOT NULL,
ADD editorFk INT UNSIGNED NULL,
ADD CONSTRAINT user_Fk FOREIGN KEY (editorFk) REFERENCES account.`user`(id),
ADD CONSTRAINT dms_FK FOREIGN KEY (dmsFk) REFERENCES vn.dms(id) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT supplier_Fk FOREIGN KEY (supplierFk) REFERENCES vn.supplier(id) ON UPDATE CASCADE;
ALTER TABLE `supplierLog`
MODIFY COLUMN `changedModel` ENUM('Supplier','SupplierAddress','SupplierAccount','SupplierContact','SupplierDms') NOT NULL DEFAULT 'Supplier';

View File

@ -0,0 +1,5 @@
DELETE FROM vn.entryObservation
WHERE observationTypeFk IS NULL;
ALTER TABLE vn.entryObservation
MODIFY COLUMN observationTypeFk tinyint(3) unsigned NOT NULL;

View File

@ -336,6 +336,7 @@
"Incorrect pin": "Pin incorrecto",
"You already have the mailAlias": "Ya tienes este alias de correo",
"The alias cant be modified": "Este alias de correo no puede ser modificado",
"this warehouse has not dms": "El Almacén no acepta documentos",
"This ticket already has a cmr saved": "Este ticket ya tiene un cmr guardado",
"Name should be uppercase": "El nombre debe ir en mayúscula",
"Bank entity must be specified": "La entidad bancaria es obligatoria",

View File

@ -103,6 +103,20 @@
"video/mp4"
]
},
"entryStorage": {
"name": "entryStorage",
"connector": "loopback-component-storage",
"provider": "filesystem",
"root": "./storage/dms",
"maxFileSize": "31457280",
"allowedContentTypes": [
"image/png",
"image/jpeg",
"image/jpg",
"image/webp",
"video/mp4"
]
},
"accessStorage": {
"name": "accessStorage",
"connector": "loopback-component-storage",

View File

@ -0,0 +1,59 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethodCtx('downloadFile', {
description: 'Get the entry file',
accessType: 'READ',
accepts: [
{
arg: 'id',
type: 'Number',
description: 'The document id',
http: {source: 'path'}
}
],
returns: [
{
arg: 'body',
type: 'file',
root: true
},
{
arg: 'Content-Type',
type: 'String',
http: {target: 'header'}
},
{
arg: 'Content-Disposition',
type: 'String',
http: {target: 'header'}
}
],
http: {
path: `/:id/downloadFile`,
verb: 'GET'
}
});
Self.downloadFile = async function(ctx, id) {
const models = Self.app.models;
const EntryContainer = models.EntryContainer;
const dms = await models.Dms.findById(id);
const pathHash = EntryContainer.getHash(dms.id);
try {
await EntryContainer.getFile(pathHash, dms.file);
} catch (e) {
if (e.code != 'ENOENT')
throw e;
const error = new UserError(`File doesn't exists`);
error.statusCode = 404;
throw error;
}
const stream = EntryContainer.downloadStream(pathHash, dms.file);
return [stream, dms.contentType, `filename="${dms.file}"`];
};
};

View File

@ -0,0 +1,53 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethodCtx('removeFile', {
description: 'Removes a entry document',
accessType: 'WRITE',
accepts: {
arg: 'id',
type: 'number',
description: 'The document id',
http: {source: 'path'}
},
returns: {
type: 'object',
root: true
},
http: {
path: `/:id/removeFile`,
verb: 'POST'
}
});
Self.removeFile = async(ctx, id, options) => {
const myOptions = {};
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const targetEntryDms = await Self.findById(id, null, myOptions);
const targetDms = await Self.app.models.Dms.removeFile(ctx, targetEntryDms.dmsFk, myOptions);
if (!targetDms)
throw new UserError('Try again');
const entryDmsDestroyed = await targetEntryDms.destroy(myOptions);
if (tx) await tx.commit();
return entryDmsDestroyed;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

@ -0,0 +1,86 @@
module.exports = Self => {
Self.remoteMethodCtx('uploadFile', {
description: 'Upload and attach a file',
accessType: 'WRITE',
accepts: [{
arg: 'id',
type: 'number',
description: 'The entry id',
http: {source: 'path'}
},
{
arg: 'warehouseId',
type: 'number',
description: 'The warehouse id',
required: true
},
{
arg: 'companyId',
type: 'number',
description: 'The company id',
required: true
},
{
arg: 'dmsTypeId',
type: 'number',
description: 'The dms type id',
required: true
},
{
arg: 'reference',
type: 'string',
required: true
},
{
arg: 'description',
type: 'string',
required: true
},
{
arg: 'hasFile',
type: 'boolean',
description: 'True if has an attached file',
required: true
}],
returns: {
type: 'object',
root: true
},
http: {
path: `/:id/uploadFile`,
verb: 'POST'
}
});
Self.uploadFile = async(ctx, id, options) => {
const {Dms, EntryDms} = 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;
}
try {
const uploadedFiles = await Dms.uploadFile(ctx, myOptions);
const promises = uploadedFiles.map(dms => EntryDms.create({
entryFk: id,
dmsFk: dms.id
}, myOptions));
await Promise.all(promises);
if (tx) await tx.commit();
return uploadedFiles;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

@ -2,6 +2,12 @@
"Entry": {
"dataSource": "vn"
},
"EntryDms": {
"dataSource": "vn"
},
"EntryContainer": {
"dataSource": "entryStorage"
},
"Buy": {
"dataSource": "vn"
},

View File

@ -0,0 +1,10 @@
{
"name": "EntryContainer",
"base": "Container",
"acls": [{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}]
}

View File

@ -0,0 +1,13 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
require('../methods/entry-dms/removeFile')(Self);
require('../methods/entry-dms/downloadFile')(Self);
require('../methods/entry-dms/uploadFile')(Self);
Self.rewriteDbError(function(err) {
if (err.code === 'ER_DUP_ENTRY')
return new UserError('This document already exists on this entry');
return err;
});
};

View File

@ -0,0 +1,36 @@
{
"name": "EntryDms",
"base": "VnModel",
"mixins": {
"Loggable": true
},
"options": {
"mysql": {
"table": "entryDms"
}
},
"allowedContentTypes": [
"image/png",
"image/jpeg",
"image/jpg"
],
"properties": {
"dmsFk": {
"type": "number",
"id": true,
"required": true
}
},
"relations": {
"entry": {
"type": "belongsTo",
"model": "Entry",
"foreignKey": "entryFk"
},
"dms": {
"type": "belongsTo",
"model": "Dms",
"foreignKey": "dmsFk"
}
}
}

View File

@ -48,23 +48,18 @@ module.exports = Self => {
if (!recipient)
throw new UserError('There is no assigned email for this client');
const dms = await models.TicketDms.findOne({
where: {ticketFk: ticketId},
include: [{
relation: 'dms',
fields: ['id'],
scope: {
relation: 'dmsType',
scope: {
where: {code: 'cmr'}
}
}
}]
}, myOptions);
const dms = await Self.rawSql(`
SELECT d.id
FROM ticketDms td
JOIN dms d ON d.id = td.dmsFk
JOIN dmsType dt ON dt.id = d.dmsTypeFk
WHERE td.ticketFk = ?
AND dt.code = 'cmr'
`, [ticketId]);
if (!dms) throw new UserError('Cmr file does not exist');
if (!dms.length) throw new UserError('Cmr file does not exist');
const response = await models.Dms.downloadFile(ctx, dms.id);
const response = await models.Dms.downloadFile(ctx, dms[0].id);
const email = new Email('cmr', {
ticketId,

View File

@ -42,18 +42,15 @@ module.exports = Self => {
const ticket = await models.Ticket.findById(ticketId, myOptions);
if (ticket.cmrFk) {
const hasDmsCmr = await models.TicketDms.findOne({
where: {ticketFk: ticketId},
include: {
relation: 'dms',
fields: ['dmsFk'],
scope: {
where: {dmsTypeFk: dmsTypeCmr.id}
}
}
}, myOptions);
const hasDmsCmr = await Self.rawSql(`
SELECT d.id
FROM ticketDms td
JOIN dms d ON d.id = td.dmsFk
WHERE td.ticketFk = ?
AND d.dmsTypeFk = ?
`, [ticketId, dmsTypeCmr.id]);
if (hasDmsCmr?.dms())
if (hasDmsCmr.length)
throw new UserError('This ticket already has a cmr saved');
ctx.args.id = ticket.cmrFk;

View File

@ -33,8 +33,10 @@ module.exports = Self => {
const models = Self.app.models;
const myOptions = {userId: ctx.req.accessToken.userId};
let tx;
let ticket;
let dms;
let gestDocCreated = false;
let isSignUploaded;
let externalTickets = [];
if (typeof options == 'object')
Object.assign(myOptions, options);
@ -44,6 +46,11 @@ module.exports = Self => {
myOptions.transaction = tx;
}
const dmsTypeTicket = await models.DmsType.findOne({
where: {code: 'ticket'},
fields: ['id']
});
async function setLocation(ticketId) {
await models.Delivery.create({
ticketFk: ticketId,
@ -53,102 +60,105 @@ module.exports = Self => {
}, myOptions);
}
async function gestDocExists(ticketId) {
const ticketDms = await models.TicketDms.findOne({
where: {ticketFk: ticketId},
fields: ['dmsFk']
}, myOptions);
async function hasSignDms(ticketId) {
const hasTicketDms = await Self.rawSql(`
SELECT d.id
FROM ticketDms td
JOIN dms d ON d.id = td.dmsFk
WHERE td.ticketFk = ?
AND d.dmsTypeFk = ?
`, [ticketId, dmsTypeTicket.id], 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;
if (hasTicketDms.length) return true;
}
async function createGestDoc(id) {
const ticket = await models.Ticket.findById(id,
{
include: [
{
relation: 'warehouse',
scope: {
fields: ['id']
async function createGestDoc() {
const ctxUploadFile = Object.assign({}, ctx);
ctxUploadFile.args = {
warehouseId: ticket.warehouseFk,
companyId: ticket.companyFk,
dmsTypeId: dmsTypeTicket.id,
reference: ticket.id,
description: `Firma del cliente - Ruta ${ticket.route().id}`,
hasFile: true
};
dms = await models.Dms.uploadFile(ctxUploadFile, myOptions);
// Si se ha subido ya la firma, no se vuelve a subir, ya que si no
// da un error de deadlock en la db
isSignUploaded = true;
}
}, {
relation: 'client',
try {
for (const ticketId of tickets) {
ticket = await models.Ticket.findById(ticketId, {
include: [{
relation: 'address',
scope: {
fields: ['name']
include: {
relation: 'province',
scope: {
include: {
relation: 'country',
scope: {
fields: ['code']
}
}
}
}
}
}, {
relation: 'route',
scope: {
fields: ['id']
}
}
]
}]
}, myOptions);
const dmsType = await models.DmsType.findOne({where: {code: 'Ticket'}, fields: ['id']}, myOptions);
const ctxUploadFile = Object.assign({}, ctx);
if (ticket.route() === null)
throw new UserError('Ticket without route');
ctxUploadFile.args = {
warehouseId: ticket.warehouseFk,
companyId: ticket.companyFk,
dmsTypeId: dmsType.id,
reference: '',
description: `Firma del cliente - Ruta ${ticket.route().id}`,
hasFile: false
};
dms = await models.Dms.uploadFile(ctxUploadFile, myOptions);
gestDocCreated = true;
}
try {
for (const ticketId of tickets) {
const ticketState = await models.TicketState.findOne(
{where: {ticketFk: ticketId},
const ticketState = await models.TicketState.findOne({
where: {ticketFk: ticketId},
fields: ['alertLevel']
}, myOptions);
const packedAlertLevel = await models.AlertLevel.findOne({where: {code: 'PACKED'},
const packedAlertLevel = await models.AlertLevel.findOne({
where: {code: 'PACKED'},
fields: ['id']
}, myOptions);
if (!ticketState)
throw new UserError('Ticket does not exist');
if (!ticket.route())
throw new UserError('Ticket without route');
if (ticketState.alertLevel < packedAlertLevel.id)
throw new UserError('This ticket cannot be signed because it has not been boxed');
if (await gestDocExists(ticketId))
if (await ticket.isSigned)
throw new UserError('Ticket is already signed');
if (location) await setLocation(ticketId);
if (!gestDocCreated) await createGestDoc(ticketId);
await models.TicketDms.create({ticketFk: ticketId, dmsFk: dms[0].id}, myOptions);
const ticket = await models.Ticket.findById(ticketId, null, myOptions);
if (!await hasSignDms(ticketId) && !isSignUploaded)
await createGestDoc(ticketId);
if (isSignUploaded)
await models.TicketDms.create({ticketFk: ticket.id, dmsFk: dms[0].id}, myOptions);
await ticket.updateAttribute('isSigned', true, myOptions);
const deliveryState = await models.State.findOne({
where: {
code: 'DELIVERED'
}
where: {code: 'DELIVERED'}
}, myOptions);
await models.Ticket.state(ctx, {
ticketFk: ticketId,
stateFk: deliveryState.id
}, myOptions);
}
if (ticket?.address()?.province()?.country()?.code != 'ES' && ticket.cmrFk) {
await models.Ticket.saveCmr(ctx, [ticketId], myOptions);
externalTickets.push(ticketId);
}
}
if (tx) await tx.commit();
return;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
await models.Route.cmrEmail(ctx, externalTickets);
};
};