Merge branch '2970-smart-table' of https://gitea.verdnatura.es/verdnatura/salix into 2970-smart-table
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Joan Sanchez 2021-11-11 17:19:07 +01:00
commit c40a73b891
10 changed files with 238 additions and 295 deletions

View File

@ -8,6 +8,6 @@ comment 'The default configuration of columns for views';
INSERT INTO `salix`.`defaultViewConfig` (tableCode, columns) INSERT INTO `salix`.`defaultViewConfig` (tableCode, columns)
VALUES VALUES
('itemsIndex', '{"intrastat":false,"stemMultiplier":false}'), ('itemsIndex', '{"intrastat":false,"stemMultiplier":false}'),
('latestBuys', '{"intrastat":false,"description":false,"density":false,"isActive":false,"freightValue":false,"packageValue":false,"isIgnored":false,"price2":false,"minPrice":false,"ektFk":false,"weight":false}'); ('latestBuys', '{"intrastat":false,"description":false,"density":false,"isActive":false,"freightValue":false,"packageValue":false,"isIgnored":false,"price2":false,"minPrice":true,"ektFk":false,"weight":false,"id":true,"packing":true,"grouping":true,"quantity":true,"size":false,"name":true,"code":true,"origin":true,"family":true,"entryFk":true,"buyingValue":true,"comissionValue":false,"price3":true,"packageFk":true,"packingOut":true}');

View File

@ -145,9 +145,8 @@ export default class MultiCheck extends FormInput {
toggle() { toggle() {
const data = this.model.data; const data = this.model.data;
if (!data) return; if (!data) return;
data.forEach(el => { for (let el of data)
el[this.checkField] = this.checkAll; el[this.checkField] = this.checkAll;
});
} }
} }
@ -158,6 +157,7 @@ ngModule.vnComponent('vnMultiCheck', {
model: '<', model: '<',
checkField: '@?', checkField: '@?',
checkAll: '=?', checkAll: '=?',
checked: '=?',
disabled: '<?' disabled: '<?'
} }
}); });

View File

@ -128,7 +128,8 @@ async function launchBackTest(done) {
if (err) if (err)
throw err; throw err;
} }
launchBackTest.description = `Runs the backend tests once using a random container, can receive --ci arg to save reports on a xml file`; launchBackTest.description = `
Runs the backend tests once using a random container, can receive --ci arg to save reports on a xml file`;
// Backend tests // Backend tests

View File

