From b4bed608aba47838e500db6ebf5ceb3d28a4f9df Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 9 Feb 2022 15:01:02 +0100 Subject: [PATCH 01/54] refactor(ticket): getMovable --- db/changes/10411-january/00-ticket_getMovable.sql | 2 +- .../ticket/front/basic-data/step-two/index.html | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/db/changes/10411-january/00-ticket_getMovable.sql b/db/changes/10411-january/00-ticket_getMovable.sql index 5f5b0a93a..051a86a7d 100644 --- a/db/changes/10411-january/00-ticket_getMovable.sql +++ b/db/changes/10411-january/00-ticket_getMovable.sql @@ -17,7 +17,7 @@ BEGIN FROM ticket t WHERE t.id = vTicketFk; - CALL itemStock(vWarehouseFk, DATE_SUB(vDatedNew, INTERVAL 1 DAY), NULL); + CALL itemStock(vWarehouseFk, vDatedNew, NULL); CALL item_getMinacum(vWarehouseFk, vDatedNew, DATEDIFF(vDatedOld, vDatedNew), NULL); SELECT s.id, diff --git a/modules/ticket/front/basic-data/step-two/index.html b/modules/ticket/front/basic-data/step-two/index.html index 092c9e746..af06a0f70 100644 --- a/modules/ticket/front/basic-data/step-two/index.html +++ b/modules/ticket/front/basic-data/step-two/index.html @@ -18,7 +18,14 @@ - {{("000000"+sale.itemFk).slice(-6)}} + + + {{("000000"+sale.itemFk).slice(-6)}} + +
{{::sale.item.name}} @@ -83,5 +90,9 @@
- + + From 135aff27a4caef315760aa1208c8d58ae4a0d3d5 Mon Sep 17 00:00:00 2001 From: alexm Date: Thu, 10 Feb 2022 09:13:48 +0100 Subject: [PATCH 02/54] fix(getMovable): show correct movable --- db/changes/10411-january/00-ticket_getMovable.sql | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/db/changes/10411-january/00-ticket_getMovable.sql b/db/changes/10411-january/00-ticket_getMovable.sql index 051a86a7d..eb5c722c4 100644 --- a/db/changes/10411-january/00-ticket_getMovable.sql +++ b/db/changes/10411-january/00-ticket_getMovable.sql @@ -6,20 +6,23 @@ CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticket_getMovable`(vTicketFk INT, vDat BEGIN /** * Cálcula el stock movible para los artículos de un ticket + * vDatedNew debe ser menor que vDatedOld, en los otros casos se + * asume que siempre es posible * * @param vTicketFk -> Ticket * @param vDatedNew -> Nueva fecha * @return Sales con Movible */ DECLARE vDatedOld DATETIME; - + SET vDatedNew = DATE_ADD(vDatedNew, INTERVAL 1 DAY); + SELECT t.shipped INTO vDatedOld FROM ticket t WHERE t.id = vTicketFk; - CALL itemStock(vWarehouseFk, vDatedNew, NULL); - CALL item_getMinacum(vWarehouseFk, vDatedNew, DATEDIFF(vDatedOld, vDatedNew), NULL); - + CALL itemStock(vWarehouseFk, vDatedNew, NULL); + CALL item_getMinacum(vWarehouseFk, vDatedNew, DATEDIFF(DATE_SUB(vDatedOld, INTERVAL 1 DAY), vDatedNew), NULL); + SELECT s.id, s.itemFk, s.quantity, From 4e5e6dcccad1c5c5dfb29dc01532d56a9c5316e1 Mon Sep 17 00:00:00 2001 From: alexm Date: Thu, 10 Feb 2022 10:15:43 +0100 Subject: [PATCH 03/54] fix(test): change movable expeted --- .../ticket/back/methods/ticket/specs/priceDifference.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js index e9aa5030a..d8c785baa 100644 --- a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js +++ b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js @@ -86,8 +86,8 @@ describe('sale priceDifference()', () => { const firstItem = result.items[0]; const secondtItem = result.items[1]; - expect(firstItem.movable).toEqual(440); - expect(secondtItem.movable).toEqual(1980); + expect(firstItem.movable).toEqual(410); + expect(secondtItem.movable).toEqual(1870); await tx.rollback(); } catch (e) { From ac0e55107a6c4c283a75516bc3ec357971538208 Mon Sep 17 00:00:00 2001 From: carlosjr Date: Tue, 15 Feb 2022 12:59:57 +0100 Subject: [PATCH 04/54] 3595 feat(toggleHidden): itemWaste now can hide panels --- modules/item/front/waste/index/index.html | 28 +++++++---- modules/item/front/waste/index/index.js | 29 ++++++++++- modules/item/front/waste/index/index.spec.js | 53 ++++++++++++++++++++ modules/item/front/waste/index/style.scss | 37 +++++++++----- 4 files changed, 123 insertions(+), 24 deletions(-) create mode 100644 modules/item/front/waste/index/index.spec.js diff --git a/modules/item/front/waste/index/index.html b/modules/item/front/waste/index/index.html index 7ad985ea8..c80733e9e 100644 --- a/modules/item/front/waste/index/index.html +++ b/modules/item/front/waste/index/index.html @@ -3,13 +3,21 @@ url="Items/getWasteByWorker" data="details"> - - -
- -
{{detail.buyer}}
-
+
+ +
{{detail.buyer}}
+ + + + +
+ @@ -21,7 +29,7 @@ + ui-sref="item.waste.detail({buyer: waste.buyer, family: waste.family})"> {{::waste.family}} {{::(waste.percentage / 100) | percentage: 2}} {{::waste.dwindle | currency: 'EUR'}} @@ -29,6 +37,6 @@ -
- - + +
+
\ No newline at end of file diff --git a/modules/item/front/waste/index/index.js b/modules/item/front/waste/index/index.js index 15e6b063f..b11f54b08 100644 --- a/modules/item/front/waste/index/index.js +++ b/modules/item/front/waste/index/index.js @@ -2,7 +2,34 @@ import ngModule from '../../module'; import Section from 'salix/components/section'; import './style.scss'; +export default class Controller extends Section { + constructor($element, $) { + super($element, $); + + this.getWasteConfig(); + } + + getWasteConfig() { + return this.wasteConfig = JSON.parse(localStorage.getItem('wasteConfig')) || {}; + } + + setWasteConfig() { + localStorage.setItem('wasteConfig', JSON.stringify(this.wasteConfig)); + } + + toggleHidePanel(detail) { + if (!this.wasteConfig[detail.buyer]) { + this.wasteConfig[detail.buyer] = { + hidden: true + }; + } else + this.wasteConfig[detail.buyer].hidden = !this.wasteConfig[detail.buyer].hidden; + + this.setWasteConfig(); + } +} + ngModule.vnComponent('vnItemWasteIndex', { template: require('./index.html'), - controller: Section + controller: Controller }); diff --git a/modules/item/front/waste/index/index.spec.js b/modules/item/front/waste/index/index.spec.js new file mode 100644 index 000000000..575e773bd --- /dev/null +++ b/modules/item/front/waste/index/index.spec.js @@ -0,0 +1,53 @@ +import './index.js'; +import crudModel from 'core/mocks/crud-model'; + +fdescribe('Item', () => { + describe('Component vnItemWasteIndex', () => { + let $scope; + let controller; + + beforeEach(ngModule('item')); + + beforeEach(inject(($componentController, $rootScope) => { + $scope = $rootScope.$new(); + $scope.model = crudModel; + const $element = angular.element(''); + controller = $componentController('vnItemWasteIndex', {$element, $scope}); + })); + + describe('getWasteConfig / setWasteConfig', () => { + it('should return the local storage wasteConfig', () => { + const result = controller.getWasteConfig(); + + expect(result).toEqual({}); + }); + + it('should set and return the local storage wasteConfig', () => { + controller.wasteConfig = {salesPerson: {hidden: true}}; + controller.setWasteConfig(); + + const result = controller.getWasteConfig(); + + expect(result).toEqual(controller.wasteConfig); + }); + }); + + describe('toggleHidePanel()', () => { + it('should make details hidden by default', () => { + controller.wasteConfig = {}; + + controller.toggleHidePanel({buyer: 'salesPerson'}); + + expect(controller.wasteConfig.salesPerson.hidden).toEqual(true); + }); + + it('should toggle hidden false', () => { + controller.wasteConfig = {salesPerson: {hidden: true}}; + + controller.toggleHidePanel({buyer: 'salesPerson'}); + + expect(controller.wasteConfig.salesPerson.hidden).toEqual(false); + }); + }); + }); +}); diff --git a/modules/item/front/waste/index/style.scss b/modules/item/front/waste/index/style.scss index faac46139..8b44cb6f1 100644 --- a/modules/item/front/waste/index/style.scss +++ b/modules/item/front/waste/index/style.scss @@ -1,21 +1,24 @@ @import "variables"; +@import "effects"; vn-item-waste-index, vn-item-waste-detail { .header { - margin-bottom: 16px; - text-transform: uppercase; - font-size: 1.25rem; - line-height: 1; - padding: 7px; - padding-bottom: 7px; - padding-bottom: 4px; - font-weight: lighter; - background-color: $color-bg; - border-bottom: 1px solid #f7931e; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + padding: 12px 0 5px 0; + color: gray; + font-size: 1.2rem; + border-bottom: $border; + margin-bottom: 10px; + + & > vn-none > vn-icon { + @extend %clickable-light; + color: $color-button; + font-size: 1.4rem; + } + + vn-none > .arrow { + transition: transform 200ms; + } } vn-table vn-th.waste-family, @@ -23,4 +26,12 @@ vn-item-waste-detail { max-width: 64px; width: 64px } + .hidden { + display: none; + + } + .header > vn-none > .arrow.hidden { + display: block; + transform: rotate(180deg); + } } \ No newline at end of file From 401174b27a69ae0d461d735801fdb4e7866e7326 Mon Sep 17 00:00:00 2001 From: carlosjr Date: Tue, 15 Feb 2022 13:46:25 +0100 Subject: [PATCH 05/54] removed focus on describe --- modules/item/front/waste/index/index.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/item/front/waste/index/index.spec.js b/modules/item/front/waste/index/index.spec.js index 575e773bd..fd7332f68 100644 --- a/modules/item/front/waste/index/index.spec.js +++ b/modules/item/front/waste/index/index.spec.js @@ -1,7 +1,7 @@ import './index.js'; import crudModel from 'core/mocks/crud-model'; -fdescribe('Item', () => { +describe('Item', () => { describe('Component vnItemWasteIndex', () => { let $scope; let controller; From 651c92698fd193bc5f40a4b9d812d283aceb5bc4 Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 15 Feb 2022 16:48:37 +0100 Subject: [PATCH 06/54] feat(docuware): start download docuware --- back/methods/docuware/download.js | 88 +++++++++++++++++++ back/model-config.json | 3 + back/models/docuware.js | 3 + back/models/docuware.json | 38 ++++++++ .../10420-valentines/00-aclDocuware.sql | 3 + db/changes/10420-valentines/00-docuware.sql | 11 +++ .../10420-valentines/00-docuwareConfig.sql | 9 ++ .../back/methods/invoiceOut/docuware.js | 65 ++++++++++++++ modules/invoiceOut/back/models/invoice-out.js | 1 + .../front/descriptor-menu/index.html | 5 ++ .../invoiceOut/front/descriptor-menu/index.js | 13 +++ 11 files changed, 239 insertions(+) create mode 100644 back/methods/docuware/download.js create mode 100644 back/models/docuware.js create mode 100644 back/models/docuware.json create mode 100644 db/changes/10420-valentines/00-aclDocuware.sql create mode 100644 db/changes/10420-valentines/00-docuware.sql create mode 100644 db/changes/10420-valentines/00-docuwareConfig.sql create mode 100644 modules/invoiceOut/back/methods/invoiceOut/docuware.js diff --git a/back/methods/docuware/download.js b/back/methods/docuware/download.js new file mode 100644 index 000000000..01e552d2d --- /dev/null +++ b/back/methods/docuware/download.js @@ -0,0 +1,88 @@ +const got = require('got'); +const {createWriteStream} = require('fs'); +const UserError = require('vn-loopback/util/user-error'); + +module.exports = Self => { + Self.remoteMethodCtx('download', { + description: 'Download an invoice PDF', + accessType: 'READ', + accepts: [ + { + arg: 'ticketId', + type: 'number', + description: 'The invoiceable ticket id' + }, + ], + returns: { + type: 'object', + root: true + }, + http: { + path: `/download`, + verb: 'POST' + } + }); + + Self.download = async function(ctx, ticketId) { + // const fileCabinet = 'ad2c49df-8976-4941-bb19-9b30685f14a4'; + // hay que crear tambien una busqueda por cada fileCabinet + // columnas necesarias. seccion, fileCabinet, DBName, dialog + const models = Self.app.models; + const [docuwareConfig] = await Self.rawSql(`SELECT * FROM vn.docuwareConfig;`); + const docuwareInfo = await models.Docuware.findOne({ + where: { + name: 'deliveryClient', + dialogName: 'findTicket' + } + }); + console.log(docuwareConfig, docuwareInfo); + + const docuwareUrl = docuwareConfig.url; + const cookie = docuwareConfig.token; + const fileCabinetName = docuwareInfo.fileCabinetName; + const find = docuwareInfo.find; + + // get fileCabinetId + const options = { + 'headers': { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Cookie': cookie + } + }; + + const fileCabinetResponse = await got.get(`${docuwareUrl}/FileCabinets`, options).json(); + const fileCabinetId = fileCabinetResponse.FileCabinet.find(dialogs => dialogs.Name === fileCabinetName).Id; + + // get dialogs + const dialogResponse = await got.get(`${docuwareUrl}/FileCabinets/${fileCabinetId}/dialogs`, options).json(); + console.log(dialogResponse); + const dialogId = dialogResponse.Dialog.find(dialogs => dialogs.DisplayName === 'find').Id; + + console.log(fileCabinetId, dialogId); + /* + // get DocuwareID + const docuwareOptions = { + 'headers': { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Cookie': cookie + }, + 'body': JSON.stringify({'Condition': [{DBName: find, Value: [ticketId]}]}) + }; + const response = await got.post(`${docuwareUrl}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`, docuwareOptions); + const docuwareId = JSON.parse(response.body).Items[0].Id; + + // download file + const downloadUrl = `${docuwareUrl}/FileCabinets/${fileCabinetId}/Documents/${docuwareId}/FileDownload?targetFileType=Auto&keepAnnotations=false`; + const downloadOptions = { + 'headers': { + 'Cookie': cookie + } + }; + + const file = await got.stream(downloadUrl, downloadOptions).pipe(createWriteStream(`${ticketId}_${docuwareId}.pdf`)); + + // return [file, 'application/pdf', `filename="${ticketId}_${docuwareId}.pdf"`];*/ + }; +}; diff --git a/back/model-config.json b/back/model-config.json index 8ad15a16a..7be2174e6 100644 --- a/back/model-config.json +++ b/back/model-config.json @@ -44,6 +44,9 @@ "DmsType": { "dataSource": "vn" }, + "Docuware": { + "dataSource": "vn" + }, "EmailUser": { "dataSource": "vn" }, diff --git a/back/models/docuware.js b/back/models/docuware.js new file mode 100644 index 000000000..8a6b0cd93 --- /dev/null +++ b/back/models/docuware.js @@ -0,0 +1,3 @@ +module.exports = Self => { + require('../methods/docuware/download')(Self); +}; diff --git a/back/models/docuware.json b/back/models/docuware.json new file mode 100644 index 000000000..f85397072 --- /dev/null +++ b/back/models/docuware.json @@ -0,0 +1,38 @@ +{ + "name": "Docuware", + "description": "Docuware sections", + "base": "VnModel", + "options": { + "mysql": { + "table": "docuware" + } + }, + "properties": { + "id": { + "type": "number", + "id": true, + "description": "Identifier" + }, + "name": { + "type": "string" + }, + "fileCabinetName": { + "type": "string" + }, + "dialogName": { + "type": "string" + }, + "find": { + "type": "string" + } + }, + "acls": [ + { + "property": "*", + "accessType": "*", + "principalType": "ROLE", + "principalId": "$everyone", + "permission": "ALLOW" + } + ] +} \ No newline at end of file diff --git a/db/changes/10420-valentines/00-aclDocuware.sql b/db/changes/10420-valentines/00-aclDocuware.sql new file mode 100644 index 000000000..21ed66c4c --- /dev/null +++ b/db/changes/10420-valentines/00-aclDocuware.sql @@ -0,0 +1,3 @@ +INSERT INTO salix.ACL +(model, property, accessType, permission, principalType, principalId) +VALUES('Docuware', '*', '*', 'ALLOW', 'ROLE', 'employee'); \ No newline at end of file diff --git a/db/changes/10420-valentines/00-docuware.sql b/db/changes/10420-valentines/00-docuware.sql new file mode 100644 index 000000000..dd915ddcd --- /dev/null +++ b/db/changes/10420-valentines/00-docuware.sql @@ -0,0 +1,11 @@ +CREATE TABLE `vn`.`docuware` ( + `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, + `name` varchar(50) NULL, + `fileCabinetName` varchar(50) NULL, + `dialogName` varchar(255) DEFAULT NULL, + `find` varchar(50) DEFAULT NULL +); + +INSERT INTO `vn`.`docuware` +(name, fileCabinetName, dialogName , find) +VALUES('deliveryClient', 'Albaranes cliente', 'findTicket', 'N__ALBAR_N'); diff --git a/db/changes/10420-valentines/00-docuwareConfig.sql b/db/changes/10420-valentines/00-docuwareConfig.sql new file mode 100644 index 000000000..0ef190cb7 --- /dev/null +++ b/db/changes/10420-valentines/00-docuwareConfig.sql @@ -0,0 +1,9 @@ +CREATE TABLE `vn`.`docuwareConfig` ( + `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, + `url` varchar(75) NULL, + `token` varchar(1000) DEFAULT NULL +); + +INSERT INTO `vn`.`docuwareConfig` +(url, token) +VALUES('https://verdnatura.docuware.cloud/docuware/platform/', '.DWPLATFORMAUTH=66C7DCD2B9365EF974AFEB43F61715152082EF39C649CB1506F9ACC34DD54C5B34944DDFBF97EAE5C5147063850B16B3B9FFFB2232FDD03F35B51B1305D5E1E7DB833F6AC560C739E40778932C8BCC64DA7ECE64B0B1F71A3DB986B3710DFA4C061776F9C61DDAA60EF30F7F37FB8733BF4B1830F98102E403E4E751F13F31B582AEDF5B33A25346E10CA34A8559F0CD6ACA39A7379AC67BE061CD27531D02675123FB0D254426E306EC6FA49DED7CF30EBBAD8365BE60D7E919D4AD2EB8F9CD94424DFCD95151C0F6DD3EE8569A7CA4A30D1A3F42DA9DD368A33955A4AFE9CB4FCCC230801BC645AA87A68EC33F6BD165D5A0F02B63D5D832AF936B9398EC428D4ACD41E56848A2CDF797C99226BB2AC48EB5F9C1C5D8C1C7F6A7F67F455ABAC1DBC7443521876B588F369CAE6EC81747BA3134F7EE2662DA296FC2C16528B0AB4839EEE6EE79A82AA3888E4AB53FEC6FFAD26A592ABD76441AFCD634097D0B0B57E16A510D0E6F769710C6F4BDB1476CCDE0967788B90A67BADFB7E37B1F7F60C879A0E9D75AD2BA6647FC11477305B44512AF408845E6099CF64B7A3D77EE; ApplicationGatewayAffinity=c5fad6cb3332163516d49258a1ebf52c; ApplicationGatewayAffinityCORS=c5fad6cb3332163516d49258a1ebf52c; DWPLATFORMBROWSERID=C2173B1A1FE42B449AA12C8465561991BA4664AFA9F44D4C9DD8748FF92EFEBF629E4A75860747C4D8290F70344385CCAFE3EAFD8814CF44F452275C95E89D19D35A178D0BCC6930EF07AC7CF91672F7CB43C2B54CDFAE52BDF17C467FFFE3411FE0D792E4F513726F295648DDE627DF2C6288C89086E2DE6916E4B0A5291AA7C269015A5328147783EC15FB8EF43EE5DAE5A6CD3D318570670234176CAE7B19D9812D3F09D731C5A27A621B39D0564C81774FA993160AAAD833CC75634445B7B47C5A2E26004FF914606B5B0CB897A694F26AD5E80A1EE0D3B7BA4881F8A570'); diff --git a/modules/invoiceOut/back/methods/invoiceOut/docuware.js b/modules/invoiceOut/back/methods/invoiceOut/docuware.js new file mode 100644 index 000000000..aa58aaed1 --- /dev/null +++ b/modules/invoiceOut/back/methods/invoiceOut/docuware.js @@ -0,0 +1,65 @@ +const got = require('got'); +const {createWriteStream} = require('fs'); +const UserError = require('vn-loopback/util/user-error'); + +module.exports = Self => { + Self.remoteMethodCtx('docuware', { + description: 'Download an invoice PDF', + accessType: 'READ', + accepts: [ + { + arg: 'ticketId', + type: 'number', + description: 'The invoiceable ticket id' + }, + ], + returns: { + type: 'object', + root: true + }, + http: { + path: `/docuware`, + verb: 'POST' + } + }); + + Self.docuware = async function(ctx, ticketId) { + // const fileCabinet = 'ad2c49df-8976-4941-bb19-9b30685f14a4'; + // hay que crear tambien una busqueda por cada fileCabinet + // columnas necesarias. seccion, fileCabinet, DBName, dialog + const models = Self.app.models; + const docuwareInfo = await models.Docuware.findOne({ + where: { + name: 'albaran' + } + }); + console.log(docuwareInfo); + const fileCabinet = docuwareInfo.fileCabinet; + const find = docuwareInfo.find; + const dialog = docuwareInfo.dialog; + const docuwareUrl = `https://verdnatura.docuware.cloud/docuware/platform/FileCabinets/${fileCabinet}`; + const cookie = '.DWPLATFORMAUTH=66C7DCD2B9365EF974AFEB43F61715152082EF39C649CB1506F9ACC34DD54C5B34944DDFBF97EAE5C5147063850B16B3B9FFFB2232FDD03F35B51B1305D5E1E7DB833F6AC560C739E40778932C8BCC64DA7ECE64B0B1F71A3DB986B3710DFA4C061776F9C61DDAA60EF30F7F37FB8733BF4B1830F98102E403E4E751F13F31B582AEDF5B33A25346E10CA34A8559F0CD6ACA39A7379AC67BE061CD27531D02675123FB0D254426E306EC6FA49DED7CF30EBBAD8365BE60D7E919D4AD2EB8F9CD94424DFCD95151C0F6DD3EE8569A7CA4A30D1A3F42DA9DD368A33955A4AFE9CB4FCCC230801BC645AA87A68EC33F6BD165D5A0F02B63D5D832AF936B9398EC428D4ACD41E56848A2CDF797C99226BB2AC48EB5F9C1C5D8C1C7F6A7F67F455ABAC1DBC7443521876B588F369CAE6EC81747BA3134F7EE2662DA296FC2C16528B0AB4839EEE6EE79A82AA3888E4AB53FEC6FFAD26A592ABD76441AFCD634097D0B0B57E16A510D0E6F769710C6F4BDB1476CCDE0967788B90A67BADFB7E37B1F7F60C879A0E9D75AD2BA6647FC11477305B44512AF408845E6099CF64B7A3D77EE; ApplicationGatewayAffinity=c5fad6cb3332163516d49258a1ebf52c; ApplicationGatewayAffinityCORS=c5fad6cb3332163516d49258a1ebf52c; DWPLATFORMBROWSERID=C2173B1A1FE42B449AA12C8465561991BA4664AFA9F44D4C9DD8748FF92EFEBF629E4A75860747C4D8290F70344385CCAFE3EAFD8814CF44F452275C95E89D19D35A178D0BCC6930EF07AC7CF91672F7CB43C2B54CDFAE52BDF17C467FFFE3411FE0D792E4F513726F295648DDE627DF2C6288C89086E2DE6916E4B0A5291AA7C269015A5328147783EC15FB8EF43EE5DAE5A6CD3D318570670234176CAE7B19D9812D3F09D731C5A27A621B39D0564C81774FA993160AAAD833CC75634445B7B47C5A2E26004FF914606B5B0CB897A694F26AD5E80A1EE0D3B7BA4881F8A570'; + + // get DocuwareID + const dialogOptions = { + 'headers': { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Cookie': cookie + }, + 'body': JSON.stringify({'Condition': [{DBName: find, Value: [ticketId]}]}) + }; + const response = await got.post(`${docuwareUrl}/Query/DialogExpression?dialogId=${dialog}`, dialogOptions); + const docuwareId = JSON.parse(response.body).Items[0].Id; + + // download file + const downloadUrl = `${docuwareUrl}/Documents/${docuwareId}/FileDownload?targetFileType=Auto&keepAnnotations=false`; + const downloadOptions = { + 'headers': { + 'Cookie': cookie + } + }; + + await got.stream(downloadUrl, downloadOptions).pipe(createWriteStream(`${ticketId}_${docuwareId}.pdf`)); + }; +}; diff --git a/modules/invoiceOut/back/models/invoice-out.js b/modules/invoiceOut/back/models/invoice-out.js index 3b2822ada..3da5aedc6 100644 --- a/modules/invoiceOut/back/models/invoice-out.js +++ b/modules/invoiceOut/back/models/invoice-out.js @@ -3,6 +3,7 @@ module.exports = Self => { require('../methods/invoiceOut/summary')(Self); require('../methods/invoiceOut/getTickets')(Self); require('../methods/invoiceOut/download')(Self); + require('../methods/invoiceOut/docuware')(Self); require('../methods/invoiceOut/delete')(Self); require('../methods/invoiceOut/book')(Self); require('../methods/invoiceOut/createPdf')(Self); diff --git a/modules/invoiceOut/front/descriptor-menu/index.html b/modules/invoiceOut/front/descriptor-menu/index.html index 3b30f891c..070da18e1 100644 --- a/modules/invoiceOut/front/descriptor-menu/index.html +++ b/modules/invoiceOut/front/descriptor-menu/index.html @@ -20,6 +20,11 @@ translate> Show as PDF + + Show as DOCUWARE + diff --git a/modules/invoiceOut/front/descriptor-menu/index.js b/modules/invoiceOut/front/descriptor-menu/index.js index 7738845f9..f6855795a 100644 --- a/modules/invoiceOut/front/descriptor-menu/index.js +++ b/modules/invoiceOut/front/descriptor-menu/index.js @@ -88,6 +88,19 @@ class Controller extends Section { }); } + downloadDocuware() { + const options = { + ticketId: 3367050 + }; + + return this.$http.post(`Docuwares/download`, options) + .then(() => { + const snackbarMessage = this.$t( + `The invoice PDF document has been downloaded`); + this.vnApp.showSuccess(snackbarMessage); + }); + } + sendPdfInvoice($data) { if (!$data.email) return this.vnApp.showError(this.$t(`The email can't be empty`)); From 3aeb2adb56bc5e4db554f02001748c9b9aacfc8f Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 16 Feb 2022 14:57:47 +0100 Subject: [PATCH 07/54] feat(ticket): docuware pdf --- back/methods/docuware/checkFile.js | 80 +++++++++++ back/methods/docuware/download.js | 104 ++++++++++---- back/methods/docuware/specs/checkFile.spec.js | 129 ++++++++++++++++++ back/methods/docuware/specs/download.spec.js | 28 ++++ back/model-config.json | 6 + back/models/docuware-config.json | 32 +++++ back/models/docuware-container.json | 10 ++ back/models/docuware.js | 1 + db/changes/10420-valentines/00-docuware.sql | 6 +- .../10420-valentines/00-docuwareConfig.sql | 6 +- db/dump/fixtures.sql | 8 ++ loopback/server/datasources.json | 11 ++ .../back/methods/invoiceOut/docuware.js | 65 --------- modules/invoiceOut/back/models/invoice-out.js | 1 - .../ticket/front/descriptor-menu/index.html | 12 +- modules/ticket/front/descriptor-menu/index.js | 8 ++ .../front/descriptor-menu/locale/es.yml | 4 +- 17 files changed, 408 insertions(+), 103 deletions(-) create mode 100644 back/methods/docuware/checkFile.js create mode 100644 back/methods/docuware/specs/checkFile.spec.js create mode 100644 back/methods/docuware/specs/download.spec.js create mode 100644 back/models/docuware-config.json create mode 100644 back/models/docuware-container.json delete mode 100644 modules/invoiceOut/back/methods/invoiceOut/docuware.js diff --git a/back/methods/docuware/checkFile.js b/back/methods/docuware/checkFile.js new file mode 100644 index 000000000..7dc1993f0 --- /dev/null +++ b/back/methods/docuware/checkFile.js @@ -0,0 +1,80 @@ +const got = require('got'); +const UserError = require('vn-loopback/util/user-error'); + +module.exports = Self => { + Self.remoteMethodCtx('checkFile', { + description: 'Download an docuware PDF', + accessType: 'READ', + accepts: [ + { + arg: 'id', + type: 'String', + description: 'The invoice id', + http: {source: 'path'} + } + ], + returns: { + type: 'boolean', + root: true + }, + http: { + path: `/:id/checkFile`, + verb: 'GET' + } + }); + + Self.checkFile = async function(ctx, id) { + // const fileCabinet = 'ad2c49df-8976-4941-bb19-9b30685f14a4'; + // hay que crear tambien una busqueda por cada fileCabinet + // columnas necesarias. seccion, fileCabinet, DBName, dialog + + const models = Self.app.models; + const docuwareConfig = await models.DocuwareConfig.findOne(); + const docuwareInfo = await models.Docuware.findOne({ + where: { + name: 'deliveryClient', + dialogName: 'findTicket' + } + }); + + const docuwareUrl = docuwareConfig.url; + const cookie = docuwareConfig.token; + const fileCabinetName = docuwareInfo.fileCabinetName; + const find = docuwareInfo.find; + + const options = { + 'headers': { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Cookie': cookie + } + }; + // get fileCabinetId + const fileCabinetResponse = await got.get(`${docuwareUrl}/FileCabinets`, options).json(); + const fileCabinetId = fileCabinetResponse.FileCabinet.find(dialogs => dialogs.Name === fileCabinetName).Id; + + // get dialog + const dialogResponse = await got.get(`${docuwareUrl}/FileCabinets/${fileCabinetId}/dialogs`, options).json(); + const dialogId = dialogResponse.Dialog.find(dialogs => dialogs.DisplayName === 'find').Id; + + // get docuwareID + const docuwareOptions = { + 'headers': { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Cookie': cookie + }, + 'body': JSON.stringify({'Condition': [{DBName: find, Value: [id]}]}) + }; + const response = await got.post( + `${docuwareUrl}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`, + docuwareOptions + ); + try { + JSON.parse(response.body).Items[0].Id; + return true; + } catch (error) { + return false; + } + }; +}; diff --git a/back/methods/docuware/download.js b/back/methods/docuware/download.js index 01e552d2d..a2a95fcd1 100644 --- a/back/methods/docuware/download.js +++ b/back/methods/docuware/download.js @@ -1,48 +1,65 @@ const got = require('got'); -const {createWriteStream} = require('fs'); +const fs = require('fs-extra'); +const path = require('path'); const UserError = require('vn-loopback/util/user-error'); +const {promisify} = require('util'); +const nodeStream = require('stream'); module.exports = Self => { Self.remoteMethodCtx('download', { - description: 'Download an invoice PDF', + description: 'Download an docuware PDF', accessType: 'READ', accepts: [ { - arg: 'ticketId', + arg: 'id', type: 'number', - description: 'The invoiceable ticket id' - }, + description: 'The ticket id', + http: {source: 'path'} + } + ], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } ], - returns: { - type: 'object', - root: true - }, http: { - path: `/download`, - verb: 'POST' + path: `/:id/download`, + verb: 'GET' } }); - Self.download = async function(ctx, ticketId) { + Self.download = async function(ctx, id) { // const fileCabinet = 'ad2c49df-8976-4941-bb19-9b30685f14a4'; // hay que crear tambien una busqueda por cada fileCabinet // columnas necesarias. seccion, fileCabinet, DBName, dialog + /* const myUserId = ctx.req.accessToken.userId; + if (!myUserId) + throw new UserError(`You don't have enough privileges`);*/ + const models = Self.app.models; - const [docuwareConfig] = await Self.rawSql(`SELECT * FROM vn.docuwareConfig;`); + const docuwareConfig = await models.DocuwareConfig.findOne(); const docuwareInfo = await models.Docuware.findOne({ where: { name: 'deliveryClient', dialogName: 'findTicket' } }); - console.log(docuwareConfig, docuwareInfo); const docuwareUrl = docuwareConfig.url; const cookie = docuwareConfig.token; const fileCabinetName = docuwareInfo.fileCabinetName; const find = docuwareInfo.find; - // get fileCabinetId const options = { 'headers': { 'Accept': 'application/json', @@ -50,27 +67,27 @@ module.exports = Self => { 'Cookie': cookie } }; - + // get fileCabinetId const fileCabinetResponse = await got.get(`${docuwareUrl}/FileCabinets`, options).json(); const fileCabinetId = fileCabinetResponse.FileCabinet.find(dialogs => dialogs.Name === fileCabinetName).Id; - // get dialogs + // get dialog const dialogResponse = await got.get(`${docuwareUrl}/FileCabinets/${fileCabinetId}/dialogs`, options).json(); - console.log(dialogResponse); const dialogId = dialogResponse.Dialog.find(dialogs => dialogs.DisplayName === 'find').Id; - console.log(fileCabinetId, dialogId); - /* - // get DocuwareID + // get docuwareID const docuwareOptions = { 'headers': { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Cookie': cookie }, - 'body': JSON.stringify({'Condition': [{DBName: find, Value: [ticketId]}]}) + 'body': JSON.stringify({'Condition': [{DBName: find, Value: [0]}]}) }; - const response = await got.post(`${docuwareUrl}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`, docuwareOptions); + const response = await got.post( + `${docuwareUrl}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`, + docuwareOptions + ); const docuwareId = JSON.parse(response.body).Items[0].Id; // download file @@ -81,8 +98,45 @@ module.exports = Self => { } }; - const file = await got.stream(downloadUrl, downloadOptions).pipe(createWriteStream(`${ticketId}_${docuwareId}.pdf`)); + try { + // save file + const ticket = await models.Ticket.findById(id); - // return [file, 'application/pdf', `filename="${ticketId}_${docuwareId}.pdf"`];*/ + const shipped = ticket.shipped; + const year = shipped.getFullYear().toString(); + const month = (shipped.getMonth() + 1).toString(); + const day = shipped.getDate().toString(); + const fileName = `${year}${id}.pdf`; + + const container = await models.DocuwareContainer.container(year); + const rootPath = container.client.root; + const src = path.join(rootPath, year, month, day); + const fileSrc = path.join(src, fileName); + + await fs.mkdir(src, {recursive: true}); + + const pipeline = promisify(nodeStream.pipeline); + await pipeline( + got.stream(downloadUrl, downloadOptions), + fs.createWriteStream(fileSrc) + ); + + // open file + const file = { + path: fileSrc, + contentType: 'application/pdf', + name: fileName + }; + + await fs.access(file.path); + let stream = fs.createReadStream(file.path); + + return [stream, file.contentType, `filename="${file.name}"`]; + } catch (error) { + if (error.code === 'ENOENT') + throw new UserError('The DOCUWARE PDF document does not exists'); + + throw error; + } }; }; diff --git a/back/methods/docuware/specs/checkFile.spec.js b/back/methods/docuware/specs/checkFile.spec.js new file mode 100644 index 000000000..7cb2ae6f9 --- /dev/null +++ b/back/methods/docuware/specs/checkFile.spec.js @@ -0,0 +1,129 @@ +const app = require('vn-loopback/server/server'); + +describe('image upload()', () => { + describe('as buyer', () => { + const buyerId = 35; + const workerId = 1106; + const itemId = 4; + + it('should try to upload a file for the collection "catalog" and throw a privileges error', async() => { + const ctx = {req: {accessToken: {userId: buyerId}}, + args: { + id: workerId, + collection: 'user' + } + }; + + let error; + try { + await app.models.Image.upload(ctx); + } catch (err) { + error = err; + } + + expect(error.message).toEqual(`You don't have enough privileges`); + }); + + it('should call to the TempContainer upload method for the collection "catalog"', async() => { + const containerModel = app.models.TempContainer; + spyOn(containerModel, 'upload'); + + const ctx = {req: {accessToken: {userId: buyerId}}, + args: { + id: itemId, + collection: 'catalog' + } + }; + + try { + await app.models.Image.upload(ctx); + } catch (err) { } + + expect(containerModel.upload).toHaveBeenCalled(); + }); + }); + + describe('as marketing', () => { + const marketingId = 51; + const workerId = 1106; + const itemId = 4; + + it('should be able to call to the TempContainer upload method for the collection "user"', async() => { + const containerModel = app.models.TempContainer; + spyOn(containerModel, 'upload'); + + const ctx = {req: {accessToken: {userId: marketingId}}, + args: { + id: workerId, + collection: 'user' + } + }; + + try { + await app.models.Image.upload(ctx); + } catch (err) { } + + expect(containerModel.upload).toHaveBeenCalled(); + }); + + it('should be able to call to the TempContainer upload method for the collection "catalog"', async() => { + const containerModel = app.models.TempContainer; + spyOn(containerModel, 'upload'); + + const ctx = {req: {accessToken: {userId: marketingId}}, + args: { + id: itemId, + collection: 'catalog' + } + }; + + try { + await app.models.Image.upload(ctx); + } catch (err) { } + + expect(containerModel.upload).toHaveBeenCalled(); + }); + }); + + describe('as hhrr', () => { + const hhrrId = 37; + const workerId = 1106; + const itemId = 4; + + it('should upload a file for the collection "user" and call to the TempContainer upload method', async() => { + const containerModel = app.models.TempContainer; + spyOn(containerModel, 'upload'); + + const ctx = {req: {accessToken: {userId: hhrrId}}, + args: { + id: itemId, + collection: 'user' + } + }; + + try { + await app.models.Image.upload(ctx); + } catch (err) { } + + expect(containerModel.upload).toHaveBeenCalled(); + }); + + it('should try to upload a file for the collection "catalog" and throw a privilege error', async() => { + const ctx = {req: {accessToken: {userId: hhrrId}}, + args: { + id: workerId, + collection: 'catalog' + } + }; + + let error; + try { + await app.models.Image.upload(ctx); + } catch (err) { + error = err; + } + + expect(error.message).toEqual(`You don't have enough privileges`); + }); + }); +}); diff --git a/back/methods/docuware/specs/download.spec.js b/back/methods/docuware/specs/download.spec.js new file mode 100644 index 000000000..4bdf800b4 --- /dev/null +++ b/back/methods/docuware/specs/download.spec.js @@ -0,0 +1,28 @@ +const models = require('vn-loopback/server/server').models; +const fs = require('fs-extra'); + +describe('image download()', () => { + const userId = 9; + const invoiceId = 1; + const ctx = { + req: { + + accessToken: {userId: userId}, + headers: {origin: 'http://localhost:5000'}, + } + }; + + it('should return the downloaded file name', async() => { + spyOn(models.DocuwareContainer, 'container').and.returnValue({ + client: {root: '/path'} + }); + spyOn(fs, 'createReadStream').and.returnValue(new Promise(resolve => resolve('streamObject'))); + spyOn(fs, 'access').and.returnValue(true); + spyOn(models.InvoiceOut, 'createPdf').and.returnValue(new Promise(resolve => resolve(true))); + + const result = await models.InvoiceOut.download(ctx, invoiceId); + + expect(result[1]).toEqual('application/pdf'); + expect(result[2]).toMatch(/filename="\d{4}T1111111.pdf"/); + }); +}); diff --git a/back/model-config.json b/back/model-config.json index 7be2174e6..f1b662354 100644 --- a/back/model-config.json +++ b/back/model-config.json @@ -47,6 +47,12 @@ "Docuware": { "dataSource": "vn" }, + "DocuwareConfig": { + "dataSource": "vn" + }, + "DocuwareContainer": { + "dataSource": "docuwareStorage" + }, "EmailUser": { "dataSource": "vn" }, diff --git a/back/models/docuware-config.json b/back/models/docuware-config.json new file mode 100644 index 000000000..8ca76d8ba --- /dev/null +++ b/back/models/docuware-config.json @@ -0,0 +1,32 @@ +{ + "name": "DocuwareConfig", + "description": "Docuware config", + "base": "VnModel", + "options": { + "mysql": { + "table": "docuwareConfig" + } + }, + "properties": { + "id": { + "type": "number", + "id": true, + "description": "Identifier" + }, + "url": { + "type": "string" + }, + "token": { + "type": "string" + } + }, + "acls": [ + { + "property": "*", + "accessType": "*", + "principalType": "ROLE", + "principalId": "$everyone", + "permission": "ALLOW" + } + ] +} \ No newline at end of file diff --git a/back/models/docuware-container.json b/back/models/docuware-container.json new file mode 100644 index 000000000..8180695c1 --- /dev/null +++ b/back/models/docuware-container.json @@ -0,0 +1,10 @@ +{ + "name": "DocuwareContainer", + "base": "Container", + "acls": [{ + "accessType": "READ", + "principalType": "ROLE", + "principalId": "$everyone", + "permission": "ALLOW" + }] +} \ No newline at end of file diff --git a/back/models/docuware.js b/back/models/docuware.js index 8a6b0cd93..8fd8065ed 100644 --- a/back/models/docuware.js +++ b/back/models/docuware.js @@ -1,3 +1,4 @@ module.exports = Self => { require('../methods/docuware/download')(Self); + require('../methods/docuware/checkFile')(Self); }; diff --git a/db/changes/10420-valentines/00-docuware.sql b/db/changes/10420-valentines/00-docuware.sql index dd915ddcd..ca4b0a114 100644 --- a/db/changes/10420-valentines/00-docuware.sql +++ b/db/changes/10420-valentines/00-docuware.sql @@ -6,6 +6,6 @@ CREATE TABLE `vn`.`docuware` ( `find` varchar(50) DEFAULT NULL ); -INSERT INTO `vn`.`docuware` -(name, fileCabinetName, dialogName , find) -VALUES('deliveryClient', 'Albaranes cliente', 'findTicket', 'N__ALBAR_N'); +INSERT INTO `vn`.`docuware` (`name`, `fileCabinetName`, `dialogName` , `find`) + VALUES + ('deliveryClient', 'Albaranes cliente', 'findTicket', 'N__ALBAR_N'); diff --git a/db/changes/10420-valentines/00-docuwareConfig.sql b/db/changes/10420-valentines/00-docuwareConfig.sql index 0ef190cb7..c2c78c67e 100644 --- a/db/changes/10420-valentines/00-docuwareConfig.sql +++ b/db/changes/10420-valentines/00-docuwareConfig.sql @@ -2,8 +2,4 @@ CREATE TABLE `vn`.`docuwareConfig` ( `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, `url` varchar(75) NULL, `token` varchar(1000) DEFAULT NULL -); - -INSERT INTO `vn`.`docuwareConfig` -(url, token) -VALUES('https://verdnatura.docuware.cloud/docuware/platform/', '.DWPLATFORMAUTH=66C7DCD2B9365EF974AFEB43F61715152082EF39C649CB1506F9ACC34DD54C5B34944DDFBF97EAE5C5147063850B16B3B9FFFB2232FDD03F35B51B1305D5E1E7DB833F6AC560C739E40778932C8BCC64DA7ECE64B0B1F71A3DB986B3710DFA4C061776F9C61DDAA60EF30F7F37FB8733BF4B1830F98102E403E4E751F13F31B582AEDF5B33A25346E10CA34A8559F0CD6ACA39A7379AC67BE061CD27531D02675123FB0D254426E306EC6FA49DED7CF30EBBAD8365BE60D7E919D4AD2EB8F9CD94424DFCD95151C0F6DD3EE8569A7CA4A30D1A3F42DA9DD368A33955A4AFE9CB4FCCC230801BC645AA87A68EC33F6BD165D5A0F02B63D5D832AF936B9398EC428D4ACD41E56848A2CDF797C99226BB2AC48EB5F9C1C5D8C1C7F6A7F67F455ABAC1DBC7443521876B588F369CAE6EC81747BA3134F7EE2662DA296FC2C16528B0AB4839EEE6EE79A82AA3888E4AB53FEC6FFAD26A592ABD76441AFCD634097D0B0B57E16A510D0E6F769710C6F4BDB1476CCDE0967788B90A67BADFB7E37B1F7F60C879A0E9D75AD2BA6647FC11477305B44512AF408845E6099CF64B7A3D77EE; ApplicationGatewayAffinity=c5fad6cb3332163516d49258a1ebf52c; ApplicationGatewayAffinityCORS=c5fad6cb3332163516d49258a1ebf52c; DWPLATFORMBROWSERID=C2173B1A1FE42B449AA12C8465561991BA4664AFA9F44D4C9DD8748FF92EFEBF629E4A75860747C4D8290F70344385CCAFE3EAFD8814CF44F452275C95E89D19D35A178D0BCC6930EF07AC7CF91672F7CB43C2B54CDFAE52BDF17C467FFFE3411FE0D792E4F513726F295648DDE627DF2C6288C89086E2DE6916E4B0A5291AA7C269015A5328147783EC15FB8EF43EE5DAE5A6CD3D318570670234176CAE7B19D9812D3F09D731C5A27A621B39D0564C81774FA993160AAAD833CC75634445B7B47C5A2E26004FF914606B5B0CB897A694F26AD5E80A1EE0D3B7BA4881F8A570'); +); \ No newline at end of file diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 07eaf23fd..7c7709716 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -2443,3 +2443,11 @@ INSERT INTO `bs`.`defaulter` (`clientFk`, `amount`, `created`, `defaulterSinced` (1103, 500, CURDATE(), CURDATE()), (1107, 500, CURDATE(), CURDATE()), (1109, 500, CURDATE(), CURDATE()); + +INSERT INTO `vn`.`docuwareConfig` (`url`, `token`) + VALUES + ('https://verdnatura.docuware.cloud/docuware/platform', '.DWPLATFORMAUTH=66C7DCD2B9365EF974AFEB43F61715152082EF39C649CB1506F9ACC34DD54C5B34944DDFBF97EAE5C5147063850B16B3B9FFFB2232FDD03F35B51B1305D5E1E7DB833F6AC560C739E40778932C8BCC64DA7ECE64B0B1F71A3DB986B3710DFA4C061776F9C61DDAA60EF30F7F37FB8733BF4B1830F98102E403E4E751F13F31B582AEDF5B33A25346E10CA34A8559F0CD6ACA39A7379AC67BE061CD27531D02675123FB0D254426E306EC6FA49DED7CF30EBBAD8365BE60D7E919D4AD2EB8F9CD94424DFCD95151C0F6DD3EE8569A7CA4A30D1A3F42DA9DD368A33955A4AFE9CB4FCCC230801BC645AA87A68EC33F6BD165D5A0F02B63D5D832AF936B9398EC428D4ACD41E56848A2CDF797C99226BB2AC48EB5F9C1C5D8C1C7F6A7F67F455ABAC1DBC7443521876B588F369CAE6EC81747BA3134F7EE2662DA296FC2C16528B0AB4839EEE6EE79A82AA3888E4AB53FEC6FFAD26A592ABD76441AFCD634097D0B0B57E16A510D0E6F769710C6F4BDB1476CCDE0967788B90A67BADFB7E37B1F7F60C879A0E9D75AD2BA6647FC11477305B44512AF408845E6099CF64B7A3D77EE; ApplicationGatewayAffinity=c5fad6cb3332163516d49258a1ebf52c; ApplicationGatewayAffinityCORS=c5fad6cb3332163516d49258a1ebf52c; DWPLATFORMBROWSERID=C2173B1A1FE42B449AA12C8465561991BA4664AFA9F44D4C9DD8748FF92EFEBF629E4A75860747C4D8290F70344385CCAFE3EAFD8814CF44F452275C95E89D19D35A178D0BCC6930EF07AC7CF91672F7CB43C2B54CDFAE52BDF17C467FFFE3411FE0D792E4F513726F295648DDE627DF2C6288C89086E2DE6916E4B0A5291AA7C269015A5328147783EC15FB8EF43EE5DAE5A6CD3D318570670234176CAE7B19D9812D3F09D731C5A27A621B39D0564C81774FA993160AAAD833CC75634445B7B47C5A2E26004FF914606B5B0CB897A694F26AD5E80A1EE0D3B7BA4881F8A570'); + +INSERT INTO `vn`.`docuware` (`name`, `fileCabinetName`, `dialogName` , `find`) + VALUES + ('deliveryClient', 'Albaranes cliente', 'findTicket', 'N__ALBAR_N'); \ No newline at end of file diff --git a/loopback/server/datasources.json b/loopback/server/datasources.json index 0df03882c..27921c78a 100644 --- a/loopback/server/datasources.json +++ b/loopback/server/datasources.json @@ -83,5 +83,16 @@ "application/octet-stream", "application/pdf" ] + }, + "docuwareStorage": { + "name": "docuwareStorage", + "connector": "loopback-component-storage", + "provider": "filesystem", + "root": "./storage/pdfs/docuware", + "maxFileSize": "52428800", + "allowedContentTypes": [ + "application/octet-stream", + "application/pdf" + ] } } \ No newline at end of file diff --git a/modules/invoiceOut/back/methods/invoiceOut/docuware.js b/modules/invoiceOut/back/methods/invoiceOut/docuware.js deleted file mode 100644 index aa58aaed1..000000000 --- a/modules/invoiceOut/back/methods/invoiceOut/docuware.js +++ /dev/null @@ -1,65 +0,0 @@ -const got = require('got'); -const {createWriteStream} = require('fs'); -const UserError = require('vn-loopback/util/user-error'); - -module.exports = Self => { - Self.remoteMethodCtx('docuware', { - description: 'Download an invoice PDF', - accessType: 'READ', - accepts: [ - { - arg: 'ticketId', - type: 'number', - description: 'The invoiceable ticket id' - }, - ], - returns: { - type: 'object', - root: true - }, - http: { - path: `/docuware`, - verb: 'POST' - } - }); - - Self.docuware = async function(ctx, ticketId) { - // const fileCabinet = 'ad2c49df-8976-4941-bb19-9b30685f14a4'; - // hay que crear tambien una busqueda por cada fileCabinet - // columnas necesarias. seccion, fileCabinet, DBName, dialog - const models = Self.app.models; - const docuwareInfo = await models.Docuware.findOne({ - where: { - name: 'albaran' - } - }); - console.log(docuwareInfo); - const fileCabinet = docuwareInfo.fileCabinet; - const find = docuwareInfo.find; - const dialog = docuwareInfo.dialog; - const docuwareUrl = `https://verdnatura.docuware.cloud/docuware/platform/FileCabinets/${fileCabinet}`; - const cookie = '.DWPLATFORMAUTH=66C7DCD2B9365EF974AFEB43F61715152082EF39C649CB1506F9ACC34DD54C5B34944DDFBF97EAE5C5147063850B16B3B9FFFB2232FDD03F35B51B1305D5E1E7DB833F6AC560C739E40778932C8BCC64DA7ECE64B0B1F71A3DB986B3710DFA4C061776F9C61DDAA60EF30F7F37FB8733BF4B1830F98102E403E4E751F13F31B582AEDF5B33A25346E10CA34A8559F0CD6ACA39A7379AC67BE061CD27531D02675123FB0D254426E306EC6FA49DED7CF30EBBAD8365BE60D7E919D4AD2EB8F9CD94424DFCD95151C0F6DD3EE8569A7CA4A30D1A3F42DA9DD368A33955A4AFE9CB4FCCC230801BC645AA87A68EC33F6BD165D5A0F02B63D5D832AF936B9398EC428D4ACD41E56848A2CDF797C99226BB2AC48EB5F9C1C5D8C1C7F6A7F67F455ABAC1DBC7443521876B588F369CAE6EC81747BA3134F7EE2662DA296FC2C16528B0AB4839EEE6EE79A82AA3888E4AB53FEC6FFAD26A592ABD76441AFCD634097D0B0B57E16A510D0E6F769710C6F4BDB1476CCDE0967788B90A67BADFB7E37B1F7F60C879A0E9D75AD2BA6647FC11477305B44512AF408845E6099CF64B7A3D77EE; ApplicationGatewayAffinity=c5fad6cb3332163516d49258a1ebf52c; ApplicationGatewayAffinityCORS=c5fad6cb3332163516d49258a1ebf52c; DWPLATFORMBROWSERID=C2173B1A1FE42B449AA12C8465561991BA4664AFA9F44D4C9DD8748FF92EFEBF629E4A75860747C4D8290F70344385CCAFE3EAFD8814CF44F452275C95E89D19D35A178D0BCC6930EF07AC7CF91672F7CB43C2B54CDFAE52BDF17C467FFFE3411FE0D792E4F513726F295648DDE627DF2C6288C89086E2DE6916E4B0A5291AA7C269015A5328147783EC15FB8EF43EE5DAE5A6CD3D318570670234176CAE7B19D9812D3F09D731C5A27A621B39D0564C81774FA993160AAAD833CC75634445B7B47C5A2E26004FF914606B5B0CB897A694F26AD5E80A1EE0D3B7BA4881F8A570'; - - // get DocuwareID - const dialogOptions = { - 'headers': { - 'Accept': 'application/json', - 'Content-Type': 'application/json', - 'Cookie': cookie - }, - 'body': JSON.stringify({'Condition': [{DBName: find, Value: [ticketId]}]}) - }; - const response = await got.post(`${docuwareUrl}/Query/DialogExpression?dialogId=${dialog}`, dialogOptions); - const docuwareId = JSON.parse(response.body).Items[0].Id; - - // download file - const downloadUrl = `${docuwareUrl}/Documents/${docuwareId}/FileDownload?targetFileType=Auto&keepAnnotations=false`; - const downloadOptions = { - 'headers': { - 'Cookie': cookie - } - }; - - await got.stream(downloadUrl, downloadOptions).pipe(createWriteStream(`${ticketId}_${docuwareId}.pdf`)); - }; -}; diff --git a/modules/invoiceOut/back/models/invoice-out.js b/modules/invoiceOut/back/models/invoice-out.js index 3da5aedc6..3b2822ada 100644 --- a/modules/invoiceOut/back/models/invoice-out.js +++ b/modules/invoiceOut/back/models/invoice-out.js @@ -3,7 +3,6 @@ module.exports = Self => { require('../methods/invoiceOut/summary')(Self); require('../methods/invoiceOut/getTickets')(Self); require('../methods/invoiceOut/download')(Self); - require('../methods/invoiceOut/docuware')(Self); require('../methods/invoiceOut/delete')(Self); require('../methods/invoiceOut/book')(Self); require('../methods/invoiceOut/createPdf')(Self); diff --git a/modules/ticket/front/descriptor-menu/index.html b/modules/ticket/front/descriptor-menu/index.html index ae5642cf3..87a821746 100644 --- a/modules/ticket/front/descriptor-menu/index.html +++ b/modules/ticket/front/descriptor-menu/index.html @@ -20,14 +20,22 @@ - Show as PDF + as PDF + + as DOCUWARE + - Show as CSV + as CSV diff --git a/modules/ticket/front/descriptor-menu/index.js b/modules/ticket/front/descriptor-menu/index.js index 9d4381f7c..6abdfcce6 100644 --- a/modules/ticket/front/descriptor-menu/index.js +++ b/modules/ticket/front/descriptor-menu/index.js @@ -82,6 +82,7 @@ class Controller extends Section { return this.$http.get(`Tickets/${this.ticketId}`, {filter}) .then(res => this.ticket = res.data) .then(() => { + this.hasDocuware(); this.canStowaway(); this.isTicketEditable(); }); @@ -122,6 +123,13 @@ class Controller extends Section { }); } + hasDocuware() { + this.$http.get(`Docuwares/${this.id}/checkFile`) + .then(res => { + this.hasDocuware = res.data; + }); + } + showCsvDeliveryNote() { this.vnReport.showCsv('delivery-note', { recipientId: this.ticket.client.id, diff --git a/modules/ticket/front/descriptor-menu/locale/es.yml b/modules/ticket/front/descriptor-menu/locale/es.yml index 1f4ee710c..4a61556db 100644 --- a/modules/ticket/front/descriptor-menu/locale/es.yml +++ b/modules/ticket/front/descriptor-menu/locale/es.yml @@ -1,7 +1,7 @@ Show Delivery Note...: Ver albarán... Send Delivery Note...: Enviar albarán... -Show as PDF: Ver como PDF -Show as CSV: Ver como CSV +as PDF: como PDF +as CSV: como CSV Send PDF: Enviar PDF Send CSV: Enviar CSV Send CSV Delivery Note: Enviar albarán en CSV From 89eee042b55327b880352010253da54768ccfd30 Mon Sep 17 00:00:00 2001 From: alexm Date: Thu, 17 Feb 2022 08:02:02 +0100 Subject: [PATCH 08/54] refactor(ticket_basic-data): zeroFill and move getMovable --- .../00-ticket_getMovable.sql | 0 modules/ticket/front/basic-data/step-two/index.html | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename db/changes/{10411-january => 10420-valentines}/00-ticket_getMovable.sql (100%) diff --git a/db/changes/10411-january/00-ticket_getMovable.sql b/db/changes/10420-valentines/00-ticket_getMovable.sql similarity index 100% rename from db/changes/10411-january/00-ticket_getMovable.sql rename to db/changes/10420-valentines/00-ticket_getMovable.sql diff --git a/modules/ticket/front/basic-data/step-two/index.html b/modules/ticket/front/basic-data/step-two/index.html index af06a0f70..6be455fc9 100644 --- a/modules/ticket/front/basic-data/step-two/index.html +++ b/modules/ticket/front/basic-data/step-two/index.html @@ -23,7 +23,7 @@ title="{{::sale.item.name}}" vn-click-stop="itemDescriptor.show($event, sale.itemFk, sale.id)" class="link"> - {{("000000"+sale.itemFk).slice(-6)}} + {{::sale.itemFk | zeroFill:6}}
From 72f4ef70ed3393ed031b2a34055ecb65da802559 Mon Sep 17 00:00:00 2001 From: vicent Date: Thu, 17 Feb 2022 10:18:47 +0100 Subject: [PATCH 09/54] recalculate neto in sql --- print/templates/reports/invoice/sql/intrastat.sql | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/print/templates/reports/invoice/sql/intrastat.sql b/print/templates/reports/invoice/sql/intrastat.sql index e391056ec..6bf72c158 100644 --- a/print/templates/reports/invoice/sql/intrastat.sql +++ b/print/templates/reports/invoice/sql/intrastat.sql @@ -2,9 +2,13 @@ SELECT ir.id AS code, ir.description AS description, CAST(SUM(IFNULL(i.stems,1) * s.quantity) AS DECIMAL(10,2)) as stems, - CAST(SUM( weight) AS DECIMAL(10,2)) as netKg, + CAST(SUM(IF(sv.physicalWeight, sv.physicalWeight, i.density * sub.cm3delivery/1000000)) AS DECIMAL(10,2)) netKg, CAST(SUM((s.quantity * s.price * (100 - s.discount) / 100 )) AS DECIMAL(10,2)) AS subtotal - FROM vn.sale s + FROM vn.sale s + LEFT JOIN (SELECT ic.itemFk, ic.cm3, ic.cm3delivery + FROM vn.itemCost ic + WHERE ic.cm3 + GROUP BY ic.itemFk) sub ON s.itemFk = sub.itemFk LEFT JOIN vn.saleVolume sv ON sv.saleFk = s.id LEFT JOIN vn.ticket t ON t.id = s.ticketFk LEFT JOIN vn.invoiceOut io ON io.ref = t.refFk From 0f4649c50f5addfdeacda0ee546604b459658a0a Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 21 Feb 2022 08:48:53 +0100 Subject: [PATCH 10/54] feat(ticket_descriptor-menu): docuware implemented --- back/methods/docuware/checkFile.js | 77 +++--- back/methods/docuware/download.js | 124 ++++------ back/methods/docuware/specs/checkFile.spec.js | 163 ++++-------- back/methods/docuware/specs/download.spec.js | 44 +++- back/model-config.json | 3 - back/models/docuware-container.json | 10 - db/changes/10420-valentines/00-docuware.sql | 2 +- db/dump/fixtures.sql | 6 +- loopback/server/datasources.json | 11 - .../front/descriptor-menu/index.html | 234 +++++++++--------- .../invoiceOut/front/descriptor-menu/index.js | 13 - .../ticket/front/descriptor-menu/index.html | 4 +- modules/ticket/front/descriptor-menu/index.js | 8 +- .../front/descriptor-menu/index.spec.js | 11 +- 14 files changed, 312 insertions(+), 398 deletions(-) delete mode 100644 back/models/docuware-container.json diff --git a/back/methods/docuware/checkFile.js b/back/methods/docuware/checkFile.js index 7dc1993f0..a674707fc 100644 --- a/back/methods/docuware/checkFile.js +++ b/back/methods/docuware/checkFile.js @@ -1,16 +1,27 @@ const got = require('got'); -const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { Self.remoteMethodCtx('checkFile', { - description: 'Download an docuware PDF', + description: 'Check if exist docuware file', accessType: 'READ', accepts: [ { arg: 'id', - type: 'String', - description: 'The invoice id', + type: 'number', + description: 'The id', http: {source: 'path'} + }, + { + arg: 'fileCabinet', + type: 'string', + required: true, + description: 'The fileCabinet name' + }, + { + arg: 'dialog', + type: 'string', + required: true, + description: 'The dialog name' } ], returns: { @@ -19,21 +30,21 @@ module.exports = Self => { }, http: { path: `/:id/checkFile`, - verb: 'GET' + verb: 'POST' } }); - Self.checkFile = async function(ctx, id) { - // const fileCabinet = 'ad2c49df-8976-4941-bb19-9b30685f14a4'; - // hay que crear tambien una busqueda por cada fileCabinet - // columnas necesarias. seccion, fileCabinet, DBName, dialog + Self.checkFile = async function(ctx, id, fileCabinet, dialog) { + const myUserId = ctx.req.accessToken.userId; + if (!myUserId) + return false; const models = Self.app.models; const docuwareConfig = await models.DocuwareConfig.findOne(); const docuwareInfo = await models.Docuware.findOne({ where: { - name: 'deliveryClient', - dialogName: 'findTicket' + name: fileCabinet, + dialogName: dialog } }); @@ -41,7 +52,6 @@ module.exports = Self => { const cookie = docuwareConfig.token; const fileCabinetName = docuwareInfo.fileCabinetName; const find = docuwareInfo.find; - const options = { 'headers': { 'Accept': 'application/json', @@ -49,29 +59,32 @@ module.exports = Self => { 'Cookie': cookie } }; - // get fileCabinetId - const fileCabinetResponse = await got.get(`${docuwareUrl}/FileCabinets`, options).json(); - const fileCabinetId = fileCabinetResponse.FileCabinet.find(dialogs => dialogs.Name === fileCabinetName).Id; - - // get dialog - const dialogResponse = await got.get(`${docuwareUrl}/FileCabinets/${fileCabinetId}/dialogs`, options).json(); - const dialogId = dialogResponse.Dialog.find(dialogs => dialogs.DisplayName === 'find').Id; - - // get docuwareID - const docuwareOptions = { - 'headers': { - 'Accept': 'application/json', - 'Content-Type': 'application/json', - 'Cookie': cookie - }, - 'body': JSON.stringify({'Condition': [{DBName: find, Value: [id]}]}) + const condtions = { + condition: [ + { + DBName: find, + Value: [id] + } + ] }; - const response = await got.post( - `${docuwareUrl}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`, - docuwareOptions - ); + try { + // get fileCabinetId + const fileCabinetResponse = await got.get(`${docuwareUrl}/FileCabinets`, options); + const fileCabinetJson = JSON.parse(fileCabinetResponse.body).FileCabinet; + const fileCabinetId = fileCabinetJson.find(dialogs => dialogs.Name === fileCabinetName).Id; + + // get dialog + const dialogResponse = await got.get(`${docuwareUrl}/FileCabinets/${fileCabinetId}/dialogs`, options); + const dialogJson = JSON.parse(dialogResponse.body).Dialog; + const dialogId = dialogJson.find(dialogs => dialogs.DisplayName === 'find').Id; + + // get docuwareID + Object.assign(options, {'body': JSON.stringify(condtions)}); + const response = await got.post( + `${docuwareUrl}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`, options); JSON.parse(response.body).Items[0].Id; + return true; } catch (error) { return false; diff --git a/back/methods/docuware/download.js b/back/methods/docuware/download.js index a2a95fcd1..75789d187 100644 --- a/back/methods/docuware/download.js +++ b/back/methods/docuware/download.js @@ -1,9 +1,6 @@ +/* eslint max-len: ["error", { "code": 180 }]*/ const got = require('got'); -const fs = require('fs-extra'); -const path = require('path'); const UserError = require('vn-loopback/util/user-error'); -const {promisify} = require('util'); -const nodeStream = require('stream'); module.exports = Self => { Self.remoteMethodCtx('download', { @@ -13,7 +10,19 @@ module.exports = Self => { { arg: 'id', type: 'number', - description: 'The ticket id', + description: 'The id', + http: {source: 'path'} + }, + { + arg: 'fileCabinet', + type: 'string', + description: 'The id', + http: {source: 'path'} + }, + { + arg: 'dialog', + type: 'string', + description: 'The id', http: {source: 'path'} } ], @@ -24,34 +33,31 @@ module.exports = Self => { root: true }, { arg: 'Content-Type', - type: 'String', + type: 'string', http: {target: 'header'} }, { arg: 'Content-Disposition', - type: 'String', + type: 'string', http: {target: 'header'} } ], http: { - path: `/:id/download`, + path: `/:id/download/:fileCabinet/:dialog`, verb: 'GET' } }); - Self.download = async function(ctx, id) { - // const fileCabinet = 'ad2c49df-8976-4941-bb19-9b30685f14a4'; - // hay que crear tambien una busqueda por cada fileCabinet - // columnas necesarias. seccion, fileCabinet, DBName, dialog - /* const myUserId = ctx.req.accessToken.userId; + Self.download = async function(ctx, id, fileCabinet, dialog) { + const myUserId = ctx.req.accessToken.userId; if (!myUserId) - throw new UserError(`You don't have enough privileges`);*/ + throw new UserError(`You don't have enough privileges`); const models = Self.app.models; const docuwareConfig = await models.DocuwareConfig.findOne(); const docuwareInfo = await models.Docuware.findOne({ where: { - name: 'deliveryClient', - dialogName: 'findTicket' + name: fileCabinet, + dialogName: dialog } }); @@ -59,7 +65,6 @@ module.exports = Self => { const cookie = docuwareConfig.token; const fileCabinetName = docuwareInfo.fileCabinetName; const find = docuwareInfo.find; - const options = { 'headers': { 'Accept': 'application/json', @@ -67,71 +72,44 @@ module.exports = Self => { 'Cookie': cookie } }; - // get fileCabinetId - const fileCabinetResponse = await got.get(`${docuwareUrl}/FileCabinets`, options).json(); - const fileCabinetId = fileCabinetResponse.FileCabinet.find(dialogs => dialogs.Name === fileCabinetName).Id; - - // get dialog - const dialogResponse = await got.get(`${docuwareUrl}/FileCabinets/${fileCabinetId}/dialogs`, options).json(); - const dialogId = dialogResponse.Dialog.find(dialogs => dialogs.DisplayName === 'find').Id; - - // get docuwareID - const docuwareOptions = { - 'headers': { - 'Accept': 'application/json', - 'Content-Type': 'application/json', - 'Cookie': cookie - }, - 'body': JSON.stringify({'Condition': [{DBName: find, Value: [0]}]}) - }; - const response = await got.post( - `${docuwareUrl}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`, - docuwareOptions - ); - const docuwareId = JSON.parse(response.body).Items[0].Id; - - // download file - const downloadUrl = `${docuwareUrl}/FileCabinets/${fileCabinetId}/Documents/${docuwareId}/FileDownload?targetFileType=Auto&keepAnnotations=false`; - const downloadOptions = { - 'headers': { - 'Cookie': cookie - } + const condtions = { + condition: [ + { + DBName: find, + Value: [id] + } + ] }; try { - // save file - const ticket = await models.Ticket.findById(id); + // get fileCabinetId + const fileCabinetResponse = await got.get(`${docuwareUrl}/FileCabinets`, options); + const fileCabinetJson = JSON.parse(fileCabinetResponse.body).FileCabinet; + const fileCabinetId = fileCabinetJson.find(dialogs => dialogs.Name === fileCabinetName).Id; - const shipped = ticket.shipped; - const year = shipped.getFullYear().toString(); - const month = (shipped.getMonth() + 1).toString(); - const day = shipped.getDate().toString(); - const fileName = `${year}${id}.pdf`; + // get dialog + const dialogResponse = await got.get(`${docuwareUrl}/FileCabinets/${fileCabinetId}/dialogs`, options); + const dialogJson = JSON.parse(dialogResponse.body).Dialog; + const dialogId = dialogJson.find(dialogs => dialogs.DisplayName === 'find').Id; - const container = await models.DocuwareContainer.container(year); - const rootPath = container.client.root; - const src = path.join(rootPath, year, month, day); - const fileSrc = path.join(src, fileName); + // get docuwareID + Object.assign(options, {'body': JSON.stringify(condtions)}); + const response = await got.post(`${docuwareUrl}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`, options); + const docuwareId = JSON.parse(response.body).Items[0].Id; - await fs.mkdir(src, {recursive: true}); - - const pipeline = promisify(nodeStream.pipeline); - await pipeline( - got.stream(downloadUrl, downloadOptions), - fs.createWriteStream(fileSrc) - ); - - // open file - const file = { - path: fileSrc, - contentType: 'application/pdf', - name: fileName + // download & save file + const fileName = `filename="${id}.pdf"`; + const contentType = 'application/pdf'; + const downloadUri = `${docuwareUrl}/FileCabinets/${fileCabinetId}/Documents/${docuwareId}/FileDownload?targetFileType=Auto&keepAnnotations=false`; + const downloadOptions = { + 'headers': { + 'Cookie': cookie + } }; - await fs.access(file.path); - let stream = fs.createReadStream(file.path); + const stream = got.stream(downloadUri, downloadOptions); - return [stream, file.contentType, `filename="${file.name}"`]; + return [stream, contentType, fileName]; } catch (error) { if (error.code === 'ENOENT') throw new UserError('The DOCUWARE PDF document does not exists'); diff --git a/back/methods/docuware/specs/checkFile.spec.js b/back/methods/docuware/specs/checkFile.spec.js index 7cb2ae6f9..2ebde0df4 100644 --- a/back/methods/docuware/specs/checkFile.spec.js +++ b/back/methods/docuware/specs/checkFile.spec.js @@ -1,129 +1,64 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; +const got = require('got'); -describe('image upload()', () => { - describe('as buyer', () => { - const buyerId = 35; - const workerId = 1106; - const itemId = 4; +describe('docuware download()', () => { + const ticketId = 1; + const userId = 9; + const ctx = { + req: { - it('should try to upload a file for the collection "catalog" and throw a privileges error', async() => { - const ctx = {req: {accessToken: {userId: buyerId}}, - args: { - id: workerId, - collection: 'user' - } - }; + accessToken: {userId: userId}, + headers: {origin: 'http://localhost:5000'}, + } + }; - let error; - try { - await app.models.Image.upload(ctx); - } catch (err) { - error = err; - } + const fileCabinetName = 'deliveryClientTest'; + const dialogDisplayName = 'find'; + const dialogName = 'findTest'; - expect(error.message).toEqual(`You don't have enough privileges`); - }); + const gotGetResponse = { + body: JSON.stringify( + { + FileCabinet: [ + {Id: 12, Name: fileCabinetName} + ], + Dialog: [ + {Id: 34, DisplayName: dialogDisplayName} + ] + }) + }; - it('should call to the TempContainer upload method for the collection "catalog"', async() => { - const containerModel = app.models.TempContainer; - spyOn(containerModel, 'upload'); + it('should return exist file in docuware', async() => { + const gotPostResponse = { + body: JSON.stringify( + { + Items: [ + {Id: 56} + ], + }) + }; - const ctx = {req: {accessToken: {userId: buyerId}}, - args: { - id: itemId, - collection: 'catalog' - } - }; + spyOn(got, 'get').and.returnValue(new Promise(resolve => resolve(gotGetResponse))); + spyOn(got, 'post').and.returnValue(new Promise(resolve => resolve(gotPostResponse))); - try { - await app.models.Image.upload(ctx); - } catch (err) { } + const result = await models.Docuware.checkFile(ctx, ticketId, fileCabinetName, dialogName); - expect(containerModel.upload).toHaveBeenCalled(); - }); + expect(result).toEqual(true); }); - describe('as marketing', () => { - const marketingId = 51; - const workerId = 1106; - const itemId = 4; + it('should return not exist file in docuware', async() => { + const gotPostResponse = { + body: JSON.stringify( + { + Items: [], + }) + }; - it('should be able to call to the TempContainer upload method for the collection "user"', async() => { - const containerModel = app.models.TempContainer; - spyOn(containerModel, 'upload'); + spyOn(got, 'get').and.returnValue(new Promise(resolve => resolve(gotGetResponse))); + spyOn(got, 'post').and.returnValue(new Promise(resolve => resolve(gotPostResponse))); - const ctx = {req: {accessToken: {userId: marketingId}}, - args: { - id: workerId, - collection: 'user' - } - }; + const result = await models.Docuware.checkFile(ctx, ticketId, fileCabinetName, dialogName); - try { - await app.models.Image.upload(ctx); - } catch (err) { } - - expect(containerModel.upload).toHaveBeenCalled(); - }); - - it('should be able to call to the TempContainer upload method for the collection "catalog"', async() => { - const containerModel = app.models.TempContainer; - spyOn(containerModel, 'upload'); - - const ctx = {req: {accessToken: {userId: marketingId}}, - args: { - id: itemId, - collection: 'catalog' - } - }; - - try { - await app.models.Image.upload(ctx); - } catch (err) { } - - expect(containerModel.upload).toHaveBeenCalled(); - }); - }); - - describe('as hhrr', () => { - const hhrrId = 37; - const workerId = 1106; - const itemId = 4; - - it('should upload a file for the collection "user" and call to the TempContainer upload method', async() => { - const containerModel = app.models.TempContainer; - spyOn(containerModel, 'upload'); - - const ctx = {req: {accessToken: {userId: hhrrId}}, - args: { - id: itemId, - collection: 'user' - } - }; - - try { - await app.models.Image.upload(ctx); - } catch (err) { } - - expect(containerModel.upload).toHaveBeenCalled(); - }); - - it('should try to upload a file for the collection "catalog" and throw a privilege error', async() => { - const ctx = {req: {accessToken: {userId: hhrrId}}, - args: { - id: workerId, - collection: 'catalog' - } - }; - - let error; - try { - await app.models.Image.upload(ctx); - } catch (err) { - error = err; - } - - expect(error.message).toEqual(`You don't have enough privileges`); - }); + expect(result).toEqual(false); }); }); diff --git a/back/methods/docuware/specs/download.spec.js b/back/methods/docuware/specs/download.spec.js index 4bdf800b4..436063fd8 100644 --- a/back/methods/docuware/specs/download.spec.js +++ b/back/methods/docuware/specs/download.spec.js @@ -1,9 +1,10 @@ const models = require('vn-loopback/server/server').models; -const fs = require('fs-extra'); +const got = require('got'); +const stream = require('stream'); -describe('image download()', () => { +describe('docuware download()', () => { const userId = 9; - const invoiceId = 1; + const ticketId = 1; const ctx = { req: { @@ -13,16 +14,37 @@ describe('image download()', () => { }; it('should return the downloaded file name', async() => { - spyOn(models.DocuwareContainer, 'container').and.returnValue({ - client: {root: '/path'} - }); - spyOn(fs, 'createReadStream').and.returnValue(new Promise(resolve => resolve('streamObject'))); - spyOn(fs, 'access').and.returnValue(true); - spyOn(models.InvoiceOut, 'createPdf').and.returnValue(new Promise(resolve => resolve(true))); + const fileCabinetName = 'deliveryClientTest'; + const dialogDisplayName = 'find'; + const dialogName = 'findTest'; + const gotGetResponse = { + body: JSON.stringify( + { + FileCabinet: [ + {Id: 12, Name: fileCabinetName} + ], + Dialog: [ + {Id: 34, DisplayName: dialogDisplayName} + ] + }) + }; - const result = await models.InvoiceOut.download(ctx, invoiceId); + const gotPostResponse = { + body: JSON.stringify( + { + Items: [ + {Id: 56} + ], + }) + }; + + spyOn(got, 'get').and.returnValue(new Promise(resolve => resolve(gotGetResponse))); + spyOn(got, 'post').and.returnValue(new Promise(resolve => resolve(gotPostResponse))); + spyOn(got, 'stream').and.returnValue(new stream.PassThrough({objectMode: true})); + + const result = await models.Docuware.download(ctx, ticketId, fileCabinetName, dialogName); expect(result[1]).toEqual('application/pdf'); - expect(result[2]).toMatch(/filename="\d{4}T1111111.pdf"/); + expect(result[2]).toEqual(`filename="${ticketId}.pdf"`); }); }); diff --git a/back/model-config.json b/back/model-config.json index f1b662354..4c79d565b 100644 --- a/back/model-config.json +++ b/back/model-config.json @@ -50,9 +50,6 @@ "DocuwareConfig": { "dataSource": "vn" }, - "DocuwareContainer": { - "dataSource": "docuwareStorage" - }, "EmailUser": { "dataSource": "vn" }, diff --git a/back/models/docuware-container.json b/back/models/docuware-container.json deleted file mode 100644 index 8180695c1..000000000 --- a/back/models/docuware-container.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "DocuwareContainer", - "base": "Container", - "acls": [{ - "accessType": "READ", - "principalType": "ROLE", - "principalId": "$everyone", - "permission": "ALLOW" - }] -} \ No newline at end of file diff --git a/db/changes/10420-valentines/00-docuware.sql b/db/changes/10420-valentines/00-docuware.sql index ca4b0a114..e5311252d 100644 --- a/db/changes/10420-valentines/00-docuware.sql +++ b/db/changes/10420-valentines/00-docuware.sql @@ -8,4 +8,4 @@ CREATE TABLE `vn`.`docuware` ( INSERT INTO `vn`.`docuware` (`name`, `fileCabinetName`, `dialogName` , `find`) VALUES - ('deliveryClient', 'Albaranes cliente', 'findTicket', 'N__ALBAR_N'); + ('deliveryClient', 'Albaranes cliente', 'findTicket', 'N__ALBAR_N'); \ No newline at end of file diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 7c7709716..74568ebc7 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -2444,10 +2444,6 @@ INSERT INTO `bs`.`defaulter` (`clientFk`, `amount`, `created`, `defaulterSinced` (1107, 500, CURDATE(), CURDATE()), (1109, 500, CURDATE(), CURDATE()); -INSERT INTO `vn`.`docuwareConfig` (`url`, `token`) - VALUES - ('https://verdnatura.docuware.cloud/docuware/platform', '.DWPLATFORMAUTH=66C7DCD2B9365EF974AFEB43F61715152082EF39C649CB1506F9ACC34DD54C5B34944DDFBF97EAE5C5147063850B16B3B9FFFB2232FDD03F35B51B1305D5E1E7DB833F6AC560C739E40778932C8BCC64DA7ECE64B0B1F71A3DB986B3710DFA4C061776F9C61DDAA60EF30F7F37FB8733BF4B1830F98102E403E4E751F13F31B582AEDF5B33A25346E10CA34A8559F0CD6ACA39A7379AC67BE061CD27531D02675123FB0D254426E306EC6FA49DED7CF30EBBAD8365BE60D7E919D4AD2EB8F9CD94424DFCD95151C0F6DD3EE8569A7CA4A30D1A3F42DA9DD368A33955A4AFE9CB4FCCC230801BC645AA87A68EC33F6BD165D5A0F02B63D5D832AF936B9398EC428D4ACD41E56848A2CDF797C99226BB2AC48EB5F9C1C5D8C1C7F6A7F67F455ABAC1DBC7443521876B588F369CAE6EC81747BA3134F7EE2662DA296FC2C16528B0AB4839EEE6EE79A82AA3888E4AB53FEC6FFAD26A592ABD76441AFCD634097D0B0B57E16A510D0E6F769710C6F4BDB1476CCDE0967788B90A67BADFB7E37B1F7F60C879A0E9D75AD2BA6647FC11477305B44512AF408845E6099CF64B7A3D77EE; ApplicationGatewayAffinity=c5fad6cb3332163516d49258a1ebf52c; ApplicationGatewayAffinityCORS=c5fad6cb3332163516d49258a1ebf52c; DWPLATFORMBROWSERID=C2173B1A1FE42B449AA12C8465561991BA4664AFA9F44D4C9DD8748FF92EFEBF629E4A75860747C4D8290F70344385CCAFE3EAFD8814CF44F452275C95E89D19D35A178D0BCC6930EF07AC7CF91672F7CB43C2B54CDFAE52BDF17C467FFFE3411FE0D792E4F513726F295648DDE627DF2C6288C89086E2DE6916E4B0A5291AA7C269015A5328147783EC15FB8EF43EE5DAE5A6CD3D318570670234176CAE7B19D9812D3F09D731C5A27A621B39D0564C81774FA993160AAAD833CC75634445B7B47C5A2E26004FF914606B5B0CB897A694F26AD5E80A1EE0D3B7BA4881F8A570'); - INSERT INTO `vn`.`docuware` (`name`, `fileCabinetName`, `dialogName` , `find`) VALUES - ('deliveryClient', 'Albaranes cliente', 'findTicket', 'N__ALBAR_N'); \ No newline at end of file + ('deliveryClientTest', 'deliveryClientTest', 'findTest', 'word'); \ No newline at end of file diff --git a/loopback/server/datasources.json b/loopback/server/datasources.json index 27921c78a..0df03882c 100644 --- a/loopback/server/datasources.json +++ b/loopback/server/datasources.json @@ -83,16 +83,5 @@ "application/octet-stream", "application/pdf" ] - }, - "docuwareStorage": { - "name": "docuwareStorage", - "connector": "loopback-component-storage", - "provider": "filesystem", - "root": "./storage/pdfs/docuware", - "maxFileSize": "52428800", - "allowedContentTypes": [ - "application/octet-stream", - "application/pdf" - ] } } \ No newline at end of file diff --git a/modules/invoiceOut/front/descriptor-menu/index.html b/modules/invoiceOut/front/descriptor-menu/index.html index 070da18e1..345e67d95 100644 --- a/modules/invoiceOut/front/descriptor-menu/index.html +++ b/modules/invoiceOut/front/descriptor-menu/index.html @@ -1,144 +1,138 @@ +icon="more_vert" +vn-popover="menu"> - - - Show invoice... + + + Show invoice... + + + + Show as PDF + + + Show as CSV + + + + + + Send invoice... - - - - Show as PDF - - - Show as DOCUWARE - - - Show as CSV - - - - - - Send invoice... - - - - - Send PDF - - - Send CSV - - - - - - Delete Invoice - - - Book invoice - - - {{!$ctrl.invoiceOut.hasPdf ? 'Generate PDF invoice': 'Regenerate PDF invoice'}} - - - Show CITES letter - - + + + + Send PDF + + + Send CSV + + + + + + Delete Invoice + + + Book invoice + + + {{!$ctrl.invoiceOut.hasPdf ? 'Generate PDF invoice': 'Regenerate PDF invoice'}} + + + Show CITES letter + + +vn-id="deleteConfirmation" +on-accept="$ctrl.deleteInvoiceOut()" +question="Are you sure you want to delete this invoice?"> +vn-id="bookConfirmation" +on-accept="$ctrl.bookInvoiceOut()" +question="Are you sure you want to book this invoice?"> +vn-id="clientDescriptor"> +vn-id="createInvoicePdfConfirmation" +on-accept="$ctrl.createPdfInvoice()" +question="Are you sure you want to generate/regenerate the PDF invoice?" +message="Generate PDF invoice document"> - - Are you sure you want to send it? - - - - - - - +vn-id="sendPdfConfirmation" +on-accept="$ctrl.sendPdfInvoice($data)" +message="Send PDF invoice"> + + Are you sure you want to send it? + + + + + + + - - Are you sure you want to send it? - - - - - - - +vn-id="sendCsvConfirmation" +on-accept="$ctrl.sendCsvInvoice($data)" +message="Send CSV invoice"> + + Are you sure you want to send it? + + + + + + + \ No newline at end of file diff --git a/modules/invoiceOut/front/descriptor-menu/index.js b/modules/invoiceOut/front/descriptor-menu/index.js index f6855795a..7738845f9 100644 --- a/modules/invoiceOut/front/descriptor-menu/index.js +++ b/modules/invoiceOut/front/descriptor-menu/index.js @@ -88,19 +88,6 @@ class Controller extends Section { }); } - downloadDocuware() { - const options = { - ticketId: 3367050 - }; - - return this.$http.post(`Docuwares/download`, options) - .then(() => { - const snackbarMessage = this.$t( - `The invoice PDF document has been downloaded`); - this.vnApp.showSuccess(snackbarMessage); - }); - } - sendPdfInvoice($data) { if (!$data.email) return this.vnApp.showError(this.$t(`The email can't be empty`)); diff --git a/modules/ticket/front/descriptor-menu/index.html b/modules/ticket/front/descriptor-menu/index.html index 87a821746..2439bfb64 100644 --- a/modules/ticket/front/descriptor-menu/index.html +++ b/modules/ticket/front/descriptor-menu/index.html @@ -27,10 +27,10 @@ - as DOCUWARE + as PDF this.ticket = res.data) .then(() => { - this.hasDocuware(); this.canStowaway(); this.isTicketEditable(); + this.hasDocuware(); }); } @@ -124,7 +124,11 @@ class Controller extends Section { } hasDocuware() { - this.$http.get(`Docuwares/${this.id}/checkFile`) + const params = { + fileCabinet: 'deliveryClient', + dialog: 'findTicket' + }; + this.$http.post(`Docuwares/${this.id}/checkFile`, params) .then(res => { this.hasDocuware = res.data; }); diff --git a/modules/ticket/front/descriptor-menu/index.spec.js b/modules/ticket/front/descriptor-menu/index.spec.js index 288c7508b..0a80d0884 100644 --- a/modules/ticket/front/descriptor-menu/index.spec.js +++ b/modules/ticket/front/descriptor-menu/index.spec.js @@ -206,7 +206,8 @@ describe('Ticket Component vnTicketDescriptorMenu', () => { it('should make a query and show a success snackbar', () => { jest.spyOn(controller.vnApp, 'showSuccess'); - $httpBackend.whenGET(`Tickets/16`).respond(); + $httpBackend.whenPOST(`Docuwares/${ticket.id}/checkFile`).respond(); + $httpBackend.whenGET(`Tickets/${ticket.id}`).respond(); $httpBackend.expectPOST(`InvoiceOuts/${ticket.invoiceOut.id}/createPdf`).respond(); controller.createPdfInvoice(); $httpBackend.flush(); @@ -275,4 +276,12 @@ describe('Ticket Component vnTicketDescriptorMenu', () => { }); }); }); + + describe('hasDocuware()', () => { + it('should call hasDocuware method', () => { + $httpBackend.whenPOST(`Docuwares/${ticket.id}/checkFile`).respond(); + controller.hasDocuware(); + $httpBackend.flush(); + }); + }); }); From 32e3af0c257ce4d8782a2164b180cff240ad4e23 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 21 Feb 2022 08:53:37 +0100 Subject: [PATCH 11/54] tabulations --- .../front/descriptor-menu/index.html | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/modules/invoiceOut/front/descriptor-menu/index.html b/modules/invoiceOut/front/descriptor-menu/index.html index 345e67d95..0e1d7c2ab 100644 --- a/modules/invoiceOut/front/descriptor-menu/index.html +++ b/modules/invoiceOut/front/descriptor-menu/index.html @@ -1,7 +1,7 @@ + icon="more_vert" + vn-popover="menu"> @@ -80,32 +80,32 @@ vn-popover="menu"> + vn-id="deleteConfirmation" + on-accept="$ctrl.deleteInvoiceOut()" + question="Are you sure you want to delete this invoice?"> + vn-id="bookConfirmation" + on-accept="$ctrl.bookInvoiceOut()" + question="Are you sure you want to book this invoice?"> + vn-id="clientDescriptor"> + vn-id="createInvoicePdfConfirmation" + on-accept="$ctrl.createPdfInvoice()" + question="Are you sure you want to generate/regenerate the PDF invoice?" + message="Generate PDF invoice document"> + vn-id="sendPdfConfirmation" + on-accept="$ctrl.sendPdfInvoice($data)" + message="Send PDF invoice"> Are you sure you want to send it? + vn-id="sendCsvConfirmation" + on-accept="$ctrl.sendCsvInvoice($data)" + message="Send CSV invoice"> Are you sure you want to send it? Date: Mon, 21 Feb 2022 08:57:43 +0100 Subject: [PATCH 12/54] tabulations --- .../front/descriptor-menu/index.html | 183 +++++++++--------- 1 file changed, 91 insertions(+), 92 deletions(-) diff --git a/modules/invoiceOut/front/descriptor-menu/index.html b/modules/invoiceOut/front/descriptor-menu/index.html index 0e1d7c2ab..ea0f2eb5a 100644 --- a/modules/invoiceOut/front/descriptor-menu/index.html +++ b/modules/invoiceOut/front/descriptor-menu/index.html @@ -4,80 +4,79 @@ vn-popover="menu"> - - - Show invoice... - - - - Show as PDF - - - Show as CSV - - - - - - Send invoice... - - - - - Send PDF - - - Send CSV - - - - - - Delete Invoice - - - Book invoice - - - {{!$ctrl.invoiceOut.hasPdf ? 'Generate PDF invoice': 'Regenerate PDF invoice'}} - - - Show CITES letter - - + + + Show invoice... + + + + Show as PDF + + + Show as CSV + + + + + + Send invoice... + + + + Send PDF + + + Send CSV + + + + + + Delete Invoice + + + Book invoice + + + {{!$ctrl.invoiceOut.hasPdf ? 'Generate PDF invoice': 'Regenerate PDF invoice'}} + + + Show CITES letter + + - - Are you sure you want to send it? - - - - - - - + + Are you sure you want to send it? + + + + + + + @@ -124,13 +123,13 @@ vn-id="sendCsvConfirmation" on-accept="$ctrl.sendCsvInvoice($data)" message="Send CSV invoice"> - - Are you sure you want to send it? - - - + + Are you sure you want to send it? + + + From 6a5d49a53586769a67aba9991ea6410875670526 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 21 Feb 2022 08:59:42 +0100 Subject: [PATCH 13/54] tabulations --- modules/invoiceOut/front/descriptor-menu/index.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/invoiceOut/front/descriptor-menu/index.html b/modules/invoiceOut/front/descriptor-menu/index.html index ea0f2eb5a..859486ab1 100644 --- a/modules/invoiceOut/front/descriptor-menu/index.html +++ b/modules/invoiceOut/front/descriptor-menu/index.html @@ -130,8 +130,8 @@ ng-model="sendCsvConfirmation.data.email"> - - - - + + + + \ No newline at end of file From 8bbb5d5c27f7907ce606807f9446846b12d528b7 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 21 Feb 2022 11:28:00 +0100 Subject: [PATCH 14/54] variable name --- db/changes/10420-valentines/00-docuwareConfig.sql | 6 +++++- modules/ticket/front/descriptor-menu/index.html | 4 ++-- modules/ticket/front/descriptor-menu/index.js | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/db/changes/10420-valentines/00-docuwareConfig.sql b/db/changes/10420-valentines/00-docuwareConfig.sql index c2c78c67e..1ba19af6d 100644 --- a/db/changes/10420-valentines/00-docuwareConfig.sql +++ b/db/changes/10420-valentines/00-docuwareConfig.sql @@ -2,4 +2,8 @@ CREATE TABLE `vn`.`docuwareConfig` ( `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, `url` varchar(75) NULL, `token` varchar(1000) DEFAULT NULL -); \ No newline at end of file +); + +INSERT INTO `vn`.`docuwareConfig` (`url`) + VALUES + ('https://verdnatura.docuware.cloud/docuware/platform'); \ No newline at end of file diff --git a/modules/ticket/front/descriptor-menu/index.html b/modules/ticket/front/descriptor-menu/index.html index 2439bfb64..d613fb5de 100644 --- a/modules/ticket/front/descriptor-menu/index.html +++ b/modules/ticket/front/descriptor-menu/index.html @@ -20,13 +20,13 @@ as PDF diff --git a/modules/ticket/front/descriptor-menu/index.js b/modules/ticket/front/descriptor-menu/index.js index 2af1b30c5..4304d8523 100644 --- a/modules/ticket/front/descriptor-menu/index.js +++ b/modules/ticket/front/descriptor-menu/index.js @@ -130,7 +130,7 @@ class Controller extends Section { }; this.$http.post(`Docuwares/${this.id}/checkFile`, params) .then(res => { - this.hasDocuware = res.data; + this.hasDocuwareFile = res.data; }); } From 812d79f2d56f69280f08b68b02a13e01520e3311 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 21 Feb 2022 15:11:39 +0100 Subject: [PATCH 15/54] feat(client_defaulter): implemented smart-table --- front/core/components/smart-table/table.scss | 5 + .../client/back/methods/defaulter/filter.js | 6 +- modules/client/front/defaulter/index.html | 216 ++++++++---------- modules/client/front/defaulter/index.js | 84 ++++++- modules/client/front/defaulter/index.spec.js | 31 ++- 5 files changed, 209 insertions(+), 133 deletions(-) diff --git a/front/core/components/smart-table/table.scss b/front/core/components/smart-table/table.scss index c38c149ca..b40b988a7 100644 --- a/front/core/components/smart-table/table.scss +++ b/front/core/components/smart-table/table.scss @@ -99,6 +99,11 @@ smart-table table { } } } + & > td > textarea { + background-color: $color-font-light; + color: $color-font-bg; + width: 90%; + } } .vn-check { margin: 0; diff --git a/modules/client/back/methods/defaulter/filter.js b/modules/client/back/methods/defaulter/filter.js index c06d1c51b..0a1d5093b 100644 --- a/modules/client/back/methods/defaulter/filter.js +++ b/modules/client/back/methods/defaulter/filter.js @@ -58,16 +58,16 @@ module.exports = Self => { DISTINCT c.id clientFk, c.name clientName, c.salesPersonFk, - u.name salesPersonName, + u.nickname salesPersonName, d.amount, co.created, CONCAT(DATE(co.created), ' ', co.text) observation, uw.id workerFk, - uw.name workerName, + uw.nickname workerName, c.creditInsurance, d.defaulterSinced FROM vn.defaulter d - JOIN vn.client c ON c.id = d.clientFk + JOIN vn.client c ON c.id = d.clientFk LEFT JOIN vn.clientObservation co ON co.clientFk = c.id LEFT JOIN account.user u ON u.id = c.salesPersonFk LEFT JOIN account.user uw ON uw.id = co.workerFk diff --git a/modules/client/front/defaulter/index.html b/modules/client/front/defaulter/index.html index 121556df2..6d723c975 100644 --- a/modules/client/front/defaulter/index.html +++ b/modules/client/front/defaulter/index.html @@ -15,17 +15,18 @@ model="model"> - - - -
+ + + +
Total
+ value="{{$ctrl.balanceDueTotal | currency: 'EUR': 2}}">
@@ -38,90 +39,98 @@ icon="icon-notes">
-
- - - - - - - - Client - Comercial - - Balance D. - - - Author - - Last observation - - Credit I. - - From - - - - - - - - - - - {{::defaulter.clientName}} - - - - - {{::defaulter.salesPersonName | dashIfEmpty}} - - - {{::defaulter.amount}} - - - {{::defaulter.workerName | dashIfEmpty}} - - - - - - - {{::defaulter.creditInsurance}} - {{::defaulter.defaulterSinced | date: 'dd/MM/yyyy'}} - - - -
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + Client + + Comercial + + Balance D. + + Author + + Last observation + + Credit I. + + From +
+ + + + + {{::defaulter.clientName}} + + + + {{::defaulter.salesPersonName | dashIfEmpty}} + + {{::defaulter.amount | currency: 'EUR': 2}} + + {{::defaulter.workerName | dashIfEmpty}} + + + + {{::defaulter.creditInsurance | currency: 'EUR': 2}}{{::defaulter.defaulterSinced | date: 'dd/MM/yyyy'}}
+
+ + + vn-id="client-descriptor"> + vn-id="worker-descriptor"> - - - - - Filter by selection - - - Exclude selection - - - Remove filter - - - Remove all filters - - - Copy value - - - - 0) { - for (let defaulter of this.checked) - balanceDueTotal += defaulter.amount; - - return balanceDueTotal; - } + for (let defaulter of defaulters) + balanceDueTotal += defaulter.amount; return balanceDueTotal; } @@ -32,6 +85,22 @@ export default class Controller extends Section { return checkedLines; } + chipColor(date) { + const day = 24 * 60 * 60 * 1000; + const today = new Date(); + today.setHours(0, 0, 0, 0); + + const observationShipped = new Date(date); + observationShipped.setHours(0, 0, 0, 0); + + const difference = today - observationShipped; + + if (difference > (day * 20)) + return 'alert'; + if (difference > (day * 10)) + return 'warning'; + } + onResponse() { if (!this.defaulter.observation) throw new UserError(`The message can't be empty`); @@ -52,7 +121,10 @@ export default class Controller extends Section { exprBuilder(param, value) { switch (param) { + case 'observation': + return {[`observation`]: value}; case 'clientName': + case 'workerFk': case 'salesPersonFk': return {[`d.${param}`]: value}; } diff --git a/modules/client/front/defaulter/index.spec.js b/modules/client/front/defaulter/index.spec.js index 6428952ec..8d6c8c307 100644 --- a/modules/client/front/defaulter/index.spec.js +++ b/modules/client/front/defaulter/index.spec.js @@ -39,11 +39,7 @@ describe('client defaulter', () => { describe('balanceDueTotal() getter', () => { it('should return balance due total', () => { const data = controller.$.model.data; - data[1].checked = true; - data[2].checked = true; - - const checkedRows = controller.checked; - const expectedAmount = checkedRows[0].amount + checkedRows[1].amount; + const expectedAmount = data[0].amount + data[1].amount + data[2].amount; const result = controller.balanceDueTotal; @@ -51,6 +47,31 @@ describe('client defaulter', () => { }); }); + describe('chipColor()', () => { + it('should return undefined when the date is the present', () => { + let today = new Date(); + let result = controller.chipColor(today); + + expect(result).toEqual(undefined); + }); + + it('should return warning when the date is 10 days in the past', () => { + let pastDate = new Date(); + pastDate = pastDate.setDate(pastDate.getDate() - 11); + let result = controller.chipColor(pastDate); + + expect(result).toEqual('warning'); + }); + + it('should return alert when the date is 20 days in the past', () => { + let pastDate = new Date(); + pastDate = pastDate.setDate(pastDate.getDate() - 21); + let result = controller.chipColor(pastDate); + + expect(result).toEqual('alert'); + }); + }); + describe('onResponse()', () => { it('should return error for empty message', () => { let error; From 0d8dffac307d289086d7405345637e82be693a3a Mon Sep 17 00:00:00 2001 From: joan Date: Tue, 22 Feb 2022 07:30:26 +0100 Subject: [PATCH 16/54] refactor(chat): check rocketchat status before sending message --- back/methods/chat/getServiceAuth.js | 55 ++++++++++ back/methods/chat/send.js | 119 ++++------------------ back/methods/chat/sendCheckingPresence.js | 67 ++++++++---- back/models/chat.js | 1 + 4 files changed, 118 insertions(+), 124 deletions(-) create mode 100644 back/methods/chat/getServiceAuth.js diff --git a/back/methods/chat/getServiceAuth.js b/back/methods/chat/getServiceAuth.js new file mode 100644 index 000000000..7eb0ceaa5 --- /dev/null +++ b/back/methods/chat/getServiceAuth.js @@ -0,0 +1,55 @@ +const axios = require('axios'); +const tokenLifespan = 10; +module.exports = Self => { + Self.remoteMethodCtx('getServiceAuth', { + description: 'Send a RocketChat message', + accessType: 'READ', + accepts: [], + returns: { + type: 'object', + root: true + }, + http: { + path: `/getServiceAuth`, + verb: 'GET' + } + }); + + Self.getServiceAuth = async() => { + if (!this.login) + this.login = await requestToken(); + + if (!this.login) return; + + if (Date.now() > this.login.expires) + this.login = await requestToken(); + + return this.login; + }; + + /** + * Requests a new Rocketchat token + */ + async function requestToken() { + const models = Self.app.models; + const chatConfig = await models.ChatConfig.findOne(); + + const {data} = await axios.post(`${chatConfig.api}/login`, { + user: chatConfig.user, + password: chatConfig.password + }); + + const requestData = data.data; + if (requestData) { + return { + host: chatConfig.host, + api: chatConfig.api, + auth: { + userId: requestData.userId, + token: requestData.authToken + }, + expires: Date.now() + (1000 * 60 * tokenLifespan) + }; + } + } +}; diff --git a/back/methods/chat/send.js b/back/methods/chat/send.js index 209dfb035..5f7944945 100644 --- a/back/methods/chat/send.js +++ b/back/methods/chat/send.js @@ -1,4 +1,4 @@ -const got = require('got'); +const axios = require('axios'); module.exports = Self => { Self.remoteMethodCtx('send', { description: 'Send a RocketChat message', @@ -30,86 +30,12 @@ module.exports = Self => { const sender = await models.Account.findById(accessToken.userId); const recipient = to.replace('@', ''); - if (sender.name != recipient) { - let {body} = await sendMessage(sender, to, message); - if (body) - body = JSON.parse(body); - else - body = false; - - return body; - } - - return false; + if (sender.name != recipient) + return sendMessage(sender, to, message); }; async function sendMessage(sender, channel, message) { - const config = await getConfig(); - const avatar = `${config.host}/avatar/${sender.name}`; - const uri = `${config.api}/chat.postMessage`; - - return sendAuth(uri, { - 'channel': channel, - 'avatar': avatar, - 'alias': sender.nickname, - 'text': message - }).catch(async error => { - if (error.statusCode === 401) { - this.auth = null; - - return sendMessage(sender, channel, message); - } - - throw new Error(error.message); - }); - } - - /** - * Returns a rocketchat token - * @return {Object} userId and authToken - */ - async function getAuthToken() { - if (!this.auth || this.auth && !this.auth.authToken) { - const config = await getConfig(); - const uri = `${config.api}/login`; - let {body} = await send(uri, { - user: config.user, - password: config.password - }); - - if (body) { - body = JSON.parse(body); - this.auth = body.data; - } - } - - return this.auth; - } - - /** - * Returns a rocketchat config - * @return {Object} Auth config - */ - async function getConfig() { - if (!this.chatConfig) { - const models = Self.app.models; - - this.chatConfig = await models.ChatConfig.findOne(); - } - - return this.chatConfig; - } - - /** - * Send unauthenticated request - * @param {*} uri - Request uri - * @param {*} params - Request params - * @param {*} options - Request options - * - * @return {Object} Request response - */ - async function send(uri, params, options = {}) { - if (process.env.NODE_ENV !== 'production') { + /* if (process.env.NODE_ENV !== 'production') { return new Promise(resolve => { return resolve({ body: JSON.stringify( @@ -118,34 +44,23 @@ module.exports = Self => { }); }); } + */ + const login = await Self.getServiceAuth(); - const defaultOptions = { - form: params - }; + const avatar = `${login.host}/avatar/${sender.name}`; - if (options) Object.assign(defaultOptions, options); - - return got.post(uri, defaultOptions); - } - - /** - * Send authenticated request - * @param {*} uri - Request uri - * @param {*} body - Request params - * - * @return {Object} Request response - */ - async function sendAuth(uri, body) { - const login = await getAuthToken(); const options = { - headers: {} + headers: { + 'X-Auth-Token': login.auth.token, + 'X-User-Id': login.auth.userId + }, }; - if (login) { - options.headers['X-Auth-Token'] = login.authToken; - options.headers['X-User-Id'] = login.userId; - } - - return send(uri, body, options); + return axios.post(`${login.api}/chat.postMessage`, { + 'channel': channel, + 'avatar': avatar, + 'alias': sender.nickname, + 'text': message + }, options); } }; diff --git a/back/methods/chat/sendCheckingPresence.js b/back/methods/chat/sendCheckingPresence.js index fcde20130..671e8f60f 100644 --- a/back/methods/chat/sendCheckingPresence.js +++ b/back/methods/chat/sendCheckingPresence.js @@ -1,21 +1,23 @@ +const axios = require('axios'); + module.exports = Self => { Self.remoteMethodCtx('sendCheckingPresence', { description: 'Sends a RocketChat message to a working worker or department channel', accessType: 'WRITE', accepts: [{ - arg: 'workerId', - type: 'Number', + arg: 'recipientId', + type: 'number', required: true, - description: 'The worker id of the destinatary' + description: 'The recipient user id' }, { arg: 'message', - type: 'String', + type: 'string', required: true, description: 'The message' }], returns: { - type: 'Object', + type: 'object', root: true }, http: { @@ -33,30 +35,51 @@ module.exports = Self => { Object.assign(myOptions, options); const models = Self.app.models; - const account = await models.Account.findById(recipientId, null, myOptions); const userId = ctx.req.accessToken.userId; + const recipient = await models.Account.findById(recipientId, null, myOptions); + // Prevent sending messages to yourself if (recipientId == userId) return false; - if (!account) + if (!recipient) throw new Error(`Could not send message "${message}" to worker id ${recipientId} from user ${userId}`); - const query = `SELECT worker_isWorking(?) isWorking`; - const [result] = await Self.rawSql(query, [recipientId], myOptions); + const {data} = await getUserStatus(recipient.name); + if (data) { + if (data.status === 'offline') { + // Send message to department room + const workerDepartment = await models.WorkerDepartment.findById(recipientId, { + include: { + relation: 'department' + } + }, myOptions); + const department = workerDepartment && workerDepartment.department(); + const channelName = department && department.chatName; - if (!result.isWorking) { - const workerDepartment = await models.WorkerDepartment.findById(recipientId, { - include: { - relation: 'department' - } - }, myOptions); - const department = workerDepartment && workerDepartment.department(); - const channelName = department && department.chatName; - - if (channelName) - return Self.send(ctx, `#${channelName}`, `@${account.name} ➔ ${message}`); + if (channelName) + return Self.send(ctx, `#${channelName}`, `@${recipient.name} ➔ ${message}`); + } else + return Self.send(ctx, `@${recipient.name}`, message); } - - return Self.send(ctx, `@${account.name}`, message); }; + + /** + * Returns the current user status on Rocketchat + * + * @param {string} username - The recipient user name + * @return {Promise} - The request promise + */ + async function getUserStatus(username) { + const login = await Self.getServiceAuth(); + + const options = { + params: {username}, + headers: { + 'X-Auth-Token': login.auth.token, + 'X-User-Id': login.auth.userId + }, + }; + + return axios.get(`${login.api}/users.getStatus`, options); + } }; diff --git a/back/models/chat.js b/back/models/chat.js index 5487569c1..7d8468aae 100644 --- a/back/models/chat.js +++ b/back/models/chat.js @@ -1,4 +1,5 @@ module.exports = Self => { + require('../methods/chat/getServiceAuth')(Self); require('../methods/chat/send')(Self); require('../methods/chat/sendCheckingPresence')(Self); require('../methods/chat/notifyIssues')(Self); From 4e89c66e2ca550c80deaa46183a6ffeef523ffc0 Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 22 Feb 2022 08:58:22 +0100 Subject: [PATCH 17/54] refactor(client_defaulter): add column date --- e2e/helpers/selectors.js | 10 +++++----- e2e/paths/02-client/21_defaulter.spec.js | 3 ++- front/core/components/smart-table/table.scss | 5 ----- modules/client/front/defaulter/index.html | 21 +++++++++++++++----- modules/client/front/defaulter/locale/es.yml | 8 +++++--- 5 files changed, 28 insertions(+), 19 deletions(-) diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index f0a5c37b5..bb141de8e 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -305,11 +305,11 @@ export default { anyCreditInsuranceLine: 'vn-client-credit-insurance-insurance-index vn-tbody > vn-tr', }, clientDefaulter: { - anyClient: 'vn-client-defaulter-index vn-tbody > vn-tr', - firstClientName: 'vn-client-defaulter-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(2) > span', - firstSalesPersonName: 'vn-client-defaulter-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(3) > span', - firstObservation: 'vn-client-defaulter-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(6) > vn-textarea[ng-model="defaulter.observation"]', - allDefaulterCheckbox: 'vn-client-defaulter-index vn-thead vn-multi-check', + anyClient: 'vn-client-defaulter-index tbody > tr', + firstClientName: 'vn-client-defaulter-index tbody > tr:nth-child(1) > td:nth-child(2) > span', + firstSalesPersonName: 'vn-client-defaulter-index tbody > tr:nth-child(1) > td:nth-child(3) > span', + firstObservation: 'vn-client-defaulter-index tbody > tr:nth-child(1) > td:nth-child(6) > vn-textarea[ng-model="defaulter.observation"]', + allDefaulterCheckbox: 'vn-client-defaulter-index thead vn-multi-check', addObservationButton: 'vn-client-defaulter-index vn-button[icon="icon-notes"]', observation: '.vn-dialog.shown vn-textarea[ng-model="$ctrl.defaulter.observation"]', saveButton: 'button[response="accept"]' diff --git a/e2e/paths/02-client/21_defaulter.spec.js b/e2e/paths/02-client/21_defaulter.spec.js index 89b5c5761..1066776d6 100644 --- a/e2e/paths/02-client/21_defaulter.spec.js +++ b/e2e/paths/02-client/21_defaulter.spec.js @@ -29,7 +29,7 @@ describe('Client defaulter path', () => { await page.waitToGetProperty(selectors.clientDefaulter.firstSalesPersonName, 'innerText'); expect(clientName).toEqual('Ororo Munroe'); - expect(salesPersonName).toEqual('salesPerson'); + expect(salesPersonName).toEqual('salesPersonNick'); }); it('should first observation not changed', async() => { @@ -65,6 +65,7 @@ describe('Client defaulter path', () => { it('should first observation changed', async() => { const message = await page.waitForSnackbar(); + await page.waitForSelector(selectors.clientDefaulter.firstObservation); const result = await page.waitToGetProperty(selectors.clientDefaulter.firstObservation, 'value'); expect(message.text).toContain('Observation saved!'); diff --git a/front/core/components/smart-table/table.scss b/front/core/components/smart-table/table.scss index b40b988a7..c38c149ca 100644 --- a/front/core/components/smart-table/table.scss +++ b/front/core/components/smart-table/table.scss @@ -99,11 +99,6 @@ smart-table table { } } } - & > td > textarea { - background-color: $color-font-light; - color: $color-font-bg; - width: 90%; - } } .vn-check { margin: 0; diff --git a/modules/client/front/defaulter/index.html b/modules/client/front/defaulter/index.html index 6d723c975..59f7b7d67 100644 --- a/modules/client/front/defaulter/index.html +++ b/modules/client/front/defaulter/index.html @@ -65,9 +65,15 @@ vn-tooltip="Worker who made the last observation"> Author - + Last observation + + Last observation D. + @@ -111,12 +117,17 @@ {{::defaulter.workerName | dashIfEmpty}} - - + + + + + {{::defaulter.created | date: 'dd/MM/yyyy'}} + {{::defaulter.creditInsurance | currency: 'EUR': 2}} {{::defaulter.defaulterSinced | date: 'dd/MM/yyyy'}} diff --git a/modules/client/front/defaulter/locale/es.yml b/modules/client/front/defaulter/locale/es.yml index 172a3125d..3f046e8d6 100644 --- a/modules/client/front/defaulter/locale/es.yml +++ b/modules/client/front/defaulter/locale/es.yml @@ -1,7 +1,9 @@ -Last observation: Última observación Add observation: Añadir observación -Search client: Buscar clientes Add observation to all selected clients: Añadir observación a {{total}} cliente(s) seleccionado(s) -Credit I.: Crédito A. Balance D.: Saldo V. +Credit I.: Crédito A. +Last observation: Última observación +Last observation D.: Fecha última O. +Last observation date: Fecha última observación +Search client: Buscar clientes Worker who made the last observation: Trabajador que ha realizado la última observación \ No newline at end of file From 4606b0d7ead878f592edfc68f1a08825acec5d67 Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 22 Feb 2022 15:23:23 +0100 Subject: [PATCH 18/54] change name for code --- back/methods/docuware/checkFile.js | 2 +- back/methods/docuware/download.js | 2 +- db/changes/10420-valentines/00-docuware.sql | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/back/methods/docuware/checkFile.js b/back/methods/docuware/checkFile.js index a674707fc..c1af68f15 100644 --- a/back/methods/docuware/checkFile.js +++ b/back/methods/docuware/checkFile.js @@ -43,7 +43,7 @@ module.exports = Self => { const docuwareConfig = await models.DocuwareConfig.findOne(); const docuwareInfo = await models.Docuware.findOne({ where: { - name: fileCabinet, + code: fileCabinet, dialogName: dialog } }); diff --git a/back/methods/docuware/download.js b/back/methods/docuware/download.js index 75789d187..46b03ce52 100644 --- a/back/methods/docuware/download.js +++ b/back/methods/docuware/download.js @@ -56,7 +56,7 @@ module.exports = Self => { const docuwareConfig = await models.DocuwareConfig.findOne(); const docuwareInfo = await models.Docuware.findOne({ where: { - name: fileCabinet, + code: fileCabinet, dialogName: dialog } }); diff --git a/db/changes/10420-valentines/00-docuware.sql b/db/changes/10420-valentines/00-docuware.sql index e5311252d..03b386977 100644 --- a/db/changes/10420-valentines/00-docuware.sql +++ b/db/changes/10420-valentines/00-docuware.sql @@ -6,6 +6,6 @@ CREATE TABLE `vn`.`docuware` ( `find` varchar(50) DEFAULT NULL ); -INSERT INTO `vn`.`docuware` (`name`, `fileCabinetName`, `dialogName` , `find`) +INSERT INTO `vn`.`docuware` (`code`, `fileCabinetName`, `dialogName` , `find`) VALUES ('deliveryClient', 'Albaranes cliente', 'findTicket', 'N__ALBAR_N'); \ No newline at end of file From f3ff64c44df2a5b99d86a80c5a8c8e7b55ebaab1 Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 23 Feb 2022 08:11:54 +0100 Subject: [PATCH 19/54] refactor(docuware): name for code --- back/models/docuware.json | 2 +- db/changes/10420-valentines/00-docuware.sql | 2 +- db/dump/fixtures.sql | 8 ++++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/back/models/docuware.json b/back/models/docuware.json index f85397072..fb2ed919e 100644 --- a/back/models/docuware.json +++ b/back/models/docuware.json @@ -13,7 +13,7 @@ "id": true, "description": "Identifier" }, - "name": { + "code": { "type": "string" }, "fileCabinetName": { diff --git a/db/changes/10420-valentines/00-docuware.sql b/db/changes/10420-valentines/00-docuware.sql index 03b386977..7cabd135f 100644 --- a/db/changes/10420-valentines/00-docuware.sql +++ b/db/changes/10420-valentines/00-docuware.sql @@ -1,6 +1,6 @@ CREATE TABLE `vn`.`docuware` ( `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, - `name` varchar(50) NULL, + `code` varchar(50) NULL, `fileCabinetName` varchar(50) NULL, `dialogName` varchar(255) DEFAULT NULL, `find` varchar(50) DEFAULT NULL diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 74568ebc7..20298677a 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -2444,6 +2444,10 @@ INSERT INTO `bs`.`defaulter` (`clientFk`, `amount`, `created`, `defaulterSinced` (1107, 500, CURDATE(), CURDATE()), (1109, 500, CURDATE(), CURDATE()); -INSERT INTO `vn`.`docuware` (`name`, `fileCabinetName`, `dialogName` , `find`) +INSERT INTO `vn`.`docuware` (`code`, `fileCabinetName`, `dialogName` , `find`) VALUES - ('deliveryClientTest', 'deliveryClientTest', 'findTest', 'word'); \ No newline at end of file + ('deliveryClientTest', 'deliveryClientTest', 'findTest', 'word'); + +INSERT INTO `vn`.`docuwareConfig` (`url`) + VALUES + ('https://verdnatura.docuware.cloud/docuware/platform'); \ No newline at end of file From 8a8951b8b0a0dcb46bd2688cf5f665c9b4e3d375 Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 23 Feb 2022 08:53:25 +0100 Subject: [PATCH 20/54] feat(client_defaulter): add columns to search --- modules/client/front/defaulter/index.js | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/modules/client/front/defaulter/index.js b/modules/client/front/defaulter/index.js index 434ae9cb6..f4071108c 100644 --- a/modules/client/front/defaulter/index.js +++ b/modules/client/front/defaulter/index.js @@ -30,10 +30,6 @@ export default class Controller extends Section { valueField: 'id', } }, - { - field: 'amount', - searchable: false - }, { field: 'workerFk', autocomplete: { @@ -52,10 +48,6 @@ export default class Controller extends Section { valueField: 'observation', } }, - { - field: 'creditInsurance', - searchable: false - }, { field: 'defaulterSinced', searchable: false @@ -122,7 +114,9 @@ export default class Controller extends Section { exprBuilder(param, value) { switch (param) { case 'observation': - return {[`observation`]: value}; + return {[`observation`]: {like: `%${value}%`}}; + case 'creditInsurance': + case 'amount': case 'clientName': case 'workerFk': case 'salesPersonFk': From a5614e5d5dbd0f363d9e7a6368a313ea687a1720 Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 23 Feb 2022 09:52:45 +0100 Subject: [PATCH 21/54] change client.name for client.socialName --- e2e/paths/02-client/21_defaulter.spec.js | 2 +- modules/client/back/methods/defaulter/filter.js | 2 +- .../client/back/methods/defaulter/specs/filter.spec.js | 4 ++-- modules/client/front/defaulter/index.js | 9 ++++++--- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/e2e/paths/02-client/21_defaulter.spec.js b/e2e/paths/02-client/21_defaulter.spec.js index 1066776d6..3630a958a 100644 --- a/e2e/paths/02-client/21_defaulter.spec.js +++ b/e2e/paths/02-client/21_defaulter.spec.js @@ -28,7 +28,7 @@ describe('Client defaulter path', () => { const salesPersonName = await page.waitToGetProperty(selectors.clientDefaulter.firstSalesPersonName, 'innerText'); - expect(clientName).toEqual('Ororo Munroe'); + expect(clientName).toEqual('Batman'); expect(salesPersonName).toEqual('salesPersonNick'); }); diff --git a/modules/client/back/methods/defaulter/filter.js b/modules/client/back/methods/defaulter/filter.js index 0a1d5093b..c65991273 100644 --- a/modules/client/back/methods/defaulter/filter.js +++ b/modules/client/back/methods/defaulter/filter.js @@ -56,7 +56,7 @@ module.exports = Self => { FROM ( SELECT DISTINCT c.id clientFk, - c.name clientName, + c.socialName clientName, c.salesPersonFk, u.nickname salesPersonName, d.amount, diff --git a/modules/client/back/methods/defaulter/specs/filter.spec.js b/modules/client/back/methods/defaulter/specs/filter.spec.js index 145bb5132..ca14d1e43 100644 --- a/modules/client/back/methods/defaulter/specs/filter.spec.js +++ b/modules/client/back/methods/defaulter/specs/filter.spec.js @@ -47,12 +47,12 @@ describe('defaulter filter()', () => { try { const options = {transaction: tx}; - const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 'bruce'}}; + const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 'spider'}}; const result = await models.Defaulter.filter(ctx, null, options); const firstRow = result[0]; - expect(firstRow.clientName).toEqual('Bruce Wayne'); + expect(firstRow.clientName).toEqual('Spider man'); await tx.rollback(); } catch (e) { diff --git a/modules/client/front/defaulter/index.js b/modules/client/front/defaulter/index.js index f4071108c..5fcc955cc 100644 --- a/modules/client/front/defaulter/index.js +++ b/modules/client/front/defaulter/index.js @@ -16,8 +16,8 @@ export default class Controller extends Section { field: 'clientName', autocomplete: { url: 'Clients', - showField: 'name', - valueField: 'name' + showField: 'socialName', + valueField: 'socialName' } }, { @@ -34,7 +34,6 @@ export default class Controller extends Section { field: 'workerFk', autocomplete: { url: 'Workers/activeWithInheritedRole', - where: `{role: 'salesPerson'}`, searchFunction: '{firstName: $search}', showField: 'nickname', valueField: 'id', @@ -48,6 +47,10 @@ export default class Controller extends Section { valueField: 'observation', } }, + { + field: 'created', + searchable: false + }, { field: 'defaulterSinced', searchable: false From 9d298c2a5eb8a7159ed51c299b1c113e57a3f3e0 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 23 Feb 2022 12:07:05 +0100 Subject: [PATCH 22/54] Updated unit tests --- back/methods/chat/send.js | 10 ++-- back/methods/chat/sendCheckingPresence.js | 16 ++++- .../chat/spec/sendCheckingPresence.spec.js | 60 ++++++++++++------- .../claim/specs/createFromSales.spec.js | 4 +- .../client/specs/updateFiscalData.spec.js | 2 +- 5 files changed, 58 insertions(+), 34 deletions(-) diff --git a/back/methods/chat/send.js b/back/methods/chat/send.js index 5f7944945..67e0dbb87 100644 --- a/back/methods/chat/send.js +++ b/back/methods/chat/send.js @@ -35,18 +35,16 @@ module.exports = Self => { }; async function sendMessage(sender, channel, message) { - /* if (process.env.NODE_ENV !== 'production') { + if (process.env.NODE_ENV !== 'production') { return new Promise(resolve => { return resolve({ - body: JSON.stringify( - {statusCode: 200, message: 'Fake notification sent'} - ) + statusCode: 200, + message: 'Fake notification sent' }); }); } - */ - const login = await Self.getServiceAuth(); + const login = await Self.getServiceAuth(); const avatar = `${login.host}/avatar/${sender.name}`; const options = { diff --git a/back/methods/chat/sendCheckingPresence.js b/back/methods/chat/sendCheckingPresence.js index 671e8f60f..10a98452f 100644 --- a/back/methods/chat/sendCheckingPresence.js +++ b/back/methods/chat/sendCheckingPresence.js @@ -44,7 +44,7 @@ module.exports = Self => { if (!recipient) throw new Error(`Could not send message "${message}" to worker id ${recipientId} from user ${userId}`); - const {data} = await getUserStatus(recipient.name); + const {data} = await Self.getUserStatus(recipient.name); if (data) { if (data.status === 'offline') { // Send message to department room @@ -69,7 +69,17 @@ module.exports = Self => { * @param {string} username - The recipient user name * @return {Promise} - The request promise */ - async function getUserStatus(username) { + Self.getUserStatus = async function getUserStatus(username) { + if (process.env.NODE_ENV !== 'production') { + return new Promise(resolve => { + return resolve({ + data: { + status: 'online' + } + }); + }); + } + const login = await Self.getServiceAuth(); const options = { @@ -81,5 +91,5 @@ module.exports = Self => { }; return axios.get(`${login.api}/users.getStatus`, options); - } + }; }; diff --git a/back/methods/chat/spec/sendCheckingPresence.spec.js b/back/methods/chat/spec/sendCheckingPresence.spec.js index e9c61fd21..2c48ef02c 100644 --- a/back/methods/chat/spec/sendCheckingPresence.spec.js +++ b/back/methods/chat/spec/sendCheckingPresence.spec.js @@ -1,46 +1,62 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('Chat sendCheckingPresence()', () => { const today = new Date(); today.setHours(6, 0); const ctx = {req: {accessToken: {userId: 1}}}; - const chatModel = app.models.Chat; + const chatModel = models.Chat; const departmentId = 23; const workerId = 1107; - it(`should call send() method with the worker name if he's currently working then return a response`, async() => { + it(`should call to send() method with "@HankPym" as recipient argument`, async() => { spyOn(chatModel, 'send').and.callThrough(); - - const timeEntry = await app.models.WorkerTimeControl.create({ - userFk: workerId, - timed: today, - manual: false, - direction: 'in' - }); + spyOn(chatModel, 'getUserStatus').and.returnValue( + new Promise(resolve => { + return resolve({ + data: { + status: 'online' + } + }); + }) + ); const response = await chatModel.sendCheckingPresence(ctx, workerId, 'I changed something'); expect(response.statusCode).toEqual(200); expect(response.message).toEqual('Fake notification sent'); expect(chatModel.send).toHaveBeenCalledWith(ctx, '@HankPym', 'I changed something'); - - // restores - await app.models.WorkerTimeControl.destroyById(timeEntry.id); }); - it(`should call to send() method with the worker department channel if he's not currently working then return a response`, async() => { + it(`should call to send() method with "#cooler" as recipient argument`, async() => { spyOn(chatModel, 'send').and.callThrough(); + spyOn(chatModel, 'getUserStatus').and.returnValue( + new Promise(resolve => { + return resolve({ + data: { + status: 'offline' + } + }); + }) + ); - const department = await app.models.Department.findById(departmentId); - await department.updateAttribute('chatName', 'cooler'); + const tx = await models.Claim.beginTransaction({}); - const response = await chatModel.sendCheckingPresence(ctx, workerId, 'I changed something'); + try { + const options = {transaction: tx}; - expect(response.statusCode).toEqual(200); - expect(response.message).toEqual('Fake notification sent'); - expect(chatModel.send).toHaveBeenCalledWith(ctx, '#cooler', '@HankPym ➔ I changed something'); + const department = await models.Department.findById(departmentId, null, options); + await department.updateAttribute('chatName', 'cooler'); - // restores - await department.updateAttribute('chatName', null); + const response = await chatModel.sendCheckingPresence(ctx, workerId, 'I changed something'); + + expect(response.statusCode).toEqual(200); + expect(response.message).toEqual('Fake notification sent'); + expect(chatModel.send).toHaveBeenCalledWith(ctx, '#cooler', '@HankPym ➔ I changed something'); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } }); }); diff --git a/modules/claim/back/methods/claim/specs/createFromSales.spec.js b/modules/claim/back/methods/claim/specs/createFromSales.spec.js index 097dcc0d9..9151c361e 100644 --- a/modules/claim/back/methods/claim/specs/createFromSales.spec.js +++ b/modules/claim/back/methods/claim/specs/createFromSales.spec.js @@ -57,7 +57,7 @@ describe('Claim createFromSales()', () => { const todayMinusEightDays = new Date(); todayMinusEightDays.setDate(todayMinusEightDays.getDate() - 8); - const ticket = await models.Ticket.findById(ticketId, options); + const ticket = await models.Ticket.findById(ticketId, null, options); await ticket.updateAttribute('landed', todayMinusEightDays, options); const claim = await models.Claim.createFromSales(ctx, ticketId, newSale, options); @@ -88,7 +88,7 @@ describe('Claim createFromSales()', () => { const todayMinusEightDays = new Date(); todayMinusEightDays.setDate(todayMinusEightDays.getDate() - 8); - const ticket = await models.Ticket.findById(ticketId, options); + const ticket = await models.Ticket.findById(ticketId, null, options); await ticket.updateAttribute('landed', todayMinusEightDays, options); await models.Claim.createFromSales(ctx, ticketId, newSale, options); diff --git a/modules/client/back/methods/client/specs/updateFiscalData.spec.js b/modules/client/back/methods/client/specs/updateFiscalData.spec.js index 75273a39f..7c0bc0599 100644 --- a/modules/client/back/methods/client/specs/updateFiscalData.spec.js +++ b/modules/client/back/methods/client/specs/updateFiscalData.spec.js @@ -35,7 +35,7 @@ describe('Client updateFiscalData', () => { try { const options = {transaction: tx}; - const client = await models.Client.findById(clientId, options); + const client = await models.Client.findById(clientId, null, options); await client.updateAttribute('isTaxDataChecked', false, options); const ctx = {req: {accessToken: {userId: salesAssistantId}}}; From 52cf79516a16263e5d343fa451cefbd37361cffc Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 23 Feb 2022 12:23:47 +0100 Subject: [PATCH 23/54] refactor(claim_summary): move responsability and improve fixtures --- db/dump/fixtures.sql | 8 +++--- modules/claim/front/summary/index.html | 36 ++++++++++++++------------ modules/claim/front/summary/style.scss | 3 +++ 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 07eaf23fd..172aad8ec 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -1703,10 +1703,10 @@ INSERT INTO `vn`.`claimState`(`id`, `code`, `description`, `roleFk`, `priority`) INSERT INTO `vn`.`claim`(`id`, `ticketCreated`, `claimStateFk`, `observation`, `clientFk`, `workerFk`, `responsibility`, `isChargedToMana`, `created` ) VALUES - (1, CURDATE(), 1, 'observation one', 1101, 18, 3, 0, CURDATE()), - (2, CURDATE(), 2, 'observation two', 1101, 18, 3, 0, CURDATE()), - (3, CURDATE(), 3, 'observation three', 1101, 18, 1, 1, CURDATE()), - (4, CURDATE(), 3, 'observation four', 1104, 18, 5, 0, CURDATE()); + (1, CURDATE(), 1, 'Cu nam labores lobortis definiebas, ei aliquyam salutatus persequeris quo, cum eu nemore fierent dissentiunt. Per vero dolor id, vide democritum scribentur eu vim, pri erroribus temporibus ex.', 1101, 18, 3, 0, CURDATE()), + (2, CURDATE(), 2, 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.', 1101, 18, 3, 0, CURDATE()), + (3, CURDATE(), 3, 'An vim commodo dolorem volutpat, cu expetendis voluptatum usu, et mutat consul adversarium his. His natum numquam legimus an, diam fabulas mei ut. Melius fabellas sadipscing vel id. Partem diceret mandamus mea ne, has te tempor nostrud. Aeque nostro eum no.', 1101, 18, 1, 1, CURDATE()), + (4, CURDATE(), 3, 'Wisi forensibus mnesarchum in cum. Per id impetus abhorreant, his no magna definiebas, inani rationibus in quo. Ut vidisse dolores est, ut quis nominavi mel. Ad pri quod apeirian concludaturque,', 1104, 18, 5, 0, CURDATE()); INSERT INTO `vn`.`claimBeginning`(`id`, `claimFk`, `saleFk`, `quantity`) VALUES diff --git a/modules/claim/front/summary/index.html b/modules/claim/front/summary/index.html index 8eea89a2b..723d2a5e7 100644 --- a/modules/claim/front/summary/index.html +++ b/modules/claim/front/summary/index.html @@ -32,28 +32,14 @@ value="{{$ctrl.summary.claim.worker.user.nickname}}"> - + - - - - - +

Action

+ + + + + + diff --git a/modules/claim/front/summary/style.scss b/modules/claim/front/summary/style.scss index e0542dea0..e81213658 100644 --- a/modules/claim/front/summary/style.scss +++ b/modules/claim/front/summary/style.scss @@ -7,4 +7,7 @@ vn-claim-summary { .photo .image { border-radius: 3px; } + vn-textarea *{ + height: 80px; + } } \ No newline at end of file From c33b8fbb83804aedd7789d69f35ccaf95631cf86 Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 23 Feb 2022 14:50:59 +0100 Subject: [PATCH 24/54] refactor(worker): absences return one or all abscences --- modules/worker/back/methods/calendar/absences.js | 15 +++++++++++++-- modules/worker/front/time-control/index.js | 3 ++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/modules/worker/back/methods/calendar/absences.js b/modules/worker/back/methods/calendar/absences.js index 32d311cdb..5861890ed 100644 --- a/modules/worker/back/methods/calendar/absences.js +++ b/modules/worker/back/methods/calendar/absences.js @@ -12,6 +12,11 @@ module.exports = Self => { arg: 'year', type: 'date', required: true, + }, + { + arg: 'all', + type: 'boolean', + required: false, }], returns: [{ arg: 'absences', @@ -27,7 +32,7 @@ module.exports = Self => { } }); - Self.absences = async(ctx, businessFk, year, options) => { + Self.absences = async(ctx, businessFk, year, all, options) => { const models = Self.app.models; const started = new Date(); @@ -45,6 +50,12 @@ module.exports = Self => { if (typeof options == 'object') Object.assign(myOptions, options); + let where = {businessFk}; + if (all) { + let worker = await models.WorkerLabour.findOne({where: where}); + where = {workerFk: worker.workerFk}; + } + const contract = await models.WorkerLabour.findOne({ include: [{ relation: 'holidays', @@ -82,7 +93,7 @@ module.exports = Self => { } } }], - where: {businessFk} + where: where }, myOptions); if (!contract) return; diff --git a/modules/worker/front/time-control/index.js b/modules/worker/front/time-control/index.js index 1f6251391..6af977506 100644 --- a/modules/worker/front/time-control/index.js +++ b/modules/worker/front/time-control/index.js @@ -128,7 +128,8 @@ class Controller extends Section { const fullYear = this.started.getFullYear(); let params = { businessFk: this.businessId, - year: fullYear + year: fullYear, + all: true }; return this.$http.get(`Calendars/absences`, {params}) From 9ba13f90d35d541eda7ba1fb22ca718b64827ee0 Mon Sep 17 00:00:00 2001 From: carlosjr Date: Wed, 23 Feb 2022 16:12:29 +0100 Subject: [PATCH 25/54] #3015 feat(unlink): tickets link to route can now be removed from the suggested tickets to route --- .../back/methods/route/getSuggestedTickets.js | 7 ++++ .../back/methods/route/specs/unlink.spec.js | 33 +++++++++++++++ modules/route/back/methods/route/unlink.js | 42 +++++++++++++++++++ modules/route/back/models/route.js | 1 + modules/route/front/tickets/index.html | 20 ++++++++- modules/route/front/tickets/index.js | 13 ++++++ modules/route/front/tickets/index.spec.js | 27 ++++++++++++ modules/route/front/tickets/locale/es.yml | 3 +- modules/zone/back/models/agency.json | 4 +- modules/zone/back/models/zone.json | 16 +++---- 10 files changed, 153 insertions(+), 13 deletions(-) create mode 100644 modules/route/back/methods/route/specs/unlink.spec.js create mode 100644 modules/route/back/methods/route/unlink.js diff --git a/modules/route/back/methods/route/getSuggestedTickets.js b/modules/route/back/methods/route/getSuggestedTickets.js index c1d6b67fe..f0333e66b 100644 --- a/modules/route/back/methods/route/getSuggestedTickets.js +++ b/modules/route/back/methods/route/getSuggestedTickets.js @@ -25,6 +25,7 @@ module.exports = Self => { Object.assign(myOptions, options); const route = await Self.app.models.Route.findById(id, null, myOptions); + const zoneAgencyModes = await Self.app.models.ZoneAgencyMode.find({ where: { agencyModeFk: route.agencyModeFk @@ -52,6 +53,12 @@ module.exports = Self => { fields: ['id', 'name'] } }, + { + relation: 'zone', + scope: { + fields: ['id', 'name'] + } + }, { relation: 'address', scope: { diff --git a/modules/route/back/methods/route/specs/unlink.spec.js b/modules/route/back/methods/route/specs/unlink.spec.js new file mode 100644 index 000000000..808cedccc --- /dev/null +++ b/modules/route/back/methods/route/specs/unlink.spec.js @@ -0,0 +1,33 @@ +const models = require('vn-loopback/server/server').models; + +describe('route unlink()', () => { + it('should show no tickets since the link between zone and route for the give agencymode was removed', async() => { + const tx = await models.ZoneAgencyMode.beginTransaction({}); + const agencyModeId = 1; + const zoneId = 1; + routeId = 1; + + try { + const options = {transaction: tx}; + + let zoneAgencyModes = await models.ZoneAgencyMode.find(null, options); + let tickets = await models.Route.getSuggestedTickets(routeId, options); + + expect(zoneAgencyModes.length).toEqual(4); + expect(tickets.length).toEqual(3); + + await models.Route.unlink(agencyModeId, zoneId, options); + + zoneAgencyModes = await models.ZoneAgencyMode.find(null, options); + tickets = await models.Route.getSuggestedTickets(routeId, options); + + expect(zoneAgencyModes.length).toEqual(3); + expect(tickets.length).toEqual(0); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); +}); diff --git a/modules/route/back/methods/route/unlink.js b/modules/route/back/methods/route/unlink.js new file mode 100644 index 000000000..5a847e337 --- /dev/null +++ b/modules/route/back/methods/route/unlink.js @@ -0,0 +1,42 @@ +module.exports = Self => { + Self.remoteMethod('unlink', { + description: 'Removes the matching entries from zoneAgencyMode', + accessType: 'WRITE', + accepts: [ + { + arg: 'agencyModeId', + type: 'number', + required: true, + description: 'The agencyMode id', + }, + { + arg: 'zoneId', + type: 'number', + required: true, + description: 'The zone id', + }, + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: `/unlink`, + verb: 'POST' + } + }); + + Self.unlink = async(agencyModeId, zoneId, options) => { + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + const where = { + agencyModeFk: agencyModeId, + zoneFk: zoneId + }; + + await Self.app.models.ZoneAgencyMode.destroyAll(where, myOptions); + }; +}; diff --git a/modules/route/back/models/route.js b/modules/route/back/models/route.js index 1cfe0927e..c82d1722e 100644 --- a/modules/route/back/models/route.js +++ b/modules/route/back/models/route.js @@ -8,6 +8,7 @@ module.exports = Self => { require('../methods/route/insertTicket')(Self); require('../methods/route/clone')(Self); require('../methods/route/getSuggestedTickets')(Self); + require('../methods/route/unlink')(Self); Self.validate('kmStart', validateDistance, { message: 'Distance must be lesser than 1000' diff --git a/modules/route/front/tickets/index.html b/modules/route/front/tickets/index.html index 7d515b67c..970c7574b 100644 --- a/modules/route/front/tickets/index.html +++ b/modules/route/front/tickets/index.html @@ -150,7 +150,7 @@ PC Address - Warehouse + Zone
@@ -174,7 +174,15 @@ {{::ticket.address.city}} {{::ticket.address.postalCode}} {{::ticket.address.street}} - {{::ticket.warehouse.name}} + + {{::ticket.zone.name}} + + + @@ -196,3 +204,11 @@ + + + + \ No newline at end of file diff --git a/modules/route/front/tickets/index.js b/modules/route/front/tickets/index.js index fd763e32f..e74cbcd40 100644 --- a/modules/route/front/tickets/index.js +++ b/modules/route/front/tickets/index.js @@ -37,6 +37,19 @@ 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 = []; diff --git a/modules/route/front/tickets/index.spec.js b/modules/route/front/tickets/index.spec.js index fbbe94360..092445e6f 100644 --- a/modules/route/front/tickets/index.spec.js +++ b/modules/route/front/tickets/index.spec.js @@ -1,3 +1,4 @@ +/* eslint max-len: ["error", { "code": 150 }]*/ import './index'; describe('Route', () => { @@ -73,6 +74,32 @@ 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 = [ diff --git a/modules/route/front/tickets/locale/es.yml b/modules/route/front/tickets/locale/es.yml index c38d4115c..6d63b4b6e 100644 --- a/modules/route/front/tickets/locale/es.yml +++ b/modules/route/front/tickets/locale/es.yml @@ -11,4 +11,5 @@ The selected ticket is not suitable for this route: El ticket seleccionado no es PC: CP The route's vehicle doesn't have a delivery point: El vehículo de la ruta no tiene un punto de entrega The route doesn't have a vehicle: La ruta no tiene un vehículo -Population: Población \ No newline at end of file +Population: Población +Unlink selected zone?: Desvincular zona seleccionada? diff --git a/modules/zone/back/models/agency.json b/modules/zone/back/models/agency.json index 9269b3db6..edec36f87 100644 --- a/modules/zone/back/models/agency.json +++ b/modules/zone/back/models/agency.json @@ -9,11 +9,11 @@ "properties": { "id": { "id": true, - "type": "Number", + "type": "number", "forceId": false }, "name": { - "type": "String", + "type": "string", "required": false } } diff --git a/modules/zone/back/models/zone.json b/modules/zone/back/models/zone.json index ad43bd6f6..5d5970173 100644 --- a/modules/zone/back/models/zone.json +++ b/modules/zone/back/models/zone.json @@ -13,10 +13,10 @@ "properties": { "id": { "id": true, - "type": "Number" + "type": "number" }, "name": { - "type": "String", + "type": "string", "required": true }, "hour": { @@ -24,22 +24,22 @@ "required": true }, "travelingDays": { - "type": "Number" + "type": "number" }, "price": { - "type": "Number" + "type": "number" }, "bonus": { - "type": "Number" + "type": "number" }, "isVolumetric": { - "type": "Boolean" + "type": "boolean" }, "inflation": { - "type": "Number" + "type": "number" }, "itemMaxSize": { - "type": "Number" + "type": "number" } }, "relations": { From fc3a46eb2646261bba6c4b98c3492b6a20fb7d87 Mon Sep 17 00:00:00 2001 From: alexm Date: Thu, 24 Feb 2022 13:52:26 +0100 Subject: [PATCH 26/54] refactor(claim): removed importTicketSales and fix tests --- .../10420-valentines/00-ImportTicketAcl.sql | 2 + db/dump/fixtures.sql | 2 +- e2e/helpers/selectors.js | 11 ++-- e2e/paths/06-claim/04_claim_action.spec.js | 29 +-------- e2e/paths/06-claim/05_summary.spec.js | 3 +- .../methods/claim-end/importTicketSales.js | 61 ------------------- .../claim-end/specs/importTicketSales.spec.js | 26 -------- .../back/methods/claim/regularizeClaim.js | 3 +- .../claim/specs/regularizeClaim.spec.js | 59 ++++++++++-------- modules/claim/back/models/claim-end.js | 3 - modules/claim/front/action/index.html | 40 +----------- modules/claim/front/action/index.js | 30 --------- modules/claim/front/action/index.spec.js | 29 --------- modules/claim/front/action/locale/es.yml | 2 - 14 files changed, 49 insertions(+), 251 deletions(-) create mode 100644 db/changes/10420-valentines/00-ImportTicketAcl.sql delete mode 100644 modules/claim/back/methods/claim-end/importTicketSales.js delete mode 100644 modules/claim/back/methods/claim-end/specs/importTicketSales.spec.js delete mode 100644 modules/claim/back/models/claim-end.js diff --git a/db/changes/10420-valentines/00-ImportTicketAcl.sql b/db/changes/10420-valentines/00-ImportTicketAcl.sql new file mode 100644 index 000000000..98192a39c --- /dev/null +++ b/db/changes/10420-valentines/00-ImportTicketAcl.sql @@ -0,0 +1,2 @@ +DELETE FROM salix.ACL +WHERE model = 'ClaimEnd' AND property = 'importTicketSales'; diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 172aad8ec..39377fad8 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -1706,7 +1706,7 @@ INSERT INTO `vn`.`claim`(`id`, `ticketCreated`, `claimStateFk`, `observation`, ` (1, CURDATE(), 1, 'Cu nam labores lobortis definiebas, ei aliquyam salutatus persequeris quo, cum eu nemore fierent dissentiunt. Per vero dolor id, vide democritum scribentur eu vim, pri erroribus temporibus ex.', 1101, 18, 3, 0, CURDATE()), (2, CURDATE(), 2, 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.', 1101, 18, 3, 0, CURDATE()), (3, CURDATE(), 3, 'An vim commodo dolorem volutpat, cu expetendis voluptatum usu, et mutat consul adversarium his. His natum numquam legimus an, diam fabulas mei ut. Melius fabellas sadipscing vel id. Partem diceret mandamus mea ne, has te tempor nostrud. Aeque nostro eum no.', 1101, 18, 1, 1, CURDATE()), - (4, CURDATE(), 3, 'Wisi forensibus mnesarchum in cum. Per id impetus abhorreant, his no magna definiebas, inani rationibus in quo. Ut vidisse dolores est, ut quis nominavi mel. Ad pri quod apeirian concludaturque,', 1104, 18, 5, 0, CURDATE()); + (4, CURDATE(), 3, 'Wisi forensibus mnesarchum in cum. Per id impetus abhorreant, his no magna definiebas, inani rationibus in quo. Ut vidisse dolores est, ut quis nominavi mel. Ad pri quod apeirian concludaturque.', 1104, 18, 5, 0, CURDATE()); INSERT INTO `vn`.`claimBeginning`(`id`, `claimFk`, `saleFk`, `quantity`) VALUES diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index f0a5c37b5..0ca23f49a 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -680,13 +680,13 @@ export default { header: 'vn-claim-summary > vn-card > h5', state: 'vn-claim-summary vn-label-value[label="State"] > section > span', observation: 'vn-claim-summary vn-textarea[ng-model="$ctrl.summary.claim.observation"]', - firstSaleItemId: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(4) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(1) > span', + firstSaleItemId: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(5) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(1) > span', firstSaleDescriptorImage: '.vn-popover.shown vn-item-descriptor img', itemDescriptorPopover: '.vn-popover.shown vn-item-descriptor', itemDescriptorPopoverItemDiaryButton: '.vn-popover vn-item-descriptor vn-quick-link[icon="icon-transaction"] > a', - firstDevelopmentWorker: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(5) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > span', + firstDevelopmentWorker: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(4) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > span', firstDevelopmentWorkerGoToClientButton: '.vn-popover vn-worker-descriptor vn-quick-link[icon="person"] > a', - firstActionTicketId: 'vn-claim-summary > vn-card > vn-horizontal > vn-auto:nth-child(6) vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > span', + firstActionTicketId: 'vn-claim-summary > vn-card > vn-horizontal > vn-auto:nth-child(5) vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > span', firstActionTicketDescriptor: '.vn-popover.shown vn-ticket-descriptor' }, claimBasicData: { @@ -722,10 +722,7 @@ export default { }, claimAction: { importClaimButton: 'vn-claim-action vn-button[label="Import claim"]', - importTicketButton: 'vn-claim-action vn-button[label="Import ticket"]', - secondImportableTicket: '.vn-popover.shown .content > div > vn-table > div > vn-tbody > vn-tr:nth-child(2)', - firstLineDestination: 'vn-claim-action vn-tr:nth-child(1) vn-autocomplete[ng-model="saleClaimed.claimDestinationFk"]', - secondLineDestination: 'vn-claim-action vn-tr:nth-child(2) vn-autocomplete[ng-model="saleClaimed.claimDestinationFk"]', + anyLine: 'vn-claim-action vn-tbody > vn-tr', firstDeleteLine: 'vn-claim-action vn-tr:nth-child(1) vn-icon-button[icon="delete"]', isPaidWithManaCheckbox: 'vn-claim-action vn-check[ng-model="$ctrl.claim.isChargedToMana"]' }, diff --git a/e2e/paths/06-claim/04_claim_action.spec.js b/e2e/paths/06-claim/04_claim_action.spec.js index 1170e0c9c..62a0ac232 100644 --- a/e2e/paths/06-claim/04_claim_action.spec.js +++ b/e2e/paths/06-claim/04_claim_action.spec.js @@ -24,22 +24,6 @@ describe('Claim action path', () => { expect(message.text).toContain('Data saved!'); }); - it('should import the second importable ticket', async() => { - await page.waitToClick(selectors.claimAction.importTicketButton); - await page.waitToClick(selectors.claimAction.secondImportableTicket); - const message = await page.waitForSnackbar(); - - expect(message.text).toContain('Data saved!'); - }); - - it('should edit the second line destination field', async() => { - await page.waitForContentLoaded(); - await page.autocompleteSearch(selectors.claimAction.secondLineDestination, 'Bueno'); - const message = await page.waitForSnackbar(); - - expect(message.text).toContain('Data saved!'); - }); - it('should delete the first line', async() => { await page.waitToClick(selectors.claimAction.firstDeleteLine); const message = await page.waitForSnackbar(); @@ -47,18 +31,11 @@ describe('Claim action path', () => { expect(message.text).toContain('Data saved!'); }); - it('should refresh the view to check the remaining line is the expected one', async() => { + it('should refresh the view to check not have lines', async() => { await page.reloadSection('claim.card.action'); - const result = await page.waitToGetProperty(selectors.claimAction.firstLineDestination, 'value'); + const result = await page.countElement(selectors.claimAction.anyLine); - expect(result).toEqual('Bueno'); - }); - - it('should delete the current first line', async() => { - await page.waitToClick(selectors.claimAction.firstDeleteLine); - const message = await page.waitForSnackbar(); - - expect(message.text).toContain('Data saved!'); + expect(result).toEqual(0); }); it('should check the "is paid with mana" checkbox', async() => { diff --git a/e2e/paths/06-claim/05_summary.spec.js b/e2e/paths/06-claim/05_summary.spec.js index cea5edb55..589b3b6cb 100644 --- a/e2e/paths/06-claim/05_summary.spec.js +++ b/e2e/paths/06-claim/05_summary.spec.js @@ -1,3 +1,4 @@ + import selectors from '../../helpers/selectors.js'; import getBrowser from '../../helpers/puppeteer'; @@ -38,7 +39,7 @@ describe('Claim summary path', () => { it('should display the observation', async() => { const result = await page.waitToGetProperty(selectors.claimSummary.observation, 'value'); - expect(result).toContain('observation four'); + expect(result).toContain('Wisi forensibus mnesarchum in cum. Per id impetus abhorreant'); }); it('should display the claimed line(s)', async() => { diff --git a/modules/claim/back/methods/claim-end/importTicketSales.js b/modules/claim/back/methods/claim-end/importTicketSales.js deleted file mode 100644 index 6dd64be36..000000000 --- a/modules/claim/back/methods/claim-end/importTicketSales.js +++ /dev/null @@ -1,61 +0,0 @@ -module.exports = Self => { - Self.remoteMethodCtx('importTicketSales', { - 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: `/importTicketSales`, - verb: 'POST' - } - }); - - Self.importTicketSales = async(ctx, params, options) => { - let models = Self.app.models; - let userId = ctx.req.accessToken.userId; - - let tx; - const myOptions = {}; - - if (typeof options == 'object') - Object.assign(myOptions, options); - - if (!myOptions.transaction) { - tx = await Self.beginTransaction({}); - myOptions.transaction = tx; - } - - try { - const worker = await models.Worker.findOne({where: {userFk: userId}}, myOptions); - - let ticketSales = await models.Sale.find({ - where: {ticketFk: params.ticketFk} - }, myOptions); - - let claimEnds = []; - ticketSales.forEach(sale => { - claimEnds.push({ - saleFk: sale.id, - claimFk: params.claimFk, - workerFk: worker.id - }); - }); - - const createdClaimEnds = await Self.create(claimEnds, myOptions); - - if (tx) await tx.commit(); - - return createdClaimEnds; - } catch (e) { - if (tx) await tx.rollback(); - throw e; - } - }; -}; diff --git a/modules/claim/back/methods/claim-end/specs/importTicketSales.spec.js b/modules/claim/back/methods/claim-end/specs/importTicketSales.spec.js deleted file mode 100644 index 93f11e21f..000000000 --- a/modules/claim/back/methods/claim-end/specs/importTicketSales.spec.js +++ /dev/null @@ -1,26 +0,0 @@ -const app = require('vn-loopback/server/server'); - -describe('Claim importTicketSales()', () => { - it('should import sales to a claim actions from an specific ticket', async() => { - const ctx = {req: {accessToken: {userId: 5}}}; - - const tx = await app.models.Entry.beginTransaction({}); - try { - const options = {transaction: tx}; - - const claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, { - claimFk: 1, - ticketFk: 1 - }, options); - - expect(claimEnds.length).toEqual(4); - expect(claimEnds[0].saleFk).toEqual(1); - expect(claimEnds[2].saleFk).toEqual(3); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); -}); diff --git a/modules/claim/back/methods/claim/regularizeClaim.js b/modules/claim/back/methods/claim/regularizeClaim.js index d1fe7c13e..29c7320f5 100644 --- a/modules/claim/back/methods/claim/regularizeClaim.js +++ b/modules/claim/back/methods/claim/regularizeClaim.js @@ -1,6 +1,7 @@ module.exports = Self => { Self.remoteMethodCtx('regularizeClaim', { - description: 'Imports lines from claimBeginning to a new ticket with specific shipped, landed dates, agency and company', + description: `Imports lines from claimBeginning to a new ticket + with specific shipped, landed dates, agency and company`, accessType: 'WRITE', accepts: [{ arg: 'id', diff --git a/modules/claim/back/methods/claim/specs/regularizeClaim.spec.js b/modules/claim/back/methods/claim/specs/regularizeClaim.spec.js index 8ea310772..bf26d2255 100644 --- a/modules/claim/back/methods/claim/specs/regularizeClaim.spec.js +++ b/modules/claim/back/methods/claim/specs/regularizeClaim.spec.js @@ -1,9 +1,10 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; describe('claim regularizeClaim()', () => { + const userId = 18; const ctx = { req: { - accessToken: {userId: 18}, + accessToken: {userId: userId}, headers: {origin: 'http://localhost'} } }; @@ -11,8 +12,9 @@ describe('claim regularizeClaim()', () => { return params.nickname; }; - const chatModel = app.models.Chat; - const claimFk = 1; + const chatModel = models.Chat; + const claimId = 1; + const ticketId = 1; const pendentState = 1; const resolvedState = 3; const trashDestination = 2; @@ -21,27 +23,40 @@ describe('claim regularizeClaim()', () => { let claimEnds = []; let trashTicket; + async function importTicket(ticketId, claimId, userId, options) { + const ticketSales = await models.Sale.find({ + where: {ticketFk: ticketId} + }, options); + const claimEnds = []; + for (let sale of ticketSales) { + claimEnds.push({ + saleFk: sale.id, + claimFk: claimId, + workerFk: userId + }); + } + + return await models.ClaimEnd.create(claimEnds, options); + } + it('should send a chat message with value "Trash" and then change claim state to resolved', async() => { - const tx = await app.models.Claim.beginTransaction({}); + const tx = await models.Claim.beginTransaction({}); try { const options = {transaction: tx}; spyOn(chatModel, 'sendCheckingPresence').and.callThrough(); - claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, { - claimFk: claimFk, - ticketFk: 1 - }, options); + claimEnds = await importTicket(ticketId, claimId, userId, options); for (claimEnd of claimEnds) await claimEnd.updateAttributes({claimDestinationFk: trashDestination}, options); - let claimBefore = await app.models.Claim.findById(claimFk, null, options); - await app.models.Claim.regularizeClaim(ctx, claimFk, options); - let claimAfter = await app.models.Claim.findById(claimFk, null, options); + let claimBefore = await models.Claim.findById(claimId, null, options); + await models.Claim.regularizeClaim(ctx, claimId, options); + let claimAfter = await models.Claim.findById(claimId, null, options); - trashTicket = await app.models.Ticket.findOne({where: {addressFk: 12}}, options); + trashTicket = await models.Ticket.findOne({where: {addressFk: 12}}, options); expect(trashTicket.addressFk).toEqual(trashAddress); expect(claimBefore.claimStateFk).toEqual(pendentState); @@ -57,22 +72,19 @@ describe('claim regularizeClaim()', () => { }); it('should send a chat message with value "Bueno" and then change claim state to resolved', async() => { - const tx = await app.models.Claim.beginTransaction({}); + const tx = await models.Claim.beginTransaction({}); try { const options = {transaction: tx}; spyOn(chatModel, 'sendCheckingPresence').and.callThrough(); - claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, { - claimFk: claimFk, - ticketFk: 1 - }, options); + claimEnds = await importTicket(ticketId, claimId, userId, options); for (claimEnd of claimEnds) await claimEnd.updateAttributes({claimDestinationFk: okDestination}, options); - await app.models.Claim.regularizeClaim(ctx, claimFk, options); + await models.Claim.regularizeClaim(ctx, claimId, options); expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Bueno'); expect(chatModel.sendCheckingPresence).toHaveBeenCalledTimes(4); @@ -85,22 +97,19 @@ describe('claim regularizeClaim()', () => { }); it('should send a chat message to the salesPerson when claim isPickUp is enabled', async() => { - const tx = await app.models.Claim.beginTransaction({}); + const tx = await models.Claim.beginTransaction({}); try { const options = {transaction: tx}; spyOn(chatModel, 'sendCheckingPresence').and.callThrough(); - claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, { - claimFk: claimFk, - ticketFk: 1 - }, options); + claimEnds = await importTicket(ticketId, claimId, userId, options); for (claimEnd of claimEnds) await claimEnd.updateAttributes({claimDestinationFk: okDestination}, options); - await app.models.Claim.regularizeClaim(ctx, claimFk, options); + await models.Claim.regularizeClaim(ctx, claimId, options); expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Bueno'); expect(chatModel.sendCheckingPresence).toHaveBeenCalledTimes(4); diff --git a/modules/claim/back/models/claim-end.js b/modules/claim/back/models/claim-end.js deleted file mode 100644 index 73531cdfc..000000000 --- a/modules/claim/back/models/claim-end.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = Self => { - require('../methods/claim-end/importTicketSales')(Self); -}; diff --git a/modules/claim/front/action/index.html b/modules/claim/front/action/index.html index eeac01d78..6c0e2402d 100644 --- a/modules/claim/front/action/index.html +++ b/modules/claim/front/action/index.html @@ -24,15 +24,9 @@ - - - - - - -
- - - - ID - F. envio - Agencia - Almacen - - - - - {{::ticket.id}} - {{::ticket.shipped | date: 'dd/MM/yyyy'}} - {{::ticket.agencyMode.name}} - {{::ticket.warehouse.name}} - - - -
-
diff --git a/modules/claim/front/action/index.js b/modules/claim/front/action/index.js index cddc6873f..4b3214211 100644 --- a/modules/claim/front/action/index.js +++ b/modules/claim/front/action/index.js @@ -60,36 +60,6 @@ export default class Controller extends Section { }); } - showLastTickets(event) { - let pastWeek = new Date(); - pastWeek.setDate(-7); - - let filter = { - include: [ - {relation: 'agencyMode', fields: ['name']}, - {relation: 'warehouse', fields: ['name']} - ], - where: { - created: {gt: pastWeek}, - clientFk: this.claim.clientFk - } - }; - this.$.lastTicketsModel.filter = filter; - this.$.lastTicketsModel.refresh(); - this.$.lastTicketsPopover.show(event); - } - - importTicketLines(ticketFk) { - let data = {claimFk: this.$params.id, ticketFk: ticketFk}; - - let query = `ClaimEnds/importTicketSales`; - this.$http.post(query, data).then(() => { - this.vnApp.showSuccess(this.$t('Data saved!')); - this.$.lastTicketsPopover.hide(); - this.$.model.refresh(); - }); - } - regularize() { const query = `Claims/${this.$params.id}/regularizeClaim`; return this.$http.post(query).then(() => { diff --git a/modules/claim/front/action/index.spec.js b/modules/claim/front/action/index.spec.js index 9fb9b75eb..f25f2eb3c 100644 --- a/modules/claim/front/action/index.spec.js +++ b/modules/claim/front/action/index.spec.js @@ -67,35 +67,6 @@ describe('claim', () => { }); }); - describe('showLastTickets()', () => { - it('should get a list of tickets and call lastTicketsPopover show() method', () => { - jest.spyOn(controller.$.lastTicketsModel, 'refresh'); - jest.spyOn(controller.$.lastTicketsPopover, 'show'); - - controller.showLastTickets({}); - - expect(controller.$.lastTicketsModel.refresh).toHaveBeenCalled(); - expect(controller.$.lastTicketsPopover.show).toHaveBeenCalled(); - }); - }); - - describe('importTicketLines()', () => { - it('should perform a post query and add lines from an existent ticket', () => { - jest.spyOn(controller.$.model, 'refresh'); - jest.spyOn(controller.vnApp, 'showSuccess'); - jest.spyOn(controller.$.lastTicketsPopover, 'hide'); - - let data = {claimFk: 1, ticketFk: 1}; - $httpBackend.expect('POST', `ClaimEnds/importTicketSales`, data).respond({}); - controller.importTicketLines(1); - $httpBackend.flush(); - - expect(controller.$.model.refresh).toHaveBeenCalledWith(); - expect(controller.vnApp.showSuccess).toHaveBeenCalled(); - expect(controller.$.lastTicketsPopover.hide).toHaveBeenCalledWith(); - }); - }); - describe('regularize()', () => { it('should perform a post query and reload the claim card', () => { jest.spyOn(controller.card, 'reload'); diff --git a/modules/claim/front/action/locale/es.yml b/modules/claim/front/action/locale/es.yml index 3ff25dca5..22b2740b3 100644 --- a/modules/claim/front/action/locale/es.yml +++ b/modules/claim/front/action/locale/es.yml @@ -3,8 +3,6 @@ Action: Actuaciones Total claimed: Total Reclamado Import claim: Importar reclamacion Imports claim details: Importa detalles de la reclamacion -Import ticket: Importar ticket -Imports ticket lines: Importa las lineas de un ticket Regularize: Regularizar Do you want to insert greuges?: Desea insertar greuges? Insert greuges on client card: Insertar greuges en la ficha del cliente From c3e480b2e7832d49aab4ed9de8acfbd823db2260 Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Thu, 24 Feb 2022 15:02:16 +0100 Subject: [PATCH 27/54] MariaDB user sync disabled in dev environment --- modules/account/back/models/role-config.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/account/back/models/role-config.js b/modules/account/back/models/role-config.js index c6b32a4c5..6051f2060 100644 --- a/modules/account/back/models/role-config.js +++ b/modules/account/back/models/role-config.js @@ -1,6 +1,10 @@ module.exports = Self => { Self.getSynchronizer = async function() { + let NODE_ENV = process.env.NODE_ENV; + if (!NODE_ENV || NODE_ENV == 'development') + return null; + return await Self.findOne({ fields: ['id', 'rolePrefix', 'userPrefix', 'userHost'] }); From bf712ba5af999de3b74f05796275e9cf73b5e052 Mon Sep 17 00:00:00 2001 From: alexm Date: Fri, 25 Feb 2022 10:33:47 +0100 Subject: [PATCH 28/54] feat(worker): absences can return all absences of worker --- db/dump/fixtures.sql | 9 ++++ .../worker/back/methods/calendar/absences.js | 54 ++++++++++++------- .../methods/calendar/specs/absences.spec.js | 9 ++-- modules/worker/front/calendar/index.js | 1 + modules/worker/front/calendar/index.spec.js | 2 +- modules/worker/front/time-control/index.js | 18 +------ 6 files changed, 54 insertions(+), 39 deletions(-) diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 07eaf23fd..7133e60cc 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -1851,6 +1851,15 @@ INSERT INTO `postgresql`.`business_labour`(`business_id`, `notes`, `department_i SELECT b.business_id, NULL, 23, 1, 0, 1, 1, 1, 1 FROM `postgresql`.`business` `b`; +INSERT INTO `postgresql`.`business` (`client_id`, `provider_id`, `date_start`, `date_end`, `workerBusiness`, `reasonEndFk`) + SELECT p.profile_id, 1000, CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL -2 YEAR)), '-12-25'), CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL -1 YEAR)), '-12-24'), CONCAT('E-46-',RPAD(CONCAT(p.profile_id,9),8,p.profile_id)), NULL + FROM `postgresql`.`profile` `p` + WHERE `p`.`profile_id` = 1109; + +INSERT INTO `postgresql`.`business_labour` (`business_id`, `notes`, `department_id`, `professional_category_id`, `incentivo`, `calendar_labour_type_id`, `porhoras`, `labour_agreement_id`, `workcenter_id`) + VALUES + (1111, NULL, 23, 1, 0.0, 1, 1, 1, 1); + UPDATE `postgresql`.`business_labour` bl JOIN `postgresql`.`business` b ON b.business_id = bl.business_id JOIN `postgresql`.`profile` pr ON pr.profile_id = b.client_id diff --git a/modules/worker/back/methods/calendar/absences.js b/modules/worker/back/methods/calendar/absences.js index 32d311cdb..ddf38a604 100644 --- a/modules/worker/back/methods/calendar/absences.js +++ b/modules/worker/back/methods/calendar/absences.js @@ -4,10 +4,15 @@ module.exports = Self => { Self.remoteMethodCtx('absences', { description: 'Returns an array of absences from an specified contract', accepts: [{ - arg: 'businessFk', + arg: 'workerFk', type: 'number', required: true, }, + { + arg: 'businessFk', + type: 'number', + required: false, + }, { arg: 'year', type: 'date', @@ -27,7 +32,7 @@ module.exports = Self => { } }); - Self.absences = async(ctx, businessFk, year, options) => { + Self.absences = async(ctx, workerFk, businessFk, year, options) => { const models = Self.app.models; const started = new Date(); @@ -45,7 +50,17 @@ module.exports = Self => { if (typeof options == 'object') Object.assign(myOptions, options); - const contract = await models.WorkerLabour.findOne({ + let condition = { + and: [ + {workerFk: workerFk}, + {businessFk: businessFk} + ] + }; + + if (businessFk) + condition.and.push({workerFk: workerFk}); + + const contracts = await models.WorkerLabour.find({ include: [{ relation: 'holidays', scope: { @@ -82,31 +97,32 @@ module.exports = Self => { } } }], - where: {businessFk} + where: condition }, myOptions); - if (!contract) return; + if (!contracts) return; - const isSubordinate = await models.Worker.isSubordinate(ctx, contract.workerFk, myOptions); + const isSubordinate = await models.Worker.isSubordinate(ctx, workerFk, myOptions); if (!isSubordinate) throw new UserError(`You don't have enough privileges`); const absences = []; - for (let absence of contract.absences()) { - absence.dated = new Date(absence.dated); - absence.dated.setHours(0, 0, 0, 0); - - absences.push(absence); - } - - // Workcenter holidays const holidays = []; - const holidayList = contract.workCenter().holidays(); - for (let day of holidayList) { - day.dated = new Date(day.dated); - day.dated.setHours(0, 0, 0, 0); - holidays.push(day); + for (let contract of contracts) { + for (let absence of contract.absences()) { + absence.dated = new Date(absence.dated); + absence.dated.setHours(0, 0, 0, 0); + + absences.push(absence); + } + + for (let day of contract.workCenter().holidays()) { + day.dated = new Date(day.dated); + day.dated.setHours(0, 0, 0, 0); + + holidays.push(day); + } } return [absences, holidays]; diff --git a/modules/worker/back/methods/calendar/specs/absences.spec.js b/modules/worker/back/methods/calendar/specs/absences.spec.js index cfe7379c3..812b9c23c 100644 --- a/modules/worker/back/methods/calendar/specs/absences.spec.js +++ b/modules/worker/back/methods/calendar/specs/absences.spec.js @@ -3,12 +3,13 @@ const app = require('vn-loopback/server/server'); describe('Worker absences()', () => { it('should get the absence calendar for a full year contract', async() => { const ctx = {req: {accessToken: {userId: 1106}}}; + const workerId = 1106; const businessId = 1106; const now = new Date(); const year = now.getFullYear(); - const [absences] = await app.models.Calendar.absences(ctx, businessId, year); + const [absences] = await app.models.Calendar.absences(ctx, workerId, businessId, year); const firstType = absences[0].absenceType().name; const sixthType = absences[5].absenceType().name; @@ -35,7 +36,7 @@ describe('Worker absences()', () => { `UPDATE postgresql.business SET date_end = ? WHERE business_id = ?`, [null, worker.businessFk], options); - const [absences] = await app.models.Calendar.absences(ctx, businessId, year, options); + const [absences] = await app.models.Calendar.absences(ctx, worker.id, businessId, year, options); let firstType = absences[0].absenceType().name; let sixthType = absences[5].absenceType().name; @@ -51,6 +52,8 @@ describe('Worker absences()', () => { it('should give the same holidays as worked days since the holidays amount matches the amount of days in a year', async() => { const businessId = 1106; + const workerId = 1106; + const userId = 1106; const today = new Date(); @@ -101,7 +104,7 @@ describe('Worker absences()', () => { const ctx = {req: {accessToken: {userId: userId}}}; - const [absences] = await app.models.Calendar.absences(ctx, businessId, currentYear); + const [absences] = await app.models.Calendar.absences(ctx, workerId, businessId, currentYear); const firstType = absences[0].absenceType().name; const sixthType = absences[5].absenceType().name; diff --git a/modules/worker/front/calendar/index.js b/modules/worker/front/calendar/index.js index 6e0cf0d9a..92bad1f0f 100644 --- a/modules/worker/front/calendar/index.js +++ b/modules/worker/front/calendar/index.js @@ -282,6 +282,7 @@ class Controller extends Section { refresh() { const params = { + workerFk: this.$params.id, businessFk: this.businessId, year: this.year }; diff --git a/modules/worker/front/calendar/index.spec.js b/modules/worker/front/calendar/index.spec.js index e8f9b3130..3d5775663 100644 --- a/modules/worker/front/calendar/index.spec.js +++ b/modules/worker/front/calendar/index.spec.js @@ -328,7 +328,7 @@ describe('Worker', () => { jest.spyOn(controller, 'onData').mockReturnThis(); const expecteResponse = [{id: 1}]; - const expectedParams = {year: year}; + const expectedParams = {workerFk: controller.worker.id, year: year}; const serializedParams = $httpParamSerializer(expectedParams); $httpBackend.expect('GET', `Calendars/absences?${serializedParams}`).respond(200, expecteResponse); controller.refresh(); diff --git a/modules/worker/front/time-control/index.js b/modules/worker/front/time-control/index.js index 1f6251391..ebf70e886 100644 --- a/modules/worker/front/time-control/index.js +++ b/modules/worker/front/time-control/index.js @@ -32,11 +32,6 @@ class Controller extends Section { set worker(value) { this._worker = value; - - if (value) { - this.getActiveContract() - .then(() => this.getAbsences()); - } } /** @@ -96,14 +91,6 @@ class Controller extends Section { } } - getActiveContract() { - return this.$http.get(`Workers/${this.worker.id}/activeContract`) - .then(res => { - if (res.data) - this.businessId = res.data.businessFk; - }); - } - fetchHours() { const params = {workerFk: this.$params.id}; const filter = { @@ -123,11 +110,10 @@ class Controller extends Section { } getAbsences() { - if (!this.businessId) return; - const fullYear = this.started.getFullYear(); let params = { - businessFk: this.businessId, + workerFk: this.$params.id, + businessFk: null, year: fullYear }; From 62286c2f9a48e34caa3a3668fa02c8cd786a2df1 Mon Sep 17 00:00:00 2001 From: alexm Date: Fri, 25 Feb 2022 10:34:17 +0100 Subject: [PATCH 29/54] refactor(defaulter): simple route --- e2e/helpers/selectors.js | 12 ++++++------ e2e/paths/02-client/21_defaulter.spec.js | 4 ++-- modules/client/front/defaulter/index.js | 2 +- modules/client/front/defaulter/index.spec.js | 4 ++-- modules/client/front/routes.json | 10 ++-------- 5 files changed, 13 insertions(+), 19 deletions(-) diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index f0a5c37b5..f29e38961 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -305,12 +305,12 @@ export default { anyCreditInsuranceLine: 'vn-client-credit-insurance-insurance-index vn-tbody > vn-tr', }, clientDefaulter: { - anyClient: 'vn-client-defaulter-index vn-tbody > vn-tr', - firstClientName: 'vn-client-defaulter-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(2) > span', - firstSalesPersonName: 'vn-client-defaulter-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(3) > span', - firstObservation: 'vn-client-defaulter-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(6) > vn-textarea[ng-model="defaulter.observation"]', - allDefaulterCheckbox: 'vn-client-defaulter-index vn-thead vn-multi-check', - addObservationButton: 'vn-client-defaulter-index vn-button[icon="icon-notes"]', + anyClient: 'vn-client-defaulter vn-tbody > vn-tr', + firstClientName: 'vn-client-defaulter vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(2) > span', + firstSalesPersonName: 'vn-client-defaulter vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(3) > span', + firstObservation: 'vn-client-defaulter vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(6) > vn-textarea[ng-model="defaulter.observation"]', + allDefaulterCheckbox: 'vn-client-defaulter vn-thead vn-multi-check', + addObservationButton: 'vn-client-defaulter vn-button[icon="icon-notes"]', observation: '.vn-dialog.shown vn-textarea[ng-model="$ctrl.defaulter.observation"]', saveButton: 'button[response="accept"]' }, diff --git a/e2e/paths/02-client/21_defaulter.spec.js b/e2e/paths/02-client/21_defaulter.spec.js index 89b5c5761..eb26d375e 100644 --- a/e2e/paths/02-client/21_defaulter.spec.js +++ b/e2e/paths/02-client/21_defaulter.spec.js @@ -9,7 +9,7 @@ describe('Client defaulter path', () => { browser = await getBrowser(); page = browser.page; await page.loginAndModule('insurance', 'client'); - await page.accessToSection('client.defaulter.index'); + await page.accessToSection('client.defaulter'); }); afterAll(async() => { @@ -52,7 +52,7 @@ describe('Client defaulter path', () => { it('shoul checked all defaulters', async() => { await page.loginAndModule('insurance', 'client'); - await page.accessToSection('client.defaulter.index'); + await page.accessToSection('client.defaulter'); await page.waitToClick(selectors.clientDefaulter.allDefaulterCheckbox); }); diff --git a/modules/client/front/defaulter/index.js b/modules/client/front/defaulter/index.js index 76afeb160..9259ad917 100644 --- a/modules/client/front/defaulter/index.js +++ b/modules/client/front/defaulter/index.js @@ -59,7 +59,7 @@ export default class Controller extends Section { } } -ngModule.vnComponent('vnClientDefaulterIndex', { +ngModule.vnComponent('vnClientDefaulter', { template: require('./index.html'), controller: Controller }); diff --git a/modules/client/front/defaulter/index.spec.js b/modules/client/front/defaulter/index.spec.js index 6428952ec..0a7d7fcc6 100644 --- a/modules/client/front/defaulter/index.spec.js +++ b/modules/client/front/defaulter/index.spec.js @@ -2,7 +2,7 @@ import './index'; import crudModel from 'core/mocks/crud-model'; describe('client defaulter', () => { - describe('Component vnClientDefaulterIndex', () => { + describe('Component vnClientDefaulter', () => { let controller; let $httpBackend; @@ -11,7 +11,7 @@ describe('client defaulter', () => { beforeEach(inject(($componentController, _$httpBackend_) => { $httpBackend = _$httpBackend_; const $element = angular.element(''); - controller = $componentController('vnClientDefaulterIndex', {$element}); + controller = $componentController('vnClientDefaulter', {$element}); controller.$.model = crudModel; controller.$.model.data = [ {clientFk: 1101, amount: 125}, diff --git a/modules/client/front/routes.json b/modules/client/front/routes.json index d6f8a70bd..8398a8745 100644 --- a/modules/client/front/routes.json +++ b/modules/client/front/routes.json @@ -8,7 +8,7 @@ "main": [ {"state": "client.index", "icon": "person"}, {"state": "client.notification", "icon": "campaign"}, - {"state": "client.defaulter.index", "icon": "icon-defaulter"} + {"state": "client.defaulter", "icon": "icon-defaulter"} ], "card": [ {"state": "client.card.basicData", "icon": "settings"}, @@ -366,13 +366,7 @@ { "url": "/defaulter", "state": "client.defaulter", - "component": "ui-view", - "description": "Defaulter" - }, - { - "url": "/index?q", - "state": "client.defaulter.index", - "component": "vn-client-defaulter-index", + "component": "vn-client-defaulter", "description": "Defaulter" }, { From 5434dd3bafba686dbf1333d4deb537931b6b8d87 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 28 Feb 2022 07:57:46 +0100 Subject: [PATCH 30/54] feat(claim_index): implemented smart-table and change state in summary --- modules/claim/back/methods/claim/filter.js | 37 +++--- modules/claim/front/index/index.html | 124 ++++++++++++--------- modules/claim/front/index/index.js | 64 ++++++++++- modules/claim/front/summary/index.html | 9 ++ modules/claim/front/summary/index.js | 41 ++++++- modules/claim/front/summary/index.spec.js | 1 + 6 files changed, 204 insertions(+), 72 deletions(-) diff --git a/modules/claim/back/methods/claim/filter.js b/modules/claim/back/methods/claim/filter.js index f4b0c26a2..cf2748e4f 100644 --- a/modules/claim/back/methods/claim/filter.js +++ b/modules/claim/back/methods/claim/filter.js @@ -94,19 +94,15 @@ module.exports = Self => { ? {'cl.id': value} : { or: [ - {'c.name': {like: `%${value}%`}} + {'cl.socialName': {like: `%${value}%`}} ] }; - case 'client': - return {'c.name': {like: `%${value}%`}}; + case 'workerFk': + return {['cl.workerFk']: value}; case 'id': - return {'cl.id': value}; - case 'clientFk': - return {'c.id': value}; case 'claimStateFk': - return {'cl.claimStateFk': value}; - case 'salesPersonFk': - return {'c.salesPersonFk': value}; + case 'priority': + return {[`cl.${param}`]: value}; case 'attenderFk': return {'cl.workerFk': value}; case 'created': @@ -123,12 +119,23 @@ module.exports = Self => { const stmts = []; const stmt = new ParameterizedSQL( - `SELECT cl.id, c.name, cl.clientFk, cl.workerFk, u.name AS userName, cs.description, cl.created - FROM claim cl - LEFT JOIN client c ON c.id = cl.clientFk - LEFT JOIN worker w ON w.id = cl.workerFk - LEFT JOIN account.user u ON u.id = w.userFk - LEFT JOIN claimState cs ON cs.id = cl.claimStateFk` + `SELECT * + FROM ( + SELECT + cl.id, + cl.clientFk, + c.socialName, + cl.workerFk, + u.name AS workerName, + cs.description, + cl.created, + cs.priority, + cl.claimStateFk + FROM claim cl + LEFT JOIN client c ON c.id = cl.clientFk + LEFT JOIN worker w ON w.id = cl.workerFk + LEFT JOIN account.user u ON u.id = w.userFk + LEFT JOIN claimState cs ON cs.id = cl.claimStateFk ) cl` ); stmt.merge(conn.makeSuffix(filter)); diff --git a/modules/claim/front/index/index.html b/modules/claim/front/index/index.html index c8f7e994c..bb2e2f711 100644 --- a/modules/claim/front/index/index.html +++ b/modules/claim/front/index/index.html @@ -1,59 +1,74 @@ - - - - - - Id - Client - Created - Worker - State - - - - -
- {{::claim.id}} - - - {{::claim.name}} - - - {{::claim.created | date:'dd/MM/yyyy'}} - - - {{::claim.userName}} - - - - - {{::claim.description}} - - - - - - - -
- - - + + + + + + + + + + + + + + + + + + + + + + + + +
+ Id + + Client + + Created + + Worker + + State +
{{::claim.id}} + + {{::claim.socialName}} + + {{::claim.created | date:'dd/MM/yyyy'}} + + {{::claim.workerName}} + + + + {{::claim.description}} + + + + +
+
+
+
@@ -62,6 +77,7 @@ + claim="$ctrl.claimSelected" + parent-reload="$ctrl.reload()"> diff --git a/modules/claim/front/index/index.js b/modules/claim/front/index/index.js index fe4b6def7..a2cc8b5e1 100644 --- a/modules/claim/front/index/index.js +++ b/modules/claim/front/index/index.js @@ -1,7 +1,69 @@ import ngModule from '../module'; import Section from 'salix/components/section'; -export default class Controller extends Section { +class Controller extends Section { + constructor($element, $) { + super($element, $); + + this.smartTableOptions = { + activeButtons: { + search: true + }, + columns: [ + { + field: 'clientFk', + autocomplete: { + url: 'Clients', + showField: 'socialName', + valueField: 'socialName' + } + }, + { + field: 'workerFk', + autocomplete: { + url: 'Workers/activeWithInheritedRole', + where: `{role: 'salesPerson'}`, + searchFunction: '{firstName: $search}', + showField: 'name', + valueField: 'id', + } + }, + { + field: 'claimStateFk', + autocomplete: { + url: 'ClaimStates', + showField: 'description', + valueField: 'id', + } + }, + { + field: 'created', + searchable: false + } + ] + }; + } + + exprBuilder(param, value) { + switch (param) { + case 'clientFk': + return {['cl.socialName']: value}; + case 'id': + case 'workerFk': + case 'claimStateFk': + case 'priority': + return {[`cl.${param}`]: value}; + case 'attenderFk': + return {'cl.workerFk': value}; + case 'created': + value.setHours(0, 0, 0, 0); + to = new Date(value); + to.setHours(23, 59, 59, 999); + + return {'cl.created': {between: [value, to]}}; + } + } + stateColor(claim) { switch (claim.description) { case 'Pendiente': diff --git a/modules/claim/front/summary/index.html b/modules/claim/front/summary/index.html index 8eea89a2b..f46b3622a 100644 --- a/modules/claim/front/summary/index.html +++ b/modules/claim/front/summary/index.html @@ -12,6 +12,15 @@ {{::$ctrl.summary.claim.id}} - {{::$ctrl.summary.claim.client.name}} + + diff --git a/modules/claim/front/summary/index.js b/modules/claim/front/summary/index.js index bda830d6a..89a920962 100644 --- a/modules/claim/front/summary/index.js +++ b/modules/claim/front/summary/index.js @@ -13,6 +13,18 @@ class Controller extends Summary { this.getSummary(); } + loadData() { + this.getSummary(); + } + + reload() { + if (this.card) { + console.log('CARD'); + this.card.reload(); + } + if (this.parentReload) + this.parentReload(); + } get isSalesPerson() { return this.aclService.hasAny(['salesPerson']); } @@ -29,8 +41,10 @@ class Controller extends Summary { this._claim = value; // Get DMS on summary load - if (value) + if (value) { this.$.$applyAsync(() => this.loadDms()); + this.loadData(); + } } loadDms() { @@ -44,11 +58,29 @@ class Controller extends Summary { this.$http.get(`Claims/${this.claim.id}/getSummary`).then(response => { this.summary = response.data; }); + this.$http.get(`Claims/${this.claim.id}/isEditable`).then(response => { + this.isEditable = response.data; + }); } getImagePath(dmsId) { return this.vnFile.getPath(`/api/dms/${dmsId}/downloadFile`); } + + changeState(value) { + const params = { + id: this.claim.id, + claimStateFk: value + }; + + this.$http.patch(`Claims/updateClaim/${this.claim.id}`, params) + .then(() => { + this.reload(); + }) + .then(() => { + this.vnApp.showSuccess(this.$t('Data saved!')); + }); + } } Controller.$inject = ['$element', '$scope', 'vnFile']; @@ -57,6 +89,11 @@ ngModule.vnComponent('vnClaimSummary', { template: require('./index.html'), controller: Controller, bindings: { - claim: '<' + claim: '<', + model: ' { it('should perform a query to set summary', () => { $httpBackend.expect('GET', `Claims/1/getSummary`).respond(200, 24); controller.getSummary(); + $httpBackend.expect('GET', `Claims/1/isEditable`).respond(200, true); $httpBackend.flush(); expect(controller.summary).toEqual(24); From bf0734ca67deb114627f8c32544823ee74552f3d Mon Sep 17 00:00:00 2001 From: carlosjr Date: Mon, 28 Feb 2022 10:46:14 +0100 Subject: [PATCH 31/54] excluded 3 test suites until db export --- modules/client/back/methods/client/specs/sendSms.spec.js | 3 ++- modules/client/back/methods/sms/send.spec.js | 3 ++- modules/ticket/back/methods/ticket/specs/sendSms.spec.js | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/client/back/methods/client/specs/sendSms.spec.js b/modules/client/back/methods/client/specs/sendSms.spec.js index 121d427ce..54fe802e3 100644 --- a/modules/client/back/methods/client/specs/sendSms.spec.js +++ b/modules/client/back/methods/client/specs/sendSms.spec.js @@ -1,7 +1,8 @@ const models = require('vn-loopback/server/server').models; const soap = require('soap'); -describe('client sendSms()', () => { +// #3673 sendSms tests excluded +xdescribe('client sendSms()', () => { it('should now send a message and log it', async() => { spyOn(soap, 'createClientAsync').and.returnValue('a so fake client'); const tx = await models.Client.beginTransaction({}); diff --git a/modules/client/back/methods/sms/send.spec.js b/modules/client/back/methods/sms/send.spec.js index 7ca78b214..a81c24e96 100644 --- a/modules/client/back/methods/sms/send.spec.js +++ b/modules/client/back/methods/sms/send.spec.js @@ -1,6 +1,7 @@ const app = require('vn-loopback/server/server'); -describe('sms send()', () => { +// #3673 sendSms tests excluded +xdescribe('sms send()', () => { it('should not return status error', async() => { const ctx = {req: {accessToken: {userId: 1}}}; const result = await app.models.Sms.send(ctx, 1105, '123456789', 'My SMS Body'); diff --git a/modules/ticket/back/methods/ticket/specs/sendSms.spec.js b/modules/ticket/back/methods/ticket/specs/sendSms.spec.js index 8ec4ca487..46ae23702 100644 --- a/modules/ticket/back/methods/ticket/specs/sendSms.spec.js +++ b/modules/ticket/back/methods/ticket/specs/sendSms.spec.js @@ -1,7 +1,8 @@ const models = require('vn-loopback/server/server').models; const soap = require('soap'); -describe('ticket sendSms()', () => { +// #3673 sendSms tests excluded +xdescribe('ticket sendSms()', () => { it('should send a message and log it', async() => { const tx = await models.Ticket.beginTransaction({}); From 4b963804c61b5c420153c740c6cd2423d8d9096b Mon Sep 17 00:00:00 2001 From: carlosjr Date: Mon, 28 Feb 2022 10:54:32 +0100 Subject: [PATCH 32/54] added transalation to item waste --- modules/item/front/waste/locale/es.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/item/front/waste/locale/es.yml b/modules/item/front/waste/locale/es.yml index 9f08e3a72..b9cd33dec 100644 --- a/modules/item/front/waste/locale/es.yml +++ b/modules/item/front/waste/locale/es.yml @@ -1,3 +1,4 @@ Family: Familia Percentage: Porcentaje -Dwindle: Mermas \ No newline at end of file +Dwindle: Mermas +Minimize/Maximize: Minimizar/Maximizar \ No newline at end of file From 60e908d82ac160d63cd9d9d3975c0304eda69b31 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 28 Feb 2022 12:40:44 +0100 Subject: [PATCH 33/54] feat(claim_summary): parentReload(), and test --- modules/claim/back/methods/claim/filter.js | 3 +- .../claim/back/methods/claim/getSummary.js | 5 +-- .../back/methods/claim/specs/filter.spec.js | 2 +- .../methods/claim/specs/getSummary.spec.js | 11 +++++-- modules/claim/front/index/index.html | 2 +- modules/claim/front/index/index.js | 6 +++- modules/claim/front/main/index.js | 8 +++-- modules/claim/front/summary/index.html | 2 +- modules/claim/front/summary/index.js | 31 +++++++++---------- modules/claim/front/summary/index.spec.js | 27 +++++++++++----- 10 files changed, 61 insertions(+), 36 deletions(-) diff --git a/modules/claim/back/methods/claim/filter.js b/modules/claim/back/methods/claim/filter.js index cf2748e4f..f4eecae6d 100644 --- a/modules/claim/back/methods/claim/filter.js +++ b/modules/claim/back/methods/claim/filter.js @@ -97,12 +97,11 @@ module.exports = Self => { {'cl.socialName': {like: `%${value}%`}} ] }; - case 'workerFk': - return {['cl.workerFk']: value}; case 'id': case 'claimStateFk': case 'priority': return {[`cl.${param}`]: value}; + case 'salesPersonFk': case 'attenderFk': return {'cl.workerFk': value}; case 'created': diff --git a/modules/claim/back/methods/claim/getSummary.js b/modules/claim/back/methods/claim/getSummary.js index 512e4a77f..0accbf920 100644 --- a/modules/claim/back/methods/claim/getSummary.js +++ b/modules/claim/back/methods/claim/getSummary.js @@ -1,5 +1,5 @@ module.exports = Self => { - Self.remoteMethod('getSummary', { + Self.remoteMethodCtx('getSummary', { description: 'Return the claim summary', accessType: 'READ', accepts: [{ @@ -19,7 +19,7 @@ module.exports = Self => { } }); - Self.getSummary = async(id, options) => { + Self.getSummary = async(ctx, id, options) => { const myOptions = {}; if (typeof options == 'object') @@ -135,6 +135,7 @@ module.exports = Self => { const res = await Promise.all(promises); + summary.isEditable = await Self.isEditable(ctx, id, myOptions); [summary.claim] = res[0]; summary.salesClaimed = res[1]; summary.developments = res[2]; diff --git a/modules/claim/back/methods/claim/specs/filter.spec.js b/modules/claim/back/methods/claim/specs/filter.spec.js index b26afe8c4..c54318e45 100644 --- a/modules/claim/back/methods/claim/specs/filter.spec.js +++ b/modules/claim/back/methods/claim/specs/filter.spec.js @@ -25,7 +25,7 @@ describe('claim filter()', () => { try { const options = {transaction: tx}; - const result = await app.models.Claim.filter({args: {filter: {}, search: 'Tony Stark'}}, null, options); + const result = await app.models.Claim.filter({args: {filter: {}, search: 'Iron man'}}, null, options); expect(result.length).toEqual(1); expect(result[0].id).toEqual(4); diff --git a/modules/claim/back/methods/claim/specs/getSummary.spec.js b/modules/claim/back/methods/claim/specs/getSummary.spec.js index 541f42cfb..6eb920b29 100644 --- a/modules/claim/back/methods/claim/specs/getSummary.spec.js +++ b/modules/claim/back/methods/claim/specs/getSummary.spec.js @@ -3,17 +3,24 @@ const app = require('vn-loopback/server/server'); describe('claim getSummary()', () => { it('should return summary with claim, salesClaimed, developments and actions defined ', async() => { const tx = await app.models.Claim.beginTransaction({}); - + const ctx = { + req: { + accessToken: { + userId: 9 + } + } + }; try { const options = {transaction: tx}; - const result = await app.models.Claim.getSummary(1, options); + const result = await app.models.Claim.getSummary(ctx, 1, options); const keys = Object.keys(result); expect(keys).toContain('claim'); expect(keys).toContain('salesClaimed'); expect(keys).toContain('developments'); expect(keys).toContain('actions'); + expect(keys).toContain('isEditable'); await tx.rollback(); } catch (e) { diff --git a/modules/claim/front/index/index.html b/modules/claim/front/index/index.html index bb2e2f711..341d6eb2f 100644 --- a/modules/claim/front/index/index.html +++ b/modules/claim/front/index/index.html @@ -19,7 +19,7 @@ Created - + Worker diff --git a/modules/claim/front/index/index.js b/modules/claim/front/index/index.js index a2cc8b5e1..bf0cb25c0 100644 --- a/modules/claim/front/index/index.js +++ b/modules/claim/front/index/index.js @@ -49,10 +49,10 @@ class Controller extends Section { case 'clientFk': return {['cl.socialName']: value}; case 'id': - case 'workerFk': case 'claimStateFk': case 'priority': return {[`cl.${param}`]: value}; + case 'salesPersonFk': case 'attenderFk': return {'cl.workerFk': value}; case 'created': @@ -79,6 +79,10 @@ class Controller extends Section { this.claimSelected = claim; this.$.summary.show(); } + + reload() { + this.$.model.refresh(); + } } ngModule.vnComponent('vnClaimIndex', { diff --git a/modules/claim/front/main/index.js b/modules/claim/front/main/index.js index 77b051897..a9fad2eeb 100644 --- a/modules/claim/front/main/index.js +++ b/modules/claim/front/main/index.js @@ -1,9 +1,13 @@ import ngModule from '../module'; import ModuleMain from 'salix/components/module-main'; -export default class Claim extends ModuleMain {} +export default class Claims extends ModuleMain { + constructor($element, $) { + super($element, $); + } +} ngModule.vnComponent('vnClaim', { - controller: Claim, + controller: Claims, template: require('./index.html') }); diff --git a/modules/claim/front/summary/index.html b/modules/claim/front/summary/index.html index f46b3622a..c1d056eed 100644 --- a/modules/claim/front/summary/index.html +++ b/modules/claim/front/summary/index.html @@ -13,7 +13,7 @@ {{::$ctrl.summary.claim.id}} - {{::$ctrl.summary.claim.client.name}} { + if (res && res.data) + this.summary = res.data; + }); } reload() { - if (this.card) { - console.log('CARD'); - this.card.reload(); - } - if (this.parentReload) - this.parentReload(); + this.loadData() + .then(() => { + if (this.card) + this.card.reload(); + // Refresh index model + if (this.parentReload) + this.parentReload(); + }); } + get isSalesPerson() { return this.aclService.hasAny(['salesPerson']); } @@ -54,15 +60,6 @@ class Controller extends Summary { this.$.model.refresh(); } - getSummary() { - this.$http.get(`Claims/${this.claim.id}/getSummary`).then(response => { - this.summary = response.data; - }); - this.$http.get(`Claims/${this.claim.id}/isEditable`).then(response => { - this.isEditable = response.data; - }); - } - getImagePath(dmsId) { return this.vnFile.getPath(`/api/dms/${dmsId}/downloadFile`); } diff --git a/modules/claim/front/summary/index.spec.js b/modules/claim/front/summary/index.spec.js index 31e10eccb..02bdf21d2 100644 --- a/modules/claim/front/summary/index.spec.js +++ b/modules/claim/front/summary/index.spec.js @@ -18,24 +18,37 @@ describe('Claim', () => { controller.$.model = crudModel; })); - describe('getSummary()', () => { + describe('loadData()', () => { it('should perform a query to set summary', () => { - $httpBackend.expect('GET', `Claims/1/getSummary`).respond(200, 24); - controller.getSummary(); - $httpBackend.expect('GET', `Claims/1/isEditable`).respond(200, true); + $httpBackend.when('GET', `Claims/1/getSummary`).respond(200, 24); + controller.loadData(); $httpBackend.flush(); expect(controller.summary).toEqual(24); }); }); + describe('changeState()', () => { + it('should make an HTTP post query, then call the showSuccess(), reload() and resetChanges() methods', () => { + jest.spyOn(controller.vnApp, 'showSuccess').mockReturnThis(); + + const expectedParams = {id: 1, claimStateFk: 1}; + $httpBackend.when('GET', `Claims/1/getSummary`).respond(200, 24); + $httpBackend.expect('PATCH', `Claims/updateClaim/1`, expectedParams).respond(200); + controller.changeState(1); + $httpBackend.flush(); + + expect(controller.vnApp.showSuccess).toHaveBeenCalled(); + }); + }); + describe('$onChanges()', () => { - it('should call getSummary when item.id is defined', () => { - jest.spyOn(controller, 'getSummary'); + it('should call loadData when item.id is defined', () => { + jest.spyOn(controller, 'loadData'); controller.$onChanges(); - expect(controller.getSummary).toHaveBeenCalledWith(); + expect(controller.loadData).toHaveBeenCalledWith(); }); }); }); From cf9851c8dc380229564a548259d51b2ba45f3ac7 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 28 Feb 2022 13:27:03 +0100 Subject: [PATCH 34/54] typo --- back/methods/docuware/checkFile.js | 4 ++-- back/methods/docuware/download.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/back/methods/docuware/checkFile.js b/back/methods/docuware/checkFile.js index c1af68f15..c6712bb65 100644 --- a/back/methods/docuware/checkFile.js +++ b/back/methods/docuware/checkFile.js @@ -59,7 +59,7 @@ module.exports = Self => { 'Cookie': cookie } }; - const condtions = { + const searchFilter = { condition: [ { DBName: find, @@ -80,7 +80,7 @@ module.exports = Self => { const dialogId = dialogJson.find(dialogs => dialogs.DisplayName === 'find').Id; // get docuwareID - Object.assign(options, {'body': JSON.stringify(condtions)}); + Object.assign(options, {'body': JSON.stringify(searchFilter)}); const response = await got.post( `${docuwareUrl}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`, options); JSON.parse(response.body).Items[0].Id; diff --git a/back/methods/docuware/download.js b/back/methods/docuware/download.js index 46b03ce52..489a07e34 100644 --- a/back/methods/docuware/download.js +++ b/back/methods/docuware/download.js @@ -72,7 +72,7 @@ module.exports = Self => { 'Cookie': cookie } }; - const condtions = { + const searchFilter = { condition: [ { DBName: find, @@ -93,7 +93,7 @@ module.exports = Self => { const dialogId = dialogJson.find(dialogs => dialogs.DisplayName === 'find').Id; // get docuwareID - Object.assign(options, {'body': JSON.stringify(condtions)}); + Object.assign(options, {'body': JSON.stringify(searchFilter)}); const response = await got.post(`${docuwareUrl}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`, options); const docuwareId = JSON.parse(response.body).Items[0].Id; From 4046617eab70394d0d0d740007fad76679e07742 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 28 Feb 2022 13:37:44 +0100 Subject: [PATCH 35/54] short form --- modules/ticket/front/descriptor-menu/index.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/ticket/front/descriptor-menu/index.js b/modules/ticket/front/descriptor-menu/index.js index 4304d8523..841dfa409 100644 --- a/modules/ticket/front/descriptor-menu/index.js +++ b/modules/ticket/front/descriptor-menu/index.js @@ -129,9 +129,7 @@ class Controller extends Section { dialog: 'findTicket' }; this.$http.post(`Docuwares/${this.id}/checkFile`, params) - .then(res => { - this.hasDocuwareFile = res.data; - }); + .then(res => this.hasDocuwareFile = res.data); } showCsvDeliveryNote() { From 3f483d36f2f420db671fd7d4e39d71cedda30269 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 28 Feb 2022 14:28:16 +0100 Subject: [PATCH 36/54] refactor(order_search-panel): change orderFk to ticketFk --- modules/order/back/methods/order/filter.js | 14 +++++++------- modules/order/front/main/index.html | 2 +- modules/order/front/search-panel/index.html | 6 +++--- modules/order/front/search-panel/locale/es.yml | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/modules/order/back/methods/order/filter.js b/modules/order/back/methods/order/filter.js index 27cacdd62..a4d0c0f8e 100644 --- a/modules/order/back/methods/order/filter.js +++ b/modules/order/back/methods/order/filter.js @@ -18,7 +18,7 @@ module.exports = Self => { }, { arg: 'search', type: 'string', - description: `If it's and integer searchs by id, otherwise it searchs by nickname` + description: `If it's and integer searchs by ticket id, otherwise it searchs by nickname` }, { arg: 'from', type: 'date', @@ -36,9 +36,9 @@ module.exports = Self => { type: 'integer', description: 'The client id' }, { - arg: 'ticketFk', + arg: 'orderFk', type: 'integer', - description: 'The ticket id' + description: 'The order id' }, { arg: 'agencyModeFk', type: 'integer', @@ -103,7 +103,7 @@ module.exports = Self => { switch (param) { case 'search': return /^\d+$/.test(value) - ? {'o.id': value} + ? {'t.id': value} : {or: [ {'c.name': {like: `%${value}%`}} ]}; @@ -119,8 +119,8 @@ module.exports = Self => { return {'o.agency_id': value}; case 'sourceApp': return {'o.source_app': value}; - case 'ticketFk': - return {'ot.ticketFk': value}; + case 'orderFk': + return {'o.id': value}; case 'isConfirmed': return {'o.confirmed': value ? 1 : 0}; case 'myTeam': @@ -131,7 +131,7 @@ module.exports = Self => { case 'showEmpty': return {'o.total': {neq: value}}; case 'id': - param = `o.${param}`; + param = `t.${param}`; return {[param]: value}; } }); diff --git a/modules/order/front/main/index.html b/modules/order/front/main/index.html index f3b72adb2..1f6c7434c 100644 --- a/modules/order/front/main/index.html +++ b/modules/order/front/main/index.html @@ -9,7 +9,7 @@ diff --git a/modules/order/front/search-panel/index.html b/modules/order/front/search-panel/index.html index c622dd152..a3ed9e5a5 100644 --- a/modules/order/front/search-panel/index.html +++ b/modules/order/front/search-panel/index.html @@ -5,7 +5,7 @@ vn-one label="General search" ng-model="filter.search" - info="Search orders by id" + info="Search orders by ticket id" vn-focus> @@ -51,8 +51,8 @@ + label="Order id" + ng-model="filter.orderFk"> Date: Tue, 1 Mar 2022 10:44:04 +0100 Subject: [PATCH 37/54] feat(supplier-account): isPayMethodChecked false when change model --- .../models/specs/supplier-account.spec.js | 63 ++++++++++++++----- .../supplier/back/models/supplier-account.js | 12 ++++ 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/modules/supplier/back/models/specs/supplier-account.spec.js b/modules/supplier/back/models/specs/supplier-account.spec.js index f56e70a89..083c681ac 100644 --- a/modules/supplier/back/models/specs/supplier-account.spec.js +++ b/modules/supplier/back/models/specs/supplier-account.spec.js @@ -1,16 +1,28 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; const LoopBackContext = require('loopback-context'); describe('loopback model Supplier-account', () => { describe('create', () => { const supplierId = 1; const bankEntityId = 2100; + const activeCtx = { + accessToken: {userId: 5}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + activeCtx.http.req.__ = value => { + return value; + }; + it('should throw an error when attempting to set an invalid iban account', async() => { let error; const expectedError = 'The IBAN does not have the correct format'; const iban = 'incorrect format'; try { - await app.models.SupplierAccount.create( + await models.SupplierAccount.create( { supplierFk: supplierId, bankEntityFk: bankEntityId, @@ -26,27 +38,16 @@ describe('loopback model Supplier-account', () => { }); it('should create a valid supplier account', async() => { - const tx = await app.models.Claim.beginTransaction({}); + const tx = await models.SupplierAccount.beginTransaction({}); try { const options = {transaction: tx}; const iban = 'ES91 2100 0418 4502 0005 1332'; - const activeCtx = { - accessToken: {userId: 5}, - http: { - req: { - headers: {origin: 'http://localhost'} - } - } - }; - activeCtx.http.req.__ = value => { - return value; - }; - spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ active: activeCtx }); - const createdSupplierAccount = await app.models.SupplierAccount.create({ + + const createdSupplierAccount = await models.SupplierAccount.create({ supplierFk: supplierId, bankEntityFk: bankEntityId, iban: iban @@ -60,5 +61,35 @@ describe('loopback model Supplier-account', () => { throw e; } }); + + it('should change isPayMethodChecked to false', async() => { + const tx = await models.SupplierAccount.beginTransaction({}); + try { + const options = {transaction: tx}; + const iban = 'ES91 2100 0418 4502 0005 1332'; + + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + + const supplierBefore = await models.Supplier.findById(supplierId, null, options); + + await models.SupplierAccount.create({ + supplierFk: supplierId, + bankEntityFk: bankEntityId, + iban: iban + }, + options); + + const supplierAfter = await models.Supplier.findById(supplierId, null, options); + + expect(supplierBefore.isPayMethodChecked).toBeTruthy(); + expect(supplierAfter.isPayMethodChecked).toBeFalsy(); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); }); }); diff --git a/modules/supplier/back/models/supplier-account.js b/modules/supplier/back/models/supplier-account.js index c8b2f0595..ae93ef83b 100644 --- a/modules/supplier/back/models/supplier-account.js +++ b/modules/supplier/back/models/supplier-account.js @@ -34,4 +34,16 @@ module.exports = Self => { ctx.instance.iban + ', entidad: ' + bankEntity.name + ', bic: ' + bankEntity.bic }); }); + + Self.observe('after save', async ctx => { + const options = {}; + + // Check for transactions + if (ctx.options && ctx.options.transaction) + options.transaction = ctx.options.transaction; + const supplier = await Self.app.models.Supplier.findById(ctx.instance.supplierFk, options); + + if (supplier.isPayMethodChecked) + await supplier.updateAttribute('isPayMethodChecked', false, options); + }); }; From a27a48f251a17a6c7a9b05d08dc03f9b13305167 Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 1 Mar 2022 10:44:46 +0100 Subject: [PATCH 38/54] fix(supplier_account): fix setWireTransfer and add test --- modules/supplier/front/account/index.js | 10 +++++++ modules/supplier/front/account/index.spec.js | 28 ++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/modules/supplier/front/account/index.js b/modules/supplier/front/account/index.js index 6c6e77d2e..5629e65d3 100644 --- a/modules/supplier/front/account/index.js +++ b/modules/supplier/front/account/index.js @@ -45,6 +45,16 @@ class Controller extends Section { this.$.payMethodToTransfer.show(); }); } + + setWireTransfer() { + const params = { + id: this.$params.id, + payMethodFk: this.wireTransferFk + }; + const query = `Suppliers/${this.$params.id}`; + return this.$http.patch(query, params) + .then(() => this.$.watcher.notifySaved()); + } } ngModule.vnComponent('vnSupplierAccount', { diff --git a/modules/supplier/front/account/index.spec.js b/modules/supplier/front/account/index.spec.js index 5c824907f..ad29d1abc 100644 --- a/modules/supplier/front/account/index.spec.js +++ b/modules/supplier/front/account/index.spec.js @@ -5,9 +5,12 @@ import crudModel from 'core/mocks/crud-model'; describe('Supplier Component vnSupplierAccount', () => { let $scope; let controller; + let $httpBackend; + beforeEach(ngModule('supplier')); beforeEach(inject(($componentController, $rootScope, _$httpBackend_) => { + $httpBackend = _$httpBackend_; $scope = $rootScope.$new(); $scope.model = crudModel; $scope.watcher = watcher; @@ -66,5 +69,30 @@ describe('Supplier Component vnSupplierAccount', () => { }).catch(done.fail); }); }); + + describe('setWireTransfer()', () => { + it(`should make HTTP PATCH request to set wire transfer and call notifySaved`, () => { + const supplierId = 1; + const params = { + id: supplierId, + payMethodFk: 2 + }; + const response = { + data: {id: 2} + }; + const uri = 'payMethods/findOne?filter=%7B%22where%22:%7B%22code%22:%22wireTransfer%22%7D%7D'; + jest.spyOn($scope.watcher, 'notifySaved'); + + controller.$params.id = supplierId; + controller.wireTransferFk = 2; + controller.supplier = {payMethodFk: 1}; + $httpBackend.expectGET(uri).respond(response); + $httpBackend.expectPATCH(`Suppliers/${supplierId}`, params).respond(); + controller.setWireTransfer(); + $httpBackend.flush(); + + expect($scope.watcher.notifySaved).toHaveBeenCalledWith(); + }); + }); }); From 3512e287ae0070991c66cf37fb4f54b6a3e60b1e Mon Sep 17 00:00:00 2001 From: joan Date: Tue, 1 Mar 2022 11:09:10 +0100 Subject: [PATCH 39/54] Updated endpoints description --- back/methods/chat/getServiceAuth.js | 2 +- back/methods/chat/sendCheckingPresence.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/back/methods/chat/getServiceAuth.js b/back/methods/chat/getServiceAuth.js index 7eb0ceaa5..827092109 100644 --- a/back/methods/chat/getServiceAuth.js +++ b/back/methods/chat/getServiceAuth.js @@ -2,7 +2,7 @@ const axios = require('axios'); const tokenLifespan = 10; module.exports = Self => { Self.remoteMethodCtx('getServiceAuth', { - description: 'Send a RocketChat message', + description: 'Authenticates with the service and request a new token', accessType: 'READ', accepts: [], returns: { diff --git a/back/methods/chat/sendCheckingPresence.js b/back/methods/chat/sendCheckingPresence.js index 10a98452f..429ecdab0 100644 --- a/back/methods/chat/sendCheckingPresence.js +++ b/back/methods/chat/sendCheckingPresence.js @@ -2,7 +2,7 @@ const axios = require('axios'); module.exports = Self => { Self.remoteMethodCtx('sendCheckingPresence', { - description: 'Sends a RocketChat message to a working worker or department channel', + description: 'Sends a RocketChat message to a connected user or department channel', accessType: 'WRITE', accepts: [{ arg: 'recipientId', From 2026e909e93e0ff76e2d70b278c65f0855360fab Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 1 Mar 2022 11:43:35 +0100 Subject: [PATCH 40/54] disable search observation --- modules/client/back/methods/defaulter/filter.js | 2 +- modules/client/front/defaulter/index.js | 8 +------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/modules/client/back/methods/defaulter/filter.js b/modules/client/back/methods/defaulter/filter.js index c65991273..095b9b1c1 100644 --- a/modules/client/back/methods/defaulter/filter.js +++ b/modules/client/back/methods/defaulter/filter.js @@ -61,7 +61,7 @@ module.exports = Self => { u.nickname salesPersonName, d.amount, co.created, - CONCAT(DATE(co.created), ' ', co.text) observation, + co.text observation, uw.id workerFk, uw.nickname workerName, c.creditInsurance, diff --git a/modules/client/front/defaulter/index.js b/modules/client/front/defaulter/index.js index 5fcc955cc..9595be61c 100644 --- a/modules/client/front/defaulter/index.js +++ b/modules/client/front/defaulter/index.js @@ -41,11 +41,7 @@ export default class Controller extends Section { }, { field: 'observation', - autocomplete: { - url: 'Defaulters/filter', - showField: 'observation', - valueField: 'observation', - } + searchable: false }, { field: 'created', @@ -116,8 +112,6 @@ export default class Controller extends Section { exprBuilder(param, value) { switch (param) { - case 'observation': - return {[`observation`]: {like: `%${value}%`}}; case 'creditInsurance': case 'amount': case 'clientName': From cb21a510650e66417c35f6770f56357f1200e848 Mon Sep 17 00:00:00 2001 From: joan Date: Tue, 1 Mar 2022 12:12:40 +0100 Subject: [PATCH 41/54] Added SQL version 10430-ash --- db/changes/10430-ash/delete.keep | 1 + 1 file changed, 1 insertion(+) create mode 100644 db/changes/10430-ash/delete.keep diff --git a/db/changes/10430-ash/delete.keep b/db/changes/10430-ash/delete.keep new file mode 100644 index 000000000..8fe7322e3 --- /dev/null +++ b/db/changes/10430-ash/delete.keep @@ -0,0 +1 @@ +delete file \ No newline at end of file From 44318903e774f5cea64a0e13ae53709b0d66ff9b Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 1 Mar 2022 15:15:58 +0100 Subject: [PATCH 42/54] feat(claim): add log section --- db/changes/10430-ash/00-aclClaimLog.sql | 3 ++ db/changes/10430-ash/delete.keep | 1 - e2e/helpers/selectors.js | 4 ++ e2e/paths/06-claim/07_.claim_log.spec.js | 52 +++++++++++++++++++ .../claim/back/models/claim-beginning.json | 7 ++- .../claim/back/models/claim-development.json | 6 ++- modules/claim/back/models/claim-end.json | 6 ++- modules/claim/back/models/claim-state.json | 7 ++- modules/claim/back/models/claim.json | 6 ++- modules/claim/front/index.js | 1 + modules/claim/front/log/index.html | 4 ++ modules/claim/front/log/index.js | 7 +++ modules/claim/front/routes.json | 9 +++- 13 files changed, 106 insertions(+), 7 deletions(-) create mode 100644 db/changes/10430-ash/00-aclClaimLog.sql delete mode 100644 db/changes/10430-ash/delete.keep create mode 100644 e2e/paths/06-claim/07_.claim_log.spec.js create mode 100644 modules/claim/front/log/index.html create mode 100644 modules/claim/front/log/index.js diff --git a/db/changes/10430-ash/00-aclClaimLog.sql b/db/changes/10430-ash/00-aclClaimLog.sql new file mode 100644 index 000000000..cad88a6ab --- /dev/null +++ b/db/changes/10430-ash/00-aclClaimLog.sql @@ -0,0 +1,3 @@ +INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId) + VALUES + ('ClaimLog', '*', 'READ', 'ALLOW', 'ROLE', 'claimManager'); diff --git a/db/changes/10430-ash/delete.keep b/db/changes/10430-ash/delete.keep deleted file mode 100644 index 8fe7322e3..000000000 --- a/db/changes/10430-ash/delete.keep +++ /dev/null @@ -1 +0,0 @@ -delete file \ No newline at end of file diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index f0a5c37b5..1adf5ff2b 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -729,6 +729,10 @@ export default { firstDeleteLine: 'vn-claim-action vn-tr:nth-child(1) vn-icon-button[icon="delete"]', isPaidWithManaCheckbox: 'vn-claim-action vn-check[ng-model="$ctrl.claim.isChargedToMana"]' }, + claimLog: { + anyLineCreated: 'vn-claim-log > vn-log vn-tbody > vn-tr', + firstLineCreatedProperty: 'vn-claim-log > vn-log vn-tbody > vn-tr:nth-child(1) > vn-td > vn-one:nth-child(3) > div span:nth-child(2)', + }, ordersIndex: { secondSearchResultTotal: 'vn-order-index vn-card > vn-table > div > vn-tbody .vn-tr:nth-child(2) vn-td:nth-child(9)', advancedSearchButton: 'vn-order-search-panel vn-submit[label="Search"]', diff --git a/e2e/paths/06-claim/07_.claim_log.spec.js b/e2e/paths/06-claim/07_.claim_log.spec.js new file mode 100644 index 000000000..a970fd1e9 --- /dev/null +++ b/e2e/paths/06-claim/07_.claim_log.spec.js @@ -0,0 +1,52 @@ +import selectors from '../../helpers/selectors.js'; +import getBrowser from '../../helpers/puppeteer'; + +fdescribe('Claim log path', () => { + let browser; + let page; + const claimId = '1'; + + beforeAll(async() => { + browser = await getBrowser(); + page = browser.page; + await page.loginAndModule('claimManager', 'claim'); + }); + + afterAll(async() => { + await browser.close(); + }); + + it('should now navigate to the target claim basicData section', async() => { + await page.loginAndModule('claimManager', 'claim'); + await page.accessToSearchResult(claimId); + await page.accessToSection('claim.card.basicData'); + }); + + it(`should edit claim state and observation fields`, async() => { + await page.autocompleteSearch(selectors.claimBasicData.claimState, 'Faltas'); + await page.waitToClick(selectors.claimBasicData.saveButton); + const message = await page.waitForSnackbar(); + + expect(message.text).toContain('Data saved!'); + }); + + it(`should edit claim state and observation fields`, async() => { + await page.autocompleteSearch(selectors.claimBasicData.claimState, 'Faltas'); + await page.waitToClick(selectors.claimBasicData.saveButton); + const message = await page.waitForSnackbar(); + + expect(message.text).toContain('Data saved!'); + }); + + it(`should search for the created item and navigate to it's log section`, async() => { + await page.waitForState('claim.card.detail'); + await page.accessToSection('claim.card.log'); + }); + + it(`should confirm the log is showing 5 entries`, async() => { + await page.waitForSelector(selectors.claimLog.anyLineCreated); + const anyLineCreatedCount = await page.countElement(selectors.claimLog.anyLineCreated); + + expect(anyLineCreatedCount).toEqual(5); + }); +}); diff --git a/modules/claim/back/models/claim-beginning.json b/modules/claim/back/models/claim-beginning.json index 50506122a..abdae440a 100644 --- a/modules/claim/back/models/claim-beginning.json +++ b/modules/claim/back/models/claim-beginning.json @@ -1,6 +1,11 @@ { "name": "ClaimBeginning", - "base": "VnModel", + "base": "Loggable", + "log": { + "model": "ClaimLog", + "relation": "claim", + "showField": "quantity" + }, "options": { "mysql": { "table": "claimBeginning" diff --git a/modules/claim/back/models/claim-development.json b/modules/claim/back/models/claim-development.json index 94c677304..2e8eb2f01 100644 --- a/modules/claim/back/models/claim-development.json +++ b/modules/claim/back/models/claim-development.json @@ -1,6 +1,10 @@ { "name": "ClaimDevelopment", - "base": "VnModel", + "base": "Loggable", + "log": { + "model": "ClaimLog", + "relation": "claim" + }, "options": { "mysql": { "table": "claimDevelopment" diff --git a/modules/claim/back/models/claim-end.json b/modules/claim/back/models/claim-end.json index 8f835ee84..d908c252b 100644 --- a/modules/claim/back/models/claim-end.json +++ b/modules/claim/back/models/claim-end.json @@ -1,6 +1,10 @@ { "name": "ClaimEnd", - "base": "VnModel", + "base": "Loggable", + "log": { + "model": "ClaimLog", + "relation": "claim" + }, "options": { "mysql": { "table": "claimEnd" diff --git a/modules/claim/back/models/claim-state.json b/modules/claim/back/models/claim-state.json index 287a525ad..e0a536e11 100644 --- a/modules/claim/back/models/claim-state.json +++ b/modules/claim/back/models/claim-state.json @@ -1,6 +1,11 @@ { "name": "ClaimState", - "base": "VnModel", + "base": "Loggable", + "log": { + "model": "ClaimLog", + "relation": "claim", + "showField": "description" + }, "options": { "mysql": { "table": "claimState" diff --git a/modules/claim/back/models/claim.json b/modules/claim/back/models/claim.json index 3cb64e31d..761a3b4c9 100644 --- a/modules/claim/back/models/claim.json +++ b/modules/claim/back/models/claim.json @@ -1,6 +1,10 @@ { "name": "Claim", - "base": "VnModel", + "base": "Loggable", + "log": { + "model": "ClaimLog", + "showField": "id" + }, "options": { "mysql": { "table": "claim" diff --git a/modules/claim/front/index.js b/modules/claim/front/index.js index b6c39196e..ebbc6ea06 100644 --- a/modules/claim/front/index.js +++ b/modules/claim/front/index.js @@ -11,3 +11,4 @@ import './development'; import './search-panel'; import './summary'; import './photos'; +import './log'; diff --git a/modules/claim/front/log/index.html b/modules/claim/front/log/index.html new file mode 100644 index 000000000..500a626d6 --- /dev/null +++ b/modules/claim/front/log/index.html @@ -0,0 +1,4 @@ + + \ No newline at end of file diff --git a/modules/claim/front/log/index.js b/modules/claim/front/log/index.js new file mode 100644 index 000000000..0143a612b --- /dev/null +++ b/modules/claim/front/log/index.js @@ -0,0 +1,7 @@ +import ngModule from '../module'; +import Section from 'salix/components/section'; + +ngModule.vnComponent('vnClaimLog', { + template: require('./index.html'), + controller: Section, +}); diff --git a/modules/claim/front/routes.json b/modules/claim/front/routes.json index ced6f4a6f..5f08255be 100644 --- a/modules/claim/front/routes.json +++ b/modules/claim/front/routes.json @@ -13,7 +13,8 @@ {"state": "claim.card.detail", "icon": "icon-details"}, {"state": "claim.card.photos", "icon": "image"}, {"state": "claim.card.development", "icon": "icon-traceability"}, - {"state": "claim.card.action", "icon": "icon-actions"} + {"state": "claim.card.action", "icon": "icon-actions"}, + {"state": "claim.card.log", "icon": "history"} ] }, "keybindings": [ @@ -88,6 +89,12 @@ "params": { "claim": "$ctrl.claim" } + }, { + "url" : "/log", + "state": "claim.card.log", + "component": "vn-claim-log", + "description": "Log", + "acl": ["claimManager"] } ] } \ No newline at end of file From 64a94cd60d05441e74abc132df1170556ef5d64d Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 2 Mar 2022 09:50:29 +0100 Subject: [PATCH 43/54] delete e2e --- e2e/helpers/selectors.js | 4 -- e2e/paths/06-claim/07_.claim_log.spec.js | 52 ------------------------ 2 files changed, 56 deletions(-) delete mode 100644 e2e/paths/06-claim/07_.claim_log.spec.js diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index 1adf5ff2b..f0a5c37b5 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -729,10 +729,6 @@ export default { firstDeleteLine: 'vn-claim-action vn-tr:nth-child(1) vn-icon-button[icon="delete"]', isPaidWithManaCheckbox: 'vn-claim-action vn-check[ng-model="$ctrl.claim.isChargedToMana"]' }, - claimLog: { - anyLineCreated: 'vn-claim-log > vn-log vn-tbody > vn-tr', - firstLineCreatedProperty: 'vn-claim-log > vn-log vn-tbody > vn-tr:nth-child(1) > vn-td > vn-one:nth-child(3) > div span:nth-child(2)', - }, ordersIndex: { secondSearchResultTotal: 'vn-order-index vn-card > vn-table > div > vn-tbody .vn-tr:nth-child(2) vn-td:nth-child(9)', advancedSearchButton: 'vn-order-search-panel vn-submit[label="Search"]', diff --git a/e2e/paths/06-claim/07_.claim_log.spec.js b/e2e/paths/06-claim/07_.claim_log.spec.js deleted file mode 100644 index a970fd1e9..000000000 --- a/e2e/paths/06-claim/07_.claim_log.spec.js +++ /dev/null @@ -1,52 +0,0 @@ -import selectors from '../../helpers/selectors.js'; -import getBrowser from '../../helpers/puppeteer'; - -fdescribe('Claim log path', () => { - let browser; - let page; - const claimId = '1'; - - beforeAll(async() => { - browser = await getBrowser(); - page = browser.page; - await page.loginAndModule('claimManager', 'claim'); - }); - - afterAll(async() => { - await browser.close(); - }); - - it('should now navigate to the target claim basicData section', async() => { - await page.loginAndModule('claimManager', 'claim'); - await page.accessToSearchResult(claimId); - await page.accessToSection('claim.card.basicData'); - }); - - it(`should edit claim state and observation fields`, async() => { - await page.autocompleteSearch(selectors.claimBasicData.claimState, 'Faltas'); - await page.waitToClick(selectors.claimBasicData.saveButton); - const message = await page.waitForSnackbar(); - - expect(message.text).toContain('Data saved!'); - }); - - it(`should edit claim state and observation fields`, async() => { - await page.autocompleteSearch(selectors.claimBasicData.claimState, 'Faltas'); - await page.waitToClick(selectors.claimBasicData.saveButton); - const message = await page.waitForSnackbar(); - - expect(message.text).toContain('Data saved!'); - }); - - it(`should search for the created item and navigate to it's log section`, async() => { - await page.waitForState('claim.card.detail'); - await page.accessToSection('claim.card.log'); - }); - - it(`should confirm the log is showing 5 entries`, async() => { - await page.waitForSelector(selectors.claimLog.anyLineCreated); - const anyLineCreatedCount = await page.countElement(selectors.claimLog.anyLineCreated); - - expect(anyLineCreatedCount).toEqual(5); - }); -}); From 619baf289677a7f2b91e82249a77bfb45213466b Mon Sep 17 00:00:00 2001 From: alexm Date: Wed, 2 Mar 2022 11:07:35 +0100 Subject: [PATCH 44/54] refactor claim_main controller --- modules/claim/front/main/index.js | 8 +------- modules/claim/front/summary/index.js | 2 +- modules/claim/front/summary/index.spec.js | 4 ++-- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/modules/claim/front/main/index.js b/modules/claim/front/main/index.js index a9fad2eeb..0c5c7d728 100644 --- a/modules/claim/front/main/index.js +++ b/modules/claim/front/main/index.js @@ -1,13 +1,7 @@ import ngModule from '../module'; import ModuleMain from 'salix/components/module-main'; -export default class Claims extends ModuleMain { - constructor($element, $) { - super($element, $); - } -} - ngModule.vnComponent('vnClaim', { - controller: Claims, + controller: ModuleMain, template: require('./index.html') }); diff --git a/modules/claim/front/summary/index.js b/modules/claim/front/summary/index.js index cc9799f05..721f51846 100644 --- a/modules/claim/front/summary/index.js +++ b/modules/claim/front/summary/index.js @@ -25,7 +25,7 @@ class Controller extends Summary { .then(() => { if (this.card) this.card.reload(); - // Refresh index model + if (this.parentReload) this.parentReload(); }); diff --git a/modules/claim/front/summary/index.spec.js b/modules/claim/front/summary/index.spec.js index 02bdf21d2..8540a3a97 100644 --- a/modules/claim/front/summary/index.spec.js +++ b/modules/claim/front/summary/index.spec.js @@ -29,7 +29,7 @@ describe('Claim', () => { }); describe('changeState()', () => { - it('should make an HTTP post query, then call the showSuccess(), reload() and resetChanges() methods', () => { + it('should make an HTTP post query, then call the showSuccess()', () => { jest.spyOn(controller.vnApp, 'showSuccess').mockReturnThis(); const expectedParams = {id: 1, claimStateFk: 1}; @@ -43,7 +43,7 @@ describe('Claim', () => { }); describe('$onChanges()', () => { - it('should call loadData when item.id is defined', () => { + it('should call loadData when $onChanges is called', () => { jest.spyOn(controller, 'loadData'); controller.$onChanges(); From e082d185646b0fe057b8c3012502c262426a434d Mon Sep 17 00:00:00 2001 From: alexm Date: Thu, 3 Mar 2022 13:03:43 +0100 Subject: [PATCH 45/54] change description --- modules/order/back/methods/order/filter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/order/back/methods/order/filter.js b/modules/order/back/methods/order/filter.js index a4d0c0f8e..008c0e5c9 100644 --- a/modules/order/back/methods/order/filter.js +++ b/modules/order/back/methods/order/filter.js @@ -18,7 +18,7 @@ module.exports = Self => { }, { arg: 'search', type: 'string', - description: `If it's and integer searchs by ticket id, otherwise it searchs by nickname` + description: `The general search by ticket id or nickname` }, { arg: 'from', type: 'date', From 6748426f670ed5878c86f249880f530fc0a7fb89 Mon Sep 17 00:00:00 2001 From: alexm Date: Thu, 3 Mar 2022 13:48:18 +0100 Subject: [PATCH 46/54] correct loopback form --- modules/supplier/back/models/supplier-account.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/supplier/back/models/supplier-account.js b/modules/supplier/back/models/supplier-account.js index ae93ef83b..dc6c6d5fd 100644 --- a/modules/supplier/back/models/supplier-account.js +++ b/modules/supplier/back/models/supplier-account.js @@ -38,10 +38,9 @@ module.exports = Self => { Self.observe('after save', async ctx => { const options = {}; - // Check for transactions if (ctx.options && ctx.options.transaction) options.transaction = ctx.options.transaction; - const supplier = await Self.app.models.Supplier.findById(ctx.instance.supplierFk, options); + const supplier = await Self.app.models.Supplier.findById(ctx.instance.supplierFk, null, options); if (supplier.isPayMethodChecked) await supplier.updateAttribute('isPayMethodChecked', false, options); From a434d9268bf9018c9f72d072d36c1ee45851d8bb Mon Sep 17 00:00:00 2001 From: alexm Date: Fri, 4 Mar 2022 11:48:18 +0100 Subject: [PATCH 47/54] fix(zone_upcoming-deliveries): fix backgroundcolor --- modules/zone/front/upcoming-deliveries/style.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/zone/front/upcoming-deliveries/style.scss b/modules/zone/front/upcoming-deliveries/style.scss index d3f33260a..b52231a09 100644 --- a/modules/zone/front/upcoming-deliveries/style.scss +++ b/modules/zone/front/upcoming-deliveries/style.scss @@ -15,6 +15,7 @@ vn-upcoming-deliveries { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + background-color: $color-bg; } vn-table vn-th.waste-family, From a658969afa4a2c1af565ac55e38ab37bfd6e4a60 Mon Sep 17 00:00:00 2001 From: alexm Date: Fri, 4 Mar 2022 12:24:01 +0100 Subject: [PATCH 48/54] feat(zone_delivery-days): get real closing hour --- .../zone/back/methods/zone/getZoneClosing.js | 68 +++++++++++++++++++ modules/zone/back/models/zone.js | 1 + modules/zone/front/delivery-days/index.html | 14 +--- modules/zone/front/delivery-days/index.js | 37 +++------- .../zone/front/delivery-days/index.spec.js | 35 +++------- 5 files changed, 90 insertions(+), 65 deletions(-) create mode 100644 modules/zone/back/methods/zone/getZoneClosing.js diff --git a/modules/zone/back/methods/zone/getZoneClosing.js b/modules/zone/back/methods/zone/getZoneClosing.js new file mode 100644 index 000000000..02286e6d5 --- /dev/null +++ b/modules/zone/back/methods/zone/getZoneClosing.js @@ -0,0 +1,68 @@ +module.exports = Self => { + Self.remoteMethod('getZoneClosing', { + description: 'Get events filtered for zone and date', + accepts: [ + { + arg: 'zonesId', + type: ['number'], + description: 'The zones id', + required: true + }, + { + arg: 'date', + type: 'date', + description: 'The date calendar', + } + ], + returns: { + type: 'object', + root: true + }, + http: { + path: `/getZoneClosing`, + verb: 'POST' + } + }); + + Self.getZoneClosing = async(zonesId, date, options) => { + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + const params = []; + const paramsSql = [date, date, date]; + for (id of zonesId) { + params.push('?'); + paramsSql.push(id); + } + + const paramsString = params.join(); + query = ` + SELECT * + FROM ( + SELECT + DISTINCT z.id, + z.name, + am.name agencyModeName, + type, + IFNULL(ze.hour, z.hour) as hour, + IFNULL(ze.price, z.price) as price + FROM vn.zone z + JOIN agencyMode am ON am.id = z.agencyModeFk + LEFT JOIN zoneEvent ze ON ze.zoneFk = z.id + WHERE + ( + dated = ? + OR ? BETWEEN started AND ended + OR INSTR(weekDays, SUBSTRING(DAYNAME(?), 1, 3) ) > 0 + ) + AND z.id IN (${paramsString}) + ORDER BY type='day' DESC, type='range' DESC, type='indefinitely' DESC) z + GROUP BY z.id + `; + + const zones = await Self.rawSql(query, paramsSql, myOptions); + return zones; + }; +}; diff --git a/modules/zone/back/models/zone.js b/modules/zone/back/models/zone.js index 9771c958b..ef1c8c5d9 100644 --- a/modules/zone/back/models/zone.js +++ b/modules/zone/back/models/zone.js @@ -7,6 +7,7 @@ module.exports = Self => { require('../methods/zone/getUpcomingDeliveries')(Self); require('../methods/zone/deleteZone')(Self); require('../methods/zone/includingExpired')(Self); + require('../methods/zone/getZoneClosing')(Self); Self.validatesPresenceOf('agencyModeFk', { message: `Agency cannot be blank` diff --git a/modules/zone/front/delivery-days/index.html b/modules/zone/front/delivery-days/index.html index f01f4ec3f..1c1a9b1b3 100644 --- a/modules/zone/front/delivery-days/index.html +++ b/modules/zone/front/delivery-days/index.html @@ -52,23 +52,15 @@ - - -
Zones
- + Id @@ -81,7 +73,7 @@ {{::zone.id}} diff --git a/modules/zone/front/delivery-days/index.js b/modules/zone/front/delivery-days/index.js index 12b1c57b1..d4bb3b335 100644 --- a/modules/zone/front/delivery-days/index.js +++ b/modules/zone/front/delivery-days/index.js @@ -74,33 +74,16 @@ class Controller extends Section { zonesIds.push(event.zoneFk); this.$.zoneEvents.show($event.target); - const zoneModel = this.$.zoneModel; - zoneModel.applyFilter({ - include: [ - { - relation: 'agencyMode', - scope: {fields: ['name']} - }, - { - relation: 'events', - scope: { - where: {dated: day} - } - }, - ], - where: { - id: {inq: zonesIds} - } - }).then(() => { - const data = zoneModel.data; - for (let row of data) { - const [event] = row.events; - if (event && event.hour) - row.hour = event.hour; - if (event && event.price) - row.price = event.price; - } - }); + + const params = { + zonesId: zonesIds, + date: day + }; + + this.$http.post(`Zones/getZoneClosing`, params) + .then(res => { + this.zoneClosing = res.data; + }); } preview(zone) { diff --git a/modules/zone/front/delivery-days/index.spec.js b/modules/zone/front/delivery-days/index.spec.js index c896021ed..c03da585f 100644 --- a/modules/zone/front/delivery-days/index.spec.js +++ b/modules/zone/front/delivery-days/index.spec.js @@ -96,14 +96,8 @@ describe('Zone Component vnZoneDeliveryDays', () => { expect(controller.$.zoneEvents.show).not.toHaveBeenCalled(); }); - it('should call the show() method and then call the applyFilter() method with the expected ids', () => { - const zoneModel = controller.$.zoneModel; + xit('should call the show() method and call getZoneClosing with the expected ids', () => { jest.spyOn(controller.$.zoneEvents, 'show'); - jest.spyOn(zoneModel, 'applyFilter').mockReturnValue(new Promise(resolve => { - zoneModel.data = [ - {id: 1, events: [{price: 25}]} - ]; - })); const event = new Event('click'); const target = document.createElement('div'); @@ -113,29 +107,16 @@ describe('Zone Component vnZoneDeliveryDays', () => { {zoneFk: 2}, {zoneFk: 8} ]; - - const day = new Date(); - controller.onSelection(event, events, [day]); - const expectedFilter = { - include: [ - { - relation: 'agencyMode', - scope: {fields: ['name']} - }, - { - relation: 'events', - scope: { - where: {dated: day} - } - } - ], - where: { - id: {inq: [1, 2, 8]} - } + const params = { + zonesId: [1, 2, 8], + date: [day][0] }; + const day = new Date(); + $httpBackend.expect('POST', 'Zones/getZoneClosing', params).respond({}); + controller.onSelection(event, events, [day]); expect(controller.$.zoneEvents.show).toHaveBeenCalledWith(target); - expect(zoneModel.applyFilter).toHaveBeenCalledWith(expectedFilter); + expect(controller.zoneClosing).toBeDefined(); }); }); }); From 2c853a7885cd7f9412d335ff8a5b9a85374001e5 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 7 Mar 2022 08:02:59 +0100 Subject: [PATCH 49/54] test(zone): getZoneClosing() front and back --- .../zone/back/methods/zone/getZoneClosing.js | 4 +--- .../methods/zone/specs/getZoneClosing.spec.js | 23 +++++++++++++++++++ modules/zone/front/delivery-days/index.js | 4 +--- .../zone/front/delivery-days/index.spec.js | 12 ++++++---- 4 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 modules/zone/back/methods/zone/specs/getZoneClosing.spec.js diff --git a/modules/zone/back/methods/zone/getZoneClosing.js b/modules/zone/back/methods/zone/getZoneClosing.js index 02286e6d5..8d9ccdb21 100644 --- a/modules/zone/back/methods/zone/getZoneClosing.js +++ b/modules/zone/back/methods/zone/getZoneClosing.js @@ -45,7 +45,6 @@ module.exports = Self => { DISTINCT z.id, z.name, am.name agencyModeName, - type, IFNULL(ze.hour, z.hour) as hour, IFNULL(ze.price, z.price) as price FROM vn.zone z @@ -62,7 +61,6 @@ module.exports = Self => { GROUP BY z.id `; - const zones = await Self.rawSql(query, paramsSql, myOptions); - return zones; + return await Self.rawSql(query, paramsSql, myOptions); }; }; diff --git a/modules/zone/back/methods/zone/specs/getZoneClosing.spec.js b/modules/zone/back/methods/zone/specs/getZoneClosing.spec.js new file mode 100644 index 000000000..0c479dda0 --- /dev/null +++ b/modules/zone/back/methods/zone/specs/getZoneClosing.spec.js @@ -0,0 +1,23 @@ +const models = require('vn-loopback/server/server').models; + +describe('zone getZoneClosing()', () => { + it('should return closing time of zones', async() => { + const tx = await models.Zone.beginTransaction({}); + + try { + const options = {transaction: tx}; + const date = new Date(); + const today = date.toISOString().split('T')[0]; + + const result = await models.Zone.getZoneClosing([1, 2, 3], today, options); + + expect(result.length).toEqual(3); + expect(result[0].hour).toBeDefined(); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); +}); diff --git a/modules/zone/front/delivery-days/index.js b/modules/zone/front/delivery-days/index.js index d4bb3b335..21c65678f 100644 --- a/modules/zone/front/delivery-days/index.js +++ b/modules/zone/front/delivery-days/index.js @@ -81,9 +81,7 @@ class Controller extends Section { }; this.$http.post(`Zones/getZoneClosing`, params) - .then(res => { - this.zoneClosing = res.data; - }); + .then(res => this.zoneClosing = res.data); } preview(zone) { diff --git a/modules/zone/front/delivery-days/index.spec.js b/modules/zone/front/delivery-days/index.spec.js index c03da585f..3d71bc93f 100644 --- a/modules/zone/front/delivery-days/index.spec.js +++ b/modules/zone/front/delivery-days/index.spec.js @@ -96,12 +96,14 @@ describe('Zone Component vnZoneDeliveryDays', () => { expect(controller.$.zoneEvents.show).not.toHaveBeenCalled(); }); - xit('should call the show() method and call getZoneClosing with the expected ids', () => { + it('should call the show() method and call getZoneClosing() with the expected ids', () => { jest.spyOn(controller.$.zoneEvents, 'show'); const event = new Event('click'); const target = document.createElement('div'); target.dispatchEvent(event); + + const day = new Date(); const events = [ {zoneFk: 1}, {zoneFk: 2}, @@ -111,12 +113,14 @@ describe('Zone Component vnZoneDeliveryDays', () => { zonesId: [1, 2, 8], date: [day][0] }; - const day = new Date(); - $httpBackend.expect('POST', 'Zones/getZoneClosing', params).respond({}); + const response = [{id: 1, hour: ''}]; + + $httpBackend.when('POST', 'Zones/getZoneClosing', params).respond({response}); controller.onSelection(event, events, [day]); + $httpBackend.flush(); expect(controller.$.zoneEvents.show).toHaveBeenCalledWith(target); - expect(controller.zoneClosing).toBeDefined(); + expect(controller.zoneClosing.id).toEqual(response.id); }); }); }); From dedbccae198b89a082168a483896e235daef20c5 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 7 Mar 2022 08:07:34 +0100 Subject: [PATCH 50/54] description --- modules/zone/back/methods/zone/getZoneClosing.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/zone/back/methods/zone/getZoneClosing.js b/modules/zone/back/methods/zone/getZoneClosing.js index 8d9ccdb21..849aa5008 100644 --- a/modules/zone/back/methods/zone/getZoneClosing.js +++ b/modules/zone/back/methods/zone/getZoneClosing.js @@ -1,6 +1,6 @@ module.exports = Self => { Self.remoteMethod('getZoneClosing', { - description: 'Get events filtered for zone and date', + description: 'Get zone events filtered for date and prioritized by type', accepts: [ { arg: 'zonesId', From b421038bbef99cea8802b3cac1d66ac60594d6c1 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 7 Mar 2022 08:11:21 +0100 Subject: [PATCH 51/54] typo --- modules/zone/back/methods/zone/getZoneClosing.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/zone/back/methods/zone/getZoneClosing.js b/modules/zone/back/methods/zone/getZoneClosing.js index 849aa5008..56fb3b7a6 100644 --- a/modules/zone/back/methods/zone/getZoneClosing.js +++ b/modules/zone/back/methods/zone/getZoneClosing.js @@ -58,8 +58,7 @@ module.exports = Self => { ) AND z.id IN (${paramsString}) ORDER BY type='day' DESC, type='range' DESC, type='indefinitely' DESC) z - GROUP BY z.id - `; + GROUP BY z.id`; return await Self.rawSql(query, paramsSql, myOptions); }; From a136d8b03d6f6b25629dfa587cb42899233c4d2e Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 7 Mar 2022 10:10:45 +0100 Subject: [PATCH 52/54] accept array in params --- modules/ticket/back/methods/sale/payBack.js | 13 ++++--------- .../ticket/back/methods/sale/recalculatePrice.js | 9 ++------- modules/zone/back/methods/zone/getZoneClosing.js | 12 ++---------- 3 files changed, 8 insertions(+), 26 deletions(-) diff --git a/modules/ticket/back/methods/sale/payBack.js b/modules/ticket/back/methods/sale/payBack.js index 3bb056465..098da4d5a 100644 --- a/modules/ticket/back/methods/sale/payBack.js +++ b/modules/ticket/back/methods/sale/payBack.js @@ -40,7 +40,6 @@ module.exports = Self => { try { const salesIds = []; - const params = []; const userId = ctx.req.accessToken.userId; const isClaimManager = await Self.app.models.Account.hasRole(userId, 'claimManager'); @@ -50,23 +49,19 @@ module.exports = Self => { if (!hasValidRole) throw new UserError(`You don't have privileges to create pay back`); - sales.forEach(sale => { + for (let sale of sales) salesIds.push(sale.id); - params.push('?'); - }); - - const paramsString = params.join(); const query = ` DROP TEMPORARY TABLE IF EXISTS tmp.sale; CREATE TEMPORARY TABLE tmp.sale SELECT s.id, s.itemFk, - s.quantity, s.concept, s.price, s.discount FROM sale s - WHERE s.id IN (${paramsString}); - CALL vn.ticket_doRefund(${ticketId}, @newTicket); + WHERE s.id IN (?); + CALL vn.ticket_doRefund(?, @newTicket); DROP TEMPORARY TABLE tmp.sale;`; - await Self.rawSql(query, salesIds, myOptions); + await Self.rawSql(query, [salesIds, ticketId], myOptions); const [newTicket] = await Self.rawSql('SELECT @newTicket id', null, myOptions); ticketId = newTicket.id; diff --git a/modules/ticket/back/methods/sale/recalculatePrice.js b/modules/ticket/back/methods/sale/recalculatePrice.js index 8a390223d..59c7d3535 100644 --- a/modules/ticket/back/methods/sale/recalculatePrice.js +++ b/modules/ticket/back/methods/sale/recalculatePrice.js @@ -35,11 +35,8 @@ module.exports = Self => { try { const salesIds = []; - const params = []; - sales.forEach(sale => { + for (let sale of sales) salesIds.push(sale.id); - params.push('?'); - }); const isEditable = await models.Ticket.isEditable(ctx, sales[0].ticketFk, myOptions); if (!isEditable) @@ -49,14 +46,12 @@ module.exports = Self => { if (!canEditSale) throw new UserError(`Sale(s) blocked, please contact production`); - const paramsString = params.join(); - const query = ` DROP TEMPORARY TABLE IF EXISTS tmp.recalculateSales; CREATE TEMPORARY TABLE tmp.recalculateSales SELECT s.id FROM sale s - WHERE s.id IN (${paramsString}); + WHERE s.id IN (?); CALL vn.sale_recalcComponent(null); DROP TEMPORARY TABLE tmp.recalculateSales;`; diff --git a/modules/zone/back/methods/zone/getZoneClosing.js b/modules/zone/back/methods/zone/getZoneClosing.js index 56fb3b7a6..fae43c0dc 100644 --- a/modules/zone/back/methods/zone/getZoneClosing.js +++ b/modules/zone/back/methods/zone/getZoneClosing.js @@ -30,14 +30,6 @@ module.exports = Self => { if (typeof options == 'object') Object.assign(myOptions, options); - const params = []; - const paramsSql = [date, date, date]; - for (id of zonesId) { - params.push('?'); - paramsSql.push(id); - } - - const paramsString = params.join(); query = ` SELECT * FROM ( @@ -56,10 +48,10 @@ module.exports = Self => { OR ? BETWEEN started AND ended OR INSTR(weekDays, SUBSTRING(DAYNAME(?), 1, 3) ) > 0 ) - AND z.id IN (${paramsString}) + AND z.id IN (?) ORDER BY type='day' DESC, type='range' DESC, type='indefinitely' DESC) z GROUP BY z.id`; - return await Self.rawSql(query, paramsSql, myOptions); + return Self.rawSql(query, [date, date, date, zonesId], myOptions); }; }; From 56bdb85af50fc1c0daf4c2405f773289b5245e29 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 7 Mar 2022 10:28:55 +0100 Subject: [PATCH 53/54] translations --- modules/zone/back/methods/zone/getEventsFiltered.js | 4 ++-- modules/zone/back/methods/zone/getZoneClosing.js | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/zone/back/methods/zone/getEventsFiltered.js b/modules/zone/back/methods/zone/getEventsFiltered.js index 2788f45d0..5e9cbae5a 100644 --- a/modules/zone/back/methods/zone/getEventsFiltered.js +++ b/modules/zone/back/methods/zone/getEventsFiltered.js @@ -11,12 +11,12 @@ module.exports = Self => { { arg: 'started', type: 'date', - description: 'The date calendar start', + description: 'The calendar date start', }, { arg: 'ended', type: 'date', - description: 'The date calendar end', + description: 'The calendar date end', } ], returns: { diff --git a/modules/zone/back/methods/zone/getZoneClosing.js b/modules/zone/back/methods/zone/getZoneClosing.js index fae43c0dc..6afb53408 100644 --- a/modules/zone/back/methods/zone/getZoneClosing.js +++ b/modules/zone/back/methods/zone/getZoneClosing.js @@ -3,15 +3,15 @@ module.exports = Self => { description: 'Get zone events filtered for date and prioritized by type', accepts: [ { - arg: 'zonesId', + arg: 'zoneIds', type: ['number'], - description: 'The zones id', + description: 'The zone identifiers or ids', required: true }, { arg: 'date', type: 'date', - description: 'The date calendar', + description: 'The calendar date', } ], returns: { @@ -24,7 +24,7 @@ module.exports = Self => { } }); - Self.getZoneClosing = async(zonesId, date, options) => { + Self.getZoneClosing = async(zoneIds, date, options) => { const myOptions = {}; if (typeof options == 'object') @@ -52,6 +52,6 @@ module.exports = Self => { ORDER BY type='day' DESC, type='range' DESC, type='indefinitely' DESC) z GROUP BY z.id`; - return Self.rawSql(query, [date, date, date, zonesId], myOptions); + return Self.rawSql(query, [date, date, date, zoneIds], myOptions); }; }; From 0359e05defca3352de61d09e39f993ea91c27eb9 Mon Sep 17 00:00:00 2001 From: alexm Date: Mon, 7 Mar 2022 11:22:16 +0100 Subject: [PATCH 54/54] description --- modules/zone/back/methods/zone/getZoneClosing.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/zone/back/methods/zone/getZoneClosing.js b/modules/zone/back/methods/zone/getZoneClosing.js index 6afb53408..2a0088203 100644 --- a/modules/zone/back/methods/zone/getZoneClosing.js +++ b/modules/zone/back/methods/zone/getZoneClosing.js @@ -5,7 +5,7 @@ module.exports = Self => { { arg: 'zoneIds', type: ['number'], - description: 'The zone identifiers or ids', + description: 'The zone ids', required: true }, {