diff --git a/client/claim/src/action/index.html b/client/claim/src/action/index.html index c6b798c9d..f20e2c370 100644 --- a/client/claim/src/action/index.html +++ b/client/claim/src/action/index.html @@ -88,7 +88,12 @@ - + {{$ctrl.resolvedStateText}} + + + + + + + \ No newline at end of file diff --git a/client/salix/src/components/main-menu/main-menu.js b/client/salix/src/components/main-menu/main-menu.js index ee2727f39..0912d394e 100644 --- a/client/salix/src/components/main-menu/main-menu.js +++ b/client/salix/src/components/main-menu/main-menu.js @@ -34,6 +34,11 @@ export default class MainMenu { }); } + openUserConfiguration(event) { + this.$.popover.parent = event.target; + this.$.popover.show(); + } + onLogoutClick() { this.$window.location = '/logout'; } diff --git a/client/salix/src/components/user-configuration-popover/index.html b/client/salix/src/components/user-configuration-popover/index.html new file mode 100644 index 000000000..c2255ca7d --- /dev/null +++ b/client/salix/src/components/user-configuration-popover/index.html @@ -0,0 +1,79 @@ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+
diff --git a/client/salix/src/components/user-configuration-popover/index.js b/client/salix/src/components/user-configuration-popover/index.js new file mode 100644 index 000000000..559425f84 --- /dev/null +++ b/client/salix/src/components/user-configuration-popover/index.js @@ -0,0 +1,90 @@ +import ngModule from '../../module'; +import './style.scss'; + +class Controller { + constructor($scope, $http, $state, vnApp, $translate) { + this.$scope = $scope; + this.$http = $http; + this.$state = $state; + this.vnApp = vnApp; + this.$translate = $translate; + this.getUserConfig(); + } + + set localBank(value) { + window.localStorage.localBank = value; + this.showOk(); + } + + get localBank() { + return parseInt(window.localStorage.localBank); + } + + set localWarehouse(value) { + window.localStorage.localWarehouse = value; + this.showOk(); + } + + get localWarehouse() { + return parseInt(window.localStorage.localWarehouse); + } + + set localCompany(value) { + window.localStorage.localCompany = value; + this.showOk(); + } + + get localCompany() { + return parseInt(window.localStorage.localCompany); + } + + set warehouseFk(value) { + this.warehouse = value; + this.setUserConfig('warehouseFk'); + } + + get warehouseFk() { + return this.warehouse; + } + + set companyFk(value) { + this.company = value; + this.setUserConfig('companyFk'); + } + + get companyFk() { + return this.company; + } + + showOk() { + this.vnApp.showSuccess(this.$translate.instant('Data saved!')); + } + + getUserConfig() { + this.$http.get('/api/UserConfigs/getUserConfig') + .then(res => { + if (res.data && res.data.warehouseFk) + this.warehouse = res.data.warehouseFk; + + if (res.data && res.data.companyFk) + this.company = res.data.companyFk; + }); + } + + setUserConfig(property) { + let params = {}; + params[property] = this[property]; + + this.$http.post('/api/UserConfigs/setUserConfig', params) + .then(() => { + this.showOk(); + }); + } +} + +Controller.$inject = ['$scope', '$http', '$state', 'vnApp', '$translate']; + +ngModule.component('vnUserConfigurationPopover', { + template: require('./index.html'), + controller: Controller +}); diff --git a/client/salix/src/components/user-configuration-popover/index.spec.js b/client/salix/src/components/user-configuration-popover/index.spec.js new file mode 100644 index 000000000..250983ac5 --- /dev/null +++ b/client/salix/src/components/user-configuration-popover/index.spec.js @@ -0,0 +1,97 @@ +import './index.js'; + +describe('Salix', () => { + describe('Component vnUserConfigurationPopover', () => { + let $componentController; + let controller; + let $httpBackend; + let $scope; + + beforeEach(() => { + angular.mock.module('salix'); + }); + + beforeEach(angular.mock.inject((_$componentController_, _$httpBackend_, $rootScope) => { + $componentController = _$componentController_; + $httpBackend = _$httpBackend_; + $httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({}); + $scope = $rootScope.$new(); + controller = $componentController('vnUserConfigurationPopover', {$scope: $scope, $translate: null}); + })); + + describe('localBank() setter', () => { + it('should set window.localStorage.localBank and call showOk', () => { + spyOn(controller, 'showOk') + controller.localBank = 4; + + expect(window.localStorage.localBank).toBe('4'); + expect(controller.showOk).toHaveBeenCalledWith(); + }); + }); + + describe('localWarehouse() setter', () => { + it('should set window.localStorage.localWarehouse and call showOk', () => { + spyOn(controller, 'showOk') + controller.localWarehouse = 4; + + expect(window.localStorage.localWarehouse).toBe('4'); + expect(controller.showOk).toHaveBeenCalledWith(); + }); + }); + + describe('localCompany() setter', () => { + it('should set window.localStorage.localCompany and call showOk', () => { + spyOn(controller, 'showOk') + controller.localCompany = 4; + + expect(window.localStorage.localCompany).toBe('4'); + expect(controller.showOk).toHaveBeenCalledWith(); + }); + }); + + describe('warehouseFk() setter', () => { + it('should set warehouse and call setUserConfig', () => { + spyOn(controller, 'setUserConfig') + controller.warehouseFk = 4; + + expect(controller.warehouse).toBe(4); + expect(controller.setUserConfig).toHaveBeenCalledWith('warehouseFk'); + }); + }); + + describe('companyFk() setter', () => { + it('should set company and call setUserConfig', () => { + spyOn(controller, 'setUserConfig') + controller.companyFk = 4; + + expect(controller.company).toBe(4); + expect(controller.setUserConfig).toHaveBeenCalledWith('companyFk'); + }); + }); + + describe('getUserConfig()', () => { + it('should make a query, set company and not set warehouse if its not in the response', () => { + $httpBackend.when('GET', `/api/UserConfigs/getUserConfig`).respond({response: {companyFk: 2}}); + $httpBackend.expect('GET', `/api/UserConfigs/getUserConfig`); + controller.getUserConfig(); + $httpBackend.flush(); + + expect(controller.warehouse).toBeUndefined(); + expect(controller.company).toEqual(2); + }); + }); + + describe('setUserConfig()', () => { + it('should make a query with the property given and call showOk', () => { + spyOn(controller, 'showOk'); + controller.company = 1; + $httpBackend.when('POST', `/api/UserConfigs/setUserConfig`, {companyFk: 1}).respond(200); + $httpBackend.expect('POST', `/api/UserConfigs/setUserConfig`, {companyFk: 1}); + controller.setUserConfig('companyFk'); + $httpBackend.flush(); + + expect(controller.showOk).toHaveBeenCalledWith(); + }); + }); + }); +}); diff --git a/client/salix/src/components/user-configuration-popover/style.scss b/client/salix/src/components/user-configuration-popover/style.scss new file mode 100644 index 000000000..d370cc279 --- /dev/null +++ b/client/salix/src/components/user-configuration-popover/style.scss @@ -0,0 +1,12 @@ +@import 'colors'; + +vn-user-configuration-popover { + color: $main-font-color; + & > vn-vertical { + min-width: 250px; + } + .body { + padding: 16px 16px 6px 16px; + } + +} \ No newline at end of file diff --git a/client/ticket/src/component/index.js b/client/ticket/src/component/index.js index 8dd556cb1..1d54d7598 100644 --- a/client/ticket/src/component/index.js +++ b/client/ticket/src/component/index.js @@ -93,7 +93,8 @@ class Controller { icon: 'icon-transaction', state: `item.card.diary({ id: ${itemFk}, - q: '{"warehouseFk": ${this.ticket.warehouseFk}}' + warehouseFk: ${this.ticket.warehouseFk}, + ticketFk: ${this.ticket.id} })`, tooltip: 'Item diary' } diff --git a/client/ticket/src/expedition/index.html b/client/ticket/src/expedition/index.html index 10253d615..695ff15ec 100644 --- a/client/ticket/src/expedition/index.html +++ b/client/ticket/src/expedition/index.html @@ -36,7 +36,7 @@ - {{expedition.itemFk}} + {{("000000"+expedition.itemFk).slice(-6)}} {{::expedition.namePackage}} diff --git a/client/ticket/src/expedition/index.js b/client/ticket/src/expedition/index.js index 50f767ec7..f83d88fcd 100644 --- a/client/ticket/src/expedition/index.js +++ b/client/ticket/src/expedition/index.js @@ -27,7 +27,8 @@ class Controller { icon: 'icon-transaction', state: `item.card.diary({ id: ${itemFk}, - q: '{"warehouseFk": ${this.ticket.warehouseFk}}' + warehouseFk: ${this.ticket.warehouseFk}, + ticketFk: ${this.ticket.id} })`, tooltip: 'Item diary' } diff --git a/client/ticket/src/locale/es.yml b/client/ticket/src/locale/es.yml index 236e3ebdd..a1d4bafcf 100644 --- a/client/ticket/src/locale/es.yml +++ b/client/ticket/src/locale/es.yml @@ -73,4 +73,4 @@ Tracking: Revisión Sale checked: Control clientes Components: Componentes Sale tracking: Líneas preparadas -Pictures: Imágenes +Pictures: Fotos diff --git a/client/ticket/src/sale-checked/index.js b/client/ticket/src/sale-checked/index.js index 204b393ab..2f69aec4d 100644 --- a/client/ticket/src/sale-checked/index.js +++ b/client/ticket/src/sale-checked/index.js @@ -39,7 +39,8 @@ class Controller { icon: 'icon-transaction', state: `item.card.diary({ id: ${itemFk}, - q: '{"warehouseFk": ${this.ticket.warehouseFk}}' + warehouseFk: ${this.ticket.warehouseFk}, + ticketFk: ${this.ticket.id} })`, tooltip: 'Item diary' } diff --git a/client/ticket/src/sale-tracking/index.js b/client/ticket/src/sale-tracking/index.js index 0ef1a0ddf..0adfce1de 100644 --- a/client/ticket/src/sale-tracking/index.js +++ b/client/ticket/src/sale-tracking/index.js @@ -12,7 +12,8 @@ class Controller { icon: 'icon-transaction', state: `item.card.diary({ id: ${itemFk}, - q: '{"warehouseFk": ${this.ticket.warehouseFk}}' + warehouseFk: ${this.ticket.warehouseFk}, + ticketFk: ${this.ticket.id} })`, tooltip: 'Item diary' } diff --git a/client/ticket/src/sale/index.js b/client/ticket/src/sale/index.js index 74b1d2f7c..71c17158d 100644 --- a/client/ticket/src/sale/index.js +++ b/client/ticket/src/sale/index.js @@ -243,7 +243,8 @@ class Controller { icon: 'icon-transaction', state: `item.card.diary({ id: ${itemFk}, - q: '{"warehouseFk": ${this.ticket.warehouseFk}}' + warehouseFk: ${this.ticket.warehouseFk}, + ticketFk: ${this.ticket.id} })`, tooltip: 'Item diary' } diff --git a/client/ticket/src/summary/index.js b/client/ticket/src/summary/index.js index 645432bcb..0446fdd16 100644 --- a/client/ticket/src/summary/index.js +++ b/client/ticket/src/summary/index.js @@ -37,7 +37,8 @@ class Controller { icon: 'icon-transaction', state: `item.card.diary({ id: ${itemFk}, - q: '{"warehouseFk": ${this.ticket.warehouseFk}}' + warehouseFk: ${this.ticket.warehouseFk}, + ticketFk: ${this.ticket.id} })`, tooltip: 'Item diary' } diff --git a/client/ticket/src/volume/index.js b/client/ticket/src/volume/index.js index 7da05435d..cc69ca3b3 100644 --- a/client/ticket/src/volume/index.js +++ b/client/ticket/src/volume/index.js @@ -52,7 +52,8 @@ class Controller { icon: 'icon-transaction', state: `item.card.diary({ id: ${itemFk}, - q: '{"warehouseFk": ${this.ticket.warehouseFk}}' + warehouseFk: ${this.ticket.warehouseFk}, + ticketFk: ${this.ticket.id} })`, tooltip: 'Item diary' } diff --git a/e2e/paths/client-module/12_lock_of_verified_data.spec.js b/e2e/paths/client-module/12_lock_of_verified_data.spec.js index 19fbf7999..41864611e 100644 --- a/e2e/paths/client-module/12_lock_of_verified_data.spec.js +++ b/e2e/paths/client-module/12_lock_of_verified_data.spec.js @@ -60,7 +60,6 @@ describe('Client lock verified data path', () => { return nightmare .wait(selectors.clientFiscalData.verifiedDataCheckboxInput) .evaluate(selector => { - console.log(document.querySelector(selector)); return document.querySelector(selector).disabled; }, selectors.clientFiscalData.verifiedDataCheckbox) .then(result => { diff --git a/services/claim/common/methods/claim/regularizeClaim.js b/services/claim/common/methods/claim/regularizeClaim.js new file mode 100644 index 000000000..4aedcb45c --- /dev/null +++ b/services/claim/common/methods/claim/regularizeClaim.js @@ -0,0 +1,156 @@ +module.exports = Self => { + Self.remoteMethodCtx('regularizeClaim', { + description: 'Imports lines from claimBeginning to a new ticket with specific shipped, landed dates, agency and company', + accessType: 'WRITE', + accepts: [{ + arg: 'params', + type: 'object', + http: {source: 'body'} + }], + returns: { + type: ['Object'], + root: true + }, + http: { + path: `/regularizeClaim`, + verb: 'POST' + } + }); + + Self.regularizeClaim = async (ctx, params) => { + const userId = ctx.req.accessToken.userId; + const models = Self.app.models; + const resolvedState = 3; + + const claimEnds = await models.ClaimEnd.find({ + include: { + relation: 'claimDestination', + fields: ['addressFk'] + }, + where: {claimFk: params.claimFk} + }); + + let transaction = await Self.beginTransaction({}); + try { + for (let i = 0; i < claimEnds.length; i++) { + const claimEnd = claimEnds[i]; + const destination = claimEnd.claimDestination(); + const addressFk = destination && destination.addressFk; + + if (!addressFk) + continue; + + let sale = await getSale(claimEnd.saleFk); + let ticketFk = await getTicketId({ + addressFk: addressFk, + companyFk: sale.ticket().companyFk, + warehouseFk: sale.ticket().warehouseFk + }, transaction); + + let address = await models.Address.findOne({ + where: {id: addressFk} + }); + + if (!ticketFk) { + ticketFk = await createTicket({ + clientFk: address.clientFk, + addressFk: addressFk, + warehouseFk: sale.ticket().warehouseFk, + companyFk: sale.ticket().companyFk, + userId: userId + }, transaction); + } + + await models.Sale.create({ + ticketFk: ticketFk, + itemFk: sale.itemFk, + concept: sale.concept, + quantity: -sale.quantity, + price: sale.price, + discount: 100 + }, {transaction: transaction}); + + await sendMessage(ctx, { + itemFk: sale.itemFk, + ticketFk: sale.ticketFk, + workerFk: sale.item().itemType().workerFk, + quantity: sale.quantity, + concept: sale.concept, + nickname: address.nickname + }, transaction); + } + + let claim = await Self.findById(params.claimFk); + claim = await claim.updateAttributes({ + claimStateFk: resolvedState + }, {transaction: transaction}); + + await transaction.commit(); + + return claim; + } catch (e) { + await transaction.rollback(); + throw e; + } + }; + + async function getSale(saleFk) { + return await Self.app.models.Sale.findOne({ + include: [ + { + relation: 'ticket', + scope: {fields: ['warehouseFk', 'companyFk']} + }, + { + relation: 'item', + scope: { + fields: ['typeFk'], + include: { + relation: 'itemType', + scope: {fields: ['workerFk']} + } + } + }], + where: {id: saleFk} + }); + } + + async function getTicketId(params, transaction) { + const currentDate = new Date(); + currentDate.setHours(0, 0, 0, 0); + + let ticket = await Self.app.models.Ticket.findOne({ + where: { + addressFk: params.addressFk, + companyFk: params.companyFk, + warehouseFk: params.warehouseFk, + shipped: currentDate, + landed: currentDate + } + }, {transaction: transaction}); + + return ticket && ticket.id; + } + + async function createTicket(params, transaction) { + return await Self.app.models.Ticket.new({ + shipped: new Date(), + landed: new Date(), + clientFk: params.clientFk, + warehouseFk: params.warehouseFk, + companyFk: params.companyFk, + addressFk: params.addressFk, + userId: params.userId + }, {transaction: transaction}); + } + + async function sendMessage(ctx, params, transaction) { + const message = `Envio ${params.quantity} unidades de "${params.concept}" (#${params.itemFk}) a ` + + `"${params.nickname}" provenientes del ticket #${params.ticketFk}`; + + await Self.app.models.Message.send(ctx, { + recipientFk: params.workerFk, + message: message + }, {transaction: transaction}); + } +}; diff --git a/services/claim/common/methods/claim/specs/regularizeClaim.spec.js b/services/claim/common/methods/claim/specs/regularizeClaim.spec.js new file mode 100644 index 000000000..a3c4b04a5 --- /dev/null +++ b/services/claim/common/methods/claim/specs/regularizeClaim.spec.js @@ -0,0 +1,45 @@ +const app = require(`${servicesDir}/claim/server/server`); + +describe('regularizeClaim()', () => { + const claimFk = 1; + const pendentState = 1; + const resolvedState = 3; + const trashDestination = 2; + const trashAddress = 12; + let claimEnds = []; + let trashTicket; + + afterAll(async() => { + let claim = await app.models.Claim.findById(claimFk); + await claim.updateAttributes({claimStateFk: pendentState}); + await app.models.Ticket.destroyById(trashTicket.id); + + claimEnds.forEach(async line => { + await line.destroy(); + }); + }); + + it('should change claim state to resolved', async() => { + let ctx = {req: {accessToken: {userId: 18}}}; + let params = {claimFk: claimFk}; + + claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, { + claimFk: claimFk, + ticketFk: 1 + }); + + claimEnds.forEach(async claimEnd => { + claimEnd.updateAttributes({claimDestinationFk: trashDestination}); + }); + + let claimBefore = await app.models.Claim.findById(params.claimFk); + await app.models.Claim.regularizeClaim(ctx, params); + let claimAfter = await app.models.Claim.findById(params.claimFk); + + trashTicket = await app.models.Ticket.findOne({where: {addressFk: 12}}); + + expect(trashTicket.addressFk).toEqual(trashAddress); + expect(claimBefore.claimStateFk).toEqual(pendentState); + expect(claimAfter.claimStateFk).toEqual(resolvedState); + }); +}); diff --git a/services/claim/common/models/claim-destination.json b/services/claim/common/models/claim-destination.json index ea3228bb0..6a0774449 100644 --- a/services/claim/common/models/claim-destination.json +++ b/services/claim/common/models/claim-destination.json @@ -18,6 +18,13 @@ "required": true } }, + "relations": { + "address": { + "type": "belongsTo", + "model": "Address", + "foreignKey": "addressFk" + } + }, "acls": [ { "accessType": "READ", diff --git a/services/claim/common/models/claim.js b/services/claim/common/models/claim.js index cd5f1f08e..dc07ebea7 100644 --- a/services/claim/common/models/claim.js +++ b/services/claim/common/models/claim.js @@ -2,4 +2,5 @@ module.exports = Self => { require('../methods/claim/getSummary')(Self); require('../methods/claim/createFromSales')(Self); require('../methods/claim/updateClaim')(Self); + require('../methods/claim/regularizeClaim')(Self); }; diff --git a/services/client/common/models/credit-insurance.js b/services/client/common/models/credit-insurance.js index 264e85cc6..fce2a03dd 100644 --- a/services/client/common/models/credit-insurance.js +++ b/services/client/common/models/credit-insurance.js @@ -71,13 +71,15 @@ module.exports = function(Self) { let customer = insurance.classification().customer(); if (!customer.salesPerson()) return; - let salesPerson = customer.salesPerson().user().name; + let salesPersonId = customer.salesPerson().user().id; let grade = data.grade ? `(Grado ${data.grade})` : '(Sin grado)'; - let message = { - message: `He cambiado el crédito asegurado del cliente "${customer.name}" a ${data.credit} € ${grade}` + let params = { + recipientFk: salesPersonId, + message: `He cambiado el crédito asegurado del ` + + `cliente "${customer.name}" a ${data.credit} € ${grade}` }; - Self.app.models.Message.send(salesPerson, message, ctx); + Self.app.models.Message.send(ctx, params); }; // Update from transaction misses ctx accessToken. diff --git a/services/db/install/changes/1.2-CHECK/06.ACL.sql b/services/db/install/changes/1.2-CHECK/06.ACL.sql index a8bf32860..b2bcb70ec 100644 --- a/services/db/install/changes/1.2-CHECK/06.ACL.sql +++ b/services/db/install/changes/1.2-CHECK/06.ACL.sql @@ -4,7 +4,10 @@ VALUES (105, 'ItemBarcode', '*', 'WRITE', 'ALLOW', 'ROLE', 'marketingBoss'), (106, 'ItemBotanical', '*', 'WRITE', 'ALLOW', 'ROLE', 'marketingBoss'), (107, 'ItemNiche', '*', 'WRITE', 'ALLOW', 'ROLE', 'marketingBoss'), -(108, 'ItemPlacement', '*', 'WRITE', 'ALLOW', 'ROLE', 'marketingBoss'); +(108, 'ItemPlacement', '*', 'WRITE', 'ALLOW', 'ROLE', 'marketingBoss'), +(109, 'UserConfig', '*', '*', 'ALLOW', 'ROLE', 'employee'), +(110, 'Bank', '*', 'READ', 'ALLOW', 'ROLE', 'employee'); + UPDATE salix.ACL SET model='ItemTag', property='*', accessType='WRITE', permission='ALLOW', principalType='ROLE', principalId='marketingBoss' diff --git a/services/db/install/changes/1.2-CHECK/08-itemDiary.sql b/services/db/install/changes/1.2-CHECK/08-itemDiary.sql new file mode 100644 index 000000000..3994672fb --- /dev/null +++ b/services/db/install/changes/1.2-CHECK/08-itemDiary.sql @@ -0,0 +1,119 @@ +USE `vn`; +DROP procedure IF EXISTS `itemDiary`; + +DELIMITER $$ +USE `vn`$$ +CREATE DEFINER=`root`@`%` PROCEDURE `itemDiary`(IN vItemId INT, IN vWarehouse INT) +BEGIN + DECLARE vDateInventory DATETIME; + DECLARE vCurdate DATE DEFAULT CURDATE(); + DECLARE vDayEnd DATETIME DEFAULT util.dayEnd(vCurdate); + -- traduccion: date, alertLevel, origin, reference, name, In, Out, Balance + SELECT Fechainventario INTO vDateInventory FROM vn2008.tblContadores; + SET @a = 0; + SELECT sql_no_cache DATE(date) AS date, + alertLevel, + stateName, + origin, + reference, + clientFk, + name, + `in`, + `out`, + @a := @a + IFNULL(`in`,0) - IFNULL(`out`,0) as balance, + isPicked, + isTicket + FROM + ( SELECT tr.landed as date, + b.quantity as `in`, + NULL as `out`, + IF(tr.isReceived != FALSE,3, IF(tr.isDelivered,1,0)) as alertLevel, + st.name AS stateName, + s.name as name, + e.ref as reference, + e.id as origin, + s.id as clientFk, + TRUE isPicked, + FALSE AS isTicket + FROM vn.buy b + JOIN vn.entry e ON e.id = b.entryFk + JOIN vn.travel tr ON tr.id = e.travelFk + JOIN vn.supplier s ON s.id = e.supplierFk + JOIN vn.alertLevel al ON al.alertLevel = + CASE + WHEN tr.isReceived != FALSE THEN 3 + WHEN tr.isDelivered THEN 1 + ELSE 0 + END + JOIN vn.state st ON st.code = al.code + WHERE tr.landed >= vDateInventory + AND vWarehouse = tr.warehouseInFk + AND b.itemFk = vItemId + AND e.isInventory = 0 + + UNION ALL + + SELECT tr.shipped as date, + NULL as `in`, + b.quantity as `out`, + IF(tr.isReceived != FALSE,3, IF(tr.isDelivered,1,0)) as alertLevel, + st.name AS stateName, + s.name as name, + e.ref as reference, + e.id as origin, + s.id as clientFk, + TRUE isPicked, + FALSE AS isTicket + FROM vn.buy b + JOIN vn.entry e ON e.id = b.entryFk + JOIN vn.travel tr ON tr.id = e.travelFk + JOIN vn.warehouse w ON w.id = tr.warehouseOutFk + JOIN vn.supplier s ON s.id = e.supplierFk + JOIN vn.alertLevel al ON al.alertLevel = + CASE + WHEN tr.isReceived != FALSE THEN 3 + WHEN tr.isDelivered THEN 1 + ELSE 0 + END + JOIN vn.state st ON st.code = al.code + WHERE tr.shipped >= vDateInventory + AND vWarehouse =tr.warehouseOutFk + AND s.id <> 4 + AND b.itemFk = vItemId + AND e.isInventory = 0 + AND w.isFeedStock = 0 + + UNION ALL + + SELECT t.shipped as date, + NULL as `in`, + s.quantity as `out`, + al.alertLevel as alertLevel, + st.name AS stateName, + t.nickname as name, + t.refFk as reference, + t.id as origin, + t.clientFk, + TRUE as isPicked, -- stk.id as isPicked + TRUE as isTicket + FROM vn.sale s + JOIN vn.ticket t ON t.id = s.ticketFk + LEFT JOIN vn.ticketState ts ON ts.ticket = t.id + JOIN vn.client c ON c.id = t.clientFk + JOIN vn.alertLevel al ON al.alertLevel = + CASE + WHEN t.shipped < vCurdate THEN 3 + WHEN t.shipped > vDayEnd THEN 0 + ELSE IFNULL(ts.alertLevel, 0) + END + JOIN vn.state st ON st.code = al.code + -- LEFT JOIN vn.saleTracking stk ON stk.saleFk = s.id AND stk.stateFk = 14 + WHERE t.shipped >= vDateInventory + AND s.itemFk = vItemId + AND vWarehouse =t.warehouseFk + ) AS itemDiary + ORDER BY date DESC, alertLevel DESC, isPicked DESC, `in` DESC, `out` DESC; +END$$ + +DELIMITER ; + diff --git a/services/db/install/dump/fixtures.sql b/services/db/install/dump/fixtures.sql index 32bf30f9c..7f9009a04 100644 --- a/services/db/install/dump/fixtures.sql +++ b/services/db/install/dump/fixtures.sql @@ -483,7 +483,7 @@ INSERT INTO `vn`.`taxCode`(`id`, `dated`, `code`, `taxTypeFk`, `rate`, `equaliza VALUES (1 , CURDATE(), '1111111111', 1, 7.0 , 0.0, 'R', 1, 1, CURDATE(), 1), (2 , CURDATE(), '2222222222', 2, 16.0, 0.0, 'G', 2, 1, CURDATE(), 1), - (21 , CURDATE(), '3333333333', 1, 18.0, 0.0, 'R', 3, 1, CURDATE(), 1), + (21 , CURDATE(), '3333333333', 1, 7.0, 0.0, 'R', 3, 1, CURDATE(), 1), (108, CURDATE(), '4444444444', 2, 8.0 , 0.0, 'R', 4, 1, CURDATE(), 1); INSERT INTO `vn`.`taxClass`(`id`, `description`, `code`) @@ -928,4 +928,7 @@ INSERT INTO `vn`.`orderTicket`(`orderFk`, `ticketFk`) (18, 18), (19, 19), (20, 20), - (21, 21); \ No newline at end of file + (21, 21); + +INSERT INTO `vn`.`userConfig` (`userFk`, `warehouseFk`, `companyFk`) + VALUES (9, 1, 442); diff --git a/services/loopback/common/locale/es.json b/services/loopback/common/locale/es.json index 21e049ff2..1309790ef 100644 --- a/services/loopback/common/locale/es.json +++ b/services/loopback/common/locale/es.json @@ -51,5 +51,6 @@ "You don't have enough privileges to change that field": "No tienes permisos para cambiar ese campo", "Warehouse cannot be blank": "El almacén no puede quedar en blanco", "Agency cannot be blank": "La agencia no puede quedar en blanco", - "You don't have enough privileges to do that": "No tienes permisos para para hacer esto" + "You don't have enough privileges to do that": "No tienes permisos para para hacer esto", + "This address doesn't exist": "This address doesn't exist" } \ No newline at end of file diff --git a/services/loopback/common/methods/message/send.js b/services/loopback/common/methods/message/send.js index b7bf00965..3b2ab1f16 100644 --- a/services/loopback/common/methods/message/send.js +++ b/services/loopback/common/methods/message/send.js @@ -1,18 +1,12 @@ module.exports = Self => { - Self.remoteMethod('send', { + Self.remoteMethodCtx('send', { description: 'Send message to user', accessType: 'WRITE', accepts: [{ - arg: 'recipient', - type: 'string', - required: true, - description: 'The user/alias name', - http: {source: 'path'} - }, { arg: 'data', type: 'object', required: true, - description: 'Message data', + description: 'recipientFk, message', http: {source: 'body'} }, { arg: 'context', @@ -31,10 +25,23 @@ module.exports = Self => { } }); - Self.send = async(recipient, data, ctx) => { - let query = `SELECT vn.messageSendWithUser(?, ?, ?) AS sent`; - let [result] = await Self.rawSql(query, [ctx.req.accessToken.userId, recipient, data.message]); + Self.send = async(ctx, data, transaction) => { + const userId = ctx.req.accessToken.userId; + const models = Self.app.models; + const sender = await models.Account.findById(userId, transaction); + const recipient = await models.Account.findById(data.recipientFk, transaction); - return result; + await Self.create({ + sender: sender.name, + recipient: recipient.name, + message: data.message + }, transaction); + + return await models.MessageInbox.create({ + sender: sender.name, + recipient: recipient.name, + finalRecipient: recipient.name, + message: data.message + }, transaction); }; }; diff --git a/services/loopback/common/methods/message/specs/send.spec.js b/services/loopback/common/methods/message/specs/send.spec.js index 869f60987..53045d3a7 100644 --- a/services/loopback/common/methods/message/specs/send.spec.js +++ b/services/loopback/common/methods/message/specs/send.spec.js @@ -3,9 +3,12 @@ const app = require(`${servicesDir}/client/server/server`); describe('message send()', () => { it('should call the send method and return the response', async() => { let ctx = {req: {accessToken: {userId: 1}}}; - await app.models.Message.send('salesPerson', {message: 'I changed something'}, ctx) - .then(response => { - expect(response.sent).toEqual(1); - }); + let params = { + recipientFk: 1, + message: 'I changed something' + }; + let response = await app.models.Message.send(ctx, params, {transaction: 'You'}); + + expect(response.message).toEqual(params.message); }); }); diff --git a/services/loopback/common/methods/userConfig/getUserConfig.js b/services/loopback/common/methods/userConfig/getUserConfig.js new file mode 100644 index 000000000..665d00966 --- /dev/null +++ b/services/loopback/common/methods/userConfig/getUserConfig.js @@ -0,0 +1,21 @@ +module.exports = function(Self) { + Self.remoteMethodCtx('getUserConfig', { + description: 'returns the information from UserConfig model for the active user', + accepts: [], + returns: { + type: 'object', + root: true + }, + http: { + path: `/getUserConfig`, + verb: 'get' + } + }); + + Self.getUserConfig = async ctx => { + let token = ctx.req.accessToken; + let currentUserId = token && token.userId; + + return await Self.findOne({userFk: currentUserId}); + }; +}; diff --git a/services/loopback/common/methods/userConfig/setUserConfig.js b/services/loopback/common/methods/userConfig/setUserConfig.js new file mode 100644 index 000000000..bd258b832 --- /dev/null +++ b/services/loopback/common/methods/userConfig/setUserConfig.js @@ -0,0 +1,28 @@ +module.exports = function(Self) { + Self.remoteMethodCtx('setUserConfig', { + description: 'Change worker of tickets state', + accepts: [{ + arg: 'params', + type: 'object', + required: true, + description: 'warehouseFk, companyFk', + http: {source: 'body'} + }], + returns: { + arg: 'response', + type: 'object' + }, + http: { + path: `/setUserConfig`, + verb: 'post' + } + }); + + Self.setUserConfig = async(ctx, params) => { + let token = ctx.req.accessToken; + let currentUserId = token && token.userId; + params.userFk = currentUserId; + + return await Self.app.models.UserConfig.upsertWithWhere({userFk: currentUserId}, params); + } +}; diff --git a/services/loopback/common/models/bank.json b/services/loopback/common/models/bank.json new file mode 100644 index 000000000..119ea9743 --- /dev/null +++ b/services/loopback/common/models/bank.json @@ -0,0 +1,40 @@ +{ + "name": "Bank", + "base": "VnModel", + "options": { + "mysql": { + "table": "bank" + } + }, + "properties": { + "id": { + "type": "Number", + "id": true, + "description": "Identifier" + }, + "bank": { + "type": "string", + "required": true + }, + "account": { + "type": "string", + "required": true + }, + "cash": { + "type": "string", + "required": true + }, + "entityFk": { + "type": "string", + "required": true + }, + "isActive": { + "type": "string", + "required": true + }, + "currencyFk": { + "type": "string", + "required": true + } + } + } \ No newline at end of file diff --git a/services/loopback/common/models/client-log.json b/services/loopback/common/models/client-log.json index fd5a06329..947036d79 100644 --- a/services/loopback/common/models/client-log.json +++ b/services/loopback/common/models/client-log.json @@ -17,8 +17,7 @@ "required": true }, "userFk": { - "type": "Number", - "required": true + "type": "Number" }, "action": { "type": "String", diff --git a/services/loopback/common/models/loggable.js b/services/loopback/common/models/loggable.js index d01a3062b..902dc1291 100644 --- a/services/loopback/common/models/loggable.js +++ b/services/loopback/common/models/loggable.js @@ -127,7 +127,7 @@ module.exports = function(Self) { let userFk; - if (!loopBackContext) userFk = process.env.NODE_ENV ? 1765 : 111; + if (!loopBackContext) userFk = null; else userFk = loopBackContext.active.accessToken.userId; let action = setActionType(ctx); diff --git a/services/loopback/common/models/message-inbox.json b/services/loopback/common/models/message-inbox.json new file mode 100644 index 000000000..238f3e590 --- /dev/null +++ b/services/loopback/common/models/message-inbox.json @@ -0,0 +1,43 @@ +{ + "name": "MessageInbox", + "base": "VnModel", + "options": { + "mysql": { + "table": "messageInbox" + } + }, + "properties": { + "id": { + "type": "Number", + "id": true, + "description": "Identifier" + }, + "sender": { + "type": "String", + "required": true + }, + "recipient": { + "type": "String", + "required": true + }, + "finalRecipient": { + "type": "String", + "required": true + }, + "message": { + "type": "String" + } + }, + "relations": { + "remitter": { + "type": "belongsTo", + "model": "User", + "foreignKey": "sender" + }, + "receptor": { + "type": "belongsTo", + "model": "User", + "foreignKey": "recipient" + } + } +} \ No newline at end of file diff --git a/services/loopback/common/models/user-config.js b/services/loopback/common/models/user-config.js new file mode 100644 index 000000000..c6c26e00b --- /dev/null +++ b/services/loopback/common/models/user-config.js @@ -0,0 +1,4 @@ +module.exports = Self => { + require('../methods/userConfig/setUserConfig')(Self); + require('../methods/userConfig/getUserConfig')(Self); +}; diff --git a/services/loopback/common/models/user-config.json b/services/loopback/common/models/user-config.json new file mode 100644 index 000000000..4e4974bfb --- /dev/null +++ b/services/loopback/common/models/user-config.json @@ -0,0 +1,46 @@ +{ + "name": "UserConfig", + "base": "VnModel", + "options": { + "mysql": { + "table": "userConfig", + "database": "vn" + } + }, + "properties": { + "userFk": { + "id": true, + "type": "Number", + "required": true + }, + "warehouseFk": { + "type": "Number" + }, + "companyFk": { + "type": "Number" + }, + "created": { + "type": "Date" + }, + "updated": { + "type": "Date" + } + }, + "relations": { + "warehouse": { + "type": "belongsTo", + "model": "Warehouse", + "foreignKey": "warehouseFk" + }, + "company": { + "type": "belongsTo", + "model": "Company", + "foreignKey": "companyFk" + }, + "account": { + "type": "belongsTo", + "model": "Account", + "foreignKey": "userFk" + } + } +} diff --git a/services/loopback/server/model-config.json b/services/loopback/server/model-config.json index aed0a97f9..be6e36f51 100644 --- a/services/loopback/server/model-config.json +++ b/services/loopback/server/model-config.json @@ -42,6 +42,9 @@ "AgencyMode": { "dataSource": "vn" }, + "Bank": { + "dataSource": "vn" + }, "Client": { "dataSource": "vn" }, @@ -120,10 +123,16 @@ "Message": { "dataSource": "vn" }, + "MessageInbox": { + "dataSource": "vn" + }, "WorkerMana": { "dataSource": "bs" }, "DeliveryMethod": { "dataSource": "vn" + }, + "UserConfig": { + "dataSource": "vn" } } diff --git a/services/order/common/methods/order-row/addToOrder.js b/services/order/common/methods/order-row/addToOrder.js index a3bbb1404..18d0c14b9 100644 --- a/services/order/common/methods/order-row/addToOrder.js +++ b/services/order/common/methods/order-row/addToOrder.js @@ -22,7 +22,6 @@ module.exports = Self => { }); Self.addToOrder = async params => { - console.log(params); let isEditable = await Self.app.models.Order.isEditable(params.orderFk); if (!isEditable)