catalog filter #581
This commit is contained in:
parent
46eb1e6f98
commit
300b2c2a07
|
@ -34,10 +34,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"url": "/catalogue",
|
"url": "/catalog?q",
|
||||||
"state": "order.card.catalogue",
|
"state": "order.card.catalog",
|
||||||
"component": "vn-order-catalogue",
|
"component": "vn-order-catalog",
|
||||||
"description": "Catalogue",
|
"description": "Catalog",
|
||||||
"params": {
|
"params": {
|
||||||
"order": "$ctrl.order"
|
"order": "$ctrl.order"
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
<vn-crud-model
|
||||||
|
vn-id="model"
|
||||||
|
url="/order/api/Orders/CatalogFilter"
|
||||||
|
filter="::$ctrl.filter"
|
||||||
|
data="items" auto-load="false">
|
||||||
|
</vn-crud-model>
|
||||||
|
|
||||||
|
<vn-horizontal>
|
||||||
|
<vn-vertical vn-one>
|
||||||
|
<vn-card>
|
||||||
|
<vn-vertical>
|
||||||
|
<vn-horizontal class="catalog-header" pad-medium>
|
||||||
|
<vn-one>{{model.data.length}} <span translate>results</span></vn-one>
|
||||||
|
<vn-one>-</vn-one>
|
||||||
|
</vn-horizontal>
|
||||||
|
<vn-horizontal class="catalog-list" pad-small>
|
||||||
|
<section class="product" ng-repeat="item in items">
|
||||||
|
<vn-one>
|
||||||
|
<vn-horizontal>
|
||||||
|
<vn-one class="image">
|
||||||
|
<img
|
||||||
|
ng-src="//verdnatura.es/vn-image-data/catalog/200x200/{{::item.image}}"
|
||||||
|
zoom-image="//verdnatura.es/vn-image-data/catalog/1600x900/{{::item.image}}"
|
||||||
|
on-error-src pointer/>
|
||||||
|
</vn-one>
|
||||||
|
<vn-one pad-small class="description ellipsize">
|
||||||
|
<vn-vertical>
|
||||||
|
<h2 class="ellipsize" vn-tooltip="{{::item.name}}">
|
||||||
|
{{::item.name}}
|
||||||
|
</h2>
|
||||||
|
<span class="ellipsize" vn-tooltip="{{::item.subName}}">
|
||||||
|
{{::item.subName}}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<vn-label-value
|
||||||
|
label="{{::item.tag5}}"
|
||||||
|
value="{{::item.value5}}">
|
||||||
|
</vn-label-value>
|
||||||
|
<vn-label-value
|
||||||
|
label="{{::item.tag6}}"
|
||||||
|
value="{{::item.value6}}">
|
||||||
|
</vn-label-value>
|
||||||
|
<vn-label-value
|
||||||
|
label="{{::item.tag7}}"
|
||||||
|
value="{{::item.value7}}">
|
||||||
|
</vn-label-value>
|
||||||
|
<vn-label-value
|
||||||
|
label="{{::item.tag8}}"
|
||||||
|
value="{{::item.value8}}">
|
||||||
|
</vn-label-value>
|
||||||
|
|
||||||
|
<vn-horizontal class="price">
|
||||||
|
<vn-one>
|
||||||
|
<span>{{::item.available}}</span>
|
||||||
|
<span translate>from</span>
|
||||||
|
<span>{{::item.price | currency: ' €': 2}}</span>
|
||||||
|
</vn-one>
|
||||||
|
<vn-auto>
|
||||||
|
<a href="" vn-tooltip="Add">
|
||||||
|
<vn-icon icon="add_circle" ng-click="$ctrl.preview($event, item)"></vn-icon>
|
||||||
|
</a>
|
||||||
|
</vn-auto>
|
||||||
|
</vn-horizontal>
|
||||||
|
</vn-vertical>
|
||||||
|
</vn-one>
|
||||||
|
</vn-horizontal>
|
||||||
|
</vn-one>
|
||||||
|
</section>
|
||||||
|
</vn-horizontal>
|
||||||
|
<vn-horizontal ng-if="model.data.length == 0">
|
||||||
|
<vn-one pad-small translate style="text-align: center">
|
||||||
|
No results
|
||||||
|
</vn-one>
|
||||||
|
</vn-horizontal>
|
||||||
|
</vn-vertical>
|
||||||
|
</vn-card>
|
||||||
|
</vn-vertical>
|
||||||
|
|
||||||
|
<vn-auto class="right-block">
|
||||||
|
<vn-catalog-filter order="$ctrl.order"></vn-catalog-filter>
|
||||||
|
</vn-auto>
|
||||||
|
</vn-horizontal>
|
||||||
|
|
||||||
|
<vn-order-prices-popover
|
||||||
|
vn-id="pricesPopover">
|
||||||
|
</vn-order-prices-popover>
|
|
@ -17,10 +17,8 @@ class Controller {
|
||||||
if (!value) return;
|
if (!value) return;
|
||||||
|
|
||||||
this.filter = {
|
this.filter = {
|
||||||
where: {
|
orderFk: value.id,
|
||||||
id: value.id,
|
where: {}
|
||||||
typeFk: 1
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +26,8 @@ class Controller {
|
||||||
return this._order;
|
return this._order;
|
||||||
}
|
}
|
||||||
|
|
||||||
openPricePopover(event, item) {
|
preview(event, item) {
|
||||||
|
event.preventDefault();
|
||||||
this.$scope.pricesPopover.show(event, item);
|
this.$scope.pricesPopover.show(event, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +38,7 @@ class Controller {
|
||||||
|
|
||||||
Controller.$inject = ['$scope', '$stateParams'];
|
Controller.$inject = ['$scope', '$stateParams'];
|
||||||
|
|
||||||
ngModule.component('vnOrderCatalogue', {
|
ngModule.component('vnOrderCatalog', {
|
||||||
template: require('./index.html'),
|
template: require('./index.html'),
|
||||||
controller: Controller,
|
controller: Controller,
|
||||||
bindings: {
|
bindings: {
|
|
@ -1,34 +0,0 @@
|
||||||
<vn-crud-model
|
|
||||||
vn-id="model"
|
|
||||||
url="/order/api/Orders/ItemFilter"
|
|
||||||
filter="::$ctrl.filter"
|
|
||||||
data="items" auto-load="false">
|
|
||||||
</vn-crud-model>
|
|
||||||
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-vertical vn-one>
|
|
||||||
<vn-card>
|
|
||||||
<vn-vertical>
|
|
||||||
<vn-horizontal class="catalogue header" pad-medium>
|
|
||||||
<vn-one>{{model.data.length}} <span translate>results</span></vn-one>
|
|
||||||
<vn-one>-</vn-one>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal class="catalogue list" pad-small>
|
|
||||||
<vn-order-product
|
|
||||||
ng-repeat="item in items"
|
|
||||||
item="::item">
|
|
||||||
</vn-order-product>
|
|
||||||
<vn-one style="text-align: center" pad-small translate>No results</vn-one>
|
|
||||||
</vn-horizontal>
|
|
||||||
</vn-vertical>
|
|
||||||
</vn-card>
|
|
||||||
</vn-vertical>
|
|
||||||
|
|
||||||
<vn-auto class="right-block">
|
|
||||||
<vn-filter order="$ctrl.order"></vn-filter>
|
|
||||||
</vn-auto>
|
|
||||||
</vn-horizontal>
|
|
||||||
|
|
||||||
<vn-order-prices-popover
|
|
||||||
vn-id="pricesPopover">
|
|
||||||
</vn-order-prices-popover>
|
|
|
@ -1,50 +0,0 @@
|
||||||
<vn-one>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-one class="image">
|
|
||||||
<img
|
|
||||||
ng-src="//verdnatura.es/vn-image-data/catalog/200x200/{{::$ctrl.item.image}}"
|
|
||||||
zoom-image="//verdnatura.es/vn-image-data/catalog/1600x900/{{::$ctrl.item.image}}"
|
|
||||||
on-error-src pointer/>
|
|
||||||
</vn-one>
|
|
||||||
<vn-one pad-small class="description ellipsize">
|
|
||||||
<vn-vertical>
|
|
||||||
<h2 class="ellipsize" vn-tooltip="{{::$ctrl.item.name}}">
|
|
||||||
{{::$ctrl.item.name}}
|
|
||||||
</h2>
|
|
||||||
<span class="ellipsize" vn-tooltip="{{::$ctrl.item.subName}}">
|
|
||||||
{{::$ctrl.item.subName}}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<vn-label-value
|
|
||||||
label="{{::$ctrl.item.tag5}}"
|
|
||||||
value="{{::$ctrl.item.value5}}">
|
|
||||||
</vn-label-value>
|
|
||||||
<vn-label-value
|
|
||||||
label="{{::$ctrl.item.tag6}}"
|
|
||||||
value="{{::$ctrl.item.value6}}">
|
|
||||||
</vn-label-value>
|
|
||||||
<vn-label-value
|
|
||||||
label="{{::$ctrl.item.tag7}}"
|
|
||||||
value="{{::$ctrl.item.value7}}">
|
|
||||||
</vn-label-value>
|
|
||||||
<vn-label-value
|
|
||||||
label="{{::$ctrl.item.tag8}}"
|
|
||||||
value="{{::$ctrl.item.value8}}">
|
|
||||||
</vn-label-value>
|
|
||||||
|
|
||||||
<vn-horizontal class="price">
|
|
||||||
<vn-one>
|
|
||||||
<span>{{::$ctrl.item.available}}</span>
|
|
||||||
<span translate>from</span>
|
|
||||||
<span>{{::$ctrl.item.price | currency: ' €': 2}}</span>
|
|
||||||
</vn-one>
|
|
||||||
<vn-auto>
|
|
||||||
<a href="" vn-tooltip="Add">
|
|
||||||
<vn-icon icon="add_circle" ng-click="$ctrl.preview($event)"></vn-icon>
|
|
||||||
</a>
|
|
||||||
</vn-auto>
|
|
||||||
</section>
|
|
||||||
</vn-vertical>
|
|
||||||
</vn-one>
|
|
||||||
</vn-horizontal>
|
|
||||||
</vn-one>
|
|
|
@ -1,24 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
|
|
||||||
class Controller {
|
|
||||||
onClick(event) {
|
|
||||||
if (event.defaultPrevented)
|
|
||||||
event.stopImmediatePropagation();
|
|
||||||
}
|
|
||||||
|
|
||||||
preview(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
this.index.openPricePopover(event, this.item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngModule.component('vnOrderProduct', {
|
|
||||||
template: require('./product.html'),
|
|
||||||
controller: Controller,
|
|
||||||
bindings: {
|
|
||||||
item: '<'
|
|
||||||
},
|
|
||||||
require: {
|
|
||||||
index: '^vnOrderCatalogue'
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,9 +1,49 @@
|
||||||
|
<vn-crud-model
|
||||||
|
vn-id="model"
|
||||||
|
url="/order/api/ItemCategories"
|
||||||
|
data="categories">
|
||||||
|
</vn-crud-model>
|
||||||
|
|
||||||
|
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-vertical vn-one>
|
<vn-vertical vn-one>
|
||||||
<vn-card pad-medium>
|
<vn-card >
|
||||||
<vn-vertical margin-medium>
|
<vn-vertical>
|
||||||
<vn-submit ng-click="$ctrl.setFilter()" label="Filter"></vn-submit>
|
<vn-horizontal pad-medium class="item-category">
|
||||||
|
<vn-one margin-small-v ng-repeat="category in categories">
|
||||||
|
<vn-icon
|
||||||
|
ng-class="{'active': $ctrl.categoryFk == category.id}"
|
||||||
|
pad-small
|
||||||
|
icon="{{::category.icon}}"
|
||||||
|
vn-tooltip="{{::category.name}}"
|
||||||
|
ng-click="$ctrl.categoryFk = category.id">
|
||||||
|
</vn-icon>
|
||||||
|
</vn-one>
|
||||||
|
</vn-horizontal>
|
||||||
|
|
||||||
|
<vn-horizontal pad-medium class="catalog-header">
|
||||||
|
<vn-icon icon="search"></vn-icon>
|
||||||
|
<vn-autocomplete vn-one
|
||||||
|
initial-data="$ctrl.typeFk"
|
||||||
|
field="$ctrl.typeFk"
|
||||||
|
data="$ctrl.itemTypes"
|
||||||
|
show-field="name"
|
||||||
|
value-field="id"
|
||||||
|
label="Type">
|
||||||
|
</vn-autocomplete>
|
||||||
|
</vn-horizontal>
|
||||||
|
|
||||||
|
<vn-horizontal pad-medium class="catalog-header">
|
||||||
|
<vn-searchbar
|
||||||
|
panel="vn-order-search-panel"
|
||||||
|
on-search="$ctrl.onSearch(filter)"
|
||||||
|
expr-builder="$ctrl.exprBuilder(param, value)">
|
||||||
|
</vn-searchbar>
|
||||||
|
</vn-horizontal>
|
||||||
|
|
||||||
|
<vn-horizontal pad-medium>
|
||||||
|
tags
|
||||||
|
</vn-horizontal>
|
||||||
</vn-vertical>
|
</vn-vertical>
|
||||||
</vn-card>
|
</vn-card>
|
||||||
</vn-vertical>
|
</vn-vertical>
|
||||||
|
|
|
@ -1,16 +1,81 @@
|
||||||
import ngModule from '../module';
|
import ngModule from '../module';
|
||||||
|
import './style.scss';
|
||||||
|
|
||||||
class Controller {
|
class Controller {
|
||||||
setFilter() {
|
constructor($http) {
|
||||||
this.catalogue.applyFilter();
|
this.$http = $http;
|
||||||
|
this.itemTypes = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
get where() {
|
||||||
|
return this.catalog.filter.where;
|
||||||
|
}
|
||||||
|
|
||||||
|
set categoryFk(value) {
|
||||||
|
if (this.where['it.categoryFk'] == value) {
|
||||||
|
this.where['it.categoryFk'] = null;
|
||||||
|
this.where['i.typeFk'] = null;
|
||||||
|
this.itemTypes = [];
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.where['it.categoryFk'] = value;
|
||||||
|
this.where['i.typeFk'] = null;
|
||||||
|
|
||||||
|
let query = `/item/api/ItemCategories/${value}/itemTypes`;
|
||||||
|
|
||||||
|
this.$http.get(query).then(res => {
|
||||||
|
this.itemTypes = res.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get categoryFk() {
|
||||||
|
return this.where['it.categoryFk'];
|
||||||
|
}
|
||||||
|
|
||||||
|
set typeFk(value) {
|
||||||
|
this.where['i.typeFk'] = value;
|
||||||
|
|
||||||
|
this.catalog.applyFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
get typeFk() {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
exprBuilder(param, value) {
|
||||||
|
switch (param) {
|
||||||
|
case 'search':
|
||||||
|
return {'itg.value': {like: value}};
|
||||||
|
case 'itg.tagFk':
|
||||||
|
case 'itg.value':
|
||||||
|
return {[param]: value};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngModule.component('vnFilter', {
|
Controller.$inject = ['$http'];
|
||||||
|
|
||||||
|
ngModule.component('vnCatalogFilter', {
|
||||||
template: require('./index.html'),
|
template: require('./index.html'),
|
||||||
controller: Controller,
|
controller: Controller,
|
||||||
require: {
|
require: {
|
||||||
catalogue: '^vnOrderCatalogue'
|
catalog: '^vnOrderCatalog'
|
||||||
},
|
},
|
||||||
bindings: {
|
bindings: {
|
||||||
order: '<'
|
order: '<'
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
@import "colors";
|
||||||
|
|
||||||
|
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 {
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
vn-icon {
|
||||||
|
background-color: $secondary-font-color;
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
i:before {
|
||||||
|
font-size: 32pt;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vn-icon.active {
|
||||||
|
background-color: $main-01;
|
||||||
|
color: #FFF
|
||||||
|
}
|
||||||
|
|
||||||
|
& > vn-one {
|
||||||
|
width: 33.33%;
|
||||||
|
text-align: center
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,11 +2,11 @@ export * from './module';
|
||||||
|
|
||||||
import './card';
|
import './card';
|
||||||
import './descriptor';
|
import './descriptor';
|
||||||
|
import './search-panel';
|
||||||
import './filter';
|
import './filter';
|
||||||
import './index/';
|
import './index/';
|
||||||
import './summary';
|
import './summary';
|
||||||
import './catalogue';
|
import './catalog';
|
||||||
import './catalogue/product';
|
|
||||||
import './line';
|
import './line';
|
||||||
import './prices-popover';
|
import './prices-popover';
|
||||||
import './volume';
|
import './volume';
|
||||||
|
|
|
@ -18,11 +18,11 @@
|
||||||
</vn-thead>
|
</vn-thead>
|
||||||
<vn-tbody>
|
<vn-tbody>
|
||||||
<vn-tr ng-repeat="order in orders" class="clickable"
|
<vn-tr ng-repeat="order in orders" class="clickable"
|
||||||
ui-sref="order.card.catalogue({id: {{::order.id}}})">
|
ui-sref="order.card.catalog({id: {{::order.id}}})">
|
||||||
<vn-td>{{::order.id}}</vn-td>
|
<vn-td>{{::order.id}}</vn-td>
|
||||||
<vn-td>{{::order.clientFk}}</vn-td>
|
<vn-td>{{::order.clientFk}}</vn-td>
|
||||||
<vn-td>{{::order.companyFk}}</vn-td>
|
<vn-td>{{::order.companyFk}}</vn-td>
|
||||||
<vn-td>{{::order.created}}</vn-td>
|
<vn-td>{{::order.created | date:'dd/MM/yyyy'}}</vn-td>
|
||||||
</vn-tr>
|
</vn-tr>
|
||||||
</vn-tbody>
|
</vn-tbody>
|
||||||
<vn-empty-rows ng-if="model.data.length === 0" translate>
|
<vn-empty-rows ng-if="model.data.length === 0" translate>
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
value="{{$ctrl.item.name}}">
|
value="{{$ctrl.item.name}}">
|
||||||
</vn-label-value>
|
</vn-label-value>
|
||||||
<vn-label-value label="Buyer"
|
<vn-label-value label="Buyer"
|
||||||
value="{{$ctrl.item.workerFirstName}} {{$ctrl.item.workerName}}">
|
value="{{$ctrl.item.firstName}} {{$ctrl.item.lastName}}">
|
||||||
</vn-label-value>
|
</vn-label-value>
|
||||||
<vn-label-value
|
<vn-label-value
|
||||||
ng-repeat="tag in $ctrl.tags"
|
ng-repeat="tag in $ctrl.tags"
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
<vn-vertical class="prices">
|
<vn-vertical class="prices">
|
||||||
<vn-horizontal
|
<vn-horizontal
|
||||||
ng-repeat="price in $ctrl.prices">
|
ng-repeat="price in $ctrl.prices">
|
||||||
<vn-one class="ellipsize text" title="{{::price.warehouseName}}">{{::price.warehouseName}}</vn-one>
|
<vn-one class="ellipsize text" title="{{::price.warehouse}}">{{::price.warehouse}}</vn-one>
|
||||||
<vn-one class="number text">
|
<vn-one class="number text">
|
||||||
<span orange ng-click="$ctrl.addQuantity(price)" class="link">{{::price.grouping}} x </span><span>{{::price.price | currency: ' €': 2}}</span>
|
<span orange ng-click="$ctrl.addQuantity(price)" class="link">{{::price.grouping}} x </span><span>{{::price.price | currency: ' €': 2}}</span>
|
||||||
</vn-one>
|
</vn-one>
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
<div pad-large style="min-width: 10em">
|
||||||
|
<form ng-submit="$ctrl.onSearch()">
|
||||||
|
<vn-horizontal>
|
||||||
|
<vn-autocomplete
|
||||||
|
vn-one
|
||||||
|
label="Tag"
|
||||||
|
field="filter['itg.tagFk']"
|
||||||
|
url="/api/Tags"
|
||||||
|
show-field="name"
|
||||||
|
value-field="id">
|
||||||
|
<tpl-item>{{name}}</tpl-item>
|
||||||
|
</vn-autocomplete>
|
||||||
|
</vn-horizontal>
|
||||||
|
<vn-horizontal>
|
||||||
|
<vn-textfield
|
||||||
|
vn-one
|
||||||
|
label="Value"
|
||||||
|
model="filter['itg.value']">
|
||||||
|
</vn-textfield>
|
||||||
|
</vn-horizontal>
|
||||||
|
<vn-horizontal margin-large-top>
|
||||||
|
<vn-submit label="Search"></vn-submit>
|
||||||
|
</vn-horizontal>
|
||||||
|
</form>
|
||||||
|
</div>
|
|
@ -0,0 +1,7 @@
|
||||||
|
import ngModule from '../module';
|
||||||
|
import SearchPanel from 'core/src/components/searchbar/search-panel';
|
||||||
|
|
||||||
|
ngModule.component('vnOrderSearchPanel', {
|
||||||
|
template: require('./index.html'),
|
||||||
|
controller: SearchPanel
|
||||||
|
});
|
|
@ -2,45 +2,45 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@media screen and (max-width: 1920px){
|
@media screen and (max-width: 1920px){
|
||||||
vn-order-product {
|
.catalog-list .product {
|
||||||
width: 25%;
|
width: 25%;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 1800px){
|
@media screen and (max-width: 1800px){
|
||||||
vn-order-product {
|
.catalog-list .product {
|
||||||
width: 33.33%
|
width: 33.33%
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 1600px){
|
@media screen and (max-width: 1600px){
|
||||||
vn-order-product {
|
.catalog-list .product {
|
||||||
width: 50%
|
width: 50%
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 1280px){
|
@media screen and (max-width: 1280px){
|
||||||
vn-order-product {
|
.catalog-list .product {
|
||||||
width: 100%
|
width: 100%
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.catalogue.header {
|
.catalog-header {
|
||||||
border-color: $lines;
|
border-color: $lines;
|
||||||
border-bottom: 1px solid rgba($lines, 0.5);
|
border-bottom: 1px solid rgba($lines, 0.5);
|
||||||
|
|
||||||
span {
|
span {
|
||||||
color: $secondary-font-color
|
color: $secondary-font-color
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.catalogue.list {
|
.catalog-list {
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
flex-wrap: wrap
|
flex-wrap: wrap;
|
||||||
}
|
|
||||||
vn-order-product {
|
.product {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
|
|
||||||
|
@ -108,3 +108,4 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
<vn-card pad-large>
|
<vn-card pad-large>
|
||||||
<vn-vertical>
|
<vn-vertical>
|
||||||
<vn-title>Pictures</vn-title>
|
<vn-title>Pictures</vn-title>
|
||||||
<vn-horizontal class="catalogue list" pad-small>
|
<vn-horizontal class="catalog-list" pad-small>
|
||||||
<vn-order-product ng-repeat="sale in sales">
|
<section class="product" ng-repeat="sale in sales">
|
||||||
<vn-one>
|
<vn-one>
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-one class="image">
|
<vn-one class="image">
|
||||||
|
@ -54,12 +54,12 @@
|
||||||
<span translate>by</span>
|
<span translate>by</span>
|
||||||
<span>{{::sale.price | currency: ' €': 2}}</span>
|
<span>{{::sale.price | currency: ' €': 2}}</span>
|
||||||
</vn-one>
|
</vn-one>
|
||||||
</section>
|
</vn-horizontal>
|
||||||
</vn-vertical>
|
</vn-vertical>
|
||||||
</vn-one>
|
</vn-one>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
</vn-one>
|
</vn-one>
|
||||||
</vn-order-product>
|
</section>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-horizontal ng-if="model.data.length == 0">
|
<vn-horizontal ng-if="model.data.length == 0">
|
||||||
<vn-one pad-small-v translate>
|
<vn-one pad-small-v translate>
|
||||||
|
|
|
@ -28,7 +28,7 @@ module.exports = function(Self) {
|
||||||
};
|
};
|
||||||
let insurance = await Self.findOne(filter);
|
let insurance = await Self.findOne(filter);
|
||||||
|
|
||||||
if (insurance && (!insurance.grade && this.grade || insurance.grade && ! this.grade))
|
if (insurance && (!insurance.grade && this.grade || insurance.grade && !this.grade))
|
||||||
err();
|
err();
|
||||||
|
|
||||||
done();
|
done();
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
export MYSQL_PWD=root
|
||||||
|
|
||||||
if [ -d /data/mysql ]; then
|
if [ -d /data/mysql ]; then
|
||||||
cp -R /data/mysql /var/lib
|
cp -R /data/mysql /var/lib
|
||||||
echo "Restored database to default state"
|
echo "Restored database to default state"
|
||||||
else
|
else
|
||||||
|
|
||||||
# Dump structure
|
# Dump structure
|
||||||
for file in dump/*-*.sql; do
|
for file in dump/*-*.sql; do
|
||||||
echo "Imported $file"
|
echo "Imported $file"
|
||||||
mysql -u root -proot -fc < $file
|
mysql -u root -fc < $file
|
||||||
done
|
done
|
||||||
|
|
||||||
# Import changes
|
# Import changes
|
||||||
for file in changes/*/*.sql; do
|
for file in changes/*/*.sql; do
|
||||||
echo "Imported $file"
|
echo "Imported $file"
|
||||||
mysql -u root -proot -fc < $file
|
mysql -u root -fc < $file
|
||||||
done
|
done
|
||||||
|
|
||||||
# Import fixtures
|
# Import fixtures
|
||||||
echo "Imported fixtures.sql"
|
echo "Imported fixtures.sql"
|
||||||
mysql -u root -proot -f < dump/fixtures.sql
|
mysql -u root -f < dump/fixtures.sql
|
||||||
|
|
||||||
# Copy dumpted data to volume
|
# Copy dumpted data to volume
|
||||||
cp -R /var/lib/mysql /data
|
cp -R /var/lib/mysql /data
|
||||||
|
|
|
@ -16,6 +16,4 @@ VIEW `sample` AS
|
||||||
`e`.`visible` AS `isVisible`,
|
`e`.`visible` AS `isVisible`,
|
||||||
`e`.`hasCompany` AS `hasCompany`
|
`e`.`hasCompany` AS `hasCompany`
|
||||||
FROM
|
FROM
|
||||||
`vn2008`.`escritos` `e`;
|
`vn2008`.`escritos` `e`;
|
||||||
|
|
||||||
DROP VIEW `vn`.`clientNotificationType`;
|
|
|
@ -13,6 +13,4 @@ VIEW `clientSample` AS
|
||||||
`e`.`userFk` AS `userFk`,
|
`e`.`userFk` AS `userFk`,
|
||||||
`e`.`empresa_id` AS `companyFk`
|
`e`.`empresa_id` AS `companyFk`
|
||||||
FROM
|
FROM
|
||||||
`vn2008`.`escritos_det` `e`;
|
`vn2008`.`escritos_det` `e`;
|
||||||
|
|
||||||
DROP VIEW `vn`.`clientNotification`;
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
USE `vn2008`;
|
||||||
|
|
||||||
|
ALTER TABLE `vn2008`.`reinos`
|
||||||
|
ADD COLUMN `icon` VARCHAR(45) NULL AFTER `mercancia`;
|
||||||
|
|
||||||
|
INSERT INTO `vn2008`.`reinos` (`reino`, `display`, `icon`) VALUES
|
||||||
|
('Handmade', '1', 'icon-handmade'),
|
||||||
|
('Artificial', '1', 'icon-artificial'),
|
||||||
|
('Green', '1', 'icon-greenery'),
|
||||||
|
('Accessories', '1', 'icon-accessory');
|
||||||
|
|
||||||
|
UPDATE `vn2008`.`reinos` SET `icon`='icon-plant' WHERE `id`=1;
|
||||||
|
UPDATE `vn2008`.`reinos` SET `icon`='icon-flower' WHERE `id`=2;
|
|
@ -0,0 +1,14 @@
|
||||||
|
USE `vn`;
|
||||||
|
CREATE
|
||||||
|
OR REPLACE ALGORITHM = UNDEFINED
|
||||||
|
DEFINER = `root`@`%`
|
||||||
|
SQL SECURITY DEFINER
|
||||||
|
VIEW `itemCategory` AS
|
||||||
|
SELECT
|
||||||
|
`r`.`id` AS `id`,
|
||||||
|
`r`.`reino` AS `name`,
|
||||||
|
`r`.`display` AS `display`,
|
||||||
|
`r`.`color` AS `color`,
|
||||||
|
r.icon
|
||||||
|
FROM
|
||||||
|
`vn2008`.`reinos` `r`;
|
|
@ -0,0 +1,117 @@
|
||||||
|
USE `vn`;
|
||||||
|
DROP procedure IF EXISTS `ticketCalculate`;
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
USE `vn`$$
|
||||||
|
CREATE DEFINER=`root`@`%` PROCEDURE `ticketCalculate`(
|
||||||
|
vDate DATE,
|
||||||
|
vAddress INT,
|
||||||
|
vAgencyMode INT)
|
||||||
|
proc: BEGIN
|
||||||
|
/**
|
||||||
|
* Calcula los articulos disponibles y sus precios
|
||||||
|
*
|
||||||
|
* @param vDate Fecha de recepcion de mercancia
|
||||||
|
* @param vAddress Id del consignatario
|
||||||
|
* @param vAgencyMode Id de la agencia
|
||||||
|
* @return tmp.ticketCalculateItem, tmp.ticketComponentPrice
|
||||||
|
**/
|
||||||
|
|
||||||
|
DECLARE vAvailableCalc INT;
|
||||||
|
DECLARE vShipment DATE;
|
||||||
|
DECLARE vAgencyId INT;
|
||||||
|
DECLARE vClient INT;
|
||||||
|
DECLARE vWarehouseFk SMALLINT;
|
||||||
|
DECLARE vDone BOOL;
|
||||||
|
DECLARE cTravelTree CURSOR FOR
|
||||||
|
SELECT warehouseFk, shipped FROM tmp.agencyHourGetShipped;
|
||||||
|
|
||||||
|
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
|
||||||
|
|
||||||
|
-- Establece los almacenes y las fechas que van a entrar al disponible
|
||||||
|
|
||||||
|
SELECT agencyFk INTO vAgencyId
|
||||||
|
FROM agencyMode WHERE id = vAgencyMode;
|
||||||
|
|
||||||
|
SELECT clientFk INTO vClient
|
||||||
|
FROM address WHERE id = vAddress;
|
||||||
|
|
||||||
|
CALL vn.agencyHourGetShipped(vDate, vAddress, vAgencyId);
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS tmp.ticketLot;
|
||||||
|
CREATE TEMPORARY TABLE tmp.ticketLot(
|
||||||
|
`warehouseFk` smallint(5) unsigned NOT NULL,
|
||||||
|
`itemFk` int(11) NOT NULL,
|
||||||
|
`available` double DEFAULT NULL,
|
||||||
|
`buyFk` int(11) DEFAULT NULL,
|
||||||
|
`fix` tinyint(3) unsigned DEFAULT '0',
|
||||||
|
KEY `itemFk` (`itemFk`),
|
||||||
|
KEY `item_warehouse` (`itemFk`,`warehouseFk`) USING HASH
|
||||||
|
) ENGINE=MEMORY DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
OPEN cTravelTree;
|
||||||
|
|
||||||
|
l: LOOP
|
||||||
|
SET vDone = FALSE;
|
||||||
|
FETCH cTravelTree INTO vWarehouseFk, vShipment;
|
||||||
|
|
||||||
|
IF vDone THEN
|
||||||
|
LEAVE l;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
CALL `cache`.available_refresh (vAvailableCalc, FALSE, vWarehouseFk, vShipment);
|
||||||
|
CALL buyUltimate (vWarehouseFk, vShipment);
|
||||||
|
|
||||||
|
INSERT INTO tmp.ticketLot (warehouseFk, itemFk, available, buyFk)
|
||||||
|
SELECT
|
||||||
|
vWarehouseFk,
|
||||||
|
i.item_id,
|
||||||
|
IFNULL(i.available, 0),
|
||||||
|
bu.buyFk
|
||||||
|
FROM `cache`.available i
|
||||||
|
JOIN tmp.item br ON br.itemFk = i.item_id
|
||||||
|
LEFT JOIN item it ON it.id = i.item_id
|
||||||
|
LEFT JOIN tmp.buyUltimate bu ON bu.itemFk = i.item_id
|
||||||
|
WHERE i.calc_id = vAvailableCalc
|
||||||
|
AND it.id != 100
|
||||||
|
AND i.available > 0;
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE tmp.buyUltimate;
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
CLOSE cTravelTree;
|
||||||
|
|
||||||
|
CALL vn.ticketComponentCalculate(vAddress, vAgencyMode);
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS tmp.ticketCalculateItem;
|
||||||
|
CREATE TEMPORARY TABLE tmp.ticketCalculateItem
|
||||||
|
ENGINE = MEMORY
|
||||||
|
SELECT
|
||||||
|
b.itemFk,
|
||||||
|
SUM(b.available) available,
|
||||||
|
p.name producer,
|
||||||
|
i.name item,
|
||||||
|
i.size size,
|
||||||
|
i.stems,
|
||||||
|
i.category,
|
||||||
|
i.inkFk,
|
||||||
|
i.image,
|
||||||
|
o.code origin, bl.price
|
||||||
|
FROM tmp.ticketLot b
|
||||||
|
JOIN item i ON b.itemFk = i.id
|
||||||
|
LEFT JOIN producer p ON p.id = i.producerFk AND p.isVisible
|
||||||
|
JOIN origin o ON o.id = i.originFk
|
||||||
|
JOIN (
|
||||||
|
SELECT MIN(price) price, itemFk
|
||||||
|
FROM tmp.ticketComponentPrice
|
||||||
|
GROUP BY itemFk
|
||||||
|
) bl ON bl.itemFk = b.itemFk
|
||||||
|
GROUP BY b.itemFk;
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE
|
||||||
|
tmp.ticketComponent,
|
||||||
|
tmp.ticketLot;
|
||||||
|
END$$
|
||||||
|
|
||||||
|
DELIMITER ;
|
||||||
|
|
|
@ -29,5 +29,6 @@
|
||||||
"The credit must be an integer greater than or equal to zero": "The credit must be an integer greater than or equal to zero",
|
"The credit must be an integer greater than or equal to zero": "The credit must be an integer greater than or equal to zero",
|
||||||
"The grade must be an integer greater than or equal to zero": "The grade must be an integer greater than or equal to zero",
|
"The grade must be an integer greater than or equal to zero": "The grade must be an integer greater than or equal to zero",
|
||||||
"Sample type cannot be blank": "Sample type cannot be blank",
|
"Sample type cannot be blank": "Sample type cannot be blank",
|
||||||
"The new quantity should be smaller than the old one": "La nueva cantidad debe ser menor que la anterior"
|
"The new quantity should be smaller than the old one": "La nueva cantidad debe ser menor que la anterior",
|
||||||
|
"The package cannot be blank": "The package cannot be blank"
|
||||||
}
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
{
|
||||||
|
"name": "ItemCategory",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "itemCategory"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "Number",
|
||||||
|
"id": true,
|
||||||
|
"description": "Identifier"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "String"
|
||||||
|
},
|
||||||
|
"display": {
|
||||||
|
"type": "Boolean"
|
||||||
|
},
|
||||||
|
"icon": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"relations": {
|
||||||
|
"itemTypes": {
|
||||||
|
"type": "hasMany",
|
||||||
|
"model": "ItemType",
|
||||||
|
"foreignKey": "categoryFk"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"acls": [
|
||||||
|
{
|
||||||
|
"accessType": "READ",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$everyone",
|
||||||
|
"permission": "ALLOW"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"scope": {
|
||||||
|
"where": {
|
||||||
|
"display": {"gte": 1}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,7 +35,12 @@
|
||||||
"type": "belongsTo",
|
"type": "belongsTo",
|
||||||
"model": "Warehouse",
|
"model": "Warehouse",
|
||||||
"foreignKey": "warehouseFk"
|
"foreignKey": "warehouseFk"
|
||||||
}
|
},
|
||||||
|
"category": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "ItemCategory",
|
||||||
|
"foreignKey": "categoryFk"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"acls": [
|
"acls": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -197,7 +197,7 @@ module.exports = function(Self) {
|
||||||
return sql + connector.columnEscaped(model, property);
|
return sql + connector.columnEscaped(model, property);
|
||||||
};
|
};
|
||||||
|
|
||||||
return wrappedConnector.buildWhere(this.modelName, filter.where);
|
return wrappedConnector.makeWhere(this.modelName, filter.where);
|
||||||
};
|
};
|
||||||
|
|
||||||
Self.buildLimit = function(filter) {
|
Self.buildLimit = function(filter) {
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
|
|
||||||
var mysql = require('mysql');
|
var mysql = require('mysql');
|
||||||
var SqlConnector = require('loopback-connector').SqlConnector;
|
const loopbackConnector = require('loopback-connector');
|
||||||
|
const SqlConnector = loopbackConnector.SqlConnector;
|
||||||
|
const ParameterizedSQL = loopbackConnector.ParameterizedSQL;
|
||||||
var MySQL = require('loopback-connector-mysql').MySQL;
|
var MySQL = require('loopback-connector-mysql').MySQL;
|
||||||
var EnumFactory = require('loopback-connector-mysql').EnumFactory;
|
var EnumFactory = require('loopback-connector-mysql').EnumFactory;
|
||||||
|
var debug = require('debug')('loopback-connector-sql');
|
||||||
|
|
||||||
exports.initialize = function(dataSource, callback) {
|
exports.initialize = function(dataSource, callback) {
|
||||||
dataSource.driver = mysql;
|
dataSource.driver = mysql;
|
||||||
|
@ -53,3 +56,140 @@ VnMySQL.prototype.toColumnValue = function(prop, val) {
|
||||||
return v < 10 ? '0' + v : v;
|
return v < 10 ? '0' + v : v;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private make method
|
||||||
|
* @param {Object} model Model instance
|
||||||
|
* @param {Object} where Where filter
|
||||||
|
* @return {ParameterizedSQL} Parametized object
|
||||||
|
*/
|
||||||
|
VnMySQL.prototype._makeWhere = function(model, where) {
|
||||||
|
let columnValue;
|
||||||
|
let sqlExp;
|
||||||
|
|
||||||
|
if (!where) {
|
||||||
|
return new ParameterizedSQL('');
|
||||||
|
}
|
||||||
|
if (typeof where !== 'object' || Array.isArray(where)) {
|
||||||
|
debug('Invalid value for where: %j', where);
|
||||||
|
return new ParameterizedSQL('');
|
||||||
|
}
|
||||||
|
var self = this;
|
||||||
|
var props = self.getModelDefinition(model).properties;
|
||||||
|
|
||||||
|
var whereStmts = [];
|
||||||
|
for (var key in where) {
|
||||||
|
var stmt = new ParameterizedSQL('', []);
|
||||||
|
// Handle and/or operators
|
||||||
|
if (key === 'and' || key === 'or') {
|
||||||
|
var branches = [];
|
||||||
|
var branchParams = [];
|
||||||
|
var clauses = where[key];
|
||||||
|
if (Array.isArray(clauses)) {
|
||||||
|
for (var i = 0, n = clauses.length; i < n; i++) {
|
||||||
|
var stmtForClause = self._makeWhere(model, clauses[i]);
|
||||||
|
if (stmtForClause.sql) {
|
||||||
|
stmtForClause.sql = '(' + stmtForClause.sql + ')';
|
||||||
|
branchParams = branchParams.concat(stmtForClause.params);
|
||||||
|
branches.push(stmtForClause.sql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stmt.merge({
|
||||||
|
sql: branches.join(' ' + key.toUpperCase() + ' '),
|
||||||
|
params: branchParams,
|
||||||
|
});
|
||||||
|
whereStmts.push(stmt);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// The value is not an array, fall back to regular fields
|
||||||
|
}
|
||||||
|
var p = props[key];
|
||||||
|
|
||||||
|
// eslint-disable one-var
|
||||||
|
var expression = where[key];
|
||||||
|
var columnName = self.columnEscaped(model, key);
|
||||||
|
// eslint-enable one-var
|
||||||
|
if (expression === null || expression === undefined) {
|
||||||
|
stmt.merge(columnName + ' IS NULL');
|
||||||
|
} else if (expression && expression.constructor === Object) {
|
||||||
|
var operator = Object.keys(expression)[0];
|
||||||
|
// Get the expression without the operator
|
||||||
|
expression = expression[operator];
|
||||||
|
if (operator === 'inq' || operator === 'nin' || operator === 'between') {
|
||||||
|
columnValue = [];
|
||||||
|
if (Array.isArray(expression)) {
|
||||||
|
// Column value is a list
|
||||||
|
for (var j = 0, m = expression.length; j < m; j++) {
|
||||||
|
columnValue.push(this.toColumnValue(p, expression[j]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
columnValue.push(this.toColumnValue(p, expression));
|
||||||
|
}
|
||||||
|
if (operator === 'between') {
|
||||||
|
// BETWEEN v1 AND v2
|
||||||
|
var v1 = columnValue[0] === undefined ? null : columnValue[0];
|
||||||
|
var v2 = columnValue[1] === undefined ? null : columnValue[1];
|
||||||
|
columnValue = [v1, v2];
|
||||||
|
} else {
|
||||||
|
// IN (v1,v2,v3) or NOT IN (v1,v2,v3)
|
||||||
|
if (columnValue.length === 0) {
|
||||||
|
if (operator === 'inq') {
|
||||||
|
columnValue = [null];
|
||||||
|
} else {
|
||||||
|
// nin () is true
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (operator === 'regexp' && expression instanceof RegExp) {
|
||||||
|
// do not coerce RegExp based on property definitions
|
||||||
|
columnValue = expression;
|
||||||
|
} else {
|
||||||
|
columnValue = this.toColumnValue(p, expression);
|
||||||
|
}
|
||||||
|
sqlExp = self.buildExpression(columnName, operator, columnValue, p);
|
||||||
|
stmt.merge(sqlExp);
|
||||||
|
} else {
|
||||||
|
// The expression is the field value, not a condition
|
||||||
|
columnValue = self.toColumnValue(p, expression);
|
||||||
|
if (columnValue === null) {
|
||||||
|
stmt.merge(columnName + ' IS NULL');
|
||||||
|
} else {
|
||||||
|
if (columnValue instanceof ParameterizedSQL) {
|
||||||
|
stmt.merge(columnName + '=').merge(columnValue);
|
||||||
|
} else {
|
||||||
|
stmt.merge({
|
||||||
|
sql: columnName + '=?',
|
||||||
|
params: [columnValue],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
whereStmts.push(stmt);
|
||||||
|
}
|
||||||
|
var params = [];
|
||||||
|
var sqls = [];
|
||||||
|
for (var k = 0, s = whereStmts.length; k < s; k++) {
|
||||||
|
sqls.push(whereStmts[k].sql);
|
||||||
|
params = params.concat(whereStmts[k].params);
|
||||||
|
}
|
||||||
|
var whereStmt = new ParameterizedSQL({
|
||||||
|
sql: sqls.join(' AND '),
|
||||||
|
params: params,
|
||||||
|
});
|
||||||
|
return whereStmt;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the SQL WHERE clause for the where object
|
||||||
|
* @param {string} model Model name
|
||||||
|
* @param {object} where An object for the where conditions
|
||||||
|
* @return {ParameterizedSQL} The SQL WHERE clause
|
||||||
|
*/
|
||||||
|
VnMySQL.prototype.makeWhere = function(model, where) {
|
||||||
|
var whereClause = this._makeWhere(model, where);
|
||||||
|
if (whereClause.sql) {
|
||||||
|
whereClause.sql = 'WHERE ' + whereClause.sql;
|
||||||
|
}
|
||||||
|
return whereClause;
|
||||||
|
};
|
||||||
|
|
|
@ -90,6 +90,9 @@
|
||||||
"ItemType": {
|
"ItemType": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
"ItemCategory": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"Expence": {
|
"Expence": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
const ParameterizedSQL = require('vn-loopback/node_modules/loopback-connector').ParameterizedSQL;
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('catalogFilter', {
|
||||||
|
description: 'Find all instances of the model matched by filter from the data source.',
|
||||||
|
accessType: 'READ',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'filter',
|
||||||
|
type: 'Object',
|
||||||
|
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
|
||||||
|
http: {source: 'query'}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
returns: {
|
||||||
|
type: ['Object'],
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/catalogFilter`,
|
||||||
|
verb: 'GET'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.catalogFilter = async filter => {
|
||||||
|
let stmts = [];
|
||||||
|
let stmt;
|
||||||
|
|
||||||
|
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.item');
|
||||||
|
|
||||||
|
stmt = new ParameterizedSQL(
|
||||||
|
`CREATE TEMPORARY TABLE tmp.item
|
||||||
|
(PRIMARY KEY (itemFk)) ENGINE = MEMORY
|
||||||
|
SELECT
|
||||||
|
i.id AS itemFk,
|
||||||
|
i.typeFk,
|
||||||
|
it.categoryFk
|
||||||
|
FROM vn.item i
|
||||||
|
JOIN vn.itemType it ON it.id = i.typeFk
|
||||||
|
JOIN vn.itemCategory ic ON ic.id = it.categoryFk`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (filter.where['itg.tagFk'] || filter.where['itg.value']) {
|
||||||
|
stmt.merge('JOIN vn.itemTag itg ON itg.itemFk = i.id');
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt.merge(Self.buildSuffix(filter));
|
||||||
|
stmts.push(stmt);
|
||||||
|
|
||||||
|
let order = await Self.findById(filter.orderFk);
|
||||||
|
stmts.push(new ParameterizedSQL(
|
||||||
|
'CALL vn.ticketCalculate(?, ?, ?)', [
|
||||||
|
order.landed,
|
||||||
|
order.address_id,
|
||||||
|
order.agency_id
|
||||||
|
]
|
||||||
|
));
|
||||||
|
|
||||||
|
let itemsIndex = stmts.push(
|
||||||
|
`SELECT
|
||||||
|
i.id,
|
||||||
|
i.name,
|
||||||
|
i.subName,
|
||||||
|
i.image,
|
||||||
|
i.tag5,
|
||||||
|
i.value5,
|
||||||
|
i.tag6,
|
||||||
|
i.value6,
|
||||||
|
i.tag7,
|
||||||
|
i.value7,
|
||||||
|
i.tag8,
|
||||||
|
i.value8,
|
||||||
|
tci.price,
|
||||||
|
tci.available,
|
||||||
|
w.name AS lastName,
|
||||||
|
w.firstName
|
||||||
|
FROM tmp.ticketCalculateItem tci
|
||||||
|
JOIN vn.item i ON i.id = tci.itemFk
|
||||||
|
JOIN vn.itemType it ON it.id = i.typeFk
|
||||||
|
JOIN vn.worker w on w.id = it.workerFk
|
||||||
|
ORDER BY relevancy DESC, itemFk ASC, producer DESC`
|
||||||
|
) - 1;
|
||||||
|
|
||||||
|
let pricesIndex = stmts.push(
|
||||||
|
`SELECT
|
||||||
|
tcp.itemFk,
|
||||||
|
tcp.grouping,
|
||||||
|
tcp.price,
|
||||||
|
w.name AS warehouse
|
||||||
|
FROM tmp.ticketComponentPrice tcp
|
||||||
|
JOIN vn.warehouse w ON w.id = tcp.warehouseFk`
|
||||||
|
) - 1;
|
||||||
|
|
||||||
|
stmts.push(
|
||||||
|
`DROP TEMPORARY TABLE
|
||||||
|
tmp.item,
|
||||||
|
tmp.ticketCalculateItem,
|
||||||
|
tmp.ticketComponentPrice`
|
||||||
|
);
|
||||||
|
|
||||||
|
let sql = ParameterizedSQL.join(stmts, ';');
|
||||||
|
let result = await Self.rawStmt(sql);
|
||||||
|
|
||||||
|
result[itemsIndex].forEach(item => {
|
||||||
|
result[pricesIndex].forEach(price => {
|
||||||
|
if (item.id === price.itemFk) {
|
||||||
|
if (item.prices) {
|
||||||
|
item.prices.push(price);
|
||||||
|
} else {
|
||||||
|
item.prices = [price];
|
||||||
|
}
|
||||||
|
item.available = price.grouping;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return result[itemsIndex];
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,61 +0,0 @@
|
||||||
module.exports = Self => {
|
|
||||||
Self.remoteMethod('itemFilter', {
|
|
||||||
description: 'Find all instances of the model matched by filter from the data source.',
|
|
||||||
accessType: 'READ',
|
|
||||||
accepts: [
|
|
||||||
{
|
|
||||||
arg: 'filter',
|
|
||||||
type: 'Object',
|
|
||||||
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
|
|
||||||
http: {source: 'query'}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
returns: {
|
|
||||||
type: ['Object'],
|
|
||||||
root: true
|
|
||||||
},
|
|
||||||
http: {
|
|
||||||
path: `/itemFilter`,
|
|
||||||
verb: 'GET'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Self.itemFilter = async filter => {
|
|
||||||
let where = filter.where;
|
|
||||||
let order = await Self.findById(where.id);
|
|
||||||
|
|
||||||
let stmt = `CALL vn2008.bionic_from_type(?, ?, ?, ?);
|
|
||||||
SELECT bi.*, i.*, w.name AS workerName, w.firstName AS workerFirstName FROM tmp.bionic_item bi
|
|
||||||
JOIN vn.item i ON i.id = bi.item_id
|
|
||||||
JOIN vn.itemType it ON it.id = i.typeFk
|
|
||||||
JOIN vn.worker w on w.id = it.workerFk
|
|
||||||
ORDER BY relevancy DESC, item_id ASC, producer DESC;
|
|
||||||
|
|
||||||
SELECT pri.*, w.name AS warehouseName FROM tmp.bionic_price pri
|
|
||||||
JOIN vn.warehouse w ON w.id = pri.warehouse_id;`;
|
|
||||||
|
|
||||||
let [rs, items, prices] = await Self.rawSql(stmt, [
|
|
||||||
order.landed,
|
|
||||||
order.address_id,
|
|
||||||
order.agency_id,
|
|
||||||
where.typeFk
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (items) {
|
|
||||||
items.forEach(item => {
|
|
||||||
prices.forEach(price => {
|
|
||||||
if (item.item_id === price.item_id) {
|
|
||||||
if (item.prices) {
|
|
||||||
item.prices.push(price);
|
|
||||||
} else {
|
|
||||||
item.prices = [price];
|
|
||||||
}
|
|
||||||
item.disponible = price.grouping;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return items;
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
const app = require(`${servicesDir}/order/server/server`);
|
||||||
|
|
||||||
|
describe('order catalogFilter()', () => {
|
||||||
|
it('should return an array of items', async() => {
|
||||||
|
let filter = {
|
||||||
|
orderFk: 1,
|
||||||
|
where: {
|
||||||
|
typeFk: 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let result = await app.models.Order.catalogFilter(filter);
|
||||||
|
let firstItemId = result[0].itemFk;
|
||||||
|
|
||||||
|
expect(result.length).toEqual(2);
|
||||||
|
expect(firstItemId).toEqual(3);
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,17 +0,0 @@
|
||||||
const app = require(`${servicesDir}/order/server/server`);
|
|
||||||
|
|
||||||
describe('order itemFilter()', () => {
|
|
||||||
it('should call the itemFilter method and return an array of items', async() => {
|
|
||||||
let filter = {
|
|
||||||
where: {
|
|
||||||
id: 1,
|
|
||||||
typeFk: 1
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let result = await app.models.Order.itemFilter(filter);
|
|
||||||
let firstItemId = result[0].item_id;
|
|
||||||
|
|
||||||
expect(result.length).toEqual(2);
|
|
||||||
expect(firstItemId).toEqual(3);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -5,5 +5,5 @@ module.exports = Self => {
|
||||||
require('../methods/order/getTaxes')(Self);
|
require('../methods/order/getTaxes')(Self);
|
||||||
require('../methods/order/isEditable')(Self);
|
require('../methods/order/isEditable')(Self);
|
||||||
require('../methods/order/getTotal')(Self);
|
require('../methods/order/getTotal')(Self);
|
||||||
require('../methods/order/itemFilter')(Self);
|
require('../methods/order/catalogFilter')(Self);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue