From a3a46d28be9c9caa0a394a7bdc2d1a3fff3a6855 Mon Sep 17 00:00:00 2001 From: Javier Segarra Date: Tue, 21 May 2024 23:58:25 +0200 Subject: [PATCH] feat(salix): refs #5926 report(1) --- .../back/methods/ticket/docuwareUpload.js | 4 +- .../back/methods/worker/docuwareUpload.js | 4 +- print/core/report.js | 2 +- .../reports/sign-pda/assets/css/import.js | 12 + .../reports/sign-pda/assets/css/style.css | 49 ++++ .../assets/images/europe.png | Bin .../templates/reports/sign-pda/locale/en.yml | 50 ++++ .../templates/reports/sign-pda/locale/es.yml | 2 + .../templates/reports/sign-pda/locale/fr.yml | 51 ++++ .../templates/reports/sign-pda/locale/pt.yml | 51 ++++ .../templates/reports/sign-pda/sign-pda.html | 252 ++++++++++++++++++ print/templates/reports/sign-pda/sign-pda.js | 110 ++++++++ 12 files changed, 582 insertions(+), 5 deletions(-) create mode 100644 print/templates/reports/sign-pda/assets/css/import.js create mode 100644 print/templates/reports/sign-pda/assets/css/style.css rename print/templates/reports/{delivery-note => sign-pda}/assets/images/europe.png (100%) create mode 100644 print/templates/reports/sign-pda/locale/en.yml create mode 100644 print/templates/reports/sign-pda/locale/es.yml create mode 100644 print/templates/reports/sign-pda/locale/fr.yml create mode 100644 print/templates/reports/sign-pda/locale/pt.yml create mode 100644 print/templates/reports/sign-pda/sign-pda.html create mode 100755 print/templates/reports/sign-pda/sign-pda.js diff --git a/modules/ticket/back/methods/ticket/docuwareUpload.js b/modules/ticket/back/methods/ticket/docuwareUpload.js index fdeeb4519..0b77b27c1 100644 --- a/modules/ticket/back/methods/ticket/docuwareUpload.js +++ b/modules/ticket/back/methods/ticket/docuwareUpload.js @@ -1,7 +1,7 @@ const axios = require('axios'); const {models} = require('vn-loopback/server/server'); const UserError = require('vn-loopback/util/user-error'); - +const isProduction = require('vn-loopback/server/boot/isProduction'); module.exports = Self => { Self.docuwareUpload = async({ctx, tabletFk, ids: ticketIds, myOptions, uri, docuwareOptions, dialogId}) => { for (id of ticketIds) { @@ -72,7 +72,7 @@ module.exports = Self => { ] }; - if (process.env.NODE_ENV != 'production') + if (!isProduction(false)) throw new UserError('Action not allowed on the test environment'); // delete old diff --git a/modules/worker/back/methods/worker/docuwareUpload.js b/modules/worker/back/methods/worker/docuwareUpload.js index 530b29ecc..37602729b 100644 --- a/modules/worker/back/methods/worker/docuwareUpload.js +++ b/modules/worker/back/methods/worker/docuwareUpload.js @@ -1,7 +1,7 @@ const axios = require('axios'); const {models} = require('vn-loopback/server/server'); const UserError = require('vn-loopback/util/user-error'); - +const isProduction = require('vn-loopback/server/boot/isProduction'); module.exports = Self => { Self.docuwareUpload = async({ctx, tabletFk, ids: workerId, myOptions, uri, docuwareOptions, dialogId}) => { if (!Array.isArray(workerId)) workerId = [workerId]; @@ -73,7 +73,7 @@ module.exports = Self => { ] }; - if (process.env.NODE_ENV != 'production') + if (!isProduction(false)) throw new UserError('Action not allowed on the test environment'); // delete old diff --git a/print/core/report.js b/print/core/report.js index 23cffac2c..fbef20a67 100644 --- a/print/core/report.js +++ b/print/core/report.js @@ -52,7 +52,7 @@ class Report extends Component { options.headerTemplate = '\n'; options.footerTemplate = footer; - const buffer = await page.pdf(options); + const buffer = await page.content(); resolve(buffer); } catch (err) { reject(err); diff --git a/print/templates/reports/sign-pda/assets/css/import.js b/print/templates/reports/sign-pda/assets/css/import.js new file mode 100644 index 000000000..37a98dfdd --- /dev/null +++ b/print/templates/reports/sign-pda/assets/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/sign-pda/assets/css/style.css b/print/templates/reports/sign-pda/assets/css/style.css new file mode 100644 index 000000000..3e1c64d85 --- /dev/null +++ b/print/templates/reports/sign-pda/assets/css/style.css @@ -0,0 +1,49 @@ +#signature { + padding-right: 10px +} + +#signature img { + -webkit-filter: brightness(0%); + filter: brightness(0%); + margin-bottom: 10px; + max-width: 150px +} + +.description strong { + text-transform: uppercase; +} + +h2 { + font-weight: 100; + color: #555 +} + +.ticket-info { + font-size: 22px +} + +#phytosanitary { + padding-right: 10px +} + +#phytosanitary .flag img { + width: 100% +} + +#phytosanitary .flag .flag-text { + padding-left: 10px; + box-sizing: border-box; +} + +.phytosanitary-info { + margin-top: 10px +} + +.observations { + text-align: justify; + text-justify: inter-word; +} + +.column-oriented { + margin-bottom: 5px; +} \ No newline at end of file diff --git a/print/templates/reports/delivery-note/assets/images/europe.png b/print/templates/reports/sign-pda/assets/images/europe.png similarity index 100% rename from print/templates/reports/delivery-note/assets/images/europe.png rename to print/templates/reports/sign-pda/assets/images/europe.png diff --git a/print/templates/reports/sign-pda/locale/en.yml b/print/templates/reports/sign-pda/locale/en.yml new file mode 100644 index 000000000..a1392e15e --- /dev/null +++ b/print/templates/reports/sign-pda/locale/en.yml @@ -0,0 +1,50 @@ +reportName: sign-pda +deliveryNote: Sign PDA +proforma: Proforma +withoutPrices: Sign PDA +clientId: Client +deliveryAddress: Delivery address +fiscalData: Fiscal data +saleLines: Line items +date: Date +reference: Ref. +quantity: Qty. +concept: Concept +price: PSP/u +discount: Disc. +vat: VAT +amount: Amount +total: Total +subtotal: Subtotal +vatType: VAT Type +digitalSignature: Digital signature +plantPassport: Plant passport +packages: Packages +services: + title: Services + theader: + quantity: Qty. + concept: Concept + price: PSP/u + vat: VAT + amount: Amount + tfoot: + subtotal: Subtotal + warning: Deposit packaging will be invoiced if they have not been returned after 30 days of their delivery. +packagings: + title: Buckets and packaging + theader: + reference: Reference + quantity: Quantity + concept: Concept +taxes: + title: Tax breakdown + theader: + type: Type + taxBase: Tax base + tax: Tax + fee: Fee + tfoot: + subtotal: Subtotal + total: Total +observations: Observations diff --git a/print/templates/reports/sign-pda/locale/es.yml b/print/templates/reports/sign-pda/locale/es.yml new file mode 100644 index 000000000..7f5b656c9 --- /dev/null +++ b/print/templates/reports/sign-pda/locale/es.yml @@ -0,0 +1,2 @@ +reportName: pda +signNote: Recepción PDA diff --git a/print/templates/reports/sign-pda/locale/fr.yml b/print/templates/reports/sign-pda/locale/fr.yml new file mode 100644 index 000000000..603623a47 --- /dev/null +++ b/print/templates/reports/sign-pda/locale/fr.yml @@ -0,0 +1,51 @@ +reportName: bon-de-livraison +deliveryNote: Bon de livraison +proforma: Proforma +withoutPrices: Bon de livraison +clientId: Client +deliveryAddress: Adresse de livraison +fiscalData: Coordonnées +saleLines: Lignes de la commande +date: Date +reference: Ref. +quantity: Quant. +concept: Concept +price: PRIX/u +discount: Remise +vat: TVA +amount: Montant +total: Total +subtotal: Total partiel +vatType: Type de TVA +digitalSignature: Signature numérique +ticket: BL {0} +plantPassport: Passeport phytosanitaire +packages: Paquets +services: + title: Service + theader: + quantity: Quantité + concept: Concept + price: PRIX/u + vat: TVA + amount: Montant + tfoot: + subtotal: Total partiel + warning: Les emballages de consigne seront facturés s'ils n'ont pas été retournés après 30 jours de leur livraison. +packagings: + title: Bacs et emballages + theader: + reference: Référence + quantity: Quantité + concept: Concept +taxes: + title: Répartition taxes + theader: + type: Type + taxBase: Base imposable + tax: Taxe + fee: Quote + tfoot: + subtotal: Total partiel + total: Total +observations: Observations \ No newline at end of file diff --git a/print/templates/reports/sign-pda/locale/pt.yml b/print/templates/reports/sign-pda/locale/pt.yml new file mode 100644 index 000000000..fb49d230b --- /dev/null +++ b/print/templates/reports/sign-pda/locale/pt.yml @@ -0,0 +1,51 @@ +reportName: nota-de-entrega +deliveryNote: Nota de Entrega +proforma: Proforma +withoutPrices: Nota de Entrega +clientId: Cliente +deliveryAddress: Morada de Entrega +fiscalData: Dados Fiscais +saleLines: Linhas da encomenda +date: Data +reference: Ref. +quantity: Qtde. +concept: Conceito +price: PVP/u +discount: Dto. +vat: IVA +amount: Importe +total: Total +subtotal: Sub-total +vatType: Tipo de IVA +digitalSignature: Assinatura digital +ticket: Nota de Entrega {0} +plantPassport: Passaporte vegetal +packages: Pacotes +services: + title: Serviços + theader: + quantity: Quantidade + concept: Conceito + price: PVP/u + vat: IVA + amount: Quantia + tfoot: + subtotal: Subtotal + warning: As embalagens em depósito serão facturadas e cobradas se não são devolvidas 30 dias após a entrega. +packagings: + title: Baldes e Embalagens + theader: + reference: Referência + quantity: Quantidade + concept: Conceito +taxes: + title: Repartição de impostos + theader: + type: Cara + taxBase: Tributável + tax: Taxa + fee: Compartilhado + tfoot: + subtotal: Subtotal + total: Total +observations: Observações \ No newline at end of file diff --git a/print/templates/reports/sign-pda/sign-pda.html b/print/templates/reports/sign-pda/sign-pda.html new file mode 100644 index 000000000..92dd1b126 --- /dev/null +++ b/print/templates/reports/sign-pda/sign-pda.html @@ -0,0 +1,252 @@ + + +
+
+
+
+
+

