#1300-1301 client.risk

This commit is contained in:
Carlos Jimenez Ruiz 2019-04-05 13:20:34 +02:00
parent 5ae58f1d70
commit 837a7b08cc
12 changed files with 228 additions and 52 deletions

View File

@ -25,6 +25,7 @@ input[type=reset]::-moz-focus-inner {
a, .link { a, .link {
color: $color-font-link; color: $color-font-link;
text-decoration: none; text-decoration: none;
outline: 0
} }
.link { .link {
cursor: pointer; cursor: pointer;

View File

@ -36,13 +36,15 @@ module.exports = Self => {
r.payed, r.payed,
c.code company, c.code company,
r.created, r.created,
NULL ref, r.invoiceFk ref,
NULL debit, NULL debit,
r.amountPaid credit, r.amountPaid credit,
r.bankFk, r.bankFk,
u.nickname userNickname, u.nickname userNickname,
u.id userId,
r.clientFk, r.clientFk,
FALSE pdf FALSE pdf,
FALSE isInvoice
FROM vn.receipt r FROM vn.receipt r
LEFT JOIN vn.worker w ON w.id = r.workerFk LEFT JOIN vn.worker w ON w.id = r.workerFk
LEFT JOIN account.user u ON u.id = w.userFk LEFT JOIN account.user u ON u.id = w.userFk
@ -60,11 +62,14 @@ module.exports = Self => {
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL,
i.clientFk, i.clientFk,
i.pdf i.pdf,
TRUE isInvoice
FROM vn.invoiceOut i FROM vn.invoiceOut i
JOIN vn.company c ON c.id = i.companyFk JOIN vn.company c ON c.id = i.companyFk
WHERE i.clientFk = ? AND i.companyFk = ? WHERE i.clientFk = ? AND i.companyFk = ?
ORDER BY payed DESC, created DESC
) t ) t
ORDER BY payed DESC, created DESC`, [ ORDER BY payed DESC, created DESC`, [
params.clientFk, params.clientFk,

View File

@ -1,7 +1,7 @@
const app = require('vn-loopback/server/server'); const app = require('vn-loopback/server/server');
describe('receipt filter()', () => { describe('receipt filter()', () => {
it('should call the filter method', async () => { it('should return the receipts', async() => {
let filter = {limit: 20}; let filter = {limit: 20};
let params = { let params = {
clientFk: 101, clientFk: 101,

View File

@ -3,15 +3,13 @@
url="/client/api/receipts/filter" url="/client/api/receipts/filter"
params="$ctrl.params" params="$ctrl.params"
limit="20" limit="20"
data="$ctrl.risks" data="$ctrl.balances">
auto-load="true">
</vn-crud-model> </vn-crud-model>
<vn-crud-model <vn-crud-model
vn-id="riskModel" vn-id="riskModel"
url="/client/api/ClientRisks" url="/client/api/ClientRisks"
filter="$ctrl.filter" filter="$ctrl.filter"
data="riskTotal" data="$ctrl.riskTotal">
auto-load="true">
</vn-crud-model> </vn-crud-model>
<vn-vertical> <vn-vertical>
<vn-card pad-large> <vn-card pad-large>
@ -20,6 +18,7 @@
</vn-one> </vn-one>
<vn-one> <vn-one>
<vn-autocomplete vn-one <vn-autocomplete vn-one
vn-id="company"
field="$ctrl.companyFk" field="$ctrl.companyFk"
on-change="$ctrl.setOrder(value)" on-change="$ctrl.setOrder(value)"
url="/client/api/Companies" url="/client/api/Companies"
@ -29,9 +28,9 @@
</vn-autocomplete> </vn-autocomplete>
</vn-one> </vn-one>
<vn-one> <vn-one>
<div class="totalBox" ng-if="riskTotal.length"> <div class="totalBox" ng-if="$ctrl.riskTotal.length">
<h6 translate>Total by company</h6> <h6 translate>Total by company</h6>
<vn-auto ng-repeat="riskByCompany in riskTotal"> <vn-auto ng-repeat="riskByCompany in $ctrl.riskTotal">
<vn-label-value <vn-label-value
label="{{riskByCompany.company.code}}" label="{{riskByCompany.company.code}}"
value="{{riskByCompany.amount | currency: 'EUR':2}}"> value="{{riskByCompany.amount | currency: 'EUR':2}}">
@ -44,7 +43,7 @@
<vn-table model="model"> <vn-table model="model">
<vn-thead> <vn-thead>
<vn-tr> <vn-tr>
<vn-th>Date</vn-th> <vn-th default-order>Date</vn-th>
<vn-th>Creation date</vn-th> <vn-th>Creation date</vn-th>
<vn-th>Employee</vn-th> <vn-th>Employee</vn-th>
<vn-th>Reference</vn-th> <vn-th>Reference</vn-th>
@ -57,27 +56,37 @@
</vn-tr> </vn-tr>
</vn-thead> </vn-thead>
<vn-tbody> <vn-tbody>
<vn-tr ng-repeat="risk in $ctrl.risks"> <vn-tr ng-repeat="balance in $ctrl.balances">
<vn-td>{{::risk.payed | dateTime:'dd/MM/yyyy'}}</vn-td> <vn-td>{{::balance.payed | dateTime:'dd/MM/yyyy'}}</vn-td>
<vn-td>{{::risk.created | dateTime:'dd/MM/yyyy HH:mm'}}</vn-td> <vn-td>{{::balance.created | dateTime:'dd/MM/yyyy HH:mm'}}</vn-td>
<vn-td>{{::risk.userNickname}}</vn-td>
<vn-td> <vn-td>
<span ng-show="risk.ref" translate>BILL</span> {{::risk.ref}} <span
class="link"
ng-click="$ctrl.showWorkerDescriptor($event, balance.userId)">
{{::balance.userNickname}}
</span>
</vn-td> </vn-td>
<vn-td number>{{::risk.bankFk}}</vn-td> <vn-td>
<vn-td number>{{::risk.debit | currency: 'EUR':2}}</vn-td> <span
<vn-td number>{{::risk.credit | currency: 'EUR':2}}</vn-td> ng-class="{'link': balance.isInvoice}"
<vn-td number>{{risk.balance | currency: 'EUR':2}}</vn-td> ng-click="$ctrl.showInvoiceOutDescriptor($event, balance)"
ng-show="balance.ref">{{balance.isInvoice ? 'BILL' : balance.ref | translate: {ref: balance.ref} }}
</span>
</vn-td>
<vn-td number>{{::balance.bankFk}}</vn-td>
<vn-td number>{{::balance.debit | currency: 'EUR':2}}</vn-td>
<vn-td number>{{::balance.credit | currency: 'EUR':2}}</vn-td>
<vn-td number>{{balance.balance | currency: 'EUR':2}}</vn-td>
<vn-td center> <vn-td center>
<vn-check <vn-check
field="risk.isConciliate" field="balance.isConciliate"
disabled="true"> disabled="true">
</vn-check> </vn-check>
</vn-td> </vn-td>
<vn-td center> <vn-td center>
<a ng-show="risk.pdf" <a ng-show="balance.pdf"
target="_blank" target="_blank"
href="api/InvoiceOuts/{{::risk.id}}/download?access_token={{::$ctrl.accessToken}}"> href="api/InvoiceOuts/{{::balance.id}}/download?access_token={{::$ctrl.accessToken}}">
<vn-icon-button <vn-icon-button
icon="cloud_download" icon="cloud_download"
title="Download PDF"> title="Download PDF">
@ -104,3 +113,13 @@
<vn-client-risk-create vn-id="riskCreateDialog"> <vn-client-risk-create vn-id="riskCreateDialog">
</vn-client-risk-create> </vn-client-risk-create>
<vn-worker-descriptor-popover
vn-id="workerDescriptor"
user-id="$ctrl.selectedWorker">
</vn-worker-descriptor-popover>
<vn-invoice-out-descriptor-popover
vn-id="invoiceOutDescriptor"
invoice-out-id="$ctrl.selectedInvoiceOut">
</vn-invoice-out-descriptor-popover>

View File

@ -2,7 +2,8 @@ import ngModule from '../../module';
import './style.scss'; import './style.scss';
class Controller { class Controller {
constructor($stateParams, $translate, $scope, vnToken) { constructor($stateParams, $translate, $scope, vnToken, $http) {
this.$http = $http;
this.$ = $scope; this.$ = $scope;
this.$stateParams = $stateParams; this.$stateParams = $stateParams;
this.$translate = $translate; this.$translate = $translate;
@ -38,26 +39,46 @@ class Controller {
this.$.riskModel.refresh(); this.$.riskModel.refresh();
} }
set risks(value) { set balances(value) {
if (value) { this._balances = value;
for (let i = this.$.model.data.length - 1; i >= 0; i--) {
let row = this.$.model.data[i];
let tot;
if (i != this.$.model.data.length - 1)
row.balance = (row.credit - row.debit) + (this.$.model.data[i + 1].balance);
else
row.balance = row.credit - row.debit;
tot = tot + row.balance; if (!value) return;
} const params = {filter: this.filter};
this._risks = this.$.model.data; this.$http.get(`/client/api/ClientRisks`, {params}).then(response => {
if (response.data) {
this.riskTotal = response.data;
this.getBalances();
} }
});
} }
get risks() { get balances() {
return this._risks; return this._balances;
} }
getCurrentBalance() {
const selectedCompany = this.$.company.selection;
const currentBalance = this.riskTotal.find(balance => {
return balance.companyFk === selectedCompany.id;
});
return currentBalance.amount;
}
getBalances() {
this.balances.forEach((balance, index) => {
if (index === 0)
balance.balance = this.getCurrentBalance();
if (index > 0) {
let previousBalance = this.balances[index - 1];
balance.balance = previousBalance.balance - (previousBalance.debit - previousBalance.credit);
}
});
}
openCreateDialog() { openCreateDialog() {
this.$.riskCreateDialog.companyFk = this.companyFk; this.$.riskCreateDialog.companyFk = this.companyFk;
this.$.riskCreateDialog.onResponse = () => { this.$.riskCreateDialog.onResponse = () => {
@ -69,9 +90,32 @@ class Controller {
onDownload() { onDownload() {
alert('Not implemented yet'); alert('Not implemented yet');
} }
showWorkerDescriptor(event, userId) {
if (event.defaultPrevented) return;
event.preventDefault();
event.stopPropagation();
this.selectedWorker = userId;
this.$.workerDescriptor.parent = event.target;
this.$.workerDescriptor.show();
}
showInvoiceOutDescriptor(event, balance) {
if (!balance.isInvoice) return;
if (event.defaultPrevented) return;
event.preventDefault();
event.stopPropagation();
this.selectedInvoiceOut = balance.id;
this.$.invoiceOutDescriptor.parent = event.target;
this.$.invoiceOutDescriptor.show();
}
} }
Controller.$inject = ['$stateParams', '$translate', '$scope', 'vnToken']; Controller.$inject = ['$stateParams', '$translate', '$scope', 'vnToken', '$http'];
ngModule.component('vnClientRiskIndex', { ngModule.component('vnClientRiskIndex', {
template: require('./index.html'), template: require('./index.html'),

View File

@ -4,29 +4,40 @@ describe('Client', () => {
describe('Component vnClientRiskIndex', () => { describe('Component vnClientRiskIndex', () => {
let $componentController; let $componentController;
let $scope; let $scope;
let $httpBackend;
let $httpParamSerializer;
let controller; let controller;
beforeEach(ngModule('client')); beforeEach(ngModule('client'));
beforeEach(angular.mock.inject((_$componentController_, $rootScope) => { beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_, _$httpParamSerializer_) => {
$componentController = _$componentController_; $componentController = _$componentController_;
$httpBackend = _$httpBackend_;
$httpParamSerializer = _$httpParamSerializer_;
$scope = $rootScope.$new(); $scope = $rootScope.$new();
controller = $componentController('vnClientRiskIndex', {$scope}); controller = $componentController('vnClientRiskIndex', {$scope});
})); }));
describe('risks() setter', () => { describe('balances() setter', () => {
it('should calculate the balance for each line from the oldest date to the newest', () => { it('should calculate the balance for each line from the oldest date to the newest', () => {
let risks = [ controller.getCurrentBalance = jasmine.createSpy(controller, 'getCurrentBalance').and.returnValue(1000);
let balances = [
{credit: -100, debit: 0},
{credit: 0, debit: 300},
{credit: 100, debit: 0}, {credit: 100, debit: 0},
{credit: 100, debit: 0}, {credit: 0, debit: -300}
{credit: 0, debit: 300}
]; ];
controller.$.model = {data: risks}; const params = {filter: controller.filter};
controller.risks = risks; let serializedParams = $httpParamSerializer(params);
$httpBackend.when('GET', `/client/api/ClientRisks?${serializedParams}`).respond(balances);
$httpBackend.expect('GET', `/client/api/ClientRisks?${serializedParams}`);
controller.balances = balances;
$httpBackend.flush();
expect(controller.risks[0].balance).toEqual(-100); expect(controller.balances[0].balance).toEqual(1000);
expect(controller.risks[1].balance).toEqual(-200); expect(controller.balances[1].balance).toEqual(900);
expect(controller.risks[2].balance).toEqual(-300); expect(controller.balances[2].balance).toEqual(600);
expect(controller.balances[3].balance).toEqual(700);
}); });
}); });
}); });

View File

@ -8,4 +8,4 @@ Havings: Haber
Balance: Balance Balance: Balance
Total by company: Total por empresa Total by company: Total por empresa
Download PDF: Descargar PDF Download PDF: Descargar PDF
BILL: N/FRA BILL: N/FRA {{ref}}

View File

@ -3,7 +3,7 @@
"name": "Clients", "name": "Clients",
"icon": "icon-person", "icon": "icon-person",
"validations" : true, "validations" : true,
"dependencies": ["worker"], "dependencies": ["worker", "invoiceOut"],
"menu": [ "menu": [
{"state": "client.card.basicData", "icon": "settings"}, {"state": "client.card.basicData", "icon": "settings"},
{"state": "client.card.fiscalData", "icon": "account_balance"}, {"state": "client.card.fiscalData", "icon": "account_balance"},

View File

@ -0,0 +1,12 @@
<vn-popover vn-id="popover">
<vn-spinner
ng-if="$ctrl.invoiceOut == null"
style="padding: 1em;"
enable="true">
</vn-spinner>
<vn-invoice-out-descriptor
ng-if="$ctrl.invoiceOut"
invoice-out="$ctrl.invoiceOut"
quicklinks="$ctrl.quicklinks">
</vn-invoice-out-descriptor>
</vn-popover>

View File

@ -0,0 +1,72 @@
import ngModule from '../module';
import Component from 'core/lib/component';
import './style.scss';
class Controller extends Component {
constructor($element, $scope, $http, $timeout, $q) {
super($element, $scope);
this.$timeout = $timeout;
this.$http = $http;
this.$q = $q;
this.worker = null;
}
set invoiceOutId(id) {
if (id == this._invoiceOutId) return;
this._invoiceOutId = id;
this.invoiceOut = null;
this.loadData();
}
get invoiceOutId() {
return this._invoiceOutId;
}
set quicklinks(value = {}) {
this._quicklinks = Object.assign(value, this._quicklinks);
}
get quicklinks() {
return this._quicklinks;
}
show() {
this.$.popover.parent = this.parent;
this.$.popover.show();
}
loadData() {
let query = `api/InvoiceOuts/findOne`;
let filter = {
where: {
id: this._invoiceOutId
},
include: [
{
relation: 'company',
scope: {
fields: ['id', 'code']
}
}
]
};
this.$http.get(query, {params: {filter}}).then(res => {
this.invoiceOut = res.data;
this.$.$applyAsync(() => {
this.$.popover.relocate();
});
});
}
}
Controller.$inject = ['$element', '$scope', '$http', '$timeout', '$q'];
ngModule.component('vnInvoiceOutDescriptorPopover', {
template: require('./index.html'),
controller: Controller,
bindings: {
invoiceOutId: '<',
quicklinks: '<'
}
});

View File

@ -0,0 +1,11 @@
vn-ticket-descriptor-popover {
vn-ticket-descriptor {
display: block;
width: 16em;
max-height: 28em;
& > vn-card {
margin: 0!important;
}
}
}

View File

@ -5,3 +5,4 @@ import './search-panel';
import './summary'; import './summary';
import './card'; import './card';
import './descriptor'; import './descriptor';
import './descriptor-popover';