diff --git a/db/changes/10002-lent/00-invoiceOut.sql b/db/changes/10002-lent/00-invoiceOut.sql new file mode 100644 index 000000000..ed58227ac --- /dev/null +++ b/db/changes/10002-lent/00-invoiceOut.sql @@ -0,0 +1,9 @@ +ALTER TABLE `vn2008`.`Facturas` +DROP FOREIGN KEY `invoice_bank_id`; +ALTER TABLE `vn2008`.`Facturas` +CHANGE COLUMN `Id_Banco` `Id_Banco` INT(11) NULL DEFAULT NULL ; +ALTER TABLE `vn2008`.`Facturas` +ADD CONSTRAINT `invoice_bank_id` + FOREIGN KEY (`Id_Banco`) + REFERENCES `vn2008`.`Bancos` (`Id_Banco`) + ON UPDATE CASCADE; diff --git a/db/changes/10002-lent/00-invoiceOutMake.sql b/db/changes/10002-lent/00-invoiceOutMake.sql new file mode 100644 index 000000000..13acbbbbc --- /dev/null +++ b/db/changes/10002-lent/00-invoiceOutMake.sql @@ -0,0 +1,141 @@ +DROP procedure IF EXISTS `vn`.`invoiceOutMake`; + +DELIMITER $$ +$$ +CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`invoiceOutMake`( + vSerial VARCHAR(255), + vInvoiceDate DATETIME, + OUT vNewInvoiceId INT) +BEGIN + +/* Creación de facturas emitidas. +* REQUIERE previamente tabla ticketToInvoice. +* +* @param vSerial, vInvoiceDate, vCompany, vClient +* +* @return vNewInvoiceId +*/ + + DECLARE vSpainCountryCode INT DEFAULT 1; + DECLARE vIsAnySaleToInvoice BOOL; + DECLARE vCountry TINYINT DEFAULT 1; + DECLARE vNewRef VARCHAR(255); + DECLARE vWorker INT DEFAULT vn.getWorker(); + DECLARE vCompany INT; + DECLARE vClient INT; + DECLARE vCplusStandardInvoiceTypeFk INT DEFAULT 1; + DECLARE vCplusCorrectingInvoiceTypeFk INT DEFAULT 6; + DECLARE vCplusSimplifiedInvoiceTypeFk INT DEFAULT 2; + DECLARE vCorrectingSerial VARCHAR(1) DEFAULT 'R'; + DECLARE vSimplifiedSerial VARCHAR(1) DEFAULT 'S'; + + SET vInvoiceDate = IFNULL(vInvoiceDate,CURDATE()); + + SELECT t.clientFk, t.companyFk + INTO vClient, vCompany + FROM ticketToInvoice tt + JOIN ticket t ON t.id = tt.id + LIMIT 1; + + -- Elimina tickets sense moviments +/* UPDATE ticket t + JOIN ticketToInvoice ti ON ti.id = t.id + LEFT JOIN sale s ON s.ticketFk = ti.id + LEFT JOIN expedition e ON e.ticketFk = t.id + LEFT JOIN ticketPackaging tp ON tp.ticketFk = t.id + SET t.shipped = '2000-02-01 00:00:00' + WHERE s.ticketFk IS NULL AND e.ticketFk IS NULL AND e.ticketFk IS NULL; +*/ + -- Eliminem de ticketToInvoice els tickets que no han de ser facturats + DELETE ti.* + FROM ticketToInvoice ti + JOIN ticket t ON t.id = ti.id + JOIN client c ON c.id = t.clientFk + WHERE YEAR(t.shipped) < 2001 + OR c.isTaxDataChecked = FALSE; + + SELECT SUM(quantity * price * (100 - discount)/100) + INTO vIsAnySaleToInvoice + FROM sale s + JOIN ticketToInvoice t on t.id = s.ticketFk; + + IF vIsAnySaleToInvoice THEN + + -- el trigger añade el siguiente Id_Factura correspondiente a la vSerial + -- el trigger añade el siguiente Id_Factura correspondiente a la vSerial + INSERT INTO invoiceOut + ( + ref, + serial, + issued, + clientFk, + dued, + companyFk, + cplusInvoiceType477Fk + ) + SELECT + 1, + vSerial, + vInvoiceDate, + vClient, + getDueDate(vInvoiceDate, dueDay), + vCompany, + IF(vSerial = vCorrectingSerial, + vCplusCorrectingInvoiceTypeFk, + IF(vSerial = vSimplifiedSerial, + vCplusSimplifiedInvoiceTypeFk, + vCplusStandardInvoiceTypeFk)) + FROM client + WHERE id = vClient; + + + SET vNewInvoiceId = LAST_INSERT_ID(); + + SELECT ref + INTO vNewRef + FROM invoiceOut + WHERE id = vNewInvoiceId; + + UPDATE ticket t + JOIN ticketToInvoice ti ON ti.id = t.id + SET t.refFk = vNewRef; + + DROP TEMPORARY TABLE IF EXISTS tmp.updateInter; + CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY + SELECT s.id,ti.id ticket_id,vWorker Id_Trabajador + FROM ticketToInvoice ti + LEFT JOIN vn.ticketState ts ON ti.id = ts.ticket + JOIN state s + WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = vn.getAlert3State(ti.id); + + INSERT INTO vncontrol.inter(state_id,Id_Ticket,Id_Trabajador) + SELECT * FROM tmp.updateInter; + + + INSERT INTO ticketLog (action, userFk,originFk, description) + SELECT 'UPDATE',account.userGetId(),ti.id, CONCAT('Crea factura ',vNewRef) + FROM ticketToInvoice ti; + + CALL invoiceExpenceMake(vNewInvoiceId); + CALL invoiceTaxMake(vNewInvoiceId,vCountry); + + UPDATE invoiceOut io + JOIN ( + SELECT SUM(amount) AS total + FROM invoiceOutExpence + WHERE invoiceOutFk = vNewInvoiceId + ) base + JOIN ( + SELECT SUM(vat) AS total + FROM invoiceOutTax + WHERE invoiceOutFk = vNewInvoiceId + ) vat + SET io.amount = base.total + vat.total + WHERE io.id = vNewInvoiceId; + + END IF; + + DROP TEMPORARY TABLE `ticketToInvoice`; +END$$ + +DELIMITER ; diff --git a/db/changes/10002-lent/00-printQueue.sql b/db/changes/10002-lent/00-printQueue.sql new file mode 100644 index 000000000..d2493458b --- /dev/null +++ b/db/changes/10002-lent/00-printQueue.sql @@ -0,0 +1,17 @@ +ALTER TABLE `vn2008`.`Colas` +DROP FOREIGN KEY `Colas_ibfk_1`, +DROP FOREIGN KEY `Colas_ibfk_2`, +DROP FOREIGN KEY `Colas_ibfk_3`, +DROP FOREIGN KEY `Colas_ibfk_5`; +ALTER TABLE `vn2008`.`Colas` +CHANGE COLUMN `Id_Impresora` `Id_Impresora` TINYINT(3) UNSIGNED NULL DEFAULT NULL , +CHANGE COLUMN `Id_Prioridad` `Id_Prioridad` TINYINT(3) UNSIGNED NULL DEFAULT NULL ; +ALTER TABLE `vn2008`.`Colas` +ADD CONSTRAINT `Colas_ibfk_4` + FOREIGN KEY (`Id_Impresora`) + REFERENCES `vn2008`.`Impresoras` (`Id_Impresora`) + ON UPDATE CASCADE, +ADD CONSTRAINT `Colas_ibfk_3` + FOREIGN KEY (`Id_Prioridad`) + REFERENCES `vn2008`.`Prioridades` (`Id_Prioridad`) + ON UPDATE CASCADE; diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 13233b69e..3b409aca3 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -973,6 +973,14 @@ INSERT INTO `vn2008`.`tblContadores`(`id`,`FechaInventario`) VALUES (1,DATE_ADD(CURDATE(),INTERVAL -1 MONTH)); +INSERT INTO `vn2008`.`Estados` (`Id_Estado`, `Estado`) + VALUES + ('1', 'En Espera'); + +INSERT INTO `vn2008`.`Informes` (`Id_Informe`, `Informe`) + VALUES + ('30', 'Generar factura PDF'); + INSERT INTO `vn`.`deliveryMethod`(`id`, `code`, `description`) VALUES ( 1, 'AGENCY', 'Agencia'), diff --git a/front/core/components/drop-down/style.scss b/front/core/components/drop-down/style.scss index 43be76492..3fceb0212 100755 --- a/front/core/components/drop-down/style.scss +++ b/front/core/components/drop-down/style.scss @@ -48,7 +48,7 @@ vn-drop-down { } } & > .list { - max-height: 12.8em; + max-height: 20em; overflow: auto; ul { diff --git a/modules/ticket/back/methods/ticket/makeInvoice.js b/modules/ticket/back/methods/ticket/makeInvoice.js index b472cfa81..1bc514990 100644 --- a/modules/ticket/back/methods/ticket/makeInvoice.js +++ b/modules/ticket/back/methods/ticket/makeInvoice.js @@ -2,14 +2,14 @@ const UserError = require('vn-loopback/util/user-error'); module.exports = function(Self) { Self.remoteMethodCtx('makeInvoice', { - description: 'Change property isEqualizated in all client addresses', + description: 'Make out an invoice from a ticket id', accessType: 'WRITE', accepts: [ { arg: 'id', type: 'string', required: true, - description: 'Client id', + description: 'Ticket id', http: {source: 'path'} } ], @@ -53,7 +53,7 @@ module.exports = function(Self) { query = `CALL vn.invoiceOutMake(?, ?, @invoiceId); SELECT @invoiceId AS invoiceId;`; result = await Self.rawSql(query, [serial, null], options); - let invoice = result[1].invoiceId; + let invoice = result[1][0].invoiceId; if (serial != 'R' && invoice) { query = `CALL vn.invoiceOutBooking(?)`; @@ -62,9 +62,11 @@ module.exports = function(Self) { let user = await Self.app.models.Worker.findOne({where: {userFk: userId}}); - query = `INSERT INTO vn2008.Colas(Id_Informe,Cola,Id_Trabajador) VALUES (?, ?, ?)`; + query = `INSERT INTO printServerQueue(reportFk, param1, workerFk) VALUES (?, ?, ?)`; await Self.rawSql(query, [3, invoice, user.id], options); await options.transaction.commit(); + + return {invoiceFk: invoice, serial}; } catch (e) { options.transaction.rollback(); throw e; diff --git a/modules/ticket/back/methods/ticket/specs/makeInvoice.spec.js b/modules/ticket/back/methods/ticket/specs/makeInvoice.spec.js new file mode 100644 index 000000000..29bd29e50 --- /dev/null +++ b/modules/ticket/back/methods/ticket/specs/makeInvoice.spec.js @@ -0,0 +1,31 @@ +const app = require('vn-loopback/server/server'); + +describe('ticket makeInvoice()', () => { + afterAll(async done => { + let ticket = await app.models.Ticket.findById(11); + ticket.updateAttributes({refFk: null}); + + done(); + }); + + it('should invoice a ticket', async() => { + let ctx = {req: {accessToken: {userId: 9}}}; + let ticketFk = 11; + let result = await app.models.Ticket.makeInvoice(ctx, ticketFk); + + expect(result.invoiceFk).not.toBeNaN(); + expect(result.serial).toEqual('T'); + }); + + it('should not invoice an already invoiced ticket', async() => { + let ctx = {req: {accessToken: {userId: 9}}}; + let ticketFk = 11; + let error; + + await app.models.Ticket.makeInvoice(ctx, ticketFk).catch(e => { + error = e; + }).finally(() => { + expect(error.message).toEqual(`This ticket can't be invoiced`); + }); + }); +}); diff --git a/modules/ticket/front/descriptor/index.html b/modules/ticket/front/descriptor/index.html index dbe8f8c89..779ce7e53 100644 --- a/modules/ticket/front/descriptor/index.html +++ b/modules/ticket/front/descriptor/index.html @@ -179,6 +179,15 @@ + + + + + \ No newline at end of file diff --git a/modules/ticket/front/descriptor/index.js b/modules/ticket/front/descriptor/index.js index 5c7d81ab9..f61c94d23 100644 --- a/modules/ticket/front/descriptor/index.js +++ b/modules/ticket/front/descriptor/index.js @@ -1,21 +1,23 @@ import ngModule from '../module'; class Controller { - constructor($state, $scope, $http, vnApp, $translate) { + constructor($state, $scope, $http, vnApp, $translate, aclService) { this.$scope = $scope; this.$state = $state; this.$http = $http; this.vnApp = vnApp; this.$translate = $translate; + this.aclService = aclService; this.moreOptions = [ - {callback: this.showAddTurnDialog, name: 'Add turn', show: true}, + {callback: this.showAddTurnDialog, name: 'Add turn'}, {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.showDeleteTicketDialog, name: 'Delete ticket', show: true}, - {callback: this.showChangeShipped, name: 'Change shipped hour', show: true}, - {callback: this.showSMSDialog, name: 'Send SMS', show: true}, - {callback: this.openRptRoute, name: 'Show pallet report', show: true} + {callback: this.showInvoiceOutMakeDialog, name: 'Make invoice', acl: 'invoicing'}, + {callback: this.showDeliveryNote, name: 'Show Delivery Note'}, + {callback: this.showDeleteTicketDialog, name: 'Delete ticket'}, + {callback: this.showChangeShipped, name: 'Change shipped hour'}, + {callback: this.showSMSDialog, name: 'Send SMS'}, + {callback: this.openRptRoute, name: 'Show pallet report'} ]; } @@ -64,7 +66,12 @@ class Controller { onMoreOpen() { let options = this.moreOptions.filter(o => { - return o.show === true || typeof o.show === 'function' && o.show(); + const hasShowProperty = Object.hasOwnProperty.call(o, 'show'); + const hasAclProperty = Object.hasOwnProperty.call(o, 'acl'); + const hasAcl = !hasAclProperty || (hasAclProperty && this.aclService.hasAny([o.acl])); + + return (!hasShowProperty || o.show === true || + typeof o.show === 'function' && o.show()) && hasAcl; }); this.$scope.moreButton.data = options; } @@ -180,9 +187,32 @@ class Controller { }; this.$scope.sms.open(); } + + /** + * Shows an invoice confirmation + */ + showInvoiceOutMakeDialog() { + this.$scope.invoiceMakeConfirmation.show(); + } + + /** + * Makes an invoice + * from current ticket + * + * @param {String} response - Response result + */ + invoiceMakeOut(response) { + if (response === 'ACCEPT') { + const query = `/ticket/api/Tickets/${this.ticket.id}/makeInvoice`; + this.$http.post(query).then(() => { + this.vnApp.showSuccess(this.$translate.instant('Ticket invoiced')); + this.$state.reload(); + }); + } + } } -Controller.$inject = ['$state', '$scope', '$http', 'vnApp', '$translate']; +Controller.$inject = ['$state', '$scope', '$http', 'vnApp', '$translate', 'aclService']; ngModule.component('vnTicketDescriptor', { template: require('./index.html'), diff --git a/modules/ticket/front/descriptor/index.spec.js b/modules/ticket/front/descriptor/index.spec.js index 2c2359299..8e5a43f71 100644 --- a/modules/ticket/front/descriptor/index.spec.js +++ b/modules/ticket/front/descriptor/index.spec.js @@ -77,5 +77,20 @@ describe('Ticket Component vnTicketDescriptor', () => { expect(window.open).toHaveBeenCalledWith(expectedPath); }); }); + + describe('invoiceMakeOut(response)', () => { + it('should make a query and call $state.reload() method if the response is ACCEPT', () => { + spyOn(controller.$state, 'reload'); + spyOn(controller.vnApp, 'showSuccess'); + + $httpBackend.when('POST', `/ticket/api/Tickets/2/makeInvoice`).respond(); + $httpBackend.expect('POST', `/ticket/api/Tickets/2/makeInvoice`).respond(); + controller.invoiceMakeOut('ACCEPT'); + $httpBackend.flush(); + + expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Ticket invoiced'); + expect(controller.$state.reload).toHaveBeenCalledWith(); + }); + }); }); diff --git a/modules/ticket/front/descriptor/locale/es.yml b/modules/ticket/front/descriptor/locale/es.yml index 3ce9905cb..0e0d0bdd6 100644 --- a/modules/ticket/front/descriptor/locale/es.yml +++ b/modules/ticket/front/descriptor/locale/es.yml @@ -6,11 +6,15 @@ Stowaways to add: Polizones a añadir Stowaways of the ticket: Polizones del ticket Add stowaway: Añadir polizón Remove stowaway: Borrar polizón -Are you sure you want to delete this stowaway?: ¿Estas seguro de que quieres borrar este polizón? +Are you sure you want to delete this stowaway?: ¿Seguro que quieres borrar este polizón? Show Delivery Note: Ver albarán Show pallet report: Mostrar hoja de pallet Change shipped hour: Cambiar hora de envío Shipped hour: Hora de envío SMSPayment: >- Verdnatura le comunica: Su pedido está pendiente de pago. - Por favor, entre en la página web y efectue el pago con tarjeta. Muchas gracias. \ No newline at end of file + Por favor, entre en la página web y efectue el pago con tarjeta. Muchas gracias. +Ticket invoiced: Ticket facturado +Make invoice: Facturar +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? \ No newline at end of file