{{$t(deliverNoteType)}}

+ + + + + + + + + + + + + + + + + + + +
{{$t('clientId')}}{{client.id}}
{{$t(deliverNoteType)}}{{ticket.id}}
{{$t('date')}}{{formatDate(ticket.shipped, '%d-%m-%Y')}}
{{$t('packages')}}{{ticket.packages}}
+
+
+
+
+
{{$t('deliveryAddress')}}
+
+

{{address.nickname}}

+
{{address.street}}
+
{{address.postalCode}}, {{address.city}} ({{address.province}})
+
+
+ +
+
{{$t('fiscalData')}}
+
+
{{client.socialName}}
+
{{client.street}}
+
{{client.fi}}
+
+
+
+
+ +

{{$t('saleLines')}}

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{{$t('reference')}}{{$t('quantity')}}{{$t('concept')}}{{$t('price')}}{{$t('discount')}}{{$t('vat')}}{{$t('amount')}}
{{sale.itemFk}}{{sale.quantity}}{{sale.concept}}{{sale.price | currency('EUR', $i18n.locale)}}{{(sale.discount / 100) | percentage}}{{sale.vatType}} + {{sale.price * sale.quantity * (1 - sale.discount / 100) | currency('EUR', $i18n.locale)}} +
+ {{sale.tag5}} {{sale.value5}} + {{sale.tag6}} {{sale.value6}} + {{sale.tag7}} {{sale.value7}} +
+ {{$t('subtotal')}} + {{getSubTotal() | currency('EUR', $i18n.locale)}}
+ +
+
+

