Tests fixed, bugs solved, vnCrudModel, vnRestModel, UserError
This commit is contained in:
parent
3833339cc6
commit
a78bb24e09
|
@ -19,38 +19,5 @@ describe('Client', () => {
|
|||
$state.params.addressId = '1';
|
||||
controller = $componentController('vnClientAddressEdit', {$state: $state});
|
||||
}));
|
||||
|
||||
it('should define and set address property', () => {
|
||||
expect(controller.address.id).toEqual(1);
|
||||
});
|
||||
|
||||
describe('_observationsEquals', () => {
|
||||
it('should return true if two observations are equals independent of control attributes', () => {
|
||||
let ob1 = {id: 1, observationTypeFk: 1, description: 'Spiderman rocks', showAddIcon: true};
|
||||
let ob2 = {id: 1, observationTypeFk: 1, description: 'Spiderman rocks', showAddIcon: false};
|
||||
let equals = controller.equalObservations(ob2, ob1);
|
||||
|
||||
expect(equals).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should return false if two observations are not equals independent of control attributes', () => {
|
||||
let ob1 = {id: 1, observationTypeFk: 1, description: 'Spiderman rocks', showAddIcon: true};
|
||||
let ob2 = {id: 1, observationTypeFk: 1, description: 'Spiderman sucks', showAddIcon: true};
|
||||
let equals = controller.equalObservations(ob2, ob1);
|
||||
|
||||
expect(equals).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('$onInit()', () => {
|
||||
it('should perform a GET query to receive the address observations', () => {
|
||||
let filter = {where: {addressFk: 1}, include: {relation: 'observationType'}};
|
||||
let res = ['some notes'];
|
||||
$httpBackend.whenGET(`/client/api/AddressObservations?filter=${JSON.stringify(filter)}`).respond(res);
|
||||
$httpBackend.expectGET(`/client/api/AddressObservations?filter=${JSON.stringify(filter)}`);
|
||||
controller.$onInit();
|
||||
$httpBackend.flush();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,16 +1,29 @@
|
|||
|
||||
<mg-ajax
|
||||
path="/client/api/Addresses/{{edit.params.addressId}}"
|
||||
actions="$ctrl.address = edit.model; $ctrl._setIconAdd();"
|
||||
actions="$ctrl.address = edit.model"
|
||||
options="mgEdit">
|
||||
</mg-ajax>
|
||||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="$ctrl.address"
|
||||
url="/client/api/Addresses"
|
||||
id-field="id"
|
||||
data="$ctrl.address"
|
||||
form="addressForm">
|
||||
form="form">
|
||||
</vn-watcher>
|
||||
<form name="addressForm" ng-submit="$ctrl.submit()">
|
||||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="/client/api/AddressObservations"
|
||||
fields="['id', 'addressFk', 'observationTypeFk', 'description']"
|
||||
link="{addressFk: $ctrl.$stateParams.addressId}"
|
||||
data="observations">
|
||||
</vn-crud-model>
|
||||
<vn-crud-model
|
||||
url="/client/api/ObservationTypes"
|
||||
fields="['id', 'description']"
|
||||
data="types">
|
||||
</vn-crud-model>
|
||||
<form name="form" ng-submit="$ctrl.submit()">
|
||||
<vn-card pad-large>
|
||||
<vn-title>Address</vn-title>
|
||||
<vn-horizontal>
|
||||
|
@ -49,32 +62,17 @@
|
|||
<vn-textfield vn-one label="Phone" field="$ctrl.address.phone"></vn-textfield>
|
||||
<vn-textfield vn-one label="Mobile" field="$ctrl.address.mobile"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-one margin-medium-top>
|
||||
</vn-card>
|
||||
</form>
|
||||
<vn-watcher form="notesForm"></vn-watcher>
|
||||
<form name="notesForm" ng-submit="$ctrl.submit()">
|
||||
<vn-card pad-large>
|
||||
<vn-title>Notes</vn-title>
|
||||
<mg-ajax path="/client/api/ObservationTypes" options="mgIndex as observationsTypes"></mg-ajax>
|
||||
<vn-horizontal ng-repeat="observation in $ctrl.observations track by $index">
|
||||
<vn-title>Notes</vn-title>
|
||||
<div name="observations">
|
||||
<vn-horizontal ng-repeat="observation in observations">
|
||||
<vn-autocomplete
|
||||
ng-if="!observation.id"
|
||||
vn-one
|
||||
vn-focus
|
||||
initial-data="observation.observationType"
|
||||
data="types"
|
||||
field="observation.observationTypeFk"
|
||||
data="observationsTypes.model"
|
||||
show-field="description"
|
||||
label="Observation type">
|
||||
</vn-autocomplete>
|
||||
<vn-textfield
|
||||
ng-if="observation.id"
|
||||
vn-one
|
||||
label="Observation type"
|
||||
model="observation.observationType.description"
|
||||
disabled="true">
|
||||
</vn-textfield>
|
||||
<vn-textfield
|
||||
vn-two
|
||||
margin-large-right
|
||||
|
@ -92,17 +90,15 @@
|
|||
</vn-icon>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
</vn-one>
|
||||
<vn-one>
|
||||
<vn-icon-button
|
||||
pointer
|
||||
vn-bind="+"
|
||||
vn-tooltip="Add note"
|
||||
icon="add_circle"
|
||||
ng-if="observationsTypes.model.length > $ctrl.observations.length"
|
||||
ng-click="$ctrl.addObservation()">
|
||||
</vn-icon-button>
|
||||
</vn-one>
|
||||
</div>
|
||||
<vn-icon-button
|
||||
pointer
|
||||
vn-bind="+"
|
||||
vn-tooltip="Add note"
|
||||
icon="add_circle"
|
||||
ng-if="types.length > observations.length"
|
||||
ng-click="model.insert()">
|
||||
</vn-icon-button>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit label="Save"></vn-submit>
|
||||
|
|
|
@ -1,151 +1,30 @@
|
|||
import ngModule from '../../module';
|
||||
|
||||
export default class Controller {
|
||||
constructor($state, $scope, $http, $q, $translate, vnApp) {
|
||||
constructor($scope, $state) {
|
||||
this.$ = $scope;
|
||||
this.$state = $state;
|
||||
this.$scope = $scope;
|
||||
this.$http = $http;
|
||||
this.$q = $q;
|
||||
this.$translate = $translate;
|
||||
this.vnApp = vnApp;
|
||||
|
||||
this.address = {
|
||||
id: parseInt($state.params.addressId)
|
||||
};
|
||||
this.observations = [];
|
||||
this.oldObservations = {};
|
||||
this.removedObservations = [];
|
||||
}
|
||||
|
||||
_setDirtyForm() {
|
||||
if (this.$scope.form) {
|
||||
this.$scope.form.$setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
_unsetDirtyForm() {
|
||||
if (this.$scope.form) {
|
||||
this.$scope.form.$setPristine();
|
||||
}
|
||||
}
|
||||
|
||||
addObservation() {
|
||||
this.observations.push({observationTypeFk: null, addressFk: this.address.id, description: null});
|
||||
this.$stateParams = $state.params;
|
||||
}
|
||||
|
||||
removeObservation(index) {
|
||||
let item = this.observations[index];
|
||||
if (item) {
|
||||
this.observations.splice(index, 1);
|
||||
if (item.id) {
|
||||
this.removedObservations.push(item.id);
|
||||
this._setDirtyForm();
|
||||
}
|
||||
}
|
||||
if (this.observations.length === 0 && Object.keys(this.oldObservations).length === 0) {
|
||||
this._unsetDirtyForm();
|
||||
}
|
||||
}
|
||||
|
||||
_submitObservations(observationsObject) {
|
||||
return this.$http.post(`/client/api/AddressObservations/crudAddressObservations`, observationsObject);
|
||||
}
|
||||
|
||||
equalObservations(oldObj, newObj) {
|
||||
return oldObj.id === newObj.id && oldObj.observationTypeFk === newObj.observationTypeFk && oldObj.description === newObj.description;
|
||||
this.$.watcher.setDirty();
|
||||
this.$.model.remove(index);
|
||||
}
|
||||
|
||||
submit() {
|
||||
if (this.$scope.addressForm.$invalid || this.$scope.notesForm.$invalid) {
|
||||
this.vnApp.showMessage(
|
||||
this.$translate.instant('Some fields are invalid')
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
let canSubmitWatcher = this.$scope.watcher.dataChanged();
|
||||
let canSubmitObservations;
|
||||
let repeatedTypes = false;
|
||||
let emptyFields = false;
|
||||
let types = [];
|
||||
let observationsObj = {
|
||||
delete: this.removedObservations,
|
||||
create: [],
|
||||
update: []
|
||||
};
|
||||
|
||||
this.observations.forEach(observation => {
|
||||
let isNewObservation = observation.id === undefined;
|
||||
|
||||
if (observation.observationTypeFk && types.indexOf(observation.observationTypeFk) !== -1) {
|
||||
repeatedTypes = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (observation.observationTypeFk === null || observation.description === null) {
|
||||
emptyFields = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (observation.observationTypeFk)
|
||||
types.push(observation.observationTypeFk);
|
||||
|
||||
if (isNewObservation && observation.observationTypeFk && observation.description) {
|
||||
observationsObj.create.push(observation);
|
||||
} else if (!isNewObservation && !this.equalObservations(this.oldObservations[observation.id], observation)) {
|
||||
observationsObj.update.push(observation);
|
||||
}
|
||||
});
|
||||
|
||||
canSubmitObservations = observationsObj.update.length > 0 || observationsObj.create.length > 0 || observationsObj.delete.length > 0;
|
||||
|
||||
if (repeatedTypes) {
|
||||
this.vnApp.showMessage(
|
||||
this.$translate.instant('The observation type must be unique')
|
||||
);
|
||||
} else if (emptyFields) {
|
||||
this.vnApp.showMessage(
|
||||
this.$translate.instant('No field can be blank')
|
||||
);
|
||||
} else if (canSubmitWatcher && !canSubmitObservations) {
|
||||
this.$scope.watcher.submit().then(() => {
|
||||
this.$state.go('client.card.address.index', {id: this.$state.params.id});
|
||||
this.$.watcher.check();
|
||||
this.$.watcher.realSubmit()
|
||||
.then(() => this.$.model.save(true))
|
||||
.then(() => {
|
||||
this.$.watcher.setPristine();
|
||||
this.$.watcher.notifySaved();
|
||||
this.card.reload();
|
||||
this.$state.go('client.card.address.index', {id: this.$stateParams.id});
|
||||
});
|
||||
} else if (!canSubmitWatcher && canSubmitObservations) {
|
||||
this._submitObservations(observationsObj).then(() => {
|
||||
this.$state.go('client.card.address.index', {id: this.$state.params.id});
|
||||
});
|
||||
} else if (canSubmitWatcher && canSubmitObservations) {
|
||||
this.$q.all([this.$scope.watcher.submit(), this._submitObservations(observationsObj)]).then(() => {
|
||||
this.$state.go('client.card.address.index', {id: this.$state.params.id});
|
||||
});
|
||||
} else {
|
||||
this.vnApp.showMessage(
|
||||
this.$translate.instant('No changes to save')
|
||||
);
|
||||
}
|
||||
this._unsetDirtyForm();
|
||||
}
|
||||
|
||||
_getAddressNotes() {
|
||||
let filter = {
|
||||
where: {addressFk: this.address.id},
|
||||
include: {relation: 'observationType'}
|
||||
};
|
||||
this.$http.get(`/client/api/AddressObservations?filter=${JSON.stringify(filter)}`).then(res => {
|
||||
this.observations = res.data;
|
||||
res.data.forEach(item => {
|
||||
this.oldObservations[item.id] = Object.assign({}, item);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
this._getAddressNotes();
|
||||
}
|
||||
}
|
||||
Controller.$inject = ['$state', '$scope', '$http', '$q', '$translate', 'vnApp'];
|
||||
Controller.$inject = ['$scope', '$state'];
|
||||
|
||||
ngModule.component('vnClientAddressEdit', {
|
||||
template: require('./index.html'),
|
||||
|
|
|
@ -62,6 +62,15 @@ export default class Autocomplete extends Input {
|
|||
this.refreshDisplayed();
|
||||
}
|
||||
|
||||
set data(value) {
|
||||
this._data = value;
|
||||
this.refreshSelection();
|
||||
}
|
||||
|
||||
get data() {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
selectionIsValid(selection) {
|
||||
return selection
|
||||
&& selection[this.valueField] == this._field
|
||||
|
@ -212,7 +221,7 @@ export default class Autocomplete extends Input {
|
|||
showDropDown(search) {
|
||||
Object.assign(this.$.dropDown.$.model, {
|
||||
url: this.url,
|
||||
staticData: this.data
|
||||
staticData: this._data
|
||||
});
|
||||
|
||||
asignProps(this, this.$.dropDown, [
|
||||
|
@ -220,9 +229,9 @@ export default class Autocomplete extends Input {
|
|||
'showField',
|
||||
'where',
|
||||
'order',
|
||||
'limit',
|
||||
'showFilter',
|
||||
'multiple',
|
||||
'limit',
|
||||
'$transclude'
|
||||
]);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<vn-model
|
||||
<vn-rest-model
|
||||
vn-id="model"
|
||||
on-data-change="$ctrl.onModelDataChange()">
|
||||
</vn-model>
|
||||
</vn-rest-model>
|
||||
<vn-popover
|
||||
vn-id="popover"
|
||||
on-open="$ctrl.onOpen()"
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import ngModule from '../../module';
|
||||
import Component from '../../lib/component';
|
||||
import './style.scss';
|
||||
import './model';
|
||||
|
||||
export default class DropDown extends Component {
|
||||
constructor($element, $scope, $transclude, $timeout, $http) {
|
||||
|
@ -366,14 +365,18 @@ ngModule.component('vnDropDown', {
|
|||
template: require('./drop-down.html'),
|
||||
controller: DropDown,
|
||||
bindings: {
|
||||
showField: '@?',
|
||||
valueField: '@?',
|
||||
where: '@?',
|
||||
order: '@?',
|
||||
limit: '<?',
|
||||
showFilter: '<?',
|
||||
multiple: '<?',
|
||||
field: '=?',
|
||||
data: '<?',
|
||||
selection: '=?',
|
||||
search: '<?',
|
||||
limit: '<?',
|
||||
showFilter: '<?',
|
||||
parent: '<?',
|
||||
multiple: '<?',
|
||||
onSelect: '&?'
|
||||
},
|
||||
transclude: {
|
||||
|
|
|
@ -32,7 +32,7 @@ describe('Component vnDropDown', () => {
|
|||
$scope.popover = $componentController('vnPopover', {$element: $popover, $scope, $timeout, $transitions});
|
||||
$scope.popover.$postLink();
|
||||
|
||||
$scope.model = $componentController('vnModel', {$httpBackend, $q, $filter});
|
||||
$scope.model = $componentController('vnRestModel', {$httpBackend, $q, $filter});
|
||||
controller = $componentController('vnDropDown', {$element, $scope, $transclude: null, $timeout, $httpBackend, $translate: null});
|
||||
controller.$postLink();
|
||||
controller.parent = angular.element('<vn-parent></vn-parent>')[0];
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import './textfield/textfield';
|
||||
import './model-proxy/model-proxy';
|
||||
import './rest-model/crud-model';
|
||||
import './rest-model/rest-model';
|
||||
import './watcher/watcher';
|
||||
import './textfield/textfield';
|
||||
import './paging/paging';
|
||||
import './icon/icon';
|
||||
import './dialog/dialog';
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
import ngModule from '../../module';
|
||||
|
||||
export default class ModelProxy {
|
||||
constructor() {
|
||||
this._data = [];
|
||||
this.resetChanges();
|
||||
}
|
||||
|
||||
get orgData() {
|
||||
return this._orgData;
|
||||
}
|
||||
|
||||
set orgData(value) {
|
||||
this._orgData = value;
|
||||
this._data = [];
|
||||
// this._data.splice(0, this._data.length);
|
||||
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
let row = new this.Row(value[i], i);
|
||||
this._data.push(row);
|
||||
}
|
||||
|
||||
this.resetChanges();
|
||||
}
|
||||
|
||||
get data() {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
set data(value) {}
|
||||
|
||||
get fields() {
|
||||
return this._fields;
|
||||
}
|
||||
|
||||
set fields(value) {
|
||||
this._fields = value;
|
||||
|
||||
let Row = function(data, index) {
|
||||
this.$data = data;
|
||||
this.$index = index;
|
||||
this.$oldData = null;
|
||||
this.$isNew = false;
|
||||
};
|
||||
|
||||
for (let prop of value) {
|
||||
Object.defineProperty(Row.prototype, prop, {
|
||||
enumerable: true,
|
||||
configurable: false,
|
||||
set: function(value) {
|
||||
if (!this.$isNew) {
|
||||
if (!this.$oldData)
|
||||
this.$oldData = {};
|
||||
if (!this.$oldData[prop])
|
||||
this.$oldData[prop] = this.$data[prop];
|
||||
}
|
||||
|
||||
this.$data[prop] = value;
|
||||
},
|
||||
get: function() {
|
||||
return this.$data[prop];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.Row = Row;
|
||||
}
|
||||
|
||||
remove(index) {
|
||||
let data = this._data;
|
||||
|
||||
let item;
|
||||
[item] = data.splice(index, 1);
|
||||
|
||||
for (let i = index; i < data.length; i++)
|
||||
data[i].$index = i;
|
||||
|
||||
if (!item.$isNew)
|
||||
this.removed.push(item);
|
||||
}
|
||||
|
||||
insert(data) {
|
||||
data = Object.assign(data || {}, this.link);
|
||||
let newRow = new this.Row(data, this._data.length);
|
||||
newRow.$isNew = true;
|
||||
return this._data.push(newRow);
|
||||
}
|
||||
|
||||
resetChanges() {
|
||||
this.removed = [];
|
||||
|
||||
for (let row of this._data) {
|
||||
row.$oldData = null;
|
||||
row.$isNew = false;
|
||||
}
|
||||
}
|
||||
|
||||
undoChanges() {
|
||||
let data = this._data;
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let row = data[i];
|
||||
|
||||
if (row.$oldData)
|
||||
Object.assign(row.$data, row.$oldData);
|
||||
if (row.$isNew)
|
||||
data.splice(i--, 1);
|
||||
}
|
||||
|
||||
for (let row of this.removed)
|
||||
data.splice(row.$index, 0, row);
|
||||
|
||||
this.resetChanges();
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.component('vnModelProxy', {
|
||||
controller: ModelProxy,
|
||||
bindings: {
|
||||
orgData: '<?',
|
||||
data: '=?',
|
||||
fields: '<?',
|
||||
link: '<?'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,103 @@
|
|||
import ngModule from '../../module';
|
||||
import ModelProxy from '../model-proxy/model-proxy';
|
||||
|
||||
export default class CrudModel extends ModelProxy {
|
||||
constructor($http, $q) {
|
||||
super();
|
||||
this.$http = $http;
|
||||
this.$q = $q;
|
||||
this.primaryKey = 'id';
|
||||
this.autoLoad = true;
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
if (this.autoLoad)
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
refresh() {
|
||||
if (!this.url) return;
|
||||
|
||||
let filter = this.filter;
|
||||
|
||||
if (!filter) {
|
||||
let where = Object.assign({}, this.link, this.where);
|
||||
filter = {
|
||||
fields: this.fields,
|
||||
where: where,
|
||||
include: this.include,
|
||||
order: this.order,
|
||||
limit: this.limit
|
||||
};
|
||||
}
|
||||
|
||||
let urlFilter = encodeURIComponent(JSON.stringify(filter));
|
||||
|
||||
return this.$http.get(`${this.url}?filter=${urlFilter}`).then(res => {
|
||||
this.orgData = res.data;
|
||||
});
|
||||
}
|
||||
|
||||
getChanges() {
|
||||
let create = [];
|
||||
let update = [];
|
||||
let remove = [];
|
||||
|
||||
for (let row of this.removed)
|
||||
remove.push(row.$data[this.primaryKey]);
|
||||
|
||||
for (let row of this._data) {
|
||||
if (row.$isNew)
|
||||
create.push(row.$data);
|
||||
else if (row.$oldData)
|
||||
update.push(row.$data);
|
||||
}
|
||||
|
||||
let isChanged =
|
||||
create.length > 0 ||
|
||||
update.length > 0 ||
|
||||
remove.length > 0;
|
||||
|
||||
if (!isChanged)
|
||||
return null;
|
||||
|
||||
let changes = {
|
||||
create: create,
|
||||
update: update,
|
||||
delete: remove
|
||||
};
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
save(ignoreChanges) {
|
||||
let changes = this.getChanges();
|
||||
|
||||
if (!changes)
|
||||
return this.$q.resolve();
|
||||
|
||||
let url = this.saveUrl ? this.saveUrl : `${this.url}/crud`;
|
||||
return this.$http.post(url, changes)
|
||||
.then(() => this.resetChanges);
|
||||
}
|
||||
}
|
||||
CrudModel.$inject = ['$http', '$q'];
|
||||
|
||||
ngModule.component('vnCrudModel', {
|
||||
controller: CrudModel,
|
||||
bindings: {
|
||||
orgData: '<?',
|
||||
data: '=?',
|
||||
fields: '<?',
|
||||
link: '<?',
|
||||
url: '@?',
|
||||
saveUrl: '@?',
|
||||
where: '<?',
|
||||
include: '<?',
|
||||
order: '@?',
|
||||
limit: '<?',
|
||||
filter: '<?',
|
||||
primaryKey: '@?',
|
||||
autoLoad: '<?'
|
||||
}
|
||||
});
|
|
@ -1,6 +1,6 @@
|
|||
import ngModule from '../../module';
|
||||
|
||||
export default class Model {
|
||||
export default class RestModel {
|
||||
constructor($http, $q, $filter) {
|
||||
this.$http = $http;
|
||||
this.$q = $q;
|
||||
|
@ -104,10 +104,10 @@ export default class Model {
|
|||
this.onDataChange();
|
||||
}
|
||||
}
|
||||
Model.$inject = ['$http', '$q', '$filter'];
|
||||
RestModel.$inject = ['$http', '$q', '$filter'];
|
||||
|
||||
ngModule.component('vnModel', {
|
||||
controller: Model,
|
||||
ngModule.component('vnRestModel', {
|
||||
controller: RestModel,
|
||||
bindings: {
|
||||
url: '@?',
|
||||
staticData: '<?',
|
|
@ -1,6 +1,6 @@
|
|||
import './model.js';
|
||||
import './rest-model.js';
|
||||
|
||||
describe('Component vnModel', () => {
|
||||
describe('Component vnRestModel', () => {
|
||||
let $componentController;
|
||||
let $httpBackend;
|
||||
let controller;
|
||||
|
@ -11,7 +11,7 @@ describe('Component vnModel', () => {
|
|||
|
||||
beforeEach(angular.mock.inject((_$componentController_, _$httpBackend_) => {
|
||||
$componentController = _$componentController_;
|
||||
controller = $componentController('vnModel', {$httpBackend});
|
||||
controller = $componentController('vnRestModel', {$httpBackend});
|
||||
}));
|
||||
|
||||
describe('set url', () => {
|
|
@ -4,6 +4,7 @@ import getModifiedData from '../../lib/modified';
|
|||
import copyObject from '../../lib/copy';
|
||||
import isEqual from '../../lib/equals';
|
||||
import isFullEmpty from '../../lib/full-empty';
|
||||
import UserError from '../../lib/user-error';
|
||||
|
||||
/**
|
||||
* Component that checks for changes on a specific model property and
|
||||
|
@ -14,10 +15,10 @@ import isFullEmpty from '../../lib/full-empty';
|
|||
export default class Watcher extends Component {
|
||||
constructor($element, $scope, $state, $transitions, $http, vnApp, $translate, $attrs, $q) {
|
||||
super($element);
|
||||
this.$scope = $scope;
|
||||
this.$ = $scope;
|
||||
this.$state = $state;
|
||||
this.$http = $http;
|
||||
this.$translate = $translate;
|
||||
this._ = $translate;
|
||||
this.$attrs = $attrs;
|
||||
this.vnApp = vnApp;
|
||||
this.$q = $q;
|
||||
|
@ -29,34 +30,38 @@ export default class Watcher extends Component {
|
|||
}
|
||||
|
||||
$onInit() {
|
||||
if (this.get && this.url) {
|
||||
if (this.get && this.url)
|
||||
this.fetchData();
|
||||
} else if (this.get && !this.url) {
|
||||
throw new Error('Error: Parameter url ommitted');
|
||||
}
|
||||
else if (this.get && !this.url)
|
||||
throw new Error('URL parameter ommitted');
|
||||
}
|
||||
|
||||
$onChanges(changes) {
|
||||
if (this.data) {
|
||||
if (this.data)
|
||||
this.updateOriginalData();
|
||||
}
|
||||
}
|
||||
|
||||
$onDestroy() {
|
||||
this.deregisterCallback();
|
||||
}
|
||||
|
||||
get dirty() {
|
||||
return this.form && this.form.$dirty || this.dataChanged();
|
||||
}
|
||||
|
||||
dataChanged() {
|
||||
let data = this.copyInNewObject(this.data);
|
||||
return !isEqual(data, this.orgData);
|
||||
}
|
||||
|
||||
fetchData() {
|
||||
let id = this.data[this.idField];
|
||||
// return new Promise((resolve, reject) => {
|
||||
this.$http.get(`${this.url}/${id}`).then(
|
||||
return this.$http.get(`${this.url}/${id}`).then(
|
||||
json => {
|
||||
this.data = copyObject(json.data);
|
||||
this.updateOriginalData();
|
||||
}
|
||||
// json => reject(json)
|
||||
);
|
||||
// });
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -91,45 +96,55 @@ export default class Watcher extends Component {
|
|||
* @return {Promise} The http request promise
|
||||
*/
|
||||
submit() {
|
||||
try {
|
||||
this.check();
|
||||
} catch (err) {
|
||||
return this.$q.reject(err);
|
||||
}
|
||||
|
||||
return this.realSubmit().then(res => {
|
||||
this.vnApp.showMessage(this.$translate.instant('Data saved!'));
|
||||
this.notifySaved();
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
errorHandler(err) {
|
||||
this.vnApp.showError(err.message);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the data without checking data validity or changes.
|
||||
*
|
||||
* @return {Promise} The http request promise
|
||||
*/
|
||||
realSubmit() {
|
||||
if (this.form) {
|
||||
if (this.form)
|
||||
this.form.$setSubmitted();
|
||||
|
||||
if (!this.form.$valid)
|
||||
return this.invalidForm();
|
||||
if (!this.dataChanged()) {
|
||||
this.updateOriginalData();
|
||||
return this.$q.resolve();
|
||||
}
|
||||
if (!this.dataChanged())
|
||||
return this.noChanges();
|
||||
|
||||
let isPost = (this.$attrs.save && this.$attrs.save.toLowerCase() === 'post');
|
||||
let changedData = isPost
|
||||
? this.data
|
||||
: getModifiedData(this.data, this.orgData);
|
||||
|
||||
let id = this.idField ? this.orgData[this.idField] : null;
|
||||
|
||||
// If watcher is associated to mgCrud
|
||||
|
||||
if (this.save && this.save.accept) {
|
||||
if (id)
|
||||
changedData[this.idField] = id;
|
||||
|
||||
this.save.model = changedData;
|
||||
return this.$q((resolve, reject) => {
|
||||
this.save.accept().then(
|
||||
json => this.writeData({data: json}, resolve),
|
||||
json => reject(json)
|
||||
reject
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// XXX: Alternative when mgCrud is not used
|
||||
|
||||
let id = this.idField ? this.orgData[this.idField] : null;
|
||||
// When mgCrud is not used
|
||||
|
||||
if (id) {
|
||||
return this.$q((resolve, reject) => {
|
||||
|
@ -148,16 +163,21 @@ export default class Watcher extends Component {
|
|||
});
|
||||
}
|
||||
|
||||
noChanges() {
|
||||
let message = this.$translate.instant('No changes to save');
|
||||
let p = this.$q.reject(new Error(message));
|
||||
console.log(p);
|
||||
return p;
|
||||
/**
|
||||
* Checks if data is ready to send.
|
||||
*/
|
||||
check() {
|
||||
if (this.form && this.form.$invalid)
|
||||
throw new UserError(this._.instant('Some fields are invalid'));
|
||||
if (!this.dirty)
|
||||
throw new UserError(this._.instant('No changes to save'));
|
||||
}
|
||||
|
||||
invalidForm() {
|
||||
let message = this.$translate.instant('Some fields are invalid');
|
||||
return this.$q.reject(new Error(message));
|
||||
/**
|
||||
* Notifies the user that the data has been saved.
|
||||
*/
|
||||
notifySaved() {
|
||||
this.vnApp.showMessage(this._.instant('Data saved!'));
|
||||
}
|
||||
|
||||
writeData(json, resolve) {
|
||||
|
@ -168,8 +188,15 @@ export default class Watcher extends Component {
|
|||
|
||||
updateOriginalData() {
|
||||
this.orgData = this.copyInNewObject(this.data);
|
||||
if (this.form && this.form.$dirty)
|
||||
this.form.$setPristine();
|
||||
this.setPristine();
|
||||
}
|
||||
|
||||
setPristine() {
|
||||
if (this.form) this.form.$setPristine();
|
||||
}
|
||||
|
||||
setDirty() {
|
||||
if (this.form) this.form.$setDirty();
|
||||
}
|
||||
|
||||
copyInNewObject(data) {
|
||||
|
@ -191,22 +218,15 @@ export default class Watcher extends Component {
|
|||
}
|
||||
|
||||
callback(transition) {
|
||||
let dataChanged = this.dataChanged();
|
||||
if (!this.state && dataChanged) {
|
||||
if (!this.state && this.dirty) {
|
||||
this.state = transition.to().name;
|
||||
this.$scope.confirm.show();
|
||||
this.$.confirm.show();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
dataChanged() {
|
||||
let newData = this.copyInNewObject(this.data);
|
||||
if (this.form && this.form.$dirty) return !isEqual(newData, this.orgData);
|
||||
return !isEqual(newData, this.orgData);
|
||||
}
|
||||
|
||||
onConfirmResponse(response) {
|
||||
if (response === 'ACCEPT') {
|
||||
if (this.data)
|
||||
|
@ -227,7 +247,7 @@ ngModule.component('vnWatcher', {
|
|||
data: '<',
|
||||
form: '<',
|
||||
save: '<',
|
||||
get: '=?'
|
||||
get: '<?'
|
||||
},
|
||||
controller: Watcher
|
||||
});
|
||||
|
|
|
@ -52,7 +52,7 @@ describe('Component vnWatcher', () => {
|
|||
|
||||
expect(function() {
|
||||
controller.$onInit();
|
||||
}).toThrow(new Error('Error: Parameter url ommitted'));
|
||||
}).toThrowError(/parameter/);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -100,32 +100,36 @@ describe('Component vnWatcher', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('check()', () => {
|
||||
it(`should throw error if controller.form is invalid`, () => {
|
||||
controller.form = {$invalid: true};
|
||||
|
||||
expect(function() {
|
||||
controller.check();
|
||||
}).toThrowError();
|
||||
});
|
||||
|
||||
it(`should throw error if controller.dirty is true`, () => {
|
||||
controller.form = {$invalid: true};
|
||||
|
||||
expect(function() {
|
||||
controller.check();
|
||||
}).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('realSubmit()', () => {
|
||||
describe('when controller.form', () => {
|
||||
it(`should call controller.form.setSubmited if controller.form is defined`, () => {
|
||||
controller.form = {$setSubmitted: () => {}};
|
||||
controller.form = {
|
||||
$setSubmitted: () => {},
|
||||
$setPristine: () => {}
|
||||
};
|
||||
spyOn(controller.form, '$setSubmitted');
|
||||
controller.realSubmit();
|
||||
|
||||
expect(controller.form.$setSubmitted).toHaveBeenCalledWith();
|
||||
});
|
||||
|
||||
it(`should call controller.invalidForm if controller.form.$valid is not defined`, () => {
|
||||
controller.form = {$setSubmitted: () => {}};
|
||||
spyOn(controller, 'invalidForm');
|
||||
controller.realSubmit();
|
||||
|
||||
expect(controller.invalidForm).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when !controller.dataChanged()', () => {
|
||||
it(`should call controller.noChanges()`, () => {
|
||||
spyOn(controller, 'noChanges');
|
||||
controller.realSubmit();
|
||||
|
||||
expect(controller.noChanges).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when controller.save()', () => {
|
||||
|
@ -197,7 +201,7 @@ describe('Component vnWatcher', () => {
|
|||
|
||||
describe('callback()', () => {
|
||||
describe(`when dataChanged() returns true and there's no state in the controller`, () => {
|
||||
it(`should define controller.state, call controller.$scope.confirm.show() and return false`, () => {
|
||||
it(`should define controller.state, call controller.$.confirm.show() and return false`, () => {
|
||||
$scope.confirm = {show: jasmine.createSpy('show')};
|
||||
controller.dataChanged = () => {
|
||||
return true;
|
||||
|
@ -209,7 +213,7 @@ describe('Component vnWatcher', () => {
|
|||
let result = controller.callback(transition);
|
||||
|
||||
expect(controller.state).toEqual('Batman');
|
||||
expect(controller.$scope.confirm.show).toHaveBeenCalledWith();
|
||||
expect(controller.$.confirm.show).toHaveBeenCalledWith();
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -13,3 +13,5 @@ import './equals';
|
|||
import './modified';
|
||||
import './key-codes';
|
||||
import './get-watchers';
|
||||
import './http-error';
|
||||
import './user-error';
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* Errors that can be visible and understood by the end user.
|
||||
* Used mainly in the global error handler.
|
||||
*/
|
||||
export default class UserError extends Error {
|
||||
constructor(message, fileName, lineNumber) {
|
||||
super(message, fileName, lineNumber);
|
||||
this.name = 'UserError';
|
||||
}
|
||||
}
|
|
@ -18,6 +18,9 @@ describe('Item', () => {
|
|||
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
|
||||
$state.params.id = '1';
|
||||
controller = $componentController('vnItemBarcode', {$state: $state});
|
||||
controller.$scope.watcher = {
|
||||
notifySaved: () => {}
|
||||
};
|
||||
}));
|
||||
|
||||
describe('add / remove barcode()', () => {
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
form="form">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="$ctrl.submit()">
|
||||
<vn-card pad-large>
|
||||
<vn-title>Item barcode</vn-title>
|
||||
|
|
|
@ -95,6 +95,7 @@ export default class Controller {
|
|||
return this.$http.post(`/item/api/ItemBarcodes/crudItemBarcodes`, barcodesObj).then(() => {
|
||||
this.getBarcodes();
|
||||
this._unsetDirtyForm();
|
||||
this.$scope.watcher.notifySaved();
|
||||
});
|
||||
}
|
||||
this.vnApp.showMessage(this.$translate.instant('No changes to save'));
|
||||
|
|
|
@ -4,6 +4,9 @@ class Controller {
|
|||
constructor($http, $state) {
|
||||
this.$http = $http;
|
||||
this.$state = $state;
|
||||
this.botanical = {
|
||||
itemFk: this.$state.params.id
|
||||
};
|
||||
}
|
||||
|
||||
_getBotanical() {
|
||||
|
@ -13,16 +16,8 @@ class Controller {
|
|||
};
|
||||
this.$http.get(`/item/api/ItemBotanicals?filter=${JSON.stringify(filter)}`)
|
||||
.then(res => {
|
||||
if (res.data.length) {
|
||||
if (res.data.length)
|
||||
this.botanical = res.data[0];
|
||||
} else {
|
||||
this.botanical = {
|
||||
itemFk: this.$state.params.id,
|
||||
botanical: null,
|
||||
genusFk: null,
|
||||
specieFk: null
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,11 @@ export default class Controller {
|
|||
this.oldNiches = {};
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
this.getNiches();
|
||||
this.getWarehouses();
|
||||
}
|
||||
|
||||
_setIconAdd() {
|
||||
if (this.niches.length) {
|
||||
this.niches.map(element => {
|
||||
|
@ -130,15 +135,11 @@ export default class Controller {
|
|||
return this.$http.post(`/item/api/ItemNiches/crudItemNiches`, nichesObj).then(() => {
|
||||
this.getNiches();
|
||||
this._unsetDirtyForm();
|
||||
this.$scope.watcher.notifySaved();
|
||||
});
|
||||
}
|
||||
this.vnApp.showMessage(this.$translate.instant('No changes to save'));
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
this.getNiches();
|
||||
this.getWarehouses();
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$stateParams', '$scope', '$http', '$translate', 'vnApp'];
|
||||
|
|
|
@ -17,6 +17,9 @@ describe('Item', () => {
|
|||
$httpBackend = _$httpBackend_;
|
||||
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
|
||||
controller = $componentController('vnItemNiche', {$state: $state});
|
||||
controller.$scope.watcher = {
|
||||
notifySaved: () => {}
|
||||
};
|
||||
}));
|
||||
|
||||
describe('add / remove niche', () => {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<form name="form" ng-submit="$ctrl.submit()">
|
||||
<vn-card pad-large>
|
||||
<vn-title>Item tags</vn-title>
|
||||
<vn-horizontal ng-repeat="itemTag in $ctrl.instancedItemTags">
|
||||
<vn-horizontal ng-repeat="itemTag in $ctrl.tags">
|
||||
<vn-autocomplete
|
||||
vn-id="tag"
|
||||
vn-one
|
||||
|
@ -15,7 +15,7 @@
|
|||
data="tags.model"
|
||||
show-field="name"
|
||||
label="Tag"
|
||||
on-change="$ctrl.checkAutocompleteChanges(itemTag)"
|
||||
on-change="itemTag.value = null"
|
||||
vn-acl="buyer"
|
||||
vn-focus
|
||||
disabled="itemTag.id != null">
|
||||
|
@ -54,7 +54,7 @@
|
|||
medium-grey
|
||||
vn-tooltip="Remove tag"
|
||||
icon="remove_circle_outline"
|
||||
ng-click="$ctrl.removeItemTag($index)">
|
||||
ng-click="$ctrl.removeTag($index)">
|
||||
</vn-icon>
|
||||
</vn-horizontal>
|
||||
<vn-one>
|
||||
|
@ -62,7 +62,7 @@
|
|||
vn-bind="+"
|
||||
vn-tooltip="Add tag"
|
||||
icon="add_circle"
|
||||
ng-click="$ctrl.addItemTag()">
|
||||
ng-click="$ctrl.addTag()">
|
||||
</vn-icon-button>
|
||||
</vn-one>
|
||||
</vn-card>
|
||||
|
|
|
@ -1,71 +1,63 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
class Controller {
|
||||
constructor($stateParams, $scope, $http, $translate, vnApp) {
|
||||
constructor($stateParams, $scope, $http) {
|
||||
this.params = $stateParams;
|
||||
this.$scope = $scope;
|
||||
this.$ = $scope;
|
||||
this.$http = $http;
|
||||
this.$translate = $translate;
|
||||
this.vnApp = vnApp;
|
||||
|
||||
this.itemTagTypes = [];
|
||||
this.removedItemTags = [];
|
||||
this.oldItemTags = {};
|
||||
this.tags = [];
|
||||
this.removedTags = [];
|
||||
}
|
||||
|
||||
_setIconAdd() {
|
||||
if (this.instancedItemTags && this.instancedItemTags.length) {
|
||||
this.instancedItemTags.map(element => {
|
||||
element.showAddIcon = false;
|
||||
return true;
|
||||
$onInit() {
|
||||
this.getTags();
|
||||
}
|
||||
|
||||
getTags() {
|
||||
let filter = {
|
||||
where: {itemFk: this.params.id},
|
||||
order: "priority ASC",
|
||||
include: {relation: "tag"}
|
||||
};
|
||||
this.$http.get(`/item/api/ItemTags?filter=${JSON.stringify(filter)}`).then(response => {
|
||||
this.removedTags = [];
|
||||
|
||||
this.itemTags = JSON.parse(JSON.stringify(this.tags));
|
||||
this.tags = response.data;
|
||||
this.orgTags = {};
|
||||
this.tags.forEach(tag => {
|
||||
this.orgTags[tag.id] = Object.assign({}, tag);
|
||||
});
|
||||
this.instancedItemTags[this.instancedItemTags.length - 1].showAddIcon = true;
|
||||
}
|
||||
|
||||
this.$.form.$setPristine();
|
||||
});
|
||||
}
|
||||
|
||||
_setDirtyForm() {
|
||||
if (this.$scope.form) {
|
||||
this.$scope.form.$setDirty();
|
||||
}
|
||||
}
|
||||
_unsetDirtyForm() {
|
||||
if (this.$scope.form) {
|
||||
this.$scope.form.$setPristine();
|
||||
}
|
||||
addTag() {
|
||||
this.tags.push({
|
||||
itemFk: this.params.id,
|
||||
priority: this.getHighestPriority(this.tags)
|
||||
});
|
||||
}
|
||||
|
||||
checkAutocompleteChanges(itemTag) {
|
||||
itemTag.value = null;
|
||||
}
|
||||
|
||||
addItemTag() {
|
||||
if (this.instancedItemTags) {
|
||||
this.instancedItemTags.push({value: null, itemFk: this.params.id, tagFk: null, priority: this.getHighestPriority(this.instancedItemTags), showAddIcon: true});
|
||||
this._setIconAdd();
|
||||
}
|
||||
}
|
||||
|
||||
removeItemTag(index) {
|
||||
let item = this.instancedItemTags[index];
|
||||
if (item) {
|
||||
this.instancedItemTags.splice(index, 1);
|
||||
this._setIconAdd();
|
||||
if (item.id) {
|
||||
this.removedItemTags.push(item.id);
|
||||
this._setDirtyForm();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getHighestPriority(instancedItemTags) {
|
||||
getHighestPriority(tags) {
|
||||
let max = 0;
|
||||
instancedItemTags.forEach(tag => {
|
||||
tags.forEach(tag => {
|
||||
if (tag.priority > max)
|
||||
max = tag.priority;
|
||||
});
|
||||
return max + 1;
|
||||
}
|
||||
|
||||
removeTag(index) {
|
||||
let item = this.tags[index];
|
||||
this.tags.splice(index, 1);
|
||||
if (item.id) {
|
||||
this.removedTags.push(item.id);
|
||||
this.$.form.$setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
getSourceTable(selection) {
|
||||
if (!selection || selection.isFree === true)
|
||||
return null;
|
||||
|
@ -78,86 +70,38 @@ class Controller {
|
|||
}
|
||||
}
|
||||
|
||||
_equalItemTags(oldTag, newTag) {
|
||||
return oldTag.tagFk === newTag.tagFk && oldTag.value === newTag.value && oldTag.priority === newTag.priority;
|
||||
}
|
||||
|
||||
_setOlTags(instancedItemTags) {
|
||||
this._setIconAdd();
|
||||
instancedItemTags.forEach(tag => {
|
||||
this.oldItemTags[tag.id] = Object.assign({}, tag);
|
||||
});
|
||||
}
|
||||
|
||||
_getItemTags() {
|
||||
let filter = {
|
||||
where: {itemFk: this.params.id},
|
||||
order: "priority ASC",
|
||||
include: {relation: "tag"}
|
||||
};
|
||||
this.$http.get(`/item/api/ItemTags?filter=${JSON.stringify(filter)}`).then(response => {
|
||||
this.instancedItemTags = response.data;
|
||||
this.itemTags = JSON.parse(JSON.stringify(this.instancedItemTags));
|
||||
this._setOlTags(response.data);
|
||||
});
|
||||
tagIsEqual(oldTag, newTag) {
|
||||
return oldTag.tagFk === newTag.tagFk &&
|
||||
oldTag.value === newTag.value &&
|
||||
oldTag.priority === newTag.priority;
|
||||
}
|
||||
|
||||
submit() {
|
||||
let itemTagsDefined = [];
|
||||
let repeatedItemTags = false;
|
||||
let canSubmit;
|
||||
let tagsObj = {
|
||||
delete: this.removedItemTags,
|
||||
this.$.watcher.check();
|
||||
|
||||
let changes = {
|
||||
delete: this.removedTags,
|
||||
create: [],
|
||||
update: []
|
||||
};
|
||||
this.instancedItemTags.forEach(tag => {
|
||||
let isNewTag = !tag.id;
|
||||
|
||||
if (itemTagsDefined.indexOf(tag.tagFk) !== -1) {
|
||||
repeatedItemTags = true;
|
||||
return;
|
||||
}
|
||||
itemTagsDefined.push(tag.tagFk);
|
||||
|
||||
if (isNewTag) {
|
||||
tagsObj.create.push(tag);
|
||||
}
|
||||
|
||||
if (!isNewTag && !this._equalItemTags(this.oldItemTags[tag.id], tag)) {
|
||||
this.tags.forEach(tag => {
|
||||
if (!tag.id)
|
||||
changes.create.push(tag);
|
||||
else if (!this.tagIsEqual(this.orgTags[tag.id], tag)) {
|
||||
let tagToUpdate = Object.assign({}, tag);
|
||||
delete tagToUpdate.tag;
|
||||
delete tagToUpdate.showAddIcon;
|
||||
tagsObj.update.push(tagToUpdate);
|
||||
changes.update.push(tagToUpdate);
|
||||
}
|
||||
});
|
||||
|
||||
if (this.$scope.form.$invalid) {
|
||||
return this.vnApp.showMessage(this.$translate.instant('Some fields are invalid'));
|
||||
}
|
||||
|
||||
if (repeatedItemTags) {
|
||||
return this.vnApp.showMessage(this.$translate.instant('The tag must be unique'));
|
||||
}
|
||||
|
||||
canSubmit = tagsObj.update.length > 0 || tagsObj.create.length > 0 || tagsObj.delete.length > 0;
|
||||
|
||||
if (canSubmit) {
|
||||
return this.$http.post(`/item/api/ItemTags/crudItemTags`, tagsObj).then(() => {
|
||||
// this.itemTags = JSON.parse(JSON.stringify(this.instancedItemTags));
|
||||
this._getItemTags();
|
||||
this._unsetDirtyForm();
|
||||
});
|
||||
}
|
||||
this.vnApp.showMessage(this.$translate.instant('No changes to save'));
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
this._getItemTags();
|
||||
this.$http.post(`/item/api/ItemTags/crud`, changes).then(() => {
|
||||
this.getTags();
|
||||
this.$.watcher.notifySaved();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$stateParams', '$scope', '$http', '$translate', 'vnApp'];
|
||||
Controller.$inject = ['$stateParams', '$scope', '$http'];
|
||||
|
||||
ngModule.component('vnItemTags', {
|
||||
template: require('./index.html'),
|
||||
|
|
|
@ -17,37 +17,41 @@ describe('Item', () => {
|
|||
$httpBackend = _$httpBackend_;
|
||||
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
|
||||
controller = $componentController('vnItemTags', {$state: $state});
|
||||
controller.$.form = {
|
||||
$setPristine: () => {},
|
||||
$dirty: true
|
||||
};
|
||||
controller.$.watcher = {
|
||||
notifySaved: () => {},
|
||||
check: () => {}
|
||||
};
|
||||
}));
|
||||
|
||||
describe('add / remove tags', () => {
|
||||
it('should add one empty tag into controller tags collection and call _setIconAdd()', () => {
|
||||
controller.instancedItemTags = [];
|
||||
spyOn(controller, '_setIconAdd').and.callThrough();
|
||||
controller.addItemTag();
|
||||
it('should add one empty tag into controller tags collection', () => {
|
||||
controller.tags = [];
|
||||
controller.addTag();
|
||||
|
||||
expect(controller._setIconAdd).toHaveBeenCalledWith();
|
||||
expect(controller.instancedItemTags.length).toEqual(1);
|
||||
expect(controller.instancedItemTags[0].id).toBe(undefined);
|
||||
expect(controller.instancedItemTags[0].showAddIcon).toBeTruthy();
|
||||
expect(controller.tags.length).toEqual(1);
|
||||
expect(controller.tags[0].id).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should remove a tag that occupies the position in the index given and call _setIconAdd()', () => {
|
||||
it('should remove a tag that occupies the position in the index', () => {
|
||||
controller.$.form = {$setDirty: () => {}};
|
||||
spyOn(controller.$.form, '$setDirty');
|
||||
|
||||
let index = 2;
|
||||
controller.instancedItemTags = [
|
||||
controller.tags = [
|
||||
{id: 1, typeFk: 1, value: '1111', showAddIcon: false},
|
||||
{id: 2, typeFk: 2, value: '2222', showAddIcon: false},
|
||||
{id: 3, typeFk: 3, value: '3333', showAddIcon: true}
|
||||
];
|
||||
|
||||
spyOn(controller, '_setIconAdd').and.callThrough();
|
||||
controller.removeTag(index);
|
||||
|
||||
controller.removeItemTag(index);
|
||||
|
||||
expect(controller._setIconAdd).toHaveBeenCalledWith();
|
||||
expect(controller.instancedItemTags.length).toEqual(2);
|
||||
expect(controller.instancedItemTags[0].showAddIcon).toBeFalsy();
|
||||
expect(controller.instancedItemTags[1].showAddIcon).toBeTruthy();
|
||||
expect(controller.instancedItemTags[index]).toBe(undefined);
|
||||
expect(controller.tags.length).toEqual(2);
|
||||
expect(controller.tags[index]).toBe(undefined);
|
||||
expect(controller.$.form.$setDirty).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -90,11 +94,11 @@ describe('Item', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('_equalItemTags()', () => {
|
||||
describe('tagIsEqual()', () => {
|
||||
it('should return true if two tags are equals independent of control attributes', () => {
|
||||
let tag1 = {id: 1, typeFk: 1, value: '1111', showAddIcon: true};
|
||||
let tag2 = {id: 1, typeFk: 1, value: '1111', showAddIcon: false};
|
||||
let equals = controller._equalItemTags(tag2, tag1);
|
||||
let equals = controller.tagIsEqual(tag2, tag1);
|
||||
|
||||
expect(equals).toBeTruthy();
|
||||
});
|
||||
|
@ -102,7 +106,7 @@ describe('Item', () => {
|
|||
it('should return false if two tags aint equal independent of control attributes', () => {
|
||||
let tag1 = {id: 1, typeFk: 1, value: '1111', showAddIcon: true};
|
||||
let tag2 = {id: 1, typeFk: 1, value: '2222', showAddIcon: true};
|
||||
let equals = controller._equalItemTags(tag2, tag1);
|
||||
let equals = controller.tagIsEqual(tag2, tag1);
|
||||
|
||||
expect(equals).toBeFalsy();
|
||||
});
|
||||
|
@ -110,73 +114,78 @@ describe('Item', () => {
|
|||
|
||||
describe('get itemTags', () => {
|
||||
it('should perform a GET query to receive the item tags', () => {
|
||||
controller.$.form = {$setPristine: () => {}};
|
||||
spyOn(controller.$.form, '$setPristine');
|
||||
|
||||
let res = [{id: 1, typeFk: 1, value: '1111'}];
|
||||
|
||||
$httpBackend.whenGET(`/item/api/ItemTags?filter={"where":{},"order":"priority ASC","include":{"relation":"tag"}}`).respond(res);
|
||||
$httpBackend.expectGET(`/item/api/ItemTags?filter={"where":{},"order":"priority ASC","include":{"relation":"tag"}}`);
|
||||
controller._getItemTags();
|
||||
controller.getTags();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.$.form.$setPristine).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('submit()', () => {
|
||||
it("should return an error message 'The tag must be unique' when the tag value isnt unique", () => {
|
||||
controller.$scope.form = [];
|
||||
// TODO: Server validation should be implemented
|
||||
xit("should return an error message 'The tag must be unique' when the tag value isnt unique", () => {
|
||||
controller.$.form = [];
|
||||
spyOn(controller.vnApp, 'showMessage').and.callThrough();
|
||||
controller.instancedItemTags = [
|
||||
controller.tags = [
|
||||
{typeFk: 1, value: 123454, itemFk: 1, id: 1},
|
||||
{typeFk: 1, value: 123454, itemFk: 1}
|
||||
];
|
||||
controller.oldItemTags = {1: {typeFk: 1, id: 1, value: 123454, itemFk: 1}};
|
||||
controller.orgTags = {1: {typeFk: 1, id: 1, value: 123454, itemFk: 1}};
|
||||
controller.submit();
|
||||
|
||||
expect(controller.vnApp.showMessage).toHaveBeenCalledWith('The tag must be unique');
|
||||
});
|
||||
|
||||
it("should perfom a query to delete tags", () => {
|
||||
controller.$scope.form = {$setPristine: () => {}};
|
||||
controller.oldItemTags = {1: {id: 1, typeFk: 1, value: '1111'}};
|
||||
controller.instancedItemTags = [];
|
||||
controller.removedItemTags = [1];
|
||||
controller.orgTags = {1: {id: 1, typeFk: 1, value: '1111'}};
|
||||
controller.tags = [];
|
||||
controller.removedTags = [1];
|
||||
|
||||
$httpBackend.whenGET(`/item/api/ItemTags?filter={"where":{},"order":"priority ASC","include":{"relation":"tag"}}`).respond([]);
|
||||
$httpBackend.expectPOST(`/item/api/ItemTags/crudItemTags`).respond('ok!');
|
||||
$httpBackend.expectPOST(`/item/api/ItemTags/crud`).respond('ok!');
|
||||
controller.submit();
|
||||
$httpBackend.flush();
|
||||
});
|
||||
|
||||
it("should perfom a query to update tags", () => {
|
||||
controller.$scope.form = {$setPristine: () => {}};
|
||||
controller.instancedItemTags = [{id: 1, typeFk: 1, value: '2222'}];
|
||||
controller.oldItemTags = {1: {id: 1, typeFk: 1, value: '1111'}};
|
||||
controller.tags = [{id: 1, typeFk: 1, value: '2222'}];
|
||||
controller.orgTags = {1: {id: 1, typeFk: 1, value: '1111'}};
|
||||
|
||||
$httpBackend.whenGET(`/item/api/ItemTags?filter={"where":{},"order":"priority ASC","include":{"relation":"tag"}}`).respond([]);
|
||||
$httpBackend.expectPOST(`/item/api/ItemTags/crudItemTags`).respond('ok!');
|
||||
$httpBackend.expectPOST(`/item/api/ItemTags/crud`).respond('ok!');
|
||||
controller.submit();
|
||||
$httpBackend.flush();
|
||||
});
|
||||
|
||||
it("should perfom a query to create new tag", () => {
|
||||
controller.$scope.form = {$setPristine: () => {}};
|
||||
controller.instancedItemTags = [{typeFk: 1, value: 1111, itemFk: 1}];
|
||||
controller.tags = [{typeFk: 1, value: 1111, itemFk: 1}];
|
||||
|
||||
$httpBackend.whenGET(`/item/api/ItemTags?filter={"where":{},"order":"priority ASC","include":{"relation":"tag"}}`).respond([]);
|
||||
$httpBackend.expectPOST(`/item/api/ItemTags/crudItemTags`).respond('ok!');
|
||||
$httpBackend.expectPOST(`/item/api/ItemTags/crud`).respond('ok!');
|
||||
controller.submit();
|
||||
$httpBackend.flush();
|
||||
});
|
||||
|
||||
it("should return a message 'No changes to save' when there are no changes to apply", () => {
|
||||
controller.$scope.form = {$setPristine: () => {}};
|
||||
spyOn(controller.vnApp, 'showMessage').and.callThrough();
|
||||
controller.oldItemTags = [
|
||||
{typeFk: 1, value: 1, itemFk: 1, id: 1},
|
||||
{typeFk: 2, value: 2, itemFk: 1, id: 2}
|
||||
];
|
||||
controller.instancedItemTags = [];
|
||||
controller.submit();
|
||||
it("should throw 'No changes to save' error when there are no changes to apply", () => {
|
||||
controller.$.watcher = {
|
||||
check: () => {
|
||||
throw new Error('No changes to save');
|
||||
}
|
||||
};
|
||||
|
||||
expect(controller.vnApp.showMessage).toHaveBeenCalledWith('No changes to save');
|
||||
controller.orgTags = [];
|
||||
controller.tags = [];
|
||||
|
||||
expect(function() {
|
||||
controller.submit();
|
||||
}).toThrowError();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
<vn-crud-model
|
||||
url="/item/api/TaxClasses"
|
||||
fields="['id', 'description', 'code']"
|
||||
data="classes">
|
||||
</vn-crud-model>
|
||||
<form name="form" ng-submit="$ctrl.submit()">
|
||||
<vn-card pad-large>
|
||||
<vn-title>Item tax</vn-title>
|
||||
|
@ -10,8 +15,7 @@
|
|||
<vn-autocomplete vn-one
|
||||
label="Class"
|
||||
field="tax.taxClassFk"
|
||||
initial-data="tax.taxClass"
|
||||
data="$ctrl.classes"
|
||||
data="classes"
|
||||
value-field="id"
|
||||
show-field="description">
|
||||
</vn-autocomplete>
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
export default class Controller {
|
||||
constructor($stateParams, $http) {
|
||||
constructor($stateParams, $http, $translate, vnApp) {
|
||||
this.$http = $http;
|
||||
this.$stateParams = $stateParams;
|
||||
this._ = $translate;
|
||||
this.vnApp = vnApp;
|
||||
|
||||
let filter = {
|
||||
fields: ['id', 'countryFk', 'taxClassFk'],
|
||||
include: [{
|
||||
relation: 'country',
|
||||
scope: {fields: ['country']}
|
||||
}, {
|
||||
relation: 'taxClass',
|
||||
scope: {fields: ['id', 'description']}
|
||||
}]
|
||||
};
|
||||
|
||||
|
@ -21,23 +20,21 @@ export default class Controller {
|
|||
$http.get(url).then(json => {
|
||||
this.taxes = json.data;
|
||||
});
|
||||
|
||||
$http.get(`/item/api/TaxClasses`).then(json => {
|
||||
this.classes = json.data;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
submit() {
|
||||
let data = [];
|
||||
for (let tax of this.taxes)
|
||||
data.push({id: tax.id, taxClassFk: tax.taxClassFk});
|
||||
|
||||
let url = `/item/api/Items/${this.$stateParams.id}/updateTaxes`;
|
||||
this.$http.post(url, data);
|
||||
this.$http.post(url, data).then(
|
||||
() => this.vnApp.showMessage(this._.instant('Data saved!'))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$stateParams', '$http'];
|
||||
Controller.$inject = ['$stateParams', '$http', '$translate', 'vnApp'];
|
||||
|
||||
ngModule.component('vnItemTax', {
|
||||
template: require('./index.html'),
|
||||
|
|
|
@ -56,12 +56,10 @@ function $exceptionHandler(vnApp, $window) {
|
|||
continueUrl = encodeURIComponent(continueUrl);
|
||||
$window.location = `/auth/?apiKey=${vnApp.name}&continue=${continueUrl}`;
|
||||
}
|
||||
} else if (exception.message) {
|
||||
} else if (exception.name == 'UserError') {
|
||||
message = exception.message;
|
||||
} else if (typeof exception == 'string') {
|
||||
message = exception;
|
||||
} else {
|
||||
message = `Unknown error`;
|
||||
message = 'Ups! Something went wrong';
|
||||
console.error(exception);
|
||||
}
|
||||
|
||||
|
|
|
@ -119,6 +119,7 @@ class Controller {
|
|||
return this.$http.post(`/ticket/api/TicketObservations/crudTicketObservation`, observationsObj).then(() => {
|
||||
this.getObservations();
|
||||
this._unsetDirtyForm();
|
||||
this.$scope.watcher.notifySaved();
|
||||
});
|
||||
}
|
||||
this.vnApp.showMessage(this.$translate.instant('No changes to save'));
|
||||
|
|
|
@ -17,6 +17,9 @@ describe('ticket', () => {
|
|||
$httpBackend = _$httpBackend_;
|
||||
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
|
||||
controller = $componentController('vnTicketObservation', {$state: $state});
|
||||
controller.$scope.watcher = {
|
||||
notifySaved: () => {}
|
||||
};
|
||||
}));
|
||||
|
||||
describe('add / remove observation', () => {
|
||||
|
|
|
@ -10,12 +10,12 @@
|
|||
<vn-title>New state</vn-title>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
field="$ctrl.ticket.stateFk"
|
||||
url="/ticket/api/States"
|
||||
label="State"
|
||||
vn-focus>
|
||||
</vn-autocomplete>
|
||||
vn-one
|
||||
field="$ctrl.ticket.stateFk"
|
||||
url="/ticket/api/States"
|
||||
label="State"
|
||||
vn-focus>
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
|
|
|
@ -7,8 +7,7 @@ class Controller {
|
|||
this.vnApp = vnApp;
|
||||
this.$translate = $translate;
|
||||
this.ticket = {
|
||||
ticketFk: $state.params.id,
|
||||
text: null
|
||||
ticketFk: $state.params.id
|
||||
};
|
||||
}
|
||||
onSubmit() {
|
||||
|
|
|
@ -4,16 +4,6 @@
|
|||
// delete me, this comment is to add a commit
|
||||
export default {
|
||||
vnTextfield: 'vn-textfield > div > input',
|
||||
vnTextarea: 'vn-textarea',
|
||||
vnSubmit: 'vn-submit > input',
|
||||
vnTopbar: 'vn-topbar > header',
|
||||
vnIcon: 'vn-icon',
|
||||
vnSearchBar: 'vn-searchbar > form > vn-horizontal',
|
||||
vnFloatButton: 'vn-float-button > button',
|
||||
vnMenuItem: 'vn-menu-item > li > a',
|
||||
vnAutocomplete: 'vn-autocomplete',
|
||||
vnCheck: 'vn-check',
|
||||
vnIconButton: 'vn-icon-button',
|
||||
vnItemSummary: 'vn-item-summary > vn-card > div > vn-vertical',
|
||||
vnLabelValue: 'vn-label-value'
|
||||
vnFloatButton: 'vn-float-button > button'
|
||||
};
|
||||
|
|
|
@ -17,7 +17,7 @@ export default {
|
|||
},
|
||||
clientsIndex: {
|
||||
searchClientInput: `${components.vnTextfield}`,
|
||||
searchButton: `${components.vnSearchBar} > vn-icon-button`,
|
||||
searchButton: `vn-searchbar vn-icon-button[icon="search"]`,
|
||||
searchResult: `vn-item-client a`,
|
||||
createClientButton: `${components.vnFloatButton}`
|
||||
},
|
||||
|
@ -33,122 +33,122 @@ export default {
|
|||
cancelButton: `button[href="#!/client/index"]`
|
||||
},
|
||||
clientBasicData: {
|
||||
basicDataButton: `${components.vnMenuItem}[ui-sref="client.card.basicData"]`,
|
||||
basicDataButton: `vn-menu-item a[ui-sref="client.card.basicData"]`,
|
||||
nameInput: `${components.vnTextfield}[name="name"]`,
|
||||
contactInput: `${components.vnTextfield}[name="contact"]`,
|
||||
phoneInput: `${components.vnTextfield}[name="phone"]`,
|
||||
mobileInput: `${components.vnTextfield}[name="mobile"]`,
|
||||
faxInput: `${components.vnTextfield}[name="fax"]`,
|
||||
emailInput: `${components.vnTextfield}[name="email"]`,
|
||||
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)`,
|
||||
salesPersonInput: `vn-autocomplete[field="$ctrl.client.salesPersonFk"] input`,
|
||||
salesPersonOptionOne: `vn-autocomplete[field="$ctrl.client.salesPersonFk"] vn-drop-down ul > li:nth-child(1)`,
|
||||
channelInput: `vn-autocomplete[field="$ctrl.client.contactChannelFk"] input`,
|
||||
channelMetropolisOption: `vn-autocomplete[field="$ctrl.client.contactChannelFk"] vn-drop-down ul > li:nth-child(3)`,
|
||||
saveButton: `${components.vnSubmit}`
|
||||
},
|
||||
clientFiscalData: {
|
||||
fiscalDataButton: `${components.vnMenuItem}[ui-sref="client.card.fiscalData"]`,
|
||||
fiscalDataButton: `vn-menu-item a[ui-sref="client.card.fiscalData"]`,
|
||||
socialNameInput: `${components.vnTextfield}[name="socialName"]`,
|
||||
fiscalIdInput: `${components.vnTextfield}[name="fi"]`,
|
||||
equalizationTaxCheckboxLabel: `${components.vnCheck}[label='Is equalizated'] > label > input`,
|
||||
equalizationTaxCheckboxLabel: `vn-check[label='Is equalizated'] > label > input`,
|
||||
acceptPropagationButton: `vn-client-fiscal-data > vn-confirm button[response=ACCEPT]`,
|
||||
addressInput: `${components.vnTextfield}[name="street"]`,
|
||||
cityInput: `${components.vnTextfield}[name="city"]`,
|
||||
postcodeInput: `${components.vnTextfield}[name="postcode"]`,
|
||||
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`,
|
||||
frozenCheckboxLabel: `${components.vnCheck}[label="Frozen"] > label`,
|
||||
invoiceByAddressCheckboxInput: `${components.vnCheck}[label='Invoice by address'] > label > input`,
|
||||
verifiedDataCheckboxInput: `${components.vnCheck}[label="Verified data"] > label > input`,
|
||||
hasToInvoiceCheckboxLabel: `${components.vnCheck}[label='Has to invoice'] > label`,
|
||||
invoiceByMailCheckboxLabel: `${components.vnCheck}[label='Invoice by mail'] > label`,
|
||||
viesCheckboxInput: `${components.vnCheck}[label='Vies'] > label > input`,
|
||||
provinceInput: `vn-autocomplete[field="$ctrl.client.provinceFk"] input`,
|
||||
provinceFifthOption: `vn-autocomplete[field="$ctrl.client.provinceFk"] vn-drop-down ul > li:nth-child(5)`,
|
||||
countryInput: `vn-autocomplete[field="$ctrl.client.countryFk"] input`,
|
||||
countryThirdOption: `vn-autocomplete[field="$ctrl.client.countryFk"] vn-drop-down ul > li:nth-child(3)`,
|
||||
activeCheckboxLabel: `vn-check[label="Active"] > label`,
|
||||
frozenCheckboxLabel: `vn-check[label="Frozen"] > label`,
|
||||
invoiceByAddressCheckboxInput: `vn-check[label='Invoice by address'] > label > input`,
|
||||
verifiedDataCheckboxInput: `vn-check[label="Verified data"] > label > input`,
|
||||
hasToInvoiceCheckboxLabel: `vn-check[label='Has to invoice'] > label`,
|
||||
invoiceByMailCheckboxLabel: `vn-check[label='Invoice by mail'] > label`,
|
||||
viesCheckboxInput: `vn-check[label='Vies'] > label > input`,
|
||||
saveButton: `${components.vnSubmit}`
|
||||
},
|
||||
clientPayMethod: {
|
||||
payMethodButton: `${components.vnMenuItem}[ui-sref="client.card.billingData"]`,
|
||||
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)`,
|
||||
payMethodButton: `vn-menu-item a[ui-sref="client.card.billingData"]`,
|
||||
payMethodInput: `vn-autocomplete[field="$ctrl.client.payMethodFk"] input`,
|
||||
payMethodIBANOption: `vn-autocomplete[field="$ctrl.client.payMethodFk"] vn-drop-down ul > li:nth-child(5)`,
|
||||
payMethodOptionOne: `vn-autocomplete[field="$ctrl.client.payMethodFk"] vn-drop-down ul > li:nth-child(2)`,
|
||||
IBANInput: `${components.vnTextfield}[name="iban"]`,
|
||||
dueDayInput: `${components.vnTextfield}[name="dueDay"]`,
|
||||
receivedCoreVNHCheckbox: `${components.vnCheck}[label='Received core VNH'] > label > input`,
|
||||
receivedCoreVNLCheckbox: `${components.vnCheck}[label='Received core VNL'] > label > input`,
|
||||
receivedB2BVNLCheckbox: `${components.vnCheck}[label='Received B2B VNL'] > label > input`,
|
||||
receivedCoreVNHCheckbox: `vn-check[label='Received core VNH'] > label > input`,
|
||||
receivedCoreVNLCheckbox: `vn-check[label='Received core VNL'] > label > input`,
|
||||
receivedB2BVNLCheckbox: `vn-check[label='Received B2B VNL'] > label > input`,
|
||||
saveButton: `${components.vnSubmit}`
|
||||
},
|
||||
clientAddresses: {
|
||||
addressesButton: `${components.vnMenuItem}[ui-sref="client.card.address.index"]`,
|
||||
addressesButton: `vn-menu-item a[ui-sref="client.card.address.index"]`,
|
||||
createAddress: `vn-client-address-index ${components.vnFloatButton}`,
|
||||
defaultCheckboxInput: `${components.vnCheck}[label='Default'] > label > input`,
|
||||
defaultCheckboxInput: `vn-check[label='Default'] > label > input`,
|
||||
consigneeInput: `${components.vnTextfield}[name="nickname"]`,
|
||||
streetAddressInput: `${components.vnTextfield}[name="street"]`,
|
||||
postcodeInput: `${components.vnTextfield}[name="postalCode"]`,
|
||||
cityInput: `${components.vnTextfield}[name="city"]`,
|
||||
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)`,
|
||||
provinceInput: `vn-autocomplete[field="$ctrl.address.provinceFk"] input`,
|
||||
provinceSecondOption: `vn-autocomplete[field="$ctrl.address.provinceFk"] vn-drop-down ul > li:nth-child(2)`,
|
||||
agencyInput: `vn-autocomplete[field="$ctrl.address.agencyModeFk"] input`,
|
||||
agenctySecondOption: `vn-autocomplete[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-address-index vn-horizontal:nth-child(2) div[name="street"]',
|
||||
secondMakeDefaultStar: 'vn-client-address-index > vn-vertical > vn-card > div > vn-horizontal:nth-child(3) > vn-one > vn-horizontal > vn-none > i',
|
||||
firstEditButton: `vn-client-address-index ${components.vnIconButton}[icon='edit']`,
|
||||
secondEditButton: `vn-client-address-index vn-horizontal:nth-child(3) ${components.vnIconButton}[icon='edit']`,
|
||||
activeCheckbox: `${components.vnCheck}[label='Enabled'] > label > input`,
|
||||
equalizationTaxCheckboxLabel: `vn-client-address-edit ${components.vnCheck}[label='Is equalizated'] > label > input`,
|
||||
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: `vn-horizontal:nth-child(4) > ${components.vnAutocomplete}[field="observation.observationTypeFk"] input`,
|
||||
secondObservationTypeSelectOptionTwo: `vn-horizontal:nth-child(4) > ${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) 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`,
|
||||
addObservationButton: `${components.vnIcon}[icon="add_circle"]`,
|
||||
firstEditButton: `vn-client-address-index vn-icon-button[icon='edit']`,
|
||||
secondEditButton: `vn-client-address-index vn-horizontal:nth-child(3) vn-icon-button[icon='edit']`,
|
||||
activeCheckbox: `vn-check[label='Enabled'] > label > input`,
|
||||
equalizationTaxCheckboxLabel: `vn-client-address-edit vn-check[label='Is equalizated'] > label > input`,
|
||||
firstObservationTypeSelect: `vn-client-address-edit [name=observations] :nth-child(1) [field="observation.observationTypeFk"] input`,
|
||||
firstObservationTypeSelectOptionOne: `vn-client-address-edit [name=observations] :nth-child(1) [field="observation.observationTypeFk"] vn-drop-down ul > li:nth-child(1)`,
|
||||
firstObservationDescriptionInput: `vn-client-address-edit [name=observations] :nth-child(1) [model="observation.description"] input`,
|
||||
secondObservationTypeSelect: `vn-client-address-edit [name=observations] :nth-child(2) [field="observation.observationTypeFk"] input`,
|
||||
secondObservationTypeSelectOptionTwo: `vn-client-address-edit [name=observations] :nth-child(2) [field="observation.observationTypeFk"] vn-drop-down ul > li:nth-child(2)`,
|
||||
secondObservationDescriptionInput: `vn-client-address-edit [name=observations] :nth-child(2) [model="observation.description"] input`,
|
||||
thirdObservationTypeSelect: `vn-client-address-edit [name=observations] :nth-child(3) [field="observation.observationTypeFk"] input`,
|
||||
thirdObservationTypeSelectOptionThree: `vn-client-address-edit [name=observations] :nth-child(3) [field="observation.observationTypeFk"] vn-drop-down ul > li:nth-child(3)`,
|
||||
thirdObservationDescriptionInput: `vn-client-address-edit [name=observations] :nth-child(3) [model="observation.description"] input`,
|
||||
addObservationButton: `vn-client-address-edit vn-icon-button[icon="add_circle"]`,
|
||||
saveButton: `${components.vnSubmit}`,
|
||||
cancelButton: `button[ui-sref="client.card.address.index"]`
|
||||
},
|
||||
clientWebAccess: {
|
||||
webAccessButton: `${components.vnMenuItem}[ui-sref="client.card.webAccess"]`,
|
||||
enableWebAccessCheckbox: `${components.vnCheck}[label='Enable web access'] > label > input`,
|
||||
webAccessButton: `vn-menu-item a[ui-sref="client.card.webAccess"]`,
|
||||
enableWebAccessCheckbox: `vn-check[label='Enable web access'] > label > input`,
|
||||
userNameInput: `${components.vnTextfield}[name="name"]`,
|
||||
saveButton: `${components.vnSubmit}`
|
||||
},
|
||||
clientNotes: {
|
||||
notesButton: `${components.vnMenuItem}[ui-sref="client.card.note.index"]`,
|
||||
notesButton: `vn-menu-item a[ui-sref="client.card.note.index"]`,
|
||||
addNoteFloatButton: `${components.vnFloatButton}`,
|
||||
noteInput: `${components.vnTextarea}[label="Note"]`,
|
||||
noteInput: `vn-textarea[label="Note"]`,
|
||||
saveButton: `${components.vnSubmit}`,
|
||||
firstNoteText: 'vn-client-note .text'
|
||||
},
|
||||
clientCredit: {
|
||||
creditButton: `${components.vnMenuItem}[ui-sref="client.card.credit.index"]`,
|
||||
creditButton: `vn-menu-item a[ui-sref="client.card.credit.index"]`,
|
||||
addCreditFloatButton: `${components.vnFloatButton}`,
|
||||
creditInput: `${components.vnTextfield}[name="credit"]`,
|
||||
saveButton: `${components.vnSubmit}`,
|
||||
firstCreditText: 'vn-client-credit-index .list-element'
|
||||
},
|
||||
clientGreuge: {
|
||||
greugeButton: `${components.vnMenuItem}[ui-sref="client.card.greuge.index"]`,
|
||||
greugeButton: `vn-menu-item a[ui-sref="client.card.greuge.index"]`,
|
||||
addGreugeFloatButton: `${components.vnFloatButton}`,
|
||||
amountInput: `${components.vnTextfield}[name="amount"]`,
|
||||
descriptionInput: `${components.vnTextfield}[name="description"]`,
|
||||
typeInput: `${components.vnAutocomplete}[field="$ctrl.greuge.greugeTypeFk"] input`,
|
||||
typeSecondOption: `${components.vnAutocomplete}[field="$ctrl.greuge.greugeTypeFk"] vn-drop-down ul > li`,
|
||||
typeInput: `vn-autocomplete[field="$ctrl.greuge.greugeTypeFk"] input`,
|
||||
typeSecondOption: `vn-autocomplete[field="$ctrl.greuge.greugeTypeFk"] vn-drop-down ul > li`,
|
||||
saveButton: `${components.vnSubmit}`,
|
||||
firstGreugeText: 'vn-client-greuge-index .list-element'
|
||||
},
|
||||
clientMandate: {
|
||||
mandateButton: `${components.vnMenuItem}[ui-sref="client.card.mandate"]`,
|
||||
mandateButton: `vn-menu-item a[ui-sref="client.card.mandate"]`,
|
||||
firstMandateText: 'vn-client-mandate .list-element'
|
||||
},
|
||||
clientInvoices: {
|
||||
invoicesButton: `${components.vnMenuItem}[ui-sref="client.card.invoice"]`,
|
||||
invoicesButton: `vn-menu-item a[ui-sref="client.card.invoice"]`,
|
||||
firstInvoiceText: 'vn-client-invoice .list-element'
|
||||
},
|
||||
itemsIndex: {
|
||||
|
@ -158,167 +158,167 @@ export default {
|
|||
searchResultCloneButton: `vn-item-product .buttons > [icon="icon-clone"]`,
|
||||
acceptClonationAlertButton: `vn-item-index [vn-id="clone"] [response="ACCEPT"]`,
|
||||
searchItemInput: `${components.vnTextfield}`,
|
||||
searchButton: `${components.vnSearchBar} > vn-icon-button`,
|
||||
searchButton: `vn-searchbar vn-icon-button[icon="search"]`,
|
||||
closeItemSummaryPreview: 'vn-item-index [vn-id="preview"] button.close'
|
||||
},
|
||||
itemCreateView: {
|
||||
name: `${components.vnTextfield}[name="name"]`,
|
||||
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)`,
|
||||
typeSelect: `vn-autocomplete[field="$ctrl.item.typeFk"] input`,
|
||||
typeSelectOptionOne: `vn-autocomplete[field="$ctrl.item.typeFk"] vn-drop-down ul > li:nth-child(2)`,
|
||||
intrastatSelect: `vn-autocomplete[field="$ctrl.item.intrastatFk"] input`,
|
||||
intrastatSelectOptionOne: `vn-autocomplete[field="$ctrl.item.intrastatFk"] vn-drop-down ul > li:nth-child(2)`,
|
||||
originSelect: `vn-autocomplete[field="$ctrl.item.originFk"] input`,
|
||||
originSelectOptionOne: `vn-autocomplete[field="$ctrl.item.originFk"] vn-drop-down ul > li:nth-child(2)`,
|
||||
createButton: `${components.vnSubmit}`,
|
||||
cancelButton: `button[ui-sref="item.index"]`
|
||||
|
||||
},
|
||||
itemBasicData: {
|
||||
goToItemIndexButton: 'vn-item-descriptor [ui-sref="item.index"]',
|
||||
basicDataButton: `${components.vnMenuItem}[ui-sref="item.card.data"]`,
|
||||
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)`,
|
||||
basicDataButton: `vn-menu-item a[ui-sref="item.card.data"]`,
|
||||
typeSelect: `vn-autocomplete[field="$ctrl.item.typeFk"] input`,
|
||||
typeSelectOptionTwo: `vn-autocomplete[field="$ctrl.item.typeFk"] vn-drop-down ul > li:nth-child(2)`,
|
||||
intrastatSelect: `vn-autocomplete[field="$ctrl.item.intrastatFk"] input`,
|
||||
intrastatSelectOptionOne: `vn-autocomplete[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"] 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)`,
|
||||
originSelect: `vn-autocomplete[field="$ctrl.item.originFk"] input`,
|
||||
originSelectOptionTwo: `vn-autocomplete[field="$ctrl.item.originFk"] vn-drop-down ul > li:nth-child(2)`,
|
||||
expenceSelect: `vn-autocomplete[field="$ctrl.item.expenceFk"] input`,
|
||||
expenceSelectOptionTwo: `vn-autocomplete[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"]`,
|
||||
firstRemoveTagButton: `vn-item-tags vn-horizontal:nth-child(2) > ${components.vnIcon}[icon="remove_circle_outline"]`,
|
||||
firstTagSelect: `vn-item-tags vn-horizontal:nth-child(2) > ${components.vnAutocomplete}[field="itemTag.tagFk"] input`,
|
||||
tagsButton: `vn-menu-item a[ui-sref="item.card.tags"]`,
|
||||
firstRemoveTagButton: `vn-item-tags vn-horizontal:nth-child(2) > vn-icon[icon="remove_circle_outline"]`,
|
||||
firstTagSelect: `vn-item-tags vn-horizontal:nth-child(2) > vn-autocomplete[field="itemTag.tagFk"] input`,
|
||||
firstTagDisabled: `vn-item-tags vn-horizontal:nth-child(2) > vn-autocomplete > div > div > input`,
|
||||
firstTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(2) > ${components.vnAutocomplete}[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(1)`,
|
||||
firstTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(2) > vn-autocomplete[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(1)`,
|
||||
firstValueInput: `vn-item-tags vn-horizontal:nth-child(2) > vn-textfield[label="Value"] > div > input`,
|
||||
firstRelevancyInput: `vn-horizontal:nth-child(2) > vn-textfield[label="Relevancy"] > div > input`,
|
||||
secondTagSelect: `vn-item-tags vn-horizontal:nth-child(3) > ${components.vnAutocomplete}[field="itemTag.tagFk"] input`,
|
||||
secondTagSelect: `vn-item-tags vn-horizontal:nth-child(3) > vn-autocomplete[field="itemTag.tagFk"] input`,
|
||||
secondTagDisabled: `vn-item-tags vn-horizontal:nth-child(3) > vn-autocomplete > div > div > input`,
|
||||
secondTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(3) > ${components.vnAutocomplete}[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(1)`,
|
||||
secondTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(3) > vn-autocomplete[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(1)`,
|
||||
secondValueInput: `vn-item-tags vn-horizontal:nth-child(3) > vn-textfield[label="Value"] > div > input`,
|
||||
secondRelevancyInput: `vn-horizontal:nth-child(3) > vn-textfield[label="Relevancy"] > div > input`,
|
||||
thirdTagSelect: `vn-item-tags vn-horizontal:nth-child(4) > ${components.vnAutocomplete}[field="itemTag.tagFk"] input`,
|
||||
thirdTagSelect: `vn-item-tags vn-horizontal:nth-child(4) > vn-autocomplete[field="itemTag.tagFk"] input`,
|
||||
thirdTagDisabled: `vn-item-tags vn-horizontal:nth-child(4) > vn-autocomplete > div > div > input`,
|
||||
thirdTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(4) > ${components.vnAutocomplete}[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(1)`,
|
||||
thirdTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(4) > vn-autocomplete[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(1)`,
|
||||
thirdValueInput: `vn-item-tags vn-horizontal:nth-child(4) > vn-textfield[label="Value"] > div > input`,
|
||||
thirdRelevancyInput: `vn-horizontal:nth-child(4) > vn-textfield[label="Relevancy"] > div > input`,
|
||||
fourthTagSelect: `vn-item-tags vn-horizontal:nth-child(5) > ${components.vnAutocomplete}[field="itemTag.tagFk"] input`,
|
||||
fourthTagSelect: `vn-item-tags vn-horizontal:nth-child(5) > vn-autocomplete[field="itemTag.tagFk"] input`,
|
||||
fourthTagDisabled: `vn-item-tags vn-horizontal:nth-child(5) > vn-autocomplete > div > div > input`,
|
||||
fourthTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(5) > ${components.vnAutocomplete}[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(1)`,
|
||||
fourthTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(5) > vn-autocomplete[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(1)`,
|
||||
fourthValueInput: `vn-item-tags vn-horizontal:nth-child(5) > vn-textfield[label="Value"] > div > input`,
|
||||
fourthRelevancyInput: `vn-horizontal:nth-child(5) > vn-textfield[label="Relevancy"] > div > input`,
|
||||
fifthTagSelect: `vn-item-tags vn-horizontal:nth-child(6) > ${components.vnAutocomplete}[field="itemTag.tagFk"] input`,
|
||||
fifthTagSelect: `vn-item-tags vn-horizontal:nth-child(6) > vn-autocomplete[field="itemTag.tagFk"] input`,
|
||||
fifthTagDisabled: `vn-item-tags vn-horizontal:nth-child(6) > vn-autocomplete > div > div > input`,
|
||||
fifthTagSelectOptionFive: `vn-item-tags vn-horizontal:nth-child(6) > ${components.vnAutocomplete}[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(5)`,
|
||||
fifthTagSelectOptionFive: `vn-item-tags vn-horizontal:nth-child(6) > vn-autocomplete[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"]`,
|
||||
addItemTagButton: `vn-icon[icon="add_circle"]`,
|
||||
submitItemTagsButton: `${components.vnSubmit}`
|
||||
},
|
||||
itemTax: {
|
||||
taxButton: `${components.vnMenuItem}[ui-sref="item.card.tax"]`,
|
||||
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)`,
|
||||
taxButton: `vn-menu-item a[ui-sref="item.card.tax"]`,
|
||||
firstClassSelect: `vn-horizontal:nth-child(2) > vn-autocomplete[field="tax.taxClassFk"] input`,
|
||||
firstClassSelectOptionTwo: `vn-horizontal:nth-child(2) > vn-autocomplete vn-drop-down ul > li:nth-child(2)`,
|
||||
secondClassSelect: `vn-horizontal:nth-child(3) > vn-autocomplete[field="tax.taxClassFk"] input`,
|
||||
secondClassSelectOptionOne: `vn-horizontal:nth-child(3) > vn-autocomplete vn-drop-down ul > li:nth-child(1)`,
|
||||
thirdClassSelect: `vn-horizontal:nth-child(4) > vn-autocomplete[field="tax.taxClassFk"] input`,
|
||||
thirdClassSelectOptionTwo: `vn-horizontal:nth-child(4) > vn-autocomplete vn-drop-down ul > li:nth-child(2)`,
|
||||
submitTaxButton: `${components.vnSubmit}`
|
||||
},
|
||||
itemBarcodes: {
|
||||
barcodeButton: `${components.vnMenuItem}[ui-sref="item.card.itemBarcode"]`,
|
||||
addBarcodeButton: `${components.vnIcon}[icon="add_circle"]`,
|
||||
barcodeButton: `vn-menu-item a[ui-sref="item.card.itemBarcode"]`,
|
||||
addBarcodeButton: `vn-icon[icon="add_circle"]`,
|
||||
thirdCodeInput: `vn-item-barcode vn-horizontal:nth-child(4) > ${components.vnTextfield}`,
|
||||
submitBarcodesButton: `${components.vnSubmit}`,
|
||||
firstCodeRemoveButton: `vn-horizontal:nth-child(2) > ${components.vnIcon}[icon="remove_circle_outline"]`
|
||||
firstCodeRemoveButton: `vn-horizontal:nth-child(2) > vn-icon[icon="remove_circle_outline"]`
|
||||
},
|
||||
itemNiches: {
|
||||
nicheButton: `${components.vnMenuItem}[ui-sref="item.card.niche"]`,
|
||||
addNicheButton: `${components.vnIcon}[icon="add_circle"]`,
|
||||
firstWarehouseSelect: `${components.vnAutocomplete}[field="itemNiche.warehouseFk"] input`,
|
||||
nicheButton: `vn-menu-item a[ui-sref="item.card.niche"]`,
|
||||
addNicheButton: `vn-icon[icon="add_circle"]`,
|
||||
firstWarehouseSelect: `vn-autocomplete[field="itemNiche.warehouseFk"] input`,
|
||||
firstWarehouseDisabled: `vn-horizontal:nth-child(2) > vn-textfield[label="Warehouse"] > div > input`,
|
||||
firstWarehouseSelectSecondOption: `${components.vnAutocomplete}[field="itemNiche.warehouseFk"] vn-drop-down ul > li:nth-child(2)`,
|
||||
firstWarehouseSelectSecondOption: `vn-autocomplete[field="itemNiche.warehouseFk"] vn-drop-down ul > li:nth-child(2)`,
|
||||
firstCodeInput: `vn-horizontal:nth-child(2) > vn-textfield[label="Code"] > div > input`,
|
||||
secondWarehouseSelect: `vn-horizontal:nth-child(3) > ${components.vnAutocomplete}[field="itemNiche.warehouseFk"] input`,
|
||||
secondWarehouseSelect: `vn-horizontal:nth-child(3) > vn-autocomplete[field="itemNiche.warehouseFk"] input`,
|
||||
secondWarehouseDisabled: `vn-horizontal:nth-child(3) > vn-textfield[label="Warehouse"] > div > input`,
|
||||
secondCodeInput: `vn-horizontal:nth-child(3) > vn-textfield[label="Code"] > div > input`,
|
||||
secondNicheRemoveButton: `vn-horizontal:nth-child(3) > ${components.vnIcon}[icon="remove_circle_outline"]`,
|
||||
thirdWarehouseSelect: `vn-horizontal:nth-child(4) > ${components.vnAutocomplete}[field="itemNiche.warehouseFk"] input`,
|
||||
secondNicheRemoveButton: `vn-horizontal:nth-child(3) > vn-icon[icon="remove_circle_outline"]`,
|
||||
thirdWarehouseSelect: `vn-horizontal:nth-child(4) > vn-autocomplete[field="itemNiche.warehouseFk"] input`,
|
||||
thirdWarehouseDisabled: `vn-horizontal:nth-child(4) > vn-textfield[label="Warehouse"] > div > input`,
|
||||
thirdWarehouseSelectFourthOption: `vn-horizontal:nth-child(4) > ${components.vnAutocomplete}[field="itemNiche.warehouseFk"] vn-drop-down ul > li:nth-child(4)`,
|
||||
thirdWarehouseSelectFourthOption: `vn-horizontal:nth-child(4) > vn-autocomplete[field="itemNiche.warehouseFk"] vn-drop-down ul > li:nth-child(4)`,
|
||||
thirdCodeInput: `vn-horizontal:nth-child(4) > vn-textfield[label="Code"] > div > input`,
|
||||
submitNichesButton: `${components.vnSubmit}`
|
||||
},
|
||||
itemBotanical: {
|
||||
botanicalButton: `${components.vnMenuItem}[ui-sref="item.card.botanical"]`,
|
||||
botanicalButton: `vn-menu-item a[ui-sref="item.card.botanical"]`,
|
||||
botanicalInput: `vn-horizontal:nth-child(2) > ${components.vnTextfield}`,
|
||||
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)`,
|
||||
genusSelect: `vn-autocomplete[field="$ctrl.botanical.genusFk"] input`,
|
||||
genusSelectOptionOne: `vn-autocomplete[field="$ctrl.botanical.genusFk"] vn-drop-down ul > li:nth-child(1)`,
|
||||
genusSelectOptionTwo: `vn-autocomplete[field="$ctrl.botanical.genusFk"] vn-drop-down ul > li:nth-child(2)`,
|
||||
speciesSelect: `vn-autocomplete[field="$ctrl.botanical.specieFk"] input`,
|
||||
speciesSelectOptionOne: `vn-autocomplete[field="$ctrl.botanical.specieFk"] vn-drop-down ul > li:nth-child(1)`,
|
||||
speciesSelectOptionTwo: `vn-autocomplete[field="$ctrl.botanical.specieFk"] vn-drop-down ul > li:nth-child(2)`,
|
||||
submitBotanicalButton: `${components.vnSubmit}`
|
||||
},
|
||||
itemSummary: {
|
||||
basicData: `${components.vnItemSummary} vn-vertical[name="basicData"]`,
|
||||
vat: `${components.vnItemSummary} vn-vertical[name="tax"]`,
|
||||
tags: `${components.vnItemSummary} vn-vertical[name="tags"]`,
|
||||
niche: `${components.vnItemSummary} vn-vertical[name="niche"]`,
|
||||
botanical: `${components.vnItemSummary} vn-vertical[name="botanical"]`,
|
||||
barcode: `${components.vnItemSummary} vn-vertical[name="barcode"]`
|
||||
basicData: `vn-item-summary vn-vertical[name="basicData"]`,
|
||||
vat: `vn-item-summary vn-vertical[name="tax"]`,
|
||||
tags: `vn-item-summary vn-vertical[name="tags"]`,
|
||||
niche: `vn-item-summary vn-vertical[name="niche"]`,
|
||||
botanical: `vn-item-summary vn-vertical[name="botanical"]`,
|
||||
barcode: `vn-item-summary vn-vertical[name="barcode"]`
|
||||
},
|
||||
ticketsIndex: {
|
||||
createTicketButton: `${components.vnFloatButton}`,
|
||||
searchResult: `table > tbody > tr`,
|
||||
searchTicketInput: `${components.vnTextfield}`,
|
||||
searchButton: `${components.vnSearchBar} > vn-icon-button`
|
||||
searchButton: `vn-searchbar vn-icon-button[icon="search"]`
|
||||
},
|
||||
ticketNotes: {
|
||||
notesButton: `${components.vnMenuItem}[ui-sref="ticket.card.observation"]`,
|
||||
firstNoteRemoveButton: `${components.vnIcon}[icon="remove_circle_outline"]`,
|
||||
addNoteButton: `${components.vnIcon}[icon="add_circle"]`,
|
||||
firstNoteSelect: `${components.vnAutocomplete}[field="ticketObservation.observationTypeFk"] input`,
|
||||
firstNoteSelectSecondOption: `${components.vnAutocomplete}[field="ticketObservation.observationTypeFk"] vn-drop-down ul > li:nth-child(2)`,
|
||||
notesButton: `vn-menu-item a[ui-sref="ticket.card.observation"]`,
|
||||
firstNoteRemoveButton: `vn-icon[icon="remove_circle_outline"]`,
|
||||
addNoteButton: `vn-icon[icon="add_circle"]`,
|
||||
firstNoteSelect: `vn-autocomplete[field="ticketObservation.observationTypeFk"] input`,
|
||||
firstNoteSelectSecondOption: `vn-autocomplete[field="ticketObservation.observationTypeFk"] vn-drop-down ul > li:nth-child(2)`,
|
||||
firstNoteDisabled: `vn-textfield[label="Observation type"] > div > input`,
|
||||
firstDescriptionInput: `vn-textfield[label="Description"] > div > input`,
|
||||
submitNotesButton: `${components.vnSubmit}`
|
||||
},
|
||||
ticketExpedition: {
|
||||
expeditionButton: `${components.vnMenuItem}[ui-sref="ticket.card.expedition"]`,
|
||||
expeditionButton: `vn-menu-item a[ui-sref="ticket.card.expedition"]`,
|
||||
secondExpeditionRemoveButton: `body > vn-app > vn-vertical > vn-vertical > ui-view > vn-ticket-card > vn-main-block > vn-horizontal > vn-one > vn-vertical > vn-ticket-expedition > vn-vertical > vn-card > div > vn-vertical > vn-one > vn-horizontal:nth-child(2) > vn-one:nth-child(1) > i`,
|
||||
secondExpeditionText: `body > vn-app > vn-vertical > vn-vertical > ui-view > vn-ticket-card > vn-main-block > vn-horizontal > vn-one > vn-vertical > vn-ticket-expedition > vn-vertical > vn-card > div > vn-vertical > vn-one > vn-horizontal:nth-child(2)`
|
||||
},
|
||||
ticketPackages: {
|
||||
packagesButton: `${components.vnMenuItem}[ui-sref="ticket.card.package.index"]`,
|
||||
firstPackageSelect: `${components.vnAutocomplete}[label="Package"] > div > div > input`,
|
||||
firstPackageSelectOptionThree: `${components.vnAutocomplete}[label="Package"] vn-drop-down ul > li:nth-child(3)`,
|
||||
packagesButton: `vn-menu-item a[ui-sref="ticket.card.package.index"]`,
|
||||
firstPackageSelect: `vn-autocomplete[label="Package"] > div > div > input`,
|
||||
firstPackageSelectOptionThree: `vn-autocomplete[label="Package"] vn-drop-down ul > li:nth-child(3)`,
|
||||
firstQuantityInput: `vn-textfield[label="Quantity"] > div > input`,
|
||||
firstRemovePackageButton: `vn-icon[vn-tooltip="Remove package"]`,
|
||||
addPackageButton: `vn-icon[vn-tooltip="Add package"]`,
|
||||
clearPackageSelectButton: `${components.vnAutocomplete}[label="Package"] > div > div > div > vn-icon > i`,
|
||||
clearPackageSelectButton: `vn-autocomplete[label="Package"] > div > div > div > vn-icon > i`,
|
||||
savePackagesButton: `${components.vnSubmit}`
|
||||
},
|
||||
ticketSales: {
|
||||
saleButton: `${components.vnMenuItem}[ui-sref="ticket.card.sale"]`,
|
||||
saleButton: `vn-menu-item a[ui-sref="ticket.card.sale"]`,
|
||||
firstSaleText: `table > tbody > tr:nth-child(1)`,
|
||||
secondSaleText: `table > tbody > tr:nth-child(2)`
|
||||
},
|
||||
ticketTracking: {
|
||||
trackingButton: `${components.vnMenuItem}[ui-sref="ticket.card.tracking.index"]`,
|
||||
trackingButton: `vn-menu-item a[ui-sref="ticket.card.tracking.index"]`,
|
||||
createStateButton: `${components.vnFloatButton}`,
|
||||
firstSaleText: `table > tbody > tr:nth-child(1)`,
|
||||
secondSaleText: `table > tbody > tr:nth-child(2)`
|
||||
},
|
||||
createStateView: {
|
||||
stateInput: `${components.vnAutocomplete}[field="$ctrl.ticket.stateFk"] > div > div > input`,
|
||||
stateInputOptionOne: `${components.vnAutocomplete}[field="$ctrl.ticket.stateFk"] vn-drop-down ul > li:nth-child(1)`,
|
||||
clearStateInputButton: `${components.vnAutocomplete}[field="$ctrl.ticket.stateFk"] > div > div > div > vn-icon > i`,
|
||||
stateInput: `vn-autocomplete[field="$ctrl.ticket.stateFk"] > div > div > input`,
|
||||
stateInputOptionOne: `vn-autocomplete[field="$ctrl.ticket.stateFk"] vn-drop-down ul > li:nth-child(1)`,
|
||||
clearStateInputButton: `vn-autocomplete[field="$ctrl.ticket.stateFk"] > div > div > div > vn-icon > i`,
|
||||
saveStateButton: `${components.vnSubmit}`
|
||||
}
|
||||
};
|
||||
|
|
|
@ -65,7 +65,7 @@ describe('Client', () => {
|
|||
.waitToClick(selectors.clientAddresses.saveButton)
|
||||
.waitForSnackbar()
|
||||
.then(result => {
|
||||
expect(result).toContain('No field can be blank');
|
||||
expect(result).toContain('type cannot be blank');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ describe('Ticket', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it(`should attempt create a new state but receive an error if state have been cleared`, () => {
|
||||
it(`should attempt create a new state then clear and save it`, () => {
|
||||
return nightmare
|
||||
.waitToClick(selectors.createStateView.stateInput)
|
||||
.waitToClick(selectors.createStateView.stateInputOptionOne)
|
||||
|
@ -73,7 +73,17 @@ describe('Ticket', () => {
|
|||
.click(selectors.createStateView.saveStateButton)
|
||||
.waitForSnackbar()
|
||||
.then(result => {
|
||||
expect(result).toContain('No changes to save');
|
||||
expect(result).toContain('Data saved!');
|
||||
});
|
||||
});
|
||||
|
||||
it('should access to the create state view by clicking the create floating button', () => {
|
||||
return nightmare
|
||||
.click(selectors.ticketTracking.createStateButton)
|
||||
.wait(selectors.createStateView.stateInput)
|
||||
.parsedUrl()
|
||||
.then(url => {
|
||||
expect(url.hash).toContain('tracking/edit');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
module.exports = Self => {
|
||||
Self.installCrudModel('crudAddressObservations');
|
||||
};
|
|
@ -1,3 +1,25 @@
|
|||
module.exports = function(Self) {
|
||||
require('../methods/address/crudAddressObservations')(Self);
|
||||
Self.validatesPresenceOf('observationTypeFk', {
|
||||
message: 'Observation type cannot be blank'
|
||||
});
|
||||
|
||||
Self.validateAsync('typeUnique', typeIsUnique, {
|
||||
message: 'Observation type must be unique'
|
||||
});
|
||||
async function typeIsUnique(err, done) {
|
||||
let filter = {
|
||||
fields: ['id'],
|
||||
where: {
|
||||
observationTypeFk: this.observationTypeFk,
|
||||
addressFk: this.addressFk
|
||||
}
|
||||
};
|
||||
|
||||
if (this.id)
|
||||
filter.where.id = {neq: this.id};
|
||||
|
||||
if (await Self.findOne(filter))
|
||||
err();
|
||||
done();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -17,5 +17,6 @@
|
|||
"The IBAN does not have the correct format": "The IBAN does not have the correct format",
|
||||
"That payment method requires an IBAN": "That payment method requires an IBAN",
|
||||
"State cannot be blank": "State cannot be blank",
|
||||
"Cannot change the payment method if no salesperson": "Cannot change the payment method if no salesperson"
|
||||
"Cannot change the payment method if no salesperson": "Cannot change the payment method if no salesperson",
|
||||
"Observation type cannot be blank": "Observation type cannot be blank"
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
"That payment method requires an IBAN": "El método de pago seleccionado requiere que se especifique el IBAN",
|
||||
"State cannot be blank": "El estado no puede estar en blanco",
|
||||
"Cannot change the payment method if no salesperson": "No se puede cambiar la forma de pago si no hay comercial asignado",
|
||||
"EXPIRED_DATE": "EXPIRED_DATE",
|
||||
"NO_AGENCY_AVAILABLE": "NO_AGENCY_AVAILABLE"
|
||||
"can't be blank": "El campo no puede estar vacío",
|
||||
"Observation type cannot be blank": "El tipo de observación no puede estar en blanco",
|
||||
"Observation type must be unique": "El tipo de observación no puede repetirse"
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
module.exports = Self => {
|
||||
Self.installCrudModel('crudItemTags');
|
||||
};
|
|
@ -1,46 +0,0 @@
|
|||
module.exports = function(Self) {
|
||||
Self.installCrudModel = function(methodName) {
|
||||
let Model = this;
|
||||
Model.remoteMethod(methodName, {
|
||||
description: 'create, update or delete model',
|
||||
accessType: 'WRITE',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'crudStruct',
|
||||
type: 'Object',
|
||||
require: true,
|
||||
description: 'object with instances of model to create, update or delete, Example: {create: [], update: [], delete: []}',
|
||||
http: {source: 'body'}
|
||||
}
|
||||
],
|
||||
http: {
|
||||
path: `/${methodName}`,
|
||||
verb: 'post'
|
||||
}
|
||||
});
|
||||
Model[methodName] = async crudObject => {
|
||||
let promises = [];
|
||||
let transaction = await Model.beginTransaction({});
|
||||
let options = {transaction: transaction};
|
||||
|
||||
try {
|
||||
if (crudObject.delete && crudObject.delete.length) {
|
||||
promises.push(Model.destroyAll({id: {inq: crudObject.delete}}, options));
|
||||
}
|
||||
if (crudObject.create && crudObject.create.length) {
|
||||
promises.push(Model.create(crudObject.create, options));
|
||||
}
|
||||
if (crudObject.update) {
|
||||
crudObject.update.forEach(toUpdate => {
|
||||
promises.push(Model.upsert(toUpdate, options));
|
||||
});
|
||||
}
|
||||
await Promise.all(promises);
|
||||
await transaction.commit();
|
||||
} catch (error) {
|
||||
await transaction.rollback();
|
||||
throw Array.isArray(error) ? error[0] : error;
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
|
@ -1,4 +1,3 @@
|
|||
module.exports = Self => {
|
||||
require('../methods/item-tag/crudItemTags')(Self);
|
||||
require('../methods/item-tag/filterItemTags')(Self);
|
||||
};
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
module.exports = function(Self) {
|
||||
Self.setup = function() {
|
||||
Self.super_.setup.call(this);
|
||||
|
||||
/* let disableMethods = {
|
||||
/*
|
||||
let disableMethods = {
|
||||
create: true,
|
||||
replaceOrCreate: true,
|
||||
patchOrCreate: true,
|
||||
|
@ -22,7 +22,9 @@ module.exports = function(Self) {
|
|||
};
|
||||
for (let method in disableMethods) {
|
||||
// this.disableRemoteMethod(method, disableMethods[method]);
|
||||
} */
|
||||
}
|
||||
*/
|
||||
this.installCrudModel('crud');
|
||||
};
|
||||
|
||||
Self.defineScope = function(serverFilter) {
|
||||
|
@ -116,8 +118,51 @@ module.exports = function(Self) {
|
|||
};
|
||||
};
|
||||
|
||||
require('../methods/vnModel/rawSql')(Self);
|
||||
require('../methods/vnModel/installMethod')(Self);
|
||||
require('../methods/vnModel/validateBinded')(Self);
|
||||
require('../methods/vnModel/installCrudModel')(Self);
|
||||
Self.installCrudModel = function(methodName) {
|
||||
this.remoteMethod(methodName, {
|
||||
description: 'Create, update or/and delete instances from model in a single request',
|
||||
accessType: 'WRITE',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'actions',
|
||||
type: 'Object',
|
||||
require: true,
|
||||
description: 'Instances to update, example: {create: [instances], update: [instances], delete: [ids]}',
|
||||
http: {source: 'body'}
|
||||
}
|
||||
],
|
||||
http: {
|
||||
path: `/${methodName}`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
this[methodName] = async actions => {
|
||||
let promises = [];
|
||||
let transaction = await this.beginTransaction({});
|
||||
let options = {transaction: transaction};
|
||||
|
||||
try {
|
||||
if (actions.delete && actions.delete.length) {
|
||||
promises.push(this.destroyAll({id: {inq: actions.delete}}, options));
|
||||
}
|
||||
if (actions.create && actions.create.length) {
|
||||
promises.push(this.create(actions.create, options));
|
||||
}
|
||||
if (actions.update) {
|
||||
actions.update.forEach(toUpdate => {
|
||||
promises.push(this.upsert(toUpdate, options));
|
||||
});
|
||||
}
|
||||
await Promise.all(promises);
|
||||
await transaction.commit();
|
||||
} catch (error) {
|
||||
await transaction.rollback();
|
||||
throw Array.isArray(error) ? error[0] : error;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
require('../methods/vn-model/rawSql')(Self);
|
||||
require('../methods/vn-model/installMethod')(Self);
|
||||
require('../methods/vn-model/validateBinded')(Self);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue