updated e2e
gitea/salix/1959-client_fiscal_data_check_phone This commit looks good Details

This commit is contained in:
Joan Sanchez 2020-02-04 11:25:15 +01:00
parent b743938fee
commit 5b0bb5dc73
12 changed files with 275 additions and 142 deletions

View File

@ -63,6 +63,7 @@ export default {
fiscalIdInput: 'vn-client-fiscal-data [ng-model="$ctrl.client.fi"]', fiscalIdInput: 'vn-client-fiscal-data [ng-model="$ctrl.client.fi"]',
equalizationTaxCheckbox: 'vn-check[ng-model="$ctrl.client.isEqualizated"]', equalizationTaxCheckbox: 'vn-check[ng-model="$ctrl.client.isEqualizated"]',
acceptPropagationButton: '.vn-confirm.shown button[response=accept]', acceptPropagationButton: '.vn-confirm.shown button[response=accept]',
acceptDuplicationButton: '.vn-confirm.shown button[response=accept]',
addressInput: 'vn-client-fiscal-data [ng-model="$ctrl.client.street"]', addressInput: 'vn-client-fiscal-data [ng-model="$ctrl.client.street"]',
postcodeInput: 'vn-client-fiscal-data [ng-model="$ctrl.client.postcode"]', postcodeInput: 'vn-client-fiscal-data [ng-model="$ctrl.client.postcode"]',
cityInput: 'vn-client-fiscal-data [ng-model="$ctrl.client.city"]', cityInput: 'vn-client-fiscal-data [ng-model="$ctrl.client.city"]',

View File

@ -80,6 +80,7 @@ describe('Client Edit fiscalData path', () => {
await page.waitToClick(selectors.clientFiscalData.equalizationTaxCheckbox); await page.waitToClick(selectors.clientFiscalData.equalizationTaxCheckbox);
await page.waitToClick(selectors.clientFiscalData.verifiedDataCheckbox); await page.waitToClick(selectors.clientFiscalData.verifiedDataCheckbox);
await page.waitToClick(selectors.clientFiscalData.saveButton); await page.waitToClick(selectors.clientFiscalData.saveButton);
await page.waitToClick(selectors.clientFiscalData.acceptDuplicationButton);
const result = await page.waitForLastSnackbar(); const result = await page.waitForLastSnackbar();
expect(result).toEqual('Invalid Tax number'); expect(result).toEqual('Invalid Tax number');
@ -89,6 +90,7 @@ describe('Client Edit fiscalData path', () => {
await page.clearInput(selectors.clientFiscalData.fiscalIdInput); await page.clearInput(selectors.clientFiscalData.fiscalIdInput);
await page.write(selectors.clientFiscalData.fiscalIdInput, '94980061C'); await page.write(selectors.clientFiscalData.fiscalIdInput, '94980061C');
await page.waitToClick(selectors.clientFiscalData.saveButton); await page.waitToClick(selectors.clientFiscalData.saveButton);
await page.waitToClick(selectors.clientFiscalData.acceptDuplicationButton);
const result = await page.waitForLastSnackbar(); const result = await page.waitForLastSnackbar();
expect(result).toEqual('Data saved!'); expect(result).toEqual('Data saved!');
@ -151,6 +153,7 @@ describe('Client Edit fiscalData path', () => {
it('should navigate back to fiscal data and uncheck EQtax then check VIES', async() => { it('should navigate back to fiscal data and uncheck EQtax then check VIES', async() => {
await page.waitToClick(selectors.clientFiscalData.fiscalDataButton); await page.waitToClick(selectors.clientFiscalData.fiscalDataButton);
await page.waitToClick(selectors.clientFiscalData.viesCheckbox); await page.waitToClick(selectors.clientFiscalData.viesCheckbox);
await page.waitToClick(selectors.clientFiscalData.invoiceByAddressCheckbox);
await page.waitToClick(selectors.clientFiscalData.equalizationTaxCheckbox); await page.waitToClick(selectors.clientFiscalData.equalizationTaxCheckbox);
await page.waitToClick(selectors.clientFiscalData.saveButton); await page.waitToClick(selectors.clientFiscalData.saveButton);
const result = await page.waitForLastSnackbar(); const result = await page.waitForLastSnackbar();
@ -239,10 +242,10 @@ describe('Client Edit fiscalData path', () => {
expect(result).toBe('unchecked'); expect(result).toBe('unchecked');
}); });
it('should confirm invoice by address checkbox is unchecked', async() => { it('should confirm invoice by address checkbox is checked', async() => {
const result = await page.checkboxState(selectors.clientFiscalData.invoiceByAddressCheckbox); const result = await page.checkboxState(selectors.clientFiscalData.invoiceByAddressCheckbox);
expect(result).toBe('unchecked'); expect(result).toBe('checked');
}); });
it('should confirm Equalization tax checkbox is unchecked', async() => { it('should confirm Equalization tax checkbox is unchecked', async() => {

View File

@ -59,6 +59,7 @@ describe('Client lock verified data path', () => {
it('should check the Verified data checkbox', async() => { it('should check the Verified data checkbox', async() => {
await page.waitToClick(selectors.clientFiscalData.verifiedDataCheckbox); await page.waitToClick(selectors.clientFiscalData.verifiedDataCheckbox);
await page.waitToClick(selectors.clientFiscalData.saveButton); await page.waitToClick(selectors.clientFiscalData.saveButton);
await page.waitToClick(selectors.clientFiscalData.acceptDuplicationButton);
const result = await page.waitForLastSnackbar(); const result = await page.waitForLastSnackbar();
expect(result).toEqual('Data saved!'); expect(result).toEqual('Data saved!');

View File

@ -1,47 +0,0 @@
module.exports = Self => {
Self.remoteMethod('byNameOrEmail', {
description: 'Returns the client with the matching phone or email',
accessType: 'READ',
accepts: [{
arg: 'email',
type: 'String',
description: 'Find my matching client email',
required: false
},
{
arg: 'phone',
type: 'String',
description: 'Find my matching client phone',
required: false
}],
returns: {
type: 'number',
root: true
},
http: {
path: `/byNameOrEmail`,
verb: 'GET'
}
});
Self.byNameOrEmail = async(email, phone) => {
const models = Self.app.models;
let match;
match = await Self.findOne({
where: {
email: email
}
});
if (match) return match;
match = await models.UserPhone.findOne({
where: {
phone: phone
}
});
return await Self.findById(match.userFk);
};
};

View File

@ -1,56 +1,40 @@
const app = require('vn-loopback/server/server'); const app = require('vn-loopback/server/server');
describe('Client updateFiscalData', () => { describe('Client updateFiscalData', () => {
const clientId = 101;
afterAll(async done => { afterAll(async done => {
let ctxOfAdmin = {req: {accessToken: {userId: 5}}}; const clientId = 101;
let validparams = {postcode: 46460}; const ctx = {req: {accessToken: {userId: 5}}};
let idWithDataChecked = 101; ctx.args = {postcode: 46460};
await app.models.Client.updateFiscalData(ctxOfAdmin, validparams, idWithDataChecked); await app.models.Client.updateFiscalData(ctx, clientId);
done(); done();
}); });
it('should return an error if the user is not administrative and the isTaxDataChecked value is true', async() => { it('should return an error if the user is not administrative and the isTaxDataChecked value is true', async() => {
const ctx = {req: {accessToken: {userId: 1}}};
ctx.args = {};
let error; let error;
await app.models.Client.updateFiscalData(ctx, clientId)
let ctxOfNoAdmin = {req: {accessToken: {userId: 1}}};
let params = [];
let idWithDataChecked = 101;
await app.models.Client.updateFiscalData(ctxOfNoAdmin, params, idWithDataChecked)
.catch(e => { .catch(e => {
error = e; error = e;
}); });
expect(error.toString()).toContain(`You can't make changes on a client with verified data`); expect(error.message).toBeDefined();
});
it('should return an error if the user is administrative and the isTaxDataChecked value is true BUT the params aint valid', async() => {
let error;
let ctxOfAdmin = {req: {accessToken: {userId: 5}}};
let invalidparams = {invalid: 'param for update'};
let idWithDataChecked = 101;
await app.models.Client.updateFiscalData(ctxOfAdmin, invalidparams, idWithDataChecked)
.catch(e => {
error = e;
});
expect(error.toString()).toContain(`You don't have enough privileges to do that`);
}); });
it('should update the client fiscal data and return the count if changes made', async() => { it('should update the client fiscal data and return the count if changes made', async() => {
let ctxOfAdmin = {req: {accessToken: {userId: 5}}}; const ctx = {req: {accessToken: {userId: 5}}};
let validparams = {postcode: 46680}; ctx.args = {postcode: 46680};
let idWithDataChecked = 101;
let client = await app.models.Client.findById(idWithDataChecked);
const client = await app.models.Client.findById(clientId);
expect(client.postcode).toEqual('46460'); expect(client.postcode).toEqual('46460');
let result = await app.models.Client.updateFiscalData(ctxOfAdmin, validparams, idWithDataChecked); const result = await app.models.Client.updateFiscalData(ctx, clientId);
expect(result.postcode).toEqual('46680'); expect(result.postcode).toEqual('46680');
}); });

View File

@ -1,21 +1,87 @@
let UserError = require('vn-loopback/util/user-error'); let UserError = require('vn-loopback/util/user-error');
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('updateFiscalData', { Self.remoteMethod('updateFiscalData', {
description: 'Updates billing data of a client', description: 'Updates fiscal data of a client',
accessType: 'WRITE', accessType: 'WRITE',
accepts: [{ accepts: [{
arg: 'data', arg: 'ctx',
type: 'Object', type: 'Object',
required: true, http: {source: 'context'}
description: 'Params to update', },
http: {source: 'body'} {
}, {
arg: 'id', arg: 'id',
type: 'string', type: 'Number',
required: true, description: 'The client id',
description: 'Model id',
http: {source: 'path'} http: {source: 'path'}
},
{
arg: 'socialName',
type: 'String'
},
{
arg: 'fi',
type: 'String'
},
{
arg: 'street',
type: 'String'
},
{
arg: 'postcode',
type: 'String'
},
{
arg: 'city',
type: 'String'
},
{
arg: 'countryFk',
type: 'Number'
},
{
arg: 'provinceFk',
type: 'Number'
},
{
arg: 'hasToInvoiceByAddress',
type: 'Boolean'
},
{
arg: 'hasToInvoice',
type: 'Boolean'
},
{
arg: 'isActive',
type: 'Boolean'
},
{
arg: 'isFreezed',
type: 'Boolean'
},
{
arg: 'isVies',
type: 'Boolean'
},
{
arg: 'isToBeMailed',
type: 'Boolean'
},
{
arg: 'isEqualizated',
type: 'Boolean'
},
{
arg: 'isTaxDataVerified',
type: 'Boolean'
},
{
arg: 'isTaxDataChecked',
type: 'Boolean'
},
{
arg: 'despiteOfClient',
type: 'Number'
}], }],
returns: { returns: {
arg: 'res', arg: 'res',
@ -28,41 +94,34 @@ module.exports = Self => {
} }
}); });
Self.updateFiscalData = async(ctx, params, id) => { Self.updateFiscalData = async(ctx, clientId) => {
let userId = ctx.req.accessToken.userId; const models = Self.app.models;
let isSalesAssistant = await Self.app.models.Account.hasRole(userId, 'salesAssistant'); const args = ctx.args;
let [taxData] = await Self.app.models.Client.find({where: {id: id}, fields: ['isTaxDataChecked']}); const userId = ctx.req.accessToken.userId;
const isSalesAssistant = await models.Account.hasRole(userId, 'salesAssistant');
if (!isSalesAssistant && taxData.isTaxDataChecked) const client = await models.Client.findById(clientId);
if (!isSalesAssistant && client.isTaxDataChecked)
throw new UserError(`You can't make changes on a client with verified data`); throw new UserError(`You can't make changes on a client with verified data`);
let validUpdateParams = [ if (args.despiteOfClient) {
'socialName', const logRecord = {
'fi', originFk: clientId,
'street', userFk: userId,
'postcode', action: 'update',
'city', changedModel: 'Client',
'countryFk', changedModelId: clientId,
'provinceFk', description: `Cliente comprobado a pesar de que existe el cliente id ${args.despiteOfClient}`
'isActive', };
'isFreezed',
'hasToInvoice',
'isVies',
'isToBeMailed',
'hasToInvoiceByAddress',
'isEqualizated',
'isTaxDataVerified',
'isTaxDataChecked'
];
for (const key in params) { await models.ClientLog.create(logRecord);
if (validUpdateParams.indexOf(key) === -1)
throw new UserError(`You don't have enough privileges to do that`);
} }
params.id = id; // Remove unwanted properties
delete args.ctx;
delete args.id;
let client = await Self.app.models.Client.findById(id); return client.updateAttributes(args);
return await client.updateAttributes(params);
}; };
}; };

View File

@ -24,7 +24,6 @@ module.exports = Self => {
require('../methods/client/canBeInvoiced')(Self); require('../methods/client/canBeInvoiced')(Self);
require('../methods/client/uploadFile')(Self); require('../methods/client/uploadFile')(Self);
require('../methods/client/lastActiveTickets')(Self); require('../methods/client/lastActiveTickets')(Self);
require('../methods/client/findByPhoneOrEmail')(Self);
require('../methods/client/sendSms')(Self); require('../methods/client/sendSms')(Self);
require('../methods/client/createAddress')(Self); require('../methods/client/createAddress')(Self);
require('../methods/client/updateAddress')(Self); require('../methods/client/updateAddress')(Self);

View File

@ -2,6 +2,7 @@
<vn-watcher <vn-watcher
vn-id="watcher" vn-id="watcher"
data="$ctrl.client" data="$ctrl.client"
id-field="id"
form="form" form="form"
save="patch"> save="patch">
</vn-watcher> </vn-watcher>
@ -129,7 +130,8 @@
vn-one vn-one
label="Is equalizated" label="Is equalizated"
ng-model="$ctrl.client.isEqualizated" ng-model="$ctrl.client.isEqualizated"
info="In order to invoice, this field is not consulted, but the consignee's ET. When modifying this field if the invoice by address option is not checked, the change will be automatically propagated to all addresses, otherwise the user will be asked if he wants to propagate it or not."> info="In order to invoice, this field is not consulted, but the consignee's ET. When modifying this field if the invoice by address option is not checked, the change will be automatically propagated to all addresses, otherwise the user will be asked if he wants to propagate it or not."
on-change="$ctrl.onChangeEqualizated(value)">
</vn-check> </vn-check>
<vn-check <vn-check
vn-one vn-one
@ -150,3 +152,8 @@
message="Do you want to spread the change?" message="Do you want to spread the change?"
on-accept="$ctrl.onAcceptEt()"> on-accept="$ctrl.onAcceptEt()">
</vn-confirm> </vn-confirm>
<vn-confirm
vn-id="confirm-duplicatedClient"
message="Found a client with this data"
on-accept="$ctrl.onAcceptDuplication()">
</vn-confirm>

View File

@ -4,30 +4,47 @@ import Component from 'core/lib/component';
export default class Controller extends Component { export default class Controller extends Component {
onSubmit() { onSubmit() {
const orgData = this.$.watcher.orgData; const orgData = this.$.watcher.orgData;
if (orgData.isEqualizated != this.client.isEqualizated) delete this.client.despiteOfClient;
this.client.hasToInvoiceByAddress = false; if (!orgData.isTaxDataChecked && this.client.isTaxDataChecked)
this.checkExistingClient();
if (!orgData.isTaxDataChecked && this.client.isTaxDataChecked) { else this.save();
const serializedParams = {email: this.client.email, phone: 111};
const query = `Clients/byNameOrEmail?filter=${serializedParams}`;
this.$http.get(query).then(res => {
console.log(res);
});
}
return this.checkEtChanges().then(
() => this.$.watcher.submit());
} }
checkEtChanges() { checkExistingClient() {
const orgData = this.$.watcher.orgData; const filterObj = {
const equalizatedHasChanged = orgData.isEqualizated != this.client.isEqualizated; where: {
and: [
{or: [{email: this.client.email}, {phone: this.client.phone}]},
{id: {neq: this.client.id}}
]
}
};
if (equalizatedHasChanged && !orgData.hasToInvoiceByAddress) const $t = this.$translate.instant;
const filter = encodeURIComponent(JSON.stringify(filterObj));
const query = `Clients/findOne?filter=${filter}`;
this.$http.get(query).then(res => {
if (res.data.id) {
const params = {clientId: res.data.id};
const question = $t('Found a client with this phone or email', params, null, null, 'sanitizeParameters');
this.client.despiteOfClient = params.clientId;
this.$.confirmDuplicatedClient.question = question;
this.$.confirmDuplicatedClient.show();
}
});
}
checkEtChanges(orgData) {
const equalizatedHasChanged = orgData.isEqualizated != this.client.isEqualizated;
const hasToInvoiceByAddress = orgData.hasToInvoiceByAddress || this.client.hasToInvoiceByAddress;
if (equalizatedHasChanged && hasToInvoiceByAddress)
this.$.propagateIsEqualizated.show(); this.$.propagateIsEqualizated.show();
else if (equalizatedHasChanged) else if (equalizatedHasChanged)
return this.onAcceptEt(); return this.onAcceptEt();
return this.$q.resolve(); return this.$q.resolve();
} }
@ -37,6 +54,29 @@ export default class Controller extends Component {
() => this.vnApp.showMessage(this.$translate.instant('Equivalent tax spreaded')) () => this.vnApp.showMessage(this.$translate.instant('Equivalent tax spreaded'))
); );
} }
onAcceptDuplication() {
this.save();
return true;
}
save() {
const orgData = this.$.watcher.orgData;
const clonedOrgData = JSON.parse(JSON.stringify(orgData));
return this.$.watcher.submit().then(
() => this.checkEtChanges(clonedOrgData));
}
onChangeEqualizated(value) {
const orgData = this.$.watcher.orgData;
if (value === true)
this.client.hasToInvoiceByAddress = false;
else if (orgData.hasToInvoiceByAddress)
this.client.hasToInvoiceByAddress = true;
this.$.$apply();
}
} }
ngModule.component('vnClientFiscalData', { ngModule.component('vnClientFiscalData', {

View File

@ -1,9 +1,11 @@
import './index'; import './index';
import watcher from 'core/mocks/watcher';
describe('Client', () => { describe('Client', () => {
describe('Component vnClientFiscalData', () => { describe('Component vnClientFiscalData', () => {
let $httpBackend; let $httpBackend;
let $scope; let $scope;
let $element;
let controller; let controller;
beforeEach(ngModule('client')); beforeEach(ngModule('client'));
@ -11,16 +13,97 @@ describe('Client', () => {
beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_) => { beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_) => {
$httpBackend = _$httpBackend_; $httpBackend = _$httpBackend_;
$scope = $rootScope.$new(); $scope = $rootScope.$new();
controller = $componentController('vnClientFiscalData', {$scope}); $scope.watcher = watcher;
$scope.watcher.orgData = {id: 101, isEqualizated: false, isTaxDataChecked: false};
$element = angular.element('<vn-client-fiscal-data></client-fiscal-data>');
controller = $componentController('vnClientFiscalData', {$element, $scope});
controller.card = {reload: () => {}}; controller.card = {reload: () => {}};
controller.client = {
id: 101,
email: 'batman@gothamcity.com',
phone: '1111111111',
isEqualizated: false,
isTaxDataChecked: false
};
})); }));
describe('returnDialogEt()', () => { describe('onSubmit()', () => {
it('should call the save() method directly', () => {
spyOn(controller, 'save');
controller.onSubmit();
expect(controller.save).toHaveBeenCalledWith();
});
it('should call the checkExistingClient() if the isTaxDataChecked property is checked', () => {
spyOn(controller, 'save');
spyOn(controller, 'checkExistingClient');
controller.client.isTaxDataChecked = true;
controller.onSubmit();
expect(controller.save).not.toHaveBeenCalledWith();
expect(controller.checkExistingClient).toHaveBeenCalledWith();
});
});
describe('checkExistingClient()', () => {
it('should show a save confirmation when a duplicated client is found and then set the despiteOfClient property', () => {
controller.$.confirmDuplicatedClient = {show: () => {}};
spyOn(controller.$.confirmDuplicatedClient, 'show');
const filterObj = {
where: {
and: [
{or: [{email: controller.client.email}, {phone: controller.client.phone}]},
{id: {neq: controller.client.id}}
]
}
};
const expectedClient = {id: 102};
const filter = encodeURIComponent(JSON.stringify(filterObj));
$httpBackend.expect('GET', `Clients/findOne?filter=${filter}`).respond(expectedClient);
controller.checkExistingClient();
$httpBackend.flush();
expect(controller.$.confirmDuplicatedClient.show).toHaveBeenCalledWith();
expect(controller.client.despiteOfClient).toEqual(102);
});
});
describe('checkEtChanges()', () => {
it(`should show a propagation confirmation if isEqualizated property is changed and invoice by address is checked`, () => {
controller.$.propagateIsEqualizated = {show: () => {}};
spyOn(controller.$.propagateIsEqualizated, 'show');
const orgData = $scope.watcher.orgData;
orgData.hasToInvoiceByAddress = true;
controller.client.isEqualizated = true;
controller.checkEtChanges(orgData);
expect(controller.$.propagateIsEqualizated.show).toHaveBeenCalledWith();
});
it(`should call to the onAcceptEt() method if isEqualizated property is changed and invoice by address isn't checked`, () => {
spyOn(controller, 'onAcceptEt');
const orgData = $scope.watcher.orgData;
orgData.hasToInvoiceByAddress = false;
controller.client.isEqualizated = true;
controller.checkEtChanges(orgData);
expect(controller.onAcceptEt).toHaveBeenCalledWith();
});
});
describe('onAcceptEt()', () => {
it('should request to patch the propagation of tax status', () => { it('should request to patch the propagation of tax status', () => {
controller.client = {id: 123, isEqualizated: false}; controller.client = {id: 123, isEqualizated: false};
$httpBackend.when('PATCH', `Clients/${controller.client.id}/addressesPropagateRe`, {isEqualizated: controller.client.isEqualizated}).respond('done'); $httpBackend.when('PATCH', `Clients/${controller.client.id}/addressesPropagateRe`, {isEqualizated: controller.client.isEqualizated}).respond('done');
$httpBackend.expectPATCH(`Clients/${controller.client.id}/addressesPropagateRe`, {isEqualizated: controller.client.isEqualizated}); $httpBackend.expectPATCH(`Clients/${controller.client.id}/addressesPropagateRe`, {isEqualizated: controller.client.isEqualizated});
controller.returnDialogEt('accept'); controller.onAcceptEt();
$httpBackend.flush(); $httpBackend.flush();
}); });
}); });

View File

@ -0,0 +1 @@
Found a client with this phone or email: The client with id <a href="#!/client/{{clientId}}/summary" target="_blank">{{clientId}}</a> already has this phone or email. <br/> ¿Do you want to continue?

View File

@ -4,3 +4,5 @@ Do you want to spread the change?: ¿Deseas propagar el cambio a sus consignatar
Frozen: Congelado Frozen: Congelado
In order to invoice, this field is not consulted, but the consignee's ET. When modifying this field if the invoice by address option is not checked, the change will be automatically propagated to all addresses, otherwise the user will be asked if he wants to propagate it or not.: Para facturar no se consulta este campo, sino el RE de consignatario. Al modificar este campo si no esta marcada la casilla Facturar por consignatario, se propagará automáticamente el cambio a todos los consignatarios, en caso contrario preguntará al usuario si quiere o no propagar. In order to invoice, this field is not consulted, but the consignee's ET. When modifying this field if the invoice by address option is not checked, the change will be automatically propagated to all addresses, otherwise the user will be asked if he wants to propagate it or not.: Para facturar no se consulta este campo, sino el RE de consignatario. Al modificar este campo si no esta marcada la casilla Facturar por consignatario, se propagará automáticamente el cambio a todos los consignatarios, en caso contrario preguntará al usuario si quiere o no propagar.
You can use letters and spaces: Se pueden utilizar letras y espacios You can use letters and spaces: Se pueden utilizar letras y espacios
Found a client with this data: Se ha encontrado un cliente con estos datos
Found a client with this phone or email: El cliente con id <a href="#!/client/{{clientId}}/summary" target="_blank">{{clientId}}</a> ya tiene este teléfono o email. <br/> ¿Quieres continuar?