diff --git a/modules/client/back/methods/receipt/balanceCompensationEmail.js b/modules/client/back/methods/receipt/balanceCompensationEmail.js new file mode 100644 index 000000000..e9ded147d --- /dev/null +++ b/modules/client/back/methods/receipt/balanceCompensationEmail.js @@ -0,0 +1,40 @@ +const {Email} = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('balanceCompensationEmail', { + description: 'Sends the debit balances compensation email with an attached PDF', + accessType: 'WRITE', + accepts: [ + { + arg: 'id', + type: 'Number', + required: true, + description: 'The receipt id', + http: { source: 'path' } + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: '/:id/balance-compensation-email', + verb: 'POST' + } + }); + + Self.balanceCompensationEmail = async (ctx, id) => { + + const models = Self.app.models; + const receipt = await models.Receipt.findById(id, {fields: ['clientFk']}); + const client = await models.Client.findById(receipt.clientFk, {fields:['email']}); + + const email = new Email('balance-compensation', { + lang: ctx.req.getLocale(), + recipient: client.email+',administracion@verdnatura.es', + id + }); + + return email.send(); + }; +}; diff --git a/modules/client/back/methods/receipt/balanceCompensationPdf.js b/modules/client/back/methods/receipt/balanceCompensationPdf.js new file mode 100644 index 000000000..ff8713253 --- /dev/null +++ b/modules/client/back/methods/receipt/balanceCompensationPdf.js @@ -0,0 +1,50 @@ +const { Report } = require('vn-print'); + +module.exports = Self => { + Self.remoteMethodCtx('balanceCompensationPdf', { + description: 'Returns the the debit balances compensation pdf', + accessType: 'READ', + accepts: [ + { + arg: 'id', + type: 'number', + required: true, + description: 'The receipt 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/balance-compensation-pdf', + verb: 'GET' + } + }); + + Self.balanceCompensationPdf = async(ctx, id) => { + const args = Object.assign({}, ctx.args); + const params = {lang: ctx.req.getLocale()}; + + delete args.ctx; + for (const param in args) + params[param] = args[param]; + + const report = new Report('balance-compensation', params); + const stream = await report.toPdfStream(); + + return [stream, 'application/pdf', `filename="doc-${id}.pdf"`]; + }; +}; diff --git a/modules/client/back/models/receipt.js b/modules/client/back/models/receipt.js index b79102e6b..3118cc239 100644 --- a/modules/client/back/models/receipt.js +++ b/modules/client/back/models/receipt.js @@ -2,6 +2,8 @@ const LoopBackContext = require('loopback-context'); module.exports = function(Self) { require('../methods/receipt/filter')(Self); + require('../methods/receipt/balanceCompensationEmail')(Self); + require('../methods/receipt/balanceCompensationPdf')(Self); require('../methods/receipt/receiptPdf')(Self); Self.validateBinded('amountPaid', isNotZero, { diff --git a/modules/client/front/balance/index/index.html b/modules/client/front/balance/index/index.html index 3c61d8543..1e0716112 100644 --- a/modules/client/front/balance/index/index.html +++ b/modules/client/front/balance/index/index.html @@ -121,9 +121,22 @@ - - - + + + + + + + + + diff --git a/modules/client/front/balance/index/index.js b/modules/client/front/balance/index/index.js index 7e09e018c..b2529924f 100644 --- a/modules/client/front/balance/index/index.js +++ b/modules/client/front/balance/index/index.js @@ -2,8 +2,9 @@ import ngModule from '../../module'; import Section from 'salix/components/section'; class Controller extends Section { - constructor($element, $) { + constructor($element, $, vnEmail) { super($element, $); + this.vnEmail = vnEmail; this.filter = { include: { relation: 'company', @@ -54,45 +55,49 @@ class Controller extends Section { } })).then(() => this.getBalances()); } - + getCurrentBalance() { const clientRisks = this.$.riskModel.data; const selectedCompany = this.companyId; const currentBalance = clientRisks.find(balance => { return balance.companyFk === selectedCompany; }); - + return currentBalance && currentBalance.amount; } - + getBalances() { const balances = this.$.model.data; balances.forEach((balance, index) => { if (index === 0) - balance.balance = this.getCurrentBalance(); + balance.balance = this.getCurrentBalance(); if (index > 0) { let previousBalance = balances[index - 1]; balance.balance = previousBalance.balance - (previousBalance.debit - previousBalance.credit); } }); } - + showInvoiceOutDescriptor(event, balance) { if (!balance.isInvoice) return; if (event.defaultPrevented) return; - + this.$.invoiceOutDescriptor.show(event.target, balance.id); } - + changeDescription(balance) { const params = {description: balance.description}; const endpoint = `Receipts/${balance.id}`; this.$http.patch(endpoint, params) - .then(() => this.vnApp.showSuccess(this.$t('Data saved!'))); + .then(() => this.vnApp.showSuccess(this.$t('Data saved!'))); + } + + sendEmail(balance) { + return this.vnEmail.send(`Receipts/${balance.id}/balance-compensation-email`); } } -Controller.$inject = ['$element', '$scope']; +Controller.$inject = ['$element', '$scope', 'vnEmail']; ngModule.vnComponent('vnClientBalanceIndex', { template: require('./index.html'), diff --git a/modules/client/front/balance/index/locale/es.yml b/modules/client/front/balance/index/locale/es.yml index 05ef7070a..de710869e 100644 --- a/modules/client/front/balance/index/locale/es.yml +++ b/modules/client/front/balance/index/locale/es.yml @@ -8,4 +8,6 @@ Havings: Haber Balance: Balance Total by company: Total por empresa Download PDF: Descargar PDF -BILL: N/FRA {{ref}} \ No newline at end of file +Send compensation: Enviar compensación +BILL: N/FRA {{ref}} +Notify compensation: ¿Desea informar de la compensación al cliente por correo? \ No newline at end of file diff --git a/print/templates/email/balance-compensation/assets/css/import.js b/print/templates/email/balance-compensation/assets/css/import.js new file mode 100644 index 000000000..4b4bb7086 --- /dev/null +++ b/print/templates/email/balance-compensation/assets/css/import.js @@ -0,0 +1,11 @@ +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); + +module.exports = new Stylesheet([ + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`]) + .mergeStyles(); diff --git a/print/templates/email/balance-compensation/attachments.json b/print/templates/email/balance-compensation/attachments.json new file mode 100644 index 000000000..d2bf461c5 --- /dev/null +++ b/print/templates/email/balance-compensation/attachments.json @@ -0,0 +1,6 @@ +[ + { + "filename": "balance-compensation.pdf", + "component": "balance-compensation" + } +] \ No newline at end of file diff --git a/print/templates/email/balance-compensation/balance-compensation.html b/print/templates/email/balance-compensation/balance-compensation.html new file mode 100644 index 000000000..c7388a7a3 --- /dev/null +++ b/print/templates/email/balance-compensation/balance-compensation.html @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + +
+ +
+
+
+ +
+
+ +
+
+ +
+
+

{{$t('description.instructions')}} {{client.name}}

+

{{$t('description.attached')}}

+

{{$t('description.response')}}

+

{{$t('description.regards')}}

+
+
+ +
+
+ + +
+
+ +
+
+ +
+
+ +
+
+
+
+ + \ No newline at end of file diff --git a/print/templates/email/balance-compensation/balance-compensation.js b/print/templates/email/balance-compensation/balance-compensation.js new file mode 100755 index 000000000..362e1b178 --- /dev/null +++ b/print/templates/email/balance-compensation/balance-compensation.js @@ -0,0 +1,39 @@ +const Component = require(`vn-print/core/component`); +const emailHeader = new Component('email-header'); +const emailFooter = new Component('email-footer'); +const attachment = new Component('attachment'); + + +module.exports = { + name: 'balance-compensation', + async serverPrefetch() { + this.client = await this.fetchClient(this.id); + }, + methods: { + fetchClient(id) { + return this.findOneFromDef('client', [id]); + }, + }, + components: { + 'email-header': emailHeader.build(), + 'email-footer': emailFooter.build(), + 'attachment': attachment.build() + }, + data() { + return { + attachments: [ + { + filename: 'balance-compensation.pdf', + type: 'pdf', + path: `Receipts/${this.id}/balance-compensation-pdf` + } + ] + }; + }, + props: { + id: { + type: Number, + required: true + } + } +}; diff --git a/print/templates/email/balance-compensation/locale/es.yml b/print/templates/email/balance-compensation/locale/es.yml new file mode 100644 index 000000000..44253bee2 --- /dev/null +++ b/print/templates/email/balance-compensation/locale/es.yml @@ -0,0 +1,6 @@ +subject: Compensación VerdNatura SL +description: + instructions: Buenos días, + attached: Adjuntamos escrito para su confirmación + response: Rogamos su respuesta a la mayor brevedad + regards: Un saludo \ No newline at end of file diff --git a/print/templates/email/balance-compensation/sql/client.sql b/print/templates/email/balance-compensation/sql/client.sql new file mode 100644 index 000000000..1e842d69d --- /dev/null +++ b/print/templates/email/balance-compensation/sql/client.sql @@ -0,0 +1,5 @@ +SELECT + c.name +FROM client c + JOIN receipt r ON r.clientFk = c.id +WHERE r.id = ?; \ No newline at end of file diff --git a/print/templates/reports/balance-compensation/balance-compensation.html b/print/templates/reports/balance-compensation/balance-compensation.html new file mode 100644 index 000000000..3291d66f4 --- /dev/null +++ b/print/templates/reports/balance-compensation/balance-compensation.html @@ -0,0 +1,41 @@ + + + + + + + + + + +
+ + + +
+
+
+
+

{{$t('Place')}} {{currentDate()}}

+

{{$t('Compensation') | uppercase}}

+

{{$t('In one hand')}}:

+

{{company.name}} {{$t('CIF')}} {{company.nif}} {{$t('Home')}} {{company.street}}, {{company.city}}.

+

{{$t('In other hand')}}:

+

{{$t('Sr')}} {{client.name}} {{$t('NIF')}} {{client.fi}} {{$t('Home')}} {{client.street}}, {{client.city}}.

+

{{$t('Agree') | uppercase}}

+

{{$t('Date')}} {{client.payed | date('%d-%m-%Y')}} {{$t('Compensate')}} {{client.amountPaid}} € {{$t('From client')}} {{client.name}} {{$t('To client')}} {{company.name}}.

+

{{$t('Reception')}} administracion@verdnatura.es

+
{{$t('Greetings')}}
+
+
+
+ +
+ + + +
+ + + \ No newline at end of file diff --git a/print/templates/reports/balance-compensation/balance-compensation.js b/print/templates/reports/balance-compensation/balance-compensation.js new file mode 100644 index 000000000..6227412a9 --- /dev/null +++ b/print/templates/reports/balance-compensation/balance-compensation.js @@ -0,0 +1,36 @@ +const Component = require(`vn-print/core/component`); +const reportHeader = new Component('report-header'); +const reportFooter = new Component('report-footer'); + +module.exports = { + name: 'balance-compensation', + async serverPrefetch() { + this.client = await this.fetchClient(this.id); + this.company = await this.fetchCompany(this.id); + }, + methods: { + fetchClient(id) { + return this.findOneFromDef('client', [id]); + }, + fetchCompany(id) { + return this.findOneFromDef('company', [id]); + }, + + currentDate() { + const current = new Date(); + const date = `${current.getDate()}/${current.getMonth()+1}/${current.getFullYear()}`; + return date; + } + }, + components: { + 'report-header': reportHeader.build(), + 'report-footer': reportFooter.build() + }, + props: { + id: { + type: Number, + required: true, + description: 'The receipt id' + } + } +}; diff --git a/print/templates/reports/balance-compensation/css/import.js b/print/templates/reports/balance-compensation/css/import.js new file mode 100644 index 000000000..37a98dfdd --- /dev/null +++ b/print/templates/reports/balance-compensation/css/import.js @@ -0,0 +1,12 @@ +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); + +module.exports = new Stylesheet([ + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/report.css`, + `${__dirname}/style.css`]) + .mergeStyles(); diff --git a/print/templates/reports/balance-compensation/locale/es.yml b/print/templates/reports/balance-compensation/locale/es.yml new file mode 100644 index 000000000..546e55f06 --- /dev/null +++ b/print/templates/reports/balance-compensation/locale/es.yml @@ -0,0 +1,16 @@ +reportName: compensacion-saldo +Place: Algemesí, a +Compensation: Compensación de saldos deudores y acreedores +In one hand: De una parte +CIF: con CIF +NIF: con NIF +Home: y domicilio sito en +In other hand: De la otra +Sr: Don/Doña +Agree: Acuerdan +Date: En fecha de +Compensate: se ha compensado el saldo de +From client: del cliente/proveedor +To client: con el cliente/proveedor +Reception: Por favor, rogamos confirmen la recepción de esta compensación al email +Greetings: Saludos cordiales, \ No newline at end of file diff --git a/print/templates/reports/balance-compensation/sql/client.sql b/print/templates/reports/balance-compensation/sql/client.sql new file mode 100644 index 000000000..92e6f6cab --- /dev/null +++ b/print/templates/reports/balance-compensation/sql/client.sql @@ -0,0 +1,12 @@ +SELECT + c.name, + c.socialName, + c.street, + c.fi, + c.city, + r.amountPaid, + r.payed + FROM client c + JOIN receipt r ON r.clientFk = c.id + JOIN supplier s ON c.fi = s.nif + WHERE r.id = ? \ No newline at end of file diff --git a/print/templates/reports/balance-compensation/sql/company.sql b/print/templates/reports/balance-compensation/sql/company.sql new file mode 100644 index 000000000..e61228a10 --- /dev/null +++ b/print/templates/reports/balance-compensation/sql/company.sql @@ -0,0 +1,8 @@ +SELECT + s.name, + s.nif, + s.street, + s.city + FROM supplier s + JOIN receipt r ON r.companyFk = s.id + WHERE r.id = ?; \ No newline at end of file