From 19887bdd16108e8d89d5b6a8340429224f757833 Mon Sep 17 00:00:00 2001 From: vicent Date: Thu, 24 Feb 2022 14:52:32 +0100 Subject: [PATCH] feat: add section autonomous --- .../10420-valentines/00-aclAgencyTerm.sql | 2 + db/dump/fixtures.sql | 23 +++ .../route/back/methods/agency-term/filter.js | 143 +++++++++++++++++ modules/route/back/model-config.json | 3 + modules/route/back/models/agency-term.js | 3 + modules/route/back/models/agency-term.json | 37 +++++ modules/route/front/agency-term/index.html | 149 ++++++++++++++++++ modules/route/front/agency-term/index.js | 121 ++++++++++++++ modules/route/front/agency-term/index.spec.js | 30 ++++ modules/route/front/agency-term/locale/es.yml | 5 + modules/route/front/agency-term/preview.svg | 11 ++ modules/route/front/agency-term/style.scss | 32 ++++ modules/route/front/index.js | 1 + modules/route/front/routes.json | 9 +- 14 files changed, 568 insertions(+), 1 deletion(-) create mode 100644 db/changes/10420-valentines/00-aclAgencyTerm.sql create mode 100644 modules/route/back/methods/agency-term/filter.js create mode 100644 modules/route/back/models/agency-term.js create mode 100644 modules/route/back/models/agency-term.json create mode 100644 modules/route/front/agency-term/index.html create mode 100644 modules/route/front/agency-term/index.js create mode 100644 modules/route/front/agency-term/index.spec.js create mode 100644 modules/route/front/agency-term/locale/es.yml create mode 100644 modules/route/front/agency-term/preview.svg create mode 100644 modules/route/front/agency-term/style.scss diff --git a/db/changes/10420-valentines/00-aclAgencyTerm.sql b/db/changes/10420-valentines/00-aclAgencyTerm.sql new file mode 100644 index 0000000000..d3e11e53e1 --- /dev/null +++ b/db/changes/10420-valentines/00-aclAgencyTerm.sql @@ -0,0 +1,2 @@ +INSERT INTO salix.ACL (model,property,accessType,principalId) + VALUES ('AgencyTerm','*','*','administrative'); diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 07eaf23fdd..35013b35b3 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -2443,3 +2443,26 @@ INSERT INTO `bs`.`defaulter` (`clientFk`, `amount`, `created`, `defaulterSinced` (1103, 500, CURDATE(), CURDATE()), (1107, 500, CURDATE(), CURDATE()), (1109, 500, CURDATE(), CURDATE()); + +INSERT INTO `vn`.`agencyTerm` (`agencyFk`, `minimumPackages`, `kmPrice`, `packagePrice`, `routePrice`, `minimumKm`, `minimumM3`, `m3Price`) + VALUES + (1, 0, 0.00, 0.00, NULL, 0, 0.00, 0), + (3, 0, 0.00, 3.05, NULL, 0, 0.00, 0), + (2, 60, 0.00, 0.00, NULL, 0, 5.00, 33); + +UPDATE `vn`.`agency` +SET `supplierFk`=1 +WHERE `id`=1; +UPDATE `vn`.`agency` +SET `supplierFk`=1 +WHERE `id`=2; +UPDATE `vn`.`agency` +SET `supplierFk`=2 +WHERE `id`=3; + +UPDATE `vn`.`route` +SET `invoiceInFk`=1 +WHERE `id`=1; +UPDATE `vn`.`route` +SET `invoiceInFk`=2 +WHERE `id`=2; \ No newline at end of file diff --git a/modules/route/back/methods/agency-term/filter.js b/modules/route/back/methods/agency-term/filter.js new file mode 100644 index 0000000000..94ed7fc91d --- /dev/null +++ b/modules/route/back/methods/agency-term/filter.js @@ -0,0 +1,143 @@ + +const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; +const buildFilter = require('vn-loopback/util/filter').buildFilter; +const mergeFilters = require('vn-loopback/util/filter').mergeFilters; + +module.exports = Self => { + Self.remoteMethodCtx('filter', { + description: 'Find all instances of the model matched by filter from the data source.', + accessType: 'READ', + accepts: [ + { + arg: 'filter', + type: 'object', + description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string', + http: {source: 'query'} + }, + { + arg: 'search', + type: 'string', + description: 'Searchs the route by id', + http: {source: 'query'} + }, + { + arg: 'agencyModeFk', + type: 'integer', + description: 'The agencyMode id', + http: {source: 'query'} + }, + { + arg: 'to', + type: 'date', + description: 'The to date filter', + http: {source: 'query'} + }, + { + arg: 'from', + type: 'date', + description: 'The to date filter', + http: {source: 'query'} + }, + { + arg: 'vehicleFk', + type: 'integer', + description: 'The vehicle id', + http: {source: 'query'} + }, + { + arg: 'm3', + type: 'number', + description: 'The m3 filter', + http: {source: 'query'} + }, + { + arg: 'warehouseFk', + type: 'number', + description: 'The warehouse filter', + http: {source: 'query'} + }, + { + arg: 'description', + type: 'string', + description: 'The description filter', + http: {source: 'query'} + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: `/filter`, + verb: 'GET' + } + }); + + Self.filter = async(ctx, filter) => { + let conn = Self.dataSource.connector; + + let where = buildFilter(ctx.args, (param, value) => { + switch (param) { + case 'search': + return {'r.id': value}; + case 'from': + return {'r.created': {gte: value}}; + case 'to': + return {'r.created': {lte: value}}; + case 'm3': + return {'r.m3': value}; + case 'description': + return {'r.description': {like: `%${value}%`}}; + case 'warehouseFk': + param = `v.${param}`; + return {[param]: value}; + case 'vehicleFk': + case 'agencyModeFk': + param = `r.${param}`; + return {[param]: value}; + } + }); + + filter = mergeFilters(ctx.args.filter, {where}); + + let stmts = []; + let stmt; + + stmt = new ParameterizedSQL( + `SELECT + r.id routeFk, + r.created, + r.agencyModeFk, + am.name agencyModeName, + am.agencyFk, + a.name agencyAgreement, + SUM(t.packages) packages, + r.m3, + r.kmEnd - r.kmStart kmTotal, + CAST(IFNULL(ate.routePrice, + (ate.kmPrice * (GREATEST(r.kmEnd - r.kmStart , ate.minimumKm)) + + GREATEST(r.m3 , ate.minimumM3) * ate.m3Price) + + ate.packagePrice * SUM(t.packages) ) + AS DECIMAL(10,2)) price, + r.invoiceInFk, + a.supplierFk, + s.name supplierName + FROM vn.route r + LEFT JOIN vn.agencyMode am ON r.agencyModeFk = am.id + LEFT JOIN vn.agency a ON am.agencyFk = a.id + LEFT JOIN vn.ticket t ON t.routeFk = r.id + LEFT JOIN vn.agencyTerm ate ON ate.agencyFk = a.id + LEFT JOIN vn.supplier s ON s.id = a.supplierFk + WHERE r.created > DATE_ADD(CURDATE(), INTERVAL -2 MONTH) AND a.supplierFk IS NOT NULL + GROUP BY r.id;` + ); + + stmt.merge(conn.makeSuffix(filter)); + let agencyTerm = stmts.push(stmt) - 1; + + let sql = ParameterizedSQL.join(stmts, ';'); + let result = await conn.executeStmt(sql); + return agencyTerm === 0 ? result : result[agencyTerm]; + }; +}; + diff --git a/modules/route/back/model-config.json b/modules/route/back/model-config.json index 0dfe1d02aa..5d5c5cc183 100644 --- a/modules/route/back/model-config.json +++ b/modules/route/back/model-config.json @@ -1,4 +1,7 @@ { + "AgencyTerm": { + "dataSource": "vn" + }, "Route": { "dataSource": "vn" }, diff --git a/modules/route/back/models/agency-term.js b/modules/route/back/models/agency-term.js new file mode 100644 index 0000000000..14fe76d281 --- /dev/null +++ b/modules/route/back/models/agency-term.js @@ -0,0 +1,3 @@ +module.exports = Self => { + require('../methods/agency-term/filter')(Self); +}; diff --git a/modules/route/back/models/agency-term.json b/modules/route/back/models/agency-term.json new file mode 100644 index 0000000000..29f70951b6 --- /dev/null +++ b/modules/route/back/models/agency-term.json @@ -0,0 +1,37 @@ +{ + "name": "AgencyTerm", + "base": "VnModel", + "options": { + "mysql": { + "table": "agencyTerm" + } + }, + "properties": { + "agencyFk": { + "type": "Number", + "id": true, + "description": "Identifier" + }, + "minimumPackages": { + "type": "Number" + }, + "kmPrice": { + "type": "Number" + }, + "packagePrice": { + "type": "Number" + }, + "routePrice": { + "type": "Number" + }, + "minimumKm": { + "type": "Number" + }, + "minimumM3": { + "type": "Number" + }, + "m3Price": { + "type": "Number" + } + } +} diff --git a/modules/route/front/agency-term/index.html b/modules/route/front/agency-term/index.html new file mode 100644 index 0000000000..6ccd0cb56d --- /dev/null +++ b/modules/route/front/agency-term/index.html @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Id + + Date + + Agency route + + Agency Agreement + + Packages + + M3 + + Km + + Price + + Received + + Autonomous +
+ + + + + {{::agencyTerm.routeFk}} + + {{::agencyTerm.created | date:'dd/MM/yyyy'}}{{::agencyTerm.agencyModeName | dashIfEmpty}}{{::agencyTerm.agencyAgreement | dashIfEmpty}}{{::agencyTerm.packages | dashIfEmpty}}{{::agencyTerm.m3 | dashIfEmpty}}{{::agencyTerm.kmTotal | dashIfEmpty}}{{::agencyTerm.price | dashIfEmpty}} + + {{::agencyTerm.invoiceInFk}} + + + + {{::agencyTerm.supplierName}} + + + + +
+
+
+
+ + + + + + + + + + + + + + + + + Filter by selection + + + Exclude selection + + + Remove filter + + + Remove all filters + + + \ No newline at end of file diff --git a/modules/route/front/agency-term/index.js b/modules/route/front/agency-term/index.js new file mode 100644 index 0000000000..4f80ffc606 --- /dev/null +++ b/modules/route/front/agency-term/index.js @@ -0,0 +1,121 @@ +import ngModule from '../module'; +import Section from 'salix/components/section'; +import './style.scss'; + +class Controller extends Section { + constructor($element, $) { + super($element, $); + + this.smartTableOptions = { + activeButtons: { + search: false, + shownColumns: false, + }, + columns: [ + { + field: 'agencyFk', + autocomplete: { + url: 'ItemCategories', + valueField: 'name', + } + }, + { + field: 'origin', + autocomplete: { + url: 'Origins', + showField: 'code', + valueField: 'code' + } + }, + { + field: 'typeFk', + autocomplete: { + url: 'ItemTypes', + } + }, + { + field: 'intrastat', + autocomplete: { + url: 'Intrastats', + showField: 'description', + valueField: 'description' + } + }, + { + field: 'buyerFk', + autocomplete: { + url: 'Workers/activeWithRole', + where: `{role: {inq: ['logistic', 'buyer']}}`, + searchFunction: '{firstName: $search}', + showField: 'nickname', + valueField: 'id', + } + }, + { + field: 'active', + searchable: false + }, + { + field: 'landed', + searchable: false + }, + ] + }; + } + + exprBuilder(param, value) { + switch (param) { + case 'category': + return {'ic.name': value}; + case 'buyerFk': + return {'it.workerFk': value}; + case 'grouping': + return {'b.grouping': value}; + case 'packing': + return {'b.packing': value}; + case 'origin': + return {'ori.code': value}; + case 'typeFk': + return {'i.typeFk': value}; + case 'intrastat': + return {'intr.description': value}; + case 'name': + return {'i.name': {like: `%${value}%`}}; + case 'producer': + return {'pr.name': {like: `%${value}%`}}; + case 'id': + case 'size': + case 'subname': + case 'isActive': + case 'density': + case 'stemMultiplier': + case 'stems': + return {[`i.${param}`]: value}; + } + } + + get checked() { + const routes = this.$.model.data || []; + const checkedRoutes = []; + for (let route of routes) { + if (route.checked) + checkedRoutes.push(route); + } + + return checkedRoutes; + } + + get totalChecked() { + return this.checked.length; + } + + preview(route) { + this.routeSelected = route; + this.$.summary.show(); + } +} + +ngModule.vnComponent('vnAgencyTerm', { + template: require('./index.html'), + controller: Controller +}); diff --git a/modules/route/front/agency-term/index.spec.js b/modules/route/front/agency-term/index.spec.js new file mode 100644 index 0000000000..18abde5810 --- /dev/null +++ b/modules/route/front/agency-term/index.spec.js @@ -0,0 +1,30 @@ +import './index.js'; + +describe('Item', () => { + describe('Component vnItemIndex', () => { + let controller; + let $httpBackend; + let $scope; + + beforeEach(ngModule('item')); + + beforeEach(inject(($componentController, _$httpBackend_, $rootScope) => { + $httpBackend = _$httpBackend_; + $scope = $rootScope.$new(); + const $element = angular.element(''); + controller = $componentController('vnItemIndex', {$element, $scope}); + })); + + describe('onCloneAccept()', () => { + it('should perform a post query and then call go() then update itemSelected in the controller', () => { + jest.spyOn(controller.$state, 'go'); + + $httpBackend.expectRoute('POST', `Items/:id/clone`).respond({id: 99}); + controller.onCloneAccept(1); + $httpBackend.flush(); + + expect(controller.$state.go).toHaveBeenCalledWith('item.card.tags', {id: 99}); + }); + }); + }); +}); diff --git a/modules/route/front/agency-term/locale/es.yml b/modules/route/front/agency-term/locale/es.yml new file mode 100644 index 0000000000..0e766f5aa1 --- /dev/null +++ b/modules/route/front/agency-term/locale/es.yml @@ -0,0 +1,5 @@ +picture: Foto +Buy requests: Peticiones de compra +Agency route: Agencia ruta +Agency Agreement: Agencia acuerdo +Autonomous: Autónomo \ No newline at end of file diff --git a/modules/route/front/agency-term/preview.svg b/modules/route/front/agency-term/preview.svg new file mode 100644 index 0000000000..5d56b5f346 --- /dev/null +++ b/modules/route/front/agency-term/preview.svg @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/modules/route/front/agency-term/style.scss b/modules/route/front/agency-term/style.scss new file mode 100644 index 0000000000..eaa1a16ed4 --- /dev/null +++ b/modules/route/front/agency-term/style.scss @@ -0,0 +1,32 @@ +@import "variables"; + +vn-item-product { + display: block; + + .id { + background-color: $color-main; + color: $color-font-dark; + margin-bottom: 0; + } + .image { + height: 112px; + width: 112px; + + & > img { + max-height: 100%; + max-width: 100%; + border-radius: 3px; + } + } + vn-label-value:first-of-type section{ + margin-top: 9px; + } +} + +table { + img { + border-radius: 50%; + width: 50px; + height: 50px; + } +} \ No newline at end of file diff --git a/modules/route/front/index.js b/modules/route/front/index.js index 7c2a17483b..206c97953e 100644 --- a/modules/route/front/index.js +++ b/modules/route/front/index.js @@ -11,3 +11,4 @@ import './create'; import './basic-data'; import './log'; import './tickets'; +import './agency-term'; diff --git a/modules/route/front/routes.json b/modules/route/front/routes.json index beb444abc5..307d0e9410 100644 --- a/modules/route/front/routes.json +++ b/modules/route/front/routes.json @@ -6,7 +6,8 @@ "dependencies": ["client", "worker", "ticket"], "menus": { "main": [ - {"state": "route.index", "icon": "icon-delivery"} + {"state": "route.index", "icon": "icon-delivery"}, + {"state": "route.agencyTerm", "icon": "icon-delivery"} ], "card": [ {"state": "route.card.basicData", "icon": "settings"}, @@ -37,6 +38,12 @@ "state": "route.card", "abstract": true, "component": "vn-route-card" + }, { + "url" : "/agency-term?q", + "state": "route.agencyTerm", + "component": "vn-agency-term", + "description": "Autonomous", + "acl": ["administrative"] }, { "url": "/summary", "state": "route.card.summary",