Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 3887-multi-check

This commit is contained in:
Alex Moreno 2022-05-10 11:42:35 +02:00
commit 5919c42df2
21 changed files with 180 additions and 31 deletions

View File

@ -0,0 +1 @@
Delete file

View File

@ -111,7 +111,7 @@ describe('Client lock verified data path', () => {
await page.waitToClick(selectors.clientFiscalData.saveButton);
const message = await page.waitForSnackbar();
expect(message.text).toContain(`You can't make changes on a client with verified data`);
expect(message.text).toContain(`Not enough privileges to edit a client with verified data`);
});
});
@ -123,19 +123,19 @@ describe('Client lock verified data path', () => {
await page.accessToSection('client.card.fiscalData');
}, 20000);
it('should confirm verified data button is enabled for salesAssistant', async() => {
it('should confirm verified data button is disabled for salesAssistant', async() => {
const isDisabled = await page.isDisabled(selectors.clientFiscalData.verifiedDataCheckbox);
expect(isDisabled).toBeFalsy();
expect(isDisabled).toBeTrue();
});
it('should now edit the social name', async() => {
it('should return error when edit the social name', async() => {
await page.clearInput(selectors.clientFiscalData.socialName);
await page.write(selectors.clientFiscalData.socialName, 'new social name edition');
await page.waitToClick(selectors.clientFiscalData.saveButton);
const message = await page.waitForSnackbar();
expect(message.text).toContain('Data saved!');
expect(message.text).toContain(`Not enough privileges to edit a client with verified data`);
});
it('should now confirm the social name have been edited once and for all', async() => {

View File

@ -12,7 +12,6 @@
"That payment method requires an IBAN": "That payment method requires an IBAN",
"That payment method requires a BIC": "That payment method requires a BIC",
"The default consignee can not be unchecked": "The default consignee can not be unchecked",
"You can't make changes on a client with verified data": "You can't make changes on a client with verified data",
"Enter an integer different to zero": "Enter an integer different to zero",
"Package cannot be blank": "Package cannot be blank",
"The new quantity should be smaller than the old one": "The new quantity should be smaller than the old one",
@ -123,5 +122,6 @@
"The type of business must be filled in basic data": "The type of business must be filled in basic data",
"The worker has hours recorded that day": "The worker has hours recorded that day",
"isWithoutNegatives": "isWithoutNegatives",
"routeFk": "routeFk"
"routeFk": "routeFk",
"Not enough privileges to edit a client with verified data": "Not enough privileges to edit a client with verified data"
}

View File

@ -50,7 +50,7 @@
"You don't have enough privileges to change that field": "No tienes permisos para cambiar ese campo",
"Warehouse cannot be blank": "El almacén no puede quedar en blanco",
"Agency cannot be blank": "La agencia no puede quedar en blanco",
"You can't make changes on a client with verified data": "No puedes hacer cambios en un cliente con datos comprobados",
"Not enough privileges to edit a client with verified data": "No tienes permisos para hacer cambios en un cliente con datos comprobados",
"This address doesn't exist": "Este consignatario no existe",
"You must delete the claim id %d first": "Antes debes borrar la reclamación %d",
"You don't have enough privileges": "No tienes suficientes permisos",

View File

@ -1,6 +1,22 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('Client addressesPropagateRe', () => {
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
it('should propagate the isEqualizated on both addresses of Mr Wayne and set hasToInvoiceByAddress to false', async() => {
const tx = await models.Client.beginTransaction({});

View File

@ -1,4 +1,5 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('Address createAddress', () => {
const clientFk = 1101;
@ -6,6 +7,21 @@ describe('Address createAddress', () => {
const incotermsFk = 'FAS';
const customAgentOneId = 1;
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
it('should throw a non uee member error if no incoterms is defined', async() => {
const tx = await models.Client.beginTransaction({});

View File

@ -1,4 +1,5 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('Client Create', () => {
const newAccount = {
@ -12,6 +13,21 @@ describe('Client Create', () => {
businessTypeFk: 'florist'
};
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
it(`should not find Deadpool as he's not created yet`, async() => {
const tx = await models.Client.beginTransaction({});

View File

@ -1,4 +1,5 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('Address updateAddress', () => {
const clientId = 1101;
@ -13,6 +14,21 @@ describe('Address updateAddress', () => {
}
};
beforeAll(async() => {
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
it('should throw the non uee member error if no incoterms is defined', async() => {
const tx = await models.Client.beginTransaction({});
@ -93,6 +109,7 @@ describe('Address updateAddress', () => {
try {
const options = {transaction: tx};
ctx.req.accessToken.userId = employeeId;
ctx.args = {
isLogifloraAllowed: true
};

View File

@ -1,10 +1,25 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('Client updateFiscalData', () => {
const clientId = 1101;
const employeeId = 1;
const salesAssistantId = 21;
const administrativeId = 5;
const activeCtx = {
accessToken: {userId: employeeId},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
beforeEach(() => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
it('should return an error if the user is not salesAssistant and the isTaxDataChecked value is true', async() => {
const tx = await models.Client.beginTransaction({});
@ -24,7 +39,7 @@ describe('Client updateFiscalData', () => {
error = e;
}
expect(error.message).toEqual(`You can't make changes on a client with verified data`);
expect(error.message).toEqual(`Not enough privileges to edit a client with verified data`);
});
it('should return an error if the salesAssistant did not fill the sage data before checking verified data', async() => {

View File

@ -125,11 +125,11 @@ module.exports = Self => {
}
try {
const isSalesAssistant = await models.Account.hasRole(userId, 'salesAssistant', myOptions);
const isAdministrative = await models.Account.hasRole(userId, 'administrative', myOptions);
const client = await models.Client.findById(clientId, null, myOptions);
if (!isSalesAssistant && client.isTaxDataChecked)
throw new UserError(`You can't make changes on a client with verified data`);
if (!isAdministrative && client.isTaxDataChecked)
throw new UserError(`Not enough privileges to edit a client with verified data`);
// Sage data validation
const taxDataChecked = args.isTaxDataChecked;

View File

@ -224,6 +224,34 @@ module.exports = Self => {
throw new UserError(`The type of business must be filled in basic data`);
});
Self.observe('before save', async ctx => {
const changes = ctx.data || ctx.instance;
const orgData = ctx.currentInstance;
const models = Self.app.models;
const loopBackContext = LoopBackContext.getCurrentContext();
const userId = loopBackContext.active.accessToken.userId;
const isAdministrative = await models.Account.hasRole(userId, 'administrative', ctx.options);
const isSalesAssistant = await models.Account.hasRole(userId, 'salesAssistant', ctx.options);
const hasChanges = orgData && changes;
const isTaxDataChecked = hasChanges && (changes.isTaxDataChecked || orgData.isTaxDataChecked);
const isTaxDataCheckedChanged = hasChanges && orgData.isTaxDataChecked != isTaxDataChecked;
const sageTaxType = hasChanges && (changes.sageTaxTypeFk || orgData.sageTaxTypeFk);
const sageTaxTypeChanged = hasChanges && orgData.sageTaxTypeFk != sageTaxType;
const sageTransactionType = hasChanges && (changes.sageTransactionTypeFk || orgData.sageTransactionTypeFk);
const sageTransactionTypeChanged = hasChanges && orgData.sageTransactionTypeFk != sageTransactionType;
const cantEditVerifiedData = isTaxDataCheckedChanged && !isAdministrative;
const cantChangeSageData = (sageTaxTypeChanged || sageTransactionTypeChanged) && !isSalesAssistant;
if (cantEditVerifiedData || cantChangeSageData)
throw new UserError(`You don't have enough privileges`);
});
Self.observe('before save', async function(ctx) {
const changes = ctx.data || ctx.instance;
const orgData = ctx.currentInstance;
@ -237,10 +265,10 @@ module.exports = Self => {
const socialNameChanged = hasChanges
&& orgData.socialName != socialName;
const dataCheckedChanged = hasChanges
const isTaxDataCheckedChanged = hasChanges
&& orgData.isTaxDataChecked != isTaxDataChecked;
if ((socialNameChanged || dataCheckedChanged) && !isAlpha(socialName))
if ((socialNameChanged || isTaxDataCheckedChanged) && !isAlpha(socialName))
throw new UserError(`The social name has an invalid format`);
if (changes.salesPerson === null) {

View File

@ -1,20 +1,36 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('loopback model address', () => {
let createdAddressId;
const clientId = 1101;
afterAll(async() => {
let client = await app.models.Client.findById(clientId);
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
await app.models.Address.destroyById(createdAddressId);
beforeEach(() => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
afterAll(async() => {
const client = await models.Client.findById(clientId);
await models.Address.destroyById(createdAddressId);
await client.updateAttribute('isEqualizated', false);
});
describe('observe()', () => {
it('should throw an error when deactivating a consignee if its the default address', async() => {
let error;
let address = await app.models.Address.findById(1);
const address = await models.Address.findById(1);
await address.updateAttribute('isActive', false)
.catch(e => {
@ -27,13 +43,13 @@ describe('loopback model address', () => {
});
it('should set isEqualizated to true of a given Client to trigger any new address to have it', async() => {
let client = await app.models.Client.findById(clientId);
const client = await models.Client.findById(clientId);
expect(client.isEqualizated).toBeFalsy();
await client.updateAttribute('isEqualizated', true);
let newAddress = await app.models.Address.create({
const newAddress = await models.Address.create({
clientFk: clientId,
agencyModeFk: 5,
city: 'here',

View File

@ -33,7 +33,7 @@
label="Social name"
ng-model="$ctrl.client.socialName"
rule
info="You can use letters and spaces"
info="Only letters, numbers and spaces can be used"
required="true">
</vn-textfield>
<vn-textfield
@ -182,7 +182,7 @@
vn-one
label="Verified data"
ng-model="$ctrl.client.isTaxDataChecked"
vn-acl="salesAssistant">
vn-acl="administrative">
</vn-check>
</vn-horizontal>
</vn-card>

View File

@ -3,7 +3,7 @@ You changed the equalization tax: Has cambiado el recargo de equivalencia
Do you want to spread the change?: ¿Deseas propagar el cambio a sus consignatarios?
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.
You can use letters and spaces: Se pueden utilizar letras y espacios
Only letters, numbers and spaces can be used: Sólo se pueden usar letras, numeros 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?
Sage tax type: Tipo de impuesto Sage

View File

@ -1,6 +1,6 @@
<vn-crud-model
vn-id="buysModel"
url="Entries/{{$ctrl.$params.id}}/getBuys"
url="Entries/{{$ctrl.entry.id}}/getBuys"
limit="5"
data="buys"
auto-load="true">

View File

@ -4,6 +4,9 @@ import Summary from 'salix/components/summary';
class Controller extends Summary {
get entry() {
if (!this._entry)
return this.$params;
return this._entry;
}

View File

@ -144,6 +144,7 @@ module.exports = Self => {
ii.isBooked,
ii.supplierRef,
ii.docFk AS dmsFk,
dm.file,
ii.supplierFk,
ii.expenceFkDeductible deductibleExpenseFk,
s.name AS supplierName,
@ -156,7 +157,8 @@ module.exports = Self => {
LEFT JOIN duaInvoiceIn dii ON dii.invoiceInFk = ii.id
LEFT JOIN dua d ON d.id = dii.duaFk
LEFT JOIN awb ON awb.id = d.awbFk
LEFT JOIN company co ON co.id = ii.companyFk`
LEFT JOIN company co ON co.id = ii.companyFk
LEFT JOIN dms dm ON dm.id = ii.docFk`
);
const sqlWhere = conn.makeWhere(filter.where);

View File

@ -13,7 +13,7 @@
<vn-th field="supplierRef">Supplier ref.</vn-th>
<vn-th field="serialNumber">Serial number</vn-th>
<vn-th field="serial">Serial</vn-th>
<vn-th field="account">Account</vn-th>
<vn-th field="dmsFk">File</vn-th>
<vn-th field="issued" expand>Issued</vn-th>
<vn-th field="isBooked" center>Is booked</vn-th>
<vn-th field="awbCode" vn-tooltip="Air Waybill">AWB</vn-th>
@ -27,7 +27,7 @@
class="clickable vn-tr search-result"
ui-sref="invoiceIn.card.summary({id: {{::invoiceIn.id}}})">
<vn-td>{{::invoiceIn.id}}</vn-td>
<vn-td>
<vn-td expand>
<span
class="link"
vn-click-stop="supplierDescriptor.show($event, invoiceIn.supplierFk)">
@ -36,8 +36,13 @@
</vn-td>
<vn-td>{{::invoiceIn.supplierRef | dashIfEmpty}}</vn-td>
<vn-td>{{::invoiceIn.serialNumber}}</vn-td>
<vn-td>{{::invoiceIn.serial}}</vn-td>
<vn-td>{{::invoiceIn.account}}</vn-td>
<vn-td>{{::invoiceIn.serial}}</vn-td>
<vn-td>
<span title="{{'Download file' | translate}}" class="link"
ng-click="$ctrl.downloadFile(invoiceIn.dmsFk)">
{{::invoiceIn.file}}
</span>
</vn-td>
<vn-td expand>{{::invoiceIn.issued | date:'dd/MM/yyyy' | dashIfEmpty}}</vn-td>
<vn-td center>
<vn-check disabled="true"

View File

@ -2,6 +2,11 @@ import ngModule from '../module';
import Section from 'salix/components/section';
export default class Controller extends Section {
constructor($element, $, vnFile) {
super($element, $, vnFile);
this.vnFile = vnFile;
}
exprBuilder(param, value) {
switch (param) {
case 'issued':
@ -39,8 +44,14 @@ export default class Controller extends Section {
this.selectedInvoiceIn = invoiceIn;
this.$.summary.show();
}
downloadFile(dmsId) {
this.vnFile.download(`api/dms/${dmsId}/downloadFile`);
}
}
Controller.$inject = ['$element', '$scope', 'vnFile'];
ngModule.vnComponent('vnInvoiceInIndex', {
template: require('./index.html'),
controller: Controller

View File

@ -93,6 +93,9 @@ describe('InvoiceOut createManualInvoice()', () => {
it('should throw an error for a non-invoiceable client', async() => {
spyOn(models.InvoiceOut, 'createPdf').and.returnValue(new Promise(resolve => resolve(true)));
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
const tx = await models.InvoiceOut.beginTransaction({});
const options = {transaction: tx};

View File

@ -38,7 +38,7 @@
vn-focus
label="Social name"
ng-model="$ctrl.supplier.name"
info="You can use letters and spaces"
info="Only letters, numbers and spaces can be used"
required="true"
rule>
</vn-textfield>