Merge branch 'dev' of http://git.verdnatura.es/salix into dev

This commit is contained in:
Carlos Jimenez 2018-10-16 15:37:27 +02:00
commit c794b5538a
26 changed files with 4094 additions and 3790 deletions

View File

@ -10,19 +10,38 @@
<vn-title>Pay method</vn-title>
<vn-horizontal>
<vn-autocomplete
vn-one
vn-two
label="Pay method"
vn-acl="administrative, salesAssistant"
vn-acl="salesAssistant"
field="$ctrl.client.payMethodFk"
url="/client/api/PayMethods"
select-fields="ibanRequired"
initial-data="$ctrl.client.payMethod">
</vn-autocomplete>
<vn-autocomplete vn-two
label="Swift / BIC"
url="/client/api/BankEntities"
field="$ctrl.client.bankEntityFk"
select-fields="['name']"
initial-data="$ctrl.client.bankEntityFk"
where="{or: [{bic: {regexp: 'search'}}, {name: {regexp: 'search'}}]}"
value-field="id"
show-field="bic"
vn-acl="salesAssistant">
<tpl-item>
<vn-horizontal>
<vn-one>{{bic}}</vn-one>
<vn-one>
<div class="ellipsize" style="max-width: 10em">{{name}}</div>
</vn-one>
</vn-horizontal>
</tpl-item>
</vn-autocomplete>
<vn-textfield
vn-one
label="Due day"
field="$ctrl.client.dueDay"
vn-acl="administrative, salesAssistant">
vn-acl="salesAssistant">
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
@ -30,7 +49,7 @@
vn-one
label="IBAN"
field="$ctrl.client.iban"
vn-acl="administrative, salesAssistant">
vn-acl="salesAssistant">
</vn-textfield>
</vn-horizontal>
<vn-horizontal pad-small-v>
@ -38,26 +57,26 @@
<vn-check
label="Received LCR"
field="$ctrl.client.hasLcr"
vn-acl="administrative, salesAssistant">
vn-acl="salesAssistant">
</vn-check>
</vn-one>
<vn-one>
<vn-check
label="Received core VNL"
field="$ctrl.client.hasCoreVnl"
vn-acl="administrative, salesAssistant">
vn-acl="salesAssistant">
</vn-check>
</vn-one>
<vn-one>
<vn-check
label="Received B2B VNL"
field="$ctrl.client.hasSepaVnl"
vn-acl="administrative, salesAssistant">
vn-acl="salesAssistant">
</vn-check>
</vn-one>
</vn-horizontal>
</vn-card>
<vn-button-bar>
<vn-submit label="Save" vn-acl="administrative, salesAssistant"></vn-submit>
<vn-submit label="Save" vn-acl="salesAssistant"></vn-submit>
</vn-button-bar>
</form>

View File

@ -158,45 +158,49 @@
</vn-vertical>
</vn-one>
<vn-one margin-medium>
<h5 translate>Recovery</h5>
<vn-vertical ng-if="$ctrl.summary.recovery">
<vn-label-value label="Since"
value="{{$ctrl.summary.recovery.started | date:'dd/MM/yyyy'}}">
<h5 translate>Business data</h5>
<vn-label-value label="Total greuge"
value="{{$ctrl.summary.totalGreuge | currency:'€ ':2}}">
</vn-label-value>
<vn-label-value label="To"
value="{{$ctrl.summary.recovery.finished | date:'dd/MM/yyyy'}}">
</vn-label-value>
<vn-label-value label="Amount"
value="{{$ctrl.summary.recovery.amount | currency:'€ ':2}}">
</vn-label-value>
<vn-label-value label="Period"
value="{{$ctrl.summary.recovery.period}}">
</vn-label-value>
</vn-vertical>
</vn-one>
<vn-one margin-medium>
<h5 translate>Financial data</h5>
<vn-label-value label="Mana"
value="{{$ctrl.summary.mana.mana | currency:'€ ':2}}">
</vn-label-value>
<vn-label-value label="Risk"
value="{{$ctrl.summary.debt.debt | currency:'€ ':2}}">
<vn-label-value label="Rate"
value="{{$ctrl.summary.claimsRatio[0].priceIncreasing | percentage}}">
</vn-label-value>
<vn-label-value label="Average invoiced"
value="{{$ctrl.summary.averageInvoiced.invoiced | currency:'€ ':2}}">
</vn-label-value>
<vn-label-value label="Total greuge"
value="{{$ctrl.summary.totalGreuge | currency:'€ ':2}}">
<vn-label-value label="Claims"
value="{{$ctrl.summary.claimsRatio[0].claimingRate | percentage}}">
</vn-label-value>
</vn-one>
<vn-one margin-medium>
<h5 translate>Financial information</h5>
<vn-label-value label="Risk"
value="{{$ctrl.summary.debt.debt | currency:'€ ':2}}"
ng-class="{bold: $ctrl.summary.debt.debt > $ctrl.summary.credit}">
</vn-label-value>
<vn-label-value label="Credit"
value="{{$ctrl.summary.credit | currency:'€ ':2}}">
value="{{$ctrl.summary.credit | currency:'€ ':2}}"
ng-class="{bold: $ctrl.summary.credit > $ctrl.summary.creditInsurance ||
($ctrl.summary.credit && $ctrl.summary.creditInsurance == null)}">
</vn-label-value>
<vn-label-value label="Secured credit"
value="{{$ctrl.summary.creditInsurance | currency:'€ ':2}}">
</vn-label-value>
<vn-label-value label="Grade"
value="{{$ctrl.grade}}">
<vn-label-value label="Balance"
value="{{$ctrl.summary.clientRisks[0].amount | currency:'€ ':2}}">
</vn-label-value>
<vn-label-value label="Balance due"
value="{{$ctrl.summary.defaulters[0].amount | currency:'€ ':2}}"
ng-class="{bold: $ctrl.summary.defaulters[0].amount}">
</vn-label-value>
<vn-vertical ng-if="$ctrl.summary.recovery.started">
<vn-label-value label="Recovery since"
value="{{$ctrl.summary.recovery.started | date:'dd/MM/yyyy'}}">
</vn-label-value>
</vn-vertical>
</vn-one>
</vn-horizontal>
</vn-vertical>

