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

This commit is contained in:
Javi Gallego 2018-03-09 14:51:50 +01:00
commit c0fbfa458e
38 changed files with 1303 additions and 1464 deletions

View File

@ -41,6 +41,9 @@ export default class Controller {
this._setDirtyForm();
}
}
if (this.observations.length === 0 && Object.keys(this.observationsOld).length === 0) {
this._unsetDirtyForm();
}
}
_submitObservations(objectObservations) {
return this.$http.post(`/client/api/AddressObservations/crudAddressObservations`, objectObservations);

View File

@ -12,16 +12,18 @@
<vn-check
vn-one
label="Enable web access"
field="$ctrl.account.active">
field="$ctrl.account.active"
vn-acl="employee"
acl-conditional-to-employee="{{$ctrl.canEnableCheckBox}}">
</vn-check>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-focus
vn-one
margin-medium-top
label="User"
field="$ctrl.account.name"
vn-focus>
field="$ctrl.account.name">
</vn-textfield>
</vn-horizontal>
</vn-card>
@ -47,7 +49,7 @@
</vn-textfield>
</tpl-body>
<tpl-buttons>
<button response="CANCEL" translate>Cancel</button>
<input type="button" response="CANCEL" translate-attr="{value: 'Cancel'}"/>
<button response="ACCEPT" translate>Change password</button>
</tpl-buttons>
</vn-dialog>

View File

@ -6,21 +6,30 @@ export default class Controller {
this.$http = $http;
this.vnApp = vnApp;
this.canChangePassword = false;
this.canEnableCheckBox = true;
}
$onChanges() {
if (this.client) {
this.account = this.client.account;
this.isCustomer();
this.checkConditions();
}
}
isCustomer() {
if (this.client && this.client.id) {
if (this.client.id) {
this.$http.get(`/client/api/Clients/${this.client.id}/hasCustomerRole`).then(res => {
this.canChangePassword = (res.data) ? res.data.isCustomer : false;
this.canChangePassword = res.data && res.data.isCustomer;
});
}
}
checkConditions() {
if (this.client.id) {
this.$http.get(`/client/api/Clients/${this.client.id}/isValidClient`).then(res => {
this.canEnableCheckBox = res.data;
});
} else {
this.canChangePassword = false;
}
}
@ -31,7 +40,7 @@ export default class Controller {
}
onPassChange(response) {
if (response == 'ACCEPT' && this.canChangePassword)
if (response == 'ACCEPT')
try {
if (!this.newPassword)
throw new Error(`Passwords can't be empty`);

View File

@ -1,22 +1,23 @@
<vn-vertical ng-click="$ctrl.showDropDown = true" tabindex="0">
<vn-textfield vn-auto
label="{{$ctrl.label}}"
model="$ctrl.displayValue"
readonly="$ctrl.readonly"
tab-index="-1">
</vn-textfield>
<vn-drop-down vn-auto
items="$ctrl.items"
show="$ctrl.showDropDown"
selected="$ctrl.field"
filter="true"
load-more="$ctrl.getItems()"
show-load-more="$ctrl.maxRow"
remove-load-more="$ctrl.removeLoadMore"
filter-action="$ctrl.findItems(search)"
item-width="$ctrl.width"
multiple="$ctrl.multiple"
parent = "$ctrl.element">
<vn-item ng-transclude="tplItem">{{$parent.item[$ctrl.showField]}}</vn-item>
<div>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input
type="button"
class="mdl-textfield__input"
ng-click="$ctrl.onMouseDown($event)"
ng-keydown="$ctrl.onKeyDown($event)">
</input>
<div class="icons">
<vn-icon
icon="clear"
class="clear"
ng-click="$ctrl.onClearClick($event)"
translate-attr="{title: 'Clear'}">
</vn-icon>
</div>
<label class="mdl-textfield__label" translate>{{::$ctrl.label}}</label>
</div>
<vn-drop-down
vn-id="drop-down"
on-select="$ctrl.onDropDownSelect(value)">
</vn-drop-down>
</vn-vertical>
</div>

482
client/core/src/components/autocomplete/autocomplete.js Normal file → Executable file
View File

@ -1,381 +1,255 @@
import ngModule from '../../module';
import Component from '../../lib/component';
import copyObject from '../../lib/copy';
import './style.scss';
class Autocomplete extends Component {
constructor($element, $scope, $http, $timeout, $filter) {
super($element);
this.$element = $element;
this.$scope = $scope;
/**
* Input with option selector.
*
* @property {String} valueField The data field name that should be shown
* @property {String} showFiled The data field name that should be used as value
* @property {Array} data Static data for the autocomplete
* @property {Object} intialData A initial data to avoid the server request used to get the selection
* @property {Boolean} multiple Wether to allow multiple selection
*/
export default class Autocomplete extends Component {
constructor($element, $scope, $http, $transclude) {
super($element, $scope);
this.$http = $http;
this.$timeout = $timeout;
this.$filter = $filter;
this.$transclude = $transclude;
this._showDropDown = false;
this.finding = false;
this.findMore = false;
this._value = null;
this._field = null;
this._preLoad = false;
this.maxRow = 10;
this.showField = 'name';
this._field = undefined;
this._selection = null;
this.valueField = 'id';
this.items = copyObject(this.data) || [];
this.displayValueMultiCheck = [];
this.showField = 'name';
this._multiField = [];
this.readonly = true;
this.removeLoadMore = false;
this.form = null;
this.findForm = false;
}
get showDropDown() {
return this._showDropDown;
}
set showDropDown(value) {
if (value && this.url && !this._preLoad) {
this._preLoad = true;
this.getItems();
}
if (value && !this.width) {
let rectangle = this.$element[0].getBoundingClientRect();
this.width = Math.round(rectangle.width) - 10;
}
this._showDropDown = value;
}
get displayValue() {
return this._value;
}
set displayValue(value) {
let val = (value === undefined || value === '') ? null : value;
if (this.multiple && val) {
let index = this.displayValueMultiCheck.indexOf(val);
if (index === -1)
this.displayValueMultiCheck.push(val);
else
this.displayValueMultiCheck.splice(index, 1);
this._value = this.displayValueMultiCheck.join(', ');
} else {
this._value = val;
}
if (value === null) {
this.field = null;
if (this.multiple && this.items.length) {
this.displayValueMultiCheck = [];
this.items.map(item => {
item.checked = false;
return item;
});
}
}
this.input = this.element.querySelector('.mdl-textfield__input');
componentHandler.upgradeElement(
this.element.querySelector('.mdl-textfield'));
}
/**
* @type {any} The autocomplete value.
*/
get field() {
return this.multiple ? this._multiField : this._field;
return this._field;
}
set field(value) {
if (!angular.equals(value, this.field)) {
this.finding = true;
if (value && value.hasOwnProperty(this.valueField)) {
this._field = value[this.valueField];
if (this.multiple) {
this.setMultiField(value[this.valueField]);
}
this.setDirtyForm();
} else {
this.setValue(value);
}
if (angular.equals(value, this._field))
return;
if (value && value.hasOwnProperty(this.showField))
this.displayValue = value[this.showField];
this._field = value;
this.refreshSelection();
this.finding = false;
if (this.onChange)
this.onChange({item: this._field});
}
if (this.onChange)
this.onChange(value);
}
set initialData(value) {
if (value && value.hasOwnProperty(this.valueField)) {
this._field = value[this.valueField];
if (this.multiple) {
this._multiField = [value[this.valueField]];
}
if (value.hasOwnProperty(this.showField)) {
this.displayValue = value[this.showField];
}
}
/**
* @type {Object} The selected data object, you can use this property
* to prevent requests to display the initial value.
*/
get selection() {
return this._selection;
}
setMultiField(val) {
if (val && typeof val === 'object' && val[this.valueField]) {
val = val[this.valueField];
}
if (val === null) {
this._multiField = [];
} else {
let index = this._multiField.indexOf(val);
if (index === -1) {
this._multiField.push(val);
} else {
this._multiField.splice(index, 1);
}
}
set selection(value) {
this._selection = value;
this.refreshDisplayed();
}
setValue(value) {
if (value) {
let data = this.items;
selectionIsValid(selection) {
return selection
&& selection[this.valueField] == this._field
&& selection[this.showField] != null;
}
if (data && data.length)
refreshSelection() {
if (this.selectionIsValid(this._selection))
return;
let value = this._field;
if (value && this.valueField && this.showField) {
if (this.selectionIsValid(this.initialData)) {
this.selection = this.initialData;
return;
}
let data = this.data;
if (!data && this.$.dropDown)
data = this.$.dropDown.$.model.data;
if (data)
for (let i = 0; i < data.length; i++)
if (data[i][this.valueField] === value) {
this.showItem(data[i]);
this.selection = data[i];
return;
}
this.requestItem(value);
} else {
this._field = null;
this.setMultiField(null);
this.displayValue = '';
}
if (this.url) {
this.requestSelection(value);
return;
}
} else
this.selection = null;
}
requestItem(value) {
if (!value) return;
requestSelection(value) {
let where = {};
where[this.valueField] = value;
if (this.multiple)
where[this.valueField] = {inq: this.field};
else
where[this.valueField] = value;
let filter = {
fields: this.getRequestFields(),
fields: this.getFields(),
where: where
};
let json = JSON.stringify(filter);
let json = encodeURIComponent(JSON.stringify(filter));
this.$http.get(`${this.url}?filter=${json}`).then(
json => this.onItemRequest(json.data),
json => this.onItemRequest(null)
json => this.onSelectionRequest(json.data),
() => this.onSelectionRequest(null)
);
}
onItemRequest(data) {
if (data && data.length > 0)
this.showItem(data[0]);
else
this.showItem(null);
onSelectionRequest(data) {
if (data && data.length > 0) {
if (this.multiple)
this.selection = data;
else
this.selection = data[0];
} else
this.selection = null;
}
showItem(item) {
this.displayValue = item ? item[this.showField] : '';
this.field = item;
refreshDisplayed() {
let display = '';
if (this._selection && this.showField) {
if (this.multiple && Array.isArray(this._selection)) {
for (var item of this._selection) {
if (display.length > 0) display += ', ';
display += item[this.showField];
}
} else {
display = this._selection[this.showField];
}
}
this.input.value = display;
this.mdlUpdate();
}
getRequestFields() {
let fields = {};
fields[this.valueField] = true;
fields[this.showField] = true;
getFields() {
let fields = [];
fields.push(this.valueField);
fields.push(this.showField);
if (this._selectFields)
for (let field of this._selectFields)
fields[field] = true;
if (this.selectFields)
for (let field of this.selectFields)
fields.push(field);
return fields;
}
getOrder() {
return this.order ? this.order : `${this.showField} ASC`;
mdlUpdate() {
let field = this.element.querySelector('.mdl-textfield');
let mdlField = field.MaterialTextfield;
if (mdlField) mdlField.updateClasses_();
}
findItems(search) {
if (this.url && search && !this.finding) {
this.maxRow = false;
let filter = {};
if (this.filterSearch) {
let toSearch = this.filterSearch.replace(/search/g, search);
filter = this.$scope.$eval(toSearch);
} else {
filter = {where: {name: {regexp: search}}};
if (this.filter && this.filter.where) {
Object.assign(filter.where, this.filter.where);
}
}
filter.order = this.getOrder();
let json = JSON.stringify(filter);
this.finding = true;
this.$http.get(`${this.url}?filter=${json}`).then(
json => {
this.items = [];
json.data.forEach(
el => {
if (this.multiple) {
el.checked = this.field.indexOf(el[this.valueField]) !== -1;
}
this.items.push(el);
}
);
this.finding = false;
},
() => {
this.finding = false;
}
);
} else if (search && !this.url && this.data) {
this.items = this.$filter('filter')(this.data, search);
} else if (!search && !this.finding) {
this.maxRow = 10;
this.items = [];
this.getItems();
}
setValue(value) {
this.field = value;
if (this.form) this.form.$setDirty();
}
getItems() {
if (this.url === undefined) {
this.items = copyObject(this.data);
this.maxRow = false;
this.removeLoadMore = true;
} else {
let filter = {};
if (!this.finding) {
this.finding = true;
if (this.maxRow) {
if (this.items) {
filter.skip = this.items.length;
}
filter.limit = this.maxRow;
filter.order = this.getOrder();
}
if (this.filter) {
Object.assign(filter, this.filter);
}
let json = JSON.stringify(filter);
this.removeLoadMore = false;
this.$http.get(`${this.url}?filter=${json}`).then(
json => {
if (json.data.length) {
json.data.forEach(
el => {
if (this.multiple) {
el.checked = this.field.indexOf(el[this.valueField]) !== -1;
}
this.items.push(el);
}
);
if (filter.skip === 0 && this.maxRow && json.data.length < this.maxRow) {
this.removeLoadMore = true;
}
} else {
this.maxRow = false;
}
this.finding = false;
},
() => {
this.finding = false;
}
);
}
}
}
_parentForm() {
this.findForm = true;
let formScope = this.$scope;
while (formScope && !formScope.form && formScope.$id > 1) {
formScope = formScope.$parent;
}
this.form = formScope ? formScope.form || null : null;
}
setDirtyForm() {
if (!this.form && !this.findForm) {
this._parentForm();
}
if (this.form) {
this.form.$setDirty();
}
onDropDownSelect(value) {
this.setValue(value);
this.field = value;
}
$onInit() {
this.findMore = this.url && this.maxRow;
this.mouseFocus = false;
this.focused = false;
onClearClick(event) {
event.preventDefault();
this.setValue(null);
}
this.$element.bind('mouseover', e => {
this.$timeout(() => {
this.mouseFocus = true;
this.showDropDown = this.focused;
});
onKeyDown(event) {
if (event.defaultPrevented) return;
switch (event.keyCode) {
case 38: // Up
case 40: // Down
case 13: // Enter
this.showDropDown();
break;
default:
if (event.key.length == 1)
this.showDropDown(event.key);
else
return;
}
event.preventDefault();
}
onMouseDown(event) {
event.preventDefault();
this.showDropDown();
}
showDropDown(search) {
Object.assign(this.$.dropDown.$.model, {
url: this.url,
staticData: this.data
});
this.$element.bind('mouseout', () => {
this.$timeout(() => {
this.mouseFocus = false;
this.showDropDown = this.focused;
});
});
this.$element.bind('focusin', e => {
this.$timeout(() => {
this.focused = true;
this.showDropDown = true;
});
});
this.$element.bind('focusout', e => {
this.$timeout(() => {
this.focused = false;
this.showDropDown = this.mouseFocus;
});
Object.assign(this.$.dropDown, {
valueField: this.valueField,
showField: this.showField,
selectFields: this.getFields(),
where: this.where,
order: this.order,
parent: this.input,
multiple: this.multiple,
limit: this.limit,
$transclude: this.$transclude
});
this.$.dropDown.show(search);
}
$onDestroy() {
this.$element.unbind('mouseover');
this.$element.unbind('mouseout');
this.$element.unbind('focusin');
this.$element.unbind('focusout');
}
$onChanges(objectChange) {
if (objectChange.data && objectChange.data.currentValue && objectChange.data.currentValue.length) {
this.items = copyObject(objectChange.data.currentValue);
this.maxRow = false;
this.removeLoadMore = true;
}
}
}
Autocomplete.$inject = ['$element', '$scope', '$http', '$timeout', '$filter'];
Autocomplete.$inject = ['$element', '$scope', '$http', '$transclude'];
ngModule.component('vnAutocomplete', {
template: require('./autocomplete.html'),
controller: Autocomplete,
bindings: {
url: '@?',
data: '<?',
showField: '@?',
valueField: '@?',
selectFields: '@?',
initialData: '<?',
onChange: '&?',
data: '<?',
field: '=',
label: '@',
multiple: '@?',
selectFields: '<?',
where: '@?',
order: '@?',
filter: '<?',
filterSearch: '@?'
label: '@',
initialData: '<?',
field: '=?',
limit: '<?',
showFilter: '<?',
selection: '<?',
multiple: '<?',
onChange: '&?'
},
transclude: {
tplItem: '?tplItem'
},
require: {
form: '?^form'
}
});

View File

@ -1,208 +1,74 @@
import './autocomplete.js';
import template from './autocomplete.html';
describe('Component vnAutocomplete', () => {
let $componentController;
let $element;
let $scope;
let $httpBackend;
let $timeout;
let $element;
let controller;
let data = {id: 1, name: 'Bruce Wayne'};
beforeEach(() => {
angular.mock.module('client');
});
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_, _$timeout_) => {
$componentController = _$componentController_;
$scope = $rootScope.$new();
$element = angular.element(`<div>${template}</div>`);
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
$timeout = _$timeout_;
$element = angular.element('<div></div>');
controller = $componentController('vnAutocomplete', {$scope, $element, $httpBackend, $timeout});
controller = _$componentController_('vnAutocomplete', {$element, $scope, $httpBackend, $transclude: null});
}));
describe('showDropDown() setter', () => {
it(`should set _showDropDown value`, () => {
controller._showDropDown = '';
controller.showDropDown = 'some value';
describe('field() setter/getter', () => {
it(`should set field controllers property`, () => {
controller.field = data.id;
expect(controller._showDropDown).toEqual('some value');
expect(controller.field).toEqual(data.id);
});
it(`should set _showDropDown value`, () => {
controller._showDropDown = '';
controller.showDropDown = 'some value';
it(`should set selection finding an existing item in the initialData property`, () => {
controller.valueField = 'id';
controller.showField = 'name';
controller.initialData = data;
controller.field = data.id;
expect(controller._showDropDown).toEqual('some value');
});
});
describe('displayValue() setter', () => {
it(`should display value in a formated way`, () => {
let value = 'some value';
controller.displayValue = value;
expect(controller._value).toEqual(value);
expect(controller.selection).toEqual(data);
});
describe('when the autocomeplete is multiple', () => {
it(`should display values separated with commas`, () => {
controller.multiple = true;
controller.displayValue = 'some value';
controller.displayValue = 'another value';
it(`should set selection finding an existing item in the data property`, () => {
controller.valueField = 'id';
controller.showField = 'name';
controller.data = [data];
controller.field = data.id;
expect(controller._value).toEqual('some value, another value');
});
});
});
describe('field() setter', () => {
describe('when value is an object', () => {
it(`should set _field controllers property`, () => {
controller.field = {id: 1, name: 'Bruce Wayne'};
expect(controller._field).toEqual(1);
});
it(`should set _multifield controllers property `, () => {
controller.multiple = true;
controller.field = {id: 1, name: 'Bruce Wayne'};
expect(controller._field).toEqual(1);
expect(controller._multiField[0]).toEqual(1);
controller.field = {id: 1, name: 'Bruce Wayne'};
expect(controller._multiField).toEqual([]);
expect(controller._field).toEqual(1);
});
it(`should set _multifield value and remove it if called a second type with same value`, () => {
controller.multiple = true;
controller.field = {id: 1, name: 'Bruce Wayne'};
expect(controller._field).toEqual(1);
expect(controller._multiField[0]).toEqual(1);
controller.field = {id: 1, name: 'Bruce Wayne'};
expect(controller._multiField).toEqual([]);
expect(controller._field).toEqual(1);
});
it(`should set displayValue finding an existing item in the controller.items property`, () => {
controller.items = [{id: 1, name: 'test1'}, {id: 2, name: 'Bruce Wayne'}];
controller.field = {id: 2, name: 'Bruce Wayne'};
expect(controller.displayValue).toEqual('Bruce Wayne');
});
expect(controller.selection).toEqual(data);
});
describe('when value is a number', () => {
it(`should set _field controller property finding an existing item in the controller.items property`, () => {
controller.items = [{id: 1, name: 'Batman'}, {id: 2, name: 'Bruce Wayne'}];
controller.field = 2;
it(`should set selection to null when can't find an existing item in the data property`, () => {
controller.valueField = 'id';
controller.showField = 'name';
controller.field = data.id;
expect(controller._field).toEqual(2);
});
it(`should set _multifield value and remove it if called a second type with same value finding an existing item in the controller.items property`, () => {
controller.items = [{id: 1, name: 'Batman'}, {id: 2, name: 'Bruce Wayne'}];
controller.multiple = true;
controller.field = 2;
expect(controller._multiField[0]).toEqual(2);
controller.field = 2;
expect(controller._multiField).toEqual([]);
});
it(`should perform a query if the item id isn't present in the controller.items property`, () => {
controller.url = 'test.com';
$httpBackend.expectGET(`${controller.url}?filter={"fields":{"id":true,"name":true},"where":{"id":3}}`);
controller.items = [{id: 1, name: 'test1'}, {id: 2, name: 'Bruce Wayne'}];
controller.field = 3;
$httpBackend.flush();
});
it(`should set displayValue finding an existing item in the controller.items property`, () => {
controller.items = [{id: 1, name: 'test1'}, {id: 2, name: 'Bruce Wayne'}];
controller.field = 2;
expect(controller.displayValue).toEqual('Bruce Wayne');
});
it(`should set field performing a query as the item id isn't present in the controller.items property`, () => {
controller.url = 'test.com';
$httpBackend.expectGET(`${controller.url}?filter={"fields":{"id":true,"name":true},"where":{"id":3}}`);
controller.items = [{id: 1, name: 'test1'}, {id: 2, name: 'Bruce Wayne'}];
controller.field = 3;
$httpBackend.flush();
});
expect(controller.selection).toEqual(null);
});
});
describe('findItems()', () => {
it(`should perform a search and store the result in controller items`, () => {
let controller = $componentController('vnAutocomplete', {$scope, $element, $httpBackend, $timeout});
controller.url = 'test.com';
let search = 'The Joker';
let json = JSON.stringify({where: {name: {regexp: search}}, order: controller.getOrder()});
$httpBackend.whenGET(`${controller.url}?filter=${json}`).respond([{id: 3, name: 'The Joker'}]);
$httpBackend.expectGET(`${controller.url}?filter=${json}`);
controller.findItems(search);
it(`should perform a query if the item id isn't present in the data property`, () => {
controller.valueField = 'id';
controller.showField = 'name';
controller.url = 'localhost';
controller.field = data.id;
let filter = {
fields: ['id', 'name'],
where: {id: data.id}
};
let json = encodeURIComponent(JSON.stringify(filter));
$httpBackend.expectGET(`localhost?filter=${json}`);
controller.field = data.id;
$httpBackend.flush();
expect(controller.items[0]).toEqual({id: 3, name: 'The Joker'});
});
it(`should perform a search and store the result in controller items with filterSearch`, () => {
let controller = $componentController('vnAutocomplete', {$scope, $element, $httpBackend, $timeout});
controller.url = 'test.com';
let search = 'The Joker';
controller.filterSearch = "{where: {name: {regexp: 'search'}}}";
let json = JSON.stringify({where: {name: {regexp: search}}, order: controller.getOrder()});
$httpBackend.whenGET(`${controller.url}?filter=${json}`).respond([{id: 3, name: 'The Joker'}]);
$httpBackend.expectGET(`${controller.url}?filter=${json}`);
controller.findItems(search);
$httpBackend.flush();
expect(controller.items[0]).toEqual({id: 3, name: 'The Joker'});
});
it(`should perform a search with multiple true and store the result in controller items with the checked property defined`, () => {
controller.url = 'test.com';
let search = 'Joker';
controller.multiple = true;
let json = JSON.stringify({where: {name: {regexp: search}}, order: controller.getOrder()});
$httpBackend.whenGET(`${controller.url}?filter=${json}`).respond([{id: 3, name: 'The Joker'}, {id: 4, name: 'Joker'}]);
$httpBackend.expectGET(`${controller.url}?filter=${json}`);
controller.findItems(search);
$httpBackend.flush();
expect(controller.items).toEqual([{id: 3, name: 'The Joker', checked: false}, {id: 4, name: 'Joker', checked: false}]);
});
it(`should call getItems function if there's no search value`, () => {
controller.url = 'test.com';
spyOn(controller, 'getItems');
controller.findItems();
expect(controller.getItems).toHaveBeenCalledWith();
});
});
describe('getItems()', () => {
it(`should perfom a query to fill the items without filter`, () => {
controller.url = 'test.com';
$httpBackend.whenGET(`${controller.url}?filter={"skip":0,"limit":10,"order":"name ASC"}`).respond([{id: 1, name: 'Batman'}, {id: 2, name: 'Bruce Wayne'}]);
$httpBackend.expectGET(`${controller.url}?filter={"skip":0,"limit":10,"order":"name ASC"}`);
controller.getItems();
$httpBackend.flush();
expect(controller.items).toEqual([{id: 1, name: 'Batman'}, {id: 2, name: 'Bruce Wayne'}]);
});
});
});

69
client/core/src/components/autocomplete/style.scss Normal file → Executable file
View File

@ -1,3 +1,47 @@
vn-autocomplete > div > .mdl-textfield {
position: relative;
width: 100%;
& > input {
cursor: pointer;
height: 26px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
&:focus {
outline: none;
}
&::-moz-focus-inner {
border: 0;
}
}
& > .icons {
display: none;
position: absolute;
right: 0;
top: 1.3em;
height: 1em;
color: #888;
border-radius: .2em;
background-color: rgba(255, 255, 255, .8);
& > vn-icon {
cursor: pointer;
font-size: 18px;
&:hover {
color: #333;
}
}
}
&:hover > .icons,
& > input:focus + .icons {
display: block;
}
}
ul.vn-autocomplete {
list-style-type: none;
padding: 1em;
@ -14,7 +58,7 @@ ul.vn-autocomplete {
&.active,
&:hover {
background-color: rgba(1,1,1,.1);
background-color: rgba(1, 1, 1, .1);
}
&.load-more {
color: #ffa410;
@ -22,27 +66,4 @@ ul.vn-autocomplete {
padding: .4em .8em;
}
}
}
vn-autocomplete {
position: relative;
vn-vertical {
outline:none;
}
.mdl-chip__action {
position: absolute;
top: 0px;
right: -6px;
margin: 22px 0px;
background: transparent;
}
.material-icons {
font-size: 18px;
}
vn-drop-down{
margin-top: 47px;
}
vn-drop-down .dropdown-body .filter vn-icon {
margin-left: -26px;
}
}

View File

@ -37,14 +37,16 @@ export default class Dialog extends Component {
show() {
if (this.shown) return;
this.shown = true;
this.keypressHandler = e => this.onKeypress(e);
this.document.addEventListener('keypress', this.keypressHandler);
this.keyDownHandler = e => this.onkeyDown(e);
this.document.addEventListener('keydown', this.keyDownHandler);
this.element.style.display = 'flex';
this.transitionTimeout =
setTimeout(() => this.$element.addClass('shown'), 30);
this.transitionTimeout = setTimeout(() => this.$element.addClass('shown'), 30);
if (this.onOpen)
this.onOpen();
let firstFocusable = this.element.querySelector('input, textarea');
if (firstFocusable) firstFocusable.focus();
}
/**
* Hides the dialog calling the response handler.
@ -68,7 +70,7 @@ export default class Dialog extends Component {
realHide() {
if (!this.shown) return;
this.element.style.display = 'none';
this.document.removeEventListener('keypress', this.keypressHandler);
this.document.removeEventListener('keydown', this.keyDownHandler);
this.lastEvent = null;
this.shown = false;
this.transitionTimeout =
@ -94,7 +96,7 @@ export default class Dialog extends Component {
if (event != this.lastEvent)
this.hide();
}
onKeypress(event) {
onkeyDown(event) {
if (event.keyCode == 27) // Esc
this.hide();
}

View File

@ -28,7 +28,10 @@
display: block;
width: 20em;
}
button {
button,
input[type="button"],
input[type="submit"],
input[type="reset"] {
text-transform: uppercase;
background-color: transparent;
border: none;
@ -55,7 +58,10 @@
margin-top: 1.5em;
text-align: right;
button {
button,
input[type="button"],
input[type="submit"],
input[type="reset"] {
color: #ffa410;
font-family: vn-font-bold;
padding: .7em;

62
client/core/src/components/drop-down/drop-down.html Normal file → Executable file
View File

@ -1,28 +1,36 @@
<vn-vertical class="dropdown-body" ng-if="$ctrl.show">
<vn-auto ng-show="$ctrl.filter" class="filter">
<vn-horizontal>
<input vn-one placeholder="{{'Search' | translate}}" type="text" ng-model="$ctrl.search"/>
<vn-icon vn-none icon="clear" ng-click="$ctrl.clearSearch()"></vn-icon>
</vn-horizontal>
</vn-auto>
<vn-auto>
<ul class="dropdown">
<li
ng-repeat="item in $ctrl.itemsFiltered track by $index"
ng-click="$ctrl.selectItem(item)"
ng-class="{'active': $index === $ctrl.activeOption, 'checked': item.checked}"
ng-mouseover="$ctrl.activeOption = $index"
>
<input type="checkbox" ng-checked="item.checked" ng-if="$ctrl.multiple">
<div ng-transclude="vnItem">{{item.name}}</div>
</li>
<li
ng-if="$ctrl.loadMore&&!$ctrl.removeLoadMore"
class="dropdown__loadMore"
ng-class="{'active': $ctrl.itemsFiltered.length === $ctrl.activeOption, 'noMore' : !$ctrl.showLoadMore}"
ng-click="$ctrl.loadItems()"
translate="{{$ctrl.showLoadMore ? 'Show More' : 'No more results'}}"
></li>
<div
class="body"
ng-mousedown="$ctrl.onMouseDown($event)">
<div ng-show="$ctrl.showFilter" class="filter">
<input
type="text"
ng-model="$ctrl.search"
tabindex="-1"
class="search"
ng-blur="$ctrl.onFocusOut()"
translate-attr="{placeholder: 'Search'}"/>
<vn-icon
icon="clear"
ng-click="$ctrl.onClearClick()"
translate-attr="{title: 'Clear'}">
</vn-icon>
</div>
<vn-model
vn-id="model"
on-data-change="$ctrl.onModelDataChange()">
</vn-model>
<div class="list">
<ul
class="dropdown"
tabindex="-1"
ng-click="$ctrl.onContainerClick($event)">
</ul>
</vn-auto>
</vn-vertical>
<div
ng-if="$ctrl.statusText"
ng-click="$ctrl.onLoadMoreClick($event)"
class="status"
translate>
{{$ctrl.statusText}}
</div>
</div>
</div>

592
client/core/src/components/drop-down/drop-down.js Normal file → Executable file
View File

@ -1,44 +1,48 @@
import ngModule from '../../module';
import validKey from '../../lib/key-codes';
import Component from '../../lib/component';
import './style.scss';
import './model';
export default class DropDown {
constructor($element, $filter, $timeout) {
this.$element = $element;
this.$filter = $filter;
export default class DropDown extends Component {
constructor($element, $scope, $transclude, $timeout, $http, $translate) {
super($element, $scope);
this.$transclude = $transclude;
this.$timeout = $timeout;
this.$translate = $translate;
this._search = null;
this.itemsFiltered = [];
this.valueField = 'id';
this.showField = 'name';
this._search = undefined;
this._shown = false;
this._activeOption = -1;
this._focusingFilter = false;
this._tryToShow = 0;
this.showLoadMore = true;
this.showFilter = true;
this.input = this.element.querySelector('.search');
this.body = this.element.querySelector('.body');
this.container = this.element.querySelector('ul');
this.list = this.element.querySelector('.list');
this.docKeyDownHandler = e => this.onDocKeyDown(e);
this.docFocusInHandler = e => this.onDocFocusIn(e);
this.element.addEventListener('mousedown',
e => this.onBackgroundMouseDown(e));
this.element.addEventListener('focusin',
e => this.onFocusIn(e));
this.list.addEventListener('scroll',
e => this.onScroll(e));
}
get container() {
return this.$element[0].querySelector('ul.dropdown');
get shown() {
return this._shown;
}
get show() {
return this._show;
}
set show(value) {
let oldValue = this.show;
// It wait up to 1 second if the dropdown opens but there is no data to show
if (value && !oldValue && !this.itemsFiltered.length && this._tryToShow < 4) {
this.$timeout(() => {
this._tryToShow++;
this.show = true;
if (this.activeOption === -1) {
this.activeOption = 0;
}
}, 250);
} else {
this._tryToShow = 0;
this._show = value;
this._toggleDropDown(value, oldValue);
}
set shown(value) {
if (value)
this.show();
else
this.hide();
}
get search() {
@ -46,242 +50,390 @@ export default class DropDown {
}
set search(value) {
let val = (value === undefined || value === '') ? null : value;
this._search = val;
value = value == '' || value == null ? null : value;
if (value === this._search) return;
if (this.filterAction)
this.onFilterRest();
else
this.filterItems();
this._search = value;
this.$.model.clear();
this.$timeout.cancel(this.searchTimeout);
this.searchTimeout = this.$timeout(() => {
this.refreshModel();
this.searchTimeout = null;
}, 350);
this.buildList();
}
get statusText() {
let model = this.$.model;
let data = model.data;
let statusText = null;
if (model.isLoading || this.searchTimeout)
statusText = 'Loading...';
else if (data == null)
statusText = 'No data';
else if (model.moreRows)
statusText = 'Load More';
else if (data.length === 0)
statusText = 'No results found';
return statusText;
}
get model() {
return this.$.model;
}
get activeOption() {
return this._activeOption;
}
set activeOption(value) {
if (value < 0) {
value = 0;
} else if (value >= this.itemsFiltered.length) {
value = this.showLoadMore ? this.itemsFiltered.length : this.itemsFiltered.length - 1;
}
this.$timeout(() => {
this._activeOption = value;
if (value && value >= this.itemsFiltered.length - 3 && !this.removeLoadMore) {
this.loadItems();
}
});
/**
* Shows the drop-down. If a parent is specified it is shown in a visible
* relative position to it.
*
* @param {String} search The initial search term or %null
*/
show(search) {
if (this._shown) return;
this._shown = true;
this._activeOption = -1;
this.search = search;
this.buildList();
this.element.style.display = 'block';
this.list.scrollTop = 0;
this.$timeout(() => this.$element.addClass('shown'), 40);
this.document.addEventListener('keydown', this.docKeyDownHandler);
this.document.addEventListener('focusin', this.docFocusInHandler);
this.relocate();
this.input.focus();
}
_toggleDropDown(value, oldValue) {
this.$timeout(() => {
this._eventScroll(value);
this._calculatePosition(value, oldValue);
});
/**
* Hides the drop-down.
*/
hide() {
if (!this._shown) return;
this._shown = false;
this.element.style.display = '';
this.$element.removeClass('shown');
this.document.removeEventListener('keydown', this.docKeyDownHandler);
this.document.removeEventListener('focusin', this.docFocusInHandler);
if (this.parent)
this.parent.focus();
}
_eventScroll(add, num) {
let count = num || 0;
if (add) {
if (this.container) {
this.container.addEventListener('scroll', e => this.loadFromScroll(e));
// this.$timeout(() => { // falla al entrar por primera vez xq pierde el foco y cierra el dropdown
// this._setFocusInFilterInput();
// });
} else if (count < 4) {
count++;
this.$timeout(() => { // wait angular ngIf
this._eventScroll(add, count);
}, 250);
}
} else if (this.container) {
this.container.removeEventListener('scroll', e => this.loadFromScroll(e));
/**
* Repositions the drop-down to a correct location relative to the parent.
*/
relocate() {
if (!this.parent) return;
let style = this.body.style;
style.width = '';
style.height = '';
let parentRect = this.parent.getBoundingClientRect();
let bodyRect = this.body.getBoundingClientRect();
let top = parentRect.top + parentRect.height;
let height = bodyRect.height;
let width = Math.max(bodyRect.width, parentRect.width);
let margin = 10;
if (top + height + margin > window.innerHeight)
top = Math.max(parentRect.top - height, margin);
style.top = `${top}px`;
style.left = `${parentRect.left}px`;
style.width = `${width}px`;
if (height + margin * 2 > window.innerHeight)
style.height = `${window.innerHeight - margin * 2}px`;
}
/**
* Activates a option and scrolls the drop-down to that option.
*
* @param {Number} option The option index
*/
moveToOption(option) {
this.activateOption(option);
let list = this.list;
let li = this.activeLi;
if (!li) return;
let liRect = li.getBoundingClientRect();
let listRect = list.getBoundingClientRect();
if (liRect.bottom > listRect.bottom)
list.scrollTop += liRect.bottom - listRect.bottom;
else if (liRect.top < listRect.top)
list.scrollTop -= listRect.top - liRect.top;
}
/**
* Activates a option.
*
* @param {Number} option The option index
*/
activateOption(option) {
this._activeOption = option;
if (this.activeLi)
this.activeLi.className = '';
let data = this.$.model.data;
if (option >= 0 && data && option < data.length) {
this.activeLi = this.container.children[option];
this.activeLi.className = 'active';
}
}
_setFocusInFilterInput() {
let inputFilterSearch = this.$element[0].querySelector('input');
this._focusingFilter = true;
if (inputFilterSearch)
this.$timeout(() => {
inputFilterSearch.focus();
this._focusingFilter = false;
}, 250);
}
/**
* Selects an option.
*
* @param {Number} option The option index
*/
selectOption(option) {
if (option != -1) {
let data = this.$.model.data;
let item = data ? data[option] : null;
let value = item ? item[this.valueField] : null;
_background(create) {
let el = document.getElementById('ddBack');
if (el) {
el.parentNode.removeChild(el);
}
if (this.multiple) {
if (!Array.isArray(this.selection)) {
this.selection = [];
this.field = [];
}
if (create) {
el = document.createElement('div');
el.id = 'ddBack';
document.body.appendChild(el);
}
}
_calculatePosition(value, oldValue) {
if (value && !oldValue) {
if (this.parent === undefined) {
this.parent = this.$element.parent().parent();
this.selection.push(item);
this.field.push(value);
} else {
this.selection = item;
this.field = value;
}
let parentRect = this.parent.getBoundingClientRect();
let elemetRect = this.$element[0].getBoundingClientRect();
let instOffset = parentRect.bottom + elemetRect.height;
if (instOffset >= window.innerHeight) {
this._background(true);
this.$element.addClass('fixed-dropDown');
this.$element.css('top', `${(parentRect.top - elemetRect.height)}px`);
this.$element.css('left', `${(parentRect.x)}px`);
this.$element.css('height', `${elemetRect.height}px`);
}
} else if (!value && oldValue) {
this.$element.removeAttr('style');
if (this.itemWidth) {
this.$element.css('width', this.itemWidth + 'px');
}
this.$element.removeClass('fixed-dropDown');
this._background();
if (this.onSelect)
this.onSelect({value: value});
}
if (!this.multiple)
this.hide();
}
filterItems() {
this.itemsFiltered = this.search ? this.$filter('filter')(this.items, this.search) : this.items;
refreshModel() {
this.$.model.filter = {
fields: this.selectFields,
where: this.getWhere(this._search),
order: this.getOrder(),
limit: this.limit || 8
};
this.$.model.refresh(this._search);
}
onFilterRest() {
if (this.filterAction) {
this.filterAction({search: this.search});
getWhere(search) {
if (search == '' || search == null)
return undefined;
if (this.where) {
let jsonFilter = this.where.replace(/search/g, search);
return this.$.$eval(jsonFilter);
}
let where = {};
where[this.showField] = {regexp: search};
return where;
}
clearSearch() {
getOrder() {
if (this.order)
return this.order;
else if (this.showField)
return `${this.showField} ASC`;
return undefined;
}
onMouseDown(event) {
this.lastMouseEvent = event;
}
onBackgroundMouseDown(event) {
if (event != this.lastMouseEvent)
this.hide();
}
onFocusIn(event) {
this.lastFocusEvent = event;
}
onDocFocusIn(event) {
if (event !== this.lastFocusEvent && event.originalTarget !== this.parent)
this.hide();
}
onClearClick() {
this.search = null;
}
selectOption() {
if (this.activeOption >= 0 && this.activeOption < this.items.length && this.items[this.activeOption]) {
this.selected = this.items[this.activeOption];
this.show = false;
this.clearSearch();
} else if (this.showLoadMore && this.activeOption === this.items.length) {
this.loadMore();
}
onScroll() {
let list = this.list;
let shouldLoad =
list.scrollTop + list.clientHeight >= (list.scrollHeight - 40)
&& !this.$.model.isLoading;
if (shouldLoad)
this.$.model.loadMore();
}
onKeydown(event) {
if (this.show) {
if (event.keyCode === 13) { // Enter
this.$timeout(() => {
this.selectOption();
});
event.preventDefault();
} else if (event.keyCode === 27) { // Escape
this.clearSearch();
} else if (event.keyCode === 38) { // Arrow up
this.activeOption--;
this.$timeout(() => {
this.setScrollPosition();
}, 100);
} else if (event.keyCode === 40) { // Arrow down
this.activeOption++;
this.$timeout(() => {
this.setScrollPosition();
}, 100);
} else if (event.keyCode === 35) { // End
this.activeOption = this.itemsFiltered.length - 1;
this.$timeout(() => {
this.setScrollPosition();
}, 100);
} else if (event.keyCode === 36) { // Start
this.activeOption = 0;
this.$timeout(() => {
this.setScrollPosition();
}, 100);
} else if (this.filter) {
let oldValue = this.search || '';
if (validKey(event)) {
this.search = oldValue + String.fromCharCode(event.keyCode);
} else if (event.keyCode === 8) { // backSpace
this.search = oldValue.slice(0, -1);
}
} /* else {
console.error(`Error: keyCode ${event.keyCode} not supported`);
} */
}
onLoadMoreClick(event) {
event.preventDefault();
this.$.model.loadMore();
}
setScrollPosition() {
let child = this.$element[0].querySelector('ul.dropdown li.active');
if (child) {
let childRect = child.getBoundingClientRect();
let containerRect = this.container.getBoundingClientRect();
if (typeof child.scrollIntoView === 'function' && (childRect.top > containerRect.top + containerRect.height || childRect.top < containerRect.top)) {
child.scrollIntoView();
onContainerClick(event) {
if (event.defaultPrevented) return;
let index = getPosition(this.container, event);
if (index != -1) this.selectOption(index);
}
onModelDataChange() {
this.buildList();
}
onDocKeyDown(event) {
if (event.defaultPrevented) return;
let data = this.$.model.data;
let option = this.activeOption;
let nOpts = data ? data.length - 1 : 0;
switch (event.keyCode) {
case 13: // Enter
this.selectOption(option);
break;
case 27: // Escape
this.hide();
break;
case 38: // Up
this.moveToOption(option <= 0 ? nOpts : option - 1);
break;
case 40: // Down
this.moveToOption(option >= nOpts ? 0 : option + 1);
break;
case 35: // End
this.moveToOption(nOpts);
break;
case 36: // Start
this.moveToOption(0);
break;
default:
return;
}
event.preventDefault();
this.$.$applyAsync();
}
buildList() {
this.destroyScopes();
this.scopes = [];
let hasTemplate = this.$transclude &&
this.$transclude.isSlotFilled('tplItem');
let fragment = this.document.createDocumentFragment();
let data = this.$.model.data;
if (data) {
for (let i = 0; i < data.length; i++) {
let li = this.document.createElement('li');
fragment.appendChild(li);
if (this.multiple) {
let check = this.document.createElement('input');
check.type = 'checkbox';
li.appendChild(check);
if (this.field && this.field.indexOf(data[i][this.valueField]) != -1)
check.checked = true;
}
if (hasTemplate) {
this.$transclude((clone, scope) => {
Object.assign(scope, data[i]);
li.appendChild(clone[0]);
this.scopes[i] = scope;
}, null, 'tplItem');
} else {
let text = this.document.createTextNode(data[i][this.showField]);
li.appendChild(text);
}
}
}
this.container.innerHTML = '';
this.container.appendChild(fragment);
this.activateOption(this._activeOption);
this.relocate();
}
selectItem(item) {
this.selected = item;
if (this.multiple) {
item.checked = !item.checked;
this.show = true;
} else {
this.show = false;
}
}
loadItems() {
if (this.showLoadMore && this.loadMore) {
this.loadMore();
}
this.show = true;
}
loadFromScroll(e) {
let containerRect = e.target.getBoundingClientRect();
if (e.target.scrollHeight - e.target.scrollTop - containerRect.height <= 50) {
this.loadItems();
}
}
$onChanges(changesObj) {
if (changesObj.show && changesObj.itemWidth && changesObj.itemWidth.currentValue) {
this.$element.css('width', changesObj.itemWidth.currentValue + 'px');
}
if (changesObj.items) {
this.filterItems();
}
}
$onInit() {
if (this.parent)
this.parent.addEventListener('keydown', e => this.onKeydown(e));
destroyScopes() {
if (this.scopes)
for (let scope of this.scopes)
scope.$destroy();
}
$onDestroy() {
if (this.parent)
this.parent.removeEventListener('keydown', e => this.onKeydown(e));
this.destroyScopes();
}
}
DropDown.$inject = ['$element', '$scope', '$transclude', '$timeout', '$http', '$translate'];
DropDown.$inject = ['$element', '$filter', '$timeout'];
/**
* Gets the position of an event element relative to a parent.
*
* @param {HTMLElement} parent The parent element
* @param {Event} event The event object
* @return {Number} The element index
*/
function getPosition(parent, event) {
let target = event.target;
let children = parent.children;
if (target === parent)
return -1;
while (target.parentNode !== parent)
target = target.parentNode;
for (let i = 0; i < children.length; i++)
if (children[i] === target)
return i;
return -1;
}
ngModule.component('vnDropDown', {
template: require('./drop-down.html'),
controller: DropDown,
bindings: {
items: '<',
show: '<',
filter: '@?',
selected: '=',
search: '=?',
loadMore: '&?',
removeLoadMore: '<?',
filterAction: '&?',
showLoadMore: '<?',
itemWidth: '<?',
field: '=?',
data: '<?',
selection: '=?',
search: '<?',
limit: '<?',
showFilter: '<?',
parent: '<?',
multiple: '<?'
multiple: '<?',
onSelect: '&?'
},
transclude: {
vnItem: '?vnItem'
tplItem: '?tplItem'
}
});

View File

@ -1,9 +1,13 @@
import './drop-down.js';
import template from './drop-down.html';
describe('Component vnDropDown', () => {
let $componentController;
let $timeout;
let $element;
let $scope;
let $httpBackend;
let $q;
let $filter;
let controller;
@ -11,337 +15,34 @@ describe('Component vnDropDown', () => {
angular.mock.module('client');
});
beforeEach(angular.mock.inject((_$componentController_, _$timeout_, _$filter_, _$httpBackend_) => {
_$httpBackend_.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$timeout_, _$httpBackend_, _$q_, _$filter_) => {
$componentController = _$componentController_;
$element = angular.element('<div><ul><li></li></ul></div>');
$element = angular.element(`<div>${template}</div>`);
$timeout = _$timeout_;
$q = _$q_;
$filter = _$filter_;
controller = $componentController('vnDropDown', {$element, $timeout, $filter});
$scope = $rootScope.$new();
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
$scope.model = $componentController('vnModel', {$httpBackend, $q, $filter});
controller = $componentController('vnDropDown', {$element, $scope, $transclude: null, $timeout, $httpBackend, $translate: null});
controller.parent = angular.element('<vn-parent></vn-parent>')[0];
}));
describe('show() setter', () => {
describe('show() method', () => {
it(`should define controllers _show using the value received as argument`, () => {
controller._show = 'old value';
controller.show = 'new value';
controller.show();
expect(controller._show).toEqual('new value');
expect(controller.shown).toEqual(true);
});
});
describe('search()', () => {
it(`should set controllers _search property with the value received`, () => {
controller.search = 'some filter valiue';
describe('hide() method', () => {
it(`should define controllers _show using the value received as argument`, () => {
controller.hide();
expect(controller._search).toEqual('some filter valiue');
});
it(`should set controllers _search property to null as the value received is an empty string`, () => {
controller.search = '';
expect(controller._search).toEqual(null);
});
it(`should call onFilterRest() if controllers filterAction is defined`, () => {
controller.filterAction = true;
spyOn(controller, 'onFilterRest');
controller.search = 'some filter valiue';
expect(controller.onFilterRest).toHaveBeenCalledWith();
});
it(`should call filterItems() if controllers filterAction is undefined`, () => {
controller.filterAction = undefined;
spyOn(controller, 'filterItems');
controller.search = 'some filter valiue';
expect(controller.filterItems).toHaveBeenCalledWith();
});
});
describe('activeOption() setter', () => {
it(`should set _activeOption as items.length if showLoadMore is defined if activeOption is bigger than items.length then call loadItems()`, () => {
spyOn(controller, 'loadItems');
controller.showLoadMore = true;
controller.itemsFiltered = [{id: 1, name: 'Batman'}, {id: 2, name: 'Bruce'}, {id: 3, name: 'Logan'}, {id: 4, name: 'Wolverine'}];
controller.activeOption = 10;
$timeout.flush();
expect(controller.activeOption).toEqual(4);
expect(controller.loadItems).toHaveBeenCalledWith();
});
it(`should set _activeOption as activeOption if showLoadMore is defined if activeOption is smaller than items.length then call loadItems()`, () => {
spyOn(controller, 'loadItems');
controller.showLoadMore = true;
controller.itemsFiltered = [{id: 1, name: 'Batman'}, {id: 2, name: 'Bruce'}, {id: 3, name: 'Logan'}, {id: 4, name: 'Wolverine'}];
controller.activeOption = 2;
$timeout.flush();
expect(controller.activeOption).toEqual(2);
expect(controller.loadItems).toHaveBeenCalledWith();
});
it(`should set _activeOption as items.length -1 if showLoadMore is not defined then call loadItems()`, () => {
spyOn(controller, 'loadItems');
controller.showLoadMore = undefined;
controller.itemsFiltered = [{id: 1, name: 'Batman'}, {id: 2, name: 'Bruce'}, {id: 3, name: 'Logan'}, {id: 4, name: 'Wolverine'}];
controller.activeOption = 10;
$timeout.flush();
expect(controller.activeOption).toEqual(3);
expect(controller.loadItems).toHaveBeenCalledWith();
});
it(`should define _activeOption as activeOption and never call loadItems()`, () => {
spyOn(controller, 'loadItems');
controller.itemsFiltered = [{id: 1, name: 'Batman'}, {id: 2, name: 'Bruce'}, {id: 3, name: 'Logan'}, {id: 4, name: 'Wolverine'}, {id: 5, name: 'Doctor X'}];
controller.activeOption = 1;
$timeout.flush();
expect(controller.activeOption).toEqual(1);
expect(controller.loadItems).not.toHaveBeenCalledWith();
});
});
describe('filterItems() setter', () => {
it(`should set _itemsFiltered using the value of items`, () => {
controller.items = [{id: 1, name: 'Batman'}];
controller.filterItems();
expect(controller.itemsFiltered).toEqual(controller.items);
});
it(`should set _itemsFiltered with the filtered value of items`, () => {
controller.items = [{id: 1, name: 'Batman'}, {id: 2, name: 'Bruce'}, {id: 3, name: 'Logan'}, {id: 4, name: 'Wolverine'}];
controller.search = 'Batman';
controller.filterItems();
expect(controller.itemsFiltered).toEqual([Object({id: 1, name: 'Batman'})]);
});
it(`should set _itemsFiltered an empty array`, () => {
controller.items = [{id: 1, name: 'Batman'}, {id: 2, name: 'Bruce'}, {id: 3, name: 'Logan'}, {id: 4, name: 'Wolverine'}];
controller.search = 'the Joker';
expect(controller.itemsFiltered.length).toEqual(0);
});
});
describe('onFilterRest()', () => {
it(`should call the filterAction() with a constructed object as argument`, () => {
controller.filterAction = () => {};
controller.search = 'Batman';
spyOn(controller, 'filterAction');
controller.onFilterRest();
expect(controller.filterAction).toHaveBeenCalledWith({search: controller.search});
});
});
describe('$onChanges()', () => {
it(`should set the width css of the $element`, () => {
let argumentObject = {show: true, itemWidth: {currentValue: 100}};
spyOn(controller.$element, 'css');
controller.$onChanges(argumentObject);
expect(controller.$element.css).toHaveBeenCalledWith('width', '100px');
});
it(`should set the width css of the $element`, () => {
let argumentObject = {items: {id: 1, name: 'Batman'}};
spyOn(controller, 'filterItems');
controller.$onChanges(argumentObject);
expect(controller.filterItems).toHaveBeenCalledWith();
});
});
describe('clearSearch()', () => {
it(`should set the controllers search property to null`, () => {
controller.search = true;
controller.clearSearch();
expect(controller.search).toEqual(null);
});
});
describe('selectOption()', () => {
it(`should set controllers selected and show properties then call clearSearch() as _activeOption is smaller than items.length`, () => {
spyOn(controller, 'clearSearch');
controller.items = [{id: 1, name: 'Batman'}, {id: 2, name: 'Bruce'}, {id: 3, name: 'Logan'}, {id: 4, name: 'Wolverine'}];
controller._activeOption = 0;
controller.selectOption();
expect(controller.selected).toEqual(controller.items[controller._activeOption]);
expect(controller._show).toEqual(false);
expect(controller.clearSearch).toHaveBeenCalledWith();
});
it(`should not set controllers selected, show and never call clearSearch() as _activeOption is bigger than items.length`, () => {
spyOn(controller, 'clearSearch');
controller.items = [{id: 1, name: 'Batman'}, {id: 2, name: 'Bruce'}, {id: 3, name: 'Logan'}, {id: 4, name: 'Wolverine'}];
controller._activeOption = 100;
controller.selectOption();
expect(controller.selected).not.toBeDefined();
expect(controller._show).not.toBeDefined();
expect(controller.clearSearch).not.toHaveBeenCalledWith();
});
it(`should call loadMore() if the activeValue equals items.length`, () => {
controller.loadMore = () => {};
spyOn(controller, 'loadMore');
controller.items = [{id: 1, name: 'Batman'}, {id: 2, name: 'Bruce'}, {id: 3, name: 'Logan'}, {id: 4, name: 'Wolverine'}];
controller._activeOption = 4;
controller.showLoadMore = 4;
controller.selectOption();
expect(controller.loadMore).toHaveBeenCalledWith();
});
});
describe('onKeydown()', () => {
it(`should call selectOption() and preventDefault() if Enter key is pressed`, () => {
spyOn(controller, 'selectOption');
controller._show = true;
controller.element = document.createElement('div');
let event = {target: controller.element, preventDefault: () => {}};
event.keyCode = 13;
spyOn(event, 'preventDefault');
controller.onKeydown(event);
$timeout.flush();
expect(controller.selectOption).toHaveBeenCalledWith();
expect(event.preventDefault).toHaveBeenCalledWith();
});
it(`should call clearSearch() Esc key is pressed`, () => {
spyOn(controller, 'clearSearch');
controller._show = true;
controller.element = document.createElement('div');
let event = {target: controller.element};
event.keyCode = 27;
controller.onKeydown(event);
expect(controller.clearSearch).toHaveBeenCalledWith();
});
it(`should call clearSearch() Esc key is pressed and take off 1 from _activeOption`, () => {
controller.itemsFiltered = [{id: 1, name: 'Batman'}, {id: 2, name: 'Bruce'}, {id: 3, name: 'Logan'}, {id: 4, name: 'Wolverine'}];
spyOn(controller, 'setScrollPosition');
controller._show = true;
controller.element = document.createElement('div');
let event = {target: controller.element};
event.keyCode = 38;
controller._activeOption = 1;
controller.onKeydown(event);
$timeout.flush();
expect(controller.setScrollPosition).toHaveBeenCalledWith();
expect(controller._activeOption).toEqual(0);
});
it(`should call clearSearch() Esc key is pressed and add up 1 to _activeOption`, () => {
controller.itemsFiltered = [{id: 1, name: 'Batman'}, {id: 2, name: 'Bruce'}, {id: 3, name: 'Logan'}, {id: 4, name: 'Wolverine'}];
spyOn(controller, 'setScrollPosition');
controller._show = true;
controller.element = document.createElement('div');
let event = {target: controller.element};
event.keyCode = 40;
controller._activeOption = 1;
controller.onKeydown(event);
$timeout.flush();
expect(controller.setScrollPosition).toHaveBeenCalledWith();
expect(controller._activeOption).toEqual(2);
});
});
describe('setScrollPosition()', () => {
it(`should call child.scrollIntoView if defined `, () => {
$element[0].firstChild.setAttribute('class', 'dropdown');
$element[0].firstChild.firstChild.setAttribute('class', 'active');
let child = $element[0].firstChild.firstChild;
spyOn(child, 'getBoundingClientRect').and.returnValue({top: 100});
let container = $element[0].firstChild;
spyOn(container, 'getBoundingClientRect').and.returnValue({top: 10, height: 70});
child.scrollIntoView = () => {};
spyOn(child, 'scrollIntoView');
controller._activeOption = 0;
controller.setScrollPosition();
expect(child.scrollIntoView).toHaveBeenCalledWith();
});
});
describe('selectItem()', () => {
it(`should pass item to selected and set controller._show to false`, () => {
let item = {id: 1, name: 'Batman'};
controller.selectItem(item);
expect(controller.selected).toEqual(item);
expect(controller._show).toEqual(false);
});
it(`should pass item to selected and set controller._show to true if the controller.multiple is defined`, () => {
let item = {id: 1, name: 'Batman'};
controller.multiple = true;
controller.selectItem(item);
expect(controller.selected).toEqual(item);
expect(controller._show).not.toBeDefined();
});
});
describe('loadItems()', () => {
it(`should set controller.show to true`, () => {
controller.show = false;
controller.itemsFiltered = [{id: 1, name: 'Batman'}, {id: 2, name: 'Bruce'}, {id: 3, name: 'Logan'}, {id: 4, name: 'Wolverine'}];
controller.loadItems();
expect(controller.show).toEqual(true);
});
it(`should call loadMore() and then set controller._show to true if there are items`, () => {
controller.showLoadMore = () => {};
controller.loadMore = () => {};
spyOn(controller, 'loadMore');
controller.itemsFiltered = [{id: 1, name: 'Batman'}, {id: 2, name: 'Bruce'}, {id: 3, name: 'Logan'}, {id: 4, name: 'Wolverine'}];
controller.loadItems();
expect(controller._show).toEqual(true);
expect(controller.loadMore).toHaveBeenCalledWith();
});
it(`should call loadMore() and then set controller._show to undefined if there are not items`, () => {
controller.showLoadMore = () => {};
controller.loadMore = () => {};
spyOn(controller, 'loadMore');
controller.itemsFiltered = [];
controller.loadItems();
expect(controller._show).not.toBeDefined();
expect(controller.loadMore).toHaveBeenCalledWith();
});
});
describe('$onInit()', () => {
it(`should add an event listener to the parent element`, () => {
spyOn(controller.parent, 'addEventListener');
controller.$onInit();
expect(controller.parent.addEventListener).toHaveBeenCalledWith('keydown', jasmine.any(Function));
});
});
describe('$onDestroy()', () => {
it(`should remove an event listener from the parent element`, () => {
spyOn(controller.parent, 'removeEventListener');
controller.$onDestroy();
expect(controller.parent.removeEventListener).toHaveBeenCalledWith('keydown', jasmine.any(Function));
expect(controller.shown).toEqual(false);
});
});
});

View File

@ -0,0 +1,107 @@
import ngModule from '../../module';
export default class Model {
constructor($http, $q, $filter) {
this.$http = $http;
this.$q = $q;
this.$filter = $filter;
this.filter = null;
this.clear();
}
get isLoading() {
return this.canceler != null;
}
loadMore() {
if (this.moreRows) {
let filter = Object.assign({}, this.myFilter);
filter.skip += filter.limit;
this.sendRequest(filter, true);
}
}
clear() {
this.cancelRequest();
this.data = null;
this.moreRows = false;
this.dataChanged();
}
refresh(search) {
if (this.url) {
let filter = Object.assign({}, this.filter);
if (filter.limit)
filter.skip = 0;
this.clear();
this.sendRequest(filter);
} else if (this.staticData) {
if (search)
this.data = this.$filter('filter')(this.staticData, search);
else
this.data = this.staticData;
this.dataChanged();
}
}
cancelRequest() {
if (this.canceler) {
this.canceler.resolve();
this.canceler = null;
this.request = null;
}
}
sendRequest(filter, append) {
this.cancelRequest();
this.canceler = this.$q.defer();
let options = {timeout: this.canceler.promise};
let json = encodeURIComponent(JSON.stringify(filter));
this.request = this.$http.get(`${this.url}?filter=${json}`, options).then(
json => this.onRemoteDone(json, filter, append),
json => this.onRemoteError(json)
);
}
onRemoteDone(json, filter, append) {
let data = json.data;
if (append)
this.data = this.data.concat(data);
else
this.data = data;
this.myFilter = filter;
this.moreRows = filter.limit && data.length == filter.limit;
this.onRequestEnd();
this.dataChanged();
}
onRemoteError(json) {
this.onRequestEnd();
}
onRequestEnd() {
this.request = null;
this.canceler = null;
}
dataChanged() {
if (this.onDataChange)
this.onDataChange();
}
}
Model.$inject = ['$http', '$q', '$filter'];
ngModule.component('vnModel', {
controller: Model,
bindings: {
url: '@?',
staticData: '<?',
data: '=?',
limit: '<?',
onDataChange: '&?'
}
});

161
client/core/src/components/drop-down/style.scss Normal file → Executable file
View File

@ -1,80 +1,95 @@
vn-drop-down {
position: absolute;
z-index: 10;
padding: 0 15px;
margin-left: -15px;
background: transparent;
max-height: 446px;
overflow: hidden;
.dropdown-body{
background: white;
border: 1px solid #A7A7A7;
.filter{
padding: 5px 9px 5px 5px;
input{
height: 25px;
padding-left: 5px;
}
vn-icon{
font-size: 16px;
margin-left: -20px;
margin-top: 7px;
cursor: pointer;
&:hover{
color: red;
}
}
}
ul{
padding: 0;
margin: 0;
background: white;
max-height: 378px;
overflow-y: auto;
li {
outline: none;
list-style-type: none;
padding: 5px 10px;
cursor: pointer;
white-space: nowrap;
&.dropdown__loadMore{
color: rgb(255,171,64);
font-weight: 700;
}
&.dropdown__loadMore.noMore{
color:#424242;
font-weight: 700;
opacity: 0.7;
}
input[type=checkbox]{
float: left;
margin: 5px 5px 0 0;
}
}
li.active{
background-color: #3D3A3B;
color: white;
}
}
}
}
#ddBack {
position: fixed;
z-index: 9998;
display: none;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: transparent;
}
vn-drop-down.fixed-dropDown {
position: fixed;
margin: 0;
padding: 0;
.dropdown-body{
height: 100%;
ul{
border-bottom: 1px solid #A7A7A7;
right: 0;
bottom: 0;
&.shown {
& > .body {
transform: translateY(0);
opacity: 1;
}
}
}
& > .body {
position: fixed;
box-shadow: 0 .1em .4em rgba(1, 1, 1, .4);
border-radius: .1em;
background-color: white;
display: flex;
flex-direction: column;
transform: translateY(-.4em);
opacity: 0;
transition-property: opacity, transform;
transition-duration: 250ms;
transition-timing-function: ease-in-out;
& > .filter {
position: relative;
& > .search {
display: block;
width: 100%;
box-sizing: border-box;
border: none;
border-bottom: 1px solid #ccc;
padding: .7em;
}
& > vn-icon[icon=clear] {
display: none;
cursor: pointer;
position: absolute;
right: .5em;
top: .7em;
height: 1em;
color: #888;
border-radius: 50%;
background-color: rgba(255, 255, 255, .8);
font-size: 18px;
&:hover {
color: #333;
}
}
&:hover > vn-icon[icon=clear] {
display: block;
}
}
& > .list {
max-height: 12.2em;
overflow: auto;
ul {
padding: 0;
margin: 0;
}
li, .status {
outline: none;
list-style-type: none;
padding: .6em;
cursor: pointer;
white-space: nowrap;
transition: background-color 250ms ease-out;
display: flex;
& > input[type=checkbox] {
margin: 0;
margin-right: .6em;
}
&:hover {
background-color: rgba(0, 0, 0, .1);
}
&.active {
background-color: #3D3A3B;
color: white;
}
}
.status {
color: #ffab40;
font-weight: bold;
}
}
}
}

View File

@ -15,6 +15,7 @@ export default class Controller extends Component {
this.button = $element[0].querySelector('button');
this.textNode = this.snackbar.querySelector('.text');
}
/**
* Shows a notification.
*
@ -29,14 +30,13 @@ export default class Controller extends Component {
this.button.textContent =
data.actionText || this.$translate.instant('Hide');
this.documentClickHandler = e => this.onDocumentClick(e);
document.addEventListener('click', this.documentClickHandler);
this.timeoutId = setTimeout(() => this.hide(),
data.timeout || 6000);
this.timeoutId = setTimeout(() =>
this.hide(), data.timeout || 6000);
this.transitionTimeout =
setTimeout(() => this.$snackbar.addClass('shown'), 30);
this.transitionTimeout = setTimeout(() =>
this.$snackbar.addClass('shown'), 30);
}
/**
* Shows an error.
*
@ -46,38 +46,38 @@ export default class Controller extends Component {
this.$snackbar.addClass('error');
this.show(data);
}
/**
* Hides the snackbar.
*/
hide() {
if (!this.shown) return;
clearTimeout(this.timeoutId);
document.removeEventListener('click', this.documentClickHandler);
this.shown = false;
this.hideTimeout = setTimeout(() => this.onTransitionEnd(), 250);
this.transitionTimeout =
setTimeout(() => this.$snackbar.removeClass('shown'), 30);
}
onTransitionEnd() {
this.$snackbar.removeClass('error');
this.textNode.textContent = '';
this.button.textContent = '';
this.actionHandler = null;
}
onDocumentClick(event) {
if (event === this.event) return;
this.hide();
}
onSnackbarClick(event) {
this.event = event;
}
onButtonClick() {
if (this.actionHandler)
this.actionHandler();
else
this.hide();
}
clearTimeouts() {
clearTimeout(this.timeoutId);
clearTimeout(this.hideTimeout);
@ -86,6 +86,7 @@ export default class Controller extends Component {
this.hideTimeout = null;
this.transitionTimeout = null;
}
$onDestroy() {
this.clearTimeouts();
}

View File

@ -12,17 +12,21 @@
<vn-auto style="position: relative" pad-medium text-center>
<img
ng-src="http://verdnatura.es/vn-image-data/catalog/200x200/{{::$ctrl.item.image}}"
zoom-image="http://verdnatura.es/vn-image-data/catalog/900x900/{{::$ctrl.item.image}}" on-error-src/>
<a href="https://www.verdnatura.es/#!form=admin/items&filter={{::$ctrl.item.id}}" target="_blank"><vn-float-button icon="edit"
style="position: absolute; bottom: 1em; right: 1em;"
vn-visible-by="administrative"></vn-float-button>
zoom-image="http://verdnatura.es/vn-image-data/catalog/900x900/{{::$ctrl.item.image}}"
on-error-src/>
<a href="https://www.verdnatura.es/#!form=admin/items&filter={{::$ctrl.item.id}}" target="_blank">
<vn-float-button
icon="edit"
style="position: absolute; margin: 1em; bottom: 0; right: 0;"
vn-visible-by="administrative">
</vn-float-button>
</a>
</vn-auto>
<vn-auto pad-medium>
<h6>{{$ctrl.item.name}}</h6>
<div><vn-label translate>Id</vn-label> {{$ctrl.item.id}}</div>
<div ng-repeat="itemTag in $ctrl.itemTags | limitTo:4">
<div><vn-label translate>{{$ctrl.tags[itemTag.tagFk].name}}</vn-label>: {{itemTag.value}}</div>
<div><vn-label translate>{{$ctrl.tags[itemTag.tagFk].name}}</vn-label> {{itemTag.value}}</div>
</div>
</vn-auto>
</vn-vertical>

View File

@ -32,14 +32,20 @@
</vn-one>
<vn-one margin-medium>
<vn-vertical>
<h5 translate>Tags</h5>
<p ng-repeat="tag in $ctrl.tags track by tag.id">
<span translate>{{tag.tag.name}}</span>: <b>{{tag.value}}</b>
<h5 translate>Tax</h5>
<p ng-repeat="tax in $ctrl.taxes track by $index">
<span translate>{{tax.country.country}}</span>: <b>{{tax.taxClass.description}}</b>
</p>
</vn-vertical>
</vn-one>
</vn-horizontal>
<vn-horizontal>
<vn-one margin-medium>
<h5 translate>Tags</h5>
<p ng-repeat="tag in $ctrl.tags track by tag.id">
<span translate>{{tag.tag.name}}</span>: <b>{{tag.value}}</b>
</p>
</vn-one>
<vn-one margin-medium>
<vn-vertical>
<h5 translate>Nicho</h5>

View File

@ -17,6 +17,25 @@ class ItemSummary {
});
}
_getTaxes() {
let filter = {
fields: ['id', 'countryFk', 'taxClassFk'],
include: [{
relation: 'country',
scope: {fields: ['country']}
}, {
relation: 'taxClass',
scope: {fields: ['id', 'description']}
}]
};
let urlFilter = encodeURIComponent(JSON.stringify(filter));
let url = `/item/api/Items/${this.item.id}/taxes?filter=${urlFilter}`;
this.$http.get(url).then(json => {
this.taxes = json.data;
});
}
_getBotanical() {
let filter = {
where: {itemFk: this.item.id},
@ -58,6 +77,7 @@ class ItemSummary {
this._getTags();
this._getBarcodes();
this._getNiches();
this._getTaxes();
if (!this.item.botanical)
this._getBotanical();
}

View File

@ -1,5 +1,5 @@
<vn-horizontal>
<ul style="list-style-type: none; margin: 0; padding: 0; width: 100%; color: #666;">
<ul style="list-style-type: none; margin: 0; padding: 0; width: 100%;">
<vn-menu-item ng-repeat="item in $ctrl.items" item="::item"></vn-menu-item>
</ul>
</vn-horizontal>

View File

@ -1,5 +1,5 @@
import ngModule from '../../module';
import './style.css';
import './style.scss';
export default class LeftMenu {
constructor(aclService, $state) {

View File

@ -1,7 +1,9 @@
<li ng-class="{active: $ctrl.item.active}">
<a ui-sref="{{::$ctrl.item.href}}" style="display: block; text-decoration: none; color: inherit; padding: .5em 2em;">
<i class="material-icons" style="float: right; margin-left: .4em;">keyboard_arrow_right</i>
<i class="material-icons" style="vertical-align: middle; margin-right: .4em;">{{::$ctrl.item.icon}}</i>
<a ui-sref="{{::$ctrl.item.href}}"
class="vn-clickable"
style="display: block; text-decoration: none; padding: .5em 2em;">
<vn-icon icon="keyboard_arrow_right" class="material-icons" style="float: right; margin-left: .4em;"></vn-icon>
<vn-icon icon="{{::$ctrl.item.icon}}" class="material-icons" style="vertical-align: middle; margin-right: .4em;"></vn-icon>
<span translate>{{::$ctrl.item.description}}</span>
</a>
</li>

View File

@ -1,7 +0,0 @@
vn-menu-item a:hover {
color: white !important;
background-color: #424242;
}
vn-menu-item li.active{
background-color: #E6E6E6;
}

View File

@ -0,0 +1,7 @@
vn-menu-item {
& > li.active {
background-color: #424242;
color: white;
}
}

View File

@ -26,11 +26,11 @@ html [bg-dark-menu], .bg-dark-menu {
background-color: darken($bg-dark-menu, 35%);
}
/* Color para items seleccionados */
.bg-dark-item{
.bg-dark-item {
background-color: $bg-dark-bar;
color: $color-white;
}
/* Color para items inactivos */
.bg-opacity-item{
.bg-opacity-item {
opacity: 0.6;
}

View File

@ -24,15 +24,6 @@ html [fixed-bottom-right] {
bottom: 2em;
right: 2em;
}
vn-label {
font-size: .9em;
color: #666;
}
vn-button-bar {
display: block;
margin-top: $margin-small;
}
html [text-center], .text-center {
text-align: center;
}
@ -105,6 +96,33 @@ html [noDrop], .noDrop{
cursor: no-drop;
}
a {
color: inherit;
}
.vn-clickable {
cursor: pointer;
transition: background-color 250ms ease-out;
&:hover {
background-color: rgba(0, 0, 0, .1);
}
}
button {
@extend .vn-clickable;
}
vn-label {
font-size: .9em;
color: #666;
}
vn-button-bar {
display: block;
margin-top: $margin-small;
}
vn-main-block {
display:block;
max-width: 1920px;
@ -118,6 +136,7 @@ vn-main-block {
padding-bottom: 1em;
}
}
.vn-descriptor {
& .header {
background: #ffa410;
@ -130,15 +149,15 @@ vn-main-block {
font-size: 2.5em;
}
& > a {
@extend .vn-clickable;
display: flex;
align-items: center;
padding: .5em;
color: white;
text-decoration: none;
transition: background-color 250ms ease-out;
&:hover {
background-color: rgba(1, 1, 1, 0.1);
}
& > vn-icon {
font-size: 1.8em;
}
@ -154,19 +173,12 @@ vn-main-block {
.vn-list-item {
@extend .pad-medium;
@extend .border-solid-bottom;
@extend .vn-clickable;
display: block;
text-decoration: none;
color: inherit;
&:hover {
color: white;
background-color: #424242;
vn-label {
color: #aaa;
}
}
& > vn-horizontal > .buttons {
align-items: center;
@ -174,6 +186,7 @@ vn-main-block {
opacity: .4;
color: #ffa410;
margin-left: .5em;
transition: opacity 250ms ease-out;
&:hover {
opacity: 1;

View File

@ -25,8 +25,8 @@ export default {
socialName: `${components.vnTextfield}[name="socialName"]`,
userName: `${components.vnTextfield}[name="userName"]`,
email: `${components.vnTextfield}[name="email"]`,
salesPersonInput: `${components.vnAutocomplete}[field="$ctrl.client.salesPersonFk"] > vn-vertical > ${components.vnTextfield}`,
salesBruceBannerOption: `${components.vnAutocomplete}[field="$ctrl.client.salesPersonFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(1)`,
salesPersonInput: `vn-autocomplete[field="$ctrl.client.salesPersonFk"] input`,
salesBruceBannerOption: `vn-autocomplete[field="$ctrl.client.salesPersonFk"] vn-drop-down ul > li:nth-child(1)`,
createButton: `${components.vnSubmit}`
},
clientBasicData: {
@ -37,10 +37,10 @@ export default {
mobileInput: `${components.vnTextfield}[name="mobile"]`,
faxInput: `${components.vnTextfield}[name="fax"]`,
emailInput: `${components.vnTextfield}[name="email"]`,
salesPersonInput: `${components.vnAutocomplete}[field="$ctrl.client.salesPersonFk"] > vn-vertical > ${components.vnTextfield}`,
salesPersonOptionOne: `${components.vnAutocomplete}[field="$ctrl.client.salesPersonFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(1)`,
channelInput: `${components.vnAutocomplete}[field="$ctrl.client.contactChannelFk"] > vn-vertical > ${components.vnTextfield}`,
channelMetropolisOption: `${components.vnAutocomplete}[field="$ctrl.client.contactChannelFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(3)`,
salesPersonInput: `${components.vnAutocomplete}[field="$ctrl.client.salesPersonFk"] input`,
salesPersonOptionOne: `${components.vnAutocomplete}[field="$ctrl.client.salesPersonFk"] vn-drop-down ul > li:nth-child(1)`,
channelInput: `${components.vnAutocomplete}[field="$ctrl.client.contactChannelFk"] input`,
channelMetropolisOption: `${components.vnAutocomplete}[field="$ctrl.client.contactChannelFk"] vn-drop-down ul > li:nth-child(3)`,
saveButton: `${components.vnSubmit}`
},
clientFiscalData: {
@ -52,10 +52,10 @@ export default {
addressInput: `${components.vnTextfield}[name="street"]`,
cityInput: `${components.vnTextfield}[name="city"]`,
postcodeInput: `${components.vnTextfield}[name="postcode"]`,
provinceInput: `${components.vnAutocomplete}[field="$ctrl.client.provinceFk"] > vn-vertical > ${components.vnTextfield}`,
provinceFifthOption: `${components.vnAutocomplete}[field="$ctrl.client.provinceFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(5)`,
countryInput: `${components.vnAutocomplete}[field="$ctrl.client.countryFk"] > vn-vertical > ${components.vnTextfield}`,
countryThirdOption: `${components.vnAutocomplete}[field="$ctrl.client.countryFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(3)`,
provinceInput: `${components.vnAutocomplete}[field="$ctrl.client.provinceFk"] input`,
provinceFifthOption: `${components.vnAutocomplete}[field="$ctrl.client.provinceFk"] vn-drop-down ul > li:nth-child(5)`,
countryInput: `${components.vnAutocomplete}[field="$ctrl.client.countryFk"] input`,
countryThirdOption: `${components.vnAutocomplete}[field="$ctrl.client.countryFk"] vn-drop-down ul > li:nth-child(3)`,
activeCheckboxLabel: `${components.vnCheck}[label='Active'] > label`,
invoiceByAddressCheckboxInput: `${components.vnCheck}[label='Invoice by address'] > label > input`,
verifiedDataCheckboxInput: `${components.vnCheck}[label='Verified data'] > label > input`,
@ -66,9 +66,9 @@ export default {
},
clientPayMethod: {
payMethodButton: `${components.vnMenuItem}[ui-sref="clientCard.billingData"]`,
payMethodInput: `${components.vnAutocomplete}[field="$ctrl.client.payMethodFk"] > vn-vertical > ${components.vnTextfield}`,
payMethodIBANOption: `${components.vnAutocomplete}[field="$ctrl.client.payMethodFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(5)`,
payMethodOptionOne: `${components.vnAutocomplete}[field="$ctrl.client.payMethodFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(2)`,
payMethodInput: `${components.vnAutocomplete}[field="$ctrl.client.payMethodFk"] input`,
payMethodIBANOption: `${components.vnAutocomplete}[field="$ctrl.client.payMethodFk"] vn-drop-down ul > li:nth-child(5)`,
payMethodOptionOne: `${components.vnAutocomplete}[field="$ctrl.client.payMethodFk"] vn-drop-down ul > li:nth-child(2)`,
IBANInput: `${components.vnTextfield}[name="iban"]`,
dueDayInput: `${components.vnTextfield}[name="dueDay"]`,
cancelNotificationButton: 'vn-client-billing-data > vn-confirm button[response=CANCEL]',
@ -85,10 +85,10 @@ export default {
streetAddressInput: `${components.vnTextfield}[name="street"]`,
postcodeInput: `${components.vnTextfield}[name="postalCode"]`,
cityInput: `${components.vnTextfield}[name="city"]`,
provinceInput: `${components.vnAutocomplete}[field="$ctrl.address.provinceFk"] > vn-vertical > ${components.vnTextfield}`,
provinceSecondOption: `${components.vnAutocomplete}[field="$ctrl.address.provinceFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(2)`,
agencyInput: `${components.vnAutocomplete}[field="$ctrl.address.agencyModeFk"] > vn-vertical > ${components.vnTextfield}`,
agenctySecondOption: `${components.vnAutocomplete}[field="$ctrl.address.agencyModeFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(2)`,
provinceInput: `${components.vnAutocomplete}[field="$ctrl.address.provinceFk"] input`,
provinceSecondOption: `${components.vnAutocomplete}[field="$ctrl.address.provinceFk"] vn-drop-down ul > li:nth-child(2)`,
agencyInput: `${components.vnAutocomplete}[field="$ctrl.address.agencyModeFk"] input`,
agenctySecondOption: `${components.vnAutocomplete}[field="$ctrl.address.agencyModeFk"] vn-drop-down ul > li:nth-child(2)`,
phoneInput: `${components.vnTextfield}[name="phone"]`,
mobileInput: `${components.vnTextfield}[name="mobile"]`,
defaultAddress: 'vn-client-addresses > vn-vertical > vn-card > div > vn-horizontal:nth-child(2) > vn-one > vn-horizontal > vn-one > div:nth-child(2)',
@ -98,14 +98,14 @@ export default {
activeCheckbox: `${components.vnCheck}[label='Enabled'] > label > input`,
equalizationTaxCheckboxLabel: `${components.vnCheck}[label='Is equalizated'] > label > input`,
addAddressNoteButton: `${components.vnIcon}[icon="add_circle"]`,
firstObservationTypeSelect: `${components.vnAutocomplete}[field="observation.observationTypeFk"]:nth-child(1) > vn-vertical > ${components.vnTextfield}`,
firstObservationTypeSelectOptionOne: `${components.vnAutocomplete}[field="observation.observationTypeFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(1)`,
firstObservationTypeSelect: `${components.vnAutocomplete}[field="observation.observationTypeFk"]:nth-child(1) input`,
firstObservationTypeSelectOptionOne: `${components.vnAutocomplete}[field="observation.observationTypeFk"] vn-drop-down ul > li:nth-child(1)`,
firstObservationDescriptionInput: `vn-horizontal:nth-child(3) > vn-textfield[label="Description"] > div > input`,
secondObservationTypeSelect: `${components.vnAutocomplete}[field="observation.observationTypeFk"]:nth-child(2) > vn-vertical > ${components.vnTextfield}`,
secondObservationTypeSelectOptionTwo: `${components.vnAutocomplete}[field="observation.observationTypeFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(2)`,
secondObservationTypeSelect: `${components.vnAutocomplete}[field="observation.observationTypeFk"]:nth-child(2) input`,
secondObservationTypeSelectOptionTwo: `${components.vnAutocomplete}[field="observation.observationTypeFk"] vn-drop-down ul > li:nth-child(2)`,
secondObservationDescriptionInput: `vn-horizontal:nth-child(4) > vn-textfield[label="Description"] > div > input`,
thirdObservationTypeSelect: `${components.vnAutocomplete}[field="observation.observationTypeFk"]:nth-child(3) > vn-vertical > ${components.vnTextfield}`,
thirdObservationTypeSelectOptionThree: `${components.vnAutocomplete}[field="observation.observationTypeFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(3)`,
thirdObservationTypeSelect: `${components.vnAutocomplete}[field="observation.observationTypeFk"]:nth-child(3) input`,
thirdObservationTypeSelectOptionThree: `${components.vnAutocomplete}[field="observation.observationTypeFk"] vn-drop-down ul > li:nth-child(3)`,
thirdObservationDescriptionInput: `vn-horizontal:nth-child(5) > vn-textfield[label="Description"] > div > input`,
saveButton: `${components.vnSubmit}`
},
@ -134,8 +134,8 @@ export default {
addGreugeFloatButton: `${components.vnFloatButton}`,
amountInput: `${components.vnTextfield}[name="amount"]`,
descriptionInput: `${components.vnTextfield}[name="description"]`,
typeInput: `${components.vnAutocomplete}[field="$ctrl.greuge.greugeTypeFk"] > vn-vertical > ${components.vnTextfield}`,
typeSecondOption: `${components.vnAutocomplete}[field="$ctrl.greuge.greugeTypeFk"] > vn-vertical > vn-drop-down > vn-vertical > vn-auto:nth-child(2) > ul > li`,
typeInput: `${components.vnAutocomplete}[field="$ctrl.greuge.greugeTypeFk"] input`,
typeSecondOption: `${components.vnAutocomplete}[field="$ctrl.greuge.greugeTypeFk"] vn-drop-down ul > li`,
saveButton: `${components.vnSubmit}`,
firstGreugeText: 'vn-client-greuge-list .list-element'
},
@ -159,54 +159,54 @@ export default {
},
itemCreateView: {
name: `${components.vnTextfield}[name="name"]`,
typeSelect: `${components.vnAutocomplete}[field="$ctrl.item.typeFk"] > vn-vertical > ${components.vnTextfield}`,
typeSelectOptionOne: `${components.vnAutocomplete}[field="$ctrl.item.typeFk"] > vn-vertical > vn-drop-down > vn-vertical > vn-auto > ul > li:nth-child(2)`,
intrastatSelect: `${components.vnAutocomplete}[field="$ctrl.item.intrastatFk"] > vn-vertical > ${components.vnTextfield}`,
intrastatSelectOptionOne: `${components.vnAutocomplete}[field="$ctrl.item.intrastatFk"] > vn-vertical > vn-drop-down > vn-vertical > vn-auto > ul > li:nth-child(2)`,
originSelect: `${components.vnAutocomplete}[field="$ctrl.item.originFk"] > vn-vertical > ${components.vnTextfield}`,
originSelectOptionOne: `${components.vnAutocomplete}[field="$ctrl.item.originFk"] > vn-vertical > vn-drop-down > vn-vertical > vn-auto > ul > li:nth-child(2)`,
expenceSelect: `${components.vnAutocomplete}[field="$ctrl.item.expenceFk"] > vn-vertical > ${components.vnTextfield}`,
expenceSelectOptionOne: `${components.vnAutocomplete}[field="$ctrl.item.expenceFk"] > vn-vertical > vn-drop-down > vn-vertical > vn-auto > ul > li:nth-child(2)`,
typeSelect: `${components.vnAutocomplete}[field="$ctrl.item.typeFk"] input`,
typeSelectOptionOne: `${components.vnAutocomplete}[field="$ctrl.item.typeFk"] vn-drop-down ul > li:nth-child(2)`,
intrastatSelect: `${components.vnAutocomplete}[field="$ctrl.item.intrastatFk"] input`,
intrastatSelectOptionOne: `${components.vnAutocomplete}[field="$ctrl.item.intrastatFk"] vn-drop-down ul > li:nth-child(2)`,
originSelect: `${components.vnAutocomplete}[field="$ctrl.item.originFk"] input`,
originSelectOptionOne: `${components.vnAutocomplete}[field="$ctrl.item.originFk"] vn-drop-down ul > li:nth-child(2)`,
expenceSelect: `${components.vnAutocomplete}[field="$ctrl.item.expenceFk"] input`,
expenceSelectOptionOne: `${components.vnAutocomplete}[field="$ctrl.item.expenceFk"] vn-drop-down ul > li:nth-child(2)`,
createButton: `${components.vnSubmit}`
},
itemBasicData: {
goToItemIndexButton: 'vn-item-descriptor [ui-sref="item.index"]',
basicDataButton: `${components.vnMenuItem}[ui-sref="item.card.data"]`,
typeSelect: `${components.vnAutocomplete}[field="$ctrl.item.typeFk"] > vn-vertical > ${components.vnTextfield}`,
typeSelectOptionTwo: `${components.vnAutocomplete}[field="$ctrl.item.typeFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(2)`,
intrastatSelect: `${components.vnAutocomplete}[field="$ctrl.item.intrastatFk"] > vn-vertical > ${components.vnTextfield}`,
intrastatSelectOptionOne: `${components.vnAutocomplete}[field="$ctrl.item.intrastatFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(1)`,
typeSelect: `${components.vnAutocomplete}[field="$ctrl.item.typeFk"] input`,
typeSelectOptionTwo: `${components.vnAutocomplete}[field="$ctrl.item.typeFk"] vn-drop-down ul > li:nth-child(2)`,
intrastatSelect: `${components.vnAutocomplete}[field="$ctrl.item.intrastatFk"] input`,
intrastatSelectOptionOne: `${components.vnAutocomplete}[field="$ctrl.item.intrastatFk"] vn-drop-down ul > li:nth-child(1)`,
nameInput: `vn-horizontal:nth-child(2) > ${components.vnTextfield}`,
relevancyInput: `vn-horizontal:nth-child(3) > ${components.vnTextfield}`,
originSelect: `${components.vnAutocomplete}[field="$ctrl.item.originFk"] > vn-vertical > ${components.vnTextfield}`,
originSelectOptionTwo: `${components.vnAutocomplete}[field="$ctrl.item.originFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(2)`,
expenceSelect: `${components.vnAutocomplete}[field="$ctrl.item.expenceFk"] > vn-vertical > ${components.vnTextfield}`,
expenceSelectOptionTwo: `${components.vnAutocomplete}[field="$ctrl.item.expenceFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(2)`,
originSelect: `${components.vnAutocomplete}[field="$ctrl.item.originFk"] input`,
originSelectOptionTwo: `${components.vnAutocomplete}[field="$ctrl.item.originFk"] vn-drop-down ul > li:nth-child(2)`,
expenceSelect: `${components.vnAutocomplete}[field="$ctrl.item.expenceFk"] input`,
expenceSelectOptionTwo: `${components.vnAutocomplete}[field="$ctrl.item.expenceFk"] vn-drop-down ul > li:nth-child(2)`,
submitBasicDataButton: `${components.vnSubmit}`
},
itemTags: {
goToItemIndexButton: 'vn-item-descriptor [ui-sref="item.index"]',
tagsButton: `${components.vnMenuItem}[ui-sref="item.card.tags"]`,
firstTagSelect: `vn-item-tags vn-horizontal:nth-child(2) > ${components.vnAutocomplete}[field="itemTag.tagFk"] > vn-vertical > ${components.vnTextfield}`,
firstTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(2) > ${components.vnAutocomplete}[field="itemTag.tagFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(1)`,
firstTagSelect: `vn-item-tags vn-horizontal:nth-child(2) > ${components.vnAutocomplete}[field="itemTag.tagFk"] 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"] > vn-vertical > ${components.vnTextfield}`,
secondTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(3) > ${components.vnAutocomplete}[field="itemTag.tagFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(1)`,
secondTagSelect: `vn-item-tags vn-horizontal:nth-child(3) > ${components.vnAutocomplete}[field="itemTag.tagFk"] 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"] > vn-vertical > ${components.vnTextfield}`,
thirdTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(4) > ${components.vnAutocomplete}[field="itemTag.tagFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(1)`,
thirdTagSelect: `vn-item-tags vn-horizontal:nth-child(4) > ${components.vnAutocomplete}[field="itemTag.tagFk"] 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"] > vn-vertical > ${components.vnTextfield}`,
fourthTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(5) > ${components.vnAutocomplete}[field="itemTag.tagFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(1)`,
fourthTagSelect: `vn-item-tags vn-horizontal:nth-child(5) > ${components.vnAutocomplete}[field="itemTag.tagFk"] 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`,
fifthRemoveTagButton: `vn-item-tags vn-horizontal:nth-child(6) > ${components.vnIcon}[icon="remove_circle_outline"]`,
fifthTagSelect: `vn-item-tags vn-horizontal:nth-child(6) > ${components.vnAutocomplete}[field="itemTag.tagFk"] > vn-vertical > ${components.vnTextfield}`,
fifthTagSelectOptionFive: `vn-item-tags vn-horizontal:nth-child(6) > ${components.vnAutocomplete}[field="itemTag.tagFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(5)`,
fifthTagSelect: `vn-item-tags vn-horizontal:nth-child(6) > ${components.vnAutocomplete}[field="itemTag.tagFk"] 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`,
addItemTagButton: `${components.vnIcon}[icon="add_circle"]`,
@ -214,12 +214,12 @@ export default {
},
itemTax: {
taxButton: `${components.vnMenuItem}[ui-sref="item.card.tax"]`,
firstClassSelect: `vn-horizontal:nth-child(2) > ${components.vnAutocomplete}[field="tax.taxClassFk"] > vn-vertical > ${components.vnTextfield}`,
firstClassSelectOptionTwo: `vn-horizontal:nth-child(2) > ${components.vnAutocomplete} > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(2)`,
secondClassSelect: `vn-horizontal:nth-child(3) > ${components.vnAutocomplete}[field="tax.taxClassFk"] > vn-vertical > ${components.vnTextfield}`,
secondClassSelectOptionOne: `vn-horizontal:nth-child(3) > ${components.vnAutocomplete} > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(1)`,
thirdClassSelect: `vn-horizontal:nth-child(4) > ${components.vnAutocomplete}[field="tax.taxClassFk"] > vn-vertical > ${components.vnTextfield}`,
thirdClassSelectOptionTwo: `vn-horizontal:nth-child(4) > ${components.vnAutocomplete} > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(2)`,
firstClassSelect: `vn-horizontal:nth-child(2) > ${components.vnAutocomplete}[field="tax.taxClassFk"] input`,
firstClassSelectOptionTwo: `vn-horizontal:nth-child(2) > ${components.vnAutocomplete} vn-drop-down ul > li:nth-child(2)`,
secondClassSelect: `vn-horizontal:nth-child(3) > ${components.vnAutocomplete}[field="tax.taxClassFk"] input`,
secondClassSelectOptionOne: `vn-horizontal:nth-child(3) > ${components.vnAutocomplete} vn-drop-down ul > li:nth-child(1)`,
thirdClassSelect: `vn-horizontal:nth-child(4) > ${components.vnAutocomplete}[field="tax.taxClassFk"] input`,
thirdClassSelectOptionTwo: `vn-horizontal:nth-child(4) > ${components.vnAutocomplete} vn-drop-down ul > li:nth-child(2)`,
submitTaxButton: `${components.vnSubmit}`
},
itemBarcodes: {
@ -232,11 +232,11 @@ export default {
itemNiches: {
nicheButton: `${components.vnMenuItem}[ui-sref="item.card.niche"]`,
addNicheButton: `${components.vnIcon}[icon="add_circle"]`,
firstWarehouseSelect: `${components.vnAutocomplete}[field="itemNiche.warehouseFk"] > vn-vertical > ${components.vnTextfield}`,
firstWarehouseSelectSecondOption: `${components.vnAutocomplete}[field="itemNiche.warehouseFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(2)`,
secondWarehouseSelect: `vn-horizontal:nth-child(3) > ${components.vnAutocomplete}[field="itemNiche.warehouseFk"] > vn-vertical > ${components.vnTextfield}`,
thirdWarehouseSelect: `vn-horizontal:nth-child(4) > ${components.vnAutocomplete}[field="itemNiche.warehouseFk"] > vn-vertical > ${components.vnTextfield}`,
thirdWarehouseSelectFourthOption: `vn-horizontal:nth-child(4) > ${components.vnAutocomplete}[field="itemNiche.warehouseFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(4)`,
firstWarehouseSelect: `${components.vnAutocomplete}[field="itemNiche.warehouseFk"] input`,
firstWarehouseSelectSecondOption: `${components.vnAutocomplete}[field="itemNiche.warehouseFk"] vn-drop-down ul > li:nth-child(2)`,
secondWarehouseSelect: `vn-horizontal:nth-child(3) > ${components.vnAutocomplete}[field="itemNiche.warehouseFk"] input`,
thirdWarehouseSelect: `vn-horizontal:nth-child(4) > ${components.vnAutocomplete}[field="itemNiche.warehouseFk"] input`,
thirdWarehouseSelectFourthOption: `vn-horizontal:nth-child(4) > ${components.vnAutocomplete}[field="itemNiche.warehouseFk"] vn-drop-down ul > li:nth-child(4)`,
secondNicheRemoveButton: `vn-horizontal:nth-child(3) > vn-one > ${components.vnIcon}[icon="remove_circle_outline"]`,
firstCodeInput: `vn-horizontal:nth-child(2) > ${components.vnTextfield}`,
secondCodeInput: `vn-horizontal:nth-child(3) > ${components.vnTextfield}`,
@ -246,19 +246,20 @@ export default {
itemBotanical: {
botanicalButton: `${components.vnMenuItem}[ui-sref="item.card.botanical"]`,
botanicalInput: `vn-horizontal:nth-child(2) > ${components.vnTextfield}`,
genusSelect: `${components.vnAutocomplete}[field="$ctrl.botanical.genusFk"] > vn-vertical > ${components.vnTextfield}`,
genusSelectOptionOne: `${components.vnAutocomplete}[field="$ctrl.botanical.genusFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(1)`,
genusSelectOptionTwo: `${components.vnAutocomplete}[field="$ctrl.botanical.genusFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(2)`,
speciesSelect: `${components.vnAutocomplete}[field="$ctrl.botanical.specieFk"] > vn-vertical > ${components.vnTextfield}`,
speciesSelectOptionOne: `${components.vnAutocomplete}[field="$ctrl.botanical.specieFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(1)`,
speciesSelectOptionTwo: `${components.vnAutocomplete}[field="$ctrl.botanical.specieFk"] > vn-vertical > vn-drop-down > vn-vertical:not(.ng-hide) > vn-auto:nth-child(2) > ul > li:nth-child(2)`,
genusSelect: `${components.vnAutocomplete}[field="$ctrl.botanical.genusFk"] input`,
genusSelectOptionOne: `${components.vnAutocomplete}[field="$ctrl.botanical.genusFk"] vn-drop-down ul > li:nth-child(1)`,
genusSelectOptionTwo: `${components.vnAutocomplete}[field="$ctrl.botanical.genusFk"] vn-drop-down ul > li:nth-child(2)`,
speciesSelect: `${components.vnAutocomplete}[field="$ctrl.botanical.specieFk"] input`,
speciesSelectOptionOne: `${components.vnAutocomplete}[field="$ctrl.botanical.specieFk"] vn-drop-down ul > li:nth-child(1)`,
speciesSelectOptionTwo: `${components.vnAutocomplete}[field="$ctrl.botanical.specieFk"] vn-drop-down ul > li:nth-child(2)`,
submitBotanicalButton: `${components.vnSubmit}`
},
itemSummary: {
basicData: `${components.vnItemSummary} > vn-horizontal:nth-child(1) > vn-one:nth-child(2) > vn-vertical > p:nth-child(2)`,
tags: `${components.vnItemSummary} > vn-horizontal:nth-child(1) > vn-one:nth-child(3) > vn-vertical > p`,
niche: `${components.vnItemSummary} > vn-horizontal:nth-child(2) > vn-one:nth-child(1) > vn-vertical > p:nth-child(2)`,
botanical: `${components.vnItemSummary} > vn-horizontal:nth-child(2) > vn-one:nth-child(2) > vn-vertical > p`,
barcode: `${components.vnItemSummary} > vn-horizontal:nth-child(2) > vn-one:nth-child(3) > vn-vertical > p`
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) > p`,
niche: `${components.vnItemSummary} > vn-horizontal:nth-child(2) > vn-one:nth-child(2) > vn-vertical > p:nth-child(2)`,
botanical: `${components.vnItemSummary} > vn-horizontal:nth-child(2) > vn-one:nth-child(3) > vn-vertical > p`,
barcode: `${components.vnItemSummary} > vn-horizontal:nth-child(2) > vn-one:nth-child(4) > vn-vertical > p`
}
};

View File

@ -122,7 +122,7 @@ describe('Add address path', () => {
.waitToClick(selectors.clientAddresses.saveButton)
.waitForSnackbar()
.then(result => {
expect(result).toContain('Some fields are invalid');
expect(result).toContain('Error:');
});
});
});

View File

@ -3,18 +3,16 @@ const routes = require('../routes');
const restoreFixtures = require('../../../../../services/db/testing_fixtures');
describe('Auth routes', () => {
let fixturesToApply = {tables: ['`salix`.`user`'], inserts: [
`INSERT INTO salix.user(id,username,password,email)
VALUES
(10, 'JessicaJones', 'ac754a330530832ba1bf7687f577da91', 'JessicaJones@verdnatura.es');`
]};
let sqlStatements = {deletes: `
DELETE FROM salix.user WHERE id = 102;
`, inserts: ``, updates: ``};
beforeEach(done => {
restoreFixtures(fixturesToApply, done);
beforeEach(() => {
restoreFixtures(sqlStatements);
});
afterAll(done => {
restoreFixtures(fixturesToApply, done);
afterAll(() => {
restoreFixtures(sqlStatements);
});
let User = app.models.User;
@ -33,6 +31,20 @@ describe('Auth routes', () => {
req = {body: {}};
});
describe('when the user doesnt exist but the client does and the password is correct', () => {
it('should create the user login and return the token', done => {
spyOn(User, 'upsertWithWhere').and.callThrough();
req.body.user = 'PetterParker';
req.body.password = 'nightmare';
res.json = response => {
expect(User.upsertWithWhere).toHaveBeenCalledWith(jasmine.any(Object), jasmine.any(Object), jasmine.any(Function));
expect(response.token).toBeDefined();
done();
};
loginFunction(req, res);
});
});
describe('when the user exists and the password is correct', () => {
it('should login and return the token', done => {
req.body.user = 'developer';
@ -44,20 +56,6 @@ describe('Auth routes', () => {
loginFunction(req, res);
});
describe('when the user doesnt exist but the client does and the password is correct', () => {
it('should create the user login and return the token', done => {
spyOn(User, 'upsertWithWhere').and.callThrough();
req.body.user = 'PetterParker';
req.body.password = 'nightmare';
res.json = response => {
expect(User.upsertWithWhere).toHaveBeenCalledWith(jasmine.any(Object), jasmine.any(Object), jasmine.any(Function));
expect(response.token).toBeDefined();
done();
};
loginFunction(req, res);
});
});
it('should define the url to continue upon login', done => {
req.body.user = 'developer';
req.body.password = 'nightmare';

View File

@ -152,25 +152,26 @@ INSERT INTO `vn`.`address`(`id`, `nickname`, `street`, `city`, `postalCode`, `pr
(107, '07', 'Somewhere in Valencia', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(108, '08', 'Somewhere in Silla', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(109, '09', 'Somewhere in London', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(110, '10', 'Somewhere in Algemesi', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(111, '11', 'Somewhere in Carlet', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(112, '12', 'Somewhere in Campanar', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(113, '13', 'Somewhere in Malilla', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(114, '14', 'Somewhere in France', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(115, '15', 'Somewhere in Birmingham', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(116, '16', 'Somewhere in Scotland', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(117, '17', 'Somewhere in nowhere', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(118, '18', 'Somewhere over the rainbow', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(119, '19', 'Somewhere in Alberic', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(120, '20', 'Somewhere in Montortal', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(121, 'my other address', 'NY roofs', 'Silla', 46460, 1, NULL, NULL, 1, 0, 102, 2, NULL, NULL, 0),
(122, 'my other address', 'The phone box', 'Silla', 46460, 1, NULL, NULL, 1, 0, 103, 2, NULL, NULL, 0),
(123, 'my other address', 'Stark tower', 'Silla', 46460, 1, NULL, NULL, 1, 0, 104, 2, NULL, NULL, 0),
(124, 'my other address', 'The plastic cell', 'Silla', 46460, 1, NULL, NULL, 1, 0, 105, 2, NULL, NULL, 0),
(125, 'my other address', 'Many places', 'Silla', 46460, 1, NULL, NULL, 1, 0, 106, 2, NULL, NULL, 0),
(126, 'my other address', 'Your pocket', 'Silla', 46460, 1, NULL, NULL, 1, 0, 107, 2, NULL, NULL, 0),
(127, 'my other address', 'Cerebro', 'Silla', 46460, 1, NULL, NULL, 1, 0, 108, 2, NULL, NULL, 0),
(128, 'my other address', 'Luke Cages Bar', 'Silla', 46460, 1, NULL, NULL, 1, 0, 110, 2, NULL, NULL, 0);
(110, '10', 'Somewhere in Algemesi', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(111, '11', 'Somewhere in Carlet', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(112, '12', 'Somewhere in Campanar', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(113, '13', 'Somewhere in Malilla', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(114, '14', 'Somewhere in France', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(115, '15', 'Somewhere in Birmingham', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(116, '16', 'Somewhere in Scotland', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(117, '17', 'Somewhere in nowhere', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(118, '18', 'Somewhere over the rainbow', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(119, '19', 'Somewhere in Alberic', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(120, '20', 'Somewhere in Montortal', 'Silla', 46460, 1, NULL, NULL, 1, 0, 109, 2, NULL, NULL, 0),
(121, 'my other address', 'the bat cave', 'Silla', 46460, 1, NULL, NULL, 1, 0, 101, 2, NULL, NULL, 0),
(122, 'my other address', 'NY roofs', 'Silla', 46460, 1, NULL, NULL, 1, 0, 102, 2, NULL, NULL, 0),
(123, 'my other address', 'The phone box', 'Silla', 46460, 1, NULL, NULL, 1, 0, 103, 2, NULL, NULL, 0),
(124, 'my other address', 'Stark tower', 'Silla', 46460, 1, NULL, NULL, 1, 0, 104, 2, NULL, NULL, 0),
(125, 'my other address', 'The plastic cell', 'Silla', 46460, 1, NULL, NULL, 1, 0, 105, 2, NULL, NULL, 0),
(126, 'my other address', 'Many places', 'Silla', 46460, 1, NULL, NULL, 1, 0, 106, 2, NULL, NULL, 0),
(127, 'my other address', 'Your pocket', 'Silla', 46460, 1, NULL, NULL, 1, 0, 107, 2, NULL, NULL, 0),
(128, 'my other address', 'Cerebro', 'Silla', 46460, 1, NULL, NULL, 1, 0, 108, 2, NULL, NULL, 0),
(129, 'my other address', 'Luke Cages Bar', 'Silla', 46460, 1, NULL, NULL, 1, 0, 110, 2, NULL, NULL, 0);
INSERT INTO `vn`.`clientCredit`(`id`, `clientFk`, `workerFk`, `amount`, `created`)
VALUES

View File

@ -16,26 +16,23 @@ let errorHandler = callback => {
};
};
let insertFixtures = (inserts, callback) => {
connection.query(inserts[0], errorHandler(callback));
// connection.query('SET FOREIGN_KEY_CHECKS = 1');
};
let truncate = (tables, callback) => {
let truncatesSQL = tables.reduce((accumulator, currentValue, i) => {
let sql = 'TRUNCATE TABLE ' + currentValue + '; ';
return (`${accumulator}${sql}`);
}, '');
connection.query(truncatesSQL.slice(0, -2), errorHandler(callback));
let insertFixtures = async function(sqlStatements) {
try {
if (sqlStatements.deletes.length)
await connection.query(sqlStatements.deletes);
if (sqlStatements.inserts.length)
await connection.query(sqlStatements.inserts);
if (sqlStatements.updates.length)
await connection.query(sqlStatements.updates);
} catch (error) {
errorHandler(error);
}
};
connection.connect();
module.exports = function restoreFixtures(fixturesToApply, callback) {
module.exports = function restoreFixtures(sqlStatements) {
connection.query('SET FOREIGN_KEY_CHECKS = 0', () => {
truncate(fixturesToApply.tables, () => {
insertFixtures(fixturesToApply.inserts, callback);
});
insertFixtures(sqlStatements);
});
};

View File

@ -0,0 +1,50 @@
module.exports = Self => {
Self.remoteMethod('isValidClient', {
description: 'Checks if the user havent got the role employee, is active and has verified data',
accessType: 'READ',
accepts: [
{
arg: 'id',
type: 'string',
required: true,
description: 'The user id',
http: {source: 'path'}
}, {
arg: 'context',
type: 'object',
required: true,
description: 'Filter defining where',
http: function(context) {
return context.req.query;
}
}
],
returns: {
type: 'boolean',
root: true
},
http: {
path: `/:id/isValidClient`,
verb: 'GET'
}
});
Self.isValidClient = async function(id) {
let query =
`SELECT r.name
FROM salix.Account A
JOIN vn.client C ON A.id = C.id
JOIN salix.RoleMapping rm ON rm.principalId = A.id
JOIN salix.Role r ON r.id = rm.roleId
WHERE A.id = ? AND C.isActive AND C.isTaxDataChecked`;
let roleNames = await Self.rawSql(query, [id]);
if (!roleNames.length) return false;
roleNames.forEach(role => {
if (role.name === 'employee')
return false;
});
return true;
};
};

View File

@ -3,58 +3,19 @@ const catchErrors = require('../../../../../../services/utils/jasmineHelpers').c
const restoreFixtures = require('../../../../../../services/db/testing_fixtures');
describe('Client addressesPropagateRe', () => {
let fixturesToApply = {tables: ['`account`.`user`', '`vn2008`.`Clientes`', '`vn2008`.`Consignatarios`'], inserts: [
`INSERT INTO account.user(id,name,password,role,active,email)
VALUES
(1, 'BruceWayne', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'BruceWayne@verdnatura.es'),
(2, 'PetterParker', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'PetterParker@verdnatura.es'),
(3, 'ClarkKent', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'ClarkKent@verdnatura.es'),
(4, 'TonyStark', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'TonyStark@verdnatura.es'),
(5, 'MaxEisenhardt', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'MaxEisenhardt@verdnatura.es'),
(6, 'DavidCharlesHaller', 'ac754a330530832ba1bf7687f577da91', 18, 1, 'DavidCharlesHaller@verdnatura.es'),
(7, 'HankPym', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'HankPym@verdnatura.es'),
(8, 'CharlesXavier', 'ac754a330530832ba1bf7687f577da91', 18, 1, 'CharlesXavier@verdnatura.es'),
(9, 'BruceBanner', 'ac754a330530832ba1bf7687f577da91', 18, 1, 'BruceBanner@verdnatura.es'),
(10, 'JessicaJones', 'ac754a330530832ba1bf7687f577da91', 9, 1, 'JessicaJones@verdnatura.es'),
(11, 'Cyborg', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'cyborg@verdnatura.es');
INSERT INTO salix.Address(id, consignee, street, city, postcode, provinceFk, phone, mobile, isEnabled, isDefaultAddress, clientFk, defaultAgencyFk, longitude, latitude, isEqualizated)
VALUES
(1, 'Bruce Wayne', 'The Bat cave', 'Silla', 46460, 1, NULL, NULL, 1, 1, 1, 2, NULL, NULL, 0),
(2, 'Petter Parker', 'NY roofs', 'Silla', 46460, 1, NULL, NULL, 1, 1, 2, 2, NULL, NULL, 0),
(3, 'Clark Kenn', 'The phone box', 'Silla', 46460, 1, NULL, NULL, 1, 1, 3, 2, NULL, NULL, 0),
(4, 'Tony Stark', 'Stark tower', 'Silla', 46460, 1, NULL, NULL, 1, 1, 4, 2, NULL, NULL, 0),
(5, 'Max Eisenhardt', 'The plastic cell', 'Silla', 46460, 1, NULL, NULL, 1, 1, 5, 2, NULL, NULL, 0),
(6, 'David Charles Haller', 'Many places', 'Silla', 46460, 1, NULL, NULL, 1, 1, 6, 2, NULL, NULL, 0),
(7, 'Hank Pym', 'Your pocket', 'Silla', 46460, 1, NULL, NULL, 1, 1, 7, 2, NULL, NULL, 0),
(8, 'Charles Xavier', 'Cerebro', 'Silla', 46460, 1, NULL, NULL, 1, 1, 8, 2, NULL, NULL, 0),
(9, 'Bruce Banner', 'Somewhere in Thailand', 'Silla', 46460, 1, NULL, NULL, 1, 1, 9, 2, NULL, NULL, 0),
(10,'Jessica Jones', 'Luke Cages Bar', 'Silla', 46460, 1, NULL, NULL, 1, 1, 10, 2, NULL, NULL, 0);
INSERT INTO vn.client(id,name,fi,socialName,contact,street,city,postcode,phone,mobile,fax,isRelevant,email,iban,dueDay,accountingAccount,isEqualizated,provinceFk,hasToInvoice,credit,countryFk,isActive,gestdocFk,quality,payMethodFk,created,isToBeMailed,contactChannelFk,hasSepaVnl,hasCoreVnl,hasCoreVnh,riskCalculated,clientTypeFk,mailAddress,cplusTerIdNifFk,hasToInvoiceByAddress,isTaxDataChecked,isFreezed,creditInsurance,isCreatedAsServed,hasInvoiceSimplified,salesPersonFk,isVies,eypbc)
VALUES
(1, 'Bruce Wayne', '74451390E', 'Batman', 'Alfred', '1007 Mountain Drive, Gotham', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'BruceWayne@verdnatura.es', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1,'0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 1, 0, 1),
(2, 'Petter Parker', '87945234L', 'Spider-Man', 'Aunt May', '20 Ingram Street', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'PetterParker@verdnatura.es', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1,'0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 1, 0, 1),
(3, 'Clark Kent', '06815934E', 'Super-Man', 'lois lane', '344 Clinton Street', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'ClarkKent@verdnatura.es', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1,'0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 1, 0, 1),
(4, 'Tony Stark', '06089160W', 'Iron-Man', 'Pepper Potts', '10880 Malibu Point', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'TonyStark@verdnatura.es', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1,'0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 1, 0, 1),
(5, 'Max Eisenhardt', '39182496H', 'Magneto', 'Rogue', 'Unknown Whereabouts', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'MaxEisenhardt@verdnatura.es', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1,'0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 3, 0, 1),
(6, 'DavidCharlesHaller', '53136686Q', 'Legion', 'Charles Xavier', 'Evil hideout', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'DavidCharlesHaller@verdnatura.es', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1,'0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 3, 0, 1),
(7, 'Hank Pym', '09854837G', 'Ant-Man', 'Hawk', 'Anthill', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'HankPym@verdnatura.es', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1,'0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 3, 0, 1),
(8, 'Charles Xavier', '22641921P', 'Professor X', 'Beast', '3800 Victory Pkwy, Cincinnati, OH 45207, USA', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'CharlesXavier@verdnatura.es', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1,'0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 4, 0, 1),
(9, 'Bruce Banner', '16104829E', 'Hulk', 'Black widow', 'Somewhere in New York', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'BruceBanner@verdnatura.es', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1,'0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 4, 0, 1),
(10, 'Jessica Jones', '58282869H', 'Jessica Jones', 'Luke Cage', 'NYCC 2015 Poster', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'JessicaJones@verdnatura.es', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1,'0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 4, 0, 1);`
]};
beforeEach(done => {
restoreFixtures(fixturesToApply, done);
let sqlStatements = {deletes: ``, inserts: ``, updates:
`UPDATE vn.address SET isEqualizated = 0 WHERE clientFk = 101;`
};
beforeEach(() => {
restoreFixtures(sqlStatements);
});
afterAll(done => {
restoreFixtures(fixturesToApply, done);
afterAll(() => {
restoreFixtures(sqlStatements);
});
it('should propagate the isEqualizated on both addresses of Mr Wayne', done => {
let id = 1;
let id = 101;
let data = {
isEqualizated: true
};

View File

@ -3,13 +3,13 @@ const catchErrors = require('../../../../../../services/utils/jasmineHelpers').c
describe('Client card', () => {
it('should call the card() method to receive a formated card of Bruce Wayne', done => {
let id = 1;
let id = 101;
let callback = (error, result) => {
if (error) return catchErrors(done)(error);
expect(result).toEqual(jasmine.objectContaining({
id: 1,
id: 101,
name: 'Bruce Wayne'
}));
done();

View File

@ -3,58 +3,18 @@ const catchErrors = require('../../../../../../services/utils/jasmineHelpers').c
const restoreFixtures = require('../../../../../../services/db/testing_fixtures');
describe('Client Create', () => {
let fixturesToApply = {tables: ['`account`.`user`', '`vn2008`.`Clientes`', '`vn2008`.`Consignatarios`'], inserts: [
`INSERT INTO account.user(id,name,password,role,active,email)
VALUES
(1, 'BruceWayne', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'BruceWayne@verdnatura.es'),
(2, 'PetterParker', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'PetterParker@verdnatura.es'),
(3, 'ClarkKent', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'ClarkKent@verdnatura.es'),
(4, 'TonyStark', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'TonyStark@verdnatura.es'),
(5, 'MaxEisenhardt', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'MaxEisenhardt@verdnatura.es'),
(6, 'DavidCharlesHaller', 'ac754a330530832ba1bf7687f577da91', 18, 1, 'DavidCharlesHaller@verdnatura.es'),
(7, 'HankPym', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'HankPym@verdnatura.es'),
(8, 'CharlesXavier', 'ac754a330530832ba1bf7687f577da91', 18, 1, 'CharlesXavier@verdnatura.es'),
(9, 'BruceBanner', 'ac754a330530832ba1bf7687f577da91', 18, 1, 'BruceBanner@verdnatura.es'),
(10, 'JessicaJones', 'ac754a330530832ba1bf7687f577da91', 9, 1, 'JessicaJones@verdnatura.es'),
(11, 'Cyborg', 'ac754a330530832ba1bf7687f577da91', 1, 1, 'cyborg@verdnatura.es');
INSERT INTO account.user(name, password, role, active, email)
SELECT name, MD5('nightmare'), id, 1, CONCAT(name, '@verdnatura.es')
FROM account.role;
let sqlStatements = {deletes: `
DELETE FROM vn.address WHERE nickname = "Wade";
DELETE FROM vn.client WHERE name = "Wade";
DELETE FROM account.user WHERE name = "Deadpool";
`, inserts: ``, updates: ``};
INSERT INTO salix.Address(id, consignee, street, city, postcode, provinceFk, phone, mobile, isEnabled, isDefaultAddress, clientFk, defaultAgencyFk, longitude, latitude, isEqualizated)
VALUES
(1, 'Bruce Wayne', 'The Bat cave', 'Silla', 46460, 1, NULL, NULL, 1, 1, 1, 2, NULL, NULL, 0),
(2, 'Petter Parker', 'NY roofs', 'Silla', 46460, 1, NULL, NULL, 1, 1, 2, 2, NULL, NULL, 0),
(3, 'Clark Kenn', 'The phone box', 'Silla', 46460, 1, NULL, NULL, 1, 1, 3, 2, NULL, NULL, 0),
(4, 'Tony Stark', 'Stark tower', 'Silla', 46460, 1, NULL, NULL, 1, 1, 4, 2, NULL, NULL, 0),
(5, 'Max Eisenhardt', 'The plastic cell', 'Silla', 46460, 1, NULL, NULL, 1, 1, 5, 2, NULL, NULL, 0),
(6, 'David Charles Haller', 'Many places', 'Silla', 46460, 1, NULL, NULL, 1, 1, 6, 2, NULL, NULL, 0),
(7, 'Hank Pym', 'Your pocket', 'Silla', 46460, 1, NULL, NULL, 1, 1, 7, 2, NULL, NULL, 0),
(8, 'Charles Xavier', 'Cerebro', 'Silla', 46460, 1, NULL, NULL, 1, 1, 8, 2, NULL, NULL, 0),
(9, 'Bruce Banner', 'Somewhere in Thailand', 'Silla', 46460, 1, NULL, NULL, 1, 1, 9, 2, NULL, NULL, 0),
(10,'Jessica Jones', 'Luke Cages Bar', 'Silla', 46460, 1, NULL, NULL, 1, 1, 10, 2, NULL, NULL, 0);
INSERT INTO vn.client(id,name,fi,socialName,contact,street,city,postcode,phone,mobile,fax,isRelevant,email,iban,dueDay,accountingAccount,isEqualizated,provinceFk,hasToInvoice,credit,countryFk,isActive,gestdocFk,quality,payMethodFk,created,isToBeMailed,contactChannelFk,hasSepaVnl,hasCoreVnl,hasCoreVnh,riskCalculated,clientTypeFk,mailAddress,cplusTerIdNifFk,hasToInvoiceByAddress,isTaxDataChecked,isFreezed,creditInsurance,isCreatedAsServed,hasInvoiceSimplified,salesPersonFk,isVies,eypbc)
VALUES
(1, 'Bruce Wayne', '74451390E', 'Batman', 'Alfred', '1007 Mountain Drive, Gotham', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'BruceWayne@verdnatura.es', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1,'0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 1, 0, 1),
(2, 'Petter Parker', '87945234L', 'Spider-Man', 'Aunt May', '20 Ingram Street', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'PetterParker@verdnatura.es', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1,'0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 1, 0, 1),
(3, 'Clark Kent', '06815934E', 'Super-Man', 'lois lane', '344 Clinton Street', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'ClarkKent@verdnatura.es', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1,'0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 1, 0, 1),
(4, 'Tony Stark', '06089160W', 'Iron-Man', 'Pepper Potts', '10880 Malibu Point', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'TonyStark@verdnatura.es', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1,'0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 1, 0, 1),
(5, 'Max Eisenhardt', '39182496H', 'Magneto', 'Rogue', 'Unknown Whereabouts', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'MaxEisenhardt@verdnatura.es', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1,'0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 3, 0, 1),
(6, 'DavidCharlesHaller', '53136686Q', 'Legion', 'Charles Xavier', 'Evil hideout', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'DavidCharlesHaller@verdnatura.es', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1,'0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 3, 0, 1),
(7, 'Hank Pym', '09854837G', 'Ant-Man', 'Hawk', 'Anthill', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'HankPym@verdnatura.es', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1,'0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 3, 0, 1),
(8, 'Charles Xavier', '22641921P', 'Professor X', 'Beast', '3800 Victory Pkwy, Cincinnati, OH 45207, USA', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'CharlesXavier@verdnatura.es', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1,'0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 4, 0, 1),
(9, 'Bruce Banner', '16104829E', 'Hulk', 'Black widow', 'Somewhere in New York', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'BruceBanner@verdnatura.es', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1,'0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 4, 0, 1),
(10, 'Jessica Jones', '58282869H', 'Jessica Jones', 'Luke Cage', 'NYCC 2015 Poster', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'JessicaJones@verdnatura.es', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1,'0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 4, 0, 1);`
]};
beforeEach(done => {
restoreFixtures(fixturesToApply, done);
beforeAll(() => {
restoreFixtures(sqlStatements);
});
afterAll(done => {
restoreFixtures(fixturesToApply, done);
afterAll(() => {
restoreFixtures(sqlStatements);
});
let newAccountData = {

View File

@ -3,7 +3,7 @@ const catchErrors = require('../../../../../../services/utils/jasmineHelpers').c
describe('Client hasCustomerRole', () => {
it('should call the hasCustomerRole() method with a customer id', done => {
let id = 1;
let id = 101;
let params = {};
let callback = (error, result) => {

View File

@ -0,0 +1,57 @@
const app = require('../../../../../client/server/server');
describe('Client isValidClient', () => {
it('should call the isValidClient() method with a client id and receive true', done => {
let id = 101;
app.models.Client.isValidClient(id)
.then(result => {
expect(result).toBeTruthy();
done();
});
});
it('should call the isValidClient() method with a employee id and receive false', done => {
let id = 1;
app.models.Client.isValidClient(id)
.then(result => {
expect(result).toBeFalsy();
done();
});
});
it('should call the isValidClient() method with a unexistant id and receive false', done => {
let id = 999999;
app.models.Client.isValidClient(id)
.then(result => {
expect(result).toBeFalsy();
done();
});
});
it('should call the isValidClient() method with a invalid id and receive false', done => {
let id = 'Pepinillos';
app.models.Client.isValidClient(id)
.then(result => {
expect(result).toBeFalsy();
done();
});
});
it('should call the isValidClient() method with a customer id which isnt active and return false', done => {
let id = '106';
app.models.Client.isValidClient(id)
.then(result => {
expect(result).toBeFalsy();
done();
});
});
it('should call the isValidClient() method with a customer id which his data isnt verified and return false', done => {
let id = '110';
app.models.Client.isValidClient(id)
.then(result => {
expect(result).toBeFalsy();
done();
});
});
});

View File

@ -7,7 +7,7 @@ describe('Client listWorkers', () => {
.then(result => {
let amountOfEmployees = Object.keys(result).length;
expect(amountOfEmployees).toEqual(32);
expect(amountOfEmployees).toEqual(37);
done();
})
.catch(catchErrors(done));

View File

@ -12,6 +12,7 @@ module.exports = function(Self) {
require('../methods/client/listWorkers')(Self);
require('../methods/client/filter')(Self);
require('../methods/client/hasCustomerRole')(Self);
require('../methods/client/isValidClient')(Self);
require('../methods/client/activeSalesPerson')(Self);
require('../methods/client/addressesPropagateRe')(Self);