diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 17f90bb26..edb937e5f 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -2453,10 +2453,22 @@ INSERT INTO `bs`.`defaulter` (`clientFk`, `amount`, `created`, `defaulterSinced` (1107, 500, CURDATE(), CURDATE()), (1109, 500, CURDATE(), CURDATE()); +INSERT INTO `bs`.`salesPerson` (`workerFk`, `year`, `month`, `portfolioWeight`) + VALUES + (18, YEAR(CURDATE()), MONTH(CURDATE()), 807.23), + (19, YEAR(CURDATE()), MONTH(CURDATE()), 34.40); + +INSERT INTO `bs`.`sale` (`saleFk`, `amount`, `dated`, `typeFk`, `clientFk`) + VALUES + (1, 501.95, CURDATE(), 2, 1101), + (2, 70.7, CURDATE(), 2, 1101), + (3, 200.78, CURDATE(), 2, 1101), + (4, 33.8, CURDATE(), 1, 1101), + (30, 34.4, CURDATE(), 1, 1108); INSERT INTO `vn`.`docuware` (`code`, `fileCabinetName`, `dialogName` , `find`) VALUES ('deliveryClientTest', 'deliveryClientTest', 'findTest', 'word'); INSERT INTO `vn`.`docuwareConfig` (`url`) VALUES - ('https://verdnatura.docuware.cloud/docuware/platform'); \ No newline at end of file + ('https://verdnatura.docuware.cloud/docuware/platform'); diff --git a/front/salix/components/descriptor/index.js b/front/salix/components/descriptor/index.js index 85baa7f02..470f0409d 100644 --- a/front/salix/components/descriptor/index.js +++ b/front/salix/components/descriptor/index.js @@ -97,7 +97,8 @@ ngModule.vnComponent('vnDescriptor', { btnOne: '?btnOne', btnTwo: '?btnTwo', btnThree: '?btnThree', - btnFour: '?btnFour' + btnFour: '?btnFour', + btnFive: '?btnFive' } }); diff --git a/front/salix/components/descriptor/style.scss b/front/salix/components/descriptor/style.scss index d15c60938..a87b3f451 100644 --- a/front/salix/components/descriptor/style.scss +++ b/front/salix/components/descriptor/style.scss @@ -104,7 +104,7 @@ vn-descriptor-content { align-items: center; justify-content: center; padding: 0 $spacing-sm; - margin: 0 $spacing-sm; + margin: 0 $spacing-xs; & > vn-icon { font-size: 1.75rem; diff --git a/modules/client/back/methods/client/getCard.js b/modules/client/back/methods/client/getCard.js index c3ce00bf3..34fba0984 100644 --- a/modules/client/back/methods/client/getCard.js +++ b/modules/client/back/methods/client/getCard.js @@ -64,6 +64,12 @@ module.exports = function(Self) { scope: { fields: ['id', 'name', 'active'] } + }, + { + relation: 'supplier', + scope: { + fields: ['id', 'nif'] + } } ] }, myOptions); diff --git a/modules/client/back/methods/client/specs/updatePortfolio.spec.js b/modules/client/back/methods/client/specs/updatePortfolio.spec.js new file mode 100644 index 000000000..0794fbf92 --- /dev/null +++ b/modules/client/back/methods/client/specs/updatePortfolio.spec.js @@ -0,0 +1,28 @@ +const models = require('vn-loopback/server/server').models; + +xdescribe('Client updatePortfolio', () => { + const salesPersonId = 18; + const clientId = 1108; + it('should update the portfolioWeight', async() => { + const tx = await models.Client.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const expectedResult = 841.63; + + await models.Client.rawSql(`UPDATE vn.client SET salesPersonFk = ${salesPersonId} WHERE id = ${clientId}; `); + + await models.Client.updatePortfolio(); + + let [vendedores] = await models.Client.rawSql(`SELECT portfolioWeight FROM bs.vendedores WHERE Id_Trabajador = ${salesPersonId}; `, null, options); + + expect(vendedores.portfolioWeight).toEqual(expectedResult); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); +}); diff --git a/modules/client/back/methods/client/updatePortfolio.js b/modules/client/back/methods/client/updatePortfolio.js new file mode 100644 index 000000000..3d522f6c8 --- /dev/null +++ b/modules/client/back/methods/client/updatePortfolio.js @@ -0,0 +1,20 @@ +module.exports = function(Self) { + Self.remoteMethodCtx('updatePortfolio', { + description: 'Update salesPeson potfolio weight', + accessType: 'READ', + accepts: [], + returns: { + type: 'Object', + root: true + }, + http: { + path: `/updatePortfolio`, + verb: 'GET' + } + }); + + Self.updatePortfolio = async() => { + query = `CALL bs.salesPerson_updatePortfolio()`; + return await Self.rawSql(query); + }; +}; diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js index e842c3ea1..9ec45f58d 100644 --- a/modules/client/back/models/client.js +++ b/modules/client/back/models/client.js @@ -29,6 +29,7 @@ module.exports = Self => { require('../methods/client/updateAddress')(Self); require('../methods/client/consumption')(Self); require('../methods/client/createReceipt')(Self); + require('../methods/client/updatePortfolio')(Self); // Validations diff --git a/modules/client/back/models/client.json b/modules/client/back/models/client.json index d6a98d83c..6404cfba0 100644 --- a/modules/client/back/models/client.json +++ b/modules/client/back/models/client.json @@ -228,7 +228,13 @@ "type": "belongsTo", "model": "Client", "foreignKey": "transferorFk" - } + }, + "supplier": { + "type": "belongsTo", + "model": "Supplier", + "foreignKey": "fi", + "primaryKey": "nif" + } }, "scopes": { "isActive": { diff --git a/modules/client/front/basic-data/index.html b/modules/client/front/basic-data/index.html index a76b448f2..a5c866979 100644 --- a/modules/client/front/basic-data/index.html +++ b/modules/client/front/basic-data/index.html @@ -10,7 +10,7 @@ url="ContactChannels" data="contactChannels"> -
+ { + const query = `Clients/updatePortfolio`; + this.$http.get(query); + }); + } } ngModule.vnComponent('vnClientBasicData', { diff --git a/modules/client/front/descriptor/index.html b/modules/client/front/descriptor/index.html index 6ae1f690e..e75246ebe 100644 --- a/modules/client/front/descriptor/index.html +++ b/modules/client/front/descriptor/index.html @@ -101,6 +101,14 @@ icon="face"> +
+ + +
diff --git a/modules/order/back/methods/order/specs/filter.spec.js b/modules/order/back/methods/order/specs/filter.spec.js index 53b666c10..68de7fe04 100644 --- a/modules/order/back/methods/order/specs/filter.spec.js +++ b/modules/order/back/methods/order/specs/filter.spec.js @@ -53,11 +53,11 @@ describe('order filter()', () => { try { const options = {transaction: tx}; - const filter = {where: {'o.confirmed': false, 'c.salesPersonFk': 18}}; + const filter = {where: {'o.confirmed': false, 'c.salesPersonFk': 9}}; const result = await models.Order.filter(myCtx, filter, options); - expect(result.length).toEqual(9); - expect(result[0].id).toEqual(7); + expect(result.length).toEqual(4); + expect(result[0].id).toEqual(19); await tx.rollback(); } catch (e) { diff --git a/modules/route/front/index.js b/modules/route/front/index.js index 7c2a17483..10ccb0634 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 './ticket-popup'; diff --git a/modules/route/front/index/index.html b/modules/route/front/index/index.html index 5a503b149..6d4bb202d 100644 --- a/modules/route/front/index/index.html +++ b/modules/route/front/index/index.html @@ -48,6 +48,11 @@ {{::route.m3 | dashIfEmpty}} {{::route.description | dashIfEmpty}} + + + + + + + + +
diff --git a/modules/route/front/index/index.js b/modules/route/front/index/index.js index b94acb55a..69c4ee99a 100644 --- a/modules/route/front/index/index.js +++ b/modules/route/front/index/index.js @@ -13,6 +13,11 @@ export default class Controller extends Section { this.$.summary.show(); } + showTicketPopup(route) { + this.routeSelected = route; + this.$.ticketPopup.show(); + } + get checked() { const rows = this.$.model.data || []; const checkedRows = []; diff --git a/modules/route/front/ticket-popup/index.html b/modules/route/front/ticket-popup/index.html new file mode 100644 index 000000000..33684a433 --- /dev/null +++ b/modules/route/front/ticket-popup/index.html @@ -0,0 +1,79 @@ + + + + Tickets to add +
+ +
+
+
+ + + + + + + + + + + + Ticket + Client + Province + + + Population + + + PC + Address + Warehouse + + + + + + + + + + + {{::ticket.id}} + + + + + {{::ticket.nickname}} + + + {{::ticket.address.province.name}} + {{::ticket.address.city}} + {{::ticket.address.postalCode}} + {{::ticket.address.street}} + + {{::ticket.zone.name}} + + + + + + + + + + diff --git a/modules/route/front/ticket-popup/index.js b/modules/route/front/ticket-popup/index.js new file mode 100644 index 000000000..8fd7b5d71 --- /dev/null +++ b/modules/route/front/ticket-popup/index.js @@ -0,0 +1,80 @@ +import ngModule from '../module'; +import Dialog from 'core/components/dialog'; +import './style.scss'; + +class Controller extends Dialog { + constructor($element, $, $transclude) { + super($element, $, $transclude); + } + + getSelectedTickets(tickets) { + const selectedTickets = []; + + if (tickets) { + for (let i = 0; i < tickets.length; i++) { + if (tickets[i].checked) + selectedTickets.push(tickets[i]); + } + } + return selectedTickets; + } + + updateVolume() { + let url = `Routes/${this.route.id}/updateVolume`; + this.$http.post(url).then(() => { + this.$.model.refresh(); + if (this.parentReload) + this.parentReload(); + }); + } + + setTicketsRoute() { + const tickets = this.getSelectedTickets(this.possibleTickets); + if (tickets.length === 0) return; + + const updates = []; + + for (let ticket of tickets) { + delete ticket.checked; + const update = { + where: {id: ticket.id}, + data: {routeFk: this.route.id} + }; + + updates.push(update); + } + + const data = {creates: [], updates: updates, deletes: []}; + return this.$http.post(`Tickets/crud`, data) + .then(() => { + this.vnApp.showSuccess(this.$t('Data saved!')); + this.updateVolume(); + this.hide(); + }); + } + + unlinkZone(ticket) { + const params = { + agencyModeId: this.route.agencyModeFk, + zoneId: ticket.zoneFk, + }; + + const query = `Routes/unlink`; + this.$http.post(query, params).then(() => { + this.vnApp.showSuccess(this.$t('Data saved!')); + this.$.model.refresh(); + this.hide(); + }); + } +} +Controller.$inject = ['$element', '$scope', '$transclude']; + +ngModule.vnComponent('vnRouteTicketPopup', { + slotTemplate: require('./index.html'), + controller: Controller, + bindings: { + route: '<', + model: ' { + let controller; + let $httpBackend; + let $scope; + + beforeEach(ngModule('route')); + + beforeEach(inject(($componentController, $rootScope, _$httpBackend_) => { + $httpBackend = _$httpBackend_; + $scope = $rootScope.$new(); + const $element = angular.element(''); + const $transclude = { + $$boundTransclude: { + $$slots: [] + } + }; + controller = $componentController('vnRouteTicketPopup', {$element, $scope, $transclude}); + controller.route = {id: 1}; + controller.$.model = { + refresh: () => {}, + remove: () => {} + }; + controller.card = {reload: () => {}}; + })); + + describe('unlink()', () => { + it('should call the route unlink endpoint with the agency and zone ids', () => { + controller.$.model = {refresh: jest.fn()}; + jest.spyOn(controller.vnApp, 'showSuccess'); + jest.spyOn(controller, 'hide'); + + controller.route = { + agencyModeFk: 1 + }; + + const ticket = { + zoneFk: 2, + }; + const params = { + agencyModeId: controller.route.agencyModeFk, + zoneId: ticket.zoneFk, + }; + + $httpBackend.expectPOST(`Routes/unlink`, params).respond('ok'); + controller.unlinkZone(ticket); + $httpBackend.flush(); + + expect(controller.vnApp.showSuccess).toHaveBeenCalled(); + expect(controller.hide).toHaveBeenCalled(); + expect(controller.$.model.refresh).toHaveBeenCalledWith(); + }); + }); + + describe('setTicketsRoute()', () => { + it('should perform a POST query to add tickets to the route', () => { + controller.$.model = {refresh: jest.fn()}; + jest.spyOn(controller.vnApp, 'showSuccess'); + jest.spyOn(controller, 'hide'); + + controller.route = {id: 111}; + + controller.possibleTickets = [ + {id: 2, checked: false}, + {id: 3, checked: true}, + {id: 4, checked: false}, + {id: 5, checked: true}, + ]; + + $httpBackend.whenPOST(`Routes/${controller.route.id}/updateVolume`).respond(200); + $httpBackend.expectPOST('Tickets/crud').respond(); + controller.setTicketsRoute(); + $httpBackend.flush(); + + expect(controller.vnApp.showSuccess).toHaveBeenCalled(); + expect(controller.hide).toHaveBeenCalled(); + expect(controller.$.model.refresh).toHaveBeenCalledWith(); + }); + }); +}); diff --git a/modules/route/front/ticket-popup/style.scss b/modules/route/front/ticket-popup/style.scss new file mode 100644 index 000000000..77fa48f20 --- /dev/null +++ b/modules/route/front/ticket-popup/style.scss @@ -0,0 +1,5 @@ +@import "variables"; + +.dialog{ + padding: $float-spacing +} \ No newline at end of file diff --git a/modules/route/front/tickets/index.html b/modules/route/front/tickets/index.html index 970c7574b..e02969219 100644 --- a/modules/route/front/tickets/index.html +++ b/modules/route/front/tickets/index.html @@ -115,83 +115,16 @@ question="Delete ticket from route?" on-accept="$ctrl.removeTicketFromRoute($index)"> - - - - - - Tickets to add -
- -
-
-
- - - - - - - - - - Ticket - Client - Province - - - Population - - - PC - Address - Zone - - - - - - - - - - - {{::ticket.id}} - - - - - {{::ticket.nickname}} - - - {{::ticket.address.province.name}} - {{::ticket.address.city}} - {{::ticket.address.postalCode}} - {{::ticket.address.street}} - - {{::ticket.zone.name}} - - - - - - - - -
+ + + + - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/modules/route/front/tickets/index.js b/modules/route/front/tickets/index.js index e74cbcd40..b14b28ed6 100644 --- a/modules/route/front/tickets/index.js +++ b/modules/route/front/tickets/index.js @@ -4,14 +4,6 @@ import './style.scss'; import UserError from 'core/lib/user-error'; class Controller extends Section { - get route() { - return this._route; - } - - set route(value) { - this._route = value; - } - get isChecked() { if (this.tickets) { for (let instance of this.tickets) @@ -37,19 +29,6 @@ class Controller extends Section { }); } - unlinkZone(ticket) { - const params = { - agencyModeId: this.route.agencyModeFk, - zoneId: ticket.zoneFk, - }; - - const query = `Routes/unlink`; - this.$http.post(query, params).then(() => { - this.vnApp.showSuccess(this.$t('Data saved!')); - this.$.possibleTicketsModel.refresh(); - }); - } - getSelectedItems(items) { const selectedItems = []; @@ -117,38 +96,6 @@ class Controller extends Section { }); } - openPossibleTicketsDialog() { - this.$.possibleTicketsModel.refresh(); - this.$.possibleTicketsDialog.show(); - } - - setTicketsRoute() { - let tickets = this.getSelectedItems(this.possibleTickets); - if (tickets.length === 0) return; - - const updates = []; - - for (let ticket of tickets) { - delete ticket.checked; - const update = { - where: {id: ticket.id}, - data: {routeFk: this.route.id} - }; - - updates.push(update); - } - - const data = {creates: [], updates: updates, deletes: []}; - - return this.$http.post(`Tickets/crud`, data) - .then(() => { - this.$.model.data = this.$.model.data.concat(tickets); - this.vnApp.showSuccess(this.$t('Data saved!')); - this.updateVolume(); - this.$.possibleTicketsDialog.hide(); - }); - } - onDrop($event) { const ticketId = $event.dataTransfer.getData('Text'); diff --git a/modules/route/front/tickets/index.spec.js b/modules/route/front/tickets/index.spec.js index 092445e6f..82647d903 100644 --- a/modules/route/front/tickets/index.spec.js +++ b/modules/route/front/tickets/index.spec.js @@ -74,32 +74,6 @@ describe('Route', () => { }); }); - describe('unlink()', () => { - it('should call the route unlink endpoint with the agency and zone ids', () => { - controller.$.possibleTicketsModel = {refresh: jest.fn()}; - jest.spyOn(controller.vnApp, 'showSuccess'); - - controller.route = { - agencyModeFk: 1 - }; - - const ticket = { - zoneFk: 2, - }; - const params = { - agencyModeId: controller.route.agencyModeFk, - zoneId: ticket.zoneFk, - }; - - $httpBackend.expectPOST(`Routes/unlink`, params).respond('ok'); - controller.unlinkZone(ticket); - $httpBackend.flush(); - - expect(controller.vnApp.showSuccess).toHaveBeenCalled(); - expect(controller.$.possibleTicketsModel.refresh).toHaveBeenCalledWith(); - }); - }); - describe('getSelectedItems()', () => { it('should return the selected items', () => { let items = [ @@ -208,55 +182,6 @@ describe('Route', () => { }); }); - describe('openPossibleTicketsDialog()', () => { - it('should call both refresh and show methods in posible tickets model and dialog', () => { - controller.$.possibleTicketsModel = {refresh: () => {}}; - jest.spyOn(controller.$.possibleTicketsModel, 'refresh'); - controller.$.possibleTicketsDialog = {show: () => {}}; - jest.spyOn(controller.$.possibleTicketsDialog, 'show'); - - controller.openPossibleTicketsDialog(); - - expect(controller.$.possibleTicketsModel.refresh).toHaveBeenCalledWith(); - expect(controller.$.possibleTicketsDialog.show).toHaveBeenCalledWith(); - }); - }); - - describe('setTicketsRoute()', () => { - it('should perform a POST query to add tickets to the route', () => { - controller.$.possibleTicketsDialog = {hide: () => {}}; - jest.spyOn(controller.$.possibleTicketsDialog, 'hide'); - - controller.$params = {id: 1101}; - controller.$.model.data = [{id: 1, checked: false}]; - - const existingTicket = controller.$.model.data[0]; - - controller.route = {id: 111}; - - controller.possibleTickets = [ - {id: 2, checked: false}, - {id: 3, checked: true}, - {id: 4, checked: false}, - {id: 5, checked: true}, - ]; - - let expectedResult = [ - existingTicket, - {id: 3}, - {id: 5} - ]; - - $httpBackend.whenPOST(`Routes/${controller.$params.id}/updateVolume`).respond(200); - $httpBackend.expectPOST('Tickets/crud').respond(); - controller.setTicketsRoute(); - $httpBackend.flush(); - - expect(controller.$.model.data).toEqual(expectedResult); - expect(controller.$.possibleTicketsDialog.hide).toHaveBeenCalledWith(); - }); - }); - describe('onDrop()', () => { it('should call the insert method when dragging a ticket number', () => { jest.spyOn(controller, 'insert'); diff --git a/modules/worker/back/methods/calendar/absences.js b/modules/worker/back/methods/calendar/absences.js index c2ec27dd8..ddf38a604 100644 --- a/modules/worker/back/methods/calendar/absences.js +++ b/modules/worker/back/methods/calendar/absences.js @@ -17,11 +17,6 @@ module.exports = Self => { arg: 'year', type: 'date', required: true, - }, - { - arg: 'all', - type: 'boolean', - required: false, }], returns: [{ arg: 'absences', diff --git a/print/templates/reports/driver-route/driver-route.html b/print/templates/reports/driver-route/driver-route.html index eed85e1d7..5d840958d 100644 --- a/print/templates/reports/driver-route/driver-route.html +++ b/print/templates/reports/driver-route/driver-route.html @@ -139,10 +139,6 @@ {{$t('salesPerson')}} {{ticket.salesPersonName}} - - {{$t('import')}} - {{ticket.import | currency('EUR', $i18n.locale)}} -