View File

@ -1,9 +1,13 @@
Default address: Consignatario pred.
Total greuge: Greuge total
Financial data: Datos financieros
Financial information: Datos financieros
Mana: Maná
Risk: Riesgo
Secured credit: Crédito asegurado
Average invoiced: Consumo medio
Sales person: Comercial
Recovery: Recobro
Balance due: Saldo vencido
Rate: Tarifa
Business data: Datos comerciales
Recovery since: Recobro desde

View File

@ -3,3 +3,7 @@ vn-dialog {
min-width: 10em;
}
}
vn-client-summary .bold {
font-family: vn-font-bold;
}

View File

@ -0,0 +1,17 @@
import ngModule from '../module';
/**
* Override angular currency formats a number adding symbol after value.
*
* @return {String} The formated number
*/
export default function currency() {
return function(input, symbol, fractionSize) {
if (input == null || input === '')
return null;
if (typeof input == 'number' && fractionSize)
input = input.toFixed(fractionSize);
return `${input} ${symbol}`;
};
}
ngModule.filter('currency', currency);

View File

@ -2,3 +2,5 @@ import './phone';
import './ucwords';
import './dash-if-empty';
import './dateTime';
import './percentage';
import './currency';

View File

@ -0,0 +1,15 @@
import ngModule from '../module';
/**
* Formats a number multiplying by 100 and adding character %.
*
* @return {String} The formated number
*/
export default function percentage() {
return function(input) {
if (input == null || input === '')
return null;
return input * 100 + ' %';
};
}
ngModule.filter('percentage', percentage);

View File

