diff --git a/CHANGELOG.md b/CHANGELOG.md
index fa2ebcd62..cbfc6e9e6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [2328.01] - 2023-07-13
+
+### Added
+
+### Changed
+
+### Fixed
+
+
## [2326.01] - 2023-06-29
### Added
diff --git a/db/changes/232801/.gitkeep b/db/changes/232801/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/loopback/locale/en.json b/loopback/locale/en.json
index 43ff4b86a..40df9a712 100644
--- a/loopback/locale/en.json
+++ b/loopback/locale/en.json
@@ -115,7 +115,7 @@
"This client is not invoiceable": "This client is not invoiceable",
"INACTIVE_PROVIDER": "Inactive provider",
"reference duplicated": "reference duplicated",
- "The PDF document does not exists": "The PDF document does not exists. Try regenerating it from 'Regenerate invoice PDF' option",
+ "The PDF document does not exist": "The PDF document does not exists. Try regenerating it from 'Regenerate invoice PDF' option",
"This item is not available": "This item is not available",
"Deny buy request": "Purchase request for ticket id [{{ticketId}}]({{{url}}}) has been rejected. Reason: {{observation}}",
"The type of business must be filled in basic data": "The type of business must be filled in basic data",
@@ -175,5 +175,6 @@
"Pass expired": "The password has expired, change it from Salix",
"Can't transfer claimed sales": "Can't transfer claimed sales",
"Invalid quantity": "Invalid quantity",
- "Failed to upload delivery note": "Error to upload delivery note {{id}}"
+ "Failed to upload delivery note": "Error to upload delivery note {{id}}",
+ "Mail not sent": "There has been an error sending the invoice to the client [{{clientId}}]({{{clientUrl}}}), please check the email address"
}
diff --git a/loopback/locale/es.json b/loopback/locale/es.json
index 895d087dc..138fa7100 100644
--- a/loopback/locale/es.json
+++ b/loopback/locale/es.json
@@ -211,7 +211,7 @@
"You don't have enough privileges to set this credit amount": "No tienes suficientes privilegios para establecer esta cantidad de crédito",
"You can't change the credit set to zero from a financialBoss": "No puedes cambiar el cŕedito establecido a cero por un jefe de finanzas",
"Amounts do not match": "Las cantidades no coinciden",
- "The PDF document does not exists": "El documento PDF no existe. Prueba a regenerarlo desde la opción 'Regenerar PDF factura'",
+ "The PDF document does not exist": "El documento PDF no existe. Prueba a regenerarlo desde la opción 'Regenerar PDF factura'",
"The type of business must be filled in basic data": "El tipo de negocio debe estar rellenado en datos básicos",
"You can't create a claim from a ticket delivered more than seven days ago": "No puedes crear una reclamación de un ticket entregado hace más de siete días",
"The worker has hours recorded that day": "El trabajador tiene horas fichadas ese día",
@@ -265,7 +265,7 @@
"It is not possible to modify cloned sales": "No es posible modificar líneas de pedido clonadas",
"A supplier with the same name already exists. Change the country.": "Un proveedor con el mismo nombre ya existe. Cambie el país.",
"There is no assigned email for this client": "No hay correo asignado para este cliente",
- "Exists an invoice with a previous date": "Existe una factura con fecha anterior",
+ "Exists an invoice with a future date": "Existe una factura con fecha posterior",
"Invoice date can't be less than max date": "La fecha de factura no puede ser inferior a la fecha límite",
"Warehouse inventory not set": "El almacén inventario no está establecido",
"This locker has already been assigned": "Esta taquilla ya ha sido asignada",
@@ -294,5 +294,9 @@
"Invalid NIF for VIES": "Invalid NIF for VIES",
"Ticket does not exist": "Este ticket no existe",
"Ticket is already signed": "Este ticket ya ha sido firmado",
+ "Fecha fuera de rango": "Fecha fuera de rango",
+ "Error while generating PDF": "Error al generar PDF",
+ "Error when sending mail to client": "Error al enviar el correo al cliente",
+ "Mail not sent": "Se ha producido un fallo al enviar la factura al cliente [{{clientId}}]({{{clientUrl}}}), por favor revisa la dirección de correo electrónico",
"The renew period has not been exceeded": "El periodo de renovación no ha sido superado"
}
diff --git a/modules/client/back/locale/client/en.yml b/modules/client/back/locale/client/en.yml
index 74384461c..ad21a6ce6 100644
--- a/modules/client/back/locale/client/en.yml
+++ b/modules/client/back/locale/client/en.yml
@@ -52,4 +52,5 @@ columns:
hasInvoiceSimplified: simplified invoice
typeFk: type
lastSalesPersonFk: last salesperson
-
+ rating: rating
+ recommendedCredit: recommended credit
diff --git a/modules/client/back/locale/client/es.yml b/modules/client/back/locale/client/es.yml
index 47bf896d9..b17f53b1c 100644
--- a/modules/client/back/locale/client/es.yml
+++ b/modules/client/back/locale/client/es.yml
@@ -52,4 +52,5 @@ columns:
hasInvoiceSimplified: factura simple
typeFk: tipo
lastSalesPersonFk: último comercial
-
+ rating: clasificación
+ recommendedCredit: crédito recomendado
diff --git a/modules/entry/back/methods/entry/editLatestBuys.js b/modules/entry/back/methods/entry/editLatestBuys.js
index 2642d4f4d..0da2b1625 100644
--- a/modules/entry/back/methods/entry/editLatestBuys.js
+++ b/modules/entry/back/methods/entry/editLatestBuys.js
@@ -75,7 +75,7 @@ module.exports = Self => {
value[field] = newValue;
if (filter) {
- ctx.args.filter = {where: filter, limit: null};
+ ctx.args = {where: filter, limit: null};
lines = await models.Buy.latestBuysFilter(ctx, null, myOptions);
}
diff --git a/modules/entry/back/methods/entry/specs/editLatestBuys.spec.js b/modules/entry/back/methods/entry/specs/editLatestBuys.spec.js
index 99d2df67b..a4dd185fd 100644
--- a/modules/entry/back/methods/entry/specs/editLatestBuys.spec.js
+++ b/modules/entry/back/methods/entry/specs/editLatestBuys.spec.js
@@ -53,7 +53,36 @@ describe('Buy editLatestsBuys()', () => {
const options = {transaction: tx};
try {
- const filter = {'i.typeFk': 1};
+ const filter = {'categoryFk': 1, 'tags': []};
+ const ctx = {
+ args: {
+ filter: filter
+ },
+ req: {accessToken: {userId: 1}}
+ };
+
+ const field = 'size';
+ const newValue = 88;
+
+ await models.Buy.editLatestBuys(ctx, field, newValue, null, filter, options);
+
+ const [result] = await models.Buy.latestBuysFilter(ctx, null, options);
+
+ expect(result[field]).toEqual(newValue);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
+ });
+
+ it('should change the value of a given column for filter tags', async() => {
+ const tx = await models.Buy.beginTransaction({});
+ const options = {transaction: tx};
+
+ try {
+ const filter = {'tags': [{tagFk: 1, value: 'Brown'}]};
const ctx = {
args: {
filter: filter
diff --git a/modules/invoiceOut/back/methods/invoiceOut/createPdf.js b/modules/invoiceOut/back/methods/invoiceOut/createPdf.js
index dfdb3c1a7..8cc584c94 100644
--- a/modules/invoiceOut/back/methods/invoiceOut/createPdf.js
+++ b/modules/invoiceOut/back/methods/invoiceOut/createPdf.js
@@ -1,5 +1,4 @@
const UserError = require('vn-loopback/util/user-error');
-const print = require('vn-print');
module.exports = Self => {
Self.remoteMethodCtx('createPdf', {
@@ -26,9 +25,6 @@ module.exports = Self => {
Self.createPdf = async function(ctx, id, options) {
const models = Self.app.models;
- if (process.env.NODE_ENV == 'test')
- throw new UserError(`Action not allowed on the test environment`);
-
let tx;
const myOptions = {};
@@ -41,40 +37,20 @@ module.exports = Self => {
}
try {
- const invoiceOut = await Self.findById(id, null, myOptions);
- const canCreatePdf = await models.ACL.checkAccessAcl(ctx, 'InvoiceOut', 'canCreatePdf', 'WRITE');
+ const invoiceOut = await Self.findById(id, {fields: ['hasPdf']}, myOptions);
- if (invoiceOut.hasPdf && !canCreatePdf)
- throw new UserError(`You don't have enough privileges`);
+ if (invoiceOut.hasPdf) {
+ const canCreatePdf = await models.ACL.checkAccessAcl(ctx, 'InvoiceOut', 'canCreatePdf', 'WRITE');
+ if (!canCreatePdf)
+ throw new UserError(`You don't have enough privileges`);
+ }
- await invoiceOut.updateAttributes({
- hasPdf: true
- }, myOptions);
-
- const invoiceReport = new print.Report('invoice', {
- reference: invoiceOut.ref,
- recipientId: invoiceOut.clientFk
- });
- const buffer = 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
- await print.storage.write(buffer, {
- type: 'invoice',
- path: `${year}/${month}/${day}`,
- fileName: fileName
- });
+ await Self.makePdf(id, myOptions);
if (tx) await tx.commit();
- } catch (e) {
+ } catch (err) {
if (tx) await tx.rollback();
- throw e;
+ throw err;
}
};
};
diff --git a/modules/invoiceOut/back/methods/invoiceOut/download.js b/modules/invoiceOut/back/methods/invoiceOut/download.js
index 5c787428b..49bba046b 100644
--- a/modules/invoiceOut/back/methods/invoiceOut/download.js
+++ b/modules/invoiceOut/back/methods/invoiceOut/download.js
@@ -43,7 +43,9 @@ module.exports = Self => {
Object.assign(myOptions, options);
try {
- const invoiceOut = await models.InvoiceOut.findById(id, null, myOptions);
+ const invoiceOut = await models.InvoiceOut.findById(id, {
+ fields: ['ref', 'issued']
+ }, myOptions);
const issued = invoiceOut.issued;
const year = issued.getFullYear().toString();
@@ -73,7 +75,7 @@ module.exports = Self => {
return [stream, file.contentType, `filename="${file.name}"`];
} catch (error) {
if (error.code === 'ENOENT')
- throw new UserError('The PDF document does not exists');
+ throw new UserError('The PDF document does not exist');
throw error;
}
diff --git a/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js b/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js
index 421cbaea1..d010ef631 100644
--- a/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js
+++ b/modules/invoiceOut/back/methods/invoiceOut/invoiceClient.js
@@ -51,6 +51,9 @@ module.exports = Self => {
const args = ctx.args;
const models = Self.app.models;
const myOptions = {userId: ctx.req.accessToken.userId};
+ const $t = ctx.req.__; // $translate
+ const origin = ctx.req.headers.origin;
+
let tx;
if (typeof options == 'object')
@@ -109,17 +112,22 @@ module.exports = Self => {
], myOptions);
const [newInvoice] = await Self.rawSql(`SELECT @invoiceId id`, null, myOptions);
- if (newInvoice.id) {
- await Self.rawSql('CALL invoiceOutBooking(?)', [newInvoice.id], myOptions);
+ if (!newInvoice)
+ throw new UserError('No tickets to invoice', 'notInvoiced');
- invoiceOut = await models.InvoiceOut.findById(newInvoice.id, {
- include: {
- relation: 'client'
+ await Self.rawSql('CALL invoiceOutBooking(?)', [newInvoice.id], myOptions);
+
+ invoiceOut = await models.InvoiceOut.findById(newInvoice.id, {
+ fields: ['id', 'ref', 'clientFk'],
+ include: {
+ relation: 'client',
+ scope: {
+ fields: ['email', 'isToBeMailed', 'salesPersonFk']
}
- }, myOptions);
+ }
+ }, myOptions);
- invoiceId = newInvoice.id;
- }
+ invoiceId = newInvoice.id;
if (tx) await tx.commit();
} catch (e) {
@@ -127,26 +135,45 @@ module.exports = Self => {
throw e;
}
- if (invoiceId) {
- if (!invoiceOut.client().isToBeMailed) {
- const query = `
- CALL vn.report_print(
- 'invoice',
- ?,
- account.myUser_getId(),
- JSON_OBJECT('refFk', ?),
- 'normal'
- );`;
- await models.InvoiceOut.rawSql(query, [args.printerFk, invoiceOut.ref]);
- } else {
+ try {
+ await Self.makePdf(invoiceId);
+ } catch (err) {
+ console.error(err);
+ throw new UserError('Error while generating PDF', 'pdfError');
+ }
+
+ if (invoiceOut.client().isToBeMailed) {
+ try {
ctx.args = {
reference: invoiceOut.ref,
- recipientId: invoiceOut.clientFk,
+ recipientId: args.clientId,
recipient: invoiceOut.client().email
};
await models.InvoiceOut.invoiceEmail(ctx, invoiceOut.ref);
+ } catch (err) {
+ const message = $t('Mail not sent', {
+ clientId: args.clientId,
+ clientUrl: `${origin}/#!/claim/${args.id}/summary`
+ });
+ const salesPersonId = invoiceOut.client().salesPersonFk;
+
+ if (salesPersonId)
+ await models.Chat.sendCheckingPresence(ctx, salesPersonId, message);
+
+ throw new UserError('Error when sending mail to client', 'mailNotSent');
}
+ } else {
+ const query = `
+ CALL vn.report_print(
+ 'invoice',
+ ?,
+ account.myUser_getId(),
+ JSON_OBJECT('refFk', ?),
+ 'normal'
+ );`;
+ await models.InvoiceOut.rawSql(query, [args.printerFk, invoiceOut.ref]);
}
+
return invoiceId;
};
diff --git a/modules/invoiceOut/back/methods/invoiceOut/invoiceEmail.js b/modules/invoiceOut/back/methods/invoiceOut/invoiceEmail.js
index 83cb84881..113526484 100644
--- a/modules/invoiceOut/back/methods/invoiceOut/invoiceEmail.js
+++ b/modules/invoiceOut/back/methods/invoiceOut/invoiceEmail.js
@@ -1,3 +1,4 @@
+const UserError = require('vn-loopback/util/user-error');
const {Email} = require('vn-print');
module.exports = Self => {
@@ -74,6 +75,10 @@ module.exports = Self => {
]
};
- return email.send(mailOptions);
+ try {
+ return email.send(mailOptions);
+ } catch (err) {
+ throw new UserError('Error when sending mail to client', 'mailNotSent');
+ }
};
};
diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/invoiceClient.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/invoiceClient.spec.js
index 9a0574dba..0faa8fe1a 100644
--- a/modules/invoiceOut/back/methods/invoiceOut/specs/invoiceClient.spec.js
+++ b/modules/invoiceOut/back/methods/invoiceOut/specs/invoiceClient.spec.js
@@ -18,12 +18,14 @@ describe('InvoiceOut invoiceClient()', () => {
accessToken: {userId: userId},
__: value => {
return value;
- }
+ },
+ headers: {origin: 'http://localhost'}
+
};
const ctx = {req: activeCtx};
it('should make a global invoicing', async() => {
- spyOn(models.InvoiceOut, 'createPdf').and.returnValue(new Promise(resolve => resolve(true)));
+ spyOn(models.InvoiceOut, 'makePdf').and.returnValue(new Promise(resolve => resolve(true)));
spyOn(models.InvoiceOut, 'invoiceEmail');
const tx = await models.InvoiceOut.beginTransaction({});
diff --git a/modules/invoiceOut/back/models/invoice-out.js b/modules/invoiceOut/back/models/invoice-out.js
index 5fcef7744..0d5ed021c 100644
--- a/modules/invoiceOut/back/models/invoice-out.js
+++ b/modules/invoiceOut/back/models/invoice-out.js
@@ -1,3 +1,5 @@
+const print = require('vn-print');
+
module.exports = Self => {
require('../methods/invoiceOut/filter')(Self);
require('../methods/invoiceOut/summary')(Self);
@@ -19,4 +21,34 @@ module.exports = Self => {
require('../methods/invoiceOut/getInvoiceDate')(Self);
require('../methods/invoiceOut/negativeBases')(Self);
require('../methods/invoiceOut/negativeBasesCsv')(Self);
+
+ Self.makePdf = async function(id, options) {
+ const fields = ['id', 'hasPdf', 'ref', 'issued'];
+ const invoiceOut = await Self.findById(id, {fields}, options);
+ const invoiceReport = new print.Report('invoice', {
+ reference: invoiceOut.ref
+ });
+ const buffer = 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
+
+ await invoiceOut.updateAttributes({
+ hasPdf: true
+ }, options);
+
+ if (process.env.NODE_ENV !== 'test') {
+ await print.storage.write(buffer, {
+ type: 'invoice',
+ path: `${year}/${month}/${day}`,
+ fileName: fileName
+ });
+ }
+ };
};
diff --git a/modules/invoiceOut/front/global-invoicing/index.html b/modules/invoiceOut/front/global-invoicing/index.html
index 3f0a10650..52bf8b619 100644
--- a/modules/invoiceOut/front/global-invoicing/index.html
+++ b/modules/invoiceOut/front/global-invoicing/index.html
@@ -55,7 +55,11 @@
{{::error.address.nickname}}