Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 4480-vnUser
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
This commit is contained in:
commit
32c9e22d96
|
@ -11,11 +11,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
-
|
-
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
-
|
- (Artículo -> Precio fijado) Modificado el buscador superior por uno lateral
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
-
|
-
|
||||||
|
|
||||||
|
|
||||||
## [2314.01] - 2023-04-20
|
## [2314.01] - 2023-04-20
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -122,9 +122,6 @@
|
||||||
"UserConfigView": {
|
"UserConfigView": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
"UserLog": {
|
|
||||||
"dataSource": "vn"
|
|
||||||
},
|
|
||||||
"Warehouse": {
|
"Warehouse": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||||
|
VALUES
|
||||||
|
('UserLog', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
|
||||||
|
('RoleLog', '*', 'READ', 'ALLOW', 'ROLE', 'employee');
|
|
@ -414,7 +414,7 @@ export default {
|
||||||
saveFieldsButton: '.vn-popover.shown vn-button[label="Save"] > button'
|
saveFieldsButton: '.vn-popover.shown vn-button[label="Save"] > button'
|
||||||
},
|
},
|
||||||
itemFixedPrice: {
|
itemFixedPrice: {
|
||||||
add: 'vn-fixed-price vn-icon-button[icon="add_circle"]',
|
add: 'vn-fixed-price vn-icon-button[vn-tooltip="Add fixed price"]',
|
||||||
firstItemID: 'vn-fixed-price tr:nth-child(2) vn-autocomplete[ng-model="price.itemFk"]',
|
firstItemID: 'vn-fixed-price tr:nth-child(2) vn-autocomplete[ng-model="price.itemFk"]',
|
||||||
fourthFixedPrice: 'vn-fixed-price tr:nth-child(5)',
|
fourthFixedPrice: 'vn-fixed-price tr:nth-child(5)',
|
||||||
fourthItemID: 'vn-fixed-price tr:nth-child(5) vn-autocomplete[ng-model="price.itemFk"]',
|
fourthItemID: 'vn-fixed-price tr:nth-child(5) vn-autocomplete[ng-model="price.itemFk"]',
|
||||||
|
@ -427,7 +427,18 @@ export default {
|
||||||
fourthEnded: 'vn-fixed-price tr:nth-child(5) vn-date-picker[ng-model="price.ended"]',
|
fourthEnded: 'vn-fixed-price tr:nth-child(5) vn-date-picker[ng-model="price.ended"]',
|
||||||
fourthDeleteIcon: 'vn-fixed-price tr:nth-child(5) > td:nth-child(9) > vn-icon-button[icon="delete"]',
|
fourthDeleteIcon: 'vn-fixed-price tr:nth-child(5) > td:nth-child(9) > vn-icon-button[icon="delete"]',
|
||||||
orderColumnId: 'vn-fixed-price th[field="itemFk"]',
|
orderColumnId: 'vn-fixed-price th[field="itemFk"]',
|
||||||
removeWarehouseFilter: 'vn-searchbar > form > vn-textfield > div.container > div.prepend > prepend > div > span:nth-child(1) > vn-icon > i'
|
removeWarehouseFilter: 'vn-searchbar > form > vn-textfield > div.container > div.prepend > prepend > div > span:nth-child(1) > vn-icon > i',
|
||||||
|
generalSearchFilter: 'vn-fixed-price-search-panel vn-textfield[ng-model="$ctrl.filter.search"]',
|
||||||
|
reignFilter: 'vn-fixed-price-search-panel vn-horizontal.item-category vn-one',
|
||||||
|
typeFilter: 'vn-fixed-price-search-panel vn-autocomplete[ng-model="$ctrl.filter.typeFk"]',
|
||||||
|
buyerFilter: 'vn-fixed-price-search-panel vn-autocomplete[ng-model="$ctrl.filter.buyerFk"]',
|
||||||
|
warehouseFilter: 'vn-fixed-price-search-panel vn-autocomplete[ng-model="$ctrl.filter.warehouseFk"]',
|
||||||
|
mineFilter: 'vn-fixed-price-search-panel vn-check[ng-model="$ctrl.filter.mine"]',
|
||||||
|
hasMinPriceFilter: 'vn-fixed-price-search-panel vn-check[ng-model="$ctrl.filter.hasMinPrice"]',
|
||||||
|
addTag: 'vn-fixed-price-search-panel vn-icon-button[icon="add_circle"]',
|
||||||
|
tagFilter: 'vn-fixed-price-search-panel vn-autocomplete[ng-model="itemTag.tagFk"]',
|
||||||
|
tagValueFilter: 'vn-fixed-price-search-panel vn-autocomplete[ng-model="itemTag.value"]',
|
||||||
|
chip: 'vn-fixed-price-search-panel vn-chip > vn-icon'
|
||||||
},
|
},
|
||||||
itemCreateView: {
|
itemCreateView: {
|
||||||
temporalName: 'vn-item-create vn-textfield[ng-model="$ctrl.item.provisionalName"]',
|
temporalName: 'vn-item-create vn-textfield[ng-model="$ctrl.item.provisionalName"]',
|
||||||
|
|
|
@ -4,20 +4,69 @@ import getBrowser from '../../helpers/puppeteer';
|
||||||
describe('Item fixed prices path', () => {
|
describe('Item fixed prices path', () => {
|
||||||
let browser;
|
let browser;
|
||||||
let page;
|
let page;
|
||||||
|
let httpRequest;
|
||||||
|
|
||||||
beforeAll(async() => {
|
beforeAll(async() => {
|
||||||
browser = await getBrowser();
|
browser = await getBrowser();
|
||||||
page = browser.page;
|
page = browser.page;
|
||||||
await page.loginAndModule('buyer', 'item');
|
await page.loginAndModule('buyer', 'item');
|
||||||
await page.accessToSection('item.fixedPrice');
|
await page.accessToSection('item.fixedPrice');
|
||||||
|
page.on('request', req => {
|
||||||
|
if (req.url().includes(`FixedPrices/filter`))
|
||||||
|
httpRequest = req.url();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async() => {
|
afterAll(async() => {
|
||||||
await browser.close();
|
await browser.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should filter using all the fields', async() => {
|
||||||
|
await page.write(selectors.itemFixedPrice.generalSearchFilter, 'item');
|
||||||
|
await page.keyboard.press('Enter');
|
||||||
|
|
||||||
|
expect(httpRequest).toContain('search=item');
|
||||||
|
|
||||||
|
await page.click(selectors.itemFixedPrice.chip);
|
||||||
|
await page.click(selectors.itemFixedPrice.reignFilter);
|
||||||
|
|
||||||
|
expect(httpRequest).toContain('categoryFk');
|
||||||
|
|
||||||
|
await page.autocompleteSearch(selectors.itemFixedPrice.typeFilter, 'Alstroemeria');
|
||||||
|
|
||||||
|
expect(httpRequest).toContain('typeFk');
|
||||||
|
|
||||||
|
await page.click(selectors.itemFixedPrice.chip);
|
||||||
|
await page.autocompleteSearch(selectors.itemFixedPrice.buyerFilter, 'buyerNick');
|
||||||
|
|
||||||
|
expect(httpRequest).toContain('buyerFk');
|
||||||
|
|
||||||
|
await page.click(selectors.itemFixedPrice.chip);
|
||||||
|
await page.autocompleteSearch(selectors.itemFixedPrice.warehouseFilter, 'Algemesi');
|
||||||
|
|
||||||
|
expect(httpRequest).toContain('warehouseFk');
|
||||||
|
|
||||||
|
await page.click(selectors.itemFixedPrice.chip);
|
||||||
|
await page.click(selectors.itemFixedPrice.mineFilter);
|
||||||
|
|
||||||
|
expect(httpRequest).toContain('mine=true');
|
||||||
|
|
||||||
|
await page.click(selectors.itemFixedPrice.chip);
|
||||||
|
await page.click(selectors.itemFixedPrice.hasMinPriceFilter);
|
||||||
|
|
||||||
|
expect(httpRequest).toContain('hasMinPrice=true');
|
||||||
|
|
||||||
|
await page.click(selectors.itemFixedPrice.chip);
|
||||||
|
await page.click(selectors.itemFixedPrice.addTag);
|
||||||
|
await page.autocompleteSearch(selectors.itemFixedPrice.tagFilter, 'Color');
|
||||||
|
await page.autocompleteSearch(selectors.itemFixedPrice.tagValueFilter, 'Brown');
|
||||||
|
|
||||||
|
expect(httpRequest).toContain('tags');
|
||||||
|
|
||||||
|
await page.click(selectors.itemFixedPrice.chip);
|
||||||
|
});
|
||||||
|
|
||||||
it('should click on the add new fixed price button', async() => {
|
it('should click on the add new fixed price button', async() => {
|
||||||
await page.waitToClick(selectors.itemFixedPrice.removeWarehouseFilter);
|
|
||||||
await page.waitForSpinnerLoad();
|
|
||||||
await page.waitToClick(selectors.itemFixedPrice.add);
|
await page.waitToClick(selectors.itemFixedPrice.add);
|
||||||
await page.waitForSelector(selectors.itemFixedPrice.fourthFixedPrice);
|
await page.waitForSelector(selectors.itemFixedPrice.fourthFixedPrice);
|
||||||
});
|
});
|
||||||
|
@ -36,10 +85,7 @@ describe('Item fixed prices path', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should reload the section and check the created price has the expected ID', async() => {
|
it('should reload the section and check the created price has the expected ID', async() => {
|
||||||
await page.accessToSection('item.index');
|
await page.goto(`http://localhost:5000/#!/item/fixed-price`);
|
||||||
await page.accessToSection('item.fixedPrice');
|
|
||||||
await page.waitToClick(selectors.itemFixedPrice.removeWarehouseFilter);
|
|
||||||
await page.waitForSpinnerLoad();
|
|
||||||
|
|
||||||
const result = await page.waitToGetProperty(selectors.itemFixedPrice.fourthItemID, 'value');
|
const result = await page.waitToGetProperty(selectors.itemFixedPrice.fourthItemID, 'value');
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,9 @@
|
||||||
"RoleConfig": {
|
"RoleConfig": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
"RoleLog": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"RoleInherit": {
|
"RoleInherit": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
@ -41,6 +44,9 @@
|
||||||
"Account": {
|
"Account": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
"UserLog": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"UserPassword": {
|
"UserPassword": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
{
|
||||||
|
"name": "RoleLog",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "account.roleLog"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"id": true,
|
||||||
|
"type": "number",
|
||||||
|
"forceId": false
|
||||||
|
},
|
||||||
|
"originFk": {
|
||||||
|
"type": "number",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"userFk": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"action": {
|
||||||
|
"type": "string",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"changedModel": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"oldInstance": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"newInstance": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"creationDate": {
|
||||||
|
"type": "date"
|
||||||
|
},
|
||||||
|
"changedModelId": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"changedModelValue": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"relations": {
|
||||||
|
"user": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Account",
|
||||||
|
"foreignKey": "userFk"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scope": {
|
||||||
|
"order": ["creationDate DESC", "id DESC"]
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
"base": "VnModel",
|
"base": "VnModel",
|
||||||
"options": {
|
"options": {
|
||||||
"mysql": {
|
"mysql": {
|
||||||
"table": "userLog"
|
"table": "account.userLog"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"properties": {
|
"properties": {
|
|
@ -19,3 +19,5 @@ import './ldap';
|
||||||
import './samba';
|
import './samba';
|
||||||
import './accounts';
|
import './accounts';
|
||||||
import './privileges';
|
import './privileges';
|
||||||
|
import './user-log';
|
||||||
|
import './role-log';
|
||||||
|
|
|
@ -9,3 +9,4 @@ Mail aliases: Alias de correo
|
||||||
Account not enabled: Cuenta no habilitada
|
Account not enabled: Cuenta no habilitada
|
||||||
Inherited roles: Roles heredados
|
Inherited roles: Roles heredados
|
||||||
Go to the user: Ir al usuario
|
Go to the user: Ir al usuario
|
||||||
|
Log: Histórico
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<vn-log url="RoleLogs" origin-id="$ctrl.$params.id"></vn-log>
|
|
@ -0,0 +1,7 @@
|
||||||
|
import ngModule from '../module';
|
||||||
|
import Section from 'salix/components/section';
|
||||||
|
|
||||||
|
ngModule.vnComponent('vnRoleLog', {
|
||||||
|
template: require('./index.html'),
|
||||||
|
controller: Section,
|
||||||
|
});
|
|
@ -20,12 +20,14 @@
|
||||||
{"state": "account.card.roles", "icon": "group"},
|
{"state": "account.card.roles", "icon": "group"},
|
||||||
{"state": "account.card.mailForwarding", "icon": "forward"},
|
{"state": "account.card.mailForwarding", "icon": "forward"},
|
||||||
{"state": "account.card.aliases", "icon": "email"},
|
{"state": "account.card.aliases", "icon": "email"},
|
||||||
{"state": "account.card.privileges", "icon": "badge"}
|
{"state": "account.card.privileges", "icon": "badge"},
|
||||||
|
{"state": "account.card.log", "icon": "history"}
|
||||||
],
|
],
|
||||||
"role": [
|
"role": [
|
||||||
{"state": "account.role.card.basicData", "icon": "settings"},
|
{"state": "account.role.card.basicData", "icon": "settings"},
|
||||||
{"state": "account.role.card.subroles", "icon": "groups"},
|
{"state": "account.role.card.subroles", "icon": "groups"},
|
||||||
{"state": "account.role.card.inherited", "icon": "account_tree"}
|
{"state": "account.role.card.inherited", "icon": "account_tree"},
|
||||||
|
{"state": "account.role.card.log", "icon": "history"}
|
||||||
],
|
],
|
||||||
"alias": [
|
"alias": [
|
||||||
{"state": "account.alias.card.basicData", "icon": "settings"},
|
{"state": "account.alias.card.basicData", "icon": "settings"},
|
||||||
|
@ -80,6 +82,18 @@
|
||||||
"description": "Basic data",
|
"description": "Basic data",
|
||||||
"acl": ["hr"]
|
"acl": ["hr"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"url" : "/log",
|
||||||
|
"state": "account.card.log",
|
||||||
|
"component": "vn-user-log",
|
||||||
|
"description": "Log"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url" : "/log",
|
||||||
|
"state": "account.role.card.log",
|
||||||
|
"component": "vn-role-log",
|
||||||
|
"description": "Log"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"url": "/roles",
|
"url": "/roles",
|
||||||
"state": "account.card.roles",
|
"state": "account.card.roles",
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<vn-log url="UserLogs" origin-id="$ctrl.$params.id"></vn-log>
|
|
@ -0,0 +1,7 @@
|
||||||
|
import ngModule from '../module';
|
||||||
|
import Section from 'salix/components/section';
|
||||||
|
|
||||||
|
ngModule.vnComponent('vnUserLog', {
|
||||||
|
template: require('./index.html'),
|
||||||
|
controller: Section,
|
||||||
|
});
|
|
@ -20,9 +20,9 @@
|
||||||
},
|
},
|
||||||
"created": {
|
"created": {
|
||||||
"type": "date"
|
"type": "date"
|
||||||
},
|
},
|
||||||
"isChecked": {
|
"isChecked": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"relations": {
|
"relations": {
|
||||||
|
|
|
@ -1,136 +1,215 @@
|
||||||
<vn-crud-model
|
<vn-crud-model url="Tags" fields="['id','name','isFree']" data="$ctrl.tags" auto-load="true" />
|
||||||
url="Tags"
|
<vn-crud-model url="ItemCategories" data="categories" auto-load="true" />
|
||||||
fields="['id','name','isFree', 'sourceTable']"
|
<vn-side-menu side="right">
|
||||||
data="tags"
|
<vn-horizontal class="input">
|
||||||
auto-load="true">
|
<vn-textfield
|
||||||
</vn-crud-model>
|
label="General search"
|
||||||
<div class="search-panel">
|
ng-model="$ctrl.filter.search"
|
||||||
<form class="vn-pa-lg" ng-submit="$ctrl.onSearch()">
|
info="Search items by id, name or barcode"
|
||||||
<vn-horizontal>
|
vn-focus
|
||||||
<vn-textfield
|
ng-keydown="$ctrl.onKeyPress($event)">
|
||||||
vn-one
|
</vn-textfield>
|
||||||
label="General search"
|
</vn-horizontal>
|
||||||
ng-model="filter.search"
|
<vn-horizontal class="item-category">
|
||||||
vn-focus>
|
<vn-autocomplete
|
||||||
</vn-textfield>
|
vn-id="category"
|
||||||
</vn-horizontal>
|
data="categories"
|
||||||
<vn-horizontal>
|
ng-model="$ctrl.filter.categoryFk"
|
||||||
<vn-autocomplete
|
show-field="name"
|
||||||
vn-one
|
value-field="id"
|
||||||
url="ItemCategories"
|
label="Category">
|
||||||
label="Category"
|
</vn-autocomplete>
|
||||||
show-field="name"
|
<vn-one ng-repeat="category in categories">
|
||||||
value-field="id"
|
<vn-icon
|
||||||
ng-model="filter.categoryFk">
|
ng-class="{'active': $ctrl.filter.categoryFk == category.id}"
|
||||||
</vn-autocomplete>
|
icon="{{::category.icon}}"
|
||||||
<vn-autocomplete vn-one
|
vn-tooltip="{{::category.name}}"
|
||||||
url="ItemTypes"
|
ng-click="$ctrl.changeCategory(category.id)">
|
||||||
label="Type"
|
</vn-icon>
|
||||||
where="{categoryFk: filter.categoryFk}"
|
</vn-one>
|
||||||
show-field="name"
|
</vn-horizontal>
|
||||||
value-field="id"
|
<vn-vertical class="input">
|
||||||
ng-model="filter.typeFk"
|
<vn-autocomplete
|
||||||
fields="['categoryFk']"
|
vn-id="type"
|
||||||
include="'category'">
|
disabled="!$ctrl.filter.categoryFk"
|
||||||
<tpl-item>
|
url="ItemTypes"
|
||||||
<div>{{name}}</div>
|
label="Type"
|
||||||
<div class="text-caption text-secondary">
|
where="{categoryFk: $ctrl.filter.categoryFk}"
|
||||||
{{category.name}}
|
show-field="name"
|
||||||
</div>
|
value-field="id"
|
||||||
</tpl-item>
|
ng-model="$ctrl.filter.typeFk"
|
||||||
</vn-autocomplete>
|
fields="['categoryFk']"
|
||||||
</vn-horizontal>
|
include="'category'"
|
||||||
<vn-horizontal>
|
on-change="$ctrl.addFilters()">
|
||||||
<vn-autocomplete
|
<tpl-item>
|
||||||
vn-one
|
<div>{{name}}</div>
|
||||||
ng-model="filter.buyerFk"
|
<div class="text-caption text-secondary">
|
||||||
url="Workers/activeWithRole"
|
{{category.name}}
|
||||||
show-field="nickname"
|
</div>
|
||||||
search-function="{firstName: $search}"
|
</tpl-item>
|
||||||
value-field="id"
|
</vn-autocomplete>
|
||||||
where="{role: {inq: ['logistic', 'buyer']}}"
|
</vn-vertical>
|
||||||
label="Buyer">
|
<vn-horizontal class="input horizontal">
|
||||||
</vn-autocomplete>
|
<vn-autocomplete
|
||||||
<vn-autocomplete
|
vn-id="buyer"
|
||||||
vn-one
|
disabled="false"
|
||||||
label="Warehouse"
|
ng-model="$ctrl.filter.buyerFk"
|
||||||
ng-model="filter.warehouseFk"
|
url="Workers/activeWithRole"
|
||||||
url="Warehouses">
|
show-field="nickname"
|
||||||
</vn-autocomplete>
|
search-function="{firstName: $search}"
|
||||||
</vn-horizontal>
|
value-field="id"
|
||||||
<vn-horizontal>
|
where="{role: {inq: ['logistic', 'buyer']}}"
|
||||||
<vn-date-picker
|
label="Buyer"
|
||||||
vn-one
|
on-change="$ctrl.addFilters()">
|
||||||
label="Started"
|
</vn-autocomplete>
|
||||||
ng-model="filter.started">
|
<vn-autocomplete
|
||||||
</vn-date-picker>
|
vn-id="warehouse"
|
||||||
<vn-date-picker
|
label="Warehouse"
|
||||||
vn-one
|
ng-model="$ctrl.filter.warehouseFk"
|
||||||
label="Ended"
|
url="Warehouses"
|
||||||
ng-model="filter.ended">
|
show-field="name"
|
||||||
</vn-date-picker>
|
value-field="id"
|
||||||
</vn-horizontal>
|
on-change="$ctrl.addFilters()">
|
||||||
<vn-horizontal>
|
</vn-autocomplete>
|
||||||
<vn-check vn-one
|
</vn-horizontal>
|
||||||
triple-state="true"
|
<vn-horizontal class="input horizontal">
|
||||||
label="For me"
|
<vn-date-picker
|
||||||
ng-model="filter.mine">
|
label="From"
|
||||||
</vn-check>
|
ng-model="$ctrl.filter.started"
|
||||||
<vn-check vn-one
|
on-change="$ctrl.addFilters()">
|
||||||
triple-state="true"
|
</vn-date-picker>
|
||||||
label="Minimum price"
|
<vn-date-picker
|
||||||
ng-model="filter.hasMinPrice">
|
label="To"
|
||||||
</vn-check>
|
ng-model="$ctrl.filter.ended"
|
||||||
</vn-horizontal>
|
on-change="$ctrl.addFilters()">
|
||||||
<vn-horizontal class="vn-pt-sm">
|
</vn-date-picker>
|
||||||
<vn-one class="text-subtitle1" translate>
|
</vn-horizontal>
|
||||||
Tags
|
<vn-horizontal class="input horizontal">
|
||||||
</vn-one>
|
<vn-check
|
||||||
<vn-icon-button
|
label="For me"
|
||||||
vn-none
|
ng-model="$ctrl.filter.mine"
|
||||||
vn-bind="+"
|
triple-state="true"
|
||||||
vn-tooltip="Add tag"
|
ng-click="$ctrl.addFilters()">
|
||||||
icon="add_circle"
|
</vn-check>
|
||||||
ng-click="filter.tags.push({})">
|
<vn-check
|
||||||
</vn-icon-button>
|
label="Minimum price"
|
||||||
</vn-horizontal>
|
ng-model="$ctrl.filter.hasMinPrice"
|
||||||
<vn-horizontal ng-repeat="itemTag in filter.tags">
|
triple-state="true"
|
||||||
<vn-autocomplete vn-two vn-id="tag"
|
ng-click="$ctrl.addFilters()">
|
||||||
label="Tag"
|
</vn-check>
|
||||||
initial-data="itemTag.tag"
|
</vn-horizontal>
|
||||||
ng-model="itemTag.tagFk"
|
<vn-horizontal class="tags">
|
||||||
data="tags"
|
<vn-one class="text-subtitle1" translate> Tags </vn-one>
|
||||||
show-field="name"
|
<vn-icon-button
|
||||||
on-change="itemTag.value = null"
|
vn-none
|
||||||
rule>
|
vn-tooltip="Add tag"
|
||||||
</vn-autocomplete>
|
icon="add_circle"
|
||||||
<vn-textfield vn-three
|
ng-click="$ctrl.filter.tags.push({})">
|
||||||
ng-show="tag.selection.isFree || tag.selection.isFree == undefined"
|
</vn-icon-button>
|
||||||
vn-id="text"
|
</vn-horizontal>
|
||||||
label="Value"
|
<vn-horizontal class="tags horizontal" ng-repeat="itemTag in $ctrl.filter.tags">
|
||||||
ng-model="itemTag.value"
|
<vn-autocomplete
|
||||||
rule>
|
vn-id="tag"
|
||||||
</vn-textfield>
|
data="$ctrl.tags"
|
||||||
<vn-autocomplete vn-three
|
ng-model="itemTag.tagFk"
|
||||||
ng-show="tag.selection.isFree === false"
|
show-field="name"
|
||||||
url="{{'Tags/' + itemTag.tagFk + '/filterValue'}}"
|
label="Tag"
|
||||||
search-function="{value: $search}"
|
on-change="itemTag.value = null">
|
||||||
label="Value"
|
</vn-autocomplete>
|
||||||
ng-model="itemTag.value"
|
<vn-textfield
|
||||||
show-field="value"
|
ng-show="tag.selection.isFree || tag.selection.isFree == undefined"
|
||||||
value-field="value"
|
label="Value"
|
||||||
rule>
|
ng-model="itemTag.value"
|
||||||
</vn-autocomplete>
|
ng-keydown="$ctrl.onKeyPress($event)">
|
||||||
<vn-icon-button
|
</vn-textfield>
|
||||||
vn-none
|
<vn-autocomplete
|
||||||
vn-tooltip="Remove tag"
|
ng-show="tag.selection.isFree === false"
|
||||||
icon="delete"
|
url="{{'Tags/' + itemTag.tagFk + '/filterValue'}}"
|
||||||
ng-click="filter.tags.splice($index, 1)"
|
search-function="{value: $search}"
|
||||||
tabindex="-1">
|
label="Value"
|
||||||
</vn-icon-button>
|
ng-model="itemTag.value"
|
||||||
</vn-horizontal>
|
show-field="value"
|
||||||
<vn-horizontal class="vn-mt-lg">
|
value-field="value"
|
||||||
<vn-submit label="Search"></vn-submit>
|
on-change="$ctrl.addFilters()">
|
||||||
</vn-horizontal>
|
</vn-autocomplete>
|
||||||
</form>
|
<vn-icon-button
|
||||||
</div>
|
vn-none
|
||||||
|
vn-tooltip="Remove tag"
|
||||||
|
icon="delete"
|
||||||
|
ng-click="$ctrl.removeTag(itemTag)">
|
||||||
|
</vn-icon-button>
|
||||||
|
</vn-horizontal>
|
||||||
|
<div class="chips">
|
||||||
|
<vn-chip
|
||||||
|
ng-if="$ctrl.filter.search"
|
||||||
|
removable="true"
|
||||||
|
on-remove="$ctrl.removeItemFilter('search')"
|
||||||
|
class="colored">
|
||||||
|
<span>Id/{{$ctrl.$t('Name')}}: {{$ctrl.filter.search}}</span>
|
||||||
|
</vn-chip>
|
||||||
|
<vn-chip
|
||||||
|
ng-if="category.selection"
|
||||||
|
removable="true"
|
||||||
|
on-remove="$ctrl.removeItemFilter('categoryFk')"
|
||||||
|
class="colored">
|
||||||
|
<span>{{$ctrl.$t('Category')}}: {{category.selection.name}}</span>
|
||||||
|
</vn-chip>
|
||||||
|
<vn-chip
|
||||||
|
ng-if="type.selection"
|
||||||
|
removable="true"
|
||||||
|
on-remove="$ctrl.removeItemFilter('typeFk')"
|
||||||
|
class="colored">
|
||||||
|
<span>{{$ctrl.$t('Type')}}: {{type.selection.name}}</span>
|
||||||
|
</vn-chip>
|
||||||
|
<vn-chip
|
||||||
|
ng-if="buyer.selection"
|
||||||
|
removable="true"
|
||||||
|
on-remove="$ctrl.removeItemFilter('buyerFk')"
|
||||||
|
class="colored">
|
||||||
|
<span>{{$ctrl.$t('Buyer')}}: {{buyer.selection.nickname}}</span>
|
||||||
|
</vn-chip>
|
||||||
|
<vn-chip
|
||||||
|
ng-if="warehouse.selection"
|
||||||
|
removable="true"
|
||||||
|
on-remove="$ctrl.removeItemFilter('warehouseFk')"
|
||||||
|
class="colored">
|
||||||
|
<span>{{$ctrl.$t('Warehouse')}}: {{warehouse.selection.name}}</span>
|
||||||
|
</vn-chip>
|
||||||
|
<vn-chip
|
||||||
|
ng-if="$ctrl.filter.started"
|
||||||
|
removable="true"
|
||||||
|
on-remove="$ctrl.removeItemFilter('started')"
|
||||||
|
class="colored">
|
||||||
|
<span>{{$ctrl.$t('Started')}}: {{$ctrl.filter.started | date:'dd/MM/yyyy'}}</span>
|
||||||
|
</vn-chip>
|
||||||
|
<vn-chip
|
||||||
|
ng-if="$ctrl.filter.ended"
|
||||||
|
removable="true"
|
||||||
|
on-remove="$ctrl.removeItemFilter('ended')"
|
||||||
|
class="colored">
|
||||||
|
<span>{{$ctrl.$t('Ended')}}: {{$ctrl.filter.ended | date:'dd/MM/yyyy'}}</span>
|
||||||
|
</vn-chip>
|
||||||
|
<vn-chip
|
||||||
|
ng-if="$ctrl.filter.mine != null"
|
||||||
|
removable="true"
|
||||||
|
on-remove="$ctrl.removeItemFilter('mine')"
|
||||||
|
class="colored">
|
||||||
|
<span>{{$ctrl.$t('For me')}}: {{$ctrl.filter.mine ? '✓' : '✗'}}</span>
|
||||||
|
</vn-chip>
|
||||||
|
<vn-chip
|
||||||
|
ng-if="$ctrl.filter.hasMinPrice != null"
|
||||||
|
removable="true"
|
||||||
|
on-remove="$ctrl.removeItemFilter('hasMinPrice')"
|
||||||
|
class="colored">
|
||||||
|
<span>{{$ctrl.$t('Minimum price')}}: {{$ctrl.filter.hasMinPrice ? '✓' : '✗'}}</span>
|
||||||
|
</vn-chip>
|
||||||
|
<vn-chip
|
||||||
|
ng-repeat="chipTag in $ctrl.filter.tags"
|
||||||
|
removable="true"
|
||||||
|
on-remove="$ctrl.removeTag(chipTag)"
|
||||||
|
class="colored"
|
||||||
|
ng-if="chipTag.value">
|
||||||
|
<span>{{$ctrl.showTagInfo(chipTag)}}</span>
|
||||||
|
</vn-chip>
|
||||||
|
</div>
|
||||||
|
</vn-side-menu>
|
||||||
|
|
|
@ -1,19 +1,60 @@
|
||||||
import ngModule from '../module';
|
import ngModule from '../module';
|
||||||
import SearchPanel from 'core/components/searchbar/search-panel';
|
import SearchPanel from 'core/components/searchbar/search-panel';
|
||||||
|
import './style.scss';
|
||||||
|
|
||||||
class Controller extends SearchPanel {
|
class Controller extends SearchPanel {
|
||||||
get filter() {
|
constructor($element, $) {
|
||||||
return this.$.filter;
|
super($element, $);
|
||||||
}
|
}
|
||||||
|
|
||||||
set filter(value = {}) {
|
$onInit() {
|
||||||
if (!value.tags) value.tags = [{}];
|
this.filter = {
|
||||||
|
tags: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
this.$.filter = value;
|
changeCategory(id) {
|
||||||
|
if (this.filter.categoryFk != id) {
|
||||||
|
this.filter.categoryFk = id;
|
||||||
|
this.addFilters();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeItemFilter(param) {
|
||||||
|
this.filter[param] = null;
|
||||||
|
if (param == 'categoryFk') this.filter['typeFk'] = null;
|
||||||
|
this.addFilters();
|
||||||
|
}
|
||||||
|
|
||||||
|
removeTag(tag) {
|
||||||
|
const index = this.filter.tags.indexOf(tag);
|
||||||
|
if (index > -1) this.filter.tags.splice(index, 1);
|
||||||
|
this.addFilters();
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyPress($event) {
|
||||||
|
if ($event.key === 'Enter')
|
||||||
|
this.addFilters();
|
||||||
|
}
|
||||||
|
|
||||||
|
addFilters() {
|
||||||
|
for (let i = 0; i < this.filter.tags.length; i++) {
|
||||||
|
if (!this.filter.tags[i].value)
|
||||||
|
this.filter.tags.splice(i, 1);
|
||||||
|
}
|
||||||
|
return this.model.addFilter({}, this.filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
showTagInfo(itemTag) {
|
||||||
|
if (!itemTag.tagFk) return itemTag.value;
|
||||||
|
return `${this.tags.find(tag => tag.id == itemTag.tagFk).name}: ${itemTag.value}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngModule.vnComponent('vnFixedPriceSearchPanel', {
|
ngModule.vnComponent('vnFixedPriceSearchPanel', {
|
||||||
template: require('./index.html'),
|
template: require('./index.html'),
|
||||||
controller: Controller
|
controller: Controller,
|
||||||
|
bindings: {
|
||||||
|
model: '<'
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
import './index.js';
|
||||||
|
|
||||||
|
describe('Item', () => {
|
||||||
|
describe('Component vnFixedPriceSearchPanel', () => {
|
||||||
|
let $element;
|
||||||
|
let controller;
|
||||||
|
|
||||||
|
beforeEach(ngModule('item'));
|
||||||
|
|
||||||
|
beforeEach(angular.mock.inject($componentController => {
|
||||||
|
$element = angular.element(`<vn-fixed-price-search-panel></vn-fixed-price-search-panel>`);
|
||||||
|
controller = $componentController('vnFixedPriceSearchPanel', {$element});
|
||||||
|
controller.model = {addFilter: () => {}};
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('removeItemFilter()', () => {
|
||||||
|
it(`should remove param from filter`, () => {
|
||||||
|
controller.filter = {tags: [], categoryFk: 1, typeFk: 1};
|
||||||
|
const expectFilter = {tags: [], categoryFk: null, typeFk: null};
|
||||||
|
|
||||||
|
controller.removeItemFilter('categoryFk');
|
||||||
|
|
||||||
|
expect(controller.filter).toEqual(expectFilter);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('removeTag()', () => {
|
||||||
|
it(`should remove tag from filter`, () => {
|
||||||
|
const tag = {tagFk: 1, value: 'Value'};
|
||||||
|
controller.filter = {tags: [tag]};
|
||||||
|
const expectFilter = {tags: []};
|
||||||
|
|
||||||
|
controller.removeTag(tag);
|
||||||
|
|
||||||
|
expect(controller.filter).toEqual(expectFilter);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('showTagInfo()', () => {
|
||||||
|
it(`should show tag value`, () => {
|
||||||
|
const tag = {value: 'Value'};
|
||||||
|
const result = controller.showTagInfo(tag);
|
||||||
|
|
||||||
|
expect(result).toEqual('Value');
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should show tag name and value`, () => {
|
||||||
|
const tag = {tagFk: 1, value: 'Value'};
|
||||||
|
controller.tags = [{id: 1, name: 'tagName'}];
|
||||||
|
const result = controller.showTagInfo(tag);
|
||||||
|
|
||||||
|
expect(result).toEqual('tagName: Value');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,71 @@
|
||||||
|
@import "variables";
|
||||||
|
|
||||||
|
vn-fixed-price-search-panel vn-side-menu {
|
||||||
|
.menu {
|
||||||
|
min-width: $right-menu-width;
|
||||||
|
}
|
||||||
|
& > div {
|
||||||
|
.input {
|
||||||
|
padding-left: $spacing-md;
|
||||||
|
padding-right: $spacing-md;
|
||||||
|
border-color: $color-spacer;
|
||||||
|
border-bottom: $border-thin;
|
||||||
|
}
|
||||||
|
.horizontal {
|
||||||
|
padding-left: $spacing-md;
|
||||||
|
padding-right: $spacing-md;
|
||||||
|
grid-auto-flow: column;
|
||||||
|
grid-column-gap: $spacing-sm;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.tags {
|
||||||
|
padding: $spacing-md;
|
||||||
|
padding-bottom: 0%;
|
||||||
|
padding-top: 0%;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.chips {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding: $spacing-md;
|
||||||
|
overflow: hidden;
|
||||||
|
max-width: 100%;
|
||||||
|
border-color: $color-spacer;
|
||||||
|
border-top: $border-thin;
|
||||||
|
}
|
||||||
|
.item-category {
|
||||||
|
padding: $spacing-sm;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: flex-start;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
vn-autocomplete[vn-id="category"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > vn-one {
|
||||||
|
padding: $spacing-sm;
|
||||||
|
min-width: 33.33%;
|
||||||
|
text-align: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
& > vn-icon {
|
||||||
|
padding: $spacing-sm;
|
||||||
|
background-color: $color-font-secondary;
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: $color-main;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
& > i:before {
|
||||||
|
font-size: 2.6rem;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,16 +14,10 @@
|
||||||
order="name">
|
order="name">
|
||||||
</vn-crud-model>
|
</vn-crud-model>
|
||||||
<vn-portal slot="topbar">
|
<vn-portal slot="topbar">
|
||||||
<vn-searchbar
|
|
||||||
auto-state="false"
|
|
||||||
panel="vn-fixed-price-search-panel"
|
|
||||||
info="Search prices by item ID or code"
|
|
||||||
suggested-filter="$ctrl.filterParams"
|
|
||||||
filter="$ctrl.filterParams"
|
|
||||||
placeholder="Search fixed prices"
|
|
||||||
model="model">
|
|
||||||
</vn-searchbar>
|
|
||||||
</vn-portal>
|
</vn-portal>
|
||||||
|
<vn-fixed-price-search-panel
|
||||||
|
model="model">
|
||||||
|
</vn-fixed-price-search-panel>
|
||||||
<div class="vn-w-xl">
|
<div class="vn-w-xl">
|
||||||
<vn-card>
|
<vn-card>
|
||||||
<smart-table
|
<smart-table
|
||||||
|
|
Loading…
Reference in New Issue