catalog order by tag #773
This commit is contained in:
parent
7398d20132
commit
bb50166e02
|
@ -18,5 +18,7 @@ module.exports.crudModel = {
|
||||||
accept();
|
accept();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
refresh: () => {}
|
refresh: () => {},
|
||||||
|
addFilter: () => {},
|
||||||
|
applyFilter: () => {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<vn-crud-model
|
<vn-crud-model auto-load="false"
|
||||||
vn-id="model"
|
vn-id="model"
|
||||||
url="/order/api/Orders/CatalogFilter"
|
url="/order/api/Orders/CatalogFilter"
|
||||||
filter="$ctrl.filter"
|
filter="$ctrl.filter"
|
||||||
limit="50"
|
limit="50"
|
||||||
data="items" auto-load="false">
|
data="items" on-data-change="$ctrl.onDataChange()" >
|
||||||
</vn-crud-model>
|
</vn-crud-model>
|
||||||
|
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
|
@ -11,17 +11,28 @@
|
||||||
<vn-card>
|
<vn-card>
|
||||||
<vn-vertical>
|
<vn-vertical>
|
||||||
<vn-horizontal class="catalog-header" pad-medium-h>
|
<vn-horizontal class="catalog-header" pad-medium-h>
|
||||||
<vn-one>{{model.data.length}} <span translate>results</span></vn-one>
|
<vn-one>{{model.data.length || 0}} <span translate>results</span></vn-one>
|
||||||
<vn-one>
|
<vn-one>
|
||||||
<vn-autocomplete vn-none
|
<vn-horizontal>
|
||||||
data="$ctrl.orderList"
|
<vn-autocomplete vn-id="field" vn-one
|
||||||
initial-data="$ctrl.orderBy"
|
data="$ctrl.fieldList"
|
||||||
field="$ctrl.orderBy"
|
initial-data="$ctrl.field"
|
||||||
on-change="$ctrl.setOrder(value)"
|
field="$ctrl.field"
|
||||||
|
translate-fields="['name']"
|
||||||
show-field="name"
|
show-field="name"
|
||||||
value-field="order"
|
value-field="field"
|
||||||
label="Order by">
|
label="Order by">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
|
<vn-autocomplete vn-one
|
||||||
|
data="$ctrl.wayList"
|
||||||
|
initial-data="$ctrl.way"
|
||||||
|
field="$ctrl.way"
|
||||||
|
translate-fields="['name']"
|
||||||
|
show-field="name"
|
||||||
|
value-field="way"
|
||||||
|
label="Order">
|
||||||
|
</vn-autocomplete>
|
||||||
|
</vn-horizontal>
|
||||||
</vn-one>
|
</vn-one>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-horizontal class="catalog-list" pad-small>
|
<vn-horizontal class="catalog-list" pad-small>
|
||||||
|
@ -78,14 +89,14 @@
|
||||||
</vn-one>
|
</vn-one>
|
||||||
</section>
|
</section>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-horizontal ng-if="model.data.length == 0">
|
<vn-horizontal ng-if="!model.data || model.data.length == 0">
|
||||||
<vn-one pad-small translate style="text-align: center">
|
<vn-one pad-small translate style="text-align: center">
|
||||||
No results
|
No results
|
||||||
</vn-one>
|
</vn-one>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
</vn-vertical>
|
</vn-vertical>
|
||||||
</vn-card>
|
</vn-card>
|
||||||
<vn-pagination
|
<vn-pagination margin-small-v
|
||||||
model="model"
|
model="model"
|
||||||
scroll-selector="ui-view">
|
scroll-selector="ui-view">
|
||||||
</vn-pagination>
|
</vn-pagination>
|
||||||
|
|
|
@ -2,48 +2,104 @@ import ngModule from '../module';
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
|
|
||||||
class Controller {
|
class Controller {
|
||||||
constructor($scope, $state, $translate) {
|
constructor($scope, $state) {
|
||||||
this.$scope = $scope;
|
this.$scope = $scope;
|
||||||
this.$state = $state;
|
this.$state = $state;
|
||||||
this.orderList = [
|
|
||||||
{
|
// Static autocomplete data
|
||||||
order: 'relevancy DESC, name',
|
this.wayList = [
|
||||||
name: $translate.instant('Default order')
|
{way: 'ASC', name: 'Ascendant'},
|
||||||
},
|
{way: 'DESC', name: 'Descendant'},
|
||||||
{
|
|
||||||
order: 'name',
|
|
||||||
name: $translate.instant('Ascendant name')
|
|
||||||
},
|
|
||||||
{
|
|
||||||
order: 'name DESC',
|
|
||||||
name: $translate.instant('Descendant name')
|
|
||||||
},
|
|
||||||
{
|
|
||||||
order: 'price',
|
|
||||||
name: $translate.instant('Ascendant price')
|
|
||||||
},
|
|
||||||
{
|
|
||||||
order: 'price DESC',
|
|
||||||
name: $translate.instant('Descendant price')
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
this.orderBy = this.orderList[0].order;
|
this.defaultFieldList = [
|
||||||
this.filter = {
|
{field: 'relevancy DESC, name', name: 'Name'},
|
||||||
order: this.orderBy
|
{field: 'price', name: 'Price'}
|
||||||
|
];
|
||||||
|
this.fieldList = [];
|
||||||
|
this.fieldList = this.fieldList.concat(this.defaultFieldList);
|
||||||
|
this._way = this.wayList[0].way;
|
||||||
|
this._field = this.fieldList[0].field;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills order autocomplete with tags
|
||||||
|
* obtained from last filtered
|
||||||
|
*/
|
||||||
|
onDataChange() {
|
||||||
|
const items = this.$scope.model.data;
|
||||||
|
|
||||||
|
if (!items) return;
|
||||||
|
|
||||||
|
this.fieldList = [];
|
||||||
|
this.fieldList = this.fieldList.concat(this.defaultFieldList);
|
||||||
|
|
||||||
|
items.forEach(item => {
|
||||||
|
item.tags.forEach(itemTag => {
|
||||||
|
const alreadyAdded = this.fieldList.find(order => {
|
||||||
|
return order.field == itemTag.tagFk;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!alreadyAdded)
|
||||||
|
this.fieldList.push({
|
||||||
|
name: itemTag.name,
|
||||||
|
field: itemTag.tagFk,
|
||||||
|
isTag: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get order way ASC/DESC
|
||||||
|
*/
|
||||||
|
get way() {
|
||||||
|
return this._way;
|
||||||
|
}
|
||||||
|
|
||||||
|
set way(value) {
|
||||||
|
this._way = value;
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
this.applyOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get order fields
|
||||||
|
*/
|
||||||
|
get field() {
|
||||||
|
return this._field;
|
||||||
|
}
|
||||||
|
|
||||||
|
set field(value) {
|
||||||
|
this._field = value;
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
this.applyOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns order param
|
||||||
|
*
|
||||||
|
* @return {Object} - Order param
|
||||||
|
*/
|
||||||
|
getOrderBy() {
|
||||||
|
let field = this.$scope.field;
|
||||||
|
let args = {
|
||||||
|
field: this.field,
|
||||||
|
way: this.way
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (field.selection && field.selection.isTag)
|
||||||
|
args.isTag = true;
|
||||||
|
|
||||||
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
get orderBy() {
|
/**
|
||||||
return this._orderBy;
|
* Apply order to model
|
||||||
}
|
*/
|
||||||
|
applyOrder() {
|
||||||
set orderBy(value) {
|
this.$scope.model.addFilter(null, {orderBy: this.getOrderBy()});
|
||||||
this._orderBy = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
setOrder(order) {
|
|
||||||
this.$scope.model.filter.order = order;
|
|
||||||
this.$scope.model.refresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
preview(event, item) {
|
preview(event, item) {
|
||||||
|
@ -56,18 +112,17 @@ class Controller {
|
||||||
}
|
}
|
||||||
|
|
||||||
$onChanges() {
|
$onChanges() {
|
||||||
if (this.order && this.order.isConfirmed) {
|
if (this.order && this.order.isConfirmed)
|
||||||
this.$state.go('order.card.line');
|
this.$state.go('order.card.line');
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller.$inject = ['$scope', '$state', '$translate'];
|
Controller.$inject = ['$scope', '$state'];
|
||||||
|
|
||||||
ngModule.component('vnOrderCatalog', {
|
ngModule.component('vnOrderCatalog', {
|
||||||
template: require('./index.html'),
|
template: require('./index.html'),
|
||||||
controller: Controller,
|
controller: Controller,
|
||||||
bindings: {
|
bindings: {
|
||||||
order: '<'
|
order: '<',
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -15,16 +15,49 @@ describe('Order', () => {
|
||||||
$componentController = _$componentController_;
|
$componentController = _$componentController_;
|
||||||
$scope = $rootScope.$new();
|
$scope = $rootScope.$new();
|
||||||
$scope.model = crudModel;
|
$scope.model = crudModel;
|
||||||
|
$scope.field = {};
|
||||||
controller = $componentController('vnOrderCatalog', {$scope: $scope});
|
controller = $componentController('vnOrderCatalog', {$scope: $scope});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('setOrder()', () => {
|
describe('onDataChange()', () => {
|
||||||
it(`should apply filter order and call model refresh() method`, () => {
|
it(`should return an object with order params`, () => {
|
||||||
spyOn(controller.$scope.model, 'refresh');
|
let expectedList = [
|
||||||
controller.setOrder('relevancy DESC');
|
{field: 'relevancy DESC, name', name: 'Name'},
|
||||||
|
{field: 'price', name: 'Price'},
|
||||||
|
{field: 4, name: 'Length', isTag: true}
|
||||||
|
];
|
||||||
|
$scope.model.data = [{id: 1, name: 'My Item', tags: [
|
||||||
|
{tagFk: 4, name: 'Length'}
|
||||||
|
]}];
|
||||||
|
|
||||||
expect(controller.$scope.model.filter.order).toEqual('relevancy DESC');
|
controller.onDataChange();
|
||||||
expect(controller.$scope.model.refresh).toHaveBeenCalledWith();
|
|
||||||
|
expect(controller.fieldList).toEqual(expectedList);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getOrderBy()', () => {
|
||||||
|
it(`should return an object with order params`, () => {
|
||||||
|
controller.field = 'relevancy DESC, name';
|
||||||
|
controller.way = 'DESC';
|
||||||
|
let expectedResult = {field: 'relevancy DESC, name', way: 'DESC'};
|
||||||
|
let result = controller.getOrderBy();
|
||||||
|
|
||||||
|
expect(result).toEqual(expectedResult);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('applyOrder()', () => {
|
||||||
|
it(`should apply order param to model calling getOrderBy()`, () => {
|
||||||
|
controller.field = 'relevancy DESC, name';
|
||||||
|
controller.way = 'ASC';
|
||||||
|
let expectedOrder = {orderBy: controller.getOrderBy()};
|
||||||
|
spyOn(controller, 'getOrderBy').and.callThrough();
|
||||||
|
spyOn(controller.$scope.model, 'addFilter');
|
||||||
|
controller.applyOrder();
|
||||||
|
|
||||||
|
expect(controller.getOrderBy).toHaveBeenCalledWith();
|
||||||
|
expect(controller.$scope.model.addFilter).toHaveBeenCalledWith(null, expectedOrder);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
</vn-icon>
|
</vn-icon>
|
||||||
</vn-one>
|
</vn-one>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
|
|
||||||
<vn-horizontal pad-medium class="catalog-header">
|
<vn-horizontal pad-medium class="catalog-header">
|
||||||
<vn-autocomplete vn-one
|
<vn-autocomplete vn-one
|
||||||
vn-id="type"
|
vn-id="type"
|
||||||
|
|
|
@ -12,7 +12,7 @@ class Controller {
|
||||||
this.itemTypes = [];
|
this.itemTypes = [];
|
||||||
this.tags = [];
|
this.tags = [];
|
||||||
|
|
||||||
/* $transitions.onSuccess({}, transition => {
|
/* $transitions.onSuccess({}, transition => {
|
||||||
let params = {};
|
let params = {};
|
||||||
if (this.category)
|
if (this.category)
|
||||||
params.category = this.category;
|
params.category = this.category;
|
||||||
|
@ -42,12 +42,15 @@ class Controller {
|
||||||
if (this.$stateParams.category)
|
if (this.$stateParams.category)
|
||||||
category = JSON.parse(this.$stateParams.category);
|
category = JSON.parse(this.$stateParams.category);
|
||||||
|
|
||||||
|
|
||||||
if (this.$stateParams.type)
|
if (this.$stateParams.type)
|
||||||
type = JSON.parse(this.$stateParams.type);
|
type = JSON.parse(this.$stateParams.type);
|
||||||
|
|
||||||
|
|
||||||
if (category && category.id)
|
if (category && category.id)
|
||||||
this.category = category;
|
this.category = category;
|
||||||
|
|
||||||
|
|
||||||
if (type && type.id)
|
if (type && type.id)
|
||||||
this.type = type;
|
this.type = type;
|
||||||
});
|
});
|
||||||
|
@ -71,7 +74,7 @@ class Controller {
|
||||||
this._category = value;
|
this._category = value;
|
||||||
this.updateStateParams();
|
this.updateStateParams();
|
||||||
|
|
||||||
let query = `/item/api/ItemCategories/${value.id}/itemTypes`;
|
const query = `/item/api/ItemCategories/${value.id}/itemTypes`;
|
||||||
this.$http.get(query).then(res => {
|
this.$http.get(query).then(res => {
|
||||||
this.itemTypes = res.data;
|
this.itemTypes = res.data;
|
||||||
});
|
});
|
||||||
|
@ -99,42 +102,47 @@ class Controller {
|
||||||
onSearch(event) {
|
onSearch(event) {
|
||||||
if (event.key !== 'Enter') return;
|
if (event.key !== 'Enter') return;
|
||||||
this.tags.push({
|
this.tags.push({
|
||||||
value: this.value
|
value: this.value,
|
||||||
});
|
});
|
||||||
this.$scope.search.value = null;
|
this.$scope.search.value = null;
|
||||||
this.applyFilters();
|
this.applyFilters();
|
||||||
}
|
}
|
||||||
|
|
||||||
applyFilters() {
|
|
||||||
let newArgs = {orderFk: this.order.id};
|
|
||||||
let model = this.catalog.$scope.model;
|
|
||||||
|
|
||||||
if (this.category)
|
|
||||||
newArgs.categoryFk = this.category.id;
|
|
||||||
|
|
||||||
if (this.type)
|
|
||||||
newArgs.typeFk = this.type.id;
|
|
||||||
|
|
||||||
model.params = {
|
|
||||||
args: newArgs,
|
|
||||||
tags: this.tags
|
|
||||||
};
|
|
||||||
|
|
||||||
this.catalog.$scope.model.refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
remove(index) {
|
remove(index) {
|
||||||
this.tags.splice(index, 1);
|
this.tags.splice(index, 1);
|
||||||
|
|
||||||
|
if (this.tags.length > 0)
|
||||||
this.applyFilters();
|
this.applyFilters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applyFilters() {
|
||||||
|
let newParams = {};
|
||||||
|
const newFilter = {};
|
||||||
|
const model = this.catalog.$scope.model;
|
||||||
|
|
||||||
|
if (this.category)
|
||||||
|
newFilter.categoryFk = this.category.id;
|
||||||
|
|
||||||
|
|
||||||
|
if (this.type)
|
||||||
|
newFilter.typeFk = this.type.id;
|
||||||
|
|
||||||
|
|
||||||
|
newParams = {
|
||||||
|
orderFk: this.order.id,
|
||||||
|
orderBy: this.catalog.getOrderBy(),
|
||||||
|
tags: this.tags,
|
||||||
|
};
|
||||||
|
|
||||||
|
model.applyFilter({where: newFilter}, newParams);
|
||||||
|
}
|
||||||
|
|
||||||
openPanel(event) {
|
openPanel(event) {
|
||||||
if (event.defaultPrevented) return;
|
if (event.defaultPrevented) return;
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
this.$panel = this.$compile(`<vn-order-search-panel/>`)(this.$scope.$new());
|
this.$panel = this.$compile(`<vn-order-catalog-search-panel/>`)(this.$scope.$new());
|
||||||
let panel = this.$panel.isolateScope().$ctrl;
|
const panel = this.$panel.isolateScope().$ctrl;
|
||||||
panel.filter = this.filter;
|
panel.filter = this.filter;
|
||||||
panel.onSubmit = filter => this.onPanelSubmit(filter);
|
panel.onSubmit = filter => this.onPanelSubmit(filter);
|
||||||
|
|
||||||
|
@ -156,16 +164,18 @@ class Controller {
|
||||||
}
|
}
|
||||||
|
|
||||||
updateStateParams() {
|
updateStateParams() {
|
||||||
let params = {};
|
const params = {};
|
||||||
|
|
||||||
if (this.category)
|
if (this.category)
|
||||||
params.category = JSON.stringify(this.category);
|
params.category = JSON.stringify(this.category);
|
||||||
|
|
||||||
|
|
||||||
if (this.type)
|
if (this.type)
|
||||||
params.type = JSON.stringify(this.type);
|
params.type = JSON.stringify(this.type);
|
||||||
else
|
else
|
||||||
params.type = undefined;
|
params.type = undefined;
|
||||||
|
|
||||||
|
|
||||||
this.$state.go(this.$state.current.name, params);
|
this.$state.go(this.$state.current.name, params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,9 +186,9 @@ ngModule.component('vnCatalogFilter', {
|
||||||
template: require('./index.html'),
|
template: require('./index.html'),
|
||||||
controller: Controller,
|
controller: Controller,
|
||||||
require: {
|
require: {
|
||||||
catalog: '^vnOrderCatalog'
|
catalog: '^vnOrderCatalog',
|
||||||
},
|
},
|
||||||
bindings: {
|
bindings: {
|
||||||
order: '<'
|
order: '<',
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -26,7 +26,10 @@ describe('Order', () => {
|
||||||
$state.current.name = 'my.current.state';
|
$state.current.name = 'my.current.state';
|
||||||
controller = $componentController('vnCatalogFilter', {$scope: $scope, $state});
|
controller = $componentController('vnCatalogFilter', {$scope: $scope, $state});
|
||||||
controller.catalog = {
|
controller.catalog = {
|
||||||
$scope: $scope
|
$scope: $scope,
|
||||||
|
getOrderBy: () => {
|
||||||
|
return {field: 'relevancy DESC, name', way: 'DESC'};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -101,15 +104,14 @@ describe('Order', () => {
|
||||||
|
|
||||||
describe('applyFilters()', () => {
|
describe('applyFilters()', () => {
|
||||||
it(`should set type property to null, call updateStateParams() method and not call applyFilters()`, () => {
|
it(`should set type property to null, call updateStateParams() method and not call applyFilters()`, () => {
|
||||||
spyOn(controller.catalog.$scope.model, 'refresh');
|
spyOn(controller.catalog.$scope.model, 'applyFilter');
|
||||||
controller.order = {id: 4};
|
controller.order = {id: 4};
|
||||||
$scope.$digest();
|
$scope.$digest();
|
||||||
controller.applyFilters();
|
controller.applyFilters();
|
||||||
|
|
||||||
let result = {args: {orderFk: 4, categoryFk: 1, typeFk: 1}, tags: []};
|
expect(controller.catalog.$scope.model.applyFilter).toHaveBeenCalledWith(
|
||||||
|
{where: {categoryFk: 1, typeFk: 1}},
|
||||||
expect(controller.catalog.$scope.model.params).toEqual(result);
|
{orderFk: 4, orderBy: controller.catalog.getOrderBy(), tags: []});
|
||||||
expect(controller.catalog.$scope.model.refresh).toHaveBeenCalledWith();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,8 @@ Accessories: Complemento
|
||||||
Category: Reino
|
Category: Reino
|
||||||
Search tag: Buscar etiqueta
|
Search tag: Buscar etiqueta
|
||||||
Order by: Ordenar por
|
Order by: Ordenar por
|
||||||
Default order: Orden predeterminado
|
Order: Orden
|
||||||
Ascendant name: Nombre ascendiente
|
Price: Precio
|
||||||
Descendant name: Nombre descendiente
|
Ascendant: Ascendente
|
||||||
Ascendant price: Precio ascendiente
|
Descendant: Descendente
|
||||||
Descendant price: Precio descendiente
|
|
||||||
Created from: Creado desde
|
Created from: Creado desde
|
|
@ -80,3 +80,4 @@ INSERT INTO `salix`.`ACL` (`id`, `model`, `property`, `accessType`, `permission`
|
||||||
|
|
||||||
|
|
||||||
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('TicketWeekly', '*', '*', 'employee');
|
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('TicketWeekly', '*', '*', 'employee');
|
||||||
|
INSERT INTO `salix`.`fieldAcl` (`model`, `property`, `actionType`, `role`) VALUES ('Receipt', '*', '*', 'administrative');
|
|
@ -25,6 +25,12 @@
|
||||||
},
|
},
|
||||||
"unit": {
|
"unit": {
|
||||||
"type": "String"
|
"type": "String"
|
||||||
|
},
|
||||||
|
"isQuantitative": {
|
||||||
|
"type": "Boolean",
|
||||||
|
"mysql": {
|
||||||
|
"columnName": "isQuantitatif"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"acls": [
|
"acls": [
|
||||||
|
|
|
@ -6,37 +6,40 @@ module.exports = Self => {
|
||||||
accessType: 'READ',
|
accessType: 'READ',
|
||||||
accepts: [
|
accepts: [
|
||||||
{
|
{
|
||||||
arg: 'filter',
|
arg: 'orderFk',
|
||||||
type: 'Object',
|
type: 'Number',
|
||||||
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
|
required: true
|
||||||
http: {source: 'query'}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
arg: 'args',
|
arg: 'orderBy',
|
||||||
type: 'Object',
|
type: 'Object',
|
||||||
description: 'orderFk, categoryFk, typeFk',
|
description: 'Items order',
|
||||||
required: true,
|
required: true
|
||||||
http: {source: 'query'}
|
},
|
||||||
|
{
|
||||||
|
arg: 'filter',
|
||||||
|
type: 'Object',
|
||||||
|
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
arg: 'tags',
|
arg: 'tags',
|
||||||
type: ['Object'],
|
type: ['Object'],
|
||||||
description: 'Request tags',
|
description: 'Filter by tag'
|
||||||
http: {source: 'query'}
|
},
|
||||||
}
|
|
||||||
],
|
],
|
||||||
returns: {
|
returns: {
|
||||||
type: ['Object'],
|
type: ['Object'],
|
||||||
root: true
|
root: true,
|
||||||
},
|
},
|
||||||
http: {
|
http: {
|
||||||
path: `/catalogFilter`,
|
path: `/catalogFilter`,
|
||||||
verb: 'GET'
|
verb: 'GET',
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.catalogFilter = async (filter, args, tags) => {
|
Self.catalogFilter = async (orderFk, orderBy, filter, tags) => {
|
||||||
let stmts = [];
|
let conn = Self.dataSource.connector;
|
||||||
|
const stmts = [];
|
||||||
let stmt;
|
let stmt;
|
||||||
|
|
||||||
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.item');
|
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.item');
|
||||||
|
@ -50,45 +53,40 @@ module.exports = Self => {
|
||||||
it.categoryFk
|
it.categoryFk
|
||||||
FROM vn.item i
|
FROM vn.item i
|
||||||
JOIN vn.itemType it ON it.id = i.typeFk
|
JOIN vn.itemType it ON it.id = i.typeFk
|
||||||
JOIN vn.itemCategory ic ON ic.id = it.categoryFk`
|
JOIN vn.itemCategory ic ON ic.id = it.categoryFk`);
|
||||||
);
|
|
||||||
|
|
||||||
|
// Filter by tag
|
||||||
if (tags) {
|
if (tags) {
|
||||||
let i = 1;
|
let i = 1;
|
||||||
for (let tag of tags) {
|
for (const tag of tags) {
|
||||||
let tAlias = `it${i++}`;
|
const tAlias = `it${i++}`;
|
||||||
|
|
||||||
if (tag.tagFk) {
|
if (tag.tagFk)
|
||||||
stmt.merge({
|
stmt.merge({
|
||||||
sql: `JOIN vn.itemTag ${tAlias} ON ${tAlias}.itemFk = i.id
|
sql: `JOIN vn.itemTag ${tAlias} ON ${tAlias}.itemFk = i.id
|
||||||
AND ${tAlias}.tagFk = ?
|
AND ${tAlias}.tagFk = ?
|
||||||
AND ${tAlias}.value LIKE ?`,
|
AND ${tAlias}.value LIKE ?`,
|
||||||
params: [tag.tagFk, `%${tag.value}%`]
|
params: [tag.tagFk, `%${tag.value}%`],
|
||||||
});
|
});
|
||||||
} else {
|
else
|
||||||
stmt.merge({
|
stmt.merge({
|
||||||
sql: `JOIN vn.itemTag ${tAlias} ON ${tAlias}.itemFk = i.id
|
sql: `JOIN vn.itemTag ${tAlias} ON ${tAlias}.itemFk = i.id
|
||||||
AND ${tAlias}.value LIKE ?`,
|
AND ${tAlias}.value LIKE ?`,
|
||||||
params: [`%${tag.value}%`]
|
params: [`%${tag.value}%`],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (args.typeFk)
|
|
||||||
stmt.merge({
|
|
||||||
sql: 'WHERE it.categoryFk = ? AND i.typeFk = ?',
|
|
||||||
params: [args.categoryFk, args.typeFk]
|
|
||||||
});
|
|
||||||
|
|
||||||
|
stmt.merge(conn.makeWhere(filter.where));
|
||||||
stmts.push(stmt);
|
stmts.push(stmt);
|
||||||
|
|
||||||
let order = await Self.findById(args.orderFk);
|
// Calculate items
|
||||||
|
const order = await Self.findById(orderFk);
|
||||||
stmts.push(new ParameterizedSQL(
|
stmts.push(new ParameterizedSQL(
|
||||||
'CALL vn.ticketCalculate(?, ?, ?)', [
|
'CALL vn.ticketCalculate(?, ?, ?)', [
|
||||||
order.landed,
|
order.landed,
|
||||||
order.address_id,
|
order.address_id,
|
||||||
order.agency_id
|
order.agency_id,
|
||||||
]
|
]
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -112,13 +110,39 @@ module.exports = Self => {
|
||||||
FROM tmp.ticketCalculateItem tci
|
FROM tmp.ticketCalculateItem tci
|
||||||
JOIN vn.item i ON i.id = tci.itemFk
|
JOIN vn.item i ON i.id = tci.itemFk
|
||||||
JOIN vn.itemType it ON it.id = i.typeFk
|
JOIN vn.itemType it ON it.id = i.typeFk
|
||||||
JOIN vn.worker w on w.id = it.workerFk`
|
JOIN vn.worker w on w.id = it.workerFk`);
|
||||||
);
|
|
||||||
stmt.merge(Self.buildSuffix(filter));
|
|
||||||
// stmt.merge(Self.buildOrderBy(orderBy));
|
|
||||||
let itemsIndex = stmts.push(stmt) - 1;
|
|
||||||
|
|
||||||
let pricesIndex = stmts.push(
|
// Apply order by tag
|
||||||
|
if (orderBy.isTag) {
|
||||||
|
stmt.merge({
|
||||||
|
sql: `
|
||||||
|
LEFT JOIN vn.itemTag itg
|
||||||
|
LEFT JOIN vn.tag t ON t.id = itg.tagFk
|
||||||
|
ON itg.itemFk = tci.itemFk AND itg.tagFk = ?`,
|
||||||
|
params: [orderBy.field],
|
||||||
|
});
|
||||||
|
|
||||||
|
let way = orderBy.way == 'DESC' ? 'DESC' : 'ASC';
|
||||||
|
let tag = await Self.app.models.Tag.findById(orderBy.field);
|
||||||
|
let orderSql = `
|
||||||
|
ORDER BY
|
||||||
|
itg.value IS NULL,
|
||||||
|
${tag.isQuantitative ? 'CAST(itg.value AS SIGNED)' : 'itg.value'}
|
||||||
|
${way}`;
|
||||||
|
|
||||||
|
stmt.merge(orderSql);
|
||||||
|
} else {
|
||||||
|
// Apply order by field
|
||||||
|
let orderParam = `${orderBy.field} ${orderBy.way}`;
|
||||||
|
orderParam = orderParam.split(/\s*,/).map(param => param.trim());
|
||||||
|
stmt.merge(conn.makeOrderBy(orderParam));
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt.merge(Self.makeLimit(filter));
|
||||||
|
const itemsIndex = stmts.push(stmt) - 1;
|
||||||
|
|
||||||
|
// Apply item prices
|
||||||
|
const pricesIndex = stmts.push(
|
||||||
`SELECT
|
`SELECT
|
||||||
tcp.itemFk,
|
tcp.itemFk,
|
||||||
tcp.grouping,
|
tcp.grouping,
|
||||||
|
@ -127,32 +151,51 @@ module.exports = Self => {
|
||||||
tcp.warehouseFk,
|
tcp.warehouseFk,
|
||||||
w.name AS warehouse
|
w.name AS warehouse
|
||||||
FROM tmp.ticketComponentPrice tcp
|
FROM tmp.ticketComponentPrice tcp
|
||||||
JOIN vn.warehouse w ON w.id = tcp.warehouseFk`
|
JOIN vn.warehouse w ON w.id = tcp.warehouseFk`) - 1;
|
||||||
) - 1;
|
|
||||||
|
|
||||||
|
// Get tags from all items
|
||||||
|
const itemTagsIndex = stmts.push(
|
||||||
|
`SELECT
|
||||||
|
it.tagFk,
|
||||||
|
it.itemFk,
|
||||||
|
t.name
|
||||||
|
FROM tmp.ticketCalculateItem tci
|
||||||
|
JOIN vn.itemTag it ON it.itemFk = tci.itemFk
|
||||||
|
JOIN vn.tag t ON t.id = it.tagFk`) - 1;
|
||||||
|
|
||||||
|
// Clean temporary tables
|
||||||
stmts.push(
|
stmts.push(
|
||||||
`DROP TEMPORARY TABLE
|
`DROP TEMPORARY TABLE
|
||||||
tmp.item,
|
tmp.item,
|
||||||
tmp.ticketCalculateItem,
|
tmp.ticketCalculateItem,
|
||||||
tmp.ticketComponentPrice`
|
tmp.ticketComponentPrice`);
|
||||||
);
|
|
||||||
|
|
||||||
let sql = ParameterizedSQL.join(stmts, ';');
|
const sql = ParameterizedSQL.join(stmts, ';');
|
||||||
let result = await Self.rawStmt(sql);
|
const result = await conn.executeStmt(sql);
|
||||||
|
|
||||||
|
// Add prices to items
|
||||||
result[itemsIndex].forEach(item => {
|
result[itemsIndex].forEach(item => {
|
||||||
result[pricesIndex].forEach(price => {
|
result[pricesIndex].forEach(price => {
|
||||||
if (item.id === price.itemFk) {
|
if (item.id === price.itemFk) {
|
||||||
if (item.prices) {
|
if (item.prices)
|
||||||
item.prices.push(price);
|
item.prices.push(price);
|
||||||
} else {
|
else
|
||||||
item.prices = [price];
|
item.prices = [price];
|
||||||
}
|
|
||||||
item.available = price.grouping;
|
item.available = price.grouping;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Attach item tags
|
||||||
|
result[itemsIndex].forEach(item => {
|
||||||
|
item.tags = [];
|
||||||
|
result[itemTagsIndex].forEach(itemTag => {
|
||||||
|
if (item.id === itemTag.itemFk)
|
||||||
|
item.tags.push(itemTag);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
return result[itemsIndex];
|
return result[itemsIndex];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,35 +1,34 @@
|
||||||
const app = require(`${servicesDir}/order/server/server`);
|
const app = require(`${servicesDir}/order/server/server`);
|
||||||
describe('order catalogFilter()', () => {
|
describe('order catalogFilter()', () => {
|
||||||
it('should return an array of items', async() => {
|
it('should return an array of items', async () => {
|
||||||
let filter = {
|
let filter = {
|
||||||
order: 'relevancy DESC, name'
|
where: {
|
||||||
};
|
|
||||||
let args = {
|
|
||||||
orderFk: 11,
|
|
||||||
categoryFk: 1,
|
categoryFk: 1,
|
||||||
typeFk: 2
|
typeFk: 2
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let tags = [];
|
let tags = [];
|
||||||
let result = await app.models.Order.catalogFilter(filter, args, tags);
|
let orderFk = 11;
|
||||||
|
let orderBy = {field: 'relevancy DESC, name', way: 'DESC'};
|
||||||
|
let result = await app.models.Order.catalogFilter(orderFk, orderBy, filter, tags);
|
||||||
let firstItemId = result[0].id;
|
let firstItemId = result[0].id;
|
||||||
|
|
||||||
expect(result.length).toEqual(2);
|
expect(result.length).toEqual(2);
|
||||||
expect(firstItemId).toEqual(1);
|
expect(firstItemId).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return an array of items based on tag filter', async() => {
|
it('should return an array of items based on tag filter', async () => {
|
||||||
let filter = {
|
let filter = {
|
||||||
order: 'relevancy DESC, name'
|
where: {
|
||||||
};
|
|
||||||
let args = {
|
|
||||||
orderFk: 11,
|
|
||||||
categoryFk: 1,
|
categoryFk: 1,
|
||||||
typeFk: 2
|
typeFk: 2
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let tags = [{tagFk: 56, value: 'Object2'}];
|
let tags = [{tagFk: 56, value: 'Object2'}];
|
||||||
let result = await app.models.Order.catalogFilter(filter, args, tags);
|
let orderFk = 11;
|
||||||
|
let orderBy = {field: 'relevancy DESC, name', way: 'DESC'};
|
||||||
|
let result = await app.models.Order.catalogFilter(orderFk, orderBy, filter, tags);
|
||||||
let firstItemId = result[0].id;
|
let firstItemId = result[0].id;
|
||||||
|
|
||||||
expect(result.length).toEqual(1);
|
expect(result.length).toEqual(1);
|
||||||
|
|
Loading…
Reference in New Issue