diff --git a/client/core/src/components/index.js b/client/core/src/components/index.js index 315f449ed..2da08fd15 100644 --- a/client/core/src/components/index.js +++ b/client/core/src/components/index.js @@ -29,4 +29,5 @@ import './combo/combo'; import './card/card'; import './switch/switch'; import './float-button/float-button'; +import './step-control/step-control'; import './label-value/label-value'; diff --git a/client/core/src/components/step-control/step-control.html b/client/core/src/components/step-control/step-control.html new file mode 100644 index 000000000..fffdfe04d --- /dev/null +++ b/client/core/src/components/step-control/step-control.html @@ -0,0 +1,33 @@ +
+
+
+
+
+
+
+
+
+ + +
+
+ + + + +
+
+
\ No newline at end of file diff --git a/client/core/src/components/step-control/step-control.js b/client/core/src/components/step-control/step-control.js new file mode 100644 index 000000000..5510a7815 --- /dev/null +++ b/client/core/src/components/step-control/step-control.js @@ -0,0 +1,71 @@ +import ngModule from '../../module'; +import './style.scss'; + +export default class StepControl { + constructor($state) { + this.$state = $state; + } + + set currentState(state) { + let isAllowed = true; + + if (this.onStepChange) + isAllowed = this.onStepChange({state}); + + if (isAllowed) + this.$state.go(state); + } + + get totalSteps() { + return this.steps.length; + } + + get currentState() { + return this.$state.current.name; + } + + get currentStepIndex() { + for (let i = 0; i < this.steps.length; i++) { + if (this.steps[i].state == this.$state.current.name) + return i; + } + } + + onPreviousClick() { + let state = this.steps[this.currentStepIndex - 1].state; + + this.currentState = state; + } + + onNextClick() { + let state = this.steps[this.currentStepIndex + 1].state; + + this.currentState = state; + } + + canMovePrevious() { + return this.steps[0].state != this.currentState; + } + + canFinalize() { + let lastStep = this.steps[this.totalSteps - 1]; + return lastStep.state == this.currentState; + } + + canMoveNext() { + let lastStep = this.steps[this.totalSteps - 1]; + return lastStep.state != this.currentState; + } +} + +StepControl.$inject = ['$state']; + +ngModule.component('vnStepControl', { + template: require('./step-control.html'), + controller: StepControl, + bindings: { + steps: '<', + onStepChange: '&?', + onStepEnd: '&?' + } +}); diff --git a/client/core/src/components/step-control/step-control.spec.js b/client/core/src/components/step-control/step-control.spec.js new file mode 100644 index 000000000..63a4354db --- /dev/null +++ b/client/core/src/components/step-control/step-control.spec.js @@ -0,0 +1,49 @@ +import './step-control.js'; + +describe('Component vnStepControl', () => { + let $componentController; + let controller; + let $state; + + beforeEach(() => { + angular.mock.module('ticket'); + }); + + beforeEach(angular.mock.inject((_$componentController_, _$state_) => { + $componentController = _$componentController_; + $state = _$state_; + controller = $componentController('vnStepControl', {$state: $state}); + })); + + describe('currentState()', () => { + it(`should call the onStepChange method then return false and never call the go method`, () => { + controller.onStepChange = jasmine.createSpy(controller, 'onStepChange').and.returnValue(false); + spyOn(controller.$state, 'go'); + + controller.currentState = "something"; + + expect(controller.onStepChange).toHaveBeenCalledWith({state: 'something'}); + expect(controller.$state.go).not.toHaveBeenCalledWith("something"); + }); + + it(`should call the onStepChange method then return true and finally call the go method`, () => { + controller.onStepChange = jasmine.createSpy(controller, 'onStepChange').and.returnValue(true); + spyOn(controller.$state, 'go'); + + controller.currentState = "something"; + + expect(controller.onStepChange).toHaveBeenCalledWith({state: 'something'}); + expect(controller.$state.go).toHaveBeenCalledWith("something"); + }); + }); + + describe('currentStepIndex()', () => { + it('should get the current state index from an Array of states', () => { + controller.$state.current.name = 'iam_a_current_state'; + controller.steps = [{state: 'iam_not_current_state'}, {state: 'iam_a_current_state'}]; + + let result = controller.currentStepIndex; + expect(result).toEqual(1); + }); + }); +}); diff --git a/client/core/src/components/step-control/style.scss b/client/core/src/components/step-control/style.scss new file mode 100644 index 000000000..085801634 --- /dev/null +++ b/client/core/src/components/step-control/style.scss @@ -0,0 +1,58 @@ +vn-step-control { + display: flex; + justify-content: center; + + .step-control { + border-top: 2px solid rgb(255,152,0); + margin-bottom: 15px; + + & > .steps { + display: flex; + flex-direction: row + } + + & > .steps > .step { + justify-content: center; + min-width: 125px; + display: flex; + flex: auto + } + + & > .steps > .step .circle { + border: 2px solid rgb(255,152,0); + background-color: #FFF; + align-content: center; + margin-top: -9.5px; + -moz-border-radius: 50%; + -webkit-border-radius: 50%; + border-radius: 50%; + cursor: pointer; + height: 15px; + width: 15px + } + + & > .steps > .step .circle.active { + background-color: rgb(255,152,0); + } + + & > .buttons { + display: flex; + flex: auto; + flex-direction: row; + justify-content: space-between; + margin-top: 10px + } + + & > .buttons > .step { + display: flex + } + + & > .buttons > .step > .mdl-button { + line-height: 32px; + font-size: 12px; + padding: 0 12px; + height: 32px + } + } + +} \ No newline at end of file diff --git a/client/core/src/locale/en.yml b/client/core/src/locale/en.yml index a89a8ca8d..1c72342dd 100644 --- a/client/core/src/locale/en.yml +++ b/client/core/src/locale/en.yml @@ -7,4 +7,7 @@ Add: Add Search: Search Show More: Show More No more results: No more results -Hide: Hide \ No newline at end of file +Hide: Hide +Next: Next +Finalize: Finalize +Previous: Back \ No newline at end of file diff --git a/client/core/src/locale/es.yml b/client/core/src/locale/es.yml index 2b6386570..0f6d87d9f 100644 --- a/client/core/src/locale/es.yml +++ b/client/core/src/locale/es.yml @@ -7,4 +7,7 @@ Add: Añadir Search: Buscar Show More: Ver más No more results: No hay más resultados -Hide: Ocultar \ No newline at end of file +Hide: Ocultar +Next: Siguiente +Finalize: Finalizar +Previous: Anterior \ No newline at end of file diff --git a/client/ticket/src/data/step-one/step-one.html b/client/ticket/src/data/step-one/step-one.html index 9972c660b..9b07d94a5 100644 --- a/client/ticket/src/data/step-one/step-one.html +++ b/client/ticket/src/data/step-one/step-one.html @@ -1,4 +1,4 @@ -
+ Basic data @@ -19,7 +19,7 @@ initial-data="$ctrl.ticket.addressFk"> - - -
diff --git a/client/ticket/src/data/step-one/step-one.js b/client/ticket/src/data/step-one/step-one.js index 3db7aa4b0..87776169e 100644 --- a/client/ticket/src/data/step-one/step-one.js +++ b/client/ticket/src/data/step-one/step-one.js @@ -1,22 +1,17 @@ import ngModule from '../../module'; class Controller { - constructor($scope, $timeout, $state) { + constructor($scope) { this.$scope = $scope; - this.$timeout = $timeout; - this.$state = $state; - } - onSubmit() { - this.$state.go('ticket.card.data.stepTwo'); } } -Controller.$inject = ['$scope', '$timeout', '$state']; +Controller.$inject = ['$scope']; ngModule.component('vnTicketDataStepOne', { template: require('./step-one.html'), + controller: Controller, bindings: { ticket: '<' - }, - controller: Controller + } }); diff --git a/client/ticket/src/data/step-three/step-three.html b/client/ticket/src/data/step-three/step-three.html index e69de29bb..472bf468d 100644 --- a/client/ticket/src/data/step-three/step-three.html +++ b/client/ticket/src/data/step-three/step-three.html @@ -0,0 +1,8 @@ +
+ + Step tree + + Ticket id {{$ctrl.ticket.id}} + + +
diff --git a/client/ticket/src/data/step-three/step-three.js b/client/ticket/src/data/step-three/step-three.js index e69de29bb..2dde82cfe 100644 --- a/client/ticket/src/data/step-three/step-three.js +++ b/client/ticket/src/data/step-three/step-three.js @@ -0,0 +1,15 @@ +import ngModule from '../../module'; + +class Controller { + constructor($scope) { + this.$scope = $scope; + } +} + +ngModule.component('vnTicketDataStepThree', { + template: require('./step-three.html'), + controller: Controller, + bindings: { + ticket: '<' + } +}); diff --git a/client/ticket/src/data/step-two/step-two.html b/client/ticket/src/data/step-two/step-two.html index e69de29bb..a1c5d3c0d 100644 --- a/client/ticket/src/data/step-two/step-two.html +++ b/client/ticket/src/data/step-two/step-two.html @@ -0,0 +1,29 @@ +
+ + Price gap + + + + + + + + + + + + + + + + + + + + + + +
ItemDescriptionQuantityPriceNew pricePrice gap
{{("000000"+sale.itemFk).slice(-6)}}{{::sale.quantity}}{{::sale.price | currency:'€':2}}--
+
+
+
diff --git a/client/ticket/src/data/step-two/step-two.js b/client/ticket/src/data/step-two/step-two.js index e69de29bb..244828304 100644 --- a/client/ticket/src/data/step-two/step-two.js +++ b/client/ticket/src/data/step-two/step-two.js @@ -0,0 +1,28 @@ +import ngModule from '../../module'; + +class Controller { + constructor($http, $scope) { + this.$http = $http; + this.$scope = $scope; + } + + $onChanges(data) { + if (!this.ticket || !this.ticket.id) return; + + let query = `/ticket/api/sales/${this.ticket.id}/priceGap`; + this.$http.get(query).then(res => { + if (res.data) + this.ticket.sales = res.data; + }); + } +} + +Controller.$inject = ['$http', '$scope']; + +ngModule.component('vnTicketDataStepTwo', { + template: require('./step-two.html'), + controller: Controller, + bindings: { + ticket: '<' + } +}); diff --git a/services/db/04-fixtures.sql b/services/db/04-fixtures.sql index 039b879bb..83662e7d0 100644 --- a/services/db/04-fixtures.sql +++ b/services/db/04-fixtures.sql @@ -151,6 +151,13 @@ INSERT INTO `vn`.`client`(`id`,`name`,`fi`,`socialName`,`contact`,`street`,`city (109, 'Bruce Banner', '16104829E', 'Hulk', 'Black widow', 'Somewhere in New York', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'BruceBanner@verdnatura.es', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1,'0000-00-00', 1, NULL, 1, 1, 0, 1, NULL, 0, 0, 19, 0, 1), (110, 'Jessica Jones', '58282869H', 'Jessica Jones', 'Luke Cage', 'NYCC 2015 Poster', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'JessicaJones@verdnatura.es', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1,'0000-00-00', 1, NULL, 1, 1, 0, 1, NULL, 0, 0, NULL, 0, 1); +INSERT INTO `vn`.`clientManaCache`(`clientFk`, `mana`, `dated`) + VALUES + ( 101, 50, CURDATE()), + ( 102, 100, CURDATE()), + ( 103, 0, CURDATE()), + ( 104, -30, CURDATE()); + INSERT INTO `vn`.`address`(`id`, `nickname`, `street`, `city`, `postalCode`, `provinceFk`, `phone`, `mobile`, `isActive`, `isDefaultAddress`, `clientFk`, `agencyModeFk`, `longitude`, `latitude`, `isEqualizated`) VALUES (101, '01', 'Somewhere in Thailand', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0), @@ -537,7 +544,7 @@ INSERT INTO `bi`.`rotacion`(`Id_Article`, `warehouse_id`, `total`, `rotacion`, ` INSERT INTO `vn`.`annualAverageInvoiced`(`clientFk`, `invoiced`) VALUES - ( 101, 0), + ( 101, 1500), ( 102, 100), ( 103, 1000), ( 104, 500), diff --git a/services/db/changes/1.0.3/01-ticketVolume.sql b/services/db/changes/1.0.3/01-ticketVolume.sql new file mode 100644 index 000000000..89cebb67e --- /dev/null +++ b/services/db/changes/1.0.3/01-ticketVolume.sql @@ -0,0 +1,29 @@ +USE `vn`; +DROP procedure IF EXISTS `ticketVolume`; + +DELIMITER $$ +USE `vn`$$ +CREATE DEFINER=`root`@`%` PROCEDURE `ticketVolume`(IN vTicketId INT) +BEGIN + DECLARE vWarehouseId INTEGER; + DECLARE vShippedDate DATE; + + DROP TEMPORARY TABLE IF EXISTS ticketVolume; + SELECT warehouseFk, shipped INTO vWarehouseId,vShippedDate FROM vn.ticket WHERE id = vTicketId; + + CREATE TEMPORARY TABLE IF NOT EXISTS ticketVolume ENGINE MEMORY + + SELECT itemFk, saleFk, quantity, concept, VolUd as m3_uni, volume as m3, volume * quantity as volumeTimesQuantity, @m3:= @m3 + ifnull(volume,0) as m3_total + FROM + ( + SELECT round(r.cm3 / 1000000,3) as VolUd ,s.quantity, round(r.cm3 * s.quantity / 1000000,3) as volume, + s.itemFk, s.id AS saleFk, s.concept, @m3:= 0, @vol:=0, t.agencyModeFk + FROM sale s + JOIN vn.ticket t on t.id = s.ticketFk + JOIN bi.rotacion r ON r.Id_Article = s.itemFk AND r.warehouse_id = t.warehouseFk + WHERE s.ticketFk = vTicketId + ) sub; +END$$ + +DELIMITER ; + diff --git a/services/loopback/common/methods/client/specs/getAverageInvoiced.spec.js b/services/loopback/common/methods/client/specs/getAverageInvoiced.spec.js index 0775423e0..a27e9a848 100644 --- a/services/loopback/common/methods/client/specs/getAverageInvoiced.spec.js +++ b/services/loopback/common/methods/client/specs/getAverageInvoiced.spec.js @@ -11,7 +11,7 @@ describe('client getAverageInvoiced()', () => { it('should call the getAverageInvoiced method', done => { model.getAverageInvoiced(101) .then(response => { - expect(response.invoiced).toEqual(0); + expect(response.invoiced).toEqual(1500); done(); }); }); diff --git a/services/loopback/common/methods/client/specs/getMana.spec.js b/services/loopback/common/methods/client/specs/getMana.spec.js index 942eaaca0..731c7a021 100644 --- a/services/loopback/common/methods/client/specs/getMana.spec.js +++ b/services/loopback/common/methods/client/specs/getMana.spec.js @@ -11,7 +11,7 @@ describe('client getMana()', () => { it('should call the getMana method', done => { model.getMana(101) .then(response => { - expect(response.mana).toEqual(0); + expect(response.mana).toEqual(30.02); done(); }); }); diff --git a/services/loopback/common/methods/sale/priceGap.js b/services/loopback/common/methods/sale/price-gap.js similarity index 100% rename from services/loopback/common/methods/sale/priceGap.js rename to services/loopback/common/methods/sale/price-gap.js diff --git a/services/ticket/common/methods/sale/saleComponentFilter.js b/services/loopback/common/methods/sale/saleComponentFilter.js similarity index 100% rename from services/ticket/common/methods/sale/saleComponentFilter.js rename to services/loopback/common/methods/sale/saleComponentFilter.js diff --git a/services/loopback/common/models/sale.js b/services/loopback/common/models/sale.js index a5189ea26..5d452295d 100644 --- a/services/loopback/common/models/sale.js +++ b/services/loopback/common/models/sale.js @@ -1,4 +1,5 @@ module.exports = function(Self) { require('../methods/sale/filter')(Self); - require('../methods/sale/priceGap')(Self); + require('../methods/sale/saleComponentFilter.js')(Self); + require('../methods/sale/price-gap')(Self); }; diff --git a/services/loopback/common/models/sale.json b/services/loopback/common/models/sale.json index fec1f2dd9..9466549da 100644 --- a/services/loopback/common/models/sale.json +++ b/services/loopback/common/models/sale.json @@ -1,38 +1,38 @@ { - "name": "Sale", - "base": "VnModel", - "options": { - "mysql": { - "table": "sale" - } + "name": "Sale", + "base": "VnModel", + "options": { + "mysql": { + "table": "sale" + } + }, + "properties": { + "id": { + "id": true, + "type": "Number", + "description": "Identifier" }, - "properties": { - "id": { - "id": true, - "type": "Number", - "description": "Identifier" - }, - "concept": { - "type": "String" - }, - "quantity": { - "type": "Number" - }, - "price": { - "type": "Number" - }, - "discount": { - "type": "Number" - }, - "reserved": { - "type": "Number" - }, - "isPicked": { - "type": "Number" - }, - "created": { - "type": "date" - } + "concept": { + "type": "String" + }, + "quantity": { + "type": "Number" + }, + "price": { + "type": "Number" + }, + "discount": { + "type": "Number" + }, + "reserved": { + "type": "Number" + }, + "isPicked": { + "type": "Number" + }, + "created": { + "type": "date" + } }, "relations": { "item": { @@ -51,6 +51,11 @@ "type": "hasOne", "model": "SaleChecked", "foreignKey": "saleFk" - } + }, + "components": { + "type": "hasMany", + "model": "SaleComponent", + "foreignKey": "saleFk" + } } } diff --git a/services/ticket/common/methods/sale/filter.js b/services/ticket/common/methods/sale/filter.js deleted file mode 100644 index f9b6304f6..000000000 --- a/services/ticket/common/methods/sale/filter.js +++ /dev/null @@ -1,39 +0,0 @@ -module.exports = Self => { - Self.installMethod('filter', filterParams); - - function filterParams(params) { - return { - where: { - ticketFk: params.ticketFk - }, - skip: (params.page - 1) * params.size, - limit: params.size, - order: params.order || 'concept ASC', - include: [{ - relation: "item", - scope: { - include: { - relation: "itemTag", - scope: { - fields: ["tagFk", "value"], - include: { - relation: "tag", - scope: { - fields: ["name"] - } - }, - limit: 6 - } - }, - fields: ["itemFk", "name"] - } - }, - { - relation: "isChecked", - scope: { - fields: ["isChecked"] - } - }] - }; - } -}; diff --git a/services/ticket/common/models/sale.js b/services/ticket/common/models/sale.js deleted file mode 100644 index c8afd2123..000000000 --- a/services/ticket/common/models/sale.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = function(Self) { - require('../methods/sale/filter.js')(Self); - require('../methods/sale/saleComponentFilter.js')(Self); -}; diff --git a/services/ticket/common/models/sale.json b/services/ticket/common/models/sale.json deleted file mode 100644 index 529329613..000000000 --- a/services/ticket/common/models/sale.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "name": "Sale", - "base": "VnModel", - "options": { - "mysql": { - "table": "sale" - } - }, - "properties": { - "id": { - "id": true, - "type": "Number", - "description": "Identifier" - }, - "concept": { - "type": "String" - }, - "quantity": { - "type": "Number" - }, - "price": { - "type": "Number" - }, - "discount": { - "type": "Number" - }, - "reserved": { - "type": "Number" - }, - "isPicked": { - "type": "Number" - }, - "created": { - "type": "date" - } - }, - "relations": { - "item": { - "type": "belongsTo", - "model": "Item", - "foreignKey": "itemFk", - "required": true - }, - "ticket": { - "type": "belongsTo", - "model": "Ticket", - "foreignKey": "ticketFk", - "required": true - }, - "isChecked": { - "type": "hasOne", - "model": "SaleChecked", - "foreignKey": "saleFk" - }, - "components": { - "type": "hasMany", - "model": "SaleComponent", - "foreignKey": "saleFk" - } - } -} diff --git a/services/ticket/server/model-config.json b/services/ticket/server/model-config.json index bb5715e73..eccd5dae5 100644 --- a/services/ticket/server/model-config.json +++ b/services/ticket/server/model-config.json @@ -5,9 +5,6 @@ "ObservationType": { "dataSource": "vn" }, - "Sale": { - "dataSource": "vn" - }, "TicketTracking": { "dataSource": "vn" },