3622-feat(client_defaulter): implemented smart-table #881

Merged
joan merged 9 commits from 3622-client_defaulter into dev 2022-03-02 09:17:08 +00:00
5 changed files with 209 additions and 133 deletions
Showing only changes of commit 812d79f2d5 - Show all commits

View File

@ -99,6 +99,11 @@ smart-table table {
} }
} }
} }
& > td > textarea {
background-color: $color-font-light;
color: $color-font-bg;
width: 90%;
}
} }
.vn-check { .vn-check {
margin: 0; margin: 0;

View File

@ -58,16 +58,16 @@ module.exports = Self => {
DISTINCT c.id clientFk, DISTINCT c.id clientFk,
c.name clientName, c.name clientName,
c.salesPersonFk, c.salesPersonFk,
u.name salesPersonName, u.nickname salesPersonName,
d.amount, d.amount,
co.created, co.created,
CONCAT(DATE(co.created), ' ', co.text) observation, CONCAT(DATE(co.created), ' ', co.text) observation,
uw.id workerFk, uw.id workerFk,
uw.name workerName, uw.nickname workerName,
c.creditInsurance, c.creditInsurance,
d.defaulterSinced d.defaulterSinced
FROM vn.defaulter d FROM vn.defaulter d
JOIN vn.client c ON c.id = d.clientFk JOIN vn.client c ON c.id = d.clientFk
LEFT JOIN vn.clientObservation co ON co.clientFk = c.id LEFT JOIN vn.clientObservation co ON co.clientFk = c.id
LEFT JOIN account.user u ON u.id = c.salesPersonFk LEFT JOIN account.user u ON u.id = c.salesPersonFk
LEFT JOIN account.user uw ON uw.id = co.workerFk LEFT JOIN account.user uw ON uw.id = co.workerFk

View File

@ -15,17 +15,18 @@
model="model"> model="model">
</vn-searchbar> </vn-searchbar>
</vn-portal> </vn-portal>
<vn-data-viewer <vn-card>
model="model" <smart-table
class="vn-w-xl"> model="model"
<vn-card> options="$ctrl.smartTableOptions"
<vn-tool-bar> expr-builder="$ctrl.exprBuilder(param, value)">
<div class="vn-pa-md"> <slot-actions>
<div>
<div class="totalBox" style="text-align: center;"> <div class="totalBox" style="text-align: center;">
<h6 translate>Total</h6> <h6 translate>Total</h6>
<vn-label-value <vn-label-value
label="Balance due" label="Balance due"
value="{{$ctrl.balanceDueTotal}}"> value="{{$ctrl.balanceDueTotal | currency: 'EUR': 2}}">
</vn-label-value> </vn-label-value>
</div> </div>
</div> </div>
@ -38,90 +39,98 @@
icon="icon-notes"> icon="icon-notes">
</vn-button> </vn-button>
</div> </div>
</vn-tool-bar> </slot-actions>
<vn-table model="model"> <slot-table>
<vn-thead> <table>
<vn-tr> <thead>
<vn-th shrink> <tr>
<vn-multi-check <th shrink>
model="model"> <vn-multi-check
</vn-multi-check> model="model">
</vn-th> </vn-multi-check>
<vn-th field="clientName">Client</vn-th> </th>
<vn-th field="salesPersonFk">Comercial</vn-th> <th field="clientName">
<vn-th <span translate>Client</span>
field="amount" </th>
vn-tooltip="Balance due" <th field="salesPersonFk">
number> <span translate>Comercial</span>
Balance D. </th>
</vn-th> <th
<vn-th field="amount"
vn-tooltip="Worker who made the last observation" vn-tooltip="Balance due">
shrink> <span translate>Balance D.</span>
Author </th>
</vn-th> <th
<vn-th expand>Last observation</vn-th> field="workerFk"
<vn-th vn-tooltip="Worker who made the last observation">
vn-tooltip="Credit insurance" <span translate>Author</span>
number> </th>
Credit I. <th field="observation">
</vn-th> <span translate>Last observation</span>
<vn-th shrink-datetime>From</vn-th> </th>
</vn-tr> <th
</vn-thead> vn-tooltip="Credit insurance"
<vn-tbody> field="creditInsurance" >
<vn-tr ng-repeat="defaulter in defaulters"> <span translate>Credit I.</span>
<vn-td shrink> </th>
<vn-check <th field="defaulterSinced">
ng-model="defaulter.checked" <span translate>From</span>
vn-click-stop> </th>
</vn-check> </tr>
</vn-td> </thead>
<vn-td> <tbody>
<span <tr ng-repeat="defaulter in defaulters">
vn-click-stop="clientDescriptor.show($event, defaulter.clientFk)" <td shrink>
title ="{{::defaulter.clientName}}" <vn-check
class="link"> ng-model="defaulter.checked"
{{::defaulter.clientName}} vn-click-stop>
</span> </vn-check>
</vn-td> </td>
<vn-td> <td title="{{::defaulter.clientName}}">
<span <span
title="{{::defaulter.salesPersonName}}" vn-click-stop="clientDescriptor.show($event, defaulter.clientFk)"
vn-click-stop="workerDescriptor.show($event, defaulter.salesPersonFk)" title ="{{::defaulter.clientName}}"
class="link" > class="link">
{{::defaulter.salesPersonName | dashIfEmpty}} {{::defaulter.clientName}}
</span> </span>
</vn-td> </td>
<vn-td number>{{::defaulter.amount}}</vn-td> <td>
<vn-td shrink> <span
<span title="{{::defaulter.salesPersonName}}"
title="{{::defaulter.workerName}}" vn-click-stop="workerDescriptor.show($event, defaulter.salesPersonFk)"
vn-click-stop="workerDescriptor.show($event, defaulter.workerFk)" class="link">
class="link" > {{::defaulter.salesPersonName | dashIfEmpty}}
{{::defaulter.workerName | dashIfEmpty}} </span>
</span> </td>
</vn-td> <td>{{::defaulter.amount | currency: 'EUR': 2}}</td>
<vn-td expand> <td>
<vn-textarea <span
vn-three title="{{::defaulter.workerName}}"
disabled="true" vn-click-stop="workerDescriptor.show($event, defaulter.workerFk)"
label="Observation" class="link">
ng-model="defaulter.observation"> {{::defaulter.workerName | dashIfEmpty}}
</vn-textarea> </span>
</vn-td> </td>
<vn-td number>{{::defaulter.creditInsurance}}</vn-td> <td>
<vn-td shrink-datetime>{{::defaulter.defaulterSinced | date: 'dd/MM/yyyy'}}</vn-td> <textarea
</vn-tr> disabled="true"
</vn-tbody> class="chip {{::$ctrl.chipColor(defaulter.created)}}"
</vn-table> ng-model="defaulter.observation">
</vn-card> </textarea>
</vn-data-viewer> </td>
<td>{{::defaulter.creditInsurance | currency: 'EUR': 2}}</td>
<td>{{::defaulter.defaulterSinced | date: 'dd/MM/yyyy'}}</td>
</tr>
</tbody>
</table>
</slot-table>
</smart-table>
</vn-card>
<vn-client-descriptor-popover <vn-client-descriptor-popover
vn-id="clientDescriptor"> vn-id="client-descriptor">
</vn-client-descriptor-popover> </vn-client-descriptor-popover>
<vn-worker-descriptor-popover <vn-worker-descriptor-popover
vn-id="workerDescriptor"> vn-id="worker-descriptor">
</vn-worker-descriptor-popover> </vn-worker-descriptor-popover>
<vn-popup vn-id="dialog-summary-client"> <vn-popup vn-id="dialog-summary-client">
<vn-client-summary <vn-client-summary
@ -129,37 +138,6 @@
</vn-client-summary> </vn-client-summary>
</vn-popup> </vn-popup>
<!--Context menu-->
<vn-contextmenu vn-id="contextmenu" targets="['vn-data-viewer']" model="model"
expr-builder="$ctrl.exprBuilder(param, value)">
<slot-menu>
<vn-item translate
ng-if="contextmenu.isFilterAllowed()"
ng-click="contextmenu.filterBySelection()">
Filter by selection
</vn-item>
<vn-item translate
ng-if="contextmenu.isFilterAllowed()"
ng-click="contextmenu.excludeSelection()">
Exclude selection
</vn-item>
<vn-item translate
ng-if="contextmenu.isFilterAllowed()"
ng-click="contextmenu.removeFilter()">
Remove filter
</vn-item>
<vn-item translate
ng-click="contextmenu.removeAllFilters()">
Remove all filters
</vn-item>
<vn-item translate
ng-if="contextmenu.isActionAllowed()"
ng-click="contextmenu.copyValue()">
Copy value
</vn-item>
</slot-menu>
</vn-contextmenu>
<!-- Dialog of add notes button --> <!-- Dialog of add notes button -->
<vn-dialog <vn-dialog
vn-id="notesDialog" vn-id="notesDialog"

View File

@ -6,17 +6,70 @@ export default class Controller extends Section {
constructor($element, $) { constructor($element, $) {
super($element, $); super($element, $);
this.defaulter = {}; this.defaulter = {};
this.smartTableOptions = {
activeButtons: {
search: true
},
columns: [
{
field: 'clientName',
autocomplete: {
url: 'Clients',
showField: 'name',
valueField: 'name'
}
},
{
field: 'salesPersonFk',
autocomplete: {
url: 'Workers/activeWithInheritedRole',
where: `{role: 'salesPerson'}`,
searchFunction: '{firstName: $search}',
showField: 'nickname',
valueField: 'id',
}
},
{
field: 'amount',
searchable: false
},
{
field: 'workerFk',
autocomplete: {
url: 'Workers/activeWithInheritedRole',
where: `{role: 'salesPerson'}`,
searchFunction: '{firstName: $search}',
showField: 'nickname',
alexm marked this conversation as resolved
Review

Disable search by observation

Disable search by observation
valueField: 'id',
}
},
{
field: 'observation',
autocomplete: {
url: 'Defaulters/filter',
showField: 'observation',
valueField: 'observation',
}
},
{
field: 'creditInsurance',
searchable: false
},
{
field: 'defaulterSinced',
searchable: false
}
]
};
} }
get balanceDueTotal() { get balanceDueTotal() {
let balanceDueTotal = 0; let balanceDueTotal = 0;
const defaulters = this.$.model.data || [];
if (this.checked.length > 0) { for (let defaulter of defaulters)
for (let defaulter of this.checked) balanceDueTotal += defaulter.amount;
balanceDueTotal += defaulter.amount;
return balanceDueTotal;
}
return balanceDueTotal; return balanceDueTotal;
} }
@ -32,6 +85,22 @@ export default class Controller extends Section {
return checkedLines; return checkedLines;
} }
chipColor(date) {
const day = 24 * 60 * 60 * 1000;
const today = new Date();
today.setHours(0, 0, 0, 0);
const observationShipped = new Date(date);
observationShipped.setHours(0, 0, 0, 0);
const difference = today - observationShipped;
if (difference > (day * 20))
return 'alert';
if (difference > (day * 10))
return 'warning';
}
onResponse() { onResponse() {
if (!this.defaulter.observation) if (!this.defaulter.observation)
throw new UserError(`The message can't be empty`); throw new UserError(`The message can't be empty`);
@ -52,7 +121,10 @@ export default class Controller extends Section {
exprBuilder(param, value) { exprBuilder(param, value) {
switch (param) { switch (param) {
case 'observation':
return {[`observation`]: value};
case 'clientName': case 'clientName':
case 'workerFk':
case 'salesPersonFk': case 'salesPersonFk':
return {[`d.${param}`]: value}; return {[`d.${param}`]: value};
} }

View File

@ -39,11 +39,7 @@ describe('client defaulter', () => {
describe('balanceDueTotal() getter', () => { describe('balanceDueTotal() getter', () => {
it('should return balance due total', () => { it('should return balance due total', () => {
const data = controller.$.model.data; const data = controller.$.model.data;
data[1].checked = true; const expectedAmount = data[0].amount + data[1].amount + data[2].amount;
data[2].checked = true;
const checkedRows = controller.checked;
const expectedAmount = checkedRows[0].amount + checkedRows[1].amount;
const result = controller.balanceDueTotal; const result = controller.balanceDueTotal;
@ -51,6 +47,31 @@ describe('client defaulter', () => {
}); });
}); });
describe('chipColor()', () => {
it('should return undefined when the date is the present', () => {
let today = new Date();
let result = controller.chipColor(today);
expect(result).toEqual(undefined);
});
it('should return warning when the date is 10 days in the past', () => {
let pastDate = new Date();
pastDate = pastDate.setDate(pastDate.getDate() - 11);
let result = controller.chipColor(pastDate);
expect(result).toEqual('warning');
});
it('should return alert when the date is 20 days in the past', () => {
let pastDate = new Date();
pastDate = pastDate.setDate(pastDate.getDate() - 21);
let result = controller.chipColor(pastDate);
expect(result).toEqual('alert');
});
});
describe('onResponse()', () => { describe('onResponse()', () => {
it('should return error for empty message', () => { it('should return error for empty message', () => {
let error; let error;