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
|
@ -8,13 +8,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
## [2316.01] - 2023-05-04
|
||||
|
||||
### Added
|
||||
-
|
||||
|
||||
### Changed
|
||||
-
|
||||
|
||||
### Changed
|
||||
- (Artículo -> Precio fijado) Modificado el buscador superior por uno lateral
|
||||
|
||||
### Fixed
|
||||
-
|
||||
-
|
||||
|
||||
|
||||
## [2314.01] - 2023-04-20
|
||||
|
||||
|
|
|
@ -122,9 +122,6 @@
|
|||
"UserConfigView": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"UserLog": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Warehouse": {
|
||||
"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'
|
||||
},
|
||||
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"]',
|
||||
fourthFixedPrice: 'vn-fixed-price tr:nth-child(5)',
|
||||
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"]',
|
||||
fourthDeleteIcon: 'vn-fixed-price tr:nth-child(5) > td:nth-child(9) > vn-icon-button[icon="delete"]',
|
||||
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: {
|
||||
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', () => {
|
||||
let browser;
|
||||
let page;
|
||||
let httpRequest;
|
||||
|
||||
beforeAll(async() => {
|
||||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('buyer', 'item');
|
||||
await page.accessToSection('item.fixedPrice');
|
||||
page.on('request', req => {
|
||||
if (req.url().includes(`FixedPrices/filter`))
|
||||
httpRequest = req.url();
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async() => {
|
||||
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() => {
|
||||
await page.waitToClick(selectors.itemFixedPrice.removeWarehouseFilter);
|
||||
await page.waitForSpinnerLoad();
|
||||
await page.waitToClick(selectors.itemFixedPrice.add);
|
||||
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() => {
|
||||
await page.accessToSection('item.index');
|
||||
await page.accessToSection('item.fixedPrice');
|
||||
await page.waitToClick(selectors.itemFixedPrice.removeWarehouseFilter);
|
||||
await page.waitForSpinnerLoad();
|
||||
await page.goto(`http://localhost:5000/#!/item/fixed-price`);
|
||||
|
||||
const result = await page.waitToGetProperty(selectors.itemFixedPrice.fourthItemID, 'value');
|
||||
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
"RoleConfig": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"RoleLog": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"RoleInherit": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
|
@ -41,10 +44,13 @@
|
|||
"Account": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"UserLog": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"UserPassword": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"UserSync": {
|
||||
"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",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "userLog"
|
||||
"table": "account.userLog"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
|
@ -16,7 +16,7 @@
|
|||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"userFk": {
|
||||
"userFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"action": {
|
||||
|
@ -50,7 +50,7 @@
|
|||
"type": "belongsTo",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"order": ["creationDate DESC", "id DESC"]
|
|
@ -19,3 +19,5 @@ import './ldap';
|
|||
import './samba';
|
||||
import './accounts';
|
||||
import './privileges';
|
||||
import './user-log';
|
||||
import './role-log';
|
||||
|
|
|
@ -8,4 +8,5 @@ Role: Rol
|
|||
Mail aliases: Alias de correo
|
||||
Account not enabled: Cuenta no habilitada
|
||||
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.mailForwarding", "icon": "forward"},
|
||||
{"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": [
|
||||
{"state": "account.role.card.basicData", "icon": "settings"},
|
||||
{"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": [
|
||||
{"state": "account.alias.card.basicData", "icon": "settings"},
|
||||
|
@ -80,6 +82,18 @@
|
|||
"description": "Basic data",
|
||||
"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",
|
||||
"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": {
|
||||
"type": "date"
|
||||
},
|
||||
"isChecked": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isChecked": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
|
|
|
@ -1,136 +1,215 @@
|
|||
<vn-crud-model
|
||||
url="Tags"
|
||||
fields="['id','name','isFree', 'sourceTable']"
|
||||
data="tags"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<div class="search-panel">
|
||||
<form class="vn-pa-lg" ng-submit="$ctrl.onSearch()">
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="General search"
|
||||
ng-model="filter.search"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
url="ItemCategories"
|
||||
label="Category"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
ng-model="filter.categoryFk">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-one
|
||||
url="ItemTypes"
|
||||
label="Type"
|
||||
where="{categoryFk: filter.categoryFk}"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
ng-model="filter.typeFk"
|
||||
fields="['categoryFk']"
|
||||
include="'category'">
|
||||
<tpl-item>
|
||||
<div>{{name}}</div>
|
||||
<div class="text-caption text-secondary">
|
||||
{{category.name}}
|
||||
</div>
|
||||
</tpl-item>
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
ng-model="filter.buyerFk"
|
||||
url="Workers/activeWithRole"
|
||||
show-field="nickname"
|
||||
search-function="{firstName: $search}"
|
||||
value-field="id"
|
||||
where="{role: {inq: ['logistic', 'buyer']}}"
|
||||
label="Buyer">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
label="Warehouse"
|
||||
ng-model="filter.warehouseFk"
|
||||
url="Warehouses">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-date-picker
|
||||
vn-one
|
||||
label="Started"
|
||||
ng-model="filter.started">
|
||||
</vn-date-picker>
|
||||
<vn-date-picker
|
||||
vn-one
|
||||
label="Ended"
|
||||
ng-model="filter.ended">
|
||||
</vn-date-picker>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-check vn-one
|
||||
triple-state="true"
|
||||
label="For me"
|
||||
ng-model="filter.mine">
|
||||
</vn-check>
|
||||
<vn-check vn-one
|
||||
triple-state="true"
|
||||
label="Minimum price"
|
||||
ng-model="filter.hasMinPrice">
|
||||
</vn-check>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="vn-pt-sm">
|
||||
<vn-one class="text-subtitle1" translate>
|
||||
Tags
|
||||
</vn-one>
|
||||
<vn-icon-button
|
||||
vn-none
|
||||
vn-bind="+"
|
||||
vn-tooltip="Add tag"
|
||||
icon="add_circle"
|
||||
ng-click="filter.tags.push({})">
|
||||
</vn-icon-button>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal ng-repeat="itemTag in filter.tags">
|
||||
<vn-autocomplete vn-two vn-id="tag"
|
||||
label="Tag"
|
||||
initial-data="itemTag.tag"
|
||||
ng-model="itemTag.tagFk"
|
||||
data="tags"
|
||||
show-field="name"
|
||||
on-change="itemTag.value = null"
|
||||
rule>
|
||||
</vn-autocomplete>
|
||||
<vn-textfield vn-three
|
||||
ng-show="tag.selection.isFree || tag.selection.isFree == undefined"
|
||||
vn-id="text"
|
||||
label="Value"
|
||||
ng-model="itemTag.value"
|
||||
rule>
|
||||
</vn-textfield>
|
||||
<vn-autocomplete vn-three
|
||||
ng-show="tag.selection.isFree === false"
|
||||
url="{{'Tags/' + itemTag.tagFk + '/filterValue'}}"
|
||||
search-function="{value: $search}"
|
||||
label="Value"
|
||||
ng-model="itemTag.value"
|
||||
show-field="value"
|
||||
value-field="value"
|
||||
rule>
|
||||
</vn-autocomplete>
|
||||
<vn-icon-button
|
||||
vn-none
|
||||
vn-tooltip="Remove tag"
|
||||
icon="delete"
|
||||
ng-click="filter.tags.splice($index, 1)"
|
||||
tabindex="-1">
|
||||
</vn-icon-button>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="vn-mt-lg">
|
||||
<vn-submit label="Search"></vn-submit>
|
||||
</vn-horizontal>
|
||||
</form>
|
||||
</div>
|
||||
<vn-crud-model url="Tags" fields="['id','name','isFree']" data="$ctrl.tags" auto-load="true" />
|
||||
<vn-crud-model url="ItemCategories" data="categories" auto-load="true" />
|
||||
<vn-side-menu side="right">
|
||||
<vn-horizontal class="input">
|
||||
<vn-textfield
|
||||
label="General search"
|
||||
ng-model="$ctrl.filter.search"
|
||||
info="Search items by id, name or barcode"
|
||||
vn-focus
|
||||
ng-keydown="$ctrl.onKeyPress($event)">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="item-category">
|
||||
<vn-autocomplete
|
||||
vn-id="category"
|
||||
data="categories"
|
||||
ng-model="$ctrl.filter.categoryFk"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
label="Category">
|
||||
</vn-autocomplete>
|
||||
<vn-one ng-repeat="category in categories">
|
||||
<vn-icon
|
||||
ng-class="{'active': $ctrl.filter.categoryFk == category.id}"
|
||||
icon="{{::category.icon}}"
|
||||
vn-tooltip="{{::category.name}}"
|
||||
ng-click="$ctrl.changeCategory(category.id)">
|
||||
</vn-icon>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
<vn-vertical class="input">
|
||||
<vn-autocomplete
|
||||
vn-id="type"
|
||||
disabled="!$ctrl.filter.categoryFk"
|
||||
url="ItemTypes"
|
||||
label="Type"
|
||||
where="{categoryFk: $ctrl.filter.categoryFk}"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
ng-model="$ctrl.filter.typeFk"
|
||||
fields="['categoryFk']"
|
||||
include="'category'"
|
||||
on-change="$ctrl.addFilters()">
|
||||
<tpl-item>
|
||||
<div>{{name}}</div>
|
||||
<div class="text-caption text-secondary">
|
||||
{{category.name}}
|
||||
</div>
|
||||
</tpl-item>
|
||||
</vn-autocomplete>
|
||||
</vn-vertical>
|
||||
<vn-horizontal class="input horizontal">
|
||||
<vn-autocomplete
|
||||
vn-id="buyer"
|
||||
disabled="false"
|
||||
ng-model="$ctrl.filter.buyerFk"
|
||||
url="Workers/activeWithRole"
|
||||
show-field="nickname"
|
||||
search-function="{firstName: $search}"
|
||||
value-field="id"
|
||||
where="{role: {inq: ['logistic', 'buyer']}}"
|
||||
label="Buyer"
|
||||
on-change="$ctrl.addFilters()">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete
|
||||
vn-id="warehouse"
|
||||
label="Warehouse"
|
||||
ng-model="$ctrl.filter.warehouseFk"
|
||||
url="Warehouses"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
on-change="$ctrl.addFilters()">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="input horizontal">
|
||||
<vn-date-picker
|
||||
label="From"
|
||||
ng-model="$ctrl.filter.started"
|
||||
on-change="$ctrl.addFilters()">
|
||||
</vn-date-picker>
|
||||
<vn-date-picker
|
||||
label="To"
|
||||
ng-model="$ctrl.filter.ended"
|
||||
on-change="$ctrl.addFilters()">
|
||||
</vn-date-picker>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="input horizontal">
|
||||
<vn-check
|
||||
label="For me"
|
||||
ng-model="$ctrl.filter.mine"
|
||||
triple-state="true"
|
||||
ng-click="$ctrl.addFilters()">
|
||||
</vn-check>
|
||||
<vn-check
|
||||
label="Minimum price"
|
||||
ng-model="$ctrl.filter.hasMinPrice"
|
||||
triple-state="true"
|
||||
ng-click="$ctrl.addFilters()">
|
||||
</vn-check>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="tags">
|
||||
<vn-one class="text-subtitle1" translate> Tags </vn-one>
|
||||
<vn-icon-button
|
||||
vn-none
|
||||
vn-tooltip="Add tag"
|
||||
icon="add_circle"
|
||||
ng-click="$ctrl.filter.tags.push({})">
|
||||
</vn-icon-button>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="tags horizontal" ng-repeat="itemTag in $ctrl.filter.tags">
|
||||
<vn-autocomplete
|
||||
vn-id="tag"
|
||||
data="$ctrl.tags"
|
||||
ng-model="itemTag.tagFk"
|
||||
show-field="name"
|
||||
label="Tag"
|
||||
on-change="itemTag.value = null">
|
||||
</vn-autocomplete>
|
||||
<vn-textfield
|
||||
ng-show="tag.selection.isFree || tag.selection.isFree == undefined"
|
||||
label="Value"
|
||||
ng-model="itemTag.value"
|
||||
ng-keydown="$ctrl.onKeyPress($event)">
|
||||
</vn-textfield>
|
||||
<vn-autocomplete
|
||||
ng-show="tag.selection.isFree === false"
|
||||
url="{{'Tags/' + itemTag.tagFk + '/filterValue'}}"
|
||||
search-function="{value: $search}"
|
||||
label="Value"
|
||||
ng-model="itemTag.value"
|
||||
show-field="value"
|
||||
value-field="value"
|
||||
on-change="$ctrl.addFilters()">
|
||||
</vn-autocomplete>
|
||||
<vn-icon-button
|
||||
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 SearchPanel from 'core/components/searchbar/search-panel';
|
||||
import './style.scss';
|
||||
|
||||
class Controller extends SearchPanel {
|
||||
get filter() {
|
||||
return this.$.filter;
|
||||
constructor($element, $) {
|
||||
super($element, $);
|
||||
}
|
||||
|
||||
set filter(value = {}) {
|
||||
if (!value.tags) value.tags = [{}];
|
||||
$onInit() {
|
||||
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', {
|
||||
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">
|
||||
</vn-crud-model>
|
||||
<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-fixed-price-search-panel
|
||||
model="model">
|
||||
</vn-fixed-price-search-panel>
|
||||
<div class="vn-w-xl">
|
||||
<vn-card>
|
||||
<smart-table
|
||||
|
|
Loading…
Reference in New Issue