Client summary & package
This commit is contained in:
parent
6b390b72f8
commit
85810e2f7e
|
@ -1,5 +1,4 @@
|
|||
import ngModule from '../module';
|
||||
import './style.css';
|
||||
|
||||
export default class Controller {
|
||||
constructor($http, $state) {
|
||||
|
|
|
@ -105,9 +105,9 @@
|
|||
<vn-horizontal vn-one>
|
||||
<vn-one margin-medium>
|
||||
<h5 translate>Default address</h5>
|
||||
<p>{{$ctrl.address.nickname}}</p>
|
||||
<p><span>{{$ctrl.address.street}}</span></p>
|
||||
<p><span>{{$ctrl.address.city}}</span></p>
|
||||
<p>{{$ctrl.summary.addresses[0].nickname}}</p>
|
||||
<p><span>{{$ctrl.summary.addresses[0].street}}</span></p>
|
||||
<p><span>{{$ctrl.summary.addresses[0].city}}</span></p>
|
||||
</vn-one>
|
||||
<vn-one margin-medium>
|
||||
<h5 translate>Web access</h5>
|
||||
|
@ -122,34 +122,30 @@
|
|||
</vn-one>
|
||||
<vn-one margin-medium>
|
||||
<h5 translate>Recovery</h5>
|
||||
<vn-vertical ng-if="$ctrl.recovery">
|
||||
<p><vn-label translate>Since</vn-label> {{$ctrl.recovery.started | date:'dd/MM/yyyy'}}</p>
|
||||
<p><vn-label translate>To</vn-label> {{$ctrl.recovery.finished | date:'dd/MM/yyyy'}}</p>
|
||||
<p><vn-label translate>Amount</vn-label> {{$ctrl.recovery.amount | currency:'€':2}}</p>
|
||||
<p><vn-label translate>Period</vn-label> {{$ctrl.recovery.period}}</p>
|
||||
<vn-vertical ng-if="$ctrl.summary.recovery">
|
||||
<p><vn-label translate>Since</vn-label> {{$ctrl.summary.recovery.started | date:'dd/MM/yyyy'}}</p>
|
||||
<p><vn-label translate>To</vn-label> {{$ctrl.summary.recovery.finished | date:'dd/MM/yyyy'}}</p>
|
||||
<p><vn-label translate>Amount</vn-label> {{$ctrl.summary.recovery.amount | currency:'€ ':2}}</p>
|
||||
<p><vn-label translate>Period</vn-label> {{$ctrl.summary.recovery.period}}</p>
|
||||
</vn-vertical>
|
||||
</vn-one>
|
||||
|
||||
<vn-one margin-medium>
|
||||
<h5 translate>Financial data</h5>
|
||||
<p><vn-label translate>Mana</vn-label> {{$ctrl.summary.mana.mana | currency:'€ ':2}}</p>
|
||||
<p><vn-label translate>Risk</vn-label> {{$ctrl.summary.debt.debt | currency:'€ ':2}}</p>
|
||||
<p><vn-label translate>Average invoiced</vn-label> {{$ctrl.summary.averageInvoiced.invoiced | currency:'€ ':2}}</p>
|
||||
<p><vn-label translate>Total greuge</vn-label> {{$ctrl.summary.totalGreuge | currency:'€ ':2}}</p>
|
||||
<p>
|
||||
<vn-label translate>Credit</vn-label>
|
||||
{{$ctrl.summary.credit | currency:'€ ':2}}
|
||||
</p>
|
||||
<p>
|
||||
<vn-label translate>Secured credit</vn-label>
|
||||
<span ng-if="!$ctrl.summary.creditInsurance">-</span>
|
||||
<span ng-if="$ctrl.summary.creditInsurance">{{$ctrl.summary.creditInsurance | currency:'€ ':2}}</span>
|
||||
</p>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal vn-one>
|
||||
<vn-one margin-medium>
|
||||
<h5 translate>Total greuge</h5>
|
||||
<p><vn-label translate>Total</vn-label> {{$ctrl.greuge.sumAmount | currency:'€':2}}</p>
|
||||
</vn-one>
|
||||
|
||||
<vn-one margin-medium>
|
||||
<h5 translate>Credit</h5>
|
||||
<p>
|
||||
<vn-label translate>Credit</vn-label>
|
||||
{{$ctrl.summary.credit | currency:'€':2}}
|
||||
</p>
|
||||
<p>
|
||||
<vn-label translate>Secured credit</vn-label>
|
||||
<span ng-if="!$ctrl.summary.creditInsurance">-</span>
|
||||
<span ng-if="$ctrl.summary.creditInsurance">{{$ctrl.summary.creditInsurance | currency:'€':2}}</span>
|
||||
</p>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
</vn-vertical>
|
|
@ -1,73 +1,22 @@
|
|||
import ngModule from '../module';
|
||||
import './style.scss';
|
||||
|
||||
class Controller {
|
||||
|
||||
constructor($http) {
|
||||
this.$http = $http;
|
||||
}
|
||||
|
||||
$onChanges() {
|
||||
if (!this.client || !this.client.id)
|
||||
if (!this.client)
|
||||
return;
|
||||
|
||||
this.getSummary();
|
||||
this.getGreuse();
|
||||
this.getRecoveries();
|
||||
}
|
||||
|
||||
getSummary() {
|
||||
let filter = {
|
||||
include: [
|
||||
{relation: 'account', scope: {fields: ['name', 'active']}},
|
||||
{relation: 'salesPerson', scope: {fields: ['name']}},
|
||||
{relation: 'country', scope: {fields: ['country']}},
|
||||
{relation: 'province', scope: {fields: ['name']}},
|
||||
{relation: 'contactChannel', scope: {fields: ['name']}},
|
||||
{relation: 'payMethod', scope: {fields: ['name']}},
|
||||
{
|
||||
relation: 'addresses',
|
||||
scope: {
|
||||
where: {isDefaultAddress: true},
|
||||
fields: ['nickname', 'street', 'city', 'postalCode']
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
filter = encodeURIComponent(JSON.stringify(filter));
|
||||
|
||||
let query = `/client/api/Clients/${this.client.id}?filter=${filter}`;
|
||||
this.$http.get(query).then(res => {
|
||||
if (res.data) {
|
||||
this.$http.get(`/client/api/Clients/${this.client.id}/summary`).then(res => {
|
||||
if (res && res.data)
|
||||
this.summary = res.data;
|
||||
this.address = res.data.addresses[0];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getGreuse() {
|
||||
let query = `/client/api/Greuges/${this.client.id}/sumAmount`;
|
||||
this.$http.get(query).then(res => {
|
||||
if (res.data)
|
||||
this.greuge = res.data;
|
||||
});
|
||||
}
|
||||
|
||||
getRecoveries() {
|
||||
let filter = {
|
||||
where: {
|
||||
and: [{clientFk: this.client.id}, {or: [{finished: null}, {finished: {gt: Date.now()}}]}]
|
||||
},
|
||||
limit: 1
|
||||
};
|
||||
filter = encodeURIComponent(JSON.stringify(filter));
|
||||
|
||||
let query = `/client/api/Recoveries?filter=${filter}`;
|
||||
this.$http.get(query).then(res => {
|
||||
if (res.data)
|
||||
this.recovery = res.data[0];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$http'];
|
||||
|
||||
ngModule.component('vnClientSummary', {
|
||||
|
|
|
@ -1,2 +1,7 @@
|
|||
Default address: Consignatario pred.
|
||||
Total greuge: Greuge total
|
||||
Total greuge: Greuge total
|
||||
Financial data: Datos financieros
|
||||
Mana: Maná
|
||||
Risk: Riesgo
|
||||
Secured credit: Crédito asegurado
|
||||
Average invoiced: Consumo medio
|
|
@ -0,0 +1,3 @@
|
|||
vn-dialog vn-one {
|
||||
min-width: 200px
|
||||
}
|
|
@ -96,8 +96,14 @@
|
|||
},
|
||||
{
|
||||
"url" : "/package",
|
||||
"abstract": true,
|
||||
"state": "ticket.card.package",
|
||||
"component": "vn-ticket-package",
|
||||
"component": "ui-view"
|
||||
},
|
||||
{
|
||||
"url" : "/index",
|
||||
"state": "ticket.card.package.index",
|
||||
"component": "vn-ticket-package-index",
|
||||
"params": {
|
||||
"ticket": "$ctrl.ticket"
|
||||
},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import ngModule from '../module';
|
||||
import ngModule from '../../module';
|
||||
|
||||
class Controller {
|
||||
|
||||
|
@ -8,7 +8,6 @@ class Controller {
|
|||
this.$translate = $translate;
|
||||
this.vnApp = vnApp;
|
||||
this.removedPackages = [];
|
||||
this.updatedPackages = [];
|
||||
}
|
||||
|
||||
submit() {
|
||||
|
@ -23,10 +22,16 @@ class Controller {
|
|||
if (typeof item.id === 'undefined')
|
||||
packagesObj.create.push(item);
|
||||
|
||||
if (typeof item.id !== 'undefined' && angular.equals(item, this.oldPackages[item.id]))
|
||||
if (typeof item.id !== 'undefined' && !this.packageEquals(item, this.oldPackages[item.id]))
|
||||
packagesObj.update.push(item);
|
||||
});
|
||||
|
||||
if (this.$.form.$invalid)
|
||||
return this.vnApp.showMessage(this.$translate.instant('Some fields are invalid'));
|
||||
|
||||
if (!this.hasChanges(packagesObj))
|
||||
return this.vnApp.showMessage(this.$translate.instant('No changes to save'));
|
||||
|
||||
this.$http.post(query, packagesObj).then(res => {
|
||||
this.$.index.accept();
|
||||
});
|
||||
|
@ -55,16 +60,31 @@ class Controller {
|
|||
}
|
||||
|
||||
setOldPackages() {
|
||||
if (this.oldPackages && !this.$.watcher.dataChanged())
|
||||
return;
|
||||
|
||||
this.oldPackages = [];
|
||||
this.removedPackages = [];
|
||||
this.packages.forEach(item => {
|
||||
this.oldPackages[item.id] = item;
|
||||
this.oldPackages[item.id] = Object.assign({}, item);
|
||||
});
|
||||
}
|
||||
|
||||
packageEquals(newPackage, oldPackage) {
|
||||
return newPackage.packagingFk === oldPackage.packagingFk && newPackage.quantity == oldPackage.quantity;
|
||||
}
|
||||
|
||||
hasChanges(packagesObj) {
|
||||
if (packagesObj.create.length || packagesObj.update.length || packagesObj.delete.length)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$http', '$scope'];
|
||||
Controller.$inject = ['$http', '$scope', '$translate', 'vnApp'];
|
||||
|
||||
ngModule.component('vnTicketPackage', {
|
||||
ngModule.component('vnTicketPackageIndex', {
|
||||
template: require('./package.html'),
|
||||
controller: Controller,
|
||||
bindings: {
|
|
@ -1,7 +1,7 @@
|
|||
import './package.js';
|
||||
|
||||
describe('Ticket', () => {
|
||||
describe('Component vnTicketPackage', () => {
|
||||
describe('Component vnTicketPackageIndex', () => {
|
||||
let $componentController;
|
||||
let controller;
|
||||
let $httpBackend;
|
||||
|
@ -19,7 +19,7 @@ describe('Ticket', () => {
|
|||
accept: function() {}
|
||||
}
|
||||
};
|
||||
controller = $componentController('vnTicketPackage', {$scope: $scope});
|
||||
controller = $componentController('vnTicketPackageIndex', {$scope: $scope});
|
||||
}));
|
||||
|
||||
describe('removePackage()', () => {
|
||||
|
@ -37,11 +37,11 @@ describe('Ticket', () => {
|
|||
let query = '/ticket/api/TicketPackagings/crudTicketPackaging';
|
||||
controller.removedPackages = [];
|
||||
controller.oldPackages = [
|
||||
{id: 1, quantity: 5, ticketFk: 1}
|
||||
{id: 1, packagingFk: 1, quantity: 5, ticketFk: 1}
|
||||
];
|
||||
controller.packages = [
|
||||
{quantity: 5, ticketFk: 1},
|
||||
{id: 1, quantity: 25, ticketFk: 1}
|
||||
{quantity: 5, packagingFk: 2, ticketFk: 1},
|
||||
{id: 1, packagingFk: 1, quantity: 25, ticketFk: 1}
|
||||
];
|
||||
let packagesObj = {
|
||||
delete: controller.removedPackages,
|
|
@ -8,7 +8,7 @@ import './data/ticket-data';
|
|||
import './note/ticket-observation';
|
||||
import './expedition/ticket-expedition';
|
||||
import './volume/ticket-volume';
|
||||
import './package/package';
|
||||
import './package/index/package';
|
||||
import './sale/sale';
|
||||
import './tracking/index';
|
||||
import './tracking/edit/edit';
|
||||
|
|
|
@ -18,14 +18,14 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.sumAmount = (clientFk, callback) => {
|
||||
Self.sumAmount = async clientFk => {
|
||||
let query = `SELECT SUM(amount) AS sumAmount FROM vn.greuge WHERE clientFk = ?`;
|
||||
Self.rawSql(query, [clientFk])
|
||||
.then(response => {
|
||||
callback(null, response.length ? response[0].sumAmount : 0);
|
||||
})
|
||||
.catch(err => {
|
||||
callback(err);
|
||||
});
|
||||
try {
|
||||
let [response] = await Self.rawSql(query, [clientFk]);
|
||||
|
||||
return response ? response.sumAmount : 0;
|
||||
} catch (e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -9,5 +9,6 @@
|
|||
"DNI Incorrecto": "DNI Incorrecto",
|
||||
"Ya existe un usuario con ese nombre": "Ya existe un usuario con ese nombre",
|
||||
"is invalid": "is invalid",
|
||||
"Quantity cannot be zero": "La cantidad no puede ser cero"
|
||||
"Quantity cannot be zero": "La cantidad no puede ser cero",
|
||||
"Package cannot be blank": "Package cannot be blank"
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('getAverageInvoiced', {
|
||||
description: 'Returns the annual average invoiced of a client',
|
||||
accessType: 'READ',
|
||||
accepts: [{
|
||||
arg: 'id',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'client id',
|
||||
http: {source: 'path'}
|
||||
}],
|
||||
returns: {
|
||||
type: 'number',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/:id/getAverageInvoiced`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.getAverageInvoiced = async clientFk => {
|
||||
let query = `SELECT invoiced FROM vn.annualAverageInvoiced WHERE clientFk = ?`;
|
||||
let [invoiced] = await Self.rawSql(query, [clientFk]);
|
||||
|
||||
return invoiced;
|
||||
};
|
||||
};
|
|
@ -21,7 +21,8 @@ module.exports = Self => {
|
|||
|
||||
Self.getDebt = async clientFk => {
|
||||
let query = `SELECT vn.clientGetDebt(?, CURDATE()) AS debt`;
|
||||
let response = await Self.rawSql(query, [clientFk]);
|
||||
return response[0];
|
||||
let [debt] = await Self.rawSql(query, [clientFk]);
|
||||
|
||||
return debt;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('getMana', {
|
||||
description: 'Returns the boolean mana of a client',
|
||||
accessType: 'READ',
|
||||
accepts: [{
|
||||
arg: 'id',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'client id',
|
||||
http: {source: 'path'}
|
||||
}],
|
||||
returns: {
|
||||
type: 'number',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/:id/getMana`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.getMana = async clientFk => {
|
||||
let query = `SELECT vn.clientGetMana(?) AS mana`;
|
||||
let [mana] = await Self.rawSql(query, [clientFk]);
|
||||
|
||||
return mana;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,68 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('summary', {
|
||||
description: 'Returns a client summary',
|
||||
accessType: 'READ',
|
||||
accepts: [{
|
||||
arg: 'id',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'client id',
|
||||
http: {source: 'path'}
|
||||
}],
|
||||
returns: {
|
||||
type: [this.modelName],
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/:id/summary`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.summary = async clientFk => {
|
||||
let models = Self.app.models;
|
||||
let summaryObj = await getSummary(models.Client, clientFk);
|
||||
|
||||
summaryObj.mana = await models.Client.getMana(clientFk);
|
||||
summaryObj.debt = await models.Client.getDebt(clientFk);
|
||||
summaryObj.averageInvoiced = await models.Client.getAverageInvoiced(clientFk);
|
||||
summaryObj.totalGreuge = await models.Greuge.sumAmount(clientFk);
|
||||
summaryObj.recovery = await getRecoveries(models.Recovery, clientFk);
|
||||
|
||||
return summaryObj;
|
||||
};
|
||||
|
||||
async function getSummary(client, clientId) {
|
||||
let filter = {
|
||||
include: [
|
||||
{relation: 'account', scope: {fields: ['name', 'active']}},
|
||||
{relation: 'salesPerson', scope: {fields: ['name']}},
|
||||
{relation: 'country', scope: {fields: ['country']}},
|
||||
{relation: 'province', scope: {fields: ['name']}},
|
||||
{relation: 'contactChannel', scope: {fields: ['name']}},
|
||||
{relation: 'payMethod', scope: {fields: ['name']}},
|
||||
{
|
||||
relation: 'addresses',
|
||||
scope: {
|
||||
where: {isDefaultAddress: true},
|
||||
fields: ['nickname', 'street', 'city', 'postalCode']
|
||||
}
|
||||
}
|
||||
],
|
||||
where: {id: clientId}
|
||||
};
|
||||
|
||||
return await client.findOne(filter);
|
||||
}
|
||||
|
||||
async function getRecoveries(recovery, clientId) {
|
||||
let filter = {
|
||||
where: {
|
||||
and: [{clientFk: clientId}, {or: [{finished: null}, {finished: {gt: Date.now()}}]}]
|
||||
},
|
||||
limit: 1
|
||||
};
|
||||
|
||||
return await recovery.findOne(filter);
|
||||
}
|
||||
};
|
|
@ -16,6 +16,9 @@ module.exports = function(Self) {
|
|||
require('../methods/client/activeSalesPerson')(Self);
|
||||
require('../methods/client/addressesPropagateRe')(Self);
|
||||
require('../methods/client/getDebt')(Self);
|
||||
require('../methods/client/getMana')(Self);
|
||||
require('../methods/client/getAverageInvoiced')(Self);
|
||||
require('../methods/client/summary')(Self);
|
||||
|
||||
// Validations
|
||||
|
||||
|
|
Loading…
Reference in New Issue