Merge pull request '7744-closeAllTest' (!3114) from 7744-closeAllTest into dev
gitea/salix/pipeline/head There was a failure building this commit
Details
gitea/salix/pipeline/head There was a failure building this commit
Details
Reviewed-on: #3114 Reviewed-by: Alex Moreno <alexm@verdnatura.es>
This commit is contained in:
commit
da772cf504
|
@ -632,14 +632,21 @@ INSERT INTO vn.invoiceOutConfig
|
||||||
SET id = 1,
|
SET id = 1,
|
||||||
parallelism = 8;
|
parallelism = 8;
|
||||||
|
|
||||||
INSERT INTO `vn`.`invoiceOutSerial` (`code`, `description`, `isTaxed`, `taxAreaFk`, `isCEE`, `type`)
|
INSERT INTO `vn`.`invoiceOutSerial`
|
||||||
|
(`code`,`description`, `isTaxed`, `taxAreaFk`, `isCEE`, `type`)
|
||||||
VALUES
|
VALUES
|
||||||
('A', 'Global nacional', 1, 'NATIONAL', 0, 'global'),
|
('A', 'Global nacional', 1, 'NATIONAL', 0, 'global'),
|
||||||
('T', 'Española rapida', 1, 'NATIONAL', 0, 'quick'),
|
('T', 'Española rapida', 1, 'NATIONAL', 0, 'quick'),
|
||||||
('V', 'Intracomunitaria global', 0, 'CEE', 1, 'global'),
|
('V', 'Intracomunitaria global', 0, 'CEE', 1, 'global'),
|
||||||
('M', 'Múltiple nacional', 1, 'NATIONAL', 0, 'multiple'),
|
('M', 'Múltiple nacional', 1, 'NATIONAL', 0, 'multiple'),
|
||||||
('R', 'Rectificativa', 1, 'NATIONAL', 0, NULL),
|
('R', 'Rectificativa', 1, 'NATIONAL', 0, NULL),
|
||||||
('E', 'Exportación rápida', 0, 'WORLD', 0, 'quick');
|
('E', 'Exportación rápida', 0, 'WORLD', 0, 'quick'),
|
||||||
|
('H', 'Intracomunitaria rápida', 0, 'CEE', 1, 'quick'),
|
||||||
|
('P', 'Factura simplificada', 1, 'NATIONAL', 0, NULL),
|
||||||
|
('PE', 'COOPERATIE FLORAHOLLAND UA', 0, 'CEE', 1, NULL),
|
||||||
|
('S', 'Simplificada', 1, 'NATIONAL', 0, NULL),
|
||||||
|
('X', 'Exportación global', 0, 'WORLD', 0, 'global'),
|
||||||
|
('N', 'Múltiple Intracomunitaria', 0, 'CEE', 1, 'multiple');
|
||||||
|
|
||||||
INSERT INTO `vn`.`invoiceOut`(`id`, `serial`, `amount`, `issued`,`clientFk`, `created`, `companyFk`, `dued`, `booked`, `bankFk`, `hasPdf`)
|
INSERT INTO `vn`.`invoiceOut`(`id`, `serial`, `amount`, `issued`,`clientFk`, `created`, `companyFk`, `dued`, `booked`, `bankFk`, `hasPdf`)
|
||||||
VALUES
|
VALUES
|
||||||
|
@ -2911,7 +2918,8 @@ INSERT INTO `util`.`notification` (`id`, `name`, `description`)
|
||||||
(6, 'book-entry-deleted', 'accounting entries deleted'),
|
(6, 'book-entry-deleted', 'accounting entries deleted'),
|
||||||
(7, 'zone-included','An email to notify zoneCollisions'),
|
(7, 'zone-included','An email to notify zoneCollisions'),
|
||||||
(8, 'backup-printer-selected','A backup printer has been selected'),
|
(8, 'backup-printer-selected','A backup printer has been selected'),
|
||||||
(9, 'mrw-deadline','The MRW deadline has passed');
|
(9, 'mrw-deadline','The MRW deadline has passed'),
|
||||||
|
(10,'invoice-ticket-closure','Tickets not invoiced during the nightly closure ticket process');
|
||||||
|
|
||||||
TRUNCATE `util`.`notificationAcl`;
|
TRUNCATE `util`.`notificationAcl`;
|
||||||
INSERT INTO `util`.`notificationAcl` (`notificationFk`, `roleFk`)
|
INSERT INTO `util`.`notificationAcl` (`notificationFk`, `roleFk`)
|
||||||
|
|
|
@ -350,6 +350,7 @@
|
||||||
"Cmr file does not exist": "El archivo del cmr no existe",
|
"Cmr file does not exist": "El archivo del cmr no existe",
|
||||||
"You are not allowed to modify the alias": "No estás autorizado a modificar el alias",
|
"You are not allowed to modify the alias": "No estás autorizado a modificar el alias",
|
||||||
"The address of the customer must have information about Incoterms and Customs Agent": "El consignatario del cliente debe tener informado Incoterms y Agente de aduanas",
|
"The address of the customer must have information about Incoterms and Customs Agent": "El consignatario del cliente debe tener informado Incoterms y Agente de aduanas",
|
||||||
|
"No invoice series found for these parameters": "No se encontró una serie para estos parámetros",
|
||||||
"The line could not be marked": "La linea no puede ser marcada",
|
"The line could not be marked": "La linea no puede ser marcada",
|
||||||
"Through this procedure, it is not possible to modify the password of users with verified email": "Mediante este procedimiento, no es posible modificar la contraseña de usuarios con correo verificado",
|
"Through this procedure, it is not possible to modify the password of users with verified email": "Mediante este procedimiento, no es posible modificar la contraseña de usuarios con correo verificado",
|
||||||
"They're not your subordinate": "No es tu subordinado/a.",
|
"They're not your subordinate": "No es tu subordinado/a.",
|
||||||
|
|
|
@ -350,6 +350,7 @@
|
||||||
"Cmr file does not exist": "Le fichier cmr n'existe pas",
|
"Cmr file does not exist": "Le fichier cmr n'existe pas",
|
||||||
"You are not allowed to modify the alias": "Vous n'êtes pas autorisé à modifier l'alias",
|
"You are not allowed to modify the alias": "Vous n'êtes pas autorisé à modifier l'alias",
|
||||||
"The address of the customer must have information about Incoterms and Customs Agent": "L'adresse du client doit contenir des informations sur les Incoterms et l'agent des douanes",
|
"The address of the customer must have information about Incoterms and Customs Agent": "L'adresse du client doit contenir des informations sur les Incoterms et l'agent des douanes",
|
||||||
|
"No invoice series found for these parameters": "Aucune série de facture trouvée pour ces paramètres",
|
||||||
"The line could not be marked": "La ligne ne peut pas être marquée",
|
"The line could not be marked": "La ligne ne peut pas être marquée",
|
||||||
"This password can only be changed by the user themselves": "Ce mot de passe ne peut être modifié que par l'utilisateur lui-même",
|
"This password can only be changed by the user themselves": "Ce mot de passe ne peut être modifié que par l'utilisateur lui-même",
|
||||||
"They're not your subordinate": "Ce n'est pas votre subordonné.",
|
"They're not your subordinate": "Ce n'est pas votre subordonné.",
|
||||||
|
|
|
@ -350,6 +350,7 @@
|
||||||
"Cmr file does not exist": "O arquivo CMR não existe",
|
"Cmr file does not exist": "O arquivo CMR não existe",
|
||||||
"You are not allowed to modify the alias": "Você não tem permissão para modificar o alias",
|
"You are not allowed to modify the alias": "Você não tem permissão para modificar o alias",
|
||||||
"The address of the customer must have information about Incoterms and Customs Agent": "O endereço do cliente deve ter informações sobre Incoterms e Agente Aduaneiro",
|
"The address of the customer must have information about Incoterms and Customs Agent": "O endereço do cliente deve ter informações sobre Incoterms e Agente Aduaneiro",
|
||||||
|
"No invoice series found for these parameters": "Nenhuma série de fatura encontrada para esses parâmetros",
|
||||||
"The line could not be marked": "A linha não pôde ser marcada",
|
"The line could not be marked": "A linha não pôde ser marcada",
|
||||||
"This password can only be changed by the user themselves": "Esta senha só pode ser alterada pelo próprio usuário",
|
"This password can only be changed by the user themselves": "Esta senha só pode ser alterada pelo próprio usuário",
|
||||||
"They're not your subordinate": "Eles não são seus subordinados.",
|
"They're not your subordinate": "Eles não são seus subordinados.",
|
||||||
|
|
|
@ -37,7 +37,7 @@ module.exports = Self => {
|
||||||
const tickets = await models.Ticket.find({
|
const tickets = await models.Ticket.find({
|
||||||
where: {refFk: invoiceOut.ref}
|
where: {refFk: invoiceOut.ref}
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
|
|
||||||
const [bookEntry] = await models.Xdiario.find({
|
const [bookEntry] = await models.Xdiario.find({
|
||||||
where: {
|
where: {
|
||||||
SERIE: invoiceOut.ref[0],
|
SERIE: invoiceOut.ref[0],
|
||||||
|
@ -55,13 +55,13 @@ module.exports = Self => {
|
||||||
if (bookEntry) {
|
if (bookEntry) {
|
||||||
if (bookEntry.enlazadoSage) {
|
if (bookEntry.enlazadoSage) {
|
||||||
const params = {
|
const params = {
|
||||||
bookEntry: bookEntry.ASIEN,
|
bookEntry: bookEntry.ASIEN,
|
||||||
invoiceOutRef: invoiceOut.ref
|
invoiceOutRef: invoiceOut.ref
|
||||||
}
|
};
|
||||||
await Self.rawSql(`SELECT util.notification_send('book-entry-deleted', ?, NULL)`,
|
await Self.rawSql(`SELECT util.notification_send('book-entry-deleted', ?, NULL)`,
|
||||||
[JSON.stringify(params)],
|
[JSON.stringify(params)],
|
||||||
myOptions);
|
myOptions);
|
||||||
};
|
}
|
||||||
|
|
||||||
await models.Xdiario.destroyAll({
|
await models.Xdiario.destroyAll({
|
||||||
ASIEN: bookEntry.ASIEN
|
ASIEN: bookEntry.ASIEN
|
||||||
|
|
|
@ -79,6 +79,8 @@ module.exports = Self => {
|
||||||
type
|
type
|
||||||
],
|
],
|
||||||
myOptions);
|
myOptions);
|
||||||
|
if (!serial)
|
||||||
|
throw new UserError('No invoice series found for these parameters');
|
||||||
|
|
||||||
const invoiceOutSerial = await Self.app.models.InvoiceOutSerial.findById(serial);
|
const invoiceOutSerial = await Self.app.models.InvoiceOutSerial.findById(serial);
|
||||||
if (invoiceOutSerial?.taxAreaFk == 'WORLD') {
|
if (invoiceOutSerial?.taxAreaFk == 'WORLD') {
|
||||||
|
|
|
@ -31,6 +31,6 @@ module.exports = Self => {
|
||||||
|
|
||||||
const usesMana = departments.find(department => department.id == workerDepartment.departmentFk);
|
const usesMana = departments.find(department => department.id == workerDepartment.departmentFk);
|
||||||
|
|
||||||
return usesMana ? true : false;
|
return !!usesMana;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,11 +1,17 @@
|
||||||
const UserError = require('vn-loopback/util/user-error');
|
|
||||||
const closure = require('./closure');
|
const closure = require('./closure');
|
||||||
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethodCtx('closeAll', {
|
Self.remoteMethodCtx('closeAll', {
|
||||||
description: 'Makes the closure process from all warehouses',
|
description: 'Makes the closure process from all warehouses',
|
||||||
accessType: 'WRITE',
|
accessType: 'WRITE',
|
||||||
accepts: [],
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'options',
|
||||||
|
type: 'object',
|
||||||
|
http: {source: 'body'},
|
||||||
|
description: 'Optional parameters, including transaction.'
|
||||||
|
}
|
||||||
|
],
|
||||||
returns: {
|
returns: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
root: true
|
root: true
|
||||||
|
@ -16,21 +22,20 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.closeAll = async ctx => {
|
Self.closeAll = async(ctx, options) => {
|
||||||
|
const userId = ctx.req.accessToken.userId;
|
||||||
|
const myOptions = {userId};
|
||||||
|
|
||||||
|
if (typeof options == 'object')
|
||||||
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
|
let tx;
|
||||||
|
// IMPORTANT: Due to its high cost in production, wrapping this process in a transaction may cause timeouts.
|
||||||
|
|
||||||
const toDate = Date.vnNew();
|
const toDate = Date.vnNew();
|
||||||
toDate.setHours(0, 0, 0, 0);
|
toDate.setHours(0, 0, 0, 0);
|
||||||
toDate.setDate(toDate.getDate() - 1);
|
toDate.setDate(toDate.getDate() - 1);
|
||||||
|
|
||||||
const todayMinDate = Date.vnNew();
|
|
||||||
todayMinDate.setHours(0, 0, 0, 0);
|
|
||||||
|
|
||||||
const todayMaxDate = Date.vnNew();
|
|
||||||
todayMaxDate.setHours(23, 59, 59, 59);
|
|
||||||
|
|
||||||
// Prevent closure for current day
|
|
||||||
if (toDate >= todayMinDate && toDate <= todayMaxDate)
|
|
||||||
throw new UserError('You cannot close tickets for today');
|
|
||||||
|
|
||||||
const tickets = await Self.rawSql(`
|
const tickets = await Self.rawSql(`
|
||||||
SELECT t.id,
|
SELECT t.id,
|
||||||
t.clientFk,
|
t.clientFk,
|
||||||
|
@ -58,12 +63,12 @@ module.exports = Self => {
|
||||||
AND t.shipped BETWEEN ? - INTERVAL tc.closureDaysAgo DAY AND util.dayEnd(?)
|
AND t.shipped BETWEEN ? - INTERVAL tc.closureDaysAgo DAY AND util.dayEnd(?)
|
||||||
AND t.refFk IS NULL
|
AND t.refFk IS NULL
|
||||||
GROUP BY t.id
|
GROUP BY t.id
|
||||||
`, [toDate, toDate]);
|
`, [toDate, toDate], myOptions);
|
||||||
const ticketIds = tickets.map(ticket => ticket.id);
|
const ticketIds = tickets.map(ticket => ticket.id);
|
||||||
await Self.rawSql(`
|
await Self.rawSql(`
|
||||||
INSERT INTO util.debug (variable, value)
|
INSERT INTO util.debug (variable, value)
|
||||||
VALUES ('nightInvoicing', ?)
|
VALUES ('nightInvoicing', ?)
|
||||||
`, [ticketIds.join(',')]);
|
`, [ticketIds.join(',')], myOptions);
|
||||||
|
|
||||||
await Self.rawSql(`
|
await Self.rawSql(`
|
||||||
WITH ticketNotInvoiceable AS(
|
WITH ticketNotInvoiceable AS(
|
||||||
|
@ -133,9 +138,9 @@ module.exports = Self => {
|
||||||
) SELECT IF(errors = '{"tickets": null}',
|
) SELECT IF(errors = '{"tickets": null}',
|
||||||
'No errors',
|
'No errors',
|
||||||
util.notification_send('invoice-ticket-closure', errors, NULL))
|
util.notification_send('invoice-ticket-closure', errors, NULL))
|
||||||
FROM ticketNotInvoiceable`, [toDate, toDate]);
|
FROM ticketNotInvoiceable`, [toDate, toDate], myOptions);
|
||||||
|
|
||||||
await closure(ctx, Self, tickets);
|
await closure(ctx, Self, tickets, myOptions);
|
||||||
|
|
||||||
await Self.rawSql(`
|
await Self.rawSql(`
|
||||||
UPDATE ticket t
|
UPDATE ticket t
|
||||||
|
@ -150,7 +155,10 @@ module.exports = Self => {
|
||||||
AND al.code NOT IN ('DELIVERED', 'PACKED')
|
AND al.code NOT IN ('DELIVERED', 'PACKED')
|
||||||
AND NOT t.packages
|
AND NOT t.packages
|
||||||
AND tob.id IS NULL
|
AND tob.id IS NULL
|
||||||
AND t.routeFk`, [toDate, toDate], {userId: ctx.req.accessToken.userId});
|
AND t.routeFk`, [toDate, toDate], myOptions);
|
||||||
|
|
||||||
|
if (tx)
|
||||||
|
await tx.commit();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
message: 'Success'
|
message: 'Success'
|
||||||
|
|
|
@ -19,9 +19,14 @@ module.exports = async function(ctx, Self, tickets, options) {
|
||||||
const failedtickets = [];
|
const failedtickets = [];
|
||||||
for (const ticket of tickets) {
|
for (const ticket of tickets) {
|
||||||
try {
|
try {
|
||||||
await Self.rawSql(`CALL util.debugAdd('invoicingTicket', ?)`, [ticket.id], {userId});
|
await Self.rawSql(`CALL util.debugAdd('invoicingTicket', ?)`, [ticket.id], myOptions);
|
||||||
|
|
||||||
await Self.app.models.InvoiceOut.getSerial(ticket.clientFk, ticket.companyFk, ticket.addressFk, 'quick');
|
await Self.app.models.InvoiceOut.getSerial(
|
||||||
|
ticket.clientFk,
|
||||||
|
ticket.companyFk,
|
||||||
|
ticket.addressFk,
|
||||||
|
'quick',
|
||||||
|
myOptions);
|
||||||
await Self.rawSql(
|
await Self.rawSql(
|
||||||
`CALL vn.ticket_closeByTicket(?)`,
|
`CALL vn.ticket_closeByTicket(?)`,
|
||||||
[ticket.id],
|
[ticket.id],
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
const models = require('vn-loopback/server/server').models;
|
||||||
|
const LoopBackContext = require('loopback-context');
|
||||||
|
|
||||||
|
describe('Ticket Closure - closeAll function', () => {
|
||||||
|
let ctx = {
|
||||||
|
req: {
|
||||||
|
getLocale: () => 'es',
|
||||||
|
accessToken: {userId: 1106},
|
||||||
|
headers: {origin: 'http://localhost'},
|
||||||
|
__: value => value,
|
||||||
|
},
|
||||||
|
args: {}
|
||||||
|
};
|
||||||
|
let options;
|
||||||
|
let tx;
|
||||||
|
let originalVnNew;
|
||||||
|
|
||||||
|
beforeEach(async() => {
|
||||||
|
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({active: ctx.req});
|
||||||
|
|
||||||
|
tx = await models.Ticket.beginTransaction({});
|
||||||
|
options = {transaction: tx};
|
||||||
|
originalVnNew = Date.vnNew;
|
||||||
|
spyOn(Date, 'vnNew').and.callFake(() => {
|
||||||
|
const mockDate = originalVnNew();
|
||||||
|
mockDate.setDate(mockDate.getDate() + 1);
|
||||||
|
return mockDate;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async() => {
|
||||||
|
if (tx)
|
||||||
|
await tx.rollback();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set routeFk to NULL when conditions are met', async() => {
|
||||||
|
const ticketsBefore = await models.Ticket.find({
|
||||||
|
where: {
|
||||||
|
routeFk: {neq: null}
|
||||||
|
}
|
||||||
|
}, options);
|
||||||
|
|
||||||
|
await models.Ticket.closeAll(ctx, options);
|
||||||
|
|
||||||
|
const ticketsAfter = await models.Ticket.find({
|
||||||
|
where: {
|
||||||
|
id: {inq: ticketsBefore.map(ticket => ticket.id)},
|
||||||
|
routeFk: {neq: null}
|
||||||
|
}
|
||||||
|
}, options);
|
||||||
|
|
||||||
|
expect(ticketsBefore.length).toBeGreaterThan(ticketsAfter.length);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue