Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 3094-invoice_csv
gitea/salix/pipeline/head There was a failure building this commit Details

This commit is contained in:
Joan Sanchez 2021-10-07 10:28:06 +02:00
commit 4610ed83d9
21 changed files with 85 additions and 44 deletions

View File

@ -0,0 +1 @@
UPDATE salix.ACL t SET t.principalId = 'employee' WHERE t.id = 269;

View File

@ -489,11 +489,11 @@ INSERT INTO `vn`.`invoiceOutSerial` (`code`, `description`, `isTaxed`, `taxAreaF
INSERT INTO `vn`.`invoiceOut`(`id`, `serial`, `amount`, `issued`,`clientFk`, `created`, `companyFk`, `dued`, `booked`, `bankFk`, `hasPdf`) INSERT INTO `vn`.`invoiceOut`(`id`, `serial`, `amount`, `issued`,`clientFk`, `created`, `companyFk`, `dued`, `booked`, `bankFk`, `hasPdf`)
VALUES VALUES
(1, 'T', 1014.24, CURDATE(), 1101, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1), (1, 'T', 1014.24, CURDATE(), 1101, CURDATE(), 442, CURDATE(), CURDATE(), 1, 0),
(2, 'T', 121.36, CURDATE(), 1102, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1), (2, 'T', 121.36, CURDATE(), 1102, CURDATE(), 442, CURDATE(), CURDATE(), 1, 0),
(3, 'T', 8.88, CURDATE(), 1103, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1), (3, 'T', 8.88, CURDATE(), 1103, CURDATE(), 442, CURDATE(), CURDATE(), 1, 0),
(4, 'T', 8.88, CURDATE(), 1103, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1), (4, 'T', 8.88, CURDATE(), 1103, CURDATE(), 442, CURDATE(), CURDATE(), 1, 0),
(5, 'A', 8.88, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1103, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 442, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 1); (5, 'A', 8.88, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1103, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 442, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 0);
UPDATE `vn`.`invoiceOut` SET ref = 'T1111111' WHERE id = 1; UPDATE `vn`.`invoiceOut` SET ref = 'T1111111' WHERE id = 1;
UPDATE `vn`.`invoiceOut` SET ref = 'T2222222' WHERE id = 2; UPDATE `vn`.`invoiceOut` SET ref = 'T2222222' WHERE id = 2;

View File

@ -29,7 +29,7 @@ module.exports = Self => {
const models = Self.app.models; const models = Self.app.models;
const headers = ctx.req.headers; const headers = ctx.req.headers;
const origin = headers.origin; const origin = headers.origin;
const authorization = ctx.req.accessToken.id; const auth = ctx.req.accessToken;
if (process.env.NODE_ENV == 'test') if (process.env.NODE_ENV == 'test')
throw new UserError(`Action not allowed on the test environment`); throw new UserError(`Action not allowed on the test environment`);
@ -48,13 +48,18 @@ module.exports = Self => {
let fileSrc; let fileSrc;
try { try {
const invoiceOut = await Self.findById(id, null, myOptions); const invoiceOut = await Self.findById(id, null, myOptions);
const hasInvoicing = await models.Account.hasRole(auth.userId, 'invoicing', myOptions);
if (invoiceOut.hasPdf && !hasInvoicing)
throw new UserError(`You don't have enough privileges`);
await invoiceOut.updateAttributes({ await invoiceOut.updateAttributes({
hasPdf: true hasPdf: true
}, myOptions); }, myOptions);
const response = got.stream(`${origin}/api/report/invoice`, { const response = got.stream(`${origin}/api/report/invoice`, {
query: { query: {
authorization: authorization, authorization: auth.id,
invoiceId: id invoiceId: id
} }
}); });

View File

@ -61,9 +61,12 @@ describe('InvoiceOut filter()', () => {
} }
}; };
const invoiceOut = await models.InvoiceOut.findById(1, null, options);
await invoiceOut.updateAttribute('hasPdf', true, options);
const result = await models.InvoiceOut.filter(ctx, {}, options); const result = await models.InvoiceOut.filter(ctx, {}, options);
expect(result.length).toEqual(5); expect(result.length).toEqual(1);
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {

View File

@ -1,5 +1,8 @@
<vn-portal slot="menu"> <vn-portal slot="menu">
<vn-invoice-out-descriptor invoice-out="$ctrl.invoiceOut"></vn-invoice-out-descriptor> <vn-invoice-out-descriptor
invoice-out="$ctrl.invoiceOut"
card-reload="$ctrl.reload()">
</vn-invoice-out-descriptor>
<vn-left-menu source="card"></vn-left-menu> <vn-left-menu source="card"></vn-left-menu>
</vn-portal> </vn-portal>
<ui-view></ui-view> <ui-view></ui-view>

View File

@ -10,7 +10,8 @@ class Controller extends ModuleCard {
'issued', 'issued',
'amount', 'amount',
'clientFk', 'clientFk',
'companyFk' 'companyFk',
'hasPdf'
], ],
include: [ include: [
{ {

View File

@ -64,11 +64,10 @@
</vn-item> </vn-item>
<vn-item <vn-item
ng-click="createInvoicePdfConfirmation.show()" ng-click="createInvoicePdfConfirmation.show()"
vn-acl="invoicing" ng-show="$ctrl.hasInvoicing || !$ctrl.invoiceOut.hasPdf"
vn-acl-action="remove"
name="regenerateInvoice" name="regenerateInvoice"
translate> translate>
Regenerate invoice PDF {{!$ctrl.invoiceOut.hasPdf ? 'Generate PDF invoice': 'Regenerate PDF invoice'}}
</vn-item> </vn-item>
</slot-menu> </slot-menu>
<slot-body> <slot-body>
@ -132,8 +131,8 @@
<vn-confirm <vn-confirm
vn-id="createInvoicePdfConfirmation" vn-id="createInvoicePdfConfirmation"
on-accept="$ctrl.createInvoicePdf()" on-accept="$ctrl.createInvoicePdf()"
question="Are you sure you want to regenerate the invoice PDF document?" question="Are you sure you want to generate/regenerate the PDF invoice?"
message="You are going to regenerate the invoice PDF document"> message="Generate PDF invoice document">
</vn-confirm> </vn-confirm>
<!-- Send PDF invoice confirmation popup --> <!-- Send PDF invoice confirmation popup -->

View File

@ -10,6 +10,10 @@ class Controller extends Descriptor {
this.entity = value; this.entity = value;
} }
get hasInvoicing() {
return this.aclService.hasAny(['invoicing']);
}
deleteInvoiceOut() { deleteInvoiceOut() {
return this.$http.post(`InvoiceOuts/${this.id}/delete`) return this.$http.post(`InvoiceOuts/${this.id}/delete`)
.then(() => this.$state.go('invoiceOut.index')) .then(() => this.$state.go('invoiceOut.index'))
@ -25,6 +29,7 @@ class Controller extends Descriptor {
createPdfInvoice() { createPdfInvoice() {
const invoiceId = this.invoiceOut.id; const invoiceId = this.invoiceOut.id;
return this.$http.post(`InvoiceOuts/${invoiceId}/createPdf`) return this.$http.post(`InvoiceOuts/${invoiceId}/createPdf`)
.then(() => this.reload())
.then(() => { .then(() => {
const snackbarMessage = this.$t( const snackbarMessage = this.$t(
`The invoice PDF document has been regenerated`); `The invoice PDF document has been regenerated`);
@ -60,6 +65,17 @@ class Controller extends Descriptor {
.then(res => this.entity = res.data); .then(res => this.entity = res.data);
} }
reload() {
return this.loadData().then(() => {
if (this.cardReload)
this.cardReload();
});
}
cardReload() {
// Prevents error when not defined
}
showCsvInvoice() { showCsvInvoice() {
this.vnReport.showCsv('invoice', { this.vnReport.showCsv('invoice', {
recipientId: this.invoiceOut.client.id, recipientId: this.invoiceOut.client.id,
@ -88,6 +104,7 @@ ngModule.vnComponent('vnInvoiceOutDescriptor', {
template: require('./index.html'), template: require('./index.html'),
controller: Controller, controller: Controller,
bindings: { bindings: {
invoiceOut: '<' invoiceOut: '<',
cardReload: '&'
} }
}); });

View File

@ -18,6 +18,7 @@ describe('vnInvoiceOutDescriptor', () => {
controller.invoiceOut = invoiceOut; controller.invoiceOut = invoiceOut;
$httpBackend.whenGET(`InvoiceOuts/${invoiceOut.id}`).respond();
$httpBackend.expectPOST(`InvoiceOuts/${invoiceOut.id}/createPdf`).respond(); $httpBackend.expectPOST(`InvoiceOuts/${invoiceOut.id}/createPdf`).respond();
controller.createInvoicePdf(); controller.createInvoicePdf();
$httpBackend.flush(); $httpBackend.flush();

View File

@ -14,5 +14,6 @@ Are you sure you want to clone this invoice?: Estas seguro de clonar esta factur
Book invoice: Asentar 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?
Regenerate invoice PDF: Regenerar PDF factura Generate PDF invoice: Generar 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

@ -11,7 +11,7 @@ class Controller extends Section {
from.setHours(0, 0, 0, 0); from.setHours(0, 0, 0, 0);
const to = new Date(); const to = new Date();
to.setDate(to.getDate() + 10); to.setDate(to.getDate() + 60);
to.setHours(23, 59, 59, 59); to.setHours(23, 59, 59, 59);
this.filter = { this.filter = {
@ -34,7 +34,7 @@ class Controller extends Section {
from.setHours(0, 0, 0, 0); from.setHours(0, 0, 0, 0);
const to = new Date(); const to = new Date();
to.setDate(to.getDate() + 10); to.setDate(to.getDate() + 60);
to.setHours(23, 59, 59, 59); to.setHours(23, 59, 59, 59);
this.filter.where.shipped = { this.filter.where.shipped = {

View File

@ -1,5 +1,8 @@
<vn-portal slot="menu"> <vn-portal slot="menu">
<vn-ticket-descriptor ticket="$ctrl.ticket" card-reload="$ctrl.reload()"></vn-ticket-descriptor> <vn-ticket-descriptor
ticket="$ctrl.ticket"
card-reload="$ctrl.reload()">
</vn-ticket-descriptor>
<vn-left-menu source="card"></vn-left-menu> <vn-left-menu source="card"></vn-left-menu>
</vn-portal> </vn-portal>
<ui-view></ui-view> <ui-view></ui-view>

View File

@ -110,12 +110,10 @@
</vn-item> </vn-item>
<vn-item <vn-item
ng-click="createPdfConfirmation.show()" ng-click="createPdfConfirmation.show()"
ng-show="$ctrl.isInvoiced" ng-show="$ctrl.isInvoiced && ($ctrl.hasInvoicing || !$ctrl.ticket.invoiceOut.hasPdf)"
vn-acl="invoicing"
vn-acl-action="remove"
name="regenerateInvoice" name="regenerateInvoice"
translate> translate>
Regenerate invoice PDF {{!$ctrl.ticket.invoiceOut.hasPdf ? 'Generate PDF invoice': 'Regenerate PDF invoice'}}
</vn-item> </vn-item>
<vn-item <vn-item
ng-click="recalculateComponentsConfirmation.show()" ng-click="recalculateComponentsConfirmation.show()"
@ -266,8 +264,8 @@
<vn-confirm <vn-confirm
vn-id="createPdfConfirmation" vn-id="createPdfConfirmation"
on-accept="$ctrl.createPdfInvoice()" on-accept="$ctrl.createPdfInvoice()"
question="Are you sure you want to regenerate the invoice PDF document?" question="Are you sure you want to generate/regenerate the PDF invoice?"
message="You are going to regenerate the invoice PDF document"> message="Generate PDF invoice document">
</vn-confirm> </vn-confirm>
<!-- Recalculate components confirmation dialog --> <!-- Recalculate components confirmation dialog -->

View File

@ -36,6 +36,18 @@ class Controller extends Section {
}); });
} }
get isInvoiced() {
return this.ticket.refFk !== null;
}
get isTicketModule() {
return this.$state.getCurrentPath()[1].state.name === 'ticket';
}
get hasInvoicing() {
return this.aclService.hasAny(['invoicing']);
}
loadData() { loadData() {
const filter = { const filter = {
include: [{ include: [{
@ -82,14 +94,6 @@ class Controller extends Section {
}); });
} }
get isInvoiced() {
return this.ticket.refFk !== null;
}
get isTicketModule() {
return this.$state.getCurrentPath()[1].state.name === 'ticket';
}
isTicketEditable() { isTicketEditable() {
if (!this.ticket) return; if (!this.ticket) return;
@ -241,6 +245,7 @@ class Controller extends Section {
createInvoicePdf() { createInvoicePdf() {
const invoiceId = this.ticket.invoiceOut.id; const invoiceId = this.ticket.invoiceOut.id;
return this.$http.post(`InvoiceOuts/${invoiceId}/createPdf`) return this.$http.post(`InvoiceOuts/${invoiceId}/createPdf`)
.then(() => this.reload())
.then(() => { .then(() => {
const snackbarMessage = this.$t( const snackbarMessage = this.$t(
`The invoice PDF document has been regenerated`); `The invoice PDF document has been regenerated`);

View File

@ -153,6 +153,7 @@ describe('Ticket Component vnTicketDescriptorMenu', () => {
it('should make a query and show a success snackbar', () => { it('should make a query and show a success snackbar', () => {
jest.spyOn(controller.vnApp, 'showSuccess'); jest.spyOn(controller.vnApp, 'showSuccess');
$httpBackend.whenGET(`Tickets/16`).respond();
$httpBackend.expectPOST(`InvoiceOuts/${ticket.invoiceOut.id}/createPdf`).respond(); $httpBackend.expectPOST(`InvoiceOuts/${ticket.invoiceOut.id}/createPdf`).respond();
controller.createInvoicePdf(); controller.createInvoicePdf();
$httpBackend.flush(); $httpBackend.flush();

View File

@ -19,8 +19,8 @@ Regenerate invoice PDF: 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
You are going to invoice this ticket: Vas a facturar este ticket You are going to invoice this ticket: Vas a facturar este ticket
Are you sure you want to invoice this ticket?: ¿Seguro que quieres facturar este ticket? Are you sure you want to invoice this ticket?: ¿Seguro que quieres facturar este ticket?
You are going to regenerate the invoice PDF document: Vas a regenerar el documento PDF de la factura Generate PDF invoice document: Generar PDF de la factura
Are you sure you want to regenerate the invoice PDF document?: ¿Seguro que quieres regenerar el documento PDF de la factura? Are you sure you want to generate/regenerate the PDF invoice?: ¿Seguro que quieres generar/regenerar el PDF de la factura?
Shipped hour updated: Hora de envio modificada Shipped hour updated: Hora de envio modificada
Deleted ticket: Ticket eliminado Deleted ticket: Ticket eliminado
Recalculate components: Recalcular componentes Recalculate components: Recalcular componentes

View File

@ -42,7 +42,7 @@ vn-worker-calendar {
border-bottom: 1px solid rgba(0, 0, 0, 0.3); border-bottom: 1px solid rgba(0, 0, 0, 0.3);
} }
vn-avatar.festive, .festive,
vn-avatar.today { vn-avatar.today {
background-color: $color-font-dark; background-color: $color-font-dark;
width: 24px; width: 24px;
@ -50,7 +50,7 @@ vn-worker-calendar {
height: 24px height: 24px
} }
vn-avatar.festive { .festive {
border: 2px solid $color-alert border: 2px solid $color-alert
} }

View File

@ -42,7 +42,7 @@ module.exports = Self => {
const stmts = []; const stmts = [];
stmts.push(new ParameterizedSQL( stmts.push(new ParameterizedSQL(
`CALL vn.zone_getShippedWarehouse(?, ?, ?)`, [ `CALL vn.zone_getShipped(?, ?, ?, TRUE)`, [
landed, landed,
addressFk, addressFk,
agencyModeFk agencyModeFk

View File

@ -26,7 +26,7 @@ vn-zone-calendar {
& > .vn-calendar { & > .vn-calendar {
max-width: 288px; max-width: 288px;
.day { #days-container .day {
&.event .day-number { &.event .day-number {
background-color: $color-success; background-color: $color-success;
} }

View File

@ -19,9 +19,9 @@ SELECT * FROM (
AND ote.type = 'M' AND ote.type = 'M'
LEFT JOIN ost_thread_entry oter ON oth.id = oter.thread_id LEFT JOIN ost_thread_entry oter ON oth.id = oter.thread_id
AND oter.type = 'R' AND oter.type = 'R'
WHERE ot.ticket_pid = NULL WHERE ot.ticket_pid IS NULL
AND ots.state = 'closed' AND ots.state = 'closed'
AND otc.closed BETWEEN ? AND ? AND ot.closed BETWEEN ? AND ?
ORDER BY oter.created DESC ORDER BY oter.created DESC
) ot GROUP BY ot.ticket_id ) ot GROUP BY ot.ticket_id
ORDER BY ot.assigned ORDER BY ot.assigned

View File

@ -19,12 +19,14 @@ module.exports = {
const map = new Map(); const map = new Map();
for (let ticket of tickets) for (let ticket of tickets) {
ticket.sales = [];
map.set(ticket.id, ticket); map.set(ticket.id, ticket);
}
for (let sale of sales) { for (let sale of sales) {
const ticket = map.get(sale.ticketFk); const ticket = map.get(sale.ticketFk);
if (!ticket.sales) ticket.sales = [];
ticket.sales.push(sale); ticket.sales.push(sale);
} }
@ -93,6 +95,7 @@ module.exports = {
}, },
ticketSubtotal(ticket) { ticketSubtotal(ticket) {
let subTotal = 0.00; let subTotal = 0.00;
console.log(ticket.sales);
for (let sale of ticket.sales) for (let sale of ticket.sales)
subTotal += this.saleImport(sale); subTotal += this.saleImport(sale);