4548-invoiceIn-pdf #1113
|
@ -0,0 +1,4 @@
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||||
|
VALUES
|
||||||
|
('InvoiceIn', 'invoiceInPdf', 'READ', 'ALLOW', 'ROLE', 'administrative'),
|
||||||
|
('InvoiceIn', 'invoiceInEmail', 'WRITE', 'ALLOW', 'ROLE', 'administrative'),
|
||||||
alexm marked this conversation as resolved
|
|
@ -0,0 +1,53 @@
|
||||||
|
const {Email} = require('vn-print');
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethodCtx('invoiceInEmail', {
|
||||||
|
description: 'Sends the invoice in email with an attached PDF',
|
||||||
|
accessType: 'WRITE',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'id',
|
||||||
|
type: 'number',
|
||||||
|
required: true,
|
||||||
|
description: 'The invoice id',
|
||||||
|
http: {source: 'path'}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'recipient',
|
||||||
|
type: 'string',
|
||||||
|
description: 'The recipient email',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'recipientId',
|
||||||
|
type: 'number',
|
||||||
|
description: 'The recipient id to send to the recipient preferred language',
|
||||||
|
required: false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
returns: {
|
||||||
|
type: ['object'],
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: '/:id/invoice-in-email',
|
||||||
|
verb: 'POST'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.invoiceInEmail = async ctx => {
|
||||||
|
const args = Object.assign({}, ctx.args);
|
||||||
|
const params = {
|
||||||
|
recipient: args.recipient,
|
||||||
|
lang: ctx.req.getLocale()
|
||||||
|
};
|
||||||
|
|
||||||
|
delete args.ctx;
|
||||||
|
for (const param in args)
|
||||||
|
params[param] = args[param];
|
||||||
|
|
||||||
|
const email = new Email('invoiceIn', params);
|
||||||
|
|
||||||
|
return email.send();
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,50 @@
|
||||||
|
const {Report} = require('vn-print');
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethodCtx('invoiceInPdf', {
|
||||||
|
description: 'Returns the invoiceIn pdf',
|
||||||
alexm marked this conversation as resolved
Outdated
joan
commented
Invoice in pdf Invoice in pdf
|
|||||||
|
accessType: 'READ',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'id',
|
||||||
|
type: 'number',
|
||||||
|
required: true,
|
||||||
|
description: 'The invoiceIn id',
|
||||||
alexm marked this conversation as resolved
Outdated
joan
commented
Invoice id? Invoice 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/invoice-in-pdf',
|
||||||
|
verb: 'GET'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.invoiceInPdf = 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('invoiceIn', params);
|
||||||
|
const stream = await report.toPdfStream();
|
||||||
|
|
||||||
|
return [stream, 'application/pdf', `filename="doc-${id}.pdf"`];
|
||||||
|
};
|
||||||
|
};
|
|
@ -4,4 +4,6 @@ module.exports = Self => {
|
||||||
require('../methods/invoice-in/clone')(Self);
|
require('../methods/invoice-in/clone')(Self);
|
||||||
require('../methods/invoice-in/toBook')(Self);
|
require('../methods/invoice-in/toBook')(Self);
|
||||||
require('../methods/invoice-in/getTotals')(Self);
|
require('../methods/invoice-in/getTotals')(Self);
|
||||||
|
require('../methods/invoice-in/invoiceInPdf')(Self);
|
||||||
|
require('../methods/invoice-in/invoiceInEmail')(Self);
|
||||||
};
|
};
|
||||||
|
|
|
@ -94,6 +94,11 @@
|
||||||
"model": "Supplier",
|
"model": "Supplier",
|
||||||
"foreignKey": "supplierFk"
|
"foreignKey": "supplierFk"
|
||||||
},
|
},
|
||||||
|
"supplierContact": {
|
||||||
|
"type": "hasMany",
|
||||||
|
"model": "SupplierContact",
|
||||||
|
"foreignKey": "supplierFk"
|
||||||
|
},
|
||||||
"currency": {
|
"currency": {
|
||||||
"type": "belongsTo",
|
"type": "belongsTo",
|
||||||
"model": "Currency",
|
"model": "Currency",
|
||||||
|
|
|
@ -8,6 +8,14 @@ class Controller extends ModuleCard {
|
||||||
{
|
{
|
||||||
relation: 'supplier'
|
relation: 'supplier'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
relation: 'supplierContact',
|
||||||
|
scope: {
|
||||||
|
where: {
|
||||||
|
email: {neq: null}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
relation: 'invoiceInDueDay'
|
relation: 'invoiceInDueDay'
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
translate>
|
translate>
|
||||||
To book
|
To book
|
||||||
</vn-item>
|
</vn-item>
|
||||||
|
|
||||||
<vn-item
|
<vn-item
|
||||||
ng-click="deleteConfirmation.show()"
|
ng-click="deleteConfirmation.show()"
|
||||||
vn-acl="administrative"
|
vn-acl="administrative"
|
||||||
|
@ -26,6 +25,16 @@
|
||||||
translate>
|
translate>
|
||||||
Clone Invoice
|
Clone Invoice
|
||||||
</vn-item>
|
</vn-item>
|
||||||
|
<vn-item
|
||||||
|
ng-click="$ctrl.showPdfInvoice()"
|
||||||
|
translate>
|
||||||
|
Show agricultural invoice as PDF
|
||||||
|
</vn-item>
|
||||||
|
<vn-item
|
||||||
|
ng-click="sendPdfConfirmation.show({email: $ctrl.entity.supplierContact[0].email})"
|
||||||
|
translate>
|
||||||
|
Send agricultural invoice as PDF
|
||||||
|
</vn-item>
|
||||||
</slot-menu>
|
</slot-menu>
|
||||||
<slot-body>
|
<slot-body>
|
||||||
<div class="attributes">
|
<div class="attributes">
|
||||||
|
@ -83,3 +92,21 @@
|
||||||
<vn-popup vn-id="summary">
|
<vn-popup vn-id="summary">
|
||||||
<vn-invoice-in-summary invoice-in="$ctrl.invoiceIn"></vn-invoice-in-summary>
|
<vn-invoice-in-summary invoice-in="$ctrl.invoiceIn"></vn-invoice-in-summary>
|
||||||
</vn-popup>
|
</vn-popup>
|
||||||
|
|
||||||
|
<!-- Send PDF invoice confirmation popup -->
|
||||||
|
<vn-dialog
|
||||||
|
vn-id="sendPdfConfirmation"
|
||||||
|
on-accept="$ctrl.sendPdfInvoice($data)"
|
||||||
|
message="Send PDF invoice">
|
||||||
|
<tpl-body>
|
||||||
|
<span translate>Are you sure you want to send it?</span>
|
||||||
|
<vn-textfield vn-one
|
||||||
|
label="Email"
|
||||||
|
ng-model="sendPdfConfirmation.data.email">
|
||||||
|
</vn-textfield>
|
||||||
|
</tpl-body>
|
||||||
|
<tpl-buttons>
|
||||||
|
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
|
||||||
|
<button response="accept" translate>Confirm</button>
|
||||||
|
</tpl-buttons>
|
||||||
|
</vn-dialog>
|
||||||
|
|
|
@ -96,6 +96,20 @@ class Controller extends Descriptor {
|
||||||
.then(() => this.$state.reload())
|
.then(() => this.$state.reload())
|
||||||
.then(() => this.vnApp.showSuccess(this.$t('InvoiceIn booked')));
|
.then(() => this.vnApp.showSuccess(this.$t('InvoiceIn booked')));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showPdfInvoice() {
|
||||||
|
this.vnReport.show(`InvoiceIns/${this.id}/invoice-in-pdf`);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendPdfInvoice($data) {
|
||||||
|
if (!$data.email)
|
||||||
|
return this.vnApp.showError(this.$t(`The email can't be empty`));
|
||||||
|
|
||||||
|
return this.vnEmail.send(`InvoiceIns/${this.entity.id}/invoice-in-email`, {
|
||||||
|
recipient: $data.email,
|
||||||
|
recipientId: this.entity.supplier.id
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngModule.vnComponent('vnInvoiceInDescriptor', {
|
ngModule.vnComponent('vnInvoiceInDescriptor', {
|
||||||
|
|
|
@ -19,3 +19,5 @@ To book: Contabilizar
|
||||||
Total amount: Total importe
|
Total amount: Total importe
|
||||||
Total net: Total neto
|
Total net: Total neto
|
||||||
Total stems: Total tallos
|
Total stems: Total tallos
|
||||||
|
Show agricultural invoice as PDF: Ver factura agrícola como PDF
|
||||||
alexm marked this conversation as resolved
Outdated
jgallego
commented
i minuscula, y per a l'anglés posa que es agricola. i minuscula, y per a l'anglés posa que es agricola.
|
|||||||
|
Send agricultural invoice as PDF: Enviar factura agrícola como PDF
|
||||||
|
|
|
@ -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();
|
|
@ -0,0 +1,6 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"filename": "invoiceIn.pdf",
|
||||||
|
"component": "invoiceIn"
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,47 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html v-bind:lang="$i18n.locale">
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width">
|
||||||
|
<meta name="format-detection" content="telephone=no">
|
||||||
|
<title>{{ $t('subject') }}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<table class="grid">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<!-- Empty block -->
|
||||||
|
<div class="grid-row">
|
||||||
|
<div class="grid-block empty"></div>
|
||||||
|
</div>
|
||||||
|
<!-- Header block -->
|
||||||
|
<div class="grid-row">
|
||||||
|
<div class="grid-block">
|
||||||
|
<email-header v-bind="$props"></email-header>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Block -->
|
||||||
|
<div class="grid-row">
|
||||||
|
<div class="grid-block vn-pa-ml">
|
||||||
|
<h1>{{ $t('title') }}</h1>
|
||||||
|
<p>{{$t('dear')}},</p>
|
||||||
|
<p v-html="$t('description')"></p>
|
||||||
|
<p v-html="$t('conclusion')"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Footer block -->
|
||||||
|
<div class="grid-row">
|
||||||
|
<div class="grid-block">
|
||||||
|
<email-footer v-bind="$props"></email-footer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Empty block -->
|
||||||
|
<div class="grid-row">
|
||||||
|
<div class="grid-block empty"></div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,11 @@
|
||||||
|
const Component = require(`vn-print/core/component`);
|
||||||
|
const emailHeader = new Component('email-header');
|
||||||
|
const emailFooter = new Component('email-footer');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: 'invoiceIn',
|
||||||
|
components: {
|
||||||
|
'email-header': emailHeader.build(),
|
||||||
|
'email-footer': emailFooter.build()
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,5 @@
|
||||||
|
subject: Your agricultural invoice
|
||||||
|
title: Your agricultural invoice
|
||||||
|
dear: Dear supplier
|
||||||
|
description: Attached you can find agricultural receipt generated from your last deliveries. Please return a signed and stamped copy to our administration department.
|
||||||
|
conclusion: Thanks for your attention!
|
|
@ -0,0 +1,5 @@
|
||||||
|
subject: Tu factura agrícola
|
||||||
|
title: Tu factura agrícola
|
||||||
|
dear: Estimado proveedor
|
||||||
|
description: Adjunto puede encontrar recibo agrícola generado de sus últimas entregas. Por favor, devuelva una copia firmada y sellada a nuestro de departamento de administración.
|
||||||
|
conclusion: ¡Gracias por tu atención!
|
|
@ -0,0 +1,5 @@
|
||||||
|
subject: Votre facture agricole
|
||||||
|
title: Votre facture agricole
|
||||||
|
dear: Cher Fournisseur
|
||||||
|
description: Vous trouverez en pièce jointe le reçu agricole généré à partir de vos dernières livraisons. Veuillez retourner une copie signée et tamponnée à notre service administratif.
|
||||||
|
conclusion: Merci pour votre attention!
|
|
@ -0,0 +1,5 @@
|
||||||
|
subject: A sua fatura agrícola
|
||||||
|
title: A sua fatura agrícola
|
||||||
|
dear: Caro Fornecedor
|
||||||
|
description: Em anexo encontra-se o recibo agrícola gerado a partir das suas últimas entregas. Por favor, devolva uma cópia assinada e carimbada ao nosso departamento de administração.
|
||||||
|
conclusion: Obrigado pela atenção.
|
|
@ -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();
|
|
@ -0,0 +1,42 @@
|
||||||
|
h2 {
|
||||||
|
font-weight: 100;
|
||||||
|
color: #555
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-title {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
font-size: .8rem
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-title h2 {
|
||||||
|
margin: 0 15px 0 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.ticket-info {
|
||||||
|
font-size: 22px
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#nickname h2 {
|
||||||
|
max-width: 400px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 54 KiB |
|
@ -0,0 +1,214 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html v-bind:lang="$i18n.locale">
|
||||||
|
<body>
|
||||||
|
<table class="grid">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
<!-- Header block -->
|
||||||
|
<report-header v-bind="$props"
|
||||||
|
v-bind:company-code="invoice.companyCode">
|
||||||
|
</report-header>
|
||||||
|
<!-- Block -->
|
||||||
|
<div class="grid-row">
|
||||||
|
<div class="grid-block">
|
||||||
|
<div class="columns vn-mb-lg">
|
||||||
|
<div class="size50">
|
||||||
|
<div class="size75 vn-mt-ml">
|
||||||
|
<h1 class="title uppercase">{{$t('title')}}</h1>
|
||||||
|
<table class="row-oriented ticket-info">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="font gray uppercase">{{$t('supplierId')}}</td>
|
||||||
|
<th>{{invoice.supplierId}}</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="font gray uppercase">{{$t('invoiceId')}}</td>
|
||||||
|
<th>{{invoice.id}}</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="font gray uppercase">{{$t('date')}}</td>
|
||||||
|
<th>{{invoice.created | date('%d-%m-%Y')}}</th>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="size50">
|
||||||
|
<div class="panel">
|
||||||
|
<div class="header">{{$t('invoiceData')}}</div>
|
||||||
|
<div class="body">
|
||||||
|
<h3 class="uppercase">{{invoice.name}}</h3>
|
||||||
|
<div>
|
||||||
|
{{invoice.postalAddress}}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{{invoice.postcodeCity}}
|
||||||
|
</div>
|
||||||
|
<div v-if="invoice.nif">
|
||||||
|
{{$t('fiscalId')}}: {{invoice.nif}}
|
||||||
|
</div>
|
||||||
|
<div v-if="invoice.phone">
|
||||||
|
{{$t('phone')}}: {{invoice.phone}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="vn-mt-lg" v-for="entry in entries">
|
||||||
|
<div class="table-title clearfix">
|
||||||
|
<div class="pull-left">
|
||||||
|
<h2>{{$t('invoiceId')}}</strong>
|
||||||
|
</div>
|
||||||
|
<div class="pull-left vn-mr-md">
|
||||||
|
<div class="field rectangle">
|
||||||
|
<span>{{entry.id}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pull-left">
|
||||||
|
<h2>{{$t('date')}}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="pull-left">
|
||||||
|
<div class="field rectangle">
|
||||||
|
<span>{{entry.landed | date}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span id="nickname" class="pull-right">
|
||||||
|
<div class="pull-left">
|
||||||
|
<h2>{{$t('reference')}}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="pull-left">
|
||||||
|
<div class="field rectangle">
|
||||||
|
<span>{{entry.ref}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<table class="column-oriented">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="50%">{{$t('item')}}</th>
|
||||||
|
<th class="number">{{$t('quantity')}}</th>
|
||||||
|
<th class="number">{{$t('buyingValue')}}</th>
|
||||||
|
<th class="number">{{$t('amount')}}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody v-for="buy in entry.buys" class="no-page-break">
|
||||||
|
<tr>
|
||||||
|
<td width="50%">{{buy.name}}</td>
|
||||||
|
<td class="number">{{buy.quantity}}</td>
|
||||||
|
<td class="number">{{buy.buyingValue}}</td>
|
||||||
|
<td class="number">{{buyImport(buy) | currency('EUR', $i18n.locale)}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="description font light-gray">
|
||||||
|
<td colspan="4">
|
||||||
|
<span v-if="buy.value5">
|
||||||
|
<strong>{{buy.tag5}}</strong> {{buy.value5}}
|
||||||
|
</span>
|
||||||
|
<span v-if="buy.value6">
|
||||||
|
<strong>{{buy.tag6}}</strong> {{buy.value6}}
|
||||||
|
</span>
|
||||||
|
<span v-if="buy.value7">
|
||||||
|
<strong>{{buy.tag7}}</strong> {{buy.value7}}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td colspan="3" class="font bold">
|
||||||
|
<span class="pull-right">{{$t('subtotal')}}</span>
|
||||||
|
</td>
|
||||||
|
<td class="number">{{entrySubtotal(entry) | currency('EUR', $i18n.locale)}}</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!-- End of sales block -->
|
||||||
|
|
||||||
|
<div class="columns vn-mt-xl">
|
||||||
|
<!-- Taxes block -->
|
||||||
|
<div id="taxes" class="size50 pull-right no-page-break" v-if="taxes">
|
||||||
|
<table class="column-oriented">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th colspan="4">{{$t('taxBreakdown')}}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<thead class="light">
|
||||||
|
<tr>
|
||||||
|
<th width="45%">{{$t('type')}}</th>
|
||||||
|
<th width="25%" class="number">
|
||||||
|
{{$t('taxBase')}}
|
||||||
|
</th>
|
||||||
|
<th>{{$t('tax')}}</th>
|
||||||
|
<th class="number">{{$t('fee')}}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="tax in taxes">
|
||||||
|
<td width="45%">{{tax.name}}</td>
|
||||||
|
<td width="25%" class="number">
|
||||||
|
{{tax.taxableBase | currency('EUR', $i18n.locale)}}
|
||||||
|
</td>
|
||||||
|
<td>{{tax.rate | percentage}}</td>
|
||||||
|
<td class="number">{{tax.vat | currency('EUR', $i18n.locale)}}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr class="font bold">
|
||||||
|
<td width="45%">{{$t('subtotal')}}</td>
|
||||||
|
<td width="20%" class="number">
|
||||||
|
{{sumTotal(taxes, 'taxableBase') | currency('EUR', $i18n.locale)}}
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
<td class="number">{{sumTotal(taxes, 'vat') | currency('EUR', $i18n.locale)}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="font bold">
|
||||||
|
<td colspan="2">{{$t('total')}}</td>
|
||||||
|
<td colspan="2" class="number">{{taxTotal() | currency('EUR', $i18n.locale)}}</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="panel" v-if="invoice.footNotes">
|
||||||
|
<div class="header">{{$t('notes')}}</div>
|
||||||
|
<div class="body">
|
||||||
|
<span>{{invoice.footNotes}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- End of taxes block -->
|
||||||
|
|
||||||
|
<!-- Observations block -->
|
||||||
|
<div class="columns vn-mt-xl">
|
||||||
|
<div class="size50 pull-left no-page-break" >
|
||||||
|
<div class="panel" >
|
||||||
|
<div class="header">{{$t('observations')}}</div>
|
||||||
|
<div class="body">
|
||||||
|
<div>{{$t('payMethod')}}</div>
|
||||||
|
<div>{{invoice.payMethod}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- End of observations block -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Footer block -->
|
||||||
|
<report-footer id="pageFooter"
|
||||||
|
v-bind:company-code="invoice.companyCode"
|
||||||
|
v-bind:left-text="$t('invoiceId')"
|
||||||
|
v-bind:center-text="invoice.name"
|
||||||
|
v-bind="$props">
|
||||||
|
</report-footer>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,94 @@
|
||||||
|
const Component = require(`vn-print/core/component`);
|
||||||
|
const reportHeader = new Component('report-header');
|
||||||
|
const reportFooter = new Component('report-footer');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: 'invoiceIn',
|
||||||
|
async serverPrefetch() {
|
||||||
|
this.invoice = await this.fetchInvoice(this.id);
|
||||||
|
this.taxes = await this.fetchTaxes(this.id);
|
||||||
|
|
||||||
|
if (!this.invoice)
|
||||||
|
throw new Error('Something went wrong');
|
||||||
|
|
||||||
|
const entries = await this.fetchEntry(this.id);
|
||||||
|
const buys = await this.fetchBuy(this.id);
|
||||||
|
|
||||||
|
const map = new Map();
|
||||||
|
|
||||||
|
for (let entry of entries) {
|
||||||
|
entry.buys = [];
|
||||||
|
|
||||||
|
map.set(entry.id, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let buy of buys) {
|
||||||
|
const entry = map.get(buy.entryFk);
|
||||||
|
|
||||||
|
if (entry) entry.buys.push(buy);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.entries = entries;
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fetchInvoice(id) {
|
||||||
|
return this.findOneFromDef('invoice', [id]);
|
||||||
|
},
|
||||||
|
fetchEntry(id) {
|
||||||
|
return this.rawSqlFromDef('entry', [id]);
|
||||||
|
},
|
||||||
|
fetchBuy(id) {
|
||||||
|
return this.rawSqlFromDef('buy', [id]);
|
||||||
|
},
|
||||||
|
async fetchTaxes(id) {
|
||||||
|
const taxes = await this.rawSqlFromDef(`taxes`, [id]);
|
||||||
|
return this.taxVat(taxes);
|
||||||
|
},
|
||||||
|
buyImport(buy) {
|
||||||
|
return buy.quantity * buy.buyingValue;
|
||||||
|
},
|
||||||
|
entrySubtotal(entry) {
|
||||||
|
let subTotal = 0.00;
|
||||||
|
for (let buy of entry.buys)
|
||||||
|
subTotal += this.buyImport(buy);
|
||||||
|
|
||||||
|
return subTotal;
|
||||||
|
},
|
||||||
|
sumTotal(rows, prop) {
|
||||||
|
let total = 0.00;
|
||||||
|
for (let row of rows)
|
||||||
|
total += parseFloat(row[prop]);
|
||||||
|
|
||||||
|
return total;
|
||||||
|
},
|
||||||
|
taxVat(taxes) {
|
||||||
|
for (tax of taxes) {
|
||||||
|
let vat = 0;
|
||||||
|
if (tax.rate && tax.taxableBase)
|
||||||
|
vat = (tax.rate / 100) * tax.taxableBase;
|
||||||
|
|
||||||
|
tax.vat = vat;
|
||||||
|
}
|
||||||
|
|
||||||
|
return taxes;
|
||||||
|
},
|
||||||
|
taxTotal() {
|
||||||
|
const base = this.sumTotal(this.taxes, 'taxableBase');
|
||||||
|
const vat = this.sumTotal(this.taxes, 'vat');
|
||||||
|
|
||||||
|
return base + vat;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
'report-header': reportHeader.build(),
|
||||||
|
'report-footer': reportFooter.build(),
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
id: {
|
||||||
|
type: Number,
|
||||||
alexm marked this conversation as resolved
Outdated
joan
commented
type: Number type: Number
|
|||||||
|
description: 'The invoice id'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,25 @@
|
||||||
|
reportName: invoice
|
||||||
|
title: Agricultural invoice
|
||||||
|
invoiceId: Agricultural invoice
|
||||||
|
supplierId: Proveedor
|
||||||
|
invoiceData: Invoice data
|
||||||
|
reference: Reference
|
||||||
|
fiscalId: FI / NIF
|
||||||
|
phone: Phone
|
||||||
|
date: Date
|
||||||
|
item: Item
|
||||||
|
quantity: Qty.
|
||||||
|
concept: Concept
|
||||||
|
buyingValue: PSP/u
|
||||||
|
discount: Disc.
|
||||||
|
vat: VAT
|
||||||
|
amount: Amount
|
||||||
|
type: Type
|
||||||
|
taxBase: Tax base
|
||||||
|
tax: Tax
|
||||||
|
fee: Fee
|
||||||
|
total: Total
|
||||||
|
subtotal: Subtotal
|
||||||
|
taxBreakdown: Tax breakdown
|
||||||
|
observations: Observations
|
||||||
|
payMethod: Pay method
|
|
@ -0,0 +1,25 @@
|
||||||
|
reportName: factura
|
||||||
|
title: Factura Agrícola
|
||||||
|
invoiceId: Factura Agrícola
|
||||||
|
supplierId: Proveedor
|
||||||
|
invoiceData: Datos de facturación
|
||||||
|
reference: Referencia
|
||||||
|
fiscalId: CIF / NIF
|
||||||
|
phone: Tlf
|
||||||
|
date: Fecha
|
||||||
|
item: Artículo
|
||||||
|
quantity: Cant.
|
||||||
|
concept: Concepto
|
||||||
|
buyingValue: PVP/u
|
||||||
|
discount: Dto.
|
||||||
|
vat: IVA
|
||||||
|
amount: Importe
|
||||||
|
type: Tipo
|
||||||
|
taxBase: Base imp.
|
||||||
|
tax: Tasa
|
||||||
|
fee: Cuota
|
||||||
|
total: Total
|
||||||
|
subtotal: Subtotal
|
||||||
|
taxBreakdown: Desglose impositivo
|
||||||
|
observations: Observaciones
|
||||||
|
payMethod: Método de pago
|
|
@ -0,0 +1,18 @@
|
||||||
|
SELECT
|
||||||
|
b.id,
|
||||||
|
e.id entryFk,
|
||||||
|
it.name,
|
||||||
|
b.quantity,
|
||||||
|
b.buyingValue,
|
||||||
|
(b.quantity * b.buyingValue) total,
|
||||||
|
it.tag5,
|
||||||
|
it.value5,
|
||||||
|
it.tag6,
|
||||||
|
it.value6,
|
||||||
|
it.tag7,
|
||||||
|
it.value7
|
||||||
|
FROM entry e
|
||||||
|
JOIN invoiceIn i ON i.id = e.invoiceInFk
|
||||||
|
JOIN buy b ON b.entryFk = e.id
|
||||||
|
JOIN item it ON it.id = b.itemFk
|
||||||
|
WHERE i.id = ?
|
|
@ -0,0 +1,8 @@
|
||||||
|
SELECT
|
||||||
|
e.id,
|
||||||
|
t.landed,
|
||||||
|
e.ref
|
||||||
|
FROM entry e
|
||||||
|
JOIN invoiceIn i ON i.id = e.invoiceInFk
|
||||||
|
JOIN travel t ON t.id = e.travelFk
|
||||||
|
WHERE i.id = ?
|
|
@ -0,0 +1,14 @@
|
||||||
|
SELECT
|
||||||
|
i.id,
|
||||||
|
s.id supplierId,
|
||||||
|
i.created,
|
||||||
|
s.name,
|
||||||
|
s.street AS postalAddress,
|
||||||
|
s.nif,
|
||||||
|
s.phone,
|
||||||
|
p.name payMethod
|
||||||
|
FROM invoiceIn i
|
||||||
|
JOIN supplier s ON s.id = i.supplierFk
|
||||||
|
JOIN company c ON c.id = i.companyFk
|
||||||
|
JOIN payMethod p ON p.id = s.payMethodFk
|
||||||
|
WHERE i.id = ?
|
|
@ -0,0 +1,8 @@
|
||||||
|
SELECT
|
||||||
|
ti.iva as name,
|
||||||
|
ti.PorcentajeIva as rate,
|
||||||
|
iit.taxableBase
|
||||||
|
FROM invoiceIn ii
|
||||||
|
JOIN invoiceInTax iit ON ii.id = iit.invoiceInFk
|
||||||
|
JOIN sage.TiposIva ti ON ti.CodigoIva = iit.taxTypeSageFk
|
||||||
|
WHERE ii.id = ?;
|
Loading…
Reference in New Issue
perque uno te read y l'altre WRITE?