{{$t('services.title')}}

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{{$t('services.theader.quantity')}}{{$t('services.theader.concept')}}{{$t('services.theader.price')}}{{$t('services.theader.vat')}}{{$t('services.theader.amount')}}
{{service.quantity}}{{service.description}}{{service.price | currency('EUR', $i18n.locale)}}{{service.taxDescription}}{{service.total | currency('EUR', $i18n.locale)}}
+ {{$t('services.tfoot.subtotal')}} + {{serviceTotal | currency('EUR', $i18n.locale)}}
+ * {{ $t('services.warning') }} +
+
+
+
+

{{$t('packagings.title')}}

+ + + + + + + + + + + + + + + +
{{$t('packagings.theader.reference')}}{{$t('packagings.theader.quantity')}}{{$t('packagings.theader.concept')}}
{{packaging.itemFk}}{{packaging.quantity}}{{packaging.name}}
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{{$t('taxes.title')}}
{{$t('taxes.theader.type')}}{{$t('taxes.theader.taxBase')}}{{$t('taxes.theader.tax')}}{{$t('taxes.theader.fee')}}
{{tax.name}}{{tax.Base | currency('EUR', $i18n.locale)}}{{tax.vatPercent | percentage}}{{tax.tax | currency('EUR', $i18n.locale)}}
{{$t('subtotal')}}{{getTotalBase() | currency('EUR', $i18n.locale)}}{{getTotalTax()| currency('EUR', $i18n.locale)}}
{{$t('total')}}{{getTotal() | currency('EUR', $i18n.locale)}}
+
+ +
+
+
+
+
+
+ +
+
{{$t('plantPassport')}}
+
+
+
+
+ A + {{getBotanical()}} +
+
+ B + ES17462130 +
+
+ C + {{ticket.id}} +
+
+ D + ES +
+
+
+
+
+
+
+
+
+
{{$t('digitalSignature')}}
+
+ +
{{formatDate(signature.created, '%d-%m-%Y')}}
+
+
+
+
+
+
+

