feat(exportation): added exportation report & send report with client invoicing
gitea/salix/pipeline/head This commit looks good Details

Refs: 3254
This commit is contained in:
Joan Sanchez 2021-10-25 11:58:23 +02:00
parent aa27ebffc9
commit 6578a498ca
18 changed files with 211 additions and 31 deletions

View File

@ -9,19 +9,19 @@
"properties": { "properties": {
"id": { "id": {
"id": true, "id": true,
"type": "Number" "type": "number"
}, },
"sender": { "receiver": {
"type": "String" "type": "string"
}, },
"replyTo": { "replyTo": {
"type": "String" "type": "string"
}, },
"subject": { "subject": {
"type": "String" "type": "string"
}, },
"body": { "body": {
"type": "String" "type": "string"
} }
}, },
"acls": [ "acls": [

View File

@ -8,6 +8,7 @@ class Controller extends ModuleCard {
'id', 'id',
'ref', 'ref',
'issued', 'issued',
'serial',
'amount', 'amount',
'clientFk', 'clientFk',
'companyFk', 'companyFk',

View File

@ -38,6 +38,12 @@
translate> translate>
{{!$ctrl.invoiceOut.hasPdf ? 'Generate PDF invoice': 'Regenerate PDF invoice'}} {{!$ctrl.invoiceOut.hasPdf ? 'Generate PDF invoice': 'Regenerate PDF invoice'}}
</vn-item> </vn-item>
<vn-item
ng-click="$ctrl.showExportationLetter()"
ng-show="$ctrl.invoiceOut.serial == 'E'"
translate>
Show CIES letter
</vn-item>
</slot-menu> </slot-menu>
<slot-body> <slot-body>
<div class="attributes"> <div class="attributes">

View File

@ -83,6 +83,13 @@ class Controller extends Descriptor {
invoiceId: this.id invoiceId: this.id
}); });
} }
showExportationLetter() {
this.vnReport.show('exportation', {
recipientId: this.invoiceOut.client.id,
invoiceId: this.id,
});
}
} }
ngModule.vnComponent('vnInvoiceOutDescriptor', { ngModule.vnComponent('vnInvoiceOutDescriptor', {

View File

@ -6,12 +6,13 @@ Show invoice PDF: Ver factura en PDF
Send invoice PDF: Enviar factura en PDF Send invoice PDF: Enviar factura en PDF
Delete Invoice: Eliminar factura Delete Invoice: Eliminar factura
Clone Invoice: Clonar factura Clone Invoice: Clonar factura
Book invoice: Asentar factura
Generate PDF invoice: Generar PDF factura
Show CIES letter: Ver carta CIES
InvoiceOut deleted: Factura eliminada InvoiceOut deleted: Factura eliminada
Are you sure you want to delete this invoice?: Estas seguro de eliminar esta factura? Are you sure you want to delete this invoice?: Estas seguro de eliminar esta factura?
Are you sure you want to clone this invoice?: Estas seguro de clonar esta factura? Are you sure you want to clone this invoice?: Estas seguro de clonar esta factura?
Book invoice: Asentar factura
InvoiceOut booked: Factura asentada InvoiceOut booked: Factura asentada
Are you sure you want to book this invoice?: Estas seguro de querer asentar esta factura? Are you sure you want to book this invoice?: Estas seguro de querer asentar esta factura?
Generate PDF invoice: Generar PDF factura
Regenerate PDF invoice: Regenerar PDF factura Regenerate PDF invoice: Regenerar PDF factura
The invoice PDF document has been regenerated: El documento PDF de la factura ha sido regenerado The invoice PDF document has been regenerated: El documento PDF de la factura ha sido regenerado

View File

@ -26,7 +26,7 @@ module.exports = Self => {
const user = await models.user.findById(loopBackContext.active.accessToken.userId); const user = await models.user.findById(loopBackContext.active.accessToken.userId);
const bankEntity = await models.BankEntity.findById(ctx.instance.bankEntityFk); const bankEntity = await models.BankEntity.findById(ctx.instance.bankEntityFk);
await Self.app.models.Mail.create({ await Self.app.models.Mail.create({
sender: 'finanzas@verdnatura.es', receiver: 'finanzas@verdnatura.es',
subject: 'Añadida cuenta bancaria al proveedor' + ctx.instance.supplierFk, subject: 'Añadida cuenta bancaria al proveedor' + ctx.instance.supplierFk,
body: user.username + ' ha añadido: ' + body: user.username + ' ha añadido: ' +
ctx.instance.iban + ', entidad: ' + bankEntity.name + ', bic: ' + bankEntity.bic ctx.instance.iban + ', entidad: ' + bankEntity.name + ', bic: ' + bankEntity.bic

View File

@ -174,7 +174,7 @@ module.exports = Self => {
const emailSubject = subject + ' ' + user.name; const emailSubject = subject + ' ' + user.name;
await Self.app.models.Mail.create({ await Self.app.models.Mail.create({
sender: sendTo, receiver: sendTo,
subject: emailSubject, subject: emailSubject,
body: emailBody body: emailBody
}); });

View File

@ -87,7 +87,7 @@ module.exports = Self => {
await models.Mail.create({ await models.Mail.create({
subject: $t('Absence change notification on the labour calendar'), subject: $t('Absence change notification on the labour calendar'),
body: body, body: body,
sender: department.notificationEmail receiver: department.notificationEmail
}, myOptions); }, myOptions);
} }

View File

@ -71,7 +71,7 @@ module.exports = Self => {
await models.Mail.create({ await models.Mail.create({
subject: $t('Absence change notification on the labour calendar'), subject: $t('Absence change notification on the labour calendar'),
body: body, body: body,
sender: department.notificationEmail receiver: department.notificationEmail
}, myOptions); }, myOptions);
} }

View File

@ -257,16 +257,3 @@ table {
background-color: #FFF; background-color: #FFF;
padding: 5px padding: 5px
} }
.signature {
width: 100%
}
.signature section {
height: 150px
}
.signature p {
margin-right: 50%;
margin-top: 140px
}

View File

@ -1,5 +1,6 @@
const db = require('../core/database'); const db = require('../core/database');
const Email = require('../core/email'); const Email = require('../core/email');
const Report = require('../core/report');
const smtp = require('../core/smtp'); const smtp = require('../core/smtp');
const config = require('../core/config'); const config = require('../core/config');
@ -195,7 +196,8 @@ module.exports = app => {
if (!ticket.recipient) { if (!ticket.recipient) {
const body = `No se ha podido enviar el albarán <strong>${ticket.id}</strong> const body = `No se ha podido enviar el albarán <strong>${ticket.id}</strong>
al cliente <strong>${ticket.clientFk}</strong> porque no tiene un email especificado.<br/><br/> al cliente <strong>${ticket.clientFk}</strong> porque no tiene un email especificado.<br/><br/>
Para dejar de recibir esta notificación, asígnale un email o desactiva la notificación por email para este cliente.`; Para dejar de recibir esta notificación, asígnale un email o desactiva
la notificación por email para este cliente.`;
smtp.send({ smtp.send({
to: ticket.salesPersonEmail, to: ticket.salesPersonEmail,
subject: 'No se ha podido enviar el albarán', subject: 'No se ha podido enviar el albarán',
@ -207,22 +209,37 @@ module.exports = app => {
const hasToInvoice = ticket.hasToInvoice && ticket.hasDailyInvoice; const hasToInvoice = ticket.hasToInvoice && ticket.hasDailyInvoice;
if (hasToInvoice) { if (hasToInvoice) {
const invoiceId = await db.findValue(` const invoice = await db.findOne(`
SELECT io.id SELECT io.id, io.ref, io.serial, cny.code companyCode
FROM ticket t FROM ticket t
JOIN invoiceOut io ON io.ref = t.refFk JOIN invoiceOut io ON io.ref = t.refFk
JOIN company cny ON cny.id = io.companyFk
WHERE t.id = ? WHERE t.id = ?
`, [ticket.id]); `, [ticket.id]);
const args = Object.assign({ const args = Object.assign({
invoiceId: invoiceId, invoiceId: invoice.id,
recipientId: ticket.clientFk, recipientId: ticket.clientFk,
recipient: ticket.recipient, recipient: ticket.recipient,
replyTo: ticket.salesPersonEmail replyTo: ticket.salesPersonEmail
}, reqArgs); }, reqArgs);
let mailOptions = {};
if (invoice.serial == 'E' && invoice.companyCode == 'VNL') {
const exportation = new Report('exportation', args);
const stream = await exportation.toPdfStream();
const fileName = `exportation-${invoice.ref}.pdf`;
mailOptions = {
overrideAttachments: false,
attachments: [{
filename: fileName,
content: stream
}]
};
}
const email = new Email('invoice', args); const email = new Email('invoice', args);
await email.send(); await email.send(mailOptions);
} else { } else {
const args = Object.assign({ const args = Object.assign({
ticketId: ticket.id, ticketId: ticket.id,

View File

@ -0,0 +1,8 @@
const Stylesheet = require(`${appPath}/core/stylesheet`);
module.exports = new Stylesheet([
`${appPath}/common/css/layout.css`,
`${appPath}/common/css/report.css`,
`${appPath}/common/css/misc.css`,
`${__dirname}/style.css`])
.mergeStyles();

View File

@ -0,0 +1,12 @@
.grid-block {
font-size: 1.2em
}
ul li {
margin-bottom: 20px;
text-align: justify;
}
.signature img {
width: 400px
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html v-bind:lang="$i18n.locale">
<body>
<table class="grid">
<tbody>
<tr>
<td>
<!-- Header block -->
<report-header v-bind="$props"></report-header>
<!-- Block -->
<div class="grid-row">
<div class="grid-block">
<h1 class="title centered uppercase">{{$t('title')}}</h1>
<p>{{$t('toAttention')}}</p>
<p v-html="$t('declaration', [invoice.ref, issued])"></p>
<p>
<ul>
<li v-for="responsibility in $t('responsibilities')">
{{responsibility}}
</li>
</ul>
</p>
<div class="signature">
<p>{{$t('issued', [
'Algemesí',
invoice.issued.getDate(),
$t('months')[invoice.issued.getMonth()],
invoice.issued.getFullYear()])
}}
</p>
<p><em>({{$t('signature')}})</em></p>
<img v-bind:src="getReportSrc('signature.png')">
<p>
<div>{{$t('signer.name')}}: JUAN VICENTE FERRER ROIG</div>
<div>{{$t('signer.ID')}}: 73943586N</div>
<div>{{$t('signer.position')}}: ADMINISTRADOR</div>
</p>
</div>
</div>
</div>
<!-- Footer block -->
<report-footer id="pageFooter"
v-bind:left-text="$t('invoice', [invoice.ref])"
v-bind="$props">
</report-footer>
</td>
</tr>
</tbody>
</table>
</body>
</html>

View File

@ -0,0 +1,34 @@
const Component = require(`${appPath}/core/component`);
const reportHeader = new Component('report-header');
const reportFooter = new Component('report-footer');
module.exports = {
name: 'exportation',
async serverPrefetch() {
this.invoice = await this.fetchInvoice(this.invoiceId);
if (!this.invoice)
throw new Error('Something went wrong');
},
methods: {
fetchInvoice(invoiceId) {
return this.findOneFromDef('invoice', [invoiceId]);
}
},
computed: {
issued: function() {
const filters = this.$options.filters;
return filters.date(this.invoice.issued, '%d-%m-%Y');
}
},
components: {
'report-header': reportHeader.build(),
'report-footer': reportFooter.build()
},
props: {
invoiceId: {
required: true
}
}
};

View File

@ -0,0 +1,50 @@
title: 'Carta CITES'
toAttention: 'A la atención del Sr. Administrador de la Aduana de la Farga de Moles.'
declaration: 'Por la presente DECLARO, bajo mi responsabilidad, que las mercancías detalladas en la factura
n° <strong>{0}</strong> de fecha <strong>{1}</strong>
asi como ninguno de sus componentes,'
issued: 'En {0}, a {1} de {2} de {3}'
invoice: 'Factura {0}'
responsibilities:
- 'NO están comprendidas en la Convención de Washington (CITES). Reglamento (CE) n° 338/1997
DO L61 de 3.3.1997 y sus últimas modificaciones, relativo a la protección de especies de fauna y
flora silvestres.'
- 'NO están incluidas en las listas del Anexo I del R/CE 428/2009 y sus posteriores modificaciones,
por lo que NO puede considerarse productos ni tecnologias de Doble Uso ni de uso militar.
No estando incluidas en la Relación de Material de Defensa del Anexo I del Real Decreto
679/2014, estando exentas a todos los efectos de autorizaciones administrativas para su comercio
exterior.'
- 'NO están incluidas los Anexos II, III y IV del R/UE 2019/125 L-30 de 31/01/2019
y sus modificaciones, sobre el comercio de determinados productos que pueden utilizarse para
aplicar la pena de muerte o infligir tortura u otros tratos o penas crueles, inhumanos o
degradantes.'
- 'NO están incluidas en el ANEXO ni en el ANEXO V del Reglamento (UE) N° 649/2012 y
sus modificaciones, relativo a la exportación e importación de productos químicos
peligrosos. ni tampoco contienen mercurio.'
- 'NO están sujetas al Reglamento/CE 1005/2009 L-286 de 30-10-2009 y sus
modificaciones, relativo a las mercancías que agotan la capa de ozono.'
- 'NO están afectadas por la prohibición a las importaciones de gases fluorados de
efecto invernadero, de acuerdo con el R/UE 517/2014.'
- 'NO están sujetas al Reglamento (CE) 116/2009 relativo a la exportación de bienes
culturales; y NO están sujetas a la Ley 16/1985, de 25 de junio, del Patrimonio
Histórico Español, estando exentas de Autorización Administrativa de Exportación.'
- 'NO están sujetos a las disposiciones del Reglamento (CE) Nº 1013/2006, relativo
a los traslados de residuos, y que en ningún modo pueden considerarse afectados por este control.'
signature: Firma y sello de la empresa
signer:
name: Nombre del firmante
ID: DNI del firmante
position: Cargo del firmante
months:
- 'Enero'
- 'Febrero'
- 'Marzo'
- 'Abril'
- 'Mayo'
- 'Junio'
- 'Julio'
- 'Agosto'
- 'Septiembre'
- 'Octubre'
- 'Noviembre'
- 'Diciembre'

View File

@ -0,0 +1,6 @@
SELECT
io.id,
io.ref,
io.issued
FROM invoiceOut io
WHERE io.id = ?