Changes
gitea/salix/pipeline/head There was a failure building this commit Details

This commit is contained in:
Joan Sanchez 2022-09-29 07:35:20 +02:00
parent d7ab95fcc8
commit fe5eb3e13d
21 changed files with 315 additions and 155 deletions

View File

@ -232,5 +232,6 @@
"Fichadas impares": "Fichadas impares",
"Descanso diario 12h.": "Descanso diario 12h.",
"Descanso semanal 36h. / 72h.": "Descanso semanal 36h. / 72h.",
"Dirección incorrecta": "Dirección incorrecta"
"Dirección incorrecta": "Dirección incorrecta",
"You cannot close tickets for today": "You cannot close tickets for today"
}

View File

@ -19,16 +19,8 @@
"waitForConnections": true
},
"osticket": {
"connector": "vn-mysql",
"database": "osticket",
"debug": false,
"host": "swarm.verdnatura.es",
"port": "40003",
"username": "osticket",
"password": "gfKmwsHJ2Q5H3Aem",
"connectTimeout": 180000,
"acquireTimeout": 60000,
"waitForConnections": true
"connector": "memory",
"timezone": "local"
},
"tempStorage": {
"name": "tempStorage",

View File

@ -1,7 +1,5 @@
const UserError = require('vn-loopback/util/user-error');
const fs = require('fs-extra');
const path = require('path');
const axios = require('axios');
const {Report, storage} = require('vn-print');
module.exports = Self => {
Self.remoteMethodCtx('createPdf', {
@ -27,9 +25,7 @@ module.exports = Self => {
Self.createPdf = async function(ctx, id, options) {
const models = Self.app.models;
const headers = ctx.req.headers;
const origin = headers.origin;
const auth = ctx.req.accessToken;
const userId = ctx.req.accessToken.userId;
if (process.env.NODE_ENV == 'test')
throw new UserError(`Action not allowed on the test environment`);
@ -45,10 +41,9 @@ module.exports = Self => {
myOptions.transaction = tx;
}
let fileSrc;
try {
const invoiceOut = await Self.findById(id, null, myOptions);
const hasInvoicing = await models.Account.hasRole(auth.userId, 'invoicing', myOptions);
const hasInvoicing = await models.Account.hasRole(userId, 'invoicing', myOptions);
if (invoiceOut.hasPdf && !hasInvoicing)
throw new UserError(`You don't have enough privileges`);
@ -57,35 +52,27 @@ module.exports = Self => {
hasPdf: true
}, myOptions);
return axios.get(`${origin}/api/report/invoice`, {
responseType: 'stream',
params: {
authorization: auth.id,
refFk: invoiceOut.ref
}
}).then(async response => {
const issued = invoiceOut.issued;
const year = issued.getFullYear().toString();
const month = (issued.getMonth() + 1).toString();
const day = issued.getDate().toString();
const container = await models.InvoiceContainer.container(year);
const rootPath = container.client.root;
const fileName = `${year}${invoiceOut.ref}.pdf`;
const src = path.join(rootPath, year, month, day);
fileSrc = path.join(src, fileName);
await fs.mkdir(src, {recursive: true});
if (tx) await tx.commit();
response.data.pipe(fs.createWriteStream(fileSrc));
}).catch(async e => {
if (fs.existsSync(fileSrc))
await fs.unlink(fileSrc);
throw e;
const invoiceReport = new Report('invoice', {
reference: invoiceOut.ref,
recipientId: invoiceOut.clientFk
});
const stream = await invoiceReport.toPdfStream();
const issued = invoiceOut.issued;
const year = issued.getFullYear().toString();
const month = (issued.getMonth() + 1).toString();
const day = issued.getDate().toString();
const fileName = `${year}${invoiceOut.ref}.pdf`;
// Store invoice
storage.write(stream, {
type: 'invoice',
path: `${year}/${month}/${day}`,
fileName: fileName
});
if (tx) await tx.commit();
} catch (e) {
if (tx) await tx.rollback();
throw e;

View File

@ -6,7 +6,7 @@ module.exports = Self => {
accessType: 'READ',
accepts: [
{
arg: 'ref',
arg: 'reference',
type: 'string',
required: true,
http: {source: 'path'}
@ -34,12 +34,12 @@ module.exports = Self => {
}
],
http: {
path: '/:ref/exportation-pdf',
path: '/:reference/exportation-pdf',
verb: 'GET'
}
});
Self.exportationPdf = async(ctx, ref) => {
Self.exportationPdf = async(ctx, reference) => {
const args = Object.assign({}, ctx.args);
const params = {lang: ctx.req.getLocale()};
@ -50,6 +50,6 @@ module.exports = Self => {
const report = new Report('exportation', params);
const stream = await report.toPdfStream();
return [stream, 'application/pdf', `filename="doc-${ref}.pdf"`];
return [stream, 'application/pdf', `filename="doc-${reference}.pdf"`];
};
};

View File

@ -6,7 +6,7 @@ module.exports = Self => {
accessType: 'WRITE',
accepts: [
{
arg: 'ref',
arg: 'reference',
type: 'string',
required: true,
http: {source: 'path'}
@ -35,7 +35,7 @@ module.exports = Self => {
root: true
},
http: {
path: '/:ref/invoice-email',
path: '/:reference/invoice-email',
verb: 'POST'
}
});

View File

@ -1,8 +1,9 @@
const UserError = require('vn-loopback/util/user-error');
const closure = require('./closure');
module.exports = Self => {
Self.remoteMethodCtx('closeAll', {
Self.remoteMethod('closeAll', {
description: 'Makes the closure process from all warehouses',
accessType: 'WRITE',
accepts: [],
@ -16,64 +17,62 @@ module.exports = Self => {
}
});
Self.closeAll = async ctx => {
Self.closeAll = async() => {
const toDate = new Date();
toDate.setDate(toDate.getDate() - 1);
// toDate.setDate(toDate.getDate() - 1);
const todayMinDate = new Date();
minDate.setHours(0, 0, 0, 0);
todayMinDate.setHours(0, 0, 0, 0);
const todayMaxDate = new Date();
maxDate.setHours(23, 59, 59, 59);
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');
// if (toDate >= todayMinDate && toDate <= todayMaxDate)
// throw new UserError('You cannot close tickets for today');
const tickets = await Self.rawSql(`
SELECT
t.id,
t.clientFk,
t.companyFk,
c.name clientName,
c.email recipient,
c.salesPersonFk,
c.isToBeMailed,
c.hasToInvoice,
co.hasDailyInvoice,
eu.email salesPersonEmail
FROM ticket t
JOIN agencyMode am ON am.id = t.agencyModeFk
JOIN warehouse wh ON wh.id = t.warehouseFk AND wh.hasComission
JOIN ticketState ts ON ts.ticketFk = t.id
JOIN alertLevel al ON al.id = ts.alertLevel
JOIN client c ON c.id = t.clientFk
JOIN province p ON p.id = c.provinceFk
JOIN country co ON co.id = p.countryFk
LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk
WHERE al.code = 'PACKED'
AND DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY)
AND util.dayEnd(?)
AND t.refFk IS NULL
GROUP BY t.id`, [toDate, toDate]);
SELECT
t.id,
t.clientFk,
t.companyFk,
c.name clientName,
c.email recipient,
c.salesPersonFk,
c.isToBeMailed,
c.hasToInvoice,
co.hasDailyInvoice,
eu.email salesPersonEmail
FROM ticket t
JOIN agencyMode am ON am.id = t.agencyModeFk
JOIN warehouse wh ON wh.id = t.warehouseFk AND wh.hasComission
JOIN ticketState ts ON ts.ticketFk = t.id
JOIN alertLevel al ON al.id = ts.alertLevel
JOIN client c ON c.id = t.clientFk
JOIN province p ON p.id = c.provinceFk
JOIN country co ON co.id = p.countryFk
LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk
WHERE al.code = 'PACKED'
AND DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY)
AND util.dayEnd(?)
GROUP BY t.id
`, [toDate, toDate]);
console.log(tickets);
await closure(Self, tickets);
// await closure.start(tickets, response.locals);
// await db.rawSql(`
// UPDATE ticket t
// JOIN ticketState ts ON t.id = ts.ticketFk
// JOIN alertLevel al ON al.id = ts.alertLevel
// JOIN agencyMode am ON am.id = t.agencyModeFk
// JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk
// JOIN zone z ON z.id = t.zoneFk
// SET t.routeFk = NULL
// WHERE DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY)
// AND util.dayEnd(?)
// AND al.code NOT IN('DELIVERED','PACKED')
// AND t.routeFk
// AND z.name LIKE '%MADRID%'`, [toDate, toDate]);
await Self.rawSql(`
UPDATE ticket t
JOIN ticketState ts ON t.id = ts.ticketFk
JOIN alertLevel al ON al.id = ts.alertLevel
JOIN agencyMode am ON am.id = t.agencyModeFk
JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk
JOIN zone z ON z.id = t.zoneFk
SET t.routeFk = NULL
WHERE DATE(t.shipped) BETWEEN DATE_ADD(?, INTERVAL -2 DAY)
AND util.dayEnd(?)
AND al.code NOT IN('DELIVERED','PACKED')
AND t.routeFk
AND z.name LIKE '%MADRID%'`, [toDate, toDate]);
return true;
};

View File

@ -0,0 +1,179 @@
const Report = require('vn-print/core/report');
const Email = require('vn-print/core/email');
const smtp = require('vn-print/core/smtp');
const config = require('vn-print/core/config');
const storage = require('vn-print/core/storage');
module.exports = async function(Self, tickets, reqArgs = {}) {
if (tickets.length == 0) return;
const failedtickets = [];
for (const ticket of tickets) {
try {
await Self.rawSql(`CALL vn.ticket_closeByTicket(?)`, [ticket.id]);
const [invoiceOut] = await Self.rawSql(`
SELECT io.id, io.ref, io.serial, cny.code companyCode, io.issued
FROM ticket t
JOIN invoiceOut io ON io.ref = t.refFk
JOIN company cny ON cny.id = io.companyFk
WHERE t.id = ?
`, [ticket.id]);
const mailOptions = {
overrideAttachments: true,
attachments: []
};
const isToBeMailed = ticket.recipient && ticket.salesPersonFk && ticket.isToBeMailed;
if (invoiceOut) {
const args = {
reference: invoiceOut.ref,
recipientId: ticket.clientFk,
recipient: ticket.recipient,
replyTo: ticket.salesPersonEmail
};
const invoiceReport = new Report('invoice', args);
const stream = await invoiceReport.toPdfStream();
const issued = invoiceOut.issued;
const year = issued.getFullYear().toString();
const month = (issued.getMonth() + 1).toString();
const day = issued.getDate().toString();
const fileName = `${year}${invoiceOut.ref}.pdf`;
// Store invoice
storage.write(stream, {
type: 'invoice',
path: `${year}/${month}/${day}`,
fileName: fileName
});
await Self.rawSql('UPDATE invoiceOut SET hasPdf = true WHERE id = ?', [invoiceOut.id]);
if (isToBeMailed) {
const invoiceAttachment = {
filename: fileName,
content: stream
};
if (invoiceOut.serial == 'E' && invoiceOut.companyCode == 'VNL') {
const exportation = new Report('exportation', args);
const stream = await exportation.toPdfStream();
const fileName = `CITES-${invoiceOut.ref}.pdf`;
mailOptions.attachments.push({
filename: fileName,
content: stream
});
}
mailOptions.attachments.push(invoiceAttachment);
const email = new Email('invoice', args);
await email.send(mailOptions);
}
} else if (isToBeMailed) {
const args = {
id: ticket.id,
recipientId: ticket.clientFk,
recipient: ticket.recipient,
replyTo: ticket.salesPersonEmail
};
const email = new Email('delivery-note-link', args);
await email.send();
}
// Incoterms authorization
const [{firstOrder}] = await Self.rawSql(`
SELECT COUNT(*) as firstOrder
FROM ticket t
JOIN client c ON c.id = t.clientFk
WHERE t.clientFk = ?
AND NOT t.isDeleted
AND c.isVies
`, [ticket.clientFk]);
if (firstOrder == 1) {
const args = {
id: ticket.clientFk,
recipientId: ticket.clientFk,
recipient: ticket.recipient,
replyTo: ticket.salesPersonEmail
};
const email = new Email('incoterms-authorization', args);
await email.send();
const sample = await Self.rawSql(
`SELECT id
FROM sample
WHERE code = 'incoterms-authorization'
`);
await Self.rawSql(`
INSERT INTO clientSample (clientFk, typeFk, companyFk) VALUES(?, ?, ?)
`, [ticket.clientFk, sample.id, ticket.companyFk]);
}
} catch (error) {
// Domain not found
if (error.responseCode == 450)
return invalidEmail(ticket);
// Save tickets on a list of failed ids
failedtickets.push({
id: ticket.id,
stacktrace: error
});
}
}
// Send email with failed tickets
if (failedtickets.length > 0) {
let body = 'This following tickets have failed:<br/><br/>';
for (const ticket of failedtickets) {
body += `Ticket: <strong>${ticket.id}</strong>
<br/> <strong>${ticket.stacktrace}</strong><br/><br/>`;
}
smtp.send({
to: config.app.reportEmail,
subject: '[API] Nightly ticket closure report',
html: body
});
}
async function invalidEmail(ticket) {
await Self.rawSql(`UPDATE client SET email = NULL WHERE id = ?`, [
ticket.clientFk
]);
const oldInstance = `{"email": "${ticket.recipient}"}`;
const newInstance = `{"email": ""}`;
await Self.rawSql(`
INSERT INTO clientLog (originFk, userFk, action, changedModel, oldInstance, newInstance)
VALUES (?, NULL, 'UPDATE', 'Client', ?, ?)`, [
ticket.clientFk,
oldInstance,
newInstance
]);
const body = `No se ha podido enviar el albarán <strong>${ticket.id}</strong>
al cliente <strong>${ticket.clientFk} - ${ticket.clientName}</strong>
porque la dirección de email <strong>"${ticket.recipient}"</strong> no es correcta
o no está disponible.<br/><br/>
Para evitar que se repita este error, se ha eliminado la dirección de email de la ficha del cliente.
Actualiza la dirección de email con una correcta.`;
smtp.send({
to: ticket.salesPersonEmail,
subject: 'No se ha podido enviar el albarán',
html: body
});
}
};

View File

@ -30,6 +30,7 @@ module.exports = Self => {
require('../methods/ticket/refund')(Self);
require('../methods/ticket/deliveryNotePdf')(Self);
require('../methods/ticket/deliveryNoteEmail')(Self);
require('../methods/ticket/closeAll')(Self);
Self.observe('before save', async function(ctx) {
const loopBackContext = LoopBackContext.getCurrentContext();

View File

@ -36,7 +36,7 @@ module.exports = Self => {
type: 'string'
},
{
arg: 'ref',
arg: 'reference',
type: 'string'
},
{

View File

@ -54,7 +54,7 @@ module.exports = Self => {
description: 'The totalEntries filter'
},
{
arg: 'ref',
arg: 'reference',
type: 'string',
description: 'The reference'
},

View File

@ -24,7 +24,7 @@ module.exports = Self => {
type: 'string'
},
{
arg: 'ref',
arg: 'reference',
type: 'string'
},
{

View File

@ -1,7 +1,6 @@
const mysql = require('mysql2');
const config = require('./config.js');
const fs = require('fs-extra');
const path = require('path');
module.exports = {
defaultDataSource: 'vn',

View File

@ -40,8 +40,9 @@ module.exports = {
return true;
},
smtp: require('./core/smtp'),
db: require('./core/database'),
Email: require('./core/email'),
Report: require('./core/report')
Report: require('./core/report'),
storage: require('./core/storage'),
smtp: require('./core/smtp'),
db: require('./core/database')
};

View File

@ -30,7 +30,7 @@
<div class="grid-block vn-pa-ml">
<h1>{{ $t('title') }}</h1>
<p>{{$t('dear')}}</p>
<p v-html="$t('description', [ticketId])"></p>
<p v-html="$t('description', [id])"></p>
</div>
</div>
<!-- Block -->
@ -38,7 +38,7 @@
<div class="grid-block vn-px-ml">
<p>{{$t('copyLink')}}</p>
<div class="external-link vn-pa-sm vn-m-md">
https://www.verdnatura.es/#!form=ecomerce/ticket&ticket={{ticketId}}
https://www.verdnatura.es/#!form=ecomerce/ticket&ticket={{id}}
</div>
</div>
</div>

View File

@ -17,7 +17,8 @@ module.exports = {
props: {
id: {
type: [Number, String],
required: true
required: true,
description: 'The client id'
},
companyId: {
type: [Number, String],

View File

@ -5,11 +5,11 @@ const emailFooter = new Component('email-footer');
module.exports = {
name: 'invoice',
async serverPrefetch() {
this.invoice = await this.fetchInvoice(this.ref);
this.invoice = await this.fetchInvoice(this.reference);
},
methods: {
fetchInvoice(ref) {
return this.findOneFromDef('invoice', [ref]);
fetchInvoice(reference) {
return this.findOneFromDef('invoice', [reference]);
},
},
components: {
@ -17,7 +17,7 @@ module.exports = {
'email-footer': emailFooter.build()
},
props: {
ref: {
reference: {
type: [Number, String],
required: true
}

View File

@ -5,7 +5,7 @@ const reportFooter = new Component('report-footer');
module.exports = {
name: 'exportation',
async serverPrefetch() {
this.invoice = await this.fetchInvoice(this.ref);
this.invoice = await this.fetchInvoice(this.reference);
if (!this.invoice)
throw new Error('Something went wrong');
@ -13,8 +13,8 @@ module.exports = {
this.company = await this.findOneFromDef('company', [this.invoice.companyFk]);
},
methods: {
fetchInvoice(ref) {
return this.findOneFromDef('invoice', [ref]);
fetchInvoice(reference) {
return this.findOneFromDef('invoice', [reference]);
}
},
computed: {
@ -29,7 +29,7 @@ module.exports = {
'report-footer': reportFooter.build()
},
props: {
ref: {
reference: {
type: [Number, String],
required: true,
description: 'The invoice ref'

View File

@ -107,7 +107,7 @@ module.exports = {
'landedTo',
'shippedFrom',
'continent',
'ref',
'reference',
'id',
'agencyModeFk',
'warehouseOutFk',

View File

@ -5,9 +5,9 @@ const reportFooter = new Component('report-footer');
module.exports = {
name: 'invoice-incoterms',
async serverPrefetch() {
this.invoice = await this.fetchInvoice(this.ref);
this.client = await this.fetchClient(this.ref);
this.incoterms = await this.fetchIncoterms(this.ref);
this.invoice = await this.fetchInvoice(this.reference);
this.client = await this.fetchClient(this.reference);
this.incoterms = await this.fetchIncoterms(this.reference);
if (!this.invoice)
throw new Error('Something went wrong');
@ -16,14 +16,14 @@ module.exports = {
},
methods: {
fetchInvoice(ref) {
return this.findOneFromDef('invoice', [ref]);
fetchInvoice(reference) {
return this.findOneFromDef('invoice', [reference]);
},
fetchClient(ref) {
return this.findOneFromDef('client', [ref]);
fetchClient(reference) {
return this.findOneFromDef('client', [reference]);
},
fetchIncoterms(ref) {
return this.findOneFromDef('incoterms', [ref, ref, ref]);
fetchIncoterms(reference) {
return this.findOneFromDef('incoterms', [reference, reference, reference]);
}
},
components: {
@ -31,7 +31,7 @@ module.exports = {
'report-footer': reportFooter.build()
},
props: {
ref: {
reference: {
type: [Number, String],
required: true,
description: 'The invoice ref'

View File

@ -7,15 +7,15 @@ const invoiceIncoterms = new Report('invoice-incoterms');
module.exports = {
name: 'invoice',
async serverPrefetch() {
this.invoice = await this.fetchInvoice(this.ref);
this.client = await this.fetchClient(this.ref);
this.taxes = await this.fetchTaxes(this.ref);
this.intrastat = await this.fetchIntrastat(this.ref);
this.rectified = await this.fetchRectified(this.ref);
this.hasIncoterms = await this.fetchHasIncoterms(this.ref);
this.invoice = await this.fetchInvoice(this.reference);
this.client = await this.fetchClient(this.reference);
this.taxes = await this.fetchTaxes(this.reference);
this.intrastat = await this.fetchIntrastat(this.reference);
this.rectified = await this.fetchRectified(this.reference);
this.hasIncoterms = await this.fetchHasIncoterms(this.reference);
const tickets = await this.fetchTickets(this.ref);
const sales = await this.fetchSales(this.ref);
const tickets = await this.fetchTickets(this.reference);
const sales = await this.fetchSales(this.reference);
const map = new Map();
@ -65,29 +65,29 @@ module.exports = {
}
},
methods: {
fetchInvoice(ref) {
return this.findOneFromDef('invoice', [ref]);
fetchInvoice(reference) {
return this.findOneFromDef('invoice', [reference]);
},
fetchClient(ref) {
return this.findOneFromDef('client', [ref]);
fetchClient(reference) {
return this.findOneFromDef('client', [reference]);
},
fetchTickets(ref) {
return this.rawSqlFromDef('tickets', [ref]);
fetchTickets(reference) {
return this.rawSqlFromDef('tickets', [reference]);
},
fetchSales(ref) {
return this.rawSqlFromDef('sales', [ref, ref]);
fetchSales(reference) {
return this.rawSqlFromDef('sales', [reference, reference]);
},
fetchTaxes(ref) {
return this.rawSqlFromDef(`taxes`, [ref]);
fetchTaxes(reference) {
return this.rawSqlFromDef(`taxes`, [reference]);
},
fetchIntrastat(ref) {
return this.rawSqlFromDef(`intrastat`, [ref, ref, ref]);
fetchIntrastat(reference) {
return this.rawSqlFromDef(`intrastat`, [reference, reference, reference]);
},
fetchRectified(ref) {
return this.rawSqlFromDef(`rectified`, [ref]);
fetchRectified(reference) {
return this.rawSqlFromDef(`rectified`, [reference]);
},
fetchHasIncoterms(ref) {
return this.findValueFromDef(`hasIncoterms`, [ref]);
fetchHasIncoterms(reference) {
return this.findValueFromDef(`hasIncoterms`, [reference]);
},
saleImport(sale) {
const price = sale.quantity * sale.price;
@ -115,7 +115,7 @@ module.exports = {
'invoice-incoterms': invoiceIncoterms.build()
},
props: {
ref: {
reference: {
type: String,
description: 'The invoice ref'
}