diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index b907a5261..8f9fcda57 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -1260,6 +1260,21 @@ export default { importBuysButton: 'vn-entry-buy-import button[type="submit"]' }, entryLatestBuys: { + table: 'tbody > tr:not(.empty-rows)', + chip: 'vn-chip > vn-icon', + generalSearchInput: 'vn-textfield[ng-model="$ctrl.filter.search"]', + firstReignIcon: 'vn-horizontal.item-category vn-one', + typeInput: 'vn-autocomplete[ng-model="$ctrl.filter.typeFk"]', + salesPersonInput: 'vn-autocomplete[ng-model="$ctrl.filter.salesPersonFk"]', + supplierInput: 'vn-autocomplete[ng-model="$ctrl.filter.supplierFk"]', + fromInput: 'vn-date-picker[ng-model="$ctrl.filter.from"]', + toInput: 'vn-date-picker[ng-model="$ctrl.filter.to"]', + activeCheck: 'vn-check[ng-model="$ctrl.filter.active"]', + floramondoCheck: 'vn-check[ng-model="$ctrl.filter.floramondo"]', + visibleCheck: 'vn-check[ng-model="$ctrl.filter.visible"]', + addTagButton: 'vn-icon-button[vn-tooltip="Add tag"]', + itemTagInput: 'vn-autocomplete[ng-model="itemTag.tagFk"]', + itemTagValueInput: 'vn-autocomplete[ng-model="itemTag.value"]', firstBuy: 'vn-entry-latest-buys tbody > tr:nth-child(1)', allBuysCheckBox: 'vn-entry-latest-buys thead vn-check', secondBuyCheckBox: 'vn-entry-latest-buys tbody tr:nth-child(2) vn-check[ng-model="buy.checked"]', diff --git a/e2e/paths/12-entry/03_latestBuys.spec.js b/e2e/paths/12-entry/03_latestBuys.spec.js index 553d41b95..a73e12659 100644 --- a/e2e/paths/12-entry/03_latestBuys.spec.js +++ b/e2e/paths/12-entry/03_latestBuys.spec.js @@ -4,10 +4,15 @@ import getBrowser from '../../helpers/puppeteer'; describe('Entry lastest buys path', () => { let browser; let page; + const httpRequests = []; beforeAll(async() => { browser = await getBrowser(); page = browser.page; + page.on('request', req => { + if (req.url().includes(`Buys/latestBuysFilter`)) + httpRequests.push(req.url()); + }); await page.loginAndModule('buyer', 'entry'); }); @@ -20,6 +25,87 @@ describe('Entry lastest buys path', () => { await page.waitForSelector(selectors.entryLatestBuys.editBuysButton, {visible: false}); }); + it('should filter by name', async() => { + await page.write(selectors.entryLatestBuys.generalSearchInput, 'Melee'); + await page.keyboard.press('Enter'); + await page.waitToClick(selectors.entryLatestBuys.chip); + + expect(httpRequests.find(req => req.includes(('search=Melee')))).toBeDefined(); + }); + + it('should filter by reign and type', async() => { + await page.click(selectors.entryLatestBuys.firstReignIcon); + await page.autocompleteSearch(selectors.entryLatestBuys.typeInput, 'Alstroemeria'); + await page.click(selectors.entryLatestBuys.chip); + + expect(httpRequests.find(req => req.includes(('categoryFk')))).toBeDefined(); + expect(httpRequests.find(req => req.includes(('typeFk')))).toBeDefined(); + }); + + it('should filter by from date', async() => { + await page.pickDate(selectors.entryLatestBuys.fromInput, new Date()); + await page.waitToClick(selectors.entryLatestBuys.chip); + + expect(httpRequests.find(req => req.includes(('from')))).toBeDefined(); + }); + + it('should filter by to date', async() => { + await page.pickDate(selectors.entryLatestBuys.toInput, new Date()); + await page.waitToClick(selectors.entryLatestBuys.chip); + + expect(httpRequests.find(req => req.includes(('to')))).toBeDefined(); + }); + + it('should filter by sales person', async() => { + await page.autocompleteSearch(selectors.entryLatestBuys.salesPersonInput, 'buyerNick'); + await page.waitToClick(selectors.entryLatestBuys.chip); + + expect(httpRequests.find(req => req.includes(('salesPersonFk')))).toBeDefined(); + }); + + it('should filter by supplier', async() => { + await page.autocompleteSearch(selectors.entryLatestBuys.supplierInput, 'Farmer King'); + await page.waitToClick(selectors.entryLatestBuys.chip); + + expect(httpRequests.find(req => req.includes(('supplierFk')))).toBeDefined(); + }); + + it('should filter by active', async() => { + await page.waitToClick(selectors.entryLatestBuys.activeCheck); + await page.waitToClick(selectors.entryLatestBuys.activeCheck); + await page.waitToClick(selectors.entryLatestBuys.chip); + + expect(httpRequests.find(req => req.includes(('active=true')))).toBeDefined(); + expect(httpRequests.find(req => req.includes(('active=false')))).toBeDefined(); + }); + + it('should filter by visible', async() => { + await page.waitToClick(selectors.entryLatestBuys.visibleCheck); + await page.waitToClick(selectors.entryLatestBuys.visibleCheck); + await page.waitToClick(selectors.entryLatestBuys.chip); + + expect(httpRequests.find(req => req.includes(('visible=true')))).toBeDefined(); + expect(httpRequests.find(req => req.includes(('visible=false')))).toBeDefined(); + }); + + it('should filter by floramondo', async() => { + await page.waitToClick(selectors.entryLatestBuys.floramondoCheck); + await page.waitToClick(selectors.entryLatestBuys.floramondoCheck); + await page.waitToClick(selectors.entryLatestBuys.chip); + + expect(httpRequests.find(req => req.includes(('floramondo=true')))).toBeDefined(); + expect(httpRequests.find(req => req.includes(('floramondo=false')))).toBeDefined(); + }); + + it('should filter by tag Color', async() => { + await page.waitToClick(selectors.entryLatestBuys.addTagButton); + await page.autocompleteSearch(selectors.entryLatestBuys.itemTagInput, 'Color'); + await page.autocompleteSearch(selectors.entryLatestBuys.itemTagValueInput, 'Brown'); + await page.waitToClick(selectors.entryLatestBuys.chip); + + expect(httpRequests.find(req => req.includes(('tags')))).toBeDefined(); + }); + it('should select all lines but one and then check the edit buys button appears', async() => { await page.waitToClick(selectors.entryLatestBuys.allBuysCheckBox); await page.waitToClick(selectors.entryLatestBuys.secondBuyCheckBox); diff --git a/modules/entry/front/latest-buys-search-panel/index.html b/modules/entry/front/latest-buys-search-panel/index.html index 8cfab622a..bc04ccd7e 100644 --- a/modules/entry/front/latest-buys-search-panel/index.html +++ b/modules/entry/front/latest-buys-search-panel/index.html @@ -1,198 +1,243 @@ - -
-
- - - - - - - - - -
{{name}}
-
- {{category.name}} -
-
> -
-
- - - - - {{name}}: {{nickname}} - - - - - - - - - - - - - - - - - - - Tags - - - - - - - - - - - - - - - - - More fields - - - - - - - - -
- - -
-
- - -
-
- - -
-
- - -
-
- - -
- - - -
-
+ + + + + + + + + + + + + + + + + + +
{{name}}
+
+ {{category.name}} +
> +
+
+ + + + + {{name}}: {{nickname}} + + + + + + + + + + + + + + + + + + Tags + + + + + + + + + + + + + +
+ + Id/Name: {{$ctrl.filter.search}} + + + {{category.selection.name}} + + + {{type.selection.name}} + + + Sales person: {{salesPerson.selection.nickname}} + + + Supplier: {{supplier.selection.name}} + + + From: {{$ctrl.filter.from | date:'dd/MM/yyyy'}} + + + To: {{$ctrl.filter.to | date:'dd/MM/yyyy'}} + + + Active: {{$ctrl.filter.active ? '✓' : '✗'}} + + + Floramondo: {{$ctrl.filter.floramondo ? '✓' : '✗'}} + + + Visible: {{$ctrl.filter.visible ? '✓' : '✗'}} + + + {{$ctrl.showTagInfo(chipTag)}} + + +
+
diff --git a/modules/entry/front/latest-buys-search-panel/index.js b/modules/entry/front/latest-buys-search-panel/index.js index 83dc88724..a5a062302 100644 --- a/modules/entry/front/latest-buys-search-panel/index.js +++ b/modules/entry/front/latest-buys-search-panel/index.js @@ -1,67 +1,61 @@ import ngModule from '../module'; import SearchPanel from 'core/components/searchbar/search-panel'; +import './style.scss'; class Controller extends SearchPanel { constructor($element, $) { super($element, $); - let model = 'Item'; - let moreFields = ['description', 'name']; + } - let properties; - let validations = window.validations; + $onInit() { + this.filter = { + isActive: true, + tags: [] + }; + } - if (validations && validations[model]) - properties = validations[model].properties; - else - properties = {}; - - this.moreFields = []; - for (let field of moreFields) { - let prop = properties[field]; - this.moreFields.push({ - name: field, - label: prop ? prop.description : field, - type: prop ? prop.type : null - }); + changeCategory(id) { + if (this.filter.categoryFk != id) { + this.filter.categoryFk = id; + this.applyFilters(); } } - get filter() { - let filter = this.$.filter; - - for (let fieldFilter of this.fieldFilters) - filter[fieldFilter.name] = fieldFilter.value; - - return filter; + removeItemFilter(param) { + this.filter[param] = null; + if (param == 'categoryFk') this.filter['typeFk'] = null; + this.applyFilters(); } - set filter(value) { - if (!value) - value = {}; - if (!value.tags) - value.tags = [{}]; + removeTag(tag) { + const index = this.filter.tags.indexOf(tag); + if (index > -1) this.filter.tags.splice(index, 1); + this.applyFilters(); + } - this.fieldFilters = []; - for (let field of this.moreFields) { - if (value[field.name] != undefined) { - this.fieldFilters.push({ - name: field.name, - value: value[field.name], - info: field - }); - } + onKeyPress($event) { + if ($event.key === 'Enter') + this.applyFilters(); + } + + applyFilters() { + for (let i = 0; i < this.filter.tags.length; i++) { + if (!this.filter.tags[i].value) + this.filter.tags.splice(i, 1); } - - this.$.filter = value; + return this.model.applyFilter({}, this.filter); } - removeField(index, field) { - this.fieldFilters.splice(index, 1); - delete this.$.filter[field]; + showTagInfo(itemTag) { + if (!itemTag.tagFk) return itemTag.value; + return `${this.tags.find(tag => tag.id == itemTag.tagFk).name}: ${itemTag.value}`; } } ngModule.component('vnLatestBuysSearchPanel', { template: require('./index.html'), - controller: Controller + controller: Controller, + bindings: { + model: '<' + } }); diff --git a/modules/entry/front/latest-buys-search-panel/index.spec.js b/modules/entry/front/latest-buys-search-panel/index.spec.js index 9e187a25a..4cc4aa6dc 100644 --- a/modules/entry/front/latest-buys-search-panel/index.spec.js +++ b/modules/entry/front/latest-buys-search-panel/index.spec.js @@ -10,50 +10,46 @@ describe('Entry', () => { beforeEach(angular.mock.inject($componentController => { $element = angular.element(``); controller = $componentController('vnLatestBuysSearchPanel', {$element}); + controller.model = {applyFilter: () => {}}; })); - describe('filter() setter', () => { - it(`should set the tags property to the scope filter with an empty array`, () => { - const expectedFilter = { - tags: [{}] - }; - controller.filter = null; + describe('removeItemFilter()', () => { + it(`should remove param from filter`, () => { + controller.filter = {tags: [], categoryFk: 1, typeFk: 1}; + const expectFilter = {tags: [], categoryFk: null, typeFk: null}; - expect(controller.filter).toEqual(expectedFilter); - }); + controller.removeItemFilter('categoryFk'); - it(`should set the tags property to the scope filter with an array of tags`, () => { - const expectedFilter = { - description: 'My item', - tags: [{}] - }; - const expectedFieldFilter = [{ - info: { - label: 'description', - name: 'description', - type: null - }, - name: 'description', - value: 'My item' - }]; - controller.filter = { - description: 'My item' - }; - - expect(controller.filter).toEqual(expectedFilter); - expect(controller.fieldFilters).toEqual(expectedFieldFilter); + expect(controller.filter).toEqual(expectFilter); }); }); - describe('removeField()', () => { - it(`should remove the description property from the fieldFilters and from the scope filter`, () => { - const expectedFilter = {tags: [{}]}; - controller.filter = {description: 'My item'}; + describe('removeTag()', () => { + it(`should remove tag from filter`, () => { + const tag = {tagFk: 1, value: 'Value'}; + controller.filter = {tags: [tag]}; + const expectFilter = {tags: []}; - controller.removeField(0, 'description'); + controller.removeTag(tag); - expect(controller.filter).toEqual(expectedFilter); - expect(controller.fieldFilters).toEqual([]); + 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'); }); }); }); diff --git a/modules/entry/front/latest-buys-search-panel/style.scss b/modules/entry/front/latest-buys-search-panel/style.scss new file mode 100644 index 000000000..ec189c7e4 --- /dev/null +++ b/modules/entry/front/latest-buys-search-panel/style.scss @@ -0,0 +1,70 @@ +@import "variables"; + +vn-latest-buys-search-panel vn-side-menu div { + & > .input { + padding-left: $spacing-md; + padding-right: $spacing-md; + border-color: $color-spacer; + border-bottom: $border-thin; + } + & > .horizontal { + grid-auto-flow: column; + grid-column-gap: $spacing-sm; + align-items: center; + } + & > .checks { + padding: $spacing-md; + flex-wrap: wrap; + border-color: $color-spacer; + border-bottom: $border-thin; + } + & > .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; + } + } + } + } +} diff --git a/modules/entry/front/latest-buys/index.html b/modules/entry/front/latest-buys/index.html index fc44ddfc2..727b19220 100644 --- a/modules/entry/front/latest-buys/index.html +++ b/modules/entry/front/latest-buys/index.html @@ -7,17 +7,11 @@ on-data-change="$ctrl.reCheck()" auto-load="true">
- - - + + + - +