From 708789502dcae72d0893735dd1c1b00afaca1b35 Mon Sep 17 00:00:00 2001 From: Joan Sanchez Date: Wed, 15 Jan 2020 13:07:33 +0100 Subject: [PATCH] Added waste section --- db/changes/10140-kings/00-waste_getDetail.sql | 30 ++++ modules/item/front/index.js | 1 + modules/item/front/routes.json | 9 ++ modules/item/front/waste/index.html | 120 ++++++++++++++++ modules/item/front/waste/index.js | 12 ++ modules/item/front/waste/index.spec.js | 133 ++++++++++++++++++ modules/item/front/waste/locale/es.yml | 6 + modules/item/front/waste/style.scss | 18 +++ .../back/methods/sale/recalculatePrice.js | 2 +- 9 files changed, 330 insertions(+), 1 deletion(-) create mode 100644 db/changes/10140-kings/00-waste_getDetail.sql create mode 100644 modules/item/front/waste/index.html create mode 100644 modules/item/front/waste/index.js create mode 100644 modules/item/front/waste/index.spec.js create mode 100644 modules/item/front/waste/locale/es.yml create mode 100644 modules/item/front/waste/style.scss diff --git a/db/changes/10140-kings/00-waste_getDetail.sql b/db/changes/10140-kings/00-waste_getDetail.sql new file mode 100644 index 000000000..9bf6cf049 --- /dev/null +++ b/db/changes/10140-kings/00-waste_getDetail.sql @@ -0,0 +1,30 @@ +USE `bs`; +DROP procedure IF EXISTS `waste_getDetail`; + +DELIMITER $$ +USE `bs`$$ +CREATE DEFINER=`root`@`%`PROCEDURE `waste_getDetail` () +BEGIN + DECLARE vWeek INT; + DECLARE vYear INT; + + SELECT week, year + INTO vWeek, vYear + FROM vn.time + WHERE dated = CURDATE(); + + SELECT *, 100 * dwindle / total AS percentage + FROM ( + SELECT buyer, + ws.family, + sum(ws.saleTotal) AS total, + sum(ws.saleWaste) AS dwindle + FROM bs.waste ws + WHERE `year` = vYear AND `week` = vWeek + GROUP BY buyer, family + ) sub + ORDER BY percentage DESC; +END$$ + +DELIMITER ; + diff --git a/modules/item/front/index.js b/modules/item/front/index.js index 2be6f95c2..0f11c0563 100644 --- a/modules/item/front/index.js +++ b/modules/item/front/index.js @@ -20,4 +20,5 @@ import './niche'; import './botanical'; import './barcode'; import './summary'; +import './waste'; diff --git a/modules/item/front/routes.json b/modules/item/front/routes.json index bda4f18a9..611bba785 100644 --- a/modules/item/front/routes.json +++ b/modules/item/front/routes.json @@ -137,6 +137,15 @@ "item": "$ctrl.item" }, "acl": ["employee"] + }, { + "url" : "/waste", + "state": "item.waste", + "component": "vn-item-waste", + "description": "Waste", + "params": { + "item": "$ctrl.item" + }, + "acl": ["employee"] } ] } \ No newline at end of file diff --git a/modules/item/front/waste/index.html b/modules/item/front/waste/index.html new file mode 100644 index 000000000..e7ddb25fd --- /dev/null +++ b/modules/item/front/waste/index.html @@ -0,0 +1,120 @@ + + + + + + + + Buyer + Family + Percentage + Mermas + Total + + + + + + + {{request.ticketFk}} + + + + + {{::request.shipped | date: 'dd/MM/yyyy'}} + + + {{::request.warehouse}} + + + {{::request.salesPersonNickname}} + + + {{::request.description}} + {{::request.quantity}} + {{::request.price | currency: 'EUR':2}} + + + {{::request.atenderNickname}} + + + + {{request.itemFk}} + + + + + + + {{request.saleQuantity}} + + + + + + + + {{request.itemDescription}} + + + {{$ctrl.getState(request.isOk)}} + + + + + + + + + + + + + + + + + + + +
Specify the reasons to deny this request
+ + + + +
+ + + + +
\ No newline at end of file diff --git a/modules/item/front/waste/index.js b/modules/item/front/waste/index.js new file mode 100644 index 000000000..f64cf3e1d --- /dev/null +++ b/modules/item/front/waste/index.js @@ -0,0 +1,12 @@ +import ngModule from '../module'; +import Component from 'core/lib/component'; +import './style.scss'; + +export default class Controller extends Component { + +} + +ngModule.component('vnItemWaste', { + template: require('./index.html'), + controller: Controller +}); diff --git a/modules/item/front/waste/index.spec.js b/modules/item/front/waste/index.spec.js new file mode 100644 index 000000000..4c1e31634 --- /dev/null +++ b/modules/item/front/waste/index.spec.js @@ -0,0 +1,133 @@ +import './index.js'; +import crudModel from 'core/mocks/crud-model'; + +describe('Item', () => { + describe('Component vnItemRequest', () => { + let $scope; + let $element; + let controller; + let $httpBackend; + + beforeEach(ngModule('item')); + + beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_) => { + $httpBackend = _$httpBackend_; + $scope = $rootScope.$new(); + $scope.model = crudModel; + $scope.denyReason = {hide: () => {}}; + $element = angular.element(''); + controller = $componentController('vnItemRequest', {$element, $scope}); + })); + + afterAll(() => { + $scope.$destroy(); + $element.remove(); + }); + + describe('getState()', () => { + it(`should return an string depending to the isOK value`, () => { + let isOk = null; + let result = controller.getState(isOk); + + expect(result).toEqual('Nueva'); + + isOk = 1; + result = controller.getState(isOk); + + expect(result).toEqual('Aceptada'); + + isOk = 0; + result = controller.getState(isOk); + + expect(result).toEqual('Denegada'); + }); + }); + + describe('confirmRequest()', () => { + it(`should do nothing if the request does't have itemFk or saleQuantity`, () => { + let request = {}; + spyOn(controller.vnApp, 'showSuccess'); + + controller.confirmRequest(request); + + expect(controller.vnApp.showSuccess).not.toHaveBeenCalledWith(); + }); + + it('should perform a query and call vnApp.showSuccess() and refresh if the conditions are met', () => { + spyOn(controller.vnApp, 'showSuccess'); + let model = controller.$.model; + spyOn(model, 'refresh'); + + const expectedResult = {concept: 'Melee Weapon'}; + let request = {itemFk: 1, saleQuantity: 1, id: 1}; + + $httpBackend.when('POST', `TicketRequests/${request.id}/confirm`).respond(expectedResult); + $httpBackend.expect('POST', `TicketRequests/${request.id}/confirm`).respond(expectedResult); + controller.confirmRequest(request); + $httpBackend.flush(); + + expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!'); + }); + }); + + describe('changeQuantity()', () => { + it(`should call confirmRequest() if there's no sale id in the request`, () => { + let request = {}; + spyOn(controller, 'confirmRequest'); + + controller.changeQuantity(request); + + expect(controller.confirmRequest).toHaveBeenCalledWith(jasmine.any(Object)); + }); + + it(`should perform a query and call vnApp.showSuccess() if the conditions are met`, () => { + let request = {saleFk: 1, saleQuantity: 1}; + spyOn(controller.vnApp, 'showSuccess'); + + + $httpBackend.when('PATCH', `Sales/${request.saleFk}/`).respond(); + $httpBackend.expect('PATCH', `Sales/${request.saleFk}/`).respond(); + controller.changeQuantity(request); + $httpBackend.flush(); + + expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!'); + }); + }); + + describe('compareDate()', () => { + it(`should return "success" if receives a future date`, () => { + let date = '3019-02-18T11:00:00.000Z'; + + let result = controller.compareDate(date); + + expect(result).toEqual('success'); + }); + + it(`should return "warning" if date is today`, () => { + let date = new Date(); + + let result = controller.compareDate(date); + + expect(result).toEqual('warning'); + }); + }); + + describe('denyRequest()', () => { + it(`should perform a query and call vnApp.showSuccess(), refresh(), hide() and set denyObservation to null in the controller`, () => { + spyOn(controller.vnApp, 'showSuccess'); + + const request = {id: 1}; + const expectedResult = {isOk: false, attenderFk: 106, response: 'Denied!'}; + controller.selectedRequest = request; + + $httpBackend.when('POST', `TicketRequests/${request.id}/deny`).respond(expectedResult); + $httpBackend.expect('POST', `TicketRequests/${request.id}/deny`).respond(expectedResult); + controller.denyRequest('accept'); + $httpBackend.flush(); + + expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!'); + }); + }); + }); +}); + diff --git a/modules/item/front/waste/locale/es.yml b/modules/item/front/waste/locale/es.yml new file mode 100644 index 000000000..33710a327 --- /dev/null +++ b/modules/item/front/waste/locale/es.yml @@ -0,0 +1,6 @@ +Discard: Descartar +Specify the reasons to deny this request: Especifica las razones para descartar la peticiĆ³n +Buy requests: Peticiones de compra +Search request by id or alias: Buscar peticiones por identificador o alias +Requested: Solicitado +Achieved: Conseguido \ No newline at end of file diff --git a/modules/item/front/waste/style.scss b/modules/item/front/waste/style.scss new file mode 100644 index 000000000..0af32c309 --- /dev/null +++ b/modules/item/front/waste/style.scss @@ -0,0 +1,18 @@ +@import "variables"; + +vn-item-request { + vn-dialog[vn-id="denyReason"] { + button.close { + display: none + } + vn-button { + margin: 0 auto + } + vn-textarea { + width: 100% + } + } + vn-icon[icon=insert_drive_file]{ + color: $color-font-secondary; + } +} \ No newline at end of file diff --git a/modules/ticket/back/methods/sale/recalculatePrice.js b/modules/ticket/back/methods/sale/recalculatePrice.js index 1bd754f6a..9ad7e68e7 100644 --- a/modules/ticket/back/methods/sale/recalculatePrice.js +++ b/modules/ticket/back/methods/sale/recalculatePrice.js @@ -29,6 +29,6 @@ module.exports = Self => { if (!isEditable) throw new UserError(`The sales of this ticket can't be modified`); - return Self.rawSql('CALL vn.ticketCalculateSale(?)', [id]); + return Self.rawSql('CALL vn.sale_calculateComponent(?, null)', [id]); }; };