@ -1,7 +1,7 @@
import selectors from '../../helpers/selectors.js';
import createNightmare from '../../helpers/helpers';
describe('Client', () => {
xdescribe('Client', () => {
describe('Edit pay method path', () => {
const nightmare = createNightmare();

7135
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,30 @@
{
"name": "BankEntity",
"base": "VnModel",
"options": {
"mysql": {
"table": "bankEntity",
"database": "vn"
}
},
"properties": {
"id": {
"type": "Number",
"id": true,
"description": "Identifier"
},
"bic": {
"type": "String"
},
"name": {
"type": "String"
}
},
"relations": {
"country": {
"type": "belongsTo",
"model": "Country",
"foreignKey": "countryFk"
}
}
}

View File

@ -8,6 +8,14 @@
}
},
"properties": {
"clientFk": {
"type": "Number",
"id": true
},
"companyFk": {
"type": "Number",
"id": true
},
"amount": {
"type": "Number"
}

View File

@ -0,0 +1,63 @@
{
"name": "Receipt",
"base": "VnModel",
"options": {
"mysql": {
"table": "receipt"
}
},
"properties": {
"id": {
"id": true,
"type": "Number",
"description": "Identifier"
},
"ref": {
"id": true,
"type": "String",
"required": true
},
"amountPaid": {
"type": "Number"
},
"amountUnpaid": {
"type": "Number"
},
"payed": {
"type": "date"
},
"worcreated": {
"type": "date"
},
"isConciliate": {
"type": "date"
}
},
"relations": {
"client": {
"type": "belongsTo",
"model": "Client",
"foreignKey": "clientFk"
},
"company": {
"type": "belongsTo",
"model": "Company",
"foreignKey": "companyFk"
},
"worker": {
"type": "belongsTo",
"model": "Worker",
"foreignKey": "workerFk"
},
"bank": {
"type": "belongsTo",
"model": "Bank",
"foreignKey": "bankFk"
},
"invoice": {
"type": "belongsTo",
"model": "InvoiceOut",
"foreignKey": "invoiceFk"
}
}
}

View File

@ -2,6 +2,9 @@
"AddressObservation": {
"dataSource": "vn"
},
"BankEntity": {
"dataSource": "vn"
},
"ClientCredit": {
"dataSource": "vn"
},
@ -58,5 +61,8 @@
},
"ClientRisk": {
"dataSource": "vn"
},
"Receipt": {
"dataSource": "vn"
}
}

View File

@ -0,0 +1,64 @@
/**
* Cambios para evitar fallos en local.
* Ya está en producción
**/
ALTER TABLE `vn2008`.`Clientes`
ADD COLUMN `bankEntityFk` INT(10) UNSIGNED NULL AFTER `hasLcr`;
USE `vn`;
CREATE
OR REPLACE ALGORITHM = UNDEFINED
DEFINER = `root`@`%`
SQL SECURITY DEFINER
VIEW `client` AS
SELECT
`c`.`id_cliente` AS `id`,
`c`.`cliente` AS `name`,
`c`.`if` AS `fi`,
`c`.`razonSocial` AS `socialName`,
`c`.`contacto` AS `contact`,
`c`.`domicilio` AS `street`,
`c`.`poblacion` AS `city`,
`c`.`codPostal` AS `postcode`,
`c`.`telefono` AS `phone`,
`c`.`movil` AS `mobile`,
`c`.`fax` AS `fax`,
`c`.`real` AS `isRelevant`,
`c`.`e-mail` AS `email`,
`c`.`iban` AS `iban`,
`c`.`vencimiento` AS `dueDay`,
`c`.`Cuenta` AS `accountingAccount`,
`c`.`RE` AS `isEqualizated`,
`c`.`province_id` AS `provinceFk`,
`c`.`invoice` AS `hasToInvoice`,
`c`.`credito` AS `credit`,
`c`.`Id_Pais` AS `countryFk`,
`c`.`activo` AS `isActive`,
`c`.`gestdoc_id` AS `gestdocFk`,
`c`.`calidad` AS `quality`,
`c`.`pay_met_id` AS `payMethodFk`,
`c`.`created` AS `created`,
`c`.`mail` AS `isToBeMailed`,
`c`.`chanel_id` AS `contactChannelFk`,
`c`.`sepaVnl` AS `hasSepaVnl`,
`c`.`coreVnl` AS `hasCoreVnl`,
`c`.`coreVnh` AS `hasCoreVnh`,
`c`.`hasLcr` AS `hasLcr`,
`c`.`default_address` AS `defaultAddressFk`,
`c`.`risk_calculated` AS `riskCalculated`,
`c`.`clientes_tipo_id` AS `clientTypeFk`,
`c`.`mail_address` AS `mailAddress`,
`c`.`cplusTerIdNifFk` AS `cplusTerIdNifFk`,
`c`.`invoiceByAddress` AS `hasToInvoiceByAddress`,
`c`.`contabilizado` AS `isTaxDataChecked`,
`c`.`congelado` AS `isFreezed`,
`c`.`creditInsurance` AS `creditInsurance`,
`c`.`isCreatedAsServed` AS `isCreatedAsServed`,
`c`.`hasInvoiceSimplified` AS `hasInvoiceSimplified`,
`c`.`Id_Trabajador` AS `salesPersonFk`,
`c`.`vies` AS `isVies`,
`c`.`EYPBC` AS `eypbc`,
bankEntityFk
FROM
`vn2008`.`Clientes` `c`;

View File

@ -1002,3 +1002,10 @@ INSERT INTO `vn`.`orderTicket`(`orderFk`, `ticketFk`)
INSERT INTO `vn`.`userConfig` (`userFk`, `warehouseFk`, `companyFk`)
VALUES (9, 1, 442);
INSERT INTO `vn`.`receipt`(`id`, `invoiceFk`, `amountPaid`, `amountUnpaid`, `payed`, `workerFk`, `bankFk`, `clientFk`, `created`, `companyFk`, `isConciliate`)
VALUES
(1, 'Cobro web', 100.50, 0.00, CURDATE(), 9, 1, 101, CURDATE(), 442, 1),
(2, 'Cobro web', 200.50, 0.00, CURDATE(), 9, 1, 101, CURDATE(), 442, 1),
(3, 'Cobro en efectivo', 300.00, 100.00, CURDATE(), 9, 1, 102, CURDATE(), 442, 0),
(4, 'Cobro en efectivo', 400.00, -50.00, CURDATE(), 9, 1, 103, CURDATE(), 442, 0);

View File

@ -7,6 +7,6 @@ describe('Client card', () => {
expect(result.id).toEqual(101);
expect(result.name).toEqual('Bruce Wayne');
expect(result.debt).toEqual(880.1);
expect(result.debt).toEqual(579.1);
});
});

View File

@ -4,7 +4,7 @@ describe('client getDebt()', () => {
it('should return the client debt', async() => {
let result = await app.models.Client.getDebt(101);
expect(result.debt).toEqual(880.1);
expect(result.debt).toEqual(579.1);
});
});

View File

@ -17,7 +17,7 @@ describe('client summary()', () => {
it('should return a summary object containing debt', async() => {
let result = await app.models.Client.summary(101);
expect(result.debt.debt).toEqual(880.1);
expect(result.debt.debt).toEqual(579.1);
});
it('should return a summary object containing averageInvoiced', async() => {

View File

@ -37,6 +37,7 @@ describe('Client updateBillingData', () => {
let params = {
phone: 2222222222,
payMethodFk: 4,
bankEntityFk: 128,
dueDay: 30,
iban: 'ES91 2100 0418 4502 0005 1332',
hasLcr: 1,

View File

@ -60,6 +60,29 @@ module.exports = Self => {
},
where: {finished: null}
}
},
{
relation: 'defaulters',
scope: {
fields: ['amount'],
order: 'created DESC',
limit: 1
}
},
{
relation: 'clientsRisk',
scope: {
where: {companyFk: 442},
fields: ['amount'],
limit: 1
}
},
{
relation: 'claimsRatio',
scope: {
fields: ['claimingRate', 'priceIncreasing'],
limit: 1
}
}
],
where: {id: clientId}

View File

@ -33,6 +33,7 @@ module.exports = Self => {
let data = filterAttributes(params, [
'payMethodFk',
'bankEntityFk',
'dueDay',
'iban',
'hasLcr',

View File

@ -0,0 +1,39 @@
{
"name": "ClaimRatio",
"base": "VnModel",
"options": {
"mysql": {
"table": "claimRatio",
"database": "vn"
}
},
"validateUpsert": true,
"properties": {
"clientFk": {
"type": "Number",
"id": true
},
"yearSale": {
"type": "Number"
},
"claimAmount": {
"type": "Number"
},
"claimingRate": {
"type": "Number"
},
"priceIncreasing": {
"type": "Number"
},
"packingRate": {
"type": "Number"
}
},
"relations": {
"client": {
"type": "belongsTo",
"model": "Client",
"foreignKey": "clientFk"
}
}
}

View File

@ -84,6 +84,7 @@ module.exports = Self => {
Self.validate('payMethod', hasSalesMan, {
message: 'Cannot change the payment method if no salesperson'
});
function hasSalesMan(err) {
if (this.payMethod && !this.salesPerson)
err();
@ -92,9 +93,10 @@ module.exports = Self => {
Self.validateAsync('payMethodFk', hasIban, {
message: 'That payment method requires an IBAN'
});
function hasIban(err, done) {
Self.app.models.PayMethod.findById(this.payMethodFk, (_, instance) => {
if (instance && instance.ibanRequired && !this.iban)
if (instance && instance.ibanRequired && (!this.iban || !this.bankEntityFk))
err();
done();
});

View File

@ -172,6 +172,26 @@
"type": "hasMany",
"model": "ClientContact",
"foreignKey": "clientFk"
},
"bank": {
"type": "belongsTo",
"model": "BankEntity",
"foreignKey": "bankEntityFk"
},
"defaulters": {
"type": "hasMany",
"model": "Defaulter",
"foreignKey": "clientFk"
},
"clientsRisk": {
"type": "hasMany",
"model": "ClientRisk",
"foreignKey": "clientFk"
},
"claimsRatio": {
"type": "hasMany",
"model": "ClaimRatio",
"foreignKey": "clientFk"
}
}
}

View File

@ -34,6 +34,9 @@
"isBargain": {
"type": "Boolean"
},
"isActive": {
"type": "Boolean"
},
"comment": {
"type": "String"
},

View File

@ -134,5 +134,8 @@
},
"UserConfig": {
"dataSource": "vn"
},
"ClaimRatio": {
"dataSource": "vn"
}
}