diff --git a/client/client/routes.json b/client/client/routes.json index aa46c5984..e26ae5356 100644 --- a/client/client/routes.json +++ b/client/client/routes.json @@ -296,14 +296,8 @@ }, { "url": "/contact", - "abstract": true, "state": "client.card.contact", - "component": "ui-view" - }, - { - "url": "/index", - "state": "client.card.contact.index", - "component": "vn-client-contact-index", + "component": "vn-client-contact", "description": "Contacts", "params": { "client": "$ctrl.client" @@ -311,6 +305,33 @@ "menu": { "icon": "contact_phone" } + }, + { + "url": "/sample", + "abstract": true, + "state": "client.card.sample", + "component": "ui-view" + }, + { + "url": "/index", + "state": "client.card.sample.index", + "component": "vn-client-sample-index", + "description": "Samples", + "params": { + "client": "$ctrl.client" + }, + "menu": { + "icon": "mail" + } + }, + { + "url": "/create", + "state": "client.card.sample.create", + "component": "vn-client-sample-create", + "description": "Send sample", + "params": { + "client": "$ctrl.client" + } } ] } diff --git a/client/client/src/basic-data/index.html b/client/client/src/basic-data/index.html index 0b42536e6..b4547ba6e 100644 --- a/client/client/src/basic-data/index.html +++ b/client/client/src/basic-data/index.html @@ -9,7 +9,10 @@ Basic data - + + diff --git a/client/client/src/client.js b/client/client/src/client.js index 5e2cfd913..4c67413dc 100644 --- a/client/client/src/client.js +++ b/client/client/src/client.js @@ -29,3 +29,5 @@ import './credit-insurance/create'; import './credit-insurance/insurance/index'; import './credit-insurance/insurance/create'; import './contact'; +import './sample/index'; +import './sample/create'; diff --git a/client/client/src/contact/contact.spec.js b/client/client/src/contact/contact.spec.js index a4d20ea7f..6d8279c83 100644 --- a/client/client/src/contact/contact.spec.js +++ b/client/client/src/contact/contact.spec.js @@ -1,7 +1,7 @@ import './index.js'; describe('Client', () => { - describe('Component vnClientContactIndex', () => { + describe('Component vnClientContact', () => { let $componentController; let $scope; let $state; @@ -20,7 +20,7 @@ describe('Client', () => { $scope = $rootScope.$new(); $scope.form = {$invalid: false}; $scope.model = {refresh: () => {}}; - controller = $componentController('vnClientContactIndex', {$scope: $scope}, {$state: $state}); + controller = $componentController('vnClientContact', {$scope: $scope}, {$state: $state}); controller.client = { id: 101 }; diff --git a/client/client/src/contact/index.js b/client/client/src/contact/index.js index 3fedfd493..06b500802 100644 --- a/client/client/src/contact/index.js +++ b/client/client/src/contact/index.js @@ -110,7 +110,7 @@ class Controller { Controller.$inject = ['$http', '$scope', '$stateParams', '$translate', 'vnApp']; -ngModule.component('vnClientContactIndex', { +ngModule.component('vnClientContact', { template: require('./index.html'), controller: Controller, bindings: { diff --git a/client/client/src/greuge/index/index.html b/client/client/src/greuge/index/index.html index af49e9b23..fd6784f18 100644 --- a/client/client/src/greuge/index/index.html +++ b/client/client/src/greuge/index/index.html @@ -16,7 +16,7 @@ Greuge -
+
@@ -43,16 +43,6 @@ No results - - - - - - - - - - + + +
+ + Send sample + + + + + + + + + + + + +
+ + + + diff --git a/client/client/src/sample/create/index.js b/client/client/src/sample/create/index.js new file mode 100644 index 000000000..3c05e26f6 --- /dev/null +++ b/client/client/src/sample/create/index.js @@ -0,0 +1,77 @@ +import ngModule from '../../module'; +import './style.scss'; + +class Controller { + constructor($scope, $state, $http, vnApp, $translate) { + this.$scope = $scope; + this.$state = $state; + this.$stateParams = $state.params; + this.$http = $http; + this.vnApp = vnApp; + this.$translate = $translate; + this.clientSample = { + clientFk: this.$stateParams.id + }; + } + + showPreview(event) { + event.preventDefault(); + + let sampleType = this.$scope.sampleType.selection; + let queryParams; + + if (!sampleType) + return this.vnApp.showError(this.$translate.instant('Choose a sample')); + + if (sampleType.hasCompany && !this.clientSample.companyFk) + return this.vnApp.showError(this.$translate.instant('Choose a company')); + + if (sampleType.hasCompany) { + queryParams = `${sampleType.code}/${this.clientSample.companyFk}/${this.$stateParams.id}/preview`; + } else { + queryParams = `${sampleType.code}/${this.$stateParams.id}/preview`; + } + + let query = `/mailer/notification/${queryParams}`; + this.$http.get(query).then(res => { + if (res.data) { + let dialog = this.$scope.showPreview.element; + let body = dialog.querySelector('tpl-body'); + body.innerHTML = res.data; + this.$scope.showPreview.show(); + } + }); + } + + onSubmit() { + this.$scope.watcher.check(); + this.$scope.watcher.realSubmit().then(() => + this.sendSample() + ); + } + + sendSample() { + let sampleType = this.$scope.sampleType.selection; + let queryParams; + + if (sampleType.hasCompany) { + queryParams = `${sampleType.code}/${this.clientSample.companyFk}/${this.$stateParams.id}`; + } else { + queryParams = `${sampleType.code}/${this.$stateParams.id}`; + } + + let query = `/mailer/notification/${queryParams}`; + this.$http.get(query).then(res => { + if (res) { + this.vnApp.showSuccess(this.$translate.instant('Notification sent!')); + this.$state.go('client.card.sample.index'); + } + }); + } +} +Controller.$inject = ['$scope', '$state', '$http', 'vnApp', '$translate']; + +ngModule.component('vnClientSampleCreate', { + template: require('./index.html'), + controller: Controller +}); diff --git a/client/client/src/sample/create/locale/es.yml b/client/client/src/sample/create/locale/es.yml new file mode 100644 index 000000000..adeacbf3e --- /dev/null +++ b/client/client/src/sample/create/locale/es.yml @@ -0,0 +1,2 @@ +Choose a sample: Selecciona una plantilla +Choose a company: Selecciona una empresa \ No newline at end of file diff --git a/client/client/src/sample/create/sample-create.spec.js b/client/client/src/sample/create/sample-create.spec.js new file mode 100644 index 000000000..fdee59311 --- /dev/null +++ b/client/client/src/sample/create/sample-create.spec.js @@ -0,0 +1,149 @@ +import './index'; + +fdescribe('Client', () => { + describe('Component vnClientSampleCreate', () => { + let $componentController; + let $scope; + let $httpBackend; + let $state; + let controller; + + beforeEach(() => { + angular.mock.module('client'); + }); + + beforeEach(angular.mock.inject((_$componentController_, _$httpBackend_, $rootScope, _$state_) => { + $componentController = _$componentController_; + $scope = $rootScope.$new(); + $scope.sampleType = {}; + $scope.watcher = { + check: () => {}, + realSubmit: () => { + return { + then: callback => { + callback(); + } + }; + } + }; + $scope.showPreview = { + element: { + querySelector: () => { + return { + innerHTML: () => {} + }; + } + }, + show: () => {} + }; + $state = _$state_; + $state.params.id = 101; + $httpBackend = _$httpBackend_; + $httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({}); + controller = $componentController('vnClientSampleCreate', {$scope: $scope}, {$state: $state}); + })); + + describe('showPreview()', () => { + it(`should perform a query (GET) and open a sample preview`, () => { + spyOn(controller.$scope.showPreview, 'show'); + + controller.$scope.sampleType.selection = { + hasCompany: false, + code: 'MyReport' + }; + + controller.clientSample = { + clientFk: 101, + typeFK: 1 + }; + + let event = {preventDefault: () => {}}; + + $httpBackend.whenGET(`/mailer/notification/MyReport/101/preview`).respond(true); + $httpBackend.expectGET(`/mailer/notification/MyReport/101/preview`); + controller.showPreview(event); + $httpBackend.flush(); + + expect(controller.$scope.showPreview.show).toHaveBeenCalledWith(); + }); + + it(`should perform a query (GET) with companyFk param and open a sample preview`, () => { + spyOn(controller.$scope.showPreview, 'show'); + + controller.$scope.sampleType.selection = { + hasCompany: true, + code: 'MyReport' + }; + + controller.clientSample = { + clientFk: 101, + companyFk: 442, + typeFK: 1 + }; + + let event = {preventDefault: () => {}}; + + $httpBackend.whenGET(`/mailer/notification/MyReport/442/101/preview`).respond(true); + $httpBackend.expectGET(`/mailer/notification/MyReport/442/101/preview`); + controller.showPreview(event); + $httpBackend.flush(); + + expect(controller.$scope.showPreview.show).toHaveBeenCalledWith(); + }); + }); + + describe('onSubmit()', () => { + it(`should call sendSample() method`, () => { + spyOn(controller, 'sendSample'); + controller.onSubmit(); + + expect(controller.sendSample).toHaveBeenCalledWith(); + }); + }); + + describe('sendSample()', () => { + it(`should perform a query (GET) and call go() method`, () => { + spyOn(controller.$state, 'go'); + + controller.$scope.sampleType.selection = { + hasCompany: false, + code: 'MyReport' + }; + + controller.clientSample = { + clientFk: 101, + typeFK: 1 + }; + + $httpBackend.whenGET(`/mailer/notification/MyReport/101`).respond(true); + $httpBackend.expectGET(`/mailer/notification/MyReport/101`); + controller.sendSample(); + $httpBackend.flush(); + + expect(controller.$state.go).toHaveBeenCalledWith('client.card.sample.index'); + }); + + it(`should perform a query (GET) with companyFk param and call go() method`, () => { + spyOn(controller.$state, 'go'); + + controller.$scope.sampleType.selection = { + hasCompany: true, + code: 'MyReport' + }; + + controller.clientSample = { + clientFk: 101, + companyFk: 442, + typeFK: 1 + }; + + $httpBackend.whenGET(`/mailer/notification/MyReport/442/101`).respond(true); + $httpBackend.expectGET(`/mailer/notification/MyReport/442/101`); + controller.sendSample(); + $httpBackend.flush(); + + expect(controller.$state.go).toHaveBeenCalledWith('client.card.sample.index'); + }); + }); + }); +}); diff --git a/client/client/src/sample/create/style.scss b/client/client/src/sample/create/style.scss new file mode 100644 index 000000000..72e588db5 --- /dev/null +++ b/client/client/src/sample/create/style.scss @@ -0,0 +1,12 @@ +vn-client-sample-create { + vn-dialog { + & > div { + padding: 0 !important + } + + tpl-body { + min-width: 800px; + max-height: 700px; + } + } +} \ No newline at end of file diff --git a/client/client/src/sample/index/index.html b/client/client/src/sample/index/index.html new file mode 100644 index 000000000..04e078184 --- /dev/null +++ b/client/client/src/sample/index/index.html @@ -0,0 +1,48 @@ + + + + + + + Samples + + + + + + Sent + Description + Worker + Company + + + + + {{::sample.created | date:'dd/MM/yyyy HH:mm' }} + {{::sample.type.description}} + {{::sample.worker.firstName}} {{::sample.worker.name}} + {{::sample.company.code}} + + + + No results + + + + + + + + + + + \ No newline at end of file diff --git a/client/client/src/sample/index/index.js b/client/client/src/sample/index/index.js new file mode 100644 index 000000000..7fd84f54c --- /dev/null +++ b/client/client/src/sample/index/index.js @@ -0,0 +1,36 @@ +import ngModule from '../../module'; + +class Controller { + constructor($stateParams) { + this.$stateParams = $stateParams; + this.filter = { + include: [ + { + relation: "type", + scope: { + fields: ["code", "description"] + } + }, + { + relation: "worker", + scope: { + fields: ["firstName", "name"] + } + }, + { + relation: "company", + scope: { + fields: ["code"] + } + } + ] + }; + } +} + +Controller.$inject = ['$stateParams']; + +ngModule.component('vnClientSampleIndex', { + template: require('./index.html'), + controller: Controller +}); diff --git a/services/client/common/models/client-sample.js b/services/client/common/models/client-sample.js new file mode 100644 index 000000000..19b72a4d8 --- /dev/null +++ b/services/client/common/models/client-sample.js @@ -0,0 +1,20 @@ +module.exports = Self => { + Self.validatesPresenceOf('typeFk', { + message: 'Sample type cannot be blank' + }); + + Self.observe('before save', async function(ctx) { + let models = Self.app.models; + let data = ctx.instance; + + let sample = await models.Sample.findById(data.typeFk); + + if (sample.hasCompany && !data.companyFk) + throw new Error('Choose a company'); + + let filter = {where: {userFk: ctx.options.accessToken.userId}}; + let worker = await Self.app.models.Worker.findOne(filter); + + data.workerFk = worker.id; + }); +}; diff --git a/services/client/common/models/sample.json b/services/client/common/models/sample.json index 25fa2b18e..b4d49cdab 100644 --- a/services/client/common/models/sample.json +++ b/services/client/common/models/sample.json @@ -20,8 +20,14 @@ }, "isVisible": { "type": "Number" + }, + "hasCompany": { + "type": "Number" } }, + "scope": { + "where": {"isVisible": 1} + }, "acls": [ { "accessType": "READ", diff --git a/services/db/install/changes/1.0.9/04-sample.sql b/services/db/install/changes/1.0.9/04-sample.sql index da1f1e90c..d71216040 100644 --- a/services/db/install/changes/1.0.9/04-sample.sql +++ b/services/db/install/changes/1.0.9/04-sample.sql @@ -1,4 +1,9 @@ USE `vn`; + +ALTER TABLE `vn2008`.`escritos` + ADD COLUMN `hasCompany` VARCHAR(45) NOT NULL DEFAULT 0 AFTER `visible`; + + CREATE OR REPLACE ALGORITHM = UNDEFINED DEFINER = `root`@`%` @@ -8,7 +13,9 @@ VIEW `sample` AS `e`.`id` AS `id`, `e`.`abrev` AS `code`, `e`.`descripcion` AS `description`, - `e`.`visible` AS `isVisible` + `e`.`visible` AS `isVisible`, + `e`.`hasCompany` AS `hasCompany` FROM `vn2008`.`escritos` `e`; +DROP VIEW `vn`.`clientNotificationType`; \ No newline at end of file diff --git a/services/db/install/changes/1.0.9/05-clientSample.sql b/services/db/install/changes/1.0.9/05-clientSample.sql index 8783399f2..26720137b 100644 --- a/services/db/install/changes/1.0.9/05-clientSample.sql +++ b/services/db/install/changes/1.0.9/05-clientSample.sql @@ -15,3 +15,4 @@ VIEW `clientSample` AS FROM `vn2008`.`escritos_det` `e`; +DROP VIEW `vn`.`clientNotification`; \ No newline at end of file diff --git a/services/loopback/common/locale/en.json b/services/loopback/common/locale/en.json index 05ba94b14..8d35e197c 100644 --- a/services/loopback/common/locale/en.json +++ b/services/loopback/common/locale/en.json @@ -22,5 +22,6 @@ "Name cannot be blank": "Name cannot be blank", "Phone cannot be blank": "Phone cannot be blank", "Observation type cannot be blank": "Observation type cannot be blank", - "NO_AGENCY_AVAILABLE": "NO_AGENCY_AVAILABLE" + "NO_AGENCY_AVAILABLE": "NO_AGENCY_AVAILABLE", + "can't be blank": "can't be blank" } \ No newline at end of file diff --git a/services/loopback/common/locale/es.json b/services/loopback/common/locale/es.json index 58fe0f3c1..18745800a 100644 --- a/services/loopback/common/locale/es.json +++ b/services/loopback/common/locale/es.json @@ -27,5 +27,6 @@ "Only manager can change the credit": "Solo el gerente puede cambiar el credito de este cliente", "Name cannot be blank": "El nombre no puede estar en blanco", "Phone cannot be blank": "El teléfono no puede estar en blanco", - "Period cannot be blank": "El periodo no puede estar en blanco" + "Period cannot be blank": "El periodo no puede estar en blanco", + "Choose a company": "Selecciona una empresa" } \ No newline at end of file diff --git a/services/print/application/template/letter-debtor/letter-debtor.js b/services/print/application/template/letter-debtor/letter-debtor.js index 77715f3b7..872a3a676 100644 --- a/services/print/application/template/letter-debtor/letter-debtor.js +++ b/services/print/application/template/letter-debtor/letter-debtor.js @@ -3,7 +3,7 @@ var database = require(path.join(__dirname, '../../database.js')); var format = require(path.join(__dirname, '../../util/format.js')); module.exports = class LetterDebtor { - getData(params, cb) { + async getData(params, cb) { let query = `SELECT c.id clientId, m.code mandateCode, @@ -29,13 +29,18 @@ module.exports = class LetterDebtor { LEFT JOIN country sc ON sc.id = s.countryFk LEFT JOIN province sp ON sp.id = s.provinceFk WHERE c.id = ?`; - database.pool.query(query, [params.clientId], (error, result) => { - if (error || result.length == 0) - return cb(new Error('No template data found')); + try { + let [result] = await database.pool.query(query, [params.clientId]); + + if (!result) + throw new Error('No body data found'); + + Object.assign(this, result); - Object.assign(this, result[0]); cb(); - }); + } catch (e) { + cb(e); + } } // Swift BIC fields diff --git a/services/print/application/template/sepa-core/sepa-core.js b/services/print/application/template/sepa-core/sepa-core.js index 304e327da..512ae8ce3 100644 --- a/services/print/application/template/sepa-core/sepa-core.js +++ b/services/print/application/template/sepa-core/sepa-core.js @@ -3,7 +3,7 @@ var database = require(path.join(__dirname, '../../database.js')); var format = require(path.join(__dirname, '../../util/format.js')); module.exports = class SepaCore { - getData(params, cb) { + async getData(params, cb) { let query = `SELECT c.id clientId, m.code mandateCode, @@ -29,13 +29,14 @@ module.exports = class SepaCore { LEFT JOIN country sc ON sc.id = s.countryFk LEFT JOIN province sp ON sp.id = s.provinceFk WHERE c.id = ?`; - database.pool.query(query, [params.clientId], (error, result) => { - if (error || result.length == 0) - return cb(new Error('No template data found')); - Object.assign(this, result[0]); - cb(); - }); + let [result] = await database.pool.query(query, [params.clientId]); + + if (!result || !result.length) + return cb(new Error('No template data found')); + + Object.assign(this, result[0]); + cb(); } // Swift BIC fields