Merge branch 'dev' of http://git.verdnatura.es/salix into dev
This commit is contained in:
commit
4748f594de
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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)"
|
||||
|
@ -10,7 +10,7 @@
|
|||
popover="vn-client-search-panel"
|
||||
ignore-keys = "['page', 'size', 'search']">
|
||||
</vn-searchbar>
|
||||
</vn-horizontal>
|
||||
</vn-horizontal>
|
||||
</vn-card>
|
||||
<vn-card margin-medium-top>
|
||||
<vn-item-client
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -5,7 +5,7 @@ vn-autocomplete > div > .mdl-textfield {
|
|||
|
||||
& > input {
|
||||
cursor: pointer;
|
||||
height: 26px;
|
||||
height: 30px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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: '@',
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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: '@?'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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);
|
|
@ -1,2 +1,3 @@
|
|||
import './phone';
|
||||
import './ucwords';
|
||||
import './dash-if-empty';
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)"
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
pointer
|
||||
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>
|
||||
|
|
|
@ -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: '<?'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
<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
|
||||
vn-id="popover"
|
||||
on-close="$ctrl.onPopoverClose()">
|
||||
</vn-popover>
|
||||
</vn-popover>
|
|
@ -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: '<?'
|
||||
},
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
vn-searchbar {
|
||||
padding-top: 6px;
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
|
||||
& > form > vn-horizontal > vn-icon-button {
|
||||
color: black;
|
||||
}
|
||||
}
|
|
@ -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);
|
|
@ -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>
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"]`,
|
||||
|
|
|
@ -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]);
|
||||
};
|
||||
};
|
|
@ -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');
|
||||
});
|
||||
});
|
|
@ -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;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
||||
"type": "String",
|
||||
"id": true,
|
||||
"description": "Identifier"
|
||||
},
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
module.exports = function(Self) {
|
||||
require('../methods/item-tag/crudItemTags.js')(Self);
|
||||
require('../methods/item-tag/filterItemTags.js')(Self);
|
||||
};
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
"required": true
|
||||
},
|
||||
"isFree": {
|
||||
"type": "Number"
|
||||
"type": "Boolean"
|
||||
},
|
||||
"sourceTable": {
|
||||
"type": "String"
|
||||
|
|
Loading…
Reference in New Issue