catalog filters #598

This commit is contained in:
Joan Sanchez 2018-09-14 09:10:30 +02:00
parent 8d1aa30287
commit fa31010069
19 changed files with 376 additions and 154 deletions

View File

@ -4,8 +4,7 @@
type="button" type="button"
class="mdl-textfield__input" class="mdl-textfield__input"
ng-click="$ctrl.onMouseDown($event)" ng-click="$ctrl.onMouseDown($event)"
ng-keydown="$ctrl.onKeyDown($event)"> ng-keydown="$ctrl.onKeyDown($event)"/>
</input>
<div class="icons"> <div class="icons">
<vn-icon <vn-icon
ng-show="!$ctrl.disabled" ng-show="!$ctrl.disabled"

View File

@ -1,8 +1,8 @@
<div> <vn-one>
<span ng-class="{'mdl-chip--deletable': !$ctrl.disabled}" class="mdl-chip"> <span ng-class="{'mdl-chip--deletable': !$ctrl.disabled}" class="mdl-chip">
<span class="mdl-chip__text" ng-transclude></span> <span class="mdl-chip__text ellipsize" ng-transclude></span>
<button ng-click="$ctrl.remove()" ng-show="!$ctrl.disabled" type="button" class="mdl-chip__action"> <button ng-click="$ctrl.remove()" ng-show="!$ctrl.disabled" type="button" class="mdl-chip__action">
<i class="material-icons">cancel</i> <i class="material-icons">cancel</i>
</button> </button>
</span> </span>
</div> </vn-one>

View File

