Client summary & package

This commit is contained in:
Joan Sanchez 2018-03-27 15:06:22 +02:00
parent 6b390b72f8
commit 85810e2f7e
19 changed files with 217 additions and 110 deletions

View File

@ -1,5 +1,4 @@
import ngModule from '../module';
import './style.css';
export default class Controller {
constructor($http, $state) {

View File

@ -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>

View File

@ -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', {

View File

@ -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

View File

@ -0,0 +1,3 @@
vn-dialog vn-one {
min-width: 200px
}

View File

@ -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"
},

View File

@ -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: {

View File

@ -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,

View File

@ -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';

View File

@ -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);
}
};
};

View File

@ -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"
}

View File

@ -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;
};
};

View File

@ -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;
};
};

View File

@ -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;
};
};

View File

@ -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);
}
};

View File

@ -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