@ -63,8 +63,21 @@ describe('Entry', () => {
} }
]}`; ]}`;
const expectedBuys = [ const expectedBuys = [
{'buyingValue': 5.77, 'description': 'Bow', 'grouping': 1, 'packing': 1, 'size': 1, 'volume': 1200}, {
{'buyingValue': 2.16, 'description': 'Arrow', 'grouping': 1, 'packing': 1, 'size': 25, 'volume': 1125} 'buyingValue': 5.77,
'description': 'Bow',
'grouping': 1,
'packing': 1,
'size': 1,
'volume': 1200},
{
'buyingValue': 2.16,
'description': 'Arrow',
'grouping': 1,
'packing': 1,
'size': 25,
'volume': 1125}
]; ];
controller.fillData(rawData); controller.fillData(rawData);
controller.$.$apply(); controller.$.$apply();
@ -81,8 +94,21 @@ describe('Entry', () => {
describe('fetchBuys()', () => { describe('fetchBuys()', () => {
it(`should perform a query to fetch the buys data`, () => { it(`should perform a query to fetch the buys data`, () => {
const buys = [ const buys = [
{'buyingValue': 5.77, 'description': 'Bow', 'grouping': 1, 'packing': 1, 'size': 1, 'volume': 1200}, {
{'buyingValue': 2.16, 'description': 'Arrow', 'grouping': 1, 'packing': 1, 'size': 25, 'volume': 1125} 'buyingValue': 5.77,
'description': 'Bow',
'grouping': 1,
'packing': 1,
'size': 1,
'volume': 1200},
{
'buyingValue': 2.16,
'description': 'Arrow',
'grouping': 1,
'packing': 1,
'size': 25,
'volume': 1125}
]; ];
const serializedParams = $httpParamSerializer({buys}); const serializedParams = $httpParamSerializer({buys});
@ -105,17 +131,31 @@ describe('Entry', () => {
observation: '123456', observation: '123456',
ref: '1, 2', ref: '1, 2',
buys: [ buys: [
{'buyingValue': 5.77, 'description': 'Bow', 'grouping': 1, 'packing': 1, 'size': 1, 'volume': 1200}, {
{'buyingValue': 2.16, 'description': 'Arrow', 'grouping': 1, 'packing': 1, 'size': 25, 'volume': 1125} 'buyingValue': 5.77,
'description': 'Bow',
'grouping': 1,
'packing': 1,
'size': 1,
'volume': 1200},
{
'buyingValue': 2.16,
'description': 'Arrow',
'grouping': 1,
'packing': 1,
'size': 25,
'volume': 1125}
] ]
}; };
controller.onSubmit(); controller.onSubmit();
expect(controller.vnApp.showError).toHaveBeenCalledWith(`Some of the imported buys doesn't have an item`); const message = `Some of the imported buys doesn't have an item`;
expect(controller.vnApp.showError).toHaveBeenCalledWith(message);
}); });
it(`should perform a query to update columns`, () => { it(`should now perform a query to update columns`, () => {
jest.spyOn(controller.vnApp, 'showSuccess'); jest.spyOn(controller.vnApp, 'showSuccess');
controller.$state.go = jest.fn(); controller.$state.go = jest.fn();
@ -123,8 +163,22 @@ describe('Entry', () => {
observation: '123456', observation: '123456',
ref: '1, 2', ref: '1, 2',
buys: [ buys: [
{'itemFk': 10, 'buyingValue': 5.77, 'description': 'Bow', 'grouping': 1, 'packing': 1, 'size': 1, 'volume': 1200}, {
{'itemFk': 11, 'buyingValue': 2.16, 'description': 'Arrow', 'grouping': 1, 'packing': 1, 'size': 25, 'volume': 1125} 'itemFk': 10,
'buyingValue': 5.77,
'description': 'Bow',
'grouping': 1,
'packing': 1,
'size': 1,
'volume': 1200},
{
'itemFk': 11,
'buyingValue': 2.16,
'description': 'Arrow',
'grouping': 1,
'packing': 1,
'size': 25,
'volume': 1125}
] ]
}; };
const params = controller.import; const params = controller.import;

View File

@ -27,7 +27,8 @@
<thead> <thead>
<tr> <tr>
<th shrink> <th shrink>
<vn-multi-check <vn-multi-check
checked="$ctrl.checkAll"
model="model" model="model"
check-field="$checked"> <!-- Change $checked as default prop --> check-field="$checked"> <!-- Change $checked as default prop -->
</vn-multi-check> </vn-multi-check>

View File

@ -6,6 +6,7 @@ export default class Controller extends Section {
constructor($element, $) { constructor($element, $) {
super($element, $); super($element, $);
this.editedColumn; this.editedColumn;
this.$checkAll = false;
this.smartTableOptions = { this.smartTableOptions = {
activeButtons: { activeButtons: {
@ -130,11 +131,7 @@ export default class Controller extends Section {
} }
uncheck() { uncheck() {
const lines = this.checked; this.checkAll = false;
for (let line of lines) {
if (line.checked)
line.checked = false;
}
} }
get totalChecked() { get totalChecked() {
@ -146,7 +143,7 @@ export default class Controller extends Section {
for (let row of this.checked) for (let row of this.checked)
rowsToEdit.push({id: row.id, itemFk: row.itemFk}); rowsToEdit.push({id: row.id, itemFk: row.itemFk});
let data = { const data = {
field: this.editedColumn.field, field: this.editedColumn.field,
newValue: this.editedColumn.newValue, newValue: this.editedColumn.newValue,
lines: rowsToEdit lines: rowsToEdit

View File

@ -7,9 +7,9 @@ describe('Entry', () => {
beforeEach(ngModule('entry')); beforeEach(ngModule('entry'));
beforeEach(angular.mock.inject(($componentController, $compile, $rootScope, _$httpBackend_) => { beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_) => {
$httpBackend = _$httpBackend_; $httpBackend = _$httpBackend_;
let $element = $compile('<vn-entry-latest-buys></vn-entry-latest-buys')($rootScope); const $element = angular.element('<vn-entry-latest-buys></vn-entry-latest-buys');
controller = $componentController('vnEntryLatestBuys', {$element}); controller = $componentController('vnEntryLatestBuys', {$element});
controller.$ = { controller.$ = {
model: {refresh: () => {}}, model: {refresh: () => {}},
@ -31,10 +31,10 @@ describe('Entry', () => {
describe('get checked', () => { describe('get checked', () => {
it(`should return a set of checked lines`, () => { it(`should return a set of checked lines`, () => {
controller.$.model.data = [ controller.$.model.data = [
{checked: true, id: 1}, {$checked: true, id: 1},
{checked: true, id: 2}, {$checked: true, id: 2},
{checked: true, id: 3}, {$checked: true, id: 3},
{checked: false, id: 4}, {$checked: false, id: 4},
]; ];
let result = controller.checked; let result = controller.checked;
@ -43,38 +43,10 @@ describe('Entry', () => {
}); });
}); });
describe('uncheck()', () => {
it(`should clear the selection of lines on the controller`, () => {
controller.$.model.data = [
{checked: true, id: 1},
{checked: true, id: 2},
{checked: true, id: 3},
{checked: false, id: 4},
];
let result = controller.checked;
expect(result.length).toEqual(3);
controller.uncheck();
result = controller.checked;
expect(result.length).toEqual(0);
});
});
describe('onEditAccept()', () => { describe('onEditAccept()', () => {
it(`should perform a query to update columns`, () => { it(`should perform a query to update columns`, () => {
$httpBackend.whenGET('UserConfigViews/getConfig?tableCode=latestBuys').respond([]);
$httpBackend.whenGET('Buys/latestBuysFilter?filter=%7B%22limit%22:20%7D').respond([
{entryFk: 1},
{entryFk: 2},
{entryFk: 3},
{entryFk: 4}
]);
controller.editedColumn = {field: 'my field', newValue: 'the new value'}; controller.editedColumn = {field: 'my field', newValue: 'the new value'};
let query = 'Buys/editLatestBuys'; const query = 'Buys/editLatestBuys';
$httpBackend.expectPOST(query).respond(); $httpBackend.expectPOST(query).respond();
controller.onEditAccept(); controller.onEditAccept();

View File

@ -1,187 +1,155 @@
<vn-auto-search <vn-auto-search
model="model"> model="model">
</vn-auto-search> </vn-auto-search>
<vn-card> <vn-data-viewer
<smart-table model="model"
model="model" class="vn-mb-xl vn-w-xl">
view-config-id="ticketIndex" <vn-card>
options="$ctrl.smartTableOptions" <vn-table model="model">
auto-save="true" <vn-thead>
expr-builder="$ctrl.exprBuilder(param, value)" <vn-tr>
default-new-data="$ctrl.defaultNewData()"> <vn-th shrink>
<slot-table> <vn-multi-check
<table class="vn-table"> model="model">
<thead> </vn-multi-check>
<tr> </vn-th>
<th shrink> <vn-th class="icon-field"></vn-th>
<vn-multi-check <vn-th field="id">Id</vn-th>
model="model" <vn-th field="salesPersonFk" class="expendable">Salesperson</vn-th>
check-field="$checked"> <!-- Change $checked as default prop --> <vn-th field="shipped" shrink-date>Date</vn-th>
</vn-multi-check> <vn-th>Hour</vn-th>
</th> <vn-th field="zoneHour" shrink>Closure</vn-th>
<th class="icon-field"></th> <vn-th field="nickname">Alias</vn-th>
<th field="id"> <vn-th field="provinceFk" class="expendable">Province</vn-th>
<span translate>#ID</span> <vn-th field="stateFk" >State</vn-th>
</th> <vn-th field="zoneFk">Zone</vn-th>
<th field="salesPersonFk"> <vn-th field="warehouseFk">Warehouse</vn-th>
<span translate>Salesperson</span> <vn-th number>Total</vn-th>
</th> <vn-th></vn-th>
<th field="shipped" shrink-date> </vn-tr>
<span translate>Date</span> </vn-thead>
</th> <vn-tbody>
<th> <a ng-repeat="ticket in model.data"
<span translate>Hour</span> class="clickable vn-tr search-result"
</th> ui-sref="ticket.card.summary({id: {{::ticket.id}}})">
<th field="zoneHour" shrink> <vn-td>
<span translate>Closure</span> <vn-check
</th> ng-model="ticket.checked"
<th field="nickname"> vn-click-stop>
<span translate>Alias</span> </vn-check>
</th> </vn-td>
<th field="provinceFk"> <vn-td class="icon-field">
<span translate>Province</span> <vn-icon
</th> ng-show="::ticket.isTaxDataChecked === 0"
<th field="stateFk"> translate-attr="{title: 'No verified data'}"
<span translate>State</span> class="bright"
</th> icon="icon-no036">
<th field="zoneFk"> </vn-icon>
<span translate>Zone</span> <vn-icon
</th> ng-show="::ticket.hasTicketRequest"
<th field="warehouseFk"> translate-attr="{title: 'Purchase request'}"
<span translate>Warehouse</span> class="bright"
</th> icon="icon-100">
<th field="totalWithVat" number> </vn-icon>
<span translate>Total</span> <vn-icon
</th> ng-show="::ticket.isAvailable === 0"
<th></th> translate-attr="{title: 'Not available'}"
</tr> class="bright"
</thead> icon="icon-unavailable">
<tbody> </vn-icon>
<tr ng-repeat="ticket in model.data | orderBy:'!!id'" <vn-icon
ng-class="{'new-row': ticket.$isNew, 'changed-row': ticket.$oldData}" ng-show="::ticket.isFreezed"
vn-anchor="::{ translate-attr="{title: 'Client frozen'}"
state: 'ticket.card.summary', class="bright"
params: {id: ticket.id} icon="icon-frozen">
}"> </vn-icon>
<td> <vn-icon
<vn-check ng-show="::ticket.risk"
ng-model="ticket.$checked" title="{{::$ctrl.$t('Risk')}}: {{ticket.risk}}"
vn-click-stop> class="bright"
</vn-check> icon="icon-risk">
</td> </vn-icon>
<td class="icon-field"> <vn-icon
<vn-icon ng-show="::ticket.hasComponentLack"
ng-show="::ticket.isTaxDataChecked === 0" translate-attr="{title: 'Component lack'}"
translate-attr="{title: 'No verified data'}" class="bright"
class="bright" icon="icon-components">
icon="icon-no036"> </vn-icon>
</vn-icon> </vn-td>
<vn-icon <vn-td shrink>{{::ticket.id}}</vn-td>
ng-show="::ticket.hasTicketRequest" <vn-td class="expendable">
translate-attr="{title: 'Purchase request'}" <span
class="bright" title="{{::ticket.userName}}"
icon="icon-100"> vn-click-stop="workerDescriptor.show($event, ticket.salesPersonFk)"
</vn-icon> class="link">
<vn-icon {{::ticket.userName | dashIfEmpty}}
ng-show="::ticket.isAvailable === 0" </span>
translate-attr="{title: 'Not available'}" </vn-td>
class="bright" <vn-td shrink-date>
icon="icon-unavailable"> <span class="chip {{$ctrl.compareDate(ticket.shipped)}}">
</vn-icon> {{::ticket.shipped | date: 'dd/MM/yyyy'}}
<vn-icon </span>
ng-show="::ticket.isFreezed" </vn-td>
translate-attr="{title: 'Client frozen'}" <vn-td shrink>{{::ticket.shipped | date: 'HH:mm'}}</vn-td>
class="bright" <vn-td shrink>{{::ticket.zoneLanding | date: 'HH:mm'}}</vn-td>
icon="icon-frozen"> <vn-td>
</vn-icon> <span
<vn-icon title="{{::ticket.nickname}}"
ng-show="::ticket.risk" vn-click-stop="clientDescriptor.show($event, ticket.clientFk)"
title="{{::$ctrl.$t('Risk')}}: {{ticket.risk}}" class="link">
class="bright" {{::ticket.nickname}}
icon="icon-risk"> </span>
</vn-icon> </vn-td>
<vn-icon <vn-td class="expendable">{{::ticket.province}}</vn-td>
ng-show="::ticket.hasComponentLack" <vn-td class="expendable">
translate-attr="{title: 'Component lack'}" <span
class="bright" ng-show="ticket.refFk"
icon="icon-components"> title="{{::ticket.refFk}}"
</vn-icon> vn-click-stop="invoiceOutDescriptor.show($event, ticket.invoiceOutId)"
</td> class="link">
<td shrink>{{::ticket.id}}</td> {{::ticket.refFk}}
<td class="expendable"> </span>
<span <span
title="{{::ticket.userName}}" ng-show="!ticket.refFk"
vn-click-stop="workerDescriptor.show($event, ticket.salesPersonFk)" class="chip {{$ctrl.stateColor(ticket)}}">
class="link"> {{ticket.state}}
{{::ticket.userName | dashIfEmpty}} </span>
</span> </vn-td>
</td> <vn-td>
<td shrink-date> <span
<span class="chip {{$ctrl.compareDate(ticket.shipped)}}"> title="{{::ticket.zoneName}}"
{{::ticket.shipped | date: 'dd/MM/yyyy'}} vn-click-stop="zoneDescriptor.show($event, ticket.zoneFk)"
</span> class="link">
</td> {{::ticket.zoneName | dashIfEmpty}}
<td shrink>{{::ticket.shipped | date: 'HH:mm'}}</td> </span>
<td shrink>{{::ticket.zoneLanding | date: 'HH:mm'}}</td> </vn-td>
<td> <vn-td>{{::ticket.warehouse}}</vn-td>
<span <vn-td number>
title="{{::ticket.nickname}}" <span class="chip {{$ctrl.totalPriceColor(ticket)}}">
vn-click-stop="clientDescriptor.show($event, ticket.clientFk)" {{::(ticket.totalWithVat ? ticket.totalWithVat : 0) | currency: 'EUR': 2}}
class="link"> </span>
{{::ticket.nickname}} </vn-td>
</span> <vn-td actions>
</td> <vn-icon-button
<td class="expendable">{{::ticket.province}}</td> vn-anchor="::{
<td class="expendable"> state: 'ticket.card.sale',
<span params: {id: ticket.id},
ng-show="ticket.refFk" target: '_blank'
title="{{::ticket.refFk}}" }"
vn-click-stop="invoiceOutDescriptor.show($event, ticket.invoiceOutId)" vn-tooltip="Go to lines"
class="link"> icon="icon-lines">
{{::ticket.refFk}} </vn-icon-button>
</span> <vn-icon-button
<span vn-click-stop="$ctrl.preview(ticket)"
ng-show="!ticket.refFk" vn-tooltip="Preview"
class="chip {{$ctrl.stateColor(ticket)}}"> icon="preview">
{{ticket.state}} </vn-icon-button>
</span> </vn-td>
</td> </a>
<td> </vn-tbody>
<span </vn-table>
title="{{::ticket.zoneName}}" </vn-card>
vn-click-stop="zoneDescriptor.show($event, ticket.zoneFk)" </vn-data-viewer>
class="link">
{{::ticket.zoneName | dashIfEmpty}}
</span>
</td>
<td>{{::ticket.warehouse}}</td>
<td number>
<span class="chip {{$ctrl.totalPriceColor(ticket)}}">
{{::(ticket.totalWithVat ? ticket.totalWithVat : 0) | currency: 'EUR': 2}}
</span>
</td>
<td actions>
<vn-icon-button
vn-anchor="::{
state: 'ticket.card.sale',
params: {id: ticket.id},
target: '_blank'
}"
vn-tooltip="Go to lines"
icon="icon-lines">
</vn-icon-button>
<vn-icon-button
vn-click-stop="$ctrl.preview(ticket)"
vn-tooltip="Preview"
icon="preview">
</vn-icon-button>
</td>
</tr>
</tbody>
</table>
</slot-table>
</smart-table>
</vn-card>
<div fixed-bottom-right> <div fixed-bottom-right>
<vn-vertical style="align-items: center;"> <vn-vertical style="align-items: center;">
<vn-button class="round sm vn-mb-sm" <vn-button class="round sm vn-mb-sm"
@ -237,8 +205,7 @@
<vn-invoice-out-descriptor-popover <vn-invoice-out-descriptor-popover
vn-id="invoiceOutDescriptor"> vn-id="invoiceOutDescriptor">
</vn-invoice-out-descriptor-popover> </vn-invoice-out-descriptor-popover>
<vn-contextmenu vn-id="contextmenu" targets="['vn-data-viewer']" model="model"
<vn-contextmenu vn-id="contextmenu" targets="['smart-table']" model="model"
expr-builder="$ctrl.exprBuilder(param, value)"> expr-builder="$ctrl.exprBuilder(param, value)">
<slot-menu> <slot-menu>
<vn-item translate <vn-item translate

View File

@ -7,49 +7,6 @@ export default class Controller extends Section {
constructor($element, $, vnReport) { constructor($element, $, vnReport) {
super($element, $); super($element, $);
this.vnReport = vnReport; this.vnReport = vnReport;
this.smartTableOptions = {
activeButtons: {
search: true,
crud: true,
shownColumns: true,
},
columns: [
{
field: 'salesPersonFk',
autocomplete: {
url: 'Workers/activeWithInheritedRole',
where: `{role: 'salesPerson'}`,
searchFunction: '{firstName: $search}',
showField: 'nickname',
valueField: 'id',
}
},
{
field: 'provinceFk',
autocomplete: {
url: 'Provinces',
}
},
{
field: 'stateFk',
autocomplete: {
url: 'States',
}
},
{
field: 'zoneFk',
autocomplete: {
url: 'Zones',
}
},
{
field: 'warehouseFk',
autocomplete: {
url: 'Warehouses',
}
},
]
};
} }
setDelivered() { setDelivered() {
@ -107,7 +64,7 @@ export default class Controller extends Section {
const tickets = this.$.model.data || []; const tickets = this.$.model.data || [];
const checkedLines = []; const checkedLines = [];
for (let ticket of tickets) { for (let ticket of tickets) {
if (ticket.$checked) if (ticket.checked)
checkedLines.push(ticket); checkedLines.push(ticket);
} }
@ -171,12 +128,6 @@ export default class Controller extends Section {
this.$.summary.show(); this.$.summary.show();
} }
defaultNewData() {
return {
nickname: 'my nickname',
};
}
exprBuilder(param, value) { exprBuilder(param, value) {
switch (param) { switch (param) {
case 'stateFk': case 'stateFk':

View File

@ -7,19 +7,19 @@ vn-ticket-index {
} }
} }
th.icon-field, vn-th.icon-field,
th.icon-field *, vn-th.icon-field *,
td.icon-field, vn-td.icon-field,
td.icon-field * { vn-td.icon-field * {
padding: 0 padding: 0
} }
td.icon-field > vn-icon { vn-td.icon-field > vn-icon {
margin-left: 3px; margin-left: 3px;
margin-right: 3px; margin-right: 3px;
} }
tbody a[ng-repeat].vn-tr:focus { vn-tbody a[ng-repeat].vn-tr:focus {
background-color: $color-primary-light background-color: $color-primary-light
} }
} }