@ -2,11 +2,6 @@ import ngModule from '../../module';
import './style.scss'; import './style.scss';
export default class Chip { export default class Chip {
constructor($element, $scope, $transclude) {
$transclude($scope.$parent, clone => {
angular.element($element[0].querySelector('div')).append(clone);
});
}
/** /**
* Remove chip event * Remove chip event

View File

@ -1,11 +1,18 @@
@import 'colors'; @import 'colors';
vn-chip { vn-chip {
margin: 0 0.5em 0.5em 0;
.mdl-chip { .mdl-chip {
background-color: rgba($main-01, 0.9); background-color: rgba($main-01, 0.9);
color: #FFF
} }
.mdl-chip:active { .mdl-chip:active {
background-color: $main-01 background-color: $main-01
} }
& > vn-one > span > span {
max-width: 100%;
}
} }

View File

@ -1,7 +1,7 @@
<div class="container" <div class="container"
ng-class="{selected: $ctrl.hasFocus}"> ng-class="{selected: $ctrl.hasFocus}">
<div class="textField"> <div class="textField">
<div class="leftIcons"></div> <div class="leftIcons" ng-transclude="leftIcons"></div>
<div class="infix"> <div class="infix">
<input <input
class="mdl-textfield__input" class="mdl-textfield__input"
@ -33,6 +33,6 @@
info_outline info_outline
</i> </i>
</div> </div>
<div class="rightIcons"></div> <div class="rightIcons" ng-transclude="rightIcons"></div>
</div> </div>
</div> </div>

View File

@ -3,7 +3,7 @@ import Input from '../../lib/input';
import './style.scss'; import './style.scss';
export default class Textfield extends Input { export default class Textfield extends Input {
constructor($element, $scope, $attrs, vnTemplate, $transclude) { constructor($element, $scope, $attrs, vnTemplate) {
super($element, $scope); super($element, $scope);
vnTemplate.normalizeInputAttrs($attrs); vnTemplate.normalizeInputAttrs($attrs);
this._value = null; this._value = null;
@ -14,20 +14,12 @@ export default class Textfield extends Input {
this.hasFocus = false; this.hasFocus = false;
this.hasMouseIn = false; this.hasMouseIn = false;
if ($transclude) {
$transclude($scope.$parent, tClone => {
this.leftIcons = tClone[0];
}, null, 'leftIcons');
$transclude($scope.$parent, tClone => {
this.rightIcons = tClone[0];
}, null, 'rightIcons');
}
this.input.addEventListener('keydown', () => { this.input.addEventListener('keydown', () => {
if (!this.oldValue) { if (!this.oldValue) {
this.saveOldValue(); this.saveOldValue();
} }
}); });
this.input.addEventListener('keyup', e => { this.input.addEventListener('keyup', e => {
if (e.key == "Escape") { if (e.key == "Escape") {
this.value = this.oldValue; this.value = this.oldValue;
@ -37,6 +29,7 @@ export default class Textfield extends Input {
if (e.key == "Escape" || e.key == "Enter") if (e.key == "Escape" || e.key == "Enter")
this.input.blur(); this.input.blur();
}); });
this.input.addEventListener('blur', () => { this.input.addEventListener('blur', () => {
if (this.onChange && !this.cancelled && if (this.onChange && !this.cancelled &&
(this.oldValue && this.oldValue != this.value)) (this.oldValue && this.oldValue != this.value))
@ -45,19 +38,11 @@ export default class Textfield extends Input {
this.cancelled = false; this.cancelled = false;
}); });
} }
saveOldValue() { saveOldValue() {
this.oldValue = this.value; this.oldValue = this.value;
} }
set leftIcons(value) {
for (let i = 0; i < value.children.length; i++) {
this.element.querySelector('.leftIcons').appendChild(value.children[i]);
}
}
set rightIcons(value) {
for (let i = 0; i < value.children.length; i++) {
this.element.querySelector('.rightIcons').appendChild(value.children[i]);
}
}
set value(value) { set value(value) {
this._value = (value === undefined || value === '') ? null : value; this._value = (value === undefined || value === '') ? null : value;
this.input.value = this._value; this.input.value = this._value;
@ -66,18 +51,23 @@ export default class Textfield extends Input {
if (this.hasValue) this.element.classList.add('not-empty'); if (this.hasValue) this.element.classList.add('not-empty');
else this.element.classList.remove('not-empty'); else this.element.classList.remove('not-empty');
} }
get value() { get value() {
return this._value; return this._value;
} }
set type(value) { set type(value) {
this._type = value || 'text'; this._type = value || 'text';
} }
get type() { get type() {
return this._type; return this._type;
} }
set vnTabIndex(value) { set vnTabIndex(value) {
this.input.tabindex = value; this.input.tabindex = value;
} }
clear() { clear() {
this.saveOldValue(); this.saveOldValue();
this.value = null; this.value = null;
@ -85,7 +75,7 @@ export default class Textfield extends Input {
this.input.focus(); this.input.focus();
} }
} }
Textfield.$inject = ['$element', '$scope', '$attrs', 'vnTemplate', '$transclude']; Textfield.$inject = ['$element', '$scope', '$attrs', 'vnTemplate'];
ngModule.component('vnTextfield', { ngModule.component('vnTextfield', {
template: require('./textfield.html'), template: require('./textfield.html'),

View File

@ -3,7 +3,7 @@
.icon-volume:before { content: '\e801'; } /* '' */ .icon-volume:before { content: '\e801'; } /* '' */
.icon-barcode:before { content: '\e802'; } /* '' */ .icon-barcode:before { content: '\e802'; } /* '' */
.icon-bucket:before { content: '\e803'; } /* '' */ .icon-bucket:before { content: '\e803'; } /* '' */
.icon-accesory:before { content: '\e804'; } /* '' */ .icon-accessory:before { content: '\e804'; } /* '' */
.icon-dfiscales:before { content: '\e805'; } /* '' */ .icon-dfiscales:before { content: '\e805'; } /* '' */
.icon-doc:before { content: '\e806'; } /* '' */ .icon-doc:before { content: '\e806'; } /* '' */
.icon-eye:before { content: '\e807'; } /* '' */ .icon-eye:before { content: '\e807'; } /* '' */
@ -37,7 +37,7 @@
.icon-entry:before { content: '\e829'; } /* '' */ .icon-entry:before { content: '\e829'; } /* '' */
.icon-traceability:before { content: '\e82a'; } /* '' */ .icon-traceability:before { content: '\e82a'; } /* '' */
.icon-transaction:before { content: '\e82b'; } /* '' */ .icon-transaction:before { content: '\e82b'; } /* '' */
.icon-verde:before { content: '\e82c'; } /* '' */ .icon-greenery:before { content: '\e82c'; } /* '' */
.icon-regentry:before { content: '\e82d'; } /* '' */ .icon-regentry:before { content: '\e82d'; } /* '' */
.icon-plant:before { content: '\e82e'; } /* '' */ .icon-plant:before { content: '\e82e'; } /* '' */
.icon-artificial:before { content: '\e82f'; } /* '' */ .icon-artificial:before { content: '\e82f'; } /* '' */

View File

@ -34,7 +34,7 @@
} }
}, },
{ {
"url": "/catalog?q", "url": "/catalog?category&type",
"state": "order.card.catalog", "state": "order.card.catalog",
"component": "vn-order-catalog", "component": "vn-order-catalog",
"description": "Catalog", "description": "Catalog",

View File

@ -1,7 +1,8 @@
<vn-crud-model <vn-crud-model
vn-id="model" vn-id="model"
url="/order/api/Orders/CatalogFilter" url="/order/api/Orders/CatalogFilter"
filter="::$ctrl.filter" filter="$ctrl.filter"
limit="50"
data="items" auto-load="false"> data="items" auto-load="false">
</vn-crud-model> </vn-crud-model>
@ -9,9 +10,19 @@
<vn-vertical vn-one> <vn-vertical vn-one>
<vn-card> <vn-card>
<vn-vertical> <vn-vertical>
<vn-horizontal class="catalog-header" pad-medium> <vn-horizontal class="catalog-header" pad-medium-h>
<vn-one>{{model.data.length}} <span translate>results</span></vn-one> <vn-one>{{model.data.length}} <span translate>results</span></vn-one>
<vn-one>-</vn-one> <vn-one>
<vn-autocomplete vn-none
data="$ctrl.orderList"
initial-data="$ctrl.orderBy"
field="$ctrl.orderBy"
on-change="$ctrl.setOrder(value)"
show-field="name"
value-field="order"
label="Order by">
</vn-autocomplete>
</vn-one>
</vn-horizontal> </vn-horizontal>
<vn-horizontal class="catalog-list" pad-small> <vn-horizontal class="catalog-list" pad-small>
<section class="product" ng-repeat="item in items"> <section class="product" ng-repeat="item in items">
@ -74,6 +85,10 @@
</vn-horizontal> </vn-horizontal>
</vn-vertical> </vn-vertical>
</vn-card> </vn-card>
<vn-pagination
model="model"
scroll-selector="ui-view">
</vn-pagination>
</vn-vertical> </vn-vertical>
<vn-auto class="right-block"> <vn-auto class="right-block">

View File

@ -1,29 +1,48 @@
import ngModule from '../module'; import ngModule from '../module';
import './style.scss';
class Controller { class Controller {
constructor($scope, $stateParams) { constructor($scope, $stateParams, $translate) {
this.$scope = $scope; this.$scope = $scope;
this.$stateParams = $stateParams; this.$stateParams = $stateParams;
} this.orderList = [
{
applyFilter() { order: 'relevancy DESC, name',
this.$scope.model.filter = this.filter; name: $translate.instant('Default order')
this.$scope.model.refresh(); },
} {
order: 'name',
set order(value) { name: $translate.instant('Ascendant name')
this._order = value; },
{
if (!value) return; order: 'name DESC',
name: $translate.instant('Descendant name')
},
{
order: 'price',
name: $translate.instant('Ascendant price')
},
{
order: 'price DESC',
name: $translate.instant('Descendant price')
}
];
this.filter = { this.filter = {
orderFk: value.id, order: this.orderList[0].order
where: {}
}; };
} }
get order() { get orderBy() {
return this._order; return this._orderBy;
}
set orderBy(value) {
this._orderBy = value;
}
setOrder(order) {
this.$scope.model.filter.order = order;
this.$scope.model.refresh();
} }
preview(event, item) { preview(event, item) {
@ -36,7 +55,7 @@ class Controller {
} }
} }
Controller.$inject = ['$scope', '$stateParams']; Controller.$inject = ['$scope', '$stateParams', '$translate'];
ngModule.component('vnOrderCatalog', { ngModule.component('vnOrderCatalog', {
template: require('./index.html'), template: require('./index.html'),

View File

@ -0,0 +1,18 @@
@import "colors";
.catalog-header {
border-color: $lines;
border-bottom: 1px solid rgba($lines, 0.5);
vn-one:first-child {
padding-top: 2em;
}
vn-one:nth-child(2) {
padding-top: 0.5em;
}
span {
color: $secondary-font-color
}
}

View File

@ -3,8 +3,6 @@
url="/order/api/ItemCategories" url="/order/api/ItemCategories"
data="categories"> data="categories">
</vn-crud-model> </vn-crud-model>
<vn-horizontal> <vn-horizontal>
<vn-vertical vn-one> <vn-vertical vn-one>
<vn-card > <vn-card >
@ -12,37 +10,91 @@
<vn-horizontal pad-medium class="item-category"> <vn-horizontal pad-medium class="item-category">
<vn-one margin-small-v ng-repeat="category in categories"> <vn-one margin-small-v ng-repeat="category in categories">
<vn-icon <vn-icon
ng-class="{'active': $ctrl.categoryFk == category.id}" ng-class="{'active': $ctrl.category.id == category.id}"
pad-small pad-small
icon="{{::category.icon}}" icon="{{::category.icon}}"
vn-tooltip="{{::category.name}}" vn-tooltip="{{::category.name}}"
ng-click="$ctrl.categoryFk = category.id"> ng-click="$ctrl.category = {
id: category.id,
value: category.name
}">
</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-icon icon="search"></vn-icon>
<vn-autocomplete vn-one <vn-autocomplete vn-one
initial-data="$ctrl.typeFk" vn-id="type"
field="$ctrl.typeFk"
data="$ctrl.itemTypes" data="$ctrl.itemTypes"
on-change="$ctrl.type = {
id: value,
value: type.selection.name
}"
field="$ctrl.type.id"
show-field="name" show-field="name"
value-field="id" value-field="id"
label="Type"> label="Type">
<t-left-icons>
<i class="material-icons">search</i>
</t-left-icons>
<t-right-icons>
<i class="material-icons"
ng-click="$ctrl.openPanel($event)"
style="cursor: pointer; color: #aaa">
keyboard_arrow_down
</i>
</t-right-icons>
</vn-autocomplete> </vn-autocomplete>
</vn-horizontal> </vn-horizontal>
<vn-horizontal pad-medium class="catalog-header"> <vn-horizontal pad-medium class="catalog-header">
<vn-searchbar <vn-one>
panel="vn-order-search-panel" <vn-textfield
on-search="$ctrl.onSearch(filter)" vn-id="search"
expr-builder="$ctrl.exprBuilder(param, value)"> ng-keyUp="$ctrl.onSearch($event)"
</vn-searchbar> label="Search tag"
model="$ctrl.value">
<t-left-icons>
<i class="material-icons">search</i>
</t-left-icons>
<t-right-icons>
<i class="material-icons"
ng-click="$ctrl.openPanel($event)"
style="cursor: pointer; color: #aaa">
keyboard_arrow_down
</i>
</t-right-icons>
</vn-textfield>
<vn-popover
vn-id="popover"
on-close="$ctrl.onPopoverClose()">
<vn-order-search-panel/>
</vn-popover>
</vn-one>
</vn-horizontal> </vn-horizontal>
<vn-horizontal pad-medium> <vn-horizontal pad-medium style="flex-wrap: wrap">
<vn-chip onRemove="$ctrl.onRemove($index)">Tag1</vn-chip> <vn-chip
ng-if="$ctrl.category"
vn-tooltip="Category"
on-remove="$ctrl.category = null" ellipsize>
<span translate>{{$ctrl.category.value}}</span>
</vn-chip>
<vn-chip
ng-if="$ctrl.type"
vn-tooltip="Type"
on-remove="$ctrl.type = null" ellipsize>
<span translate>{{$ctrl.type.value}}</span>
</vn-chip>
<vn-chip
ng-repeat="tag in $ctrl.tags"
vn-tooltip="Value"
on-remove="$ctrl.remove($index)" ellipsize>
<span translate>{{::tag.value}}</span>
</vn-chip>
</vn-horizontal> </vn-horizontal>
</vn-vertical> </vn-vertical>
</vn-card> </vn-card>

View File

@ -2,74 +2,175 @@ import ngModule from '../module';
import './style.scss'; import './style.scss';
class Controller { class Controller {
constructor($http) { constructor($http, $scope, $state, $compile, $transitions, $window) {
this.$http = $http; this.$http = $http;
this.$scope = $scope;
this.$state = $state;
this.$stateParams = $state.params;
this.$compile = $compile;
this.$transitions = $transitions;
this.itemTypes = []; this.itemTypes = [];
this.tags = [];
/* $transitions.onSuccess({}, transition => {
let params = {};
if (this.category)
params.category = this.category;
if (this.type)
params.type = this.type;
$window.history.replaceState(params);
this.applyFilters();
}); */
} }
get where() { get order() {
return this.catalog.filter.where; return this._order;
} }
set categoryFk(value) { set order(value) {
if (this.where['it.categoryFk'] == value) { this._order = value;
this.where['it.categoryFk'] = null;
this.where['i.typeFk'] = null; if (!value.id) return;
this.itemTypes = [];
this.$scope.$$postDigest(() => {
let category;
let type;
if (this.$stateParams.category)
category = JSON.parse(this.$stateParams.category);
if (this.$stateParams.type)
type = JSON.parse(this.$stateParams.type);
if (category && category.id)
this.category = category;
if (type && type.id)
this.type = type;
});
}
get category() {
return this._category;
}
set category(value) {
this.itemTypes = [];
this.type = null;
if (!value || (this.category && this.category.id == value.id)) {
this._category = null;
this.updateStateParams();
return; return;
} }
this.where['it.categoryFk'] = value; this._category = value;
this.where['i.typeFk'] = null; this.updateStateParams();
let query = `/item/api/ItemCategories/${value}/itemTypes`;
let 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;
}); });
} }
get categoryFk() { get type() {
return this.where['it.categoryFk']; return this._type;
} }
set typeFk(value) { set type(value) {
this.where['i.typeFk'] = value; if (value && this.type && this.type.id == value.id) return;
this.catalog.applyFilter(); if (!value || !value.id) {
} this._type = null;
this.updateStateParams();
get typeFk() { return;
return this.where['i.typeFk'];
}
onSearch(filter) {
if (!Object.keys(filter).length) return;
if (filter.search) {
console.log(this.exprBuilder('search', filter.search));
Object.assign(this.where, this.exprBuilder('search', filter.search));
} else {
Object.assign(this.where, filter);
console.log(this.where);
} }
this.catalog.applyFilter(); this._type = value;
this.updateStateParams();
this.applyFilters();
} }
exprBuilder(param, value) { onSearch(event) {
switch (param) { if (event.key !== 'Enter') return;
case 'search': this.tags.push({
return {'itg.value': {like: value}}; value: this.value
case 'itg.tagFk': });
case 'itg.value': this.$scope.search.value = null;
return {[param]: value}; 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) {
this.tags.splice(index, 1);
this.applyFilters();
}
openPanel(event) {
if (event.defaultPrevented) return;
event.preventDefault();
this.$panel = this.$compile(`<vn-order-search-panel/>`)(this.$scope.$new());
let panel = this.$panel.isolateScope().$ctrl;
panel.filter = this.filter;
panel.onSubmit = filter => this.onPanelSubmit(filter);
this.$scope.popover.parent = this.$scope.search.element;
this.$scope.popover.child = this.$panel[0];
this.$scope.popover.show();
}
onPanelSubmit(filter) {
this.$scope.popover.hide();
this.tags.push(filter);
this.applyFilters();
}
onPopoverClose() {
this.$panel.scope().$destroy();
this.$panel.remove();
this.$panel = null;
}
updateStateParams() {
let params = {};
if (this.category)
params.category = JSON.stringify(this.category);
if (this.type)
params.type = JSON.stringify(this.type);
else
params.type = undefined;
this.$state.go(this.$state.current.name, params);
} }
} }
Controller.$inject = ['$http']; Controller.$inject = ['$http', '$scope', '$state', '$compile', '$transitions', '$window'];
ngModule.component('vnCatalogFilter', { ngModule.component('vnCatalogFilter', {
template: require('./index.html'), template: require('./index.html'),

View File

@ -1,22 +1,6 @@
@import "colors"; @import "colors";
vn-catalog-filter { vn-catalog-filter {
/* .item-category, .item-category * {
vn-button button {
border-radius: 50%;
padding: 1em;
width: 4.9em;
height: 4.9em;
vn-icon i {
font-size: 32pt
}
}
} */
.item-category { .item-category {
justify-content: flex-start; justify-content: flex-start;
align-items: flex-start; align-items: flex-start;

View File

@ -1,5 +1,18 @@
Address: Consignatario Address: Consignatario
Catalogue: Catálogo Catalog: Catálogo
from: desde from: desde
results: resultados results: resultados
No results: Sin resultados No results: Sin resultados
Plant: Planta
Flower: Flor
Handmade: Confección
Green: Verde
Accessories: Complemento
Category: Reino
Search tag: Buscar etiqueta
Order by: Ordenar por
Default order: Orden predeterminado
Ascendant name: Nombre ascendiente
Descendant name: Nombre descendiente
Ascendant price: Precio ascendiente
Descendant price: Precio descendiente

View File

@ -4,7 +4,7 @@
<vn-autocomplete <vn-autocomplete
vn-one vn-one
label="Tag" label="Tag"
field="filter['itg.tagFk']" field="filter.tagFk"
url="/api/Tags" url="/api/Tags"
show-field="name" show-field="name"
value-field="id"> value-field="id">
@ -15,7 +15,7 @@
<vn-textfield <vn-textfield
vn-one vn-one
label="Value" label="Value"
model="filter['itg.value']"> model="filter.value">
</vn-textfield> </vn-textfield>
</vn-horizontal> </vn-horizontal>
<vn-horizontal margin-large-top> <vn-horizontal margin-large-top>

View File

@ -54,6 +54,7 @@ function config($stateProvider, $urlRouterProvider, aclServiceProvider, modulesF
url: route.url, url: route.url,
template: `<${route.component} ${getParams(route)}></${route.component}>`, template: `<${route.component} ${getParams(route)}></${route.component}>`,
description: route.description, description: route.description,
reloadOnSearch: false,
resolve: { resolve: {
loader: loader(moduleName, validations) loader: loader(moduleName, validations)
}, },

View File

@ -26,15 +26,6 @@
} }
} }
.catalog-header {
border-color: $lines;
border-bottom: 1px solid rgba($lines, 0.5);
span {
color: $secondary-font-color
}
}
.catalog-list { .catalog-list {
justify-content: flex-start; justify-content: flex-start;
align-items: flex-start; align-items: flex-start;

View File

@ -10,6 +10,19 @@ module.exports = Self => {
type: 'Object', type: 'Object',
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string', description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
http: {source: 'query'} http: {source: 'query'}
},
{
arg: 'args',
type: 'Object',
description: 'orderFk, categoryFk, typeFk',
required: true,
http: {source: 'query'}
},
{
arg: 'tags',
type: ['Object'],
description: 'Request tags',
http: {source: 'query'}
} }
], ],
returns: { returns: {
@ -22,7 +35,7 @@ module.exports = Self => {
} }
}); });
Self.catalogFilter = async filter => { Self.catalogFilter = async (filter, args, tags) => {
let stmts = []; let stmts = [];
let stmt; let stmt;
@ -31,23 +44,46 @@ module.exports = Self => {
stmt = new ParameterizedSQL( stmt = new ParameterizedSQL(
`CREATE TEMPORARY TABLE tmp.item `CREATE TEMPORARY TABLE tmp.item
(PRIMARY KEY (itemFk)) ENGINE = MEMORY (PRIMARY KEY (itemFk)) ENGINE = MEMORY
SELECT SELECT DISTINCT
i.id AS itemFk, i.id AS itemFk,
i.typeFk, i.typeFk,
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`
); );
if (filter.where['itg.tagFk'] || filter.where['itg.value']) { if (tags) {
stmt.merge('JOIN vn.itemTag itg ON itg.itemFk = i.id'); let i = 1;
for (let tag of tags) {
let tAlias = `it${i++}`;
if (tag.tagFk) {
stmt.merge({
sql: `JOIN vn.itemTag ${tAlias} ON ${tAlias}.itemFk = i.id
AND ${tAlias}.tagFk = ?
AND ${tAlias}.value LIKE ?`,
params: [tag.tagFk, `%${tag.value}%`]
});
} else {
stmt.merge({
sql: `JOIN vn.itemTag ${tAlias} ON ${tAlias}.itemFk = i.id
AND ${tAlias}.value LIKE ?`,
params: [`%${tag.value}%`]
});
}
}
} }
stmt.merge(Self.buildSuffix(filter)); if (args.typeFk)
stmt.merge({
sql: 'WHERE it.categoryFk = ? AND i.typeFk = ?',
params: [args.categoryFk, args.typeFk]
});
stmts.push(stmt); stmts.push(stmt);
let order = await Self.findById(filter.orderFk); let order = await Self.findById(args.orderFk);
stmts.push(new ParameterizedSQL( stmts.push(new ParameterizedSQL(
'CALL vn.ticketCalculate(?, ?, ?)', [ 'CALL vn.ticketCalculate(?, ?, ?)', [
order.landed, order.landed,
@ -56,8 +92,7 @@ module.exports = Self => {
] ]
)); ));
let itemsIndex = stmts.push( stmt = new ParameterizedSQL(`SELECT
`SELECT
i.id, i.id,
i.name, i.name,
i.subName, i.subName,
@ -77,9 +112,11 @@ 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`
ORDER BY relevancy DESC, itemFk ASC, producer DESC` );
) - 1; stmt.merge(Self.buildSuffix(filter));
// stmt.merge(Self.buildOrderBy(orderBy));
let itemsIndex = stmts.push(stmt) - 1;
let pricesIndex = stmts.push( let pricesIndex = stmts.push(
`SELECT `SELECT