Add services to deliver-note #1201. Renamed receipt
gitea/salix/dev This commit has test failures Details

This commit is contained in:
Joan Sanchez 2019-03-05 14:59:18 +01:00
parent fbc84f48a1
commit 11603f8d90
22 changed files with 400 additions and 353 deletions

View File

@ -13,7 +13,7 @@ module.exports = Self => {
http: {source: 'query'}
}],
returns: {
type: ["Object"],
type: ['Object'],
root: true
},
http: {
@ -28,7 +28,8 @@ module.exports = Self => {
`SELECT name, itemFk, packagingFk
FROM (SELECT i.name, i.id itemFk, p.id packagingFk
FROM item i
JOIN packaging p ON i.id = p.itemFk) p`
JOIN packaging p ON i.id = p.itemFk
WHERE i.name <> '') p`
);
stmt.merge(conn.makeSuffix(filter));

View File

@ -11,7 +11,7 @@ class Controller {
{callback: this.showAddTurnDialog, name: 'Add turn', show: true},
{callback: this.showAddStowaway, name: 'Add stowaway', show: () => this.isTicketModule()},
{callback: this.showRemoveStowaway, name: 'Remove stowaway', show: () => this.shouldShowRemoveStowaway()},
/* {callback: this.showDeliveryNote, name: 'Show Delivery Note', show: true}, */
{callback: this.showDeliveryNote, name: 'Show Delivery Note', show: true},
{callback: this.showDeleteTicketDialog, name: 'Delete ticket', show: true},
/* callback: this.showChangeShipped, name: 'Change shipped hour', show: true} */
];

View File

@ -18,7 +18,6 @@ class Controller {
this.$scope.watcher.check();
this.$scope.model.save().then(() => {
this.$scope.watcher.notifySaved();
this.$scope.model.refresh();
});
}
}

400
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -60,7 +60,7 @@
"jasmine-reporters": "^2.3.2",
"jasmine-spec-reporter": "^4.2.1",
"json-loader": "^0.5.7",
"karma": "^3.1.4",
"karma": "^4.0.1",
"karma-chrome-launcher": "^2.2.0",
"karma-firefox-launcher": "^1.1.0",
"karma-jasmine": "^2.0.1",

View File

@ -11,7 +11,7 @@
{"type": "report", "name": "rpt-claim-pickup-order"},
{"type": "report", "name": "rpt-letter-debtor"},
{"type": "report", "name": "rpt-sepa-core"},
{"type": "report", "name": "rpt-informe"},
{"type": "report", "name": "rpt-receipt"},
{"type": "static", "name": "email-header"},
{"type": "static", "name": "email-footer"},
{"type": "static", "name": "report-header"},

View File

@ -26,7 +26,8 @@ module.exports = {
const result = await this.preFetch(component, ctx);
const i18n = new VueI18n({
locale: 'es',
fallbackLocale: 'es'
fallbackLocale: 'es',
silentTranslationWarn: true
});
const app = new Vue({i18n,
render: h => h(result.component)});

View File

@ -242,9 +242,9 @@
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"denque": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/denque/-/denque-1.3.0.tgz",
"integrity": "sha512-4SRaSj+PqmrS1soW5/Avd7eJIM2JJIqLLmwhRqIGleZM/8KwZq80njbSS2Iqas+6oARkSkLDHEk4mm78q3JlIg=="
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/denque/-/denque-1.4.0.tgz",
"integrity": "sha512-gh513ac7aiKrAgjiIBWZG0EASyDF9p4JMWwKA8YU5s9figrL5SRNEMT6FDynsegakuhWd1wVqTvqvqAoDxw7wQ=="
},
"dom-serializer": {
"version": "0.1.0",
@ -690,9 +690,9 @@
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
},
"lru-cache": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz",
"integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==",
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
"integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
"requires": {
"pseudomap": "^1.0.2",
"yallist": "^2.1.2"
@ -743,33 +743,26 @@
"optional": true
},
"mysql2": {
"version": "1.6.4",
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-1.6.4.tgz",
"integrity": "sha512-ZYbYgK06HKfxU45tYYLfwW5gKt8BslfE7FGyULNrf2K2fh+DuEX+e0QKsd2ObpZkMILefaVn8hsakVsTFqravQ==",
"version": "1.6.5",
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-1.6.5.tgz",
"integrity": "sha512-zedaOOyb3msuuZcJJnxIX/EGOpmljDG7B+UevRH5lqcv+yhy9eCwkArBz8/AO+/rlY3/oCsOdG8R5oD6k0hNfg==",
"requires": {
"denque": "1.3.0",
"denque": "^1.4.0",
"generate-function": "^2.3.1",
"iconv-lite": "^0.4.24",
"long": "^4.0.0",
"lru-cache": "4.1.3",
"named-placeholders": "1.1.1",
"seq-queue": "0.0.5",
"sqlstring": "2.3.1"
"lru-cache": "^4.1.3",
"named-placeholders": "^1.1.2",
"seq-queue": "^0.0.5",
"sqlstring": "^2.3.1"
}
},
"named-placeholders": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.1.tgz",
"integrity": "sha1-O3oNJiA910s6nfTJz7gnsvuQfmQ=",
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz",
"integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==",
"requires": {
"lru-cache": "2.5.0"
},
"dependencies": {
"lru-cache": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.5.0.tgz",
"integrity": "sha1-2COIrpyWC+y+oMc7uet5tsbOmus="
}
"lru-cache": "^4.1.3"
}
},
"nice-try": {
@ -1131,19 +1124,19 @@
}
},
"vue": {
"version": "2.5.22",
"resolved": "https://registry.npmjs.org/vue/-/vue-2.5.22.tgz",
"integrity": "sha512-pxY3ZHlXNJMFQbkjEgGVMaMMkSV1ONpz+4qB55kZuJzyJOhn6MSy/YZdzhdnumegNzVTL/Dn3Pp4UrVBYt1j/g=="
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/vue/-/vue-2.6.7.tgz",
"integrity": "sha512-g7ADfQ82QU+j6F/bVDioVQf2ccIMYLuR4E8ev+RsDBlmwRkhGO3HhgF4PF9vpwjdPpxyb1zzLur2nQ2oIMAMEg=="
},
"vue-i18n": {
"version": "8.7.0",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.7.0.tgz",
"integrity": "sha512-qey+OyZSUIje0xJW8HZrvpIss1jW8yBBRe+0QlUn7HENU31m/+Med/u4pcwjoeCaErHU9WMscBEhqK5aAvvEEQ=="
"version": "8.8.2",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.8.2.tgz",
"integrity": "sha512-P09ZN2S0mX1AmhSR/+wP2owP3izGVx1pSoDFcOXTLya5xvP95dG7kc9LQUnboPgSzK/JKe9FkYmoYdDTKDjPSw=="
},
"vue-server-renderer": {
"version": "2.5.22",
"resolved": "https://registry.npmjs.org/vue-server-renderer/-/vue-server-renderer-2.5.22.tgz",
"integrity": "sha512-PQ0PubA6b2MyZud/gepWeiUuDFSbRfa6h1qYINcbwXRr4Z3yLTHprEQuFnWikdkTkZpeLFYUqZrDxPbDcJ71mA==",
"version": "2.6.7",
"resolved": "https://registry.npmjs.org/vue-server-renderer/-/vue-server-renderer-2.6.7.tgz",
"integrity": "sha512-CVtGR+bE63y4kyIeOcCEF2UNKquSquFQAsTHZ5R1cGM4L4Z0BXgAUEcngTOy8kN+tubt3c1zpRvbrok/bHKeDg==",
"requires": {
"chalk": "^1.1.3",
"hash-sum": "^1.0.2",

View File

@ -16,11 +16,11 @@
"fs-extra": "^7.0.1",
"html-pdf": "^2.2.0",
"juice": "^5.0.1",
"mysql2": "^1.6.1",
"mysql2": "^1.6.5",
"nodemailer": "^4.7.0",
"strftime": "^0.10.0",
"vue": "^2.5.17",
"vue-i18n": "^8.3.1",
"vue-server-renderer": "^2.5.17"
"vue": "^2.6.7",
"vue-i18n": "^8.8.2",
"vue-server-renderer": "^2.6.7"
}
}

View File

@ -21,6 +21,8 @@ module.exports = {
'Abre el programa QLabel',
'Haz clic en el icono de la barra superior con forma de "carpeta"',
'Selecciona el archivo llamado "model.ezp" adjunto en este correo, y haz click en abrir',
'Ve a "File" -> "Save as" y guárdalo en el escritorio con otro nombre',
'Cierra el Qlabel y abre el archivo que acabamos de guardar',
'Haz clic <strong>encima del texto</strong> con el botón secundario del ratón',
'Elige la primera opción "setup"',
'Cambia el texto para imprimir',

View File

@ -9,16 +9,11 @@
max-width: 150px
}
#packagings {
box-sizing: border-box;
padding-right: 10px
}
#taxes {
box-sizing: border-box;
padding-left: 10px
}
.description.phytosanitary {
background-color: #e5e5e5
}
h3 {
font-weight: 100;
color: #555
}

View File

@ -58,6 +58,9 @@
</section>
</section>
</section>
<!-- Sales block -->
<h3>{{$t('saleLines')}}</h3>
<table class="column-oriented">
<thead>
<tr>
@ -116,32 +119,40 @@
</tr>
</tfoot>
</table>
<!-- End of sales block -->
<section class="columns">
<section id="packagings" class="size50 pull-left" v-if="packagings.length > 0">
<h3>{{$t('packaging')}}</h3>
<!-- Services block-->
<section class="size100" v-if="services.length > 0">
<h3>{{$t('services')}}</h3>
<table class="column-oriented">
<thead>
<tr>
<td>Id</td>
<td>{{$t('concept')}}</td>
<td class="number">{{$t('quantity')}}</td>
<td>{{$t('vatType')}}</td>
<td class="number">{{$t('amount')}}</td>
</tr>
</thead>
<tbody>
<tr v-for="packaging in packagings">
<td>{{packaging.itemFk}}</td>
<td>{{packaging.name}}</td>
<td class="number">{{packaging.quantity}}</td>
<tr v-for="service in services">
<td>{{service.description}}</td>
<td class="number">{{service.quantity}}</td>
<td>{{service.taxDescription}}</td>
<td class="number">{{service.price | currency('EUR')}}</td>
</tr>
</tbody>
<tfoot>
<tr class="font bold">
<td colspan="2">{{$t('total')}}</td>
<td class="number">0</td>
<tr>
<td colspan="3"></td>
<td class="number">{{$t('total')}} {{serviceTotal | currency('EUR')}}</td>
</tr>
</tfoot>
</table>
</section>
<!-- End of services block -->
<!-- Taxes block -->
<section id="taxes" class="size50 pull-right" v-if="taxes">
<h3>{{$t('taxBreakdown')}}</h3>
<table class="column-oriented">
@ -175,15 +186,41 @@
</tfoot>
</table>
</section>
<!-- End of taxes block -->
<!-- Packages block -->
<section id="packagings" class="size100" v-if="packagings.length > 0">
<h3>{{$t('packagings')}}</h3>
<table class="column-oriented">
<thead>
<tr>
<td>Id</td>
<td>{{$t('concept')}}</td>
<td class="number">{{$t('quantity')}}</td>
</tr>
</thead>
<tbody>
<tr v-for="packaging in packagings">
<td>{{packaging.itemFk}}</td>
<td>{{packaging.name}}</td>
<td class="number">{{packaging.quantity}}</td>
</tr>
</tbody>
</table>
</section>
<!-- End of packages block -->
<!-- Signature block -->
<section class="size50 pull-left">
<section id="signature" class="panel" v-if="signature && signature.id">
<section class="header">Firma digital</section>
<section class="header">{{$t('digitalSignature')}}</section>
<section class="body centered">
<img v-bind:src="dmsPath"/>
<section>{{signature.created | date}}</section>
</section>
</section>
</section>
<!-- End of signature block -->
</section>
</section>
<!-- Footer component -->

View File

@ -14,11 +14,12 @@ module.exports = {
const [[taxes]] = await this.fetchTaxes(params.ticketFk);
const [sales] = await this.fetchSales(params.ticketFk);
const [packagings] = await this.fetchPackagings(params.ticketFk);
const [services] = await this.fetchServices(params.ticketFk);
if (!ticket)
throw new UserException('No ticket data found');
return {client, ticket, address, sales, taxes, packagings, signature};
return {client, ticket, address, sales, taxes, packagings, services, signature};
},
created() {
if (this.client.locale)
@ -35,6 +36,14 @@ module.exports = {
},
shipped() {
return strftime('%d-%m-%Y', this.ticket.shipped);
},
serviceTotal() {
let total = 0.00;
this.services.forEach(service => {
total += parseFloat(service.price) * service.quantity;
});
return total;
}
},
filters: {
@ -169,6 +178,17 @@ module.exports = {
WHERE tp.ticketFk = ?
ORDER BY itemFk`, [ticketFk]);
},
fetchServices(ticketFk) {
return database.pool.query(
`SELECT
tc.description taxDescription,
ts.description,
ts.quantity,
ts.price
FROM ticketService ts
JOIN taxClass tc ON tc.id = ts.taxClassFk
WHERE ts.ticketFk = ?`, [ticketFk]);
},
fetchSignature(ticketFk) {
return database.pool.query(
`SELECT

View File

@ -6,6 +6,7 @@ module.exports = {
clientId: 'Cliente',
deliveryAddress: 'Dirección de entrega',
fiscalData: 'Datos fiscales',
saleLines: 'Líneas de pedido',
date: 'Fecha',
reference: 'Ref.',
quantity: 'Cant.',
@ -18,10 +19,13 @@ module.exports = {
taxBase: 'Base imp.',
tax: 'Tasa',
fee: 'Cuota',
packaging: 'Cubos y embalajes',
taxBreakdown: 'Desglose impositivo',
total: 'Total',
subtotal: 'Subtotal',
taxBreakdown: 'Desglose impositivo',
packagings: 'Cubos y embalajes',
services: 'Servicios',
vatType: 'Tipo de IVA',
digitalSignature: 'Firma digital',
ticket: 'Albarán {0}'
},
},

View File

@ -1,33 +0,0 @@
const strftime = require('strftime');
module.exports = {
name: 'rpt-informe',
created() {
if (this.locale)
this.$i18n.locale = this.locale;
const embeded = [];
this.files.map(file => {
embeded[file] = `file://${__dirname + file}`;
});
this.embeded = embeded;
},
data() {
return {
client: {
id: 101,
name: 'Batman'
},
files: ['/assets/images/signature.png'],
};
},
methods: {
/* dated: () => {
return strftime('%d-%m-%Y', new Date());
}, */
},
components: {
'report-header': require('../report-header'),
'report-footer': require('../report-footer'),
},
};