{{$t('observations')}}

+

{{ticket.description}}

+
+
+
+
+ +
\ No newline at end of file diff --git a/print/templates/reports/sign-pda/sign-pda.js b/print/templates/reports/sign-pda/sign-pda.js new file mode 100755 index 000000000..50d5720ad --- /dev/null +++ b/print/templates/reports/sign-pda/sign-pda.js @@ -0,0 +1,110 @@ +const config = require(`vn-print/core/config`); +const vnReport = require('../../../core/mixins/vn-report.js'); +const md5 = require('md5'); +const fs = require('fs-extra'); + +module.exports = { + name: 'delivery-note', + mixins: [vnReport], + async serverPrefetch() { + this.ticket = await this.findOneFromDef('ticket', [this.id]); + this.checkMainEntity(this.ticket); + this.client = await this.findOneFromDef('client', [this.id]); + this.sales = await this.rawSqlFromDef('sales', [this.id]); + this.address = await this.findOneFromDef(`address`, [this.id]); + this.services = await this.rawSqlFromDef('services', [this.id]); + this.taxes = await this.findOneFromDef('taxes', [this.id]); + this.packagings = await this.rawSqlFromDef('packagings', [this.id]); + this.signature = await this.findOneFromDef('signature', [this.id]); + }, + data() { + return {totalBalance: 0.00}; + }, + computed: { + dmsPath() { + if (!this.signature) return; + + const hash = md5(this.signature.id.toString()).substring(0, 3); + const file = `${config.storage.root}/${hash}/${this.signature.id}.png`; + + if (!fs.existsSync(file)) return null; + + const src = fs.readFileSync(file); + const base64 = Buffer.from(src, 'utf8').toString('base64'); + + return `data:image/png;base64, ${base64}`; + }, + deliverNoteType() { + return this.type ? this.type : 'deliveryNote'; + }, + serviceTotal() { + let total = 0.00; + this.services.forEach(service => { + total += parseFloat(service.price) * service.quantity; + }); + + return total; + }, + showPrices() { + return this.deliverNoteType != 'withoutPrices'; + }, + footerType() { + const translatedType = this.$t(this.deliverNoteType); + return `${translatedType} ${this.id}`; + }, + hasObservations() { + return this.ticket.description !== null; + } + }, + methods: { + getSubTotal() { + let subTotal = 0.00; + this.sales.forEach(sale => { + subTotal += sale.quantity * sale.price * (1 - sale.discount / 100); + }); + + return subTotal; + }, + getTotalBase() { + let totalBase = 0.00; + this.taxes.forEach(tax => { + totalBase += parseFloat(tax.Base); + }); + + return totalBase; + }, + getTotalTax() { + let totalTax = 0.00; + this.taxes.forEach(tax => { + totalTax += parseFloat(tax.tax); + }); + + return totalTax; + }, + getTotal() { + return this.getTotalBase() + this.getTotalTax(); + }, + getBotanical() { + let phytosanitary = []; + this.sales.forEach(sale => { + if (sale.botanical) + phytosanitary.push(sale.botanical); + }); + + return phytosanitary.filter((item, index) => + phytosanitary.indexOf(item) == index + ).join(', '); + } + }, + props: { + id: { + type: Number, + required: true, + description: 'The ticket id' + }, + type: { + type: String, + required: false + } + } +};