diff --git a/back/models/warehouse.json b/back/models/warehouse.json index f66bcffe9..fc6baacbc 100644 --- a/back/models/warehouse.json +++ b/back/models/warehouse.json @@ -21,6 +21,9 @@ }, "isManaged":{ "type": "boolean" + }, + "hasStowaway":{ + "type": "boolean" } }, "acls": [ diff --git a/db/changes/10080-september/00-warehouse.sql b/db/changes/10080-september/00-warehouse.sql new file mode 100644 index 000000000..87c8b2aad --- /dev/null +++ b/db/changes/10080-september/00-warehouse.sql @@ -0,0 +1,26 @@ +ALTER TABLE `vn2008`.`warehouse` +ADD COLUMN `hasStowaway` TINYINT(1) NOT NULL DEFAULT 0 AFTER `hasConfectionTeam`; + + + -- UPDATE `vn2008`.`warehouse` SET `hasStowaway` = '1' WHERE (`id` = '1'); + + + +CREATE + OR REPLACE ALGORITHM = UNDEFINED + DEFINER = `root`@`%` + SQL SECURITY DEFINER +VIEW `vn`.`warehouse` AS + SELECT + `t`.`id` AS `id`, + `t`.`name` AS `name`, + `t`.`inventario` AS `isInventory`, + `t`.`fuente` AS `isFeedStock`, + `t`.`is_comparative` AS `isComparative`, + `t`.`comisionantes` AS `hasComission`, + `t`.`reserve` AS `hasAvailable`, + `t`.`isManaged` AS `isManaged`, + `t`.`tpv` AS `isForTicket`, + `t`.`hasStowaway` AS `hasStowaway` + FROM + `vn2008`.`warehouse` `t`; diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 49d884c2c..770a2c676 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -56,13 +56,13 @@ INSERT INTO `vn`.`country`(`id`, `country`, `isUeeMember`, `code`, `currencyFk`, (19,'Francia', 1, 'FR', 1, 25), (30,'Canarias', 1, 'IC', 1, 22); -INSERT INTO `vn`.`warehouse`(`id`, `name`, `isComparative`, `isInventory`, `hasAvailable`, `isManaged`) +INSERT INTO `vn`.`warehouse`(`id`, `name`, `isComparative`, `isInventory`, `hasAvailable`, `isManaged`, `hasStowaway`) VALUES - (1, 'Warehouse One', 1, 1, 1, 1), - (2, 'Warehouse Two', 1, 1, 1, 1), - (3, 'Warehouse Three', 1, 1, 1, 1), - (4, 'Warehouse Four', 1, 1, 1, 1), - (5, 'Warehouse Five', 1, 1, 1, 1); + (1, 'Warehouse One', 1, 1, 1, 1, 1), + (2, 'Warehouse Two', 1, 1, 1, 1, 0), + (3, 'Warehouse Three', 1, 1, 1, 1, 0), + (4, 'Warehouse Four', 1, 1, 1, 1, 0), + (5, 'Warehouse Five', 1, 1, 1, 1, 0); INSERT INTO `vn`.`warehouseAlias`(`id`, `name`) VALUES diff --git a/e2e/paths/05-ticket-module/12_descriptor.spec.js b/e2e/paths/05-ticket-module/12_descriptor.spec.js index 7819ec546..cbae66d93 100644 --- a/e2e/paths/05-ticket-module/12_descriptor.spec.js +++ b/e2e/paths/05-ticket-module/12_descriptor.spec.js @@ -110,6 +110,7 @@ describe('Ticket descriptor path', () => { it('should open the add stowaway dialog', async() => { const isVisible = await nightmare + .waitForSpinnerLoad() .waitToClick(selectors.ticketDescriptor.moreMenu) .waitToClick(selectors.ticketDescriptor.moreMenuAddStowaway) .wait(selectors.ticketDescriptor.addStowawayDialogFirstTicket) diff --git a/loopback/locale/es.json b/loopback/locale/es.json index dfa637260..4e82aa871 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -101,5 +101,6 @@ "This ticket is already on weekly tickets": "Este ticket ya está en tickets programados", "Ticket id cannot be blank": "El id de ticket no puede quedar en blanco", "Weekday cannot be blank": "El día de la semana no puede quedar en blanco", - "You can't delete a confirmed order": "No puedes borrar un pedido confirmado" + "You can't delete a confirmed order": "No puedes borrar un pedido confirmado", + "Can't create stowaway for this ticket": "No se puede crear un polizon para este ticket" } \ No newline at end of file diff --git a/modules/ticket/back/methods/ticket/canBeStowawayed.js b/modules/ticket/back/methods/ticket/canBeStowawayed.js new file mode 100644 index 000000000..72b6d7f46 --- /dev/null +++ b/modules/ticket/back/methods/ticket/canBeStowawayed.js @@ -0,0 +1,31 @@ + +module.exports = Self => { + Self.remoteMethod('canBeStowawayed', { + description: 'Returns if a ticket can be stowawayed', + accessType: 'READ', + accepts: [{ + arg: 'id', + type: 'number', + required: true, + description: 'ticket id', + http: {source: 'path'} + }], + returns: { + root: true + }, + http: { + path: `/:id/canBeStowawayed`, + verb: 'GET' + } + }); + + Self.canBeStowawayed = async id => { + const ticket = await Self.app.models.Ticket.findById(id); + const warehouse = await Self.app.models.Warehouse.findById(ticket.warehouseFk); + + if (warehouse && warehouse.hasStowaway) + return true; + + return false; + }; +}; diff --git a/modules/ticket/back/methods/ticket/getPossibleStowaways.js b/modules/ticket/back/methods/ticket/getPossibleStowaways.js index 581a0a9c3..2f7d1864a 100644 --- a/modules/ticket/back/methods/ticket/getPossibleStowaways.js +++ b/modules/ticket/back/methods/ticket/getPossibleStowaways.js @@ -1,3 +1,5 @@ +const UserError = require('vn-loopback/util/user-error'); + module.exports = Self => { Self.remoteMethod('getPossibleStowaways', { description: 'Returns mana of a salesperson of a ticket', @@ -19,6 +21,11 @@ module.exports = Self => { }); Self.getPossibleStowaways = async ticketFk => { + let canStowaway = await Self.app.models.Ticket.canBeStowawayed(ticketFk); + + if (!canStowaway) + throw new UserError(`Can't create stowaway for this ticket`); + let ship = await Self.app.models.Ticket.findById(ticketFk); if (!ship || !ship.shipped) diff --git a/modules/ticket/back/methods/ticket/specs/canBeStowawayed.spec.js b/modules/ticket/back/methods/ticket/specs/canBeStowawayed.spec.js new file mode 100644 index 000000000..49a775225 --- /dev/null +++ b/modules/ticket/back/methods/ticket/specs/canBeStowawayed.spec.js @@ -0,0 +1,17 @@ +const app = require('vn-loopback/server/server'); + +describe('ticket canBeStowawayed()', () => { + it('should return true if the ticket warehouse have hasStowaway equal 1', async() => { + const ticketId = 16; + let canStowaway = await app.models.Ticket.canBeStowawayed(ticketId); + + expect(canStowaway).toBeTruthy(); + }); + + it('should return false if the ticket warehouse dont have hasStowaway equal 0', async() => { + const ticketId = 10; + let canStowaway = await app.models.Ticket.canBeStowawayed(ticketId); + + expect(canStowaway).toBeFalsy(); + }); +}); diff --git a/modules/ticket/back/models/stowaway.js b/modules/ticket/back/models/stowaway.js index 714d823b0..a8f967d24 100644 --- a/modules/ticket/back/models/stowaway.js +++ b/modules/ticket/back/models/stowaway.js @@ -1,6 +1,13 @@ const LoopBackContext = require('loopback-context'); +const UserError = require('vn-loopback/util/user-error'); + module.exports = function(Self) { Self.observe('before save', async function(ctx) { + let isStowaway = await Self.app.models.Ticket.canBeStowawayed(ctx.instance.id); + + if (!isStowaway) + throw new UserError(`Can't create stowaway for this ticket`); + if (ctx.isNewInstance) { let where = { code: 'BOARDING' diff --git a/modules/ticket/back/models/ticket.js b/modules/ticket/back/models/ticket.js index 4518b9007..21a41783f 100644 --- a/modules/ticket/back/models/ticket.js +++ b/modules/ticket/back/models/ticket.js @@ -25,6 +25,7 @@ module.exports = Self => { require('../methods/ticket/uploadFile')(Self); require('../methods/ticket/addSale')(Self); require('../methods/ticket/transferSales')(Self); + require('../methods/ticket/canBeStowawayed')(Self); Self.observe('before save', async function(ctx) { if (ctx.isNewInstance) return; diff --git a/modules/ticket/front/basic-data/step-one/index.spec.js b/modules/ticket/front/basic-data/step-one/index.spec.js index 1ebce7bf1..d035d30a5 100644 --- a/modules/ticket/front/basic-data/step-one/index.spec.js +++ b/modules/ticket/front/basic-data/step-one/index.spec.js @@ -156,7 +156,6 @@ describe('Ticket', () => { $httpBackend.when('GET', `/api/Clients/${clientId}/addresses?filter=${filter}`).respond(200); $httpBackend.expect('GET', `/api/Clients/${clientId}/addresses?filter=${filter}`); - controller.onChangeClient(clientId); $httpBackend.flush(); }); @@ -175,66 +174,11 @@ describe('Ticket', () => { $httpBackend.when('GET', `/api/Zones/${zoneId}`).respond(200); $httpBackend.expect('GET', `/api/Zones/${zoneId}`); - controller.onChangeZone(zoneId); $httpBackend.flush(); }); }); - - /* it('should return an available agency', async() => { - const landed = new Date(); - const agencyModeId = 7; - controller._ticket = { - id: 1, - landed: landed, - addressFk: 121, - agencyModeFk: agencyModeId, - warehouseFk: 1 - }; - let params = { - landed: landed, - addressFk: 121, - agencyModeFk: agencyModeId, - warehouseFk: 1 - }; - - let serializedParams = $httpParamSerializer(params); - $httpBackend.when('GET', `/api/Agencies/getShipped?${serializedParams}`).respond(200); - $httpBackend.expect('GET', `/api/Agencies/getShipped?${serializedParams}`); - - controller.onChangeAgencyMode(agencyModeId); - $httpBackend.flush(); - }); - - it('should throw a user error', async() => { - spyOn(controller.vnApp, 'showMessage'); - const landed = new Date(); - const agencyModeId = 7; - controller._ticket = { - id: 1, - landed: landed, - addressFk: 121, - agencyModeFk: agencyModeId, - warehouseFk: 1 - }; - let params = { - landed: landed, - addressFk: 121, - agencyModeFk: agencyModeId, - warehouseFk: 1 - }; - - let serializedParams = $httpParamSerializer(params); - $httpBackend.when('GET', `/api/Agencies/getShipped?${serializedParams}`).respond(null); - $httpBackend.expect('GET', `/api/Agencies/getShipped?${serializedParams}`); - - controller.onChangeAgencyMode(agencyModeId); - $httpBackend.flush(); - - expect(controller.vnApp.showMessage).toHaveBeenCalledWith('No delivery zone available for this parameters'); - }); */ - describe('isFormInvalid()', () => { it('should check if all form fields are valid', () => { controller.ticket = { diff --git a/modules/ticket/front/descriptor/index.js b/modules/ticket/front/descriptor/index.js index 67e539877..184176cdc 100644 --- a/modules/ticket/front/descriptor/index.js +++ b/modules/ticket/front/descriptor/index.js @@ -18,7 +18,7 @@ class Controller { { name: 'Add stowaway', callback: this.showAddStowaway, - show: () => this.isTicketModule() + show: () => this.canShowStowaway }, { name: 'Remove stowaway', @@ -40,6 +40,14 @@ class Controller { ]; } + set canShowStowaway(value) { + this._canShowStowaway = value; + } + + get canShowStowaway() { + return this._canShowStowaway; + } + showChangeShipped() { if (!this.isEditable) { this.vnApp.showError(this.$translate.instant('This ticket can\'t be modified')); @@ -62,12 +70,24 @@ class Controller { isTicketModule() { let path = this.$state.getCurrentPath(); - if (path[1].state.name === 'ticket') + const isTicket = path[1].state.name === 'ticket'; + if (isTicket) return true; return false; } + canStowaway() { + if (!this.isTicketModule()) return; + + this.$http.get(`/api/Tickets/${this.ticket.id}/canBeStowawayed`).then(response => { + if (response.data === true) + return this.canShowStowaway = true; + + return this.canShowStowaway = false; + }); + } + shouldShowRemoveStowaway() { if (!this._ticket || !this.isTicketModule()) return false; @@ -153,6 +173,8 @@ class Controller { set ticket(value) { this._ticket = value; + if (value) + this.canStowaway(); if (!value) return; diff --git a/modules/ticket/front/descriptor/index.spec.js b/modules/ticket/front/descriptor/index.spec.js index 360f18cf1..9517c646b 100644 --- a/modules/ticket/front/descriptor/index.spec.js +++ b/modules/ticket/front/descriptor/index.spec.js @@ -3,13 +3,21 @@ import './index.js'; describe('Ticket Component vnTicketDescriptor', () => { let $httpBackend; let controller; + let $state; beforeEach(ngModule('ticket')); - beforeEach(angular.mock.inject(($componentController, _$httpBackend_) => { + beforeEach(angular.mock.inject(($componentController, _$state_, _$httpBackend_) => { + $state = _$state_; + $state.getCurrentPath = () => { + return [ + {state: {}}, + {state: {name: 'ticket'}} + ]; + }; $httpBackend = _$httpBackend_; - controller = $componentController('vnTicketDescriptor'); - controller.ticket = {id: 2, invoiceOut: {id: 1}}; + controller = $componentController('vnTicketDescriptor', {$state}); + controller._ticket = {id: 2, invoiceOut: {id: 1}}; controller.cardReload = ()=> { return true; }; @@ -25,7 +33,7 @@ describe('Ticket Component vnTicketDescriptor', () => { }); }); - describe('addTurn(day)', () => { + describe('addTurn()', () => { it('should make a query and call $.addTurn.hide() and vnApp.showSuccess()', () => { controller.$scope.addTurn = {hide: () => {}}; spyOn(controller.$scope.addTurn, 'hide'); @@ -57,7 +65,7 @@ describe('Ticket Component vnTicketDescriptor', () => { }); }); - describe('deleteTicket(response)', () => { + describe('deleteTicket()', () => { it('should make a query and call vnApp.showSuccess() if the response is ACCEPT', () => { spyOn(controller.$state, 'go'); spyOn(controller.vnApp, 'showSuccess'); @@ -81,7 +89,7 @@ describe('Ticket Component vnTicketDescriptor', () => { }); }); - describe('makeInvoice(response)', () => { + describe('makeInvoice()', () => { it('should make a query and call $state.reload() method if the response is ACCEPT', () => { spyOn(controller.$state, 'reload'); spyOn(controller.vnApp, 'showSuccess'); @@ -96,7 +104,7 @@ describe('Ticket Component vnTicketDescriptor', () => { }); }); - describe('regenerateInvoice(response)', () => { + describe('regenerateInvoice()', () => { it('should make a query and show a success snackbar if the response is ACCEPT', () => { spyOn(controller.vnApp, 'showSuccess'); @@ -109,7 +117,7 @@ describe('Ticket Component vnTicketDescriptor', () => { }); }); - describe('changeShipped(response)', () => { + describe('changeShipped()', () => { it('should make a query and change the shipped hour if the response is ACCEPT', () => { controller.ticket.id = 12; spyOn(controller.vnApp, 'showSuccess'); @@ -124,4 +132,33 @@ describe('Ticket Component vnTicketDescriptor', () => { expect(controller.cardReload).toHaveBeenCalledWith(); }); }); + + describe('canStowaway()', () => { + it('should make a query and return if the ticket can be stowawayed', () => { + controller.ticket.id = 16; + spyOn(controller, 'isTicketModule').and.callThrough(); + $httpBackend.when('GET', '/api/Tickets/16/canBeStowawayed').respond(true); + $httpBackend.expect('GET', '/api/Tickets/16/canBeStowawayed').respond(true); + controller.canStowaway(); + $httpBackend.flush(); + + expect(controller.canShowStowaway).toBeTruthy(); + expect(controller.isTicketModule).toHaveBeenCalledWith(); + }); + + it('should not make a query if is not on the ticket module', () => { + controller.ticket.id = 16; + $state.getCurrentPath = () => { + return [ + {state: {}}, + {state: {name: 'client'}} + ]; + }; + spyOn(controller, 'isTicketModule').and.callThrough(); + controller.canStowaway(); + + expect(controller.canShowStowaway).toBeUndefined(); + expect(controller.isTicketModule).toHaveBeenCalledWith(); + }); + }); });