Added ticket invoice #1310
gitea/salix/dev This commit has test failures Details

This commit is contained in:
Joan Sanchez 2019-04-12 13:54:31 +02:00
parent 6eef192929
commit ac8a27d2f4
11 changed files with 282 additions and 16 deletions

View File

@ -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;

View File

@ -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 ;

View File

@ -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;

View File

@ -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'),

View File

@ -48,7 +48,7 @@ vn-drop-down {
}
}
& > .list {
max-height: 12.8em;
max-height: 20em;
overflow: auto;
ul {

View File

@ -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;

View File

@ -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`);
});
});
});

View File

@ -179,6 +179,15 @@
</tpl-buttons>
</vn-dialog>
<!-- Make invoice dialog -->
<vn-confirm
vn-id="invoiceMakeConfirmation"
on-response="$ctrl.invoiceMakeOut(response)"
question="You are going to invoice this ticket"
message="Are you sure you want to invoice this ticket?">
</vn-confirm>
<!-- Make invoice dialog -->
<!-- SMS Dialog -->
<vn-client-sms vn-id="sms" sms="$ctrl.newSMS"></vn-client-sms>
<!-- SMS Dialog -->

View File

@ -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'),

View File

@ -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();
});
});
});

View File

@ -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.
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?