Merge branch 'dev' of http://git.verdnatura.es/salix into dev

This commit is contained in:
Carlos Jimenez 2018-04-19 15:48:29 +02:00
commit 4748f594de
41 changed files with 508 additions and 114 deletions

View File

@ -26,7 +26,7 @@ $ npm install -g karma-cli gulp webpack nodemon
Your user must be on the docker group to use it so you will need to run this command:
```
$ sudo usermod -G docker yourusername
$ sudo usermod -a -G docker yourusername
```
## Getting Started // Installing

View File

@ -41,7 +41,7 @@
<vn-autocomplete vn-one
initial-data="$ctrl.address.agencyMode"
field="$ctrl.address.agencyModeFk"
url="/client/api/AgencyModes"
url="/client/api/AgencyModes/deliveryMethod"
show-field="name"
value-field="id"
label="Agency">
@ -61,6 +61,7 @@
<vn-autocomplete
ng-if="!observation.id"
vn-one
vn-focus
initial-data="observation.observationType"
field="observation.observationTypeFk"
data="observationsTypes.model"
@ -94,15 +95,14 @@
</vn-horizontal>
</vn-one>
<vn-one>
<vn-icon
<vn-icon-button
pointer
vn-tooltip="Add note"
tooltip-position = "right"
orange
icon="add_circle"
ng-if="observationsTypes.model.length > $ctrl.observations.length"
ng-click="$ctrl.addObservation()">
</vn-icon>
</vn-icon-button>
</vn-one>
</vn-card>
<vn-button-bar>

View File

@ -30,7 +30,7 @@
<span>{{::observation.description}}</span>
</vn-one>
</vn-vertical>
<a vn-auto ui-sref="clientCard.addresses.edit({addressId: {{::address.id}}})">
<a pad-medium-h vn-auto ui-sref="clientCard.addresses.edit({addressId: {{::address.id}}})">
<vn-icon-button icon="edit"></vn-icon-button>
</a>
</vn-horizontal>

View File

@ -1,4 +1,3 @@
No: No
Yes, notify: Sí, notificar
You changed the equalization tax: Has cambiado el recargo de equivalencia
Do you want to spread the change: ¿Deseas propagar el cambio a sus consignatarios?

View File

@ -2,7 +2,7 @@
<div margin-medium>
<div class="vn-list">
<vn-card>
<vn-horizontal pad-medium>
<vn-horizontal>
<vn-searchbar vn-one
index="index"
on-search="$ctrl.search(index)"

View File

