itemDiary, filter, grid and new directive repeat-last #346
This commit is contained in:
parent
2ab6eb5e83
commit
86a8ae0322
|
@ -1,8 +1,12 @@
|
|||
Active: Activo
|
||||
Add contact: Añadir contacto
|
||||
Amount: Importe
|
||||
Client: Cliente
|
||||
Clients: Clientes
|
||||
Comercial Name: Comercial
|
||||
Contacts: Contactos
|
||||
Basic data: Datos básicos
|
||||
Back: Volver
|
||||
Fiscal data: Datos Fiscales
|
||||
Addresses: Consignatarios
|
||||
Web access: Acceso web
|
||||
|
@ -21,6 +25,4 @@ Credit : Crédito
|
|||
Credit contracts: Contratos de crédito
|
||||
Verified data: Datos comprobados
|
||||
Mandate: Mandato
|
||||
Amount: Importe
|
||||
Back: Volver
|
||||
Contacts: Contactos
|
||||
Remove contact: Eliminar
|
|
@ -8,3 +8,4 @@ import './on-error-src';
|
|||
import './zoom-image';
|
||||
import './visible-by';
|
||||
import './bind';
|
||||
import './repeat-last';
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
/**
|
||||
* Calls a passed function if is the last element from an ng-repeat.
|
||||
*
|
||||
* @attribute {String} onLast - Callback function
|
||||
* @return {Object} The directive
|
||||
*/
|
||||
directive.$inject = ['$parse'];
|
||||
export function directive($parse) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function($scope, $element, $attrs) {
|
||||
if ($scope.$last && $attrs.onLast) {
|
||||
let fn = $parse($attrs.onLast);
|
||||
fn($scope);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
ngModule.directive('vnRepeatLast', directive);
|
|
@ -110,7 +110,7 @@
|
|||
"item": "$ctrl.item"
|
||||
}
|
||||
}, {
|
||||
"url" : "/diary",
|
||||
"url" : "/diary?q",
|
||||
"state": "item.card.diary",
|
||||
"component": "vn-item-diary",
|
||||
"params": {
|
||||
|
|
|
@ -25,8 +25,8 @@ describe('Item', () => {
|
|||
|
||||
describe('_getItem()', () => {
|
||||
it('should request to get the item', () => {
|
||||
$httpBackend.whenGET('/item/api/Items/123?filter={"include":[{"relation":"itemType","scope":{"fields":["name","workerFk"],"include":{"relation":"worker","fields":["firstName","name"]}}},{"relation":"origin"},{"relation":"ink"},{"relation":"producer"},{"relation":"intrastat"},{"relation":"expence"}]}').respond({data: 'item'});
|
||||
$httpBackend.expectGET('/item/api/Items/123?filter={"include":[{"relation":"itemType","scope":{"fields":["name","workerFk"],"include":{"relation":"worker","fields":["firstName","name"]}}},{"relation":"origin"},{"relation":"ink"},{"relation":"producer"},{"relation":"intrastat"},{"relation":"expence"}]}');
|
||||
$httpBackend.whenGET('/item/api/Items/123?filter={"include":[{"relation":"itemType","scope":{"fields":["name","workerFk","warehouseFk"],"include":{"relation":"worker","fields":["firstName","name"]}}},{"relation":"origin"},{"relation":"ink"},{"relation":"producer"},{"relation":"intrastat"},{"relation":"expence"}]}').respond({data: 'item'});
|
||||
$httpBackend.expectGET('/item/api/Items/123?filter={"include":[{"relation":"itemType","scope":{"fields":["name","workerFk","warehouseFk"],"include":{"relation":"worker","fields":["firstName","name"]}}},{"relation":"origin"},{"relation":"ink"},{"relation":"producer"},{"relation":"intrastat"},{"relation":"expence"}]}');
|
||||
controller._getItem();
|
||||
$httpBackend.flush();
|
||||
});
|
||||
|
|
|
@ -35,7 +35,7 @@ class Controller {
|
|||
include: [
|
||||
{relation: "itemType",
|
||||
scope: {
|
||||
fields: ['name', 'workerFk'],
|
||||
fields: ['name', 'workerFk', 'warehouseFk'],
|
||||
include: {
|
||||
relation: 'worker',
|
||||
fields: ['firstName', 'name']
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="item/api/Items/getDiary"
|
||||
filter="::$ctrl.filter"
|
||||
data="sales"
|
||||
auto-load="false">
|
||||
</vn-crud-model>
|
||||
|
||||
<vn-vertical>
|
||||
<vn-card pad-large>
|
||||
<vn-vertical>
|
||||
|
@ -8,42 +16,42 @@
|
|||
url="/item/api/Warehouses"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
initial-data="$ctrl.warehouseFk"
|
||||
field="$ctrl.warehouseFk"
|
||||
label="Select warehouse">
|
||||
initial-data="$ctrl.filter.where.warehouseFk"
|
||||
field="$ctrl.filter.where.warehouseFk"
|
||||
label="Select warehouse" on-change="$ctrl.onChange(value)">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<table class="vn-grid">
|
||||
<thead>
|
||||
<tr>
|
||||
<th number translate>Date</th>
|
||||
<th number translate>State</th>
|
||||
<th number translate>Origin</th>
|
||||
<th number translate>Reference</th>
|
||||
<th style="text-align: center" translate>Name</th>
|
||||
<th number translate>In</th>
|
||||
<th number translate>Out</th>
|
||||
<th number translate>Balance</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="diary in $ctrl.diary">
|
||||
<td number>{{diary.date | date:'dd/MM/yyyy HH:mm' }}</td>
|
||||
<td number>{{diary.alertLevel | dashIfEmpty}}</td>
|
||||
<td number>{{diary.origin | dashIfEmpty}}</td>
|
||||
<td number>{{diary.reference | dashIfEmpty}}</td>
|
||||
<td style="text-align: center">{{diary.name | dashIfEmpty}}</td>
|
||||
<td number>{{diary.in | dashIfEmpty}}</td>
|
||||
<td number>{{diary.out | dashIfEmpty}}</td>
|
||||
<td number>{{diary.balance | dashIfEmpty}}</td>
|
||||
</tr>
|
||||
<tr ng-if="$ctrl.diary.length === 0" class="list list-element">
|
||||
<td colspan="8" style="text-align: center" translate>No results</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th>Date</vn-th>
|
||||
<vn-th number>State</vn-th>
|
||||
<vn-th number>Origin</vn-th>
|
||||
<vn-th number>Reference</vn-th>
|
||||
<vn-th field="name">Worker</vn-th>
|
||||
<vn-th number>In</vn-th>
|
||||
<vn-th number>Out</vn-th>
|
||||
<vn-th number>Balance</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-class="{'warning': $ctrl.isToday(sale.date)}"
|
||||
ng-repeat="sale in sales" vn-repeat-last on-last="$ctrl.scrollToActive()">
|
||||
<vn-td>{{::sale.date | date:'dd/MM/yyyy HH:mm' }}</vn-td>
|
||||
<vn-td number>{{::sale.alertLevel | dashIfEmpty}}</vn-td>
|
||||
<vn-td number>{{::sale.origin | dashIfEmpty}}</vn-td>
|
||||
<vn-td number>{{::sale.reference | dashIfEmpty}}</vn-td>
|
||||
<vn-td>{{sale.name | dashIfEmpty}}</vn-td>
|
||||
<vn-td number>{{::sale.in | dashIfEmpty}}</vn-td>
|
||||
<vn-td number>{{::sale.out | dashIfEmpty}}</vn-td>
|
||||
<vn-td number><span class="balance">{{::sale.balance | dashIfEmpty}}</span></vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
<vn-empty-rows ng-if="model.data.length === 0" translate>
|
||||
No results
|
||||
</vn-empty-rows>
|
||||
</vn-table>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<vn-paging margin-large-top vn-one index="$ctrl.diary" total="$ctrl.diary.count"></vn-paging>
|
||||
<!-- <vn-auto-paging margin-large-top vn-one index="index" total="index.model.count" items="$ctrl.instances"></vn-auto-paging> -->
|
||||
|
||||
</vn-vertical>
|
||||
|
|
|
@ -2,32 +2,96 @@ import ngModule from '../module';
|
|||
import './style.scss';
|
||||
|
||||
class Controller {
|
||||
constructor($scope, $http) {
|
||||
this.$ = $scope;
|
||||
constructor($scope, $http, $state, $window) {
|
||||
this.$scope = $scope;
|
||||
this.$http = $http;
|
||||
this.diary = [];
|
||||
this.$state = $state;
|
||||
this.$window = $window;
|
||||
}
|
||||
|
||||
set warehouseFk(value) {
|
||||
this._getItemDiary(value);
|
||||
this._warehouseFk = value;
|
||||
$postLink() {
|
||||
if (this.item)
|
||||
this.filterBuilder();
|
||||
}
|
||||
|
||||
get warehouseFk() {
|
||||
return this._warehouseFk;
|
||||
set item(value) {
|
||||
this._item = value;
|
||||
|
||||
if (value && this.$scope.model)
|
||||
this.filterBuilder();
|
||||
}
|
||||
|
||||
_getItemDiary(warehouse) {
|
||||
if (warehouse == null)
|
||||
return;
|
||||
let params = {itemFk: this.item.id, warehouseFk: warehouse};
|
||||
this.$http.get(`/item/api/Items/getDiary?params=${JSON.stringify(params)}`).then(res => {
|
||||
this.diary = res.data;
|
||||
});
|
||||
get item() {
|
||||
return this._item;
|
||||
}
|
||||
|
||||
get alertLevelIndex() {
|
||||
let lines = this.$scope.model.data;
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
let isFutureDate = new Date(lines[i].date) > new Date();
|
||||
let isGenreOut = lines[i].alertLevel != 0;
|
||||
|
||||
if (!isFutureDate && !isGenreOut)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
onChange(value) {
|
||||
if (!value) return;
|
||||
|
||||
this.filter.where.warehouseFk = value;
|
||||
this.$scope.model.refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a filter with default values
|
||||
* and aplies query params.
|
||||
*/
|
||||
filterBuilder() {
|
||||
this.filter = {
|
||||
where: {
|
||||
itemFk: this.item.id,
|
||||
warehouseFk: this.item.itemType.warehouseFk
|
||||
}
|
||||
|
||||
};
|
||||
let where = this.filter.where;
|
||||
|
||||
if (this.$state.params.q) {
|
||||
let queryFilter = JSON.parse(this.$state.params.q);
|
||||
where.warehouseFk = queryFilter.warehouseFk;
|
||||
}
|
||||
}
|
||||
|
||||
scrollToActive() {
|
||||
let body = this.$window.document.body;
|
||||
let lineIndex = this.alertLevelIndex;
|
||||
let lines = body.querySelector('vn-tbody').children;
|
||||
|
||||
if (!lineIndex || !lines.length) return;
|
||||
|
||||
lines[lineIndex].scrollIntoView();
|
||||
lines[lineIndex - 1].querySelector('.balance').classList.add('counter');
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares a date with the current one
|
||||
* @param {Object} date - Date to compare
|
||||
* @return {Boolean} - Returns true if the two dates equals
|
||||
*/
|
||||
isToday(date) {
|
||||
let today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
|
||||
let comparedDate = new Date(date);
|
||||
comparedDate.setHours(0, 0, 0, 0);
|
||||
|
||||
if (!(today - comparedDate))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$scope', '$http'];
|
||||
Controller.$inject = ['$scope', '$http', '$state', '$window'];
|
||||
|
||||
ngModule.component('vnItemDiary', {
|
||||
template: require('./index.html'),
|
||||
|
|
|
@ -17,25 +17,47 @@ describe('Item', () => {
|
|||
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
|
||||
$scope = $rootScope.$new();
|
||||
controller = $componentController('vnItemDiary', {$scope: $scope});
|
||||
controller.item = {id: 3};
|
||||
controller.$scope.model = {};
|
||||
}));
|
||||
|
||||
describe('set warehouseFk()', () => {
|
||||
it(`should call _getItemDiary() with 2 and set warehouseFk`, () => {
|
||||
spyOn(controller, '_getItemDiary');
|
||||
controller.warehouseFk = 2;
|
||||
describe('isToday()', () => {
|
||||
it(`should call isToday() an return true if an specified date is the current date`, () => {
|
||||
let date = new Date();
|
||||
|
||||
expect(controller._getItemDiary).toHaveBeenCalledWith(2);
|
||||
expect(controller.warehouseFk).toEqual(2);
|
||||
let result = controller.isToday(date);
|
||||
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should call isToday() an return false if an specified date is the current date`, () => {
|
||||
let date = '2018-07-03';
|
||||
|
||||
let result = controller.isToday(date);
|
||||
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('_getItemDiary()', () => {
|
||||
it(`should make a request to get the diary hwen is called with a number`, () => {
|
||||
$httpBackend.whenGET('/item/api/Items/getDiary?params={"itemFk":3,"warehouseFk":2}').respond({data: 'item'});
|
||||
$httpBackend.expectGET('/item/api/Items/getDiary?params={"itemFk":3,"warehouseFk":2}');
|
||||
controller._getItemDiary(2);
|
||||
$httpBackend.flush();
|
||||
describe('alertLevelIndex()', () => {
|
||||
it(`should call alertLevelIndex() and return an index from line with alertLevel 0 and current date`, () => {
|
||||
controller.$scope.model = {data: [
|
||||
{name: 'My item 1', alertLevel: 3, date: '2018-05-02'},
|
||||
{name: 'My item 2', alertLevel: 1, date: '2018-05-03'},
|
||||
{name: 'My item 3', alertLevel: 0, date: new Date()}]
|
||||
};
|
||||
let result = controller.alertLevelIndex;
|
||||
|
||||
expect(result).toEqual(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('set item()', () => {
|
||||
it(`should call filterBuilder()`, () => {
|
||||
spyOn(controller, 'filterBuilder');
|
||||
controller.item = {id: 1};
|
||||
|
||||
expect(controller.filterBuilder).toHaveBeenCalledWith();
|
||||
expect(controller.item).toEqual({id: 1});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -242,4 +242,15 @@ fieldset[disabled] .mdl-textfield .mdl-textfield__label,
|
|||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.counter {
|
||||
background-color: $main-header;
|
||||
color: $color-white;
|
||||
border-radius: 3px;
|
||||
padding: 5px
|
||||
}
|
||||
|
||||
.counter.small {
|
||||
font-size: 0.7em
|
||||
}
|
|
@ -3,12 +3,14 @@ module.exports = Self => {
|
|||
description: 'Returns the ',
|
||||
accessType: 'READ',
|
||||
accepts: [{
|
||||
arg: 'params',
|
||||
type: 'object',
|
||||
description: 'itemFk, warehouseFk'
|
||||
arg: 'filter',
|
||||
type: 'Object',
|
||||
required: true,
|
||||
description: 'Filter defining where and paginated data',
|
||||
http: {source: 'query'}
|
||||
}],
|
||||
returns: {
|
||||
arg: 'diary',
|
||||
type: ['Object'],
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
|
@ -17,8 +19,9 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.getDiary = async params => {
|
||||
let [diary] = await Self.rawSql(`CALL vn.itemDiary(?, ?)`, [params.itemFk, params.warehouseFk]);
|
||||
Self.getDiary = async filter => {
|
||||
let where = filter.where;
|
||||
let [diary] = await Self.rawSql(`CALL vn.itemDiary(?, ?)`, [where.itemFk, where.warehouseFk]);
|
||||
return diary;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -24,10 +24,15 @@
|
|||
},
|
||||
"relations": {
|
||||
"worker": {
|
||||
"type": "belongsTo",
|
||||
"model": "Worker",
|
||||
"foreignKey": "workerFk"
|
||||
}
|
||||
"type": "belongsTo",
|
||||
"model": "Worker",
|
||||
"foreignKey": "workerFk"
|
||||
},
|
||||
"warehouse": {
|
||||
"type": "belongsTo",
|
||||
"model": "Warehouse",
|
||||
"foreignKey": "warehouseFk"
|
||||
}
|
||||
},
|
||||
"acls": [
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue