diff --git a/db/changes/10400-christmas/00-ACL.sql b/db/changes/10400-christmas/00-ACL.sql new file mode 100644 index 000000000..45dc56c6b --- /dev/null +++ b/db/changes/10400-christmas/00-ACL.sql @@ -0,0 +1,2 @@ +INSERT INTO salix.ACL (model,property,accessType,permission,principalType,principalId) + VALUES ('Sale','payment','WRITE','ALLOW','ROLE','employee'); diff --git a/db/changes/10400-christmas/00-ticket_doRefund.sql b/db/changes/10400-christmas/00-ticket_doRefund.sql new file mode 100644 index 000000000..1c1faf315 --- /dev/null +++ b/db/changes/10400-christmas/00-ticket_doRefund.sql @@ -0,0 +1,90 @@ +DROP PROCEDURE IF EXISTS `vn`.`ticket_doRefund`; + +DELIMITER $$ +$$ +CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_doRefund`(IN vOriginTicket INT, OUT vNewTicket INT) +BEGIN + + DECLARE vDone BIT DEFAULT 0; + DECLARE vCustomer MEDIUMINT; + DECLARE vWarehouse TINYINT; + DECLARE vCompany MEDIUMINT; + DECLARE vAddress MEDIUMINT; + DECLARE vRefundAgencyMode INT; + DECLARE vItemFk INT; + DECLARE vQuantity DECIMAL (10,2); + DECLARE vConcept VARCHAR(50); + DECLARE vPrice DECIMAL (10,2); + DECLARE vDiscount TINYINT; + DECLARE vSaleNew INT; + DECLARE vSaleMain INT; + DECLARE vZoneFk INT; + + DECLARE vRsMainTicket CURSOR FOR + SELECT * + FROM tmp.sale; + + DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = 1; + + SELECT id INTO vRefundAgencyMode + FROM agencyMode WHERE `name` = 'ABONO'; + + SELECT clientFk, warehouseFk, companyFk, addressFk + INTO vCustomer, vWarehouse, vCompany, vAddress + FROM ticket + WHERE id = vOriginTicket; + + SELECT id INTO vZoneFk + FROM zone WHERE agencyModeFk = vRefundAgencyMode + LIMIT 1; + + INSERT INTO vn.ticket ( + clientFk, + shipped, + addressFk, + agencyModeFk, + nickname, + warehouseFk, + companyFk, + landed, + zoneFk + ) + SELECT + vCustomer, + CURDATE(), + vAddress, + vRefundAgencyMode, + a.nickname, + vWarehouse, + vCompany, + CURDATE(), + vZoneFk + FROM address a + WHERE a.id = vAddress; + + SET vNewTicket = LAST_INSERT_ID(); + + SET vDone := 0; + OPEN vRsMainTicket ; + FETCH vRsMainTicket INTO vSaleMain, vItemFk, vQuantity, vConcept, vPrice, vDiscount; + + WHILE NOT vDone DO + + INSERT INTO vn.sale(ticketFk, itemFk, quantity, concept, price, discount) + VALUES( vNewTicket, vItemFk, vQuantity, vConcept, vPrice, vDiscount ); + + SET vSaleNew = LAST_INSERT_ID(); + + INSERT INTO vn.saleComponent(saleFk,componentFk,`value`) + SELECT vSaleNew,componentFk,`value` + FROM vn.saleComponent + WHERE saleFk = vSaleMain; + + FETCH vRsMainTicket INTO vSaleMain, vItemFk, vQuantity, vConcept, vPrice, vDiscount; + + END WHILE; + CLOSE vRsMainTicket; + +END; +$$ +DELIMITER ; \ No newline at end of file diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index 24b87b398..7b80d7a96 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -558,6 +558,7 @@ export default { moreMenuUnmarkReseved: 'vn-item[name="unreserve"]', moreMenuUpdateDiscount: 'vn-item[name="discount"]', moreMenuRecalculatePrice: 'vn-item[name="calculatePrice"]', + moreMenuPayment: 'vn-item[name="payment"]', moreMenuUpdateDiscountInput: 'vn-input-number[ng-model="$ctrl.edit.discount"] input', transferQuantityInput: '.vn-popover.shown vn-table > div > vn-tbody > vn-tr > vn-td-editable > span > text', transferQuantityCell: '.vn-popover.shown vn-table > div > vn-tbody > vn-tr > vn-td-editable', diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 2611ee0dd..ad2ea2841 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -216,5 +216,6 @@ "The type of business must be filled in basic data": "El tipo de negocio debe estar rellenado en datos básicos", "You can't create a claim from a ticket delivered more than seven days ago": "No puedes crear una reclamación de un ticket entregado hace más de siete días", "The worker has hours recorded that day": "El trabajador tiene horas fichadas ese día", - "The worker has a marked absence that day": "El trabajador tiene marcada una ausencia ese día" + "The worker has a marked absence that day": "El trabajador tiene marcada una ausencia ese día", + "There is no zone for these parameters": "There is no zone for these parameters" } \ No newline at end of file diff --git a/modules/ticket/back/methods/sale/payment.js b/modules/ticket/back/methods/sale/payment.js new file mode 100644 index 000000000..ab221e4d2 --- /dev/null +++ b/modules/ticket/back/methods/sale/payment.js @@ -0,0 +1,77 @@ +module.exports = Self => { + Self.remoteMethodCtx('payment', { + description: 'Create ticket with the selected lines changing the sign to the quantites', + accessType: 'WRITE', + accepts: [{ + arg: 'sales', + description: 'The sales', + type: ['object'], + required: true + }, + { + arg: 'ticketId', + type: 'number', + required: true, + description: 'The ticket id' + }], + returns: { + type: 'number', + root: true + }, + http: { + path: `/payment`, + verb: 'post' + } + }); + + Self.payment = async(ctx, sales, ticketId, options) => { + const myOptions = {}; + let tx; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } + + try { + const salesIds = []; + const params = []; + sales.forEach(sale => { + salesIds.push(sale.id); + params.push('?'); + }); + + const paramsString = params.join(); + + const query = ` + DROP TEMPORARY TABLE IF EXISTS tmp.sale; + CREATE TEMPORARY TABLE tmp.sale + SELECT s.id, s.itemFk, - s.quantity, s.concept, s.price, s.discount + FROM sale s + WHERE s.id IN (${paramsString}); + CALL vn.ticket_doRefund(${ticketId}, @newTicket); + DROP TEMPORARY TABLE tmp.sale;`; + + await Self.rawSql(query, salesIds, myOptions); + const [newTicket] = await Self.rawSql('SELECT @newTicket id', null, myOptions); + ticketId = newTicket.id; + console.log(ticketId); + /* + const message = $t('Deleted sales from ticket', { + ticketId: ticketId, + ticketUrl: `${origin}/#!/ticket/${ticketId}/sale`, + deletions: deletions + }); + */ + if (tx) await tx.commit(); + + return ticketId; + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } + }; +}; diff --git a/modules/ticket/back/models/sale.js b/modules/ticket/back/models/sale.js index 545e054dc..88e1b8308 100644 --- a/modules/ticket/back/models/sale.js +++ b/modules/ticket/back/models/sale.js @@ -6,6 +6,7 @@ module.exports = Self => { require('../methods/sale/updateQuantity')(Self); require('../methods/sale/updateConcept')(Self); require('../methods/sale/recalculatePrice')(Self); + require('../methods/sale/payment')(Self); require('../methods/sale/canEdit')(Self); Self.validatesPresenceOf('concept', { diff --git a/modules/ticket/front/sale/index.html b/modules/ticket/front/sale/index.html index f7a279d9a..7ca1d47f9 100644 --- a/modules/ticket/front/sale/index.html +++ b/modules/ticket/front/sale/index.html @@ -490,4 +490,9 @@ ng-if="$ctrl.isEditable && $ctrl.hasReserves()"> Unmark as reserved + + Payment + \ No newline at end of file diff --git a/modules/ticket/front/sale/index.js b/modules/ticket/front/sale/index.js index 752ed23ba..256c72b39 100644 --- a/modules/ticket/front/sale/index.js +++ b/modules/ticket/front/sale/index.js @@ -460,6 +460,18 @@ class Controller extends Section { }); } + createPayment() { + const sales = this.selectedValidSales(); + if (!sales) return; + + const params = {sales: sales, ticketId: this.ticket.id}; + const query = `Sales/payment`; + this.resetChanges(); + this.$http.post(query, params).then(res => { + this.$state.go('ticket.card.sale', {id: res.data}); + }); + } + itemSearchFunc($search) { return /^\d+$/.test($search) ? {id: $search} diff --git a/modules/ticket/front/sale/index.spec.js b/modules/ticket/front/sale/index.spec.js index 673e9a3f9..2a0d60fa6 100644 --- a/modules/ticket/front/sale/index.spec.js +++ b/modules/ticket/front/sale/index.spec.js @@ -701,6 +701,27 @@ describe('Ticket', () => { }); }); + describe('createPayment()', () => { + it('should make an HTTP POST query and then call to the $state go() method', () => { + jest.spyOn(controller, 'resetChanges').mockReturnThis(); + jest.spyOn(controller.$state, 'go').mockReturnThis(); + + const ticketId = 13; + const expectedResponse = {id: ticketId}; + const params = { + sales: controller.sales, + ticketId: 13 + }; + + $httpBackend.expect('POST', `Sales/payment`, params).respond(expectedResponse); + controller.createPayment(); + $httpBackend.flush(); + + expect(controller.resetChanges).toHaveBeenCalledWith(); + expect(controller.$state.go).toHaveBeenCalledWith('ticket.card.sale', {id: ticketId}); + }); + }); + describe('itemSearchFunc()', () => { it('should return the filter by id property for an input of a number', () => { const itemId = 1; diff --git a/modules/ticket/front/sale/locale/es.yml b/modules/ticket/front/sale/locale/es.yml index 92d8dfe28..734bbdbfd 100644 --- a/modules/ticket/front/sale/locale/es.yml +++ b/modules/ticket/front/sale/locale/es.yml @@ -35,4 +35,5 @@ Address: Dirección Warehouse: Almacen Agency: Agencia Shipped: F. envio -Packaging: Encajado \ No newline at end of file +Packaging: Encajado +Payment: Abono \ No newline at end of file