diff --git a/db/changes/10370-pickles/00-payMethod.sql b/db/changes/10370-pickles/00-payMethod.sql new file mode 100644 index 000000000..ac6429b99 --- /dev/null +++ b/db/changes/10370-pickles/00-payMethod.sql @@ -0,0 +1,4 @@ +ALTER TABLE vn.payMethod CHANGE ibanRequired ibanRequiredForClients tinyint(3) DEFAULT 0 NULL; +ALTER TABLE vn.payMethod ADD ibanRequiredForSuppliers tinyint(3) DEFAULT 0 NULL; +ALTER TABLE vn.payMethod CHANGE ibanRequiredForSuppliers ibanRequiredForSuppliers tinyint(3) DEFAULT 0 NULL AFTER ibanRequiredForClients; +UPDATE vn.payMethod SET ibanRequiredForSuppliers = 1 WHERE code = 'wireTransfer'; \ No newline at end of file diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 28b8e9181..10462d5ef 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -217,14 +217,14 @@ UPDATE `vn`.`agencyMode` SET `web` = 1, `reportMail` = 'no-reply@gothamcity.com' UPDATE `vn`.`agencyMode` SET `code` = 'refund' WHERE `id` = 23; -INSERT INTO `vn`.`payMethod`(`id`,`code`, `name`, `graceDays`, `outstandingDebt`, `ibanRequired`) +INSERT INTO `vn`.`payMethod`(`id`,`code`, `name`, `graceDays`, `outstandingDebt`, `ibanRequiredForClients`, `ibanRequiredForSuppliers`) VALUES - (1, NULL, 'PayMethod one', 0, 001, 0), - (2, NULL, 'PayMethod two', 10, 001, 0), - (3, 'compensation', 'PayMethod three', 0, 001, 0), - (4, NULL, 'PayMethod with IBAN', 0, 001, 1), - (5, NULL, 'PayMethod five', 10, 001, 0), - (8,'wireTransfer', 'WireTransfer', 5, 001, 1); + (1, NULL, 'PayMethod one', 0, 001, 0, 0), + (2, NULL, 'PayMethod two', 10, 001, 0, 0), + (3, 'compensation', 'PayMethod three', 0, 001, 0, 0), + (4, NULL, 'PayMethod with IBAN', 0, 001, 1, 0), + (5, NULL, 'PayMethod five', 10, 001, 0, 0), + (8,'wireTransfer', 'WireTransfer', 5, 001, 1, 1); INSERT INTO `vn`.`payDem`(`id`, `payDem`) VALUES diff --git a/db/dump/structure.sql b/db/dump/structure.sql index 3ab1d5608..68f320ec6 100644 --- a/db/dump/structure.sql +++ b/db/dump/structure.sql @@ -33928,7 +33928,8 @@ CREATE TABLE `payMethod` ( `solution` varchar(1) COLLATE utf8_unicode_ci DEFAULT NULL, `outstandingDebt` tinyint(3) unsigned zerofill NOT NULL DEFAULT '000', `graceDays` int(11) unsigned NOT NULL DEFAULT '0', - `ibanRequired` tinyint(3) DEFAULT '0', + `ibanRequiredForClients` tinyint(3) DEFAULT '0', + `ibanRequiredForSuppliers` tinyint(3) DEFAULT '0', `isNotified` tinyint(3) NOT NULL DEFAULT '1', PRIMARY KEY (`id`) ) ENGINE=InnoDBDEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index d4d5d33aa..d3e4da99a 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -119,6 +119,7 @@ export default { name: 'vn-client-create vn-textfield[ng-model="$ctrl.client.name"]', taxNumber: 'vn-client-create vn-textfield[ng-model="$ctrl.client.fi"]', socialName: 'vn-client-create vn-textfield[ng-model="$ctrl.client.socialName"]', + businessType: 'vn-client-create vn-autocomplete[ng-model="$ctrl.client.businessTypeFk"]', street: 'vn-client-create vn-textfield[ng-model="$ctrl.client.street"]', addPostCode: 'vn-client-create vn-datalist[ng-model="$ctrl.client.postcode"] vn-icon-button[icon="add_circle"]', addProvince: 'vn-autocomplete[ng-model="$ctrl.location.provinceFk"] vn-icon-button[icon="add_circle"]', diff --git a/e2e/paths/02-client/01_create_client.spec.js b/e2e/paths/02-client/01_create_client.spec.js index 5860eca49..37b39798d 100644 --- a/e2e/paths/02-client/01_create_client.spec.js +++ b/e2e/paths/02-client/01_create_client.spec.js @@ -27,16 +27,19 @@ describe('Client create path', () => { await page.waitForState('client.create'); }); - it('should receive an error when clicking the create button having name and Business name fields empty', async() => { - await page.write(selectors.createClientView.taxNumber, '74451390E'); - await page.write(selectors.createClientView.userName, 'CaptainMarvel'); - await page.write(selectors.createClientView.email, 'CarolDanvers@verdnatura.es'); - await page.autocompleteSearch(selectors.createClientView.salesPerson, 'salesPerson'); - await page.waitToClick(selectors.createClientView.createButton); - const message = await page.waitForSnackbar(); + it('should receive an error when clicking the create button having name and Business name fields empty', + async() => { + await page.write(selectors.createClientView.taxNumber, '74451390E'); + await page.write(selectors.createClientView.userName, 'CaptainMarvel'); + await page.write(selectors.createClientView.email, 'CarolDanvers@verdnatura.es'); + await page.autocompleteSearch(selectors.createClientView.salesPerson, 'salesPerson'); + await page.autocompleteSearch(selectors.createClientView.businessType, 'florist'); + await page.waitToClick(selectors.createClientView.createButton); + const message = await page.waitForSnackbar(); - expect(message.text).toContain('Some fields are invalid'); - }); + expect(message.text).toContain('Some fields are invalid'); + } + ); it(`should create a new province`, async() => { await page.waitToClick(selectors.createClientView.addPostCode); @@ -80,9 +83,18 @@ describe('Client create path', () => { expect(message.text).toContain('Some fields are invalid'); }); - it(`should attempt to create a new user with all it's data but wrong postal code`, async() => { + it(`should attempt to create a new user with all it's data but wrong business type`, async() => { await page.clearInput(selectors.createClientView.email); await page.write(selectors.createClientView.email, 'CarolDanvers@verdnatura.es'); + await page.clearInput(selectors.createClientView.businessType); + await page.waitToClick(selectors.createClientView.createButton); + const message = await page.waitForSnackbar(); + + expect(message.text).toContain('Some fields are invalid'); + }); + + it(`should attempt to create a new user with all it's data but wrong postal code`, async() => { + await page.autocompleteSearch(selectors.createClientView.businessType, 'florist'); await page.clearInput(selectors.createClientView.postcode); await page.write(selectors.createClientView.postcode, '479999'); await page.waitToClick(selectors.createClientView.createButton); diff --git a/loopback/locale/en.json b/loopback/locale/en.json index 8890e911f..271c3fd4f 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -117,5 +117,6 @@ "INACTIVE_PROVIDER": "Inactive provider", "reference duplicated": "reference duplicated", "The PDF document does not exists": "The PDF document does not exists. Try regenerating it from 'Regenerate invoice PDF' option", - "This item is not available": "This item is not available" + "This item is not available": "This item is not available", + "Deny buy request": "Purchase request for ticket id [{{ticketId}}]({{{url}}}) has been rejected. Reason: {{observation}}" } \ No newline at end of file diff --git a/loopback/locale/es.json b/loopback/locale/es.json index cdf15c674..afa349684 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -133,6 +133,7 @@ "reserved": "reservado", "Changed sale reserved state": "He cambiado el estado reservado de las siguientes lineas al ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}", "Bought units from buy request": "Se ha comprado {{quantity}} unidades de [{{itemId}} {{concept}}]({{{urlItem}}}) para el ticket id [{{ticketId}}]({{{url}}})", + "Deny buy request":"Se ha rechazado la petición de compra para el ticket id [{{ticketId}}]({{{url}}}). Motivo: {{observation}}", "MESSAGE_INSURANCE_CHANGE": "He cambiado el crédito asegurado del cliente [{{clientName}} ({{clientId}})]({{{url}}}) a *{{credit}} €*", "Changed client paymethod": "He cambiado la forma de pago del cliente [{{clientName}} ({{clientId}})]({{{url}}})", "Sent units from ticket": "Envio *{{quantity}}* unidades de [{{concept}} ({{itemId}})]({{{itemUrl}}}) a *\"{{nickname}}\"* provenientes del ticket id [{{ticketId}}]({{{ticketUrl}}})", diff --git a/modules/client/back/methods/client/createWithUser.js b/modules/client/back/methods/client/createWithUser.js index f32979d52..cb97d5d59 100644 --- a/modules/client/back/methods/client/createWithUser.js +++ b/modules/client/back/methods/client/createWithUser.js @@ -50,7 +50,8 @@ module.exports = function(Self) { city: data.city, provinceFk: data.provinceFk, countryFk: data.countryFk, - isEqualizated: data.isEqualizated + isEqualizated: data.isEqualizated, + businessTypeFk: data.businessTypeFk }, myOptions); const address = await models.Address.create({ diff --git a/modules/client/back/methods/client/specs/createWithUser.spec.js b/modules/client/back/methods/client/specs/createWithUser.spec.js index f85ad1929..4c827c745 100644 --- a/modules/client/back/methods/client/specs/createWithUser.spec.js +++ b/modules/client/back/methods/client/specs/createWithUser.spec.js @@ -8,7 +8,8 @@ describe('Client Create', () => { name: 'Wade', socialName: 'Deadpool Marvel', street: 'Wall Street', - city: 'New York' + city: 'New York', + businessTypeFk: 'florist' }; it(`should not find Deadpool as he's not created yet`, async() => { @@ -45,6 +46,7 @@ describe('Client Create', () => { expect(client.email).toEqual(newAccount.email); expect(client.fi).toEqual(newAccount.fi); expect(client.socialName).toEqual(newAccount.socialName); + expect(client.businessTypeFk).toEqual(newAccount.businessTypeFk); await tx.rollback(); } catch (e) { diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js index 6519cb979..4cac16358 100644 --- a/modules/client/back/models/client.js +++ b/modules/client/back/models/client.js @@ -129,7 +129,7 @@ module.exports = Self => { function hasIban(err, done) { Self.app.models.PayMethod.findById(this.payMethodFk, (_, instance) => { - if (instance && instance.ibanRequired && !this.iban) + if (instance && instance.ibanRequiredForClients && !this.iban) err(); done(); }); diff --git a/modules/client/back/models/client.json b/modules/client/back/models/client.json index 1cf539439..76e1bffdb 100644 --- a/modules/client/back/models/client.json +++ b/modules/client/back/models/client.json @@ -130,6 +130,13 @@ "mysql": { "columnName": "transactionTypeSageFk" } + }, + "businessTypeFk": { + "type": "string", + "mysql": { + "columnName": "businessTypeFk" + }, + "required": true } }, "relations": { diff --git a/modules/client/back/models/pay-method.json b/modules/client/back/models/pay-method.json index a025bee47..0666be7a5 100644 --- a/modules/client/back/models/pay-method.json +++ b/modules/client/back/models/pay-method.json @@ -25,7 +25,10 @@ "outstandingDebt": { "type": "Number" }, - "ibanRequired": { + "ibanRequiredForClients": { + "type": "boolean" + }, + "ibanRequiredForSuppliers": { "type": "boolean" } } diff --git a/modules/client/front/billing-data/index.html b/modules/client/front/billing-data/index.html index ff2e2f157..8c7c6cfe9 100644 --- a/modules/client/front/billing-data/index.html +++ b/modules/client/front/billing-data/index.html @@ -19,7 +19,7 @@ vn-acl="salesAssistant" ng-model="$ctrl.client.payMethodFk" data="paymethods" - fields="['ibanRequired']" + fields="['ibanRequiredForClients']" initial-data="$ctrl.client.payMethod"> - - + + + + + { { relation: 'client', scope: { - fields: ['id', 'socialName'] + fields: ['id', 'socialName', 'email'] } } ] diff --git a/modules/invoiceOut/front/descriptor-menu/index.html b/modules/invoiceOut/front/descriptor-menu/index.html new file mode 100644 index 000000000..dbfd5fe82 --- /dev/null +++ b/modules/invoiceOut/front/descriptor-menu/index.html @@ -0,0 +1,139 @@ + + + + + + + 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 CIES letter + + + + + + + + + + + + + + + + + + Are you sure you want to send it? + + + + + + + + + + + + + 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 new file mode 100644 index 000000000..b6e7e0261 --- /dev/null +++ b/modules/invoiceOut/front/descriptor-menu/index.js @@ -0,0 +1,121 @@ +import ngModule from '../module'; +import Section from 'salix/components/section'; +import './style.scss'; + +class Controller extends Section { + constructor($element, $, vnReport, vnEmail) { + super($element, $); + this.vnReport = vnReport; + this.vnEmail = vnEmail; + } + + get invoiceOut() { + return this._invoiceOut; + } + + set invoiceOut(value) { + this._invoiceOut = value; + if (value) + this.id = value.id; + } + + loadData() { + const filter = { + include: [ + { + relation: 'company', + scope: { + fields: ['id', 'code'] + } + }, { + relation: 'client', + scope: { + fields: ['id', 'name', 'email'] + } + } + ] + }; + return this.$http.get(`InvoiceOuts/${this.invoiceOut.id}`, {filter}) + .then(res => this.invoiceOut = res.data); + } + reload() { + return this.loadData().then(() => { + if (this.parentReload) + this.parentReload(); + }); + } + + cardReload() { + // Prevents error when not defined + } + + deleteInvoiceOut() { + return this.$http.post(`InvoiceOuts/${this.invoiceOut.id}/delete`) + .then(() => this.$state.go('invoiceOut.index')) + .then(() => this.$state.reload()) + .then(() => this.vnApp.showSuccess(this.$t('InvoiceOut deleted'))); + } + + bookInvoiceOut() { + return this.$http.post(`InvoiceOuts/${this.invoiceOut.ref}/book`) + .then(() => this.$state.reload()) + .then(() => this.vnApp.showSuccess(this.$t('InvoiceOut booked'))); + } + + createPdfInvoice() { + return this.$http.post(`InvoiceOuts/${this.id}/createPdf`) + .then(() => this.reload()) + .then(() => { + const snackbarMessage = this.$t( + `The invoice PDF document has been regenerated`); + this.vnApp.showSuccess(snackbarMessage); + }); + } + + showCsvInvoice() { + this.vnReport.showCsv('invoice', { + recipientId: this.invoiceOut.client.id, + invoiceId: this.id + }); + } + + sendPdfInvoice($data) { + if (!$data.email) + return this.vnApp.showError(this.$t(`The email can't be empty`)); + + return this.vnEmail.send('invoice', { + recipientId: this.invoiceOut.client.id, + recipient: $data.email, + invoiceId: this.id + }); + } + + sendCsvInvoice($data) { + if (!$data.email) + return this.vnApp.showError(this.$t(`The email can't be empty`)); + + return this.vnEmail.sendCsv('invoice', { + recipientId: this.invoiceOut.client.id, + recipient: $data.email, + invoiceId: this.id + }); + } + + showExportationLetter() { + this.vnReport.show('exportation', { + recipientId: this.invoiceOut.client.id, + invoiceId: this.id + }); + } +} + +Controller.$inject = ['$element', '$scope', 'vnReport', 'vnEmail']; + +ngModule.vnComponent('vnInvoiceOutDescriptorMenu', { + template: require('./index.html'), + controller: Controller, + bindings: { + invoiceOut: '<', + parentReload: '&' + } +}); diff --git a/modules/invoiceOut/front/descriptor-menu/index.spec.js b/modules/invoiceOut/front/descriptor-menu/index.spec.js new file mode 100644 index 000000000..19822f094 --- /dev/null +++ b/modules/invoiceOut/front/descriptor-menu/index.spec.js @@ -0,0 +1,96 @@ +import './index'; + +describe('vnInvoiceOutDescriptorMenu', () => { + let controller; + let $httpBackend; + let $httpParamSerializer; + const invoiceOut = { + id: 1, + client: {id: 1101} + }; + + beforeEach(ngModule('invoiceOut')); + + beforeEach(inject(($componentController, _$httpParamSerializer_, _$httpBackend_) => { + $httpBackend = _$httpBackend_; + $httpParamSerializer = _$httpParamSerializer_; + controller = $componentController('vnInvoiceOutDescriptorMenu', {$element: null}); + })); + + describe('createPdfInvoice()', () => { + it('should make a query to the createPdf() endpoint and show a success snackbar', () => { + jest.spyOn(controller.vnApp, 'showSuccess'); + + controller.invoiceOut = invoiceOut; + + $httpBackend.whenGET(`InvoiceOuts/${invoiceOut.id}`).respond(); + $httpBackend.expectPOST(`InvoiceOuts/${invoiceOut.id}/createPdf`).respond(); + controller.createPdfInvoice(); + $httpBackend.flush(); + + expect(controller.vnApp.showSuccess).toHaveBeenCalled(); + }); + }); + + describe('showCsvInvoice()', () => { + it('should make a query to the csv invoice download endpoint and show a message snackbar', () => { + jest.spyOn(window, 'open').mockReturnThis(); + + controller.invoiceOut = invoiceOut; + + const expectedParams = { + invoiceId: invoiceOut.id, + recipientId: invoiceOut.client.id + }; + const serializedParams = $httpParamSerializer(expectedParams); + const expectedPath = `api/csv/invoice/download?${serializedParams}`; + controller.showCsvInvoice(); + + expect(window.open).toHaveBeenCalledWith(expectedPath); + }); + }); + + describe('sendPdfInvoice()', () => { + it('should make a query to the email invoice endpoint and show a message snackbar', () => { + jest.spyOn(controller.vnApp, 'showMessage'); + + controller.invoiceOut = invoiceOut; + + const $data = {email: 'brucebanner@gothamcity.com'}; + const expectedParams = { + invoiceId: invoiceOut.id, + recipient: $data.email, + recipientId: invoiceOut.client.id + }; + const serializedParams = $httpParamSerializer(expectedParams); + + $httpBackend.expectGET(`email/invoice?${serializedParams}`).respond(); + controller.sendPdfInvoice($data); + $httpBackend.flush(); + + expect(controller.vnApp.showMessage).toHaveBeenCalled(); + }); + }); + + describe('sendCsvInvoice()', () => { + it('should make a query to the csv invoice send endpoint and show a message snackbar', () => { + jest.spyOn(controller.vnApp, 'showMessage'); + + controller.invoiceOut = invoiceOut; + + const $data = {email: 'brucebanner@gothamcity.com'}; + const expectedParams = { + invoiceId: invoiceOut.id, + recipient: $data.email, + recipientId: invoiceOut.client.id + }; + const serializedParams = $httpParamSerializer(expectedParams); + + $httpBackend.expectGET(`csv/invoice/send?${serializedParams}`).respond(); + controller.sendCsvInvoice($data); + $httpBackend.flush(); + + expect(controller.vnApp.showMessage).toHaveBeenCalled(); + }); + }); +}); diff --git a/modules/invoiceOut/front/descriptor-menu/locale/es.yml b/modules/invoiceOut/front/descriptor-menu/locale/es.yml new file mode 100644 index 000000000..01e58633b --- /dev/null +++ b/modules/invoiceOut/front/descriptor-menu/locale/es.yml @@ -0,0 +1,17 @@ +Show invoice...: Ver factura... +Send invoice...: Enviar factura... +Send PDF invoice: Enviar factura en PDF +Send CSV invoice: Enviar factura en CSV +Delete Invoice: Eliminar factura +Clone Invoice: Clonar factura +Book invoice: Asentar factura +Generate PDF invoice: Generar PDF factura +Show CIES letter: Ver carta CIES +InvoiceOut deleted: Factura eliminada +Are you sure you want to delete this invoice?: Estas seguro de eliminar esta factura? +Are you sure you want to clone this invoice?: Estas seguro de clonar esta factura? +InvoiceOut booked: Factura asentada +Are you sure you want to book this invoice?: Estas seguro de querer asentar esta factura? +Regenerate PDF invoice: Regenerar PDF factura +The invoice PDF document has been regenerated: El documento PDF de la factura ha sido regenerado +The email can't be empty: El correo no puede estar vacío \ No newline at end of file diff --git a/modules/invoiceOut/front/descriptor-menu/style.scss b/modules/invoiceOut/front/descriptor-menu/style.scss new file mode 100644 index 000000000..b68301961 --- /dev/null +++ b/modules/invoiceOut/front/descriptor-menu/style.scss @@ -0,0 +1,24 @@ +@import "./effects"; +@import "variables"; + +vn-invoice-out-descriptor-menu { + & > vn-icon-button[icon="more_vert"] { + display: flex; + min-width: 45px; + height: 45px; + box-sizing: border-box; + align-items: center; + justify-content: center; + } + & > vn-icon-button[icon="more_vert"] { + @extend %clickable; + color: inherit; + + & > vn-icon { + padding: 10px; + } + vn-icon { + font-size: 1.75rem; + } + } +} \ No newline at end of file diff --git a/modules/invoiceOut/front/descriptor/index.html b/modules/invoiceOut/front/descriptor/index.html index d5522f6a9..135eae0e1 100644 --- a/modules/invoiceOut/front/descriptor/index.html +++ b/modules/invoiceOut/front/descriptor/index.html @@ -1,81 +1,12 @@ - - - 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 CIES letter - - + + +
-
- - - - - - - - - - - - - - - Are you sure you want to send it? - - - - - - - - - - - - - Are you sure you want to send it? - - - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/modules/invoiceOut/front/descriptor/index.js b/modules/invoiceOut/front/descriptor/index.js index f4f8c07bd..7eeb85ea6 100644 --- a/modules/invoiceOut/front/descriptor/index.js +++ b/modules/invoiceOut/front/descriptor/index.js @@ -41,70 +41,6 @@ class Controller extends Descriptor { return this.getData(`InvoiceOuts/${this.id}`, {filter}) .then(res => this.entity = res.data); } - - reload() { - return this.loadData().then(() => { - if (this.cardReload) - this.cardReload(); - }); - } - - cardReload() { - // Prevents error when not defined - } - - deleteInvoiceOut() { - return this.$http.post(`InvoiceOuts/${this.id}/delete`) - .then(() => this.$state.go('invoiceOut.index')) - .then(() => this.vnApp.showSuccess(this.$t('InvoiceOut deleted'))); - } - - bookInvoiceOut() { - return this.$http.post(`InvoiceOuts/${this.invoiceOut.ref}/book`) - .then(() => this.$state.reload()) - .then(() => this.vnApp.showSuccess(this.$t('InvoiceOut booked'))); - } - - createPdfInvoice() { - const invoiceId = this.invoiceOut.id; - return this.$http.post(`InvoiceOuts/${invoiceId}/createPdf`) - .then(() => this.reload()) - .then(() => { - const snackbarMessage = this.$t( - `The invoice PDF document has been regenerated`); - this.vnApp.showSuccess(snackbarMessage); - }); - } - - showCsvInvoice() { - this.vnReport.showCsv('invoice', { - recipientId: this.invoiceOut.client.id, - invoiceId: this.id, - }); - } - - sendPdfInvoice($data) { - return this.vnEmail.send('invoice', { - recipientId: this.invoiceOut.client.id, - recipient: $data.email, - invoiceId: this.id - }); - } - - sendCsvInvoice($data) { - return this.vnEmail.sendCsv('invoice', { - recipientId: this.invoiceOut.client.id, - recipient: $data.email, - invoiceId: this.id - }); - } - - showExportationLetter() { - this.vnReport.show('exportation', { - recipientId: this.invoiceOut.client.id, - invoiceId: this.id, - }); - } } ngModule.vnComponent('vnInvoiceOutDescriptor', { @@ -112,6 +48,5 @@ ngModule.vnComponent('vnInvoiceOutDescriptor', { controller: Controller, bindings: { invoiceOut: '<', - cardReload: '&' } }); diff --git a/modules/invoiceOut/front/descriptor/index.spec.js b/modules/invoiceOut/front/descriptor/index.spec.js index 12430d44d..987763b0a 100644 --- a/modules/invoiceOut/front/descriptor/index.spec.js +++ b/modules/invoiceOut/front/descriptor/index.spec.js @@ -3,17 +3,11 @@ import './index'; describe('vnInvoiceOutDescriptor', () => { let controller; let $httpBackend; - let $httpParamSerializer; - const invoiceOut = { - id: 1, - client: {id: 1101} - }; beforeEach(ngModule('invoiceOut')); - beforeEach(inject(($componentController, _$httpParamSerializer_, _$httpBackend_) => { + beforeEach(inject(($componentController, _$httpBackend_) => { $httpBackend = _$httpBackend_; - $httpParamSerializer = _$httpParamSerializer_; controller = $componentController('vnInvoiceOutDescriptor', {$element: null}); })); @@ -29,81 +23,4 @@ describe('vnInvoiceOutDescriptor', () => { expect(controller.invoiceOut).toEqual(response); }); }); - - describe('createPdfInvoice()', () => { - it('should make a query to the createPdf() endpoint and show a success snackbar', () => { - jest.spyOn(controller.vnApp, 'showSuccess'); - - controller.invoiceOut = invoiceOut; - - $httpBackend.whenGET(`InvoiceOuts/${invoiceOut.id}`).respond(); - $httpBackend.expectPOST(`InvoiceOuts/${invoiceOut.id}/createPdf`).respond(); - controller.createPdfInvoice(); - $httpBackend.flush(); - - expect(controller.vnApp.showSuccess).toHaveBeenCalled(); - }); - }); - - describe('showCsvInvoice()', () => { - it('should make a query to the csv invoice download endpoint and show a message snackbar', () => { - jest.spyOn(window, 'open').mockReturnThis(); - - controller.invoiceOut = invoiceOut; - - const expectedParams = { - invoiceId: invoiceOut.id, - recipientId: invoiceOut.client.id - }; - const serializedParams = $httpParamSerializer(expectedParams); - const expectedPath = `api/csv/invoice/download?${serializedParams}`; - controller.showCsvInvoice(); - - expect(window.open).toHaveBeenCalledWith(expectedPath); - }); - }); - - describe('sendPdfInvoice()', () => { - it('should make a query to the email invoice endpoint and show a message snackbar', () => { - jest.spyOn(controller.vnApp, 'showMessage'); - - controller.invoiceOut = invoiceOut; - - const $data = {email: 'brucebanner@gothamcity.com'}; - const expectedParams = { - invoiceId: invoiceOut.id, - recipient: $data.email, - recipientId: invoiceOut.client.id - }; - const serializedParams = $httpParamSerializer(expectedParams); - - $httpBackend.expectGET(`email/invoice?${serializedParams}`).respond(); - controller.sendPdfInvoice($data); - $httpBackend.flush(); - - expect(controller.vnApp.showMessage).toHaveBeenCalled(); - }); - }); - - describe('sendCsvInvoice()', () => { - it('should make a query to the csv invoice send endpoint and show a message snackbar', () => { - jest.spyOn(controller.vnApp, 'showMessage'); - - controller.invoiceOut = invoiceOut; - - const $data = {email: 'brucebanner@gothamcity.com'}; - const expectedParams = { - invoiceId: invoiceOut.id, - recipient: $data.email, - recipientId: invoiceOut.client.id - }; - const serializedParams = $httpParamSerializer(expectedParams); - - $httpBackend.expectGET(`csv/invoice/send?${serializedParams}`).respond(); - controller.sendCsvInvoice($data); - $httpBackend.flush(); - - expect(controller.vnApp.showMessage).toHaveBeenCalled(); - }); - }); }); diff --git a/modules/invoiceOut/front/descriptor/locale/es.yml b/modules/invoiceOut/front/descriptor/locale/es.yml index 8a4a09db1..0e88a7dc7 100644 --- a/modules/invoiceOut/front/descriptor/locale/es.yml +++ b/modules/invoiceOut/front/descriptor/locale/es.yml @@ -1,20 +1,2 @@ -Volume exceded: Volumen excedido -Volume: Volumen Client card: Ficha del cliente -Invoice ticket list: Listado de tickets de la factura -Show invoice...: Ver factura... -Send invoice...: Enviar factura... -Send PDF invoice: Enviar factura en PDF -Send CSV invoice: Enviar factura en CSV -Delete Invoice: Eliminar factura -Clone Invoice: Clonar factura -Book invoice: Asentar factura -Generate PDF invoice: Generar PDF factura -Show CIES letter: Ver carta CIES -InvoiceOut deleted: Factura eliminada -Are you sure you want to delete this invoice?: Estas seguro de eliminar esta factura? -Are you sure you want to clone this invoice?: Estas seguro de clonar esta factura? -InvoiceOut booked: Factura asentada -Are you sure you want to book this invoice?: Estas seguro de querer asentar esta factura? -Regenerate PDF invoice: Regenerar PDF factura -The invoice PDF document has been regenerated: El documento PDF de la factura ha sido regenerado \ No newline at end of file +Invoice ticket list: Listado de tickets de la factura \ No newline at end of file diff --git a/modules/invoiceOut/front/index.js b/modules/invoiceOut/front/index.js index 3bb6d54d2..0307b2b4b 100644 --- a/modules/invoiceOut/front/index.js +++ b/modules/invoiceOut/front/index.js @@ -7,5 +7,6 @@ import './summary'; import './card'; import './descriptor'; import './descriptor-popover'; +import './descriptor-menu'; import './index/manual'; import './index/global-invoicing'; diff --git a/modules/invoiceOut/front/summary/index.html b/modules/invoiceOut/front/summary/index.html index 6a117052e..a0d050efd 100644 --- a/modules/invoiceOut/front/summary/index.html +++ b/modules/invoiceOut/front/summary/index.html @@ -13,6 +13,10 @@ {{$ctrl.summary.invoiceOut.ref}} - {{$ctrl.summary.invoiceOut.client.socialName}} + diff --git a/modules/item/front/diary/index.html b/modules/item/front/diary/index.html index 2f5bce197..0f00f5854 100644 --- a/modules/item/front/diary/index.html +++ b/modules/item/front/diary/index.html @@ -50,7 +50,7 @@ on-last="$ctrl.scrollToLine(sale.lastPreparedLineFk)" ng-attr-id="vnItemDiary-{{::sale.lineFk}}"> - + diff --git a/modules/supplier/back/models/specs/supplier.spec.js b/modules/supplier/back/models/specs/supplier.spec.js index c3c99e676..27bd873ad 100644 --- a/modules/supplier/back/models/specs/supplier.spec.js +++ b/modules/supplier/back/models/specs/supplier.spec.js @@ -1,12 +1,13 @@ -const app = require('vn-loopback/server/server'); +const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('loopback model Supplier', () => { let supplierOne; let supplierTwo; beforeAll(async() => { - supplierOne = await app.models.Supplier.findById(1); - supplierTwo = await app.models.Supplier.findById(442); + supplierOne = await models.Supplier.findById(1); + supplierTwo = await models.Supplier.findById(442); }); afterAll(async() => { @@ -18,9 +19,9 @@ describe('loopback model Supplier', () => { it('should throw an error when attempting to set an invalid payMethod id in the supplier', async() => { let error; const expectedError = 'You can not select this payment method without a registered bankery account'; - const supplier = await app.models.Supplier.findById(1); + const supplier = await models.Supplier.findById(1); - await supplier.updateAttribute('payMethodFk', 4) + await supplier.updateAttribute('payMethodFk', 8) .catch(e => { error = e; @@ -31,14 +32,27 @@ describe('loopback model Supplier', () => { }); it('should not throw if the payMethod id is valid', async() => { + const activeCtx = { + accessToken: {userId: 9}, + http: { + req: { + headers: {origin: 'http://localhost'} + } + } + }; + + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + let error; - const supplier = await app.models.Supplier.findById(442); + const supplier = await models.Supplier.findById(442); await supplier.updateAttribute('payMethodFk', 4) .catch(e => { error = e; }); - expect(error).toBeDefined(); + expect(error).not.toBeDefined(); }); }); }); diff --git a/modules/supplier/back/models/supplier-log.json b/modules/supplier/back/models/supplier-log.json index 9b66bdf74..7c07fa9d4 100644 --- a/modules/supplier/back/models/supplier-log.json +++ b/modules/supplier/back/models/supplier-log.json @@ -9,40 +9,40 @@ "properties": { "id": { "id": true, - "type": "Number", + "type": "number", "forceId": false }, "originFk": { - "type": "Number", + "type": "number", "required": true }, "userFk": { - "type": "Number" + "type": "number" }, "action": { - "type": "String", + "type": "string", "required": true }, "changedModel": { - "type": "String" + "type": "string" }, "oldInstance": { - "type": "Object" + "type": "object" }, "newInstance": { - "type": "Object" + "type": "object" }, "creationDate": { - "type": "Date" + "type": "date" }, "changedModelId": { - "type": "String" + "type": "string" }, "changedModelValue": { - "type": "String" + "type": "string" }, "description": { - "type": "String" + "type": "string" } }, "relations": { diff --git a/modules/supplier/back/models/supplier.js b/modules/supplier/back/models/supplier.js index a95df9f20..2d1c6ac28 100644 --- a/modules/supplier/back/models/supplier.js +++ b/modules/supplier/back/models/supplier.js @@ -80,7 +80,7 @@ module.exports = Self => { const supplierAccount = await Self.app.models.SupplierAccount.findOne({where: {supplierFk: this.id}}); const hasIban = supplierAccount && supplierAccount.iban; - if (payMethod && payMethod.ibanRequired && !hasIban) + if (payMethod && payMethod.ibanRequiredForSuppliers && !hasIban) err(); done(); diff --git a/modules/supplier/front/billing-data/index.html b/modules/supplier/front/billing-data/index.html index 12d3b84b3..c1c57e135 100644 --- a/modules/supplier/front/billing-data/index.html +++ b/modules/supplier/front/billing-data/index.html @@ -24,7 +24,7 @@ vn-acl="salesAssistant" ng-model="$ctrl.supplier.payMethodFk" data="paymethods" - fields="['ibanRequired']" + fields="['ibanRequiredForSuppliers']" initial-data="$ctrl.supplier.payMethod"> { }); Self.deny = async(ctx, options) => { + const models = Self.app.models; + const $t = ctx.req.__; // $translate const myOptions = {}; let tx; @@ -48,6 +50,17 @@ module.exports = Self => { const request = await Self.app.models.TicketRequest.findById(ctx.args.id, null, myOptions); await request.updateAttributes(params, myOptions); + const origin = ctx.req.headers.origin; + const requesterId = request.requesterFk; + + const message = $t('Deny buy request', { + ticketId: request.ticketFk, + url: `${origin}/#!/ticket/${request.ticketFk}/request/index`, + observation: params.response + }); + + await models.Chat.sendCheckingPresence(ctx, requesterId, message, myOptions); + if (tx) await tx.commit(); return request; diff --git a/modules/ticket/back/methods/ticket-request/specs/deny.spec.js b/modules/ticket/back/methods/ticket-request/specs/deny.spec.js index 523c5f065..95fd0e84d 100644 --- a/modules/ticket/back/methods/ticket-request/specs/deny.spec.js +++ b/modules/ticket/back/methods/ticket-request/specs/deny.spec.js @@ -1,13 +1,23 @@ const models = require('vn-loopback/server/server').models; describe('ticket-request deny()', () => { - it('should return the dinied ticket request', async() => { + it('should return the denied ticket request', async() => { const tx = await models.TicketRequest.beginTransaction({}); try { const options = {transaction: tx}; - const ctx = {req: {accessToken: {userId: 9}}, args: {id: 4, observation: 'my observation'}}; + const ctx = { + req: { + accessToken: {userId: 9}, + headers: {origin: 'http://localhost'} + }, + args: {id: 4, observation: 'my observation'}, + }; + + ctx.req.__ = value => { + return value; + }; const result = await models.TicketRequest.deny(ctx, options); diff --git a/modules/ticket/front/request/index/index.html b/modules/ticket/front/request/index/index.html index 39a290d8c..054f0c76a 100644 --- a/modules/ticket/front/request/index/index.html +++ b/modules/ticket/front/request/index/index.html @@ -25,7 +25,7 @@ Quantity Price Item id - Ok + State @@ -78,13 +78,9 @@ {{::request.saleFk | zeroFill:6}} - - - + + {{$ctrl.getRequestState(request.isOk)}} - + diff --git a/modules/ticket/front/request/index/locale/es.yml b/modules/ticket/front/request/index/locale/es.yml index 1adcbad49..871c8bf0b 100644 --- a/modules/ticket/front/request/index/locale/es.yml +++ b/modules/ticket/front/request/index/locale/es.yml @@ -4,4 +4,7 @@ Remove request: Eliminar petición New request: Crear petición Sale id: Id linea Requester: Solicitante -New purchase request: Nueva petición de compra \ No newline at end of file +New purchase request: Nueva petición de compra +Denied: Denegada +Acepted: Aceptada +New: Nueva