@ -125,8 +125,12 @@ export default class Autocomplete extends Input {
this.selection = data;
else
this.selection = data[0];
} else
this.selection = null;
} else {
let selection = {};
selection[this.showField] = this._field;
selection[this.valueField] = this._field;
this.selection = selection;
}
}
refreshDisplayed() {

View File

@ -5,7 +5,7 @@ vn-autocomplete > div > .mdl-textfield {
& > input {
cursor: pointer;
height: 26px;
height: 30px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;

View File

@ -40,7 +40,7 @@ export default class DropDown extends Component {
set search(value) {
value = value == '' || value == null ? null : value;
if (value === this._search) return;
if (value === this._search && this.$.model.data != null) return;
this._search = value;
this.$.model.clear();

View File

@ -13,6 +13,17 @@ export default class Model {
return this.canceler != null;
}
set url(url) {
if (this._url != url) {
this._url = url;
this.clear();
}
}
get url() {
return this._url;
}
loadMore() {
if (this.moreRows) {
let filter = Object.assign({}, this.myFilter);

View File

@ -0,0 +1,34 @@
import './model.js';
describe('Component vnModel', () => {
let $componentController;
let $httpBackend;
let controller;
beforeEach(() => {
angular.mock.module('client');
});
beforeEach(angular.mock.inject((_$componentController_, _$httpBackend_) => {
$componentController = _$componentController_;
controller = $componentController('vnModel', {$httpBackend});
}));
describe('set url', () => {
it(`should call clear function when the controller _url is undefined`, () => {
spyOn(controller, 'clear');
controller.url = 'localhost';
expect(controller._url).toEqual('localhost');
expect(controller.clear).toHaveBeenCalledWith();
});
it(`should do nothing when the url is matching`, () => {
controller._url = 'localhost';
spyOn(controller, 'clear');
controller.url = 'localhost';
expect(controller.clear).not.toHaveBeenCalledWith();
});
});
});

View File

@ -21,5 +21,29 @@
}
& > tbody > tr {
border-bottom: 1px solid #9D9D9D;
transition: background-color 200ms ease-in-out;
&.clickable {
cursor: pointer;
&:hover {
background-color: #e5e5e5;
}
}
&.success {
background-color: rgba(163, 209, 49, 0.3);
&:hover {
background-color: rgba(163, 209, 49, 0.5);
}
}
&.warning {
background-color: rgba(247, 147, 30, 0.3);
&:hover {
background-color: rgba(247, 147, 30, 0.5);
}
}
}
}

View File

@ -1,5 +1 @@
<button
class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored icon-square {{::$ctrl.className}}"
{{$ctrl.enabled}}>
<vn-icon icon="{{::$ctrl.icon}}"></vn-icon>{{::$ctrl.label}}
</button>
<vn-icon icon="{{::$ctrl.icon}}"></vn-icon>

View File

@ -1,6 +1,24 @@
import ngModule from '../../module';
import './style.scss';
export default class IconButton {
constructor($element) {
$element[0].tabIndex = 0;
$element.on("keyup", event => this.onKeyDown(event, $element));
}
onKeyDown(event, $element) {
if (event.defaultPrevented) return;
if (event.keyCode == 13) {
event.preventDefault();
$element.triggerHandler('click');
}
}
}
IconButton.$inject = ['$element'];
ngModule.component('vnIconButton', {
controller: IconButton,
template: require('./icon-button.html'),
bindings: {
icon: '@',

View File

@ -0,0 +1,17 @@
vn-icon-button {
display: inline-block;
text-align: center;
color: rgba(#f7931e, 0.7);
transition: color 200ms ease-in-out;
cursor: pointer;
& > i,
& > i.material-icons {
display: block;
font-size: inherit;
color: inherit;
}
&:hover {
color: #f7931e;
}
}

View File

@ -11,7 +11,8 @@
ng-disabled="$ctrl.disabled"
ng-readonly="$ctrl.readonly"
ng-focus="$ctrl.hasFocus = true"
ng-blur="$ctrl.hasFocus = false"/>
ng-blur="$ctrl.hasFocus = false"
tabindex="{{$ctrl.input.tabindex}}"/>
<div class="mdl-chip__action">
<i class="material-icons"
ng-if="$ctrl.hasInfo"

View File

@ -24,9 +24,11 @@ export default class Textfield extends Input {
this.hasValue = Boolean(this._value);
this.mdlUpdate();
}
set tabIndex(value) {
this.input.tabIndex = value;
set vnTabIndex(value) {
this.input.tabindex = value;
}
clear() {
this.value = null;
this.input.focus();
@ -49,6 +51,6 @@ ngModule.component('vnTextfield', {
readonly: '<?',
rule: '@?',
type: '@?',
tabIndex: '@?'
vnTabIndex: '@?'
}
});

View File

@ -0,0 +1,15 @@
import ngModule from '../module';
/**
* Returns dash when value is empty, otherwise returns the same string.
*
* @return {String} The string result
*/
export default function dashIfEmpty() {
return function(input) {
if (input == null || input == '')
return '-';
return input;
};
}
ngModule.filter('dashIfEmpty', dashIfEmpty);

View File

@ -1,2 +1,3 @@
import './phone';
import './ucwords';
import './dash-if-empty';

View File

@ -6,26 +6,27 @@
vn-three
label="Code"
model="barcode.code"
vn-acl="buyer, replenisher">
vn-acl="buyer, replenisher"
vn-focus>
</vn-textfield>
<vn-icon
pad-medium-top
vn-acl="buyer,replenisher"
pointer
medium-grey
vn-tooltip="Remove note"
vn-tooltip="Remove barcode"
tooltip-position="left"
icon="remove_circle_outline"
ng-click="$ctrl.removeBarcode($index)">
</vn-icon>
</vn-horizontal>
<vn-one>
<vn-icon
<vn-icon-button
vn-acl="buyer, replenisher"
pointer vn-tooltip="Add note"
tooltip-position="right" orange icon="add_circle"
vn-tooltip="Add barcode"
tooltip-position="right" icon="add_circle"
ng-click="$ctrl.addBarcode()">
</vn-icon>
</vn-icon-button>
</vn-one>
</vn-card>
<vn-button-bar>

View File

@ -2,7 +2,7 @@
<div margin-medium>
<div class="vn-list">
<vn-card>
<vn-horizontal pad-medium>
<vn-horizontal>
<vn-searchbar vn-one
index="index"
on-search="$ctrl.search(index)"

View File

@ -10,6 +10,7 @@
<vn-autocomplete
ng-if="!itemNiche.id"
vn-one
vn-focus
data="$ctrl.warehouses"
show-field="name"
value-field="id"
@ -20,6 +21,7 @@
</vn-autocomplete>
<vn-textfield
ng-if="itemNiche.id"
vn-focus
vn-one
label="Warehouse"
model="itemNiche.warehouse.name"
@ -37,19 +39,19 @@
vn-acl="buyer,replenisher"
pointer
medium-grey
vn-tooltip="Remove note"
vn-tooltip="Remove niche"
tooltip-position="left"
icon="remove_circle_outline"
ng-click="$ctrl.removeNiche($index)">
</vn-icon>
</vn-horizontal>
<vn-one>
<vn-icon
<vn-icon-button
vn-acl="buyer, replenisher"
pointer vn-tooltip="Add note"
tooltip-position="right" orange icon="add_circle"
vn-tooltip="Add niche"
tooltip-position="right" icon="add_circle"
ng-click="$ctrl.addNiche()">
</vn-icon>
</vn-icon-button>
</vn-one>
</vn-card>
<vn-button-bar>

View File

@ -6,32 +6,41 @@
<form name="form" ng-submit="$ctrl.submit()">
<vn-card pad-large>
<vn-title>Item tags</vn-title>
<vn-horizontal ng-repeat="itemTag in $ctrl.instancedItemTags track by $index">
<vn-horizontal ng-repeat="itemTag in $ctrl.instancedItemTags">
<vn-autocomplete
ng-if="!itemTag.id"
vn-id="tag"
vn-one
initial-data="itemTag.tag"
field="itemTag.tagFk"
data="tags.model"
show-field="name"
label="Tag"
vn-acl="buyer">
on-change="$ctrl.checkAutocompleteChanges(itemTag)"
vn-acl="buyer"
vn-focus
disabled="itemTag.id != null">
</vn-autocomplete>
<vn-textfield
ng-if="itemTag.id"
vn-one
label="Tag"
model="itemTag.tag.name"
disabled="true">
</vn-textfield>
<vn-textfield
ng-show="tag.selection.isFree || tag.selection.isFree == undefined"
vn-id="text"
vn-three
label="Value"
model="itemTag.value"
rule="itemTag.value"
vn-acl="buyer">
</vn-textfield>
<vn-autocomplete
ng-show="tag.selection.isFree === false"
vn-three
url="{{$ctrl.getSourceTable(tag.selection)}}"
label="Value"
field="itemTag.value"
show-field="name"
value-field="name"
vn-acl="buyer">
</vn-autocomplete>
<vn-textfield
vn-tab-index="-1"
vn-one
type="number"
label="Relevancy"
@ -39,25 +48,24 @@
rule="itemTag.priority"
vn-acl="buyer">
</vn-textfield>
<vn-one pad-medium-top></vn-one>
<vn-icon
pad-medium-top
pointer
medium-grey
vn-tooltip="Remove tag"
tooltip-position="left"
icon="remove_circle_outline"
ng-click="$ctrl.removeItemTag($index)"
vn-acl="buyer">
ng-click="$ctrl.removeItemTag($index)">
</vn-icon>
<vn-icon
pointer
margin-medium-left
orange
icon="add_circle"
ng-if="itemTag.showAddIcon && tags.model.length > $ctrl.instancedItemTags.length"
ng-click="$ctrl.addItemTag()"
vn-acl="buyer">
</vn-icon>
</vn-one>
</vn-horizontal>
<vn-one>
<vn-icon-button
vn-tooltip="Add tag"
tooltip-position="right"
icon="add_circle"
ng-click="$ctrl.addItemTag()">
</vn-icon-button>
</vn-one>
</vn-card>
<vn-button-bar>
<vn-submit label="Save"></vn-submit>

View File

@ -20,10 +20,9 @@ class ItemTags {
return true;
});
this.instancedItemTags[this.instancedItemTags.length - 1].showAddIcon = true;
} else {
this.addItemTag();
}
}
_setDirtyForm() {
if (this.$scope.form) {
this.$scope.form.$setDirty();
@ -35,9 +34,13 @@ class ItemTags {
}
}
checkAutocompleteChanges(itemTag) {
itemTag.value = null;
}
addItemTag() {
if (this.instancedItemTags) {
this.instancedItemTags.push({value: null, itemFk: this.params.id, tagFk: null, priority: this.getMaxPriority(this.instancedItemTags) + 1, showAddIcon: true});
this.instancedItemTags.push({value: null, itemFk: this.params.id, tagFk: null, priority: this.getHighestPriority(this.instancedItemTags), showAddIcon: true});
this._setIconAdd();
}
}
@ -54,13 +57,25 @@ class ItemTags {
}
}
getMaxPriority(instancedItemTags) {
getHighestPriority(instancedItemTags) {
let max = 0;
instancedItemTags.forEach(tag => {
if (tag.priority > max)
max = tag.priority;
});
return max;
return max + 1;
}
getSourceTable(selection) {
if (!selection || selection.isFree === true)
return null;
if (selection.sourceTable) {
return "/api/" + selection.sourceTable.charAt(0).toUpperCase() +
selection.sourceTable.substring(1) + 's';
} else if (selection.sourceTable == null) {
return `/api/ItemTags/filterItemTags/${selection.id}`;
}
}
_equalItemTags(oldTag, newTag) {
@ -147,6 +162,7 @@ ngModule.component('vnItemTags', {
template: require('./tags.html'),
controller: ItemTags,
bindings: {
itemTags: '='
itemTags: '=',
selection: '<?'
}
});

View File

@ -50,6 +50,45 @@ describe('Item', () => {
});
});
describe('getHighestPriority', () => {
it('should return the highest priority value + 1 from the array', () => {
let tags = [{priority: 1}, {priority: 2}, {priority: 1}];
let result = controller.getHighestPriority(tags);
expect(result).toEqual(3);
});
it('should return 1 when there is no priority defined', () => {
let tags = [];
let result = controller.getHighestPriority(tags);
expect(result).toEqual(1);
});
});
describe('getSourceTable', () => {
it('should return null when the property isFree equals true', () => {
let selection = {isFree: true};
let result = controller.getSourceTable(selection);
expect(result).toBe(null);
});
it('should return the route of the model in loopback with the first char of the string uppercase and adding a s', () => {
let selection = {sourceTable: "ink"};
let result = controller.getSourceTable(selection);
expect(result).toBe("/api/Inks");
});
it('should return the route filteritemtags with the id of the selection', () => {
let selection = {id: 3, sourceTable: null, isFree: false};
let result = controller.getSourceTable(selection);
expect(result).toBe("/api/ItemTags/filterItemTags/3");
});
});
describe('_equalItemTags()', () => {
it('should return true if two tags are equals independent of control attributes', () => {
let tag1 = {id: 1, typeFk: 1, value: '1111', showAddIcon: true};

View File

@ -1,15 +1,18 @@
<form ng-submit="$ctrl.onSubmit()">
<vn-horizontal>
<vn-icon-button
icon="search"
ng-click="$ctrl.clearFilter(); $ctrl.onSubmit()"
style="cursor: pointer; padding-top: 23px">
</vn-icon-button>
<vn-textfield vn-one label="Search" model="$ctrl.stringSearch"></vn-textfield>
<vn-icon
pad-medium-top
ng-if="$ctrl.advanced"
ng-click="$ctrl.onpenFilters($event)"
icon="keyboard_arrow_down"
style="cursor: pointer;">
style="cursor: pointer; color: #aaa">
</vn-icon>
<vn-button ng-if="$ctrl.label" vn-none label="{{$ctrl.label}}"></vn-button>
<vn-icon-button ng-if="!$ctrl.label" icon="search" ng-click="$ctrl.clearFilter()"></vn-icon-button>
</vn-horizontal>
</form>
<vn-popover

View File

@ -1,4 +1,5 @@
import ngModule from '../../module';
import './style.scss';
export default class Controller {
constructor($element, $scope, $compile, $timeout, $state, $transitions) {
@ -152,7 +153,6 @@ ngModule.component('vnSearchbar', {
onSearch: '&',
advanced: '=',
popover: '@',
label: '@?',
ignoreKeys: '<?',
data: '<?'
},

View File

@ -0,0 +1,9 @@
vn-searchbar {
padding-top: 6px;
padding-left: 16px;
padding-right: 16px;
& > form > vn-horizontal > vn-icon-button {
color: black;
}
}

View File

@ -1,12 +1,12 @@
$color-green: #a3d131;
$color-orange: #f7931e;
$color-white: white;
$color-dark: #3d3d3d;
$color-dark-grey: #424242;
$color-light-grey: #e5e5e5;
$color-medium-grey: #9D9D9D;
$color-medium-green: rgba(163, 209, 49, 0.5);
$color-medium-orange: rgba(247, 147, 30, 0.5);
$color-light-green: rgba(163, 209, 49, 0.3);
$color-light-orange: rgba(247, 147, 30, 0.3);
$color-medium-grey: #9b9b9b;
$color-grey: #c4c4c4;
$color-medium-green: rgba($color-green, 0.5);
$color-medium-orange: rgba($color-orange, 0.5);
$color-light-green: rgba($color-green, 0.3);
$color-light-orange: rgba($color-orange, 0.3);

View File

@ -1,20 +1,66 @@
<mg-ajax path="/ticket/api/Tickets/filter" options="vnIndexNonAuto"></mg-ajax>
<div margin-medium>
<div class="vn-list">
<vn-card>
<vn-horizontal pad-medium>
<div margin-large>
<div>
<vn-card pad-medium>
<vn-title>TICKETS</vn-title>
<vn-horizontal class="vn-list">
<vn-searchbar vn-one
index="index"
on-search="$ctrl.search(index)"
ignore-keys = "['page', 'size', 'search']">
</vn-searchbar>
</vn-horizontal>
</vn-card>
<vn-card margin-medium-top>
<vn-ticket-item
ng-repeat="ticket in index.model.instances"
ticket="ticket">
</vn-ticket-item>
<vn-horizontal>
<table class="vn-grid">
<thead>
<tr>
<th></th>
<th number translate>ID Ticket</th>
<th translate>Comercial</th>
<th translate>Date</th>
<th translate>Hora</th>
<th translate>Alias</th>
<th translate>Provincia</th>
<th translate>Estado</th>
<th translate>Agencia</th>
<th translate>Almacen</th>
<th number translate>Factura</th>
<th number translate>Ruta</th>
<th></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="ticket in index.model.instances"
class="{{::$ctrl.compareDate(ticket.shipped)}} clickable"
ui-sref="ticket.card.summary({id: {{::ticket.id}}})">
<td>
<!-- <i pointer
class="material-icons"
vn-tooltip="delete expedition"
ng-click="$ctrl.deleteExpedition(expedition)">warning</i> -->
</td>
<th number>{{::ticket.id}}</th>
<td translate>{{::ticket.client.salesPerson.name | dashIfEmpty}}</td>
<td translate>{{::ticket.shipped | date:'dd/MM/yyyy'}}</td>
<td translate>{{::ticket.shipped | date:'HH:MM'}}</td>
<td translate>{{::ticket.nickname}}</td>
<td translate>{{::ticket.address.province.name}}</td>
<td translate>{{::ticket.ticketTracking.state.name}}</td>
<td translate>{{::ticket.agencyMode.name}}</td>
<td translate>{{::ticket.warehouse.name}}</td>
<td number translate>{{::ticket.refFk | dashIfEmpty}}</td>
<td number translate>{{::ticket.routeFk | dashIfEmpty}}</td>
<td>
<vn-icon-button
ng-click="$ctrl.preview($event, ticket)"
vn-tooltip="Preview"
icon="desktop_windows">
</vn-icon-button>
</td>
</tr>
</tbody>
</table>
</vn-horizontal>
</vn-card>
<vn-paging index="index" total="index.model.count"></vn-paging>
</div>

View File

@ -8,13 +8,30 @@ export default class Controller {
this.ticketSelected = null;
}
search(index) {
index.accept();
compareDate(date) {
let today = new Date();
today.setHours(0, 0, 0, 0);
let timeTicket = new Date(date);
timeTicket.setHours(0, 0, 0, 0);
let comparation = today - timeTicket;
if (comparation == 0)
return 'warning';
if (comparation < 0)
return 'success';
}
openSummary(ticket) {
this.ticketSelected = ticket;
preview(event, ticket) {
event.preventDefault();
event.stopImmediatePropagation();
this.$scope.dialogSummaryTicket.show();
this.ticketSelected = ticket;
}
search(index) {
index.accept();
}
}

View File

@ -0,0 +1,48 @@
import './ticket-list.js';
describe('ticket', () => {
describe('Component vnTicketList', () => {
let $componentController;
let controller;
beforeEach(() => {
angular.mock.module('ticket');
});
beforeEach(angular.mock.inject(_$componentController_ => {
$componentController = _$componentController_;
controller = $componentController('vnTicketList');
}));
describe('compareDate()', () => {
it('should return warning when the date is the present', () => {
let date = new Date();
let result = controller.compareDate(date);
expect(result).toEqual('warning');
});
it('should return warning when the date is in the future', () => {
let date = '2518-05-19T00:00:00.000Z';
let result = controller.compareDate(date);
expect(result).toEqual('success');
});
});
describe('preview()', () => {
it('should call preventDefault and stopImmediatePropagation from event and show', () => {
let event = jasmine.createSpyObj('event', ['preventDefault', 'stopImmediatePropagation']);
controller.$scope = {dialogSummaryTicket: {show: () => {}}};
spyOn(controller.$scope.dialogSummaryTicket, 'show');
let ticket = {};
controller.preview(event, ticket);
expect(event.preventDefault).toHaveBeenCalledWith();
expect(event.stopImmediatePropagation).toHaveBeenCalledWith();
expect(controller.$scope.dialogSummaryTicket.show).toHaveBeenCalledWith();
});
});
});
});

View File

@ -14,6 +14,7 @@
<vn-autocomplete
ng-if="!ticketObservation.id"
vn-one
vn-focus
initial-data="ticketObservation.observationType"
field="ticketObservation.observationTypeFk"
data="observationTypes.model"
@ -47,12 +48,12 @@
</vn-horizontal>
</vn-one>
<vn-one>
<vn-icon
<vn-icon-button
pointer vn-tooltip="Add note"
tooltip-position="right" orange icon="add_circle"
tooltip-position="right" icon="add_circle"
ng-if="observationTypes.model.length > $ctrl.ticketObservations.length"
ng-click="$ctrl.addObservation()">
</vn-icon>
</vn-icon-button>
</vn-one>
</vn-card>
<vn-button-bar>

View File

@ -16,6 +16,7 @@
<vn-horizontal ng-repeat="package in index.model track by $index">
<vn-autocomplete vn-one
margin-large-right
vn-focus
url="/ticket/api/Packagings/listPackaging"
label="Package"
show-field="name"
@ -51,14 +52,13 @@
</vn-horizontal>
</vn-one>
<vn-one>
<vn-icon
<vn-icon-button
pointer
vn-tooltip="Add package"
tooltip-position = "right"
orange
icon="add_circle"
ng-click="$ctrl.addPackage()">
</vn-icon>
</vn-icon-button>
</vn-one>
</vn-card>
<vn-button-bar>

View File

@ -15,7 +15,7 @@
</tr>
</thead>
<tbody>
<tr ng-repeat="sale in index.model.instances track by sale.id">
<tr ng-repeat="sale in index.model.instances track by sale.id" class="list list-element">
<td number>{{::sale.itemFk}}</td>
<td><vn-fetched-tags sale="sale"/></td>
<td number>{{::sale.quantity}}</td>

View File

@ -17,7 +17,7 @@ export default {
},
clientsIndex: {
searchClientInput: `${components.vnTextfield}`,
searchButton: `${components.vnSearchBar} > vn-icon-button > button`,
searchButton: `${components.vnSearchBar} > vn-icon-button`,
searchResult: `vn-item-client a`,
createClientButton: `${components.vnFloatButton}`
},
@ -157,7 +157,7 @@ export default {
searchResultCloneButton: `vn-item-product .buttons > [icon="icon-clone"]`,
acceptClonationAlertButton: `vn-item-list [vn-id="clone"] [response="ACCEPT"]`,
searchItemInput: `${components.vnTextfield}`,
searchButton: `${components.vnSearchBar} > vn-icon-button > button`,
searchButton: `${components.vnSearchBar} > vn-icon-button`,
closeItemSummaryPreview: 'vn-item-list [vn-id="preview"] button.close'
},
itemCreateView: {
@ -191,27 +191,27 @@ export default {
tagsButton: `${components.vnMenuItem}[ui-sref="item.card.tags"]`,
firstRemoveTagButton: `vn-item-tags vn-horizontal:nth-child(2) > ${components.vnIcon}[icon="remove_circle_outline"]`,
firstTagSelect: `vn-item-tags vn-horizontal:nth-child(2) > ${components.vnAutocomplete}[field="itemTag.tagFk"] input`,
firstTagDisabled: `vn-item-tags vn-horizontal:nth-child(2) > vn-textfield[label="Tag"] > div > input`,
firstTagDisabled: `vn-item-tags vn-horizontal:nth-child(2) > vn-autocomplete > div > div > input`,
firstTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(2) > ${components.vnAutocomplete}[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(1)`,
firstValueInput: `vn-item-tags vn-horizontal:nth-child(2) > vn-textfield[label="Value"] > div > input`,
firstRelevancyInput: `vn-horizontal:nth-child(2) > vn-textfield[label="Relevancy"] > div > input`,
secondTagSelect: `vn-item-tags vn-horizontal:nth-child(3) > ${components.vnAutocomplete}[field="itemTag.tagFk"] input`,
secondTagDisabled: `vn-item-tags vn-horizontal:nth-child(3) > vn-textfield[label="Tag"] > div > input`,
secondTagDisabled: `vn-item-tags vn-horizontal:nth-child(3) > vn-autocomplete > div > div > input`,
secondTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(3) > ${components.vnAutocomplete}[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(1)`,
secondValueInput: `vn-item-tags vn-horizontal:nth-child(3) > vn-textfield[label="Value"] > div > input`,
secondRelevancyInput: `vn-horizontal:nth-child(3) > vn-textfield[label="Relevancy"] > div > input`,
thirdTagSelect: `vn-item-tags vn-horizontal:nth-child(4) > ${components.vnAutocomplete}[field="itemTag.tagFk"] input`,
thirdTagDisabled: `vn-item-tags vn-horizontal:nth-child(4) > vn-textfield[label="Tag"] > div > input`,
thirdTagDisabled: `vn-item-tags vn-horizontal:nth-child(4) > vn-autocomplete > div > div > input`,
thirdTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(4) > ${components.vnAutocomplete}[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(1)`,
thirdValueInput: `vn-item-tags vn-horizontal:nth-child(4) > vn-textfield[label="Value"] > div > input`,
thirdRelevancyInput: `vn-horizontal:nth-child(4) > vn-textfield[label="Relevancy"] > div > input`,
fourthTagSelect: `vn-item-tags vn-horizontal:nth-child(5) > ${components.vnAutocomplete}[field="itemTag.tagFk"] input`,
fourthTagDisabled: `vn-item-tags vn-horizontal:nth-child(5) > vn-textfield[label="Tag"] > div > input`,
fourthTagDisabled: `vn-item-tags vn-horizontal:nth-child(5) > vn-autocomplete > div > div > input`,
fourthTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(5) > ${components.vnAutocomplete}[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(1)`,
fourthValueInput: `vn-item-tags vn-horizontal:nth-child(5) > vn-textfield[label="Value"] > div > input`,
fourthRelevancyInput: `vn-horizontal:nth-child(5) > vn-textfield[label="Relevancy"] > div > input`,
fifthTagSelect: `vn-item-tags vn-horizontal:nth-child(6) > ${components.vnAutocomplete}[field="itemTag.tagFk"] input`,
fifthTagDisabled: `vn-item-tags vn-horizontal:nth-child(6) > vn-textfield[label="Tag"] > div > input`,
fifthTagDisabled: `vn-item-tags vn-horizontal:nth-child(6) > vn-autocomplete > div > div > input`,
fifthTagSelectOptionFive: `vn-item-tags vn-horizontal:nth-child(6) > ${components.vnAutocomplete}[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(5)`,
fifthValueInput: `vn-item-tags vn-horizontal:nth-child(6) > vn-textfield[label="Value"] > div > input`,
fifthRelevancyInput: `vn-horizontal:nth-child(6) > vn-textfield[label="Relevancy"] > div > input`,
@ -264,18 +264,18 @@ export default {
submitBotanicalButton: `${components.vnSubmit}`
},
itemSummary: {
basicData: `${components.vnItemSummary} > vn-horizontal:nth-child(1) > vn-one:nth-child(2) > vn-vertical`,
vat: `${components.vnItemSummary} > vn-horizontal:nth-child(1) > vn-one:nth-child(3) > vn-vertical > p`,
tags: `${components.vnItemSummary} > vn-horizontal:nth-child(2) > vn-one:nth-child(1) > vn-vertical:nth-child(1) > vn-label-value:nth-child(2)`,
niche: `${components.vnItemSummary} > vn-horizontal:nth-child(2) > vn-one:nth-child(2) > vn-vertical > vn-label-value:nth-child(2)`,
botanical: `${components.vnItemSummary} > vn-horizontal:nth-child(2) > vn-one:nth-child(3) > vn-vertical > vn-label-value:nth-child(2)`,
barcode: `${components.vnItemSummary} > vn-horizontal:nth-child(2) > vn-one:nth-child(4) > vn-vertical > p`
basicData: `${components.vnItemSummary} vn-vertical[name="basicData"]`,
vat: `${components.vnItemSummary} vn-vertical[name="tax"]`,
tags: `${components.vnItemSummary} vn-vertical[name="tags"]`,
niche: `${components.vnItemSummary} vn-vertical[name="niche"]`,
botanical: `${components.vnItemSummary} vn-vertical[name="botanical"]`,
barcode: `${components.vnItemSummary} vn-vertical[name="barcode"]`
},
ticketsIndex: {
createTicketButton: `${components.vnFloatButton}`,
searchResult: `vn-ticket-item a`,
searchResult: `table > tbody > tr`,
searchTicketInput: `${components.vnTextfield}`,
searchButton: `${components.vnSearchBar} > vn-icon-button > button`
searchButton: `${components.vnSearchBar} > vn-icon-button`
},
ticketNotes: {
notesButton: `${components.vnMenuItem}[ui-sref="ticket.card.observation"]`,

View File

@ -0,0 +1,26 @@
module.exports = Self => {
Self.remoteMethod('filterItemTags', {
description: 'Returns the distinct values of a tag property',
accessType: 'READ',
accepts: [{
arg: 'tagFk',
type: 'number',
required: true,
description: 'The foreign key from tag table',
http: {source: 'path'}
}],
returns: {
root: true,
type: ['object']
},
http: {
path: `/filterItemTags/:tagFk`,
verb: 'get'
}
});
Self.filterItemTags = async tagFk => {
let query = `SELECT DISTINCT(value) AS name FROM vn.itemTag WHERE tagFk = ?`;
return await Self.rawSql(query, [tagFk]);
};
};

View File

@ -0,0 +1,9 @@
const app = require(`${servicesDir}/item/server/server`);
describe('item filterItemTags()', () => {
it('should call the filterItemTags method', async() => {
let [result] = await app.models.ItemTag.filterItemTags(1);
expect(result.name).toEqual('Yellow');
});
});

View File

@ -6,7 +6,53 @@ module.exports = Self => {
where: {},
skip: (params.page - 1) * params.size,
limit: params.size,
order: params.order || 'created DESC'
order: params.order || 'created DESC',
include: [
{
relation: 'address',
scope: {
fields: ['provinceFk'],
include: {
relation: 'province',
scope: {
fields: ['name']
}
}
}
}, {
relation: 'warehouse',
scope: {
fields: ['name']
}
}, {
relation: 'agencyMode',
scope: {
fields: ['name']
}
}, {
relation: 'ticketTracking',
scope: {
fields: ['stateFk'],
include: {
relation: 'state',
scope: {
fields: ['name']
}
}
}
}, {
relation: 'client',
scope: {
fields: ['salesPersonFk'],
include: {
relation: 'salesPerson',
scope: {
fields: ['name']
}
}
}
}
]
};
delete params.page;

View File

@ -8,7 +8,7 @@
},
"properties": {
"id": {
"type": "Number",
"type": "String",
"id": true,
"description": "Identifier"
},

View File

@ -1,3 +1,4 @@
module.exports = function(Self) {
require('../methods/item-tag/crudItemTags.js')(Self);
require('../methods/item-tag/filterItemTags.js')(Self);
};

View File

@ -18,7 +18,7 @@
"required": true
},
"isFree": {
"type": "Number"
"type": "Boolean"
},
"sourceTable": {
"type": "String"