#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 {
|
||||
color: $color-font-link;
|
||||
text-decoration: none;
|
||||
outline: 0
|
||||
}
|
||||
.link {
|
||||
cursor: pointer;
|
||||
|
|
|
@ -36,13 +36,15 @@ module.exports = Self => {
|
|||
r.payed,
|
||||
c.code company,
|
||||
r.created,
|
||||
NULL ref,
|
||||
r.invoiceFk ref,
|
||||
NULL debit,
|
||||
r.amountPaid credit,
|
||||
r.bankFk,
|
||||
u.nickname userNickname,
|
||||
u.id userId,
|
||||
r.clientFk,
|
||||
FALSE pdf
|
||||
FALSE pdf,
|
||||
FALSE isInvoice
|
||||
FROM vn.receipt r
|
||||
LEFT JOIN vn.worker w ON w.id = r.workerFk
|
||||
LEFT JOIN account.user u ON u.id = w.userFk
|
||||
|
@ -60,11 +62,14 @@ module.exports = Self => {
|
|||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
i.clientFk,
|
||||
i.pdf
|
||||
i.pdf,
|
||||
TRUE isInvoice
|
||||
FROM vn.invoiceOut i
|
||||
JOIN vn.company c ON c.id = i.companyFk
|
||||
WHERE i.clientFk = ? AND i.companyFk = ?
|
||||
ORDER BY payed DESC, created DESC
|
||||
) t
|
||||
ORDER BY payed DESC, created DESC`, [
|
||||
params.clientFk,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
describe('receipt filter()', () => {
|
||||
it('should call the filter method', async () => {
|
||||
it('should return the receipts', async() => {
|
||||
let filter = {limit: 20};
|
||||
let params = {
|
||||
clientFk: 101,
|
||||
|
|
|
@ -3,15 +3,13 @@
|
|||
url="/client/api/receipts/filter"
|
||||
params="$ctrl.params"
|
||||
limit="20"
|
||||
data="$ctrl.risks"
|
||||
auto-load="true">
|
||||
data="$ctrl.balances">
|
||||
</vn-crud-model>
|
||||
<vn-crud-model
|
||||
vn-id="riskModel"
|
||||
url="/client/api/ClientRisks"
|
||||
filter="$ctrl.filter"
|
||||
data="riskTotal"
|
||||
auto-load="true">
|
||||
data="$ctrl.riskTotal">
|
||||
</vn-crud-model>
|
||||
<vn-vertical>
|
||||
<vn-card pad-large>
|
||||
|
@ -20,6 +18,7 @@
|
|||
</vn-one>
|
||||
<vn-one>
|
||||
<vn-autocomplete vn-one
|
||||
vn-id="company"
|
||||
field="$ctrl.companyFk"
|
||||
on-change="$ctrl.setOrder(value)"
|
||||
url="/client/api/Companies"
|
||||
|
@ -29,9 +28,9 @@
|
|||
</vn-autocomplete>
|
||||
</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>
|
||||
<vn-auto ng-repeat="riskByCompany in riskTotal">
|
||||
<vn-auto ng-repeat="riskByCompany in $ctrl.riskTotal">
|
||||
<vn-label-value
|
||||
label="{{riskByCompany.company.code}}"
|
||||
value="{{riskByCompany.amount | currency: 'EUR':2}}">
|
||||
|
@ -44,7 +43,7 @@
|
|||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th>Date</vn-th>
|
||||
<vn-th default-order>Date</vn-th>
|
||||
<vn-th>Creation date</vn-th>
|
||||
<vn-th>Employee</vn-th>
|
||||
<vn-th>Reference</vn-th>
|
||||
|
@ -57,27 +56,37 @@
|
|||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="risk in $ctrl.risks">
|
||||
<vn-td>{{::risk.payed | dateTime:'dd/MM/yyyy'}}</vn-td>
|
||||
<vn-td>{{::risk.created | dateTime:'dd/MM/yyyy HH:mm'}}</vn-td>
|
||||
<vn-td>{{::risk.userNickname}}</vn-td>
|
||||
<vn-tr ng-repeat="balance in $ctrl.balances">
|
||||
<vn-td>{{::balance.payed | dateTime:'dd/MM/yyyy'}}</vn-td>
|
||||
<vn-td>{{::balance.created | dateTime:'dd/MM/yyyy HH:mm'}}</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 number>{{::risk.bankFk}}</vn-td>
|
||||
<vn-td number>{{::risk.debit | currency: 'EUR':2}}</vn-td>
|
||||
<vn-td number>{{::risk.credit | currency: 'EUR':2}}</vn-td>
|
||||
<vn-td number>{{risk.balance | currency: 'EUR':2}}</vn-td>
|
||||
<vn-td>
|
||||
<span
|
||||
ng-class="{'link': balance.isInvoice}"
|
||||
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-check
|
||||
field="risk.isConciliate"
|
||||
field="balance.isConciliate"
|
||||
disabled="true">
|
||||
</vn-check>
|
||||
</vn-td>
|
||||
<vn-td center>
|
||||
<a ng-show="risk.pdf"
|
||||
<a ng-show="balance.pdf"
|
||||
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
|
||||
icon="cloud_download"
|
||||
title="Download PDF">
|
||||
|
@ -104,3 +113,13 @@
|
|||
|
||||
<vn-client-risk-create vn-id="riskCreateDialog">
|
||||
</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';
|
||||
|
||||
class Controller {
|
||||
constructor($stateParams, $translate, $scope, vnToken) {
|
||||
constructor($stateParams, $translate, $scope, vnToken, $http) {
|
||||
this.$http = $http;
|
||||
this.$ = $scope;
|
||||
this.$stateParams = $stateParams;
|
||||
this.$translate = $translate;
|
||||
|
@ -38,26 +39,46 @@ class Controller {
|
|||
this.$.riskModel.refresh();
|
||||
}
|
||||
|
||||
set risks(value) {
|
||||
if (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;
|
||||
set balances(value) {
|
||||
this._balances = value;
|
||||
|
||||
tot = tot + row.balance;
|
||||
}
|
||||
this._risks = this.$.model.data;
|
||||
if (!value) return;
|
||||
const params = {filter: this.filter};
|
||||
this.$http.get(`/client/api/ClientRisks`, {params}).then(response => {
|
||||
if (response.data) {
|
||||
this.riskTotal = response.data;
|
||||
|
||||
this.getBalances();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get risks() {
|
||||
return this._risks;
|
||||
get balances() {
|
||||
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() {
|
||||
this.$.riskCreateDialog.companyFk = this.companyFk;
|
||||
this.$.riskCreateDialog.onResponse = () => {
|
||||
|
@ -69,9 +90,32 @@ class Controller {
|
|||
onDownload() {
|
||||
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', {
|
||||
template: require('./index.html'),
|
||||
|
|
|
@ -4,29 +4,40 @@ describe('Client', () => {
|
|||
describe('Component vnClientRiskIndex', () => {
|
||||
let $componentController;
|
||||
let $scope;
|
||||
let $httpBackend;
|
||||
let $httpParamSerializer;
|
||||
let controller;
|
||||
|
||||
beforeEach(ngModule('client'));
|
||||
|
||||
beforeEach(angular.mock.inject((_$componentController_, $rootScope) => {
|
||||
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_, _$httpParamSerializer_) => {
|
||||
$componentController = _$componentController_;
|
||||
$httpBackend = _$httpBackend_;
|
||||
$httpParamSerializer = _$httpParamSerializer_;
|
||||
$scope = $rootScope.$new();
|
||||
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', () => {
|
||||
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: 0, debit: 300}
|
||||
{credit: 0, debit: -300}
|
||||
];
|
||||
controller.$.model = {data: risks};
|
||||
controller.risks = risks;
|
||||
const params = {filter: controller.filter};
|
||||
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.risks[1].balance).toEqual(-200);
|
||||
expect(controller.risks[2].balance).toEqual(-300);
|
||||
expect(controller.balances[0].balance).toEqual(1000);
|
||||
expect(controller.balances[1].balance).toEqual(900);
|
||||
expect(controller.balances[2].balance).toEqual(600);
|
||||
expect(controller.balances[3].balance).toEqual(700);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,4 +8,4 @@ Havings: Haber
|
|||
Balance: Balance
|
||||
Total by company: Total por empresa
|
||||
Download PDF: Descargar PDF
|
||||
BILL: N/FRA
|
||||
BILL: N/FRA {{ref}}
|
|
@ -3,7 +3,7 @@
|
|||
"name": "Clients",
|
||||
"icon": "icon-person",
|
||||
"validations" : true,
|
||||
"dependencies": ["worker"],
|
||||
"dependencies": ["worker", "invoiceOut"],
|
||||
"menu": [
|
||||
{"state": "client.card.basicData", "icon": "settings"},
|
||||
{"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 './card';
|
||||
import './descriptor';
|
||||
import './descriptor-popover';
|
||||
|
|
Loading…
Reference in New Issue