#1300-1301 client.risk
This commit is contained in:
parent
5ae58f1d70
commit
837a7b08cc
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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>
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller.$inject = ['$stateParams', '$translate', '$scope', 'vnToken'];
|
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', '$http'];
|
||||||
|
|
||||||
ngModule.component('vnClientRiskIndex', {
|
ngModule.component('vnClientRiskIndex', {
|
||||||
template: require('./index.html'),
|
template: require('./index.html'),
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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}}
|
|
@ -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"},
|
||||||
|
|
|
@ -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>
|
|
@ -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: '<'
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,11 @@
|
||||||
|
vn-ticket-descriptor-popover {
|
||||||
|
vn-ticket-descriptor {
|
||||||
|
display: block;
|
||||||
|
width: 16em;
|
||||||
|
max-height: 28em;
|
||||||
|
|
||||||
|
& > vn-card {
|
||||||
|
margin: 0!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,3 +5,4 @@ import './search-panel';
|
||||||
import './summary';
|
import './summary';
|
||||||
import './card';
|
import './card';
|
||||||
import './descriptor';
|
import './descriptor';
|
||||||
|
import './descriptor-popover';
|
||||||
|
|
Loading…
Reference in New Issue