View File

@ -1,10 +0,0 @@
module.exports = {
messages: {
es: {
title: 'Recibo',
date: 'Fecha',
dated: 'En {0}, a {1} de {2} de {3}',
client: 'Cliente {0}',
},
},
};

View File

@ -3,10 +3,6 @@ p {
margin: 0
}
.main {
position: relative;
height: 100%
}
.content {
position: absolute;

View File

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 101 KiB

View File

@ -3,20 +3,27 @@
<body>
<section class="container" id="report">
<!-- Header component -->
<report-header :locale="locale"></report-header>
<report-header :locale="client.locale"></report-header>
<!-- End header component -->
<section class="main">
<!-- Report start -->
<section class="content">
<h1 class="title centered uppercase">{{$t('title')}}</h1>
<p class="centered">
Recibo de <strong class="uppercase">LEON LLORENS LUIS ENRIQUE</strong>,
la cantidad de <strong>259,96 €</strong> en concepto de 'entrega a cuenta', quedando pendiente en la cuenta del cliente
un saldo de <strong>0,00 €</strong>.
Recibo de <strong class="uppercase">{{client.socialName}}</strong>,
la cantidad de <strong>{{receipt.amountPaid}} €</strong> en concepto de 'entrega a cuenta',
quedando pendiente en la cuenta del cliente
un saldo de <strong>{{receipt.amountUnpaid}} €</strong>.
</p>
<section class="signature">
<img :src="embeded['/assets/images/signature.png']">
<p class="centered">{{$t('dated', ['Silla', '20', 'enero', '2019'])}}</p>
<p class="centered">{{$t('payed', [
'Silla',
receipt.payed.getDate(),
$t('months')[receipt.payed.getMonth()],
receipt.payed.getFullYear()])
}}
</p>
</section>
</section>
<!-- Report end -->
@ -24,8 +31,8 @@
<!-- Footer component -->
<report-footer id="pageFooter"
:left-text="$t('client', [client.id])"
:center-text="client.name"
:locale="locale">
:center-text="client.socialName"
:locale="client.locale">
</report-footer>
<!-- End footer component -->
</section>

View File

@ -0,0 +1,71 @@
const strftime = require('strftime');
const database = require(`${appPath}/lib/database`);
const UserException = require(`${appPath}/lib/exceptions/userException`);
module.exports = {
name: 'rpt-receipt',
/* serverPrefetch() {
console.log(arguments);
return new Promise(accept => {
this.client = this.getReceipt();
});
}, */
async asyncData(ctx, params) {
Object.assign(this, this.methods);
const [[client]] = await this.fetchClient(params.receiptFk);
const [[receipt]] = await this.fetchReceipt(params.receiptFk);
if (!receipt)
throw new UserException('No receipt data found');
return {client, receipt};
},
created() {
if (this.client.locale)
this.$i18n.locale = this.client.locale;
const embeded = [];
this.files.map(file => {
embeded[file] = `file://${__dirname + file}`;
});
this.embeded = embeded;
},
data() {
return {
files: ['/assets/images/signature.png']
};
},
methods: {
fetchClient(receiptFk) {
return database.pool.query(
`SELECT
c.id,
c.socialName,
u.lang locale
FROM receipt r
JOIN client c ON c.id = r.clientFk
JOIN account.user u ON u.id = c.id
WHERE r.id = ?`, [receiptFk]);
},
fetchReceipt(receiptFk) {
return database.pool.query(
`SELECT
r.id,
r.amountPaid,
r.amountUnpaid,
r.payed,
r.companyFk
FROM receipt r
JOIN client c ON c.id = r.clientFk
WHERE r.id = ?`, [receiptFk]);
}
/* dated: () => {
return strftime('%d-%m-%Y', new Date());
}, */
},
components: {
'report-header': require('../report-header'),
'report-footer': require('../report-footer'),
},
};

View File

@ -0,0 +1,24 @@
module.exports = {
messages: {
es: {
title: 'Recibo',
date: 'Fecha',
payed: 'En {0}, a {1} de {2} de {3}',
client: 'Cliente {0}',
months: [
'Enero',
'Febrero',
'Marzo',
'Abril',
'Mayo',
'Junio',
'Julio',
'Agosto',
'Septiembre',
'Octubre',
'Noviembre',
'Diciembre'
]
},
},
};