From fa344f4ff68e3fc00e192f56352138bb7cbcdb99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joan=20S=C3=A1nchez?= Date: Sat, 19 Sep 2020 13:02:00 +0200 Subject: [PATCH 1/5] 2449 - Autocompletion --- front/core/components/autocomplete/index.js | 4 +- front/core/components/drop-down/index.js | 3 ++ .../front/basic-data/step-one/index.html | 11 ++++-- .../ticket/front/basic-data/step-one/index.js | 12 +++++- .../back/methods/agency-mode/byWarehouse.js | 38 +++++++++++++++++++ modules/zone/back/models/agency-mode.js | 3 ++ 6 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 modules/zone/back/methods/agency-mode/byWarehouse.js create mode 100644 modules/zone/back/models/agency-mode.js diff --git a/front/core/components/autocomplete/index.js b/front/core/components/autocomplete/index.js index 30e984fc6b..b335d266f0 100755 --- a/front/core/components/autocomplete/index.js +++ b/front/core/components/autocomplete/index.js @@ -248,7 +248,8 @@ export default class Autocomplete extends Field { 'where', 'order', 'limit', - 'searchFunction' + 'searchFunction', + 'whereFunction' ]); } @@ -290,6 +291,7 @@ ngModule.vnComponent('vnAutocomplete', { limit: ' + ng-model="$ctrl.agencyModeId" + where="{warehouseFk: $ctrl.warehouseId}"> + vn-acl="productionBoss" + where-function="$ctrl.zoneWhere()"> {{::name}} - Max. {{::hour | date: 'HH:mm'}} h. diff --git a/modules/ticket/front/basic-data/step-one/index.js b/modules/ticket/front/basic-data/step-one/index.js index 45fd397ddf..0e18326aec 100644 --- a/modules/ticket/front/basic-data/step-one/index.js +++ b/modules/ticket/front/basic-data/step-one/index.js @@ -56,12 +56,14 @@ class Controller extends Component { set warehouseId(value) { if (value != this.ticket.warehouseFk) { this.ticket.warehouseFk = value; - this.getShipped({ + this.ticket.agencyModeFk = null; + this.ticket.zoneFk = null; + /* this.getShipped({ landed: this.ticket.landed, addressFk: this.ticket.addressFk, agencyModeFk: this.ticket.agencyModeFk, warehouseFk: value - }); + }); */ } } @@ -241,6 +243,12 @@ class Controller extends Component { || !this.ticket.companyFk || !this.ticket.shipped || !this.ticket.landed || !this.ticket.zoneFk; } + + zoneWhere() { + if (this.agencyModeId) + return {agencyModeFk: this.agencyModeId}; + return {}; + } } ngModule.vnComponent('vnTicketBasicDataStepOne', { diff --git a/modules/zone/back/methods/agency-mode/byWarehouse.js b/modules/zone/back/methods/agency-mode/byWarehouse.js new file mode 100644 index 0000000000..c89217eef0 --- /dev/null +++ b/modules/zone/back/methods/agency-mode/byWarehouse.js @@ -0,0 +1,38 @@ +const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; +const mergeFilters = require('vn-loopback/util/filter').mergeFilters; + +module.exports = Self => { + Self.remoteMethod('byWarehouse', { + description: 'Returns a list of agencies from a warehouse', + accepts: [{ + arg: 'filter', + type: 'Object', + description: `Filter defining where, order, offset, and limit - must be a JSON-encoded string` + }], + returns: { + type: ['object'], + root: true + }, + http: { + path: `/byWarehouse`, + verb: 'GET' + } + }); + + Self.byWarehouse = async filter => { + const conn = Self.dataSource.connector; + const where = {isActive: true}; + filter = mergeFilters(filter, {where}); + + let stmt = new ParameterizedSQL( + `SELECT id, name + FROM ( + SELECT DISTINCT am.id, am.name, am.isActive, zw.warehouseFk + FROM zoneWarehouse zw + JOIN zone z ON z.id = zw.zoneFk + JOIN agencyMode am ON am.id = z.agencyModeFk) am`); + stmt.merge(conn.makeSuffix(filter)); + + return conn.executeStmt(stmt); + }; +}; diff --git a/modules/zone/back/models/agency-mode.js b/modules/zone/back/models/agency-mode.js new file mode 100644 index 0000000000..93658f471c --- /dev/null +++ b/modules/zone/back/models/agency-mode.js @@ -0,0 +1,3 @@ +module.exports = Self => { + require('../methods/agency-mode/byWarehouse')(Self); +}; From ae3d00bad198a9449c74fcbbb81905ed8d26c626 Mon Sep 17 00:00:00 2001 From: joan Date: Tue, 22 Sep 2020 07:38:20 +0200 Subject: [PATCH 2/5] Added new method --- .../front/basic-data/step-one/index.html | 2 +- .../ticket/front/basic-data/step-one/index.js | 10 +++- .../back/methods/zone/includingExpired.js | 60 +++++++++++++++++++ modules/zone/back/models/zone.js | 1 + 4 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 modules/zone/back/methods/zone/includingExpired.js diff --git a/modules/ticket/front/basic-data/step-one/index.html b/modules/ticket/front/basic-data/step-one/index.html index eb2fe95605..59435635ed 100644 --- a/modules/ticket/front/basic-data/step-one/index.html +++ b/modules/ticket/front/basic-data/step-one/index.html @@ -70,7 +70,7 @@ { + Self.remoteMethod('includingExpired', { + description: 'Returns a list of agencies from a warehouse', + accepts: [{ + arg: 'filter', + type: 'Object', + description: `Filter defining where, order, offset, and limit - must be a JSON-encoded string` + }], + returns: { + type: ['object'], + root: true + }, + http: { + path: `/includingExpired`, + verb: 'GET' + } + }); + + Self.includingExpired = async filter => { + const conn = Self.dataSource.connector; + const where = filter.where; + // filter = mergeFilters(filter, {where}); + const stmts = []; + let stmt; + + console.log(where); + + if (where.agencyModeFk) { + stmt = new ParameterizedSQL(`CALL vn.zone_getLanded(?, ?, ?, ?, ?)`, [ + where.shipped, + where.addressFk, + where.agencyModeFk, + where.warehouseFk, + true]); + stmts.push(stmt); + } + + stmt = new ParameterizedSQL( + `SELECT id, name, agencyModeFk + FROM vn.zone z`); + + if (where.agencyModeFk) + stmt.merge(`JOIN tmp.zoneGetLanded zgl ON zgl.zoneFk = z.id`); + + stmt.merge(conn.makePagination(filter)); + + let index; + if (stmts.length) + index = stmts.push(stmt) - 1; + else stmts.push(stmt); + + const sql = ParameterizedSQL.join(stmts, ';'); + const result = await conn.executeStmt(sql); + + return index ? result[index] : result; + }; +}; diff --git a/modules/zone/back/models/zone.js b/modules/zone/back/models/zone.js index b0f21c998d..0b1b9d106e 100644 --- a/modules/zone/back/models/zone.js +++ b/modules/zone/back/models/zone.js @@ -5,6 +5,7 @@ module.exports = Self => { require('../methods/zone/toggleIsIncluded')(Self); require('../methods/zone/getUpcomingDeliveries')(Self); require('../methods/zone/deleteZone')(Self); + require('../methods/zone/includingExpired')(Self); Self.validatesPresenceOf('agencyModeFk', { message: `Agency cannot be blank` From 5ec5979a3e1763002555477d439598e1deaea2b1 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 23 Sep 2020 11:21:25 +0200 Subject: [PATCH 3/5] Updated tests --- .../05-ticket/06_basic_data_steps.spec.js | 3 +- .../front/basic-data/step-one/index.html | 2 +- .../ticket/front/basic-data/step-one/index.js | 24 ++++++----- .../front/basic-data/step-one/index.spec.js | 39 ++++++++++++------ .../agency-mode/specs/byWarehouse.spec.js | 21 ++++++++++ modules/zone/back/methods/agency/getLanded.js | 17 ++++---- .../methods/agency/specs/getLanded.spec.js | 4 +- .../back/methods/zone/includingExpired.js | 27 +++++++++---- .../zone/specs/includingExpired.spec.js | 40 +++++++++++++++++++ 9 files changed, 135 insertions(+), 42 deletions(-) create mode 100644 modules/zone/back/methods/agency-mode/specs/byWarehouse.spec.js create mode 100644 modules/zone/back/methods/zone/specs/includingExpired.spec.js diff --git a/e2e/paths/05-ticket/06_basic_data_steps.spec.js b/e2e/paths/05-ticket/06_basic_data_steps.spec.js index 3191673a55..f9ad65a293 100644 --- a/e2e/paths/05-ticket/06_basic_data_steps.spec.js +++ b/e2e/paths/05-ticket/06_basic_data_steps.spec.js @@ -50,7 +50,7 @@ describe('Ticket Edit basic data path', () => { }); it(`should edit the ticket agency then check there are no zones for it`, async() => { - await page.autocompleteSearch(selectors.ticketBasicData.agency, 'Entanglement'); + await page.autocompleteSearch(selectors.ticketBasicData.agency, 'inhouse pickup'); await page.waitFor(1000); let emptyZone = await page .expectPropertyValue(selectors.ticketBasicData.zone, 'value', ''); @@ -59,6 +59,7 @@ describe('Ticket Edit basic data path', () => { }); it(`should edit the ticket zone then check the agency is for the new zone`, async() => { + await page.clearInput(selectors.ticketBasicData.agency); await page.autocompleteSearch(selectors.ticketBasicData.zone, 'Zone expensive A'); let zone = await page .waitToGetProperty(selectors.ticketBasicData.agency, 'value'); diff --git a/modules/ticket/front/basic-data/step-one/index.html b/modules/ticket/front/basic-data/step-one/index.html index 59435635ed..0e8d25b7ce 100644 --- a/modules/ticket/front/basic-data/step-one/index.html +++ b/modules/ticket/front/basic-data/step-one/index.html @@ -66,7 +66,7 @@ show-field="name" value-field="id" ng-model="$ctrl.agencyModeId" - where="{warehouseFk: $ctrl.warehouseId}"> + where-function="$ctrl.agencyModeWhere()"> { jest.spyOn(controller, 'getShipped'); controller.ticket.warehouseId = 1; controller.warehouseId = 2; - const landed = new Date(); - const expectedResult = { - landed: landed, - addressFk: 121, - agencyModeFk: 7, - warehouseFk: 2 - }; - controller.landed = landed; - expect(controller.getShipped).toHaveBeenCalledWith(expectedResult); expect(controller.ticket.warehouseFk).toEqual(2); }); }); @@ -125,7 +116,6 @@ describe('Ticket', () => { shipped: shipped, addressFk: 121, agencyModeFk: 7, - showExpiredZones: false, warehouseFk: 1 }; controller.shipped = shipped; @@ -176,8 +166,7 @@ describe('Ticket', () => { shipped: shipped, addressFk: 121, agencyModeFk: agencyModeId, - warehouseFk: 1, - showExpiredZones: false, + warehouseFk: 1 }; controller.ticket.shipped = shipped; controller.agencyModeId = 8; @@ -363,5 +352,31 @@ describe('Ticket', () => { expect(controller.landed).toEqual(landed); }); }); + + describe('zoneWhere() getter', () => { + it('should return an object containing filter properties', async() => { + const shipped = new Date(); + controller.ticket.shipped = shipped; + + const expectedResult = { + addressFk: 121, + agencyModeFk: 7, + shipped: shipped, + warehouseFk: 1 + }; + const result = controller.zoneWhere(); + + expect(result).toEqual(expect.objectContaining(expectedResult)); + }); + }); + + describe('agencyModeWhere() getter', () => { + it('should return an object containing the warehouseFk property', async() => { + const expectedResult = {warehouseFk: 1}; + const result = controller.agencyModeWhere(); + + expect(result).toEqual(expect.objectContaining(expectedResult)); + }); + }); }); }); diff --git a/modules/zone/back/methods/agency-mode/specs/byWarehouse.spec.js b/modules/zone/back/methods/agency-mode/specs/byWarehouse.spec.js new file mode 100644 index 0000000000..a2c2ca5924 --- /dev/null +++ b/modules/zone/back/methods/agency-mode/specs/byWarehouse.spec.js @@ -0,0 +1,21 @@ +const app = require('vn-loopback/server/server'); + +describe('AgencyMode byWarehhouse()', () => { + const warehouseId = 1; + it('should return all the agencies', async() => { + const where = {}; + const agencies = await app.models.AgencyMode.byWarehouse({where}); + + expect(agencies.length).toBeGreaterThan(10); + }); + + it('should return only the agencies for a warehouse', async() => { + const where = {warehouseFk: warehouseId}; + const agencies = await app.models.AgencyMode.byWarehouse({where}); + + const validWarehouse = agencies.every(agency => agency.warehouseFk = warehouseId); + + expect(agencies.length).toEqual(6); + expect(validWarehouse).toBeTruthy(); + }); +}); diff --git a/modules/zone/back/methods/agency/getLanded.js b/modules/zone/back/methods/agency/getLanded.js index ef68331e6c..27ac88327a 100644 --- a/modules/zone/back/methods/agency/getLanded.js +++ b/modules/zone/back/methods/agency/getLanded.js @@ -1,7 +1,7 @@ const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; module.exports = Self => { - Self.remoteMethod('getLanded', { + Self.remoteMethodCtx('getLanded', { description: 'Returns the first shipped and landed possible for params', accessType: 'READ', accepts: [{ @@ -23,11 +23,6 @@ module.exports = Self => { arg: 'warehouseFk', type: 'number', required: true - }, - { - arg: 'showExpiredZones', - type: 'boolean', - required: true }], returns: { type: 'object', @@ -39,7 +34,13 @@ module.exports = Self => { } }); - Self.getLanded = async(shipped, addressFk, agencyModeFk, warehouseFk, showExpiredZones) => { + Self.getLanded = async(ctx, shipped, addressFk, agencyModeFk, warehouseFk) => { + const userId = ctx.req.accessToken.userId; + const models = Self.app.models; + const isProductionBoss = await models.Account.hasRole(userId, 'productionBoss'); + let showExpired = false; + if (isProductionBoss) showExpired = true; + let stmts = []; stmts.push(new ParameterizedSQL( `CALL vn.zone_getLanded(?, ?, ?, ?, ?)`, [ @@ -47,7 +48,7 @@ module.exports = Self => { addressFk, agencyModeFk, warehouseFk, - showExpiredZones + showExpired ] )); diff --git a/modules/zone/back/methods/agency/specs/getLanded.spec.js b/modules/zone/back/methods/agency/specs/getLanded.spec.js index c24379530d..fee3bd608e 100644 --- a/modules/zone/back/methods/agency/specs/getLanded.spec.js +++ b/modules/zone/back/methods/agency/specs/getLanded.spec.js @@ -2,13 +2,13 @@ const app = require('vn-loopback/server/server'); describe('agency getLanded()', () => { it('should return a landing date', async() => { + const ctx = {req: {accessToken: {userId: 1}}}; const shipped = new Date(); shipped.setDate(shipped.getDate() + 1); const addressFk = 121; const agencyModeFk = 7; const warehouseFk = 1; - const showExpiredZones = true; - let result = await app.models.Agency.getLanded(shipped, addressFk, agencyModeFk, warehouseFk, showExpiredZones); + let result = await app.models.Agency.getLanded(ctx, shipped, addressFk, agencyModeFk, warehouseFk); expect(result.landed).toBeDefined(); }); diff --git a/modules/zone/back/methods/zone/includingExpired.js b/modules/zone/back/methods/zone/includingExpired.js index 14af42c26d..6428d5b887 100644 --- a/modules/zone/back/methods/zone/includingExpired.js +++ b/modules/zone/back/methods/zone/includingExpired.js @@ -2,7 +2,7 @@ const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; const mergeFilters = require('vn-loopback/util/filter').mergeFilters; module.exports = Self => { - Self.remoteMethod('includingExpired', { + Self.remoteMethodCtx('includingExpired', { description: 'Returns a list of agencies from a warehouse', accepts: [{ arg: 'filter', @@ -19,33 +19,44 @@ module.exports = Self => { } }); - Self.includingExpired = async filter => { + Self.includingExpired = async(ctx, filter) => { + const userId = ctx.req.accessToken.userId; const conn = Self.dataSource.connector; + const models = Self.app.models; const where = filter.where; - // filter = mergeFilters(filter, {where}); + const stmts = []; let stmt; - console.log(where); + const filterByAvailability = where.shipped && where.addressFk + && where.agencyModeFk && where.warehouseFk; + + if (filterByAvailability) { + const isProductionBoss = await models.Account.hasRole(userId, 'productionBoss'); + let showExpired = false; + if (isProductionBoss) showExpired = true; - if (where.agencyModeFk) { stmt = new ParameterizedSQL(`CALL vn.zone_getLanded(?, ?, ?, ?, ?)`, [ where.shipped, where.addressFk, where.agencyModeFk, where.warehouseFk, - true]); + showExpired]); stmts.push(stmt); } + delete where.shipped; + delete where.addressFk; + delete where.warehouseFk; + stmt = new ParameterizedSQL( `SELECT id, name, agencyModeFk FROM vn.zone z`); - if (where.agencyModeFk) + if (filterByAvailability) stmt.merge(`JOIN tmp.zoneGetLanded zgl ON zgl.zoneFk = z.id`); - stmt.merge(conn.makePagination(filter)); + stmt.merge(conn.makeWhere(filter.where)); let index; if (stmts.length) diff --git a/modules/zone/back/methods/zone/specs/includingExpired.spec.js b/modules/zone/back/methods/zone/specs/includingExpired.spec.js new file mode 100644 index 0000000000..ebda578689 --- /dev/null +++ b/modules/zone/back/methods/zone/specs/includingExpired.spec.js @@ -0,0 +1,40 @@ +const app = require('vn-loopback/server/server'); + +describe('zone includingExpired()', () => { + const inhousePickupId = 1; + const addressId = 101; + const warehouseId = 1; + + it('should return an array containing all zones', async() => { + const ctx = {req: {accessToken: {userId: 1}}}; + const where = {}; + const result = await app.models.Zone.includingExpired(ctx, {where}); + + expect(result.length).toBeGreaterThan(2); + }); + + it('should return an array containing zones from the agencyMode "Inhouse pickup"', async() => { + const ctx = {req: {accessToken: {userId: 1}}}; + const where = {agencyModeFk: inhousePickupId}; + const result = await app.models.Zone.includingExpired(ctx, {where}); + + const validAgency = result.every(zone => zone.agencyModeFk = inhousePickupId); + + expect(result.length).toEqual(3); + expect(validAgency).toBeTruthy(); + }); + + it('should return an array containing available zones', async() => { + const ctx = {req: {accessToken: {userId: 1}}}; + const where = { + shipped: new Date(), + addressFk: addressId, + agencyModeFk: inhousePickupId, + warehouseFk: warehouseId + }; + const result = await app.models.Zone.includingExpired(ctx, {where}); + const firstZone = result[0]; + + expect(firstZone.name).toEqual('Zone pickup A'); + }); +}); From a8589d694554632fa5621ef867092ac6d440395e Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 23 Sep 2020 14:13:44 +0200 Subject: [PATCH 4/5] Autocomplete warehouse on agency selection --- .../front/basic-data/step-one/index.html | 18 ++++++++++++++---- .../ticket/front/basic-data/step-one/index.js | 3 +++ .../back/methods/agency-mode/byWarehouse.js | 2 +- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/modules/ticket/front/basic-data/step-one/index.html b/modules/ticket/front/basic-data/step-one/index.html index 0e8d25b7ce..98d92e7e24 100644 --- a/modules/ticket/front/basic-data/step-one/index.html +++ b/modules/ticket/front/basic-data/step-one/index.html @@ -7,8 +7,10 @@
- - - diff --git a/modules/ticket/front/basic-data/step-one/index.js b/modules/ticket/front/basic-data/step-one/index.js index d7dbb8cd10..e7eb305831 100644 --- a/modules/ticket/front/basic-data/step-one/index.js +++ b/modules/ticket/front/basic-data/step-one/index.js @@ -99,6 +99,9 @@ class Controller extends Component { if (!value) return; + const agencyMode = this.$.agencyMode.selection; + this.ticket.warehouseFk = agencyMode.warehouseFk; + this.getLanded({ shipped: this.ticket.shipped, addressFk: this.ticket.addressFk, diff --git a/modules/zone/back/methods/agency-mode/byWarehouse.js b/modules/zone/back/methods/agency-mode/byWarehouse.js index c89217eef0..f336f5ed2d 100644 --- a/modules/zone/back/methods/agency-mode/byWarehouse.js +++ b/modules/zone/back/methods/agency-mode/byWarehouse.js @@ -25,7 +25,7 @@ module.exports = Self => { filter = mergeFilters(filter, {where}); let stmt = new ParameterizedSQL( - `SELECT id, name + `SELECT id, name, warehouseFk FROM ( SELECT DISTINCT am.id, am.name, am.isActive, zw.warehouseFk FROM zoneWarehouse zw From 75ac6ad8d3de1140b02a83e42688dac2cc76994d Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 23 Sep 2020 14:20:41 +0200 Subject: [PATCH 5/5] Updated unit test --- modules/ticket/front/basic-data/step-one/index.spec.js | 1 + 1 file changed, 1 insertion(+) 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 eea22b73ba..bd88b88ac4 100644 --- a/modules/ticket/front/basic-data/step-one/index.spec.js +++ b/modules/ticket/front/basic-data/step-one/index.spec.js @@ -160,6 +160,7 @@ describe('Ticket', () => { describe('agencyModeId() setter', () => { it('should set agencyModeId property and call getLanded() method', () => { jest.spyOn(controller, 'getLanded'); + controller.$.agencyMode = {selection: {warehouseFk: 1}}; const shipped = new Date(); const agencyModeId = 8; const expectedResult = {