-
+ ng-blur="$ctrl.hasFocus = false"/>
{
@@ -30,11 +31,13 @@ export default class Controller {
this.$scope.form.$setDirty();
}
}
+
_unsetDirtyForm() {
if (this.$scope.form) {
this.$scope.form.$setPristine();
}
}
+
_equalBarcodes(oldBarcode, newBarcode) {
return oldBarcode.id === newBarcode.id && oldBarcode.code === newBarcode.code;
}
diff --git a/client/item/src/niche/item-niche.html b/client/item/src/niche/item-niche.html
index ae30034db7..068eedb41d 100644
--- a/client/item/src/niche/item-niche.html
+++ b/client/item/src/niche/item-niche.html
@@ -8,7 +8,8 @@
Item Niches
+
+
{
this.niches = response.data;
this.setOldNiches(response);
@@ -95,6 +97,7 @@ export default class Controller {
create: [],
update: []
};
+
this.niches.forEach(niche => {
let isNewNiche = !niche.id;
diff --git a/client/item/src/niche/item-niche.spec.js b/client/item/src/niche/item-niche.spec.js
index 3218f262e4..e223133d93 100644
--- a/client/item/src/niche/item-niche.spec.js
+++ b/client/item/src/niche/item-niche.spec.js
@@ -92,7 +92,7 @@ describe('Item', () => {
});
describe('submit()', () => {
- it("should return an error message 'The niche must be unique' when the niche code isnt unique", () => {
+ it("should return an error message 'The niche must be unique' when the niche warehouse isnt unique", () => {
controller.$scope.form = {};
spyOn(controller.vnApp, 'showMessage').and.callThrough();
controller.niches = [
diff --git a/client/item/src/tags/item-tags.html b/client/item/src/tags/item-tags.html
index 318a5dec7b..c92a13292f 100644
--- a/client/item/src/tags/item-tags.html
+++ b/client/item/src/tags/item-tags.html
@@ -8,6 +8,7 @@
Item tags
+
+
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
diff --git a/client/salix/src/components/searchbar/searchbar.js b/client/salix/src/components/searchbar/searchbar.js
index 324ddf5a47..81e71198cf 100644
--- a/client/salix/src/components/searchbar/searchbar.js
+++ b/client/salix/src/components/searchbar/searchbar.js
@@ -1,12 +1,10 @@
import ngModule from '../../module';
export default class Controller {
- constructor($element, $scope, $document, $compile, vnPopover, $timeout, $state, $transitions) {
+ constructor($element, $scope, $compile, $timeout, $state, $transitions) {
this.element = $element[0];
- this.$scope = $scope;
- this.$document = $document;
+ this.$ = $scope;
this.$compile = $compile;
- this.vnPopover = vnPopover;
this.$timeout = $timeout;
this.stringSearch = '';
this.$state = $state;
@@ -91,23 +89,32 @@ export default class Controller {
filter = this.getFiltersFromString(this.stringSearch);
}
- this.child = this.vnPopover.showComponent(this.popover, this.$scope, this.element);
+ this.$child = this.$compile(`<${this.popover}/>`)(this.$.$new());
- // XXX: ¿Existe una forma más adecuada de acceder al controlador de un componente?
- var childCtrl = angular.element(this.child).isolateScope().$ctrl;
+ var childCtrl = this.$child.isolateScope().$ctrl;
childCtrl.filter = Object.assign({}, filter);
childCtrl.onSubmit = filter => this.onChildSubmit(filter);
if (this.data)
childCtrl.data = Object.assign({}, this.data);
+
event.preventDefault();
+
+ this.$.popover.parent = this.element;
+ this.$.popover.child = this.$child[0];
+ this.$.popover.show();
+ }
+
+ onPopoverClose() {
+ this.$child.scope().$destroy();
+ this.$child.remove();
+ this.$child = null;
}
onChildSubmit(filter) {
+ this.$.popover.hide();
this.stringSearch = this.createStringFromObject(filter);
this.clearFilter();
- this.$timeout(() => {
- this.onSubmit();
- });
+ this.$timeout(() => this.onSubmit());
}
onSubmit() {
@@ -120,12 +127,6 @@ export default class Controller {
if (this.onSearch)
this.onSearch();
- if (angular.element(this.child)) {
- if (angular.element(this.child).scope())
- angular.element(this.child).scope().$destroy();
- angular.element(this.child).remove();
- }
- delete this.child;
this.pushFiltersToState(filter);
}
@@ -139,12 +140,10 @@ export default class Controller {
let filter = JSON.parse(decodeURIComponent(this.$state.params.q));
this.stringSearch = this.createStringFromObject(filter);
}
- this.$timeout(() => {
- this.onSubmit();
- });
+ this.$timeout(() => this.onSubmit());
}
}
-Controller.$inject = ['$element', '$scope', '$document', '$compile', 'vnPopover', '$timeout', '$state', '$transitions'];
+Controller.$inject = ['$element', '$scope', '$compile', '$timeout', '$state', '$transitions'];
ngModule.component('vnSearchbar', {
template: require('./searchbar.html'),
diff --git a/client/ticket/routes.json b/client/ticket/routes.json
index c35adf301d..8f88f96849 100644
--- a/client/ticket/routes.json
+++ b/client/ticket/routes.json
@@ -46,6 +46,18 @@
"icon": "settings"
}
},
+ {
+ "url": "/observations",
+ "state": "ticket.card.observations",
+ "component": "vn-ticket-observations",
+ "params": {
+ "ticket": "$ctrl.ticket"
+ },
+ "menu": {
+ "description": "Notes",
+ "icon": "insert_drive_file"
+ }
+ },
{
"url" : "/package",
"abstract": true,
@@ -64,6 +76,18 @@
"icon": "icon-bucket"
}
},
+ {
+ "url" : "/review",
+ "state": "ticket.card.review",
+ "component": "vn-ticket-review",
+ "params": {
+ "ticket": "$ctrl.ticket"
+ },
+ "menu": {
+ "description": "Review",
+ "icon": "remove_red_eye"
+ }
+ },
{
"url" : "/sale",
"state": "ticket.card.sale",
diff --git a/client/ticket/src/locale/es.yml b/client/ticket/src/locale/es.yml
index 1f272d4201..e65b6ab54c 100644
--- a/client/ticket/src/locale/es.yml
+++ b/client/ticket/src/locale/es.yml
@@ -1 +1,6 @@
-Tickets: Tickets
\ No newline at end of file
+Tickets: Tickets
+Notes: Notas
+Observation type: Tipo de observación
+Description: Descripción
+The observation type must be unique: El tipo de observación debe ser único
+Some fields are invalid: Algunos campos no son válidos
\ No newline at end of file
diff --git a/client/ticket/src/notes/ticket-observations.html b/client/ticket/src/notes/ticket-observations.html
new file mode 100644
index 0000000000..b48ec5a727
--- /dev/null
+++ b/client/ticket/src/notes/ticket-observations.html
@@ -0,0 +1,60 @@
+
+
+
\ No newline at end of file
diff --git a/client/ticket/src/notes/ticket-observations.js b/client/ticket/src/notes/ticket-observations.js
new file mode 100644
index 0000000000..793865fde6
--- /dev/null
+++ b/client/ticket/src/notes/ticket-observations.js
@@ -0,0 +1,140 @@
+import ngModule from '../module';
+
+class TicketObservations {
+ constructor($stateParams, $scope, $http, $translate, vnApp) {
+ this.params = $stateParams;
+ this.$scope = $scope;
+ this.$http = $http;
+ this.$translate = $translate;
+ this.vnApp = vnApp;
+
+ this.ticketObservations = [];
+ this.oldObservations = {};
+ this.removedObservations = [];
+ }
+
+ _setIconAdd() {
+ if (this.ticketObservations.length) {
+ this.ticketObservations.map(element => {
+ element.showAddIcon = false;
+ return true;
+ });
+ this.ticketObservations[this.ticketObservations.length - 1].showAddIcon = true;
+ }
+ }
+
+ _setDirtyForm() {
+ if (this.$scope.form) {
+ this.$scope.form.$setDirty();
+ }
+ }
+
+ _unsetDirtyForm() {
+ if (this.$scope.form) {
+ this.$scope.form.$setPristine();
+ }
+ }
+
+ addObservation() {
+ this.ticketObservations.push({description: null, ticketFk: this.params.id, showAddIcon: true});
+ this._setIconAdd();
+ }
+
+ removeObservation(index) {
+ let item = this.ticketObservations[index];
+ if (item) {
+ this.ticketObservations.splice(index, 1);
+ this._setIconAdd();
+ if (item.id) {
+ this.removedObservations.push(item.id);
+ this._setDirtyForm();
+ }
+ }
+ }
+
+ _equalObservations(oldObservation, newObservation) {
+ return oldObservation.id === newObservation.id && oldObservation.observationTypeFk === newObservation.observationTypeFk && oldObservation.description === newObservation.description;
+ }
+
+ setOldObservations(response) {
+ this._setIconAdd();
+ response.data.forEach(observation => {
+ this.oldObservations[observation.id] = Object.assign({}, observation);
+ });
+ }
+
+ getObservations() {
+ let filter = {
+ where: {ticketFk: this.params.id},
+ include: ['observationType']
+ };
+
+ this.$http.get(`/ticket/api/TicketObservations?filter=${JSON.stringify(filter)}`).then(response => {
+ this.ticketObservations = response.data;
+ this.setOldObservations(response);
+ });
+ }
+
+ submit() {
+ let typesDefined = [];
+ let repeatedType = false;
+ let canSubmit;
+ let observationsObj = {
+ delete: this.removedObservations,
+ create: [],
+ update: []
+ };
+
+ this.ticketObservations.forEach(observation => {
+ let isNewObservation = !observation.id;
+
+ delete observation.showAddIcon;
+
+ if (typesDefined.indexOf(observation.observationTypeFk) !== -1) {
+ repeatedType = true;
+ return;
+ }
+ typesDefined.push(observation.observationTypeFk);
+
+ if (isNewObservation && observation.description && observation.observationTypeFk) {
+ observationsObj.create.push(observation);
+ }
+
+ if (!isNewObservation && !this._equalObservations(this.oldObservations[observation.id], observation)) {
+ observationsObj.update.push(observation);
+ }
+ });
+
+ if (this.$scope.form.$invalid) {
+ return this.vnApp.showMessage(this.$translate.instant('Some fields are invalid'));
+ }
+
+ if (repeatedType) {
+ return this.vnApp.showMessage(this.$translate.instant('The observation type must be unique'));
+ }
+
+ canSubmit = observationsObj.update.length > 0 || observationsObj.create.length > 0 || observationsObj.delete.length > 0;
+
+ if (canSubmit) {
+ return this.$http.post(`/ticket/api/TicketObservations/crudTicketObservations`, observationsObj).then(() => {
+ this.getObservations();
+ this._unsetDirtyForm();
+ });
+ }
+ this.vnApp.showMessage(this.$translate.instant('No changes to save'));
+ }
+
+ $onInit() {
+ this.getObservations();
+ }
+}
+
+TicketObservations.$inject = ['$stateParams', '$scope', '$http', '$translate', 'vnApp'];
+
+ngModule.component('vnTicketObservations', {
+ template: require('./ticket-observations.html'),
+ controller: TicketObservations,
+ bindings: {
+ ticket: '<'
+ }
+});
diff --git a/client/ticket/src/notes/ticket-observations.spec.js b/client/ticket/src/notes/ticket-observations.spec.js
new file mode 100644
index 0000000000..982cfb61b1
--- /dev/null
+++ b/client/ticket/src/notes/ticket-observations.spec.js
@@ -0,0 +1,143 @@
+import './ticket-observations.js';
+
+describe('ticket', () => {
+ describe('Component vnTicketObservations', () => {
+ let $componentController;
+ let $state;
+ let controller;
+ let $httpBackend;
+
+ beforeEach(() => {
+ angular.mock.module('ticket');
+ });
+
+ beforeEach(angular.mock.inject((_$componentController_, _$state_, _$httpBackend_) => {
+ $componentController = _$componentController_;
+ $state = _$state_;
+ $httpBackend = _$httpBackend_;
+ controller = $componentController('vnTicketObservations', {$state: $state});
+ }));
+
+ describe('add / remove observation', () => {
+ it('should add one empty observation into controller observations collection and call _setIconAdd()', () => {
+ controller.ticketObservations = [];
+ spyOn(controller, '_setIconAdd').and.callThrough();
+ controller.addObservation();
+
+ expect(controller._setIconAdd).toHaveBeenCalledWith();
+ expect(controller.ticketObservations.length).toEqual(1);
+ expect(controller.ticketObservations[0].id).toBe(undefined);
+ expect(controller.ticketObservations[0].showAddIcon).toBeTruthy();
+ });
+
+ it('should remove an observation that occupies the position in the index given and call _setIconAdd()', () => {
+ let index = 2;
+ controller.ticketObservations = [
+ {id: 1, observationTypeFk: 1, description: 'one', showAddIcon: false},
+ {id: 2, observationTypeFk: 2, description: 'two', showAddIcon: false},
+ {id: 3, observationTypeFk: 3, description: 'three', showAddIcon: true}
+ ];
+
+ spyOn(controller, '_setIconAdd').and.callThrough();
+
+ controller.removeObservation(index);
+
+ expect(controller._setIconAdd).toHaveBeenCalledWith();
+ expect(controller.ticketObservations.length).toEqual(2);
+ expect(controller.ticketObservations[0].showAddIcon).toBeFalsy();
+ expect(controller.ticketObservations[1].showAddIcon).toBeTruthy();
+ expect(controller.ticketObservations[index]).toBe(undefined);
+ });
+ });
+
+ describe('_equalObservations()', () => {
+ it('should return true if two observations are equals independent of control attributes', () => {
+ let observationOne = {id: 1, observationTypeFk: 1, description: 'one', showAddIcon: true};
+ let observationTwo = {id: 1, observationTypeFk: 1, description: 'one', showAddIcon: false};
+ let equals = controller._equalObservations(observationOne, observationTwo);
+
+ expect(equals).toBeTruthy();
+ });
+
+ it('should return false if two observations aint equals independent of control attributes', () => {
+ let observationOne = {id: 1, observationTypeFk: 1, description: 'one', showAddIcon: true};
+ let observationTwo = {id: 1, observationTypeFk: 1, description: 'two', showAddIcon: true};
+ let equals = controller._equalObservations(observationOne, observationTwo);
+
+ expect(equals).toBeFalsy();
+ });
+ });
+
+ describe('get Observations()', () => {
+ it('should perform a GET query to receive the ticket observations', () => {
+ let res = [{id: 1, observationTypeFk: 1, description: 'one'}];
+
+ $httpBackend.whenGET(`/ticket/api/TicketObservations?filter={"where":{},"include":["observationType"]}`).respond(res);
+ $httpBackend.expectGET(`/ticket/api/TicketObservations?filter={"where":{},"include":["observationType"]}`);
+ controller.getObservations();
+ $httpBackend.flush();
+ });
+ });
+
+ describe('submit()', () => {
+ it("should return an error message 'The observation type must be unique'", () => {
+ controller.$scope.form = {};
+ spyOn(controller.vnApp, 'showMessage').and.callThrough();
+ controller.ticketObservations = [
+ {id: 1, observationTypeFk: 1, description: 'one', itemFk: 1},
+ {observationTypeFk: 1, description: 'one', itemFk: 1}
+ ];
+ controller.oldObservations = {1: {id: 1, observationTypeFk: 1, description: 'one', itemFk: 1}};
+ controller.submit();
+
+ expect(controller.vnApp.showMessage).toHaveBeenCalledWith('The observation type must be unique');
+ });
+
+ it("should perfom a query to delete observations", () => {
+ controller.$scope.form = {$setPristine: () => {}};
+ controller.oldObservations = {1: {id: 1, observationTypeFk: 1, description: 'one'}};
+ controller.ticketObservations = [];
+ controller.removedObservations = [1];
+
+ $httpBackend.whenGET(`/ticket/api/TicketObservations?filter={"where":{},"include":["observationType"]}`).respond([]);
+ $httpBackend.expectPOST(`/ticket/api/TicketObservations/crudTicketObservations`).respond('ok!');
+ controller.submit();
+ $httpBackend.flush();
+ });
+
+ it("should perfom a query to update observations", () => {
+ controller.$scope.form = {$setPristine: () => {}};
+ controller.ticketObservations = [{id: 1, observationTypeFk: 1, description: 'number one!'}];
+ controller.oldObservations = {1: {id: 1, observationTypeFk: 1, description: 'one'}};
+
+ $httpBackend.whenGET(`/ticket/api/TicketObservations?filter={"where":{},"include":["observationType"]}`).respond([]);
+ $httpBackend.expectPOST(`/ticket/api/TicketObservations/crudTicketObservations`).respond('ok!');
+ controller.submit();
+ $httpBackend.flush();
+ });
+
+ it("should perfom a query to create new observation", () => {
+ controller.$scope.form = {$setPristine: () => {}};
+ controller.ticketObservations = [{observationTypeFk: 2, description: 'two'}];
+
+ $httpBackend.whenGET(`/ticket/api/TicketObservations?filter={"where":{},"include":["observationType"]}`).respond([]);
+ $httpBackend.expectPOST(`/ticket/api/TicketObservations/crudTicketObservations`).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.oldObservations = [
+ {id: 1, observationTypeFk: 1, description: 'one', showAddIcon: false},
+ {id: 2, observationTypeFk: 2, description: 'two', showAddIcon: true}
+ ];
+ controller.ticketObservations = [];
+ controller.submit();
+
+ expect(controller.vnApp.showMessage).toHaveBeenCalledWith('No changes to save');
+ });
+ });
+ });
+});
diff --git a/client/ticket/src/review/locale/es.yml b/client/ticket/src/review/locale/es.yml
new file mode 100644
index 0000000000..ae3a7e678e
--- /dev/null
+++ b/client/ticket/src/review/locale/es.yml
@@ -0,0 +1,4 @@
+date : Fecha
+Employee : Empleado
+State: Estado
+Review: Revision
\ No newline at end of file
diff --git a/client/ticket/src/review/review.html b/client/ticket/src/review/review.html
new file mode 100644
index 0000000000..d38b231e5c
--- /dev/null
+++ b/client/ticket/src/review/review.html
@@ -0,0 +1,23 @@
+
+
+
+
+ Review
+
+
+
+
+
+
+
+
+
+ No results
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/client/ticket/src/review/review.js b/client/ticket/src/review/review.js
new file mode 100644
index 0000000000..7b4cc5678a
--- /dev/null
+++ b/client/ticket/src/review/review.js
@@ -0,0 +1,18 @@
+import ngModule from '../module';
+
+class ticketReview {
+ construct($http, $scope) {
+ this.$http = $http;
+ this.$ = $scope;
+ }
+}
+
+ticketReview.$inject = ['$http', '$scope'];
+
+ngModule.component('vnTicketReview', {
+ template: require('./review.html'),
+ controller: ticketReview,
+ bindings: {
+ ticket: '<'
+ }
+});
diff --git a/client/ticket/src/ticket.js b/client/ticket/src/ticket.js
index 17973330e9..d02656ba2f 100644
--- a/client/ticket/src/ticket.js
+++ b/client/ticket/src/ticket.js
@@ -5,5 +5,7 @@ import './create/ticket-create';
import './card/ticket-card';
import './summary/ticket-summary';
import './data/ticket-data';
+import './notes/ticket-observations';
import './package/list/package-list';
import './sale/sale';
+import './review/review';
diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js
index ab30e2db70..9acf8b1fe2 100644
--- a/e2e/helpers/selectors.js
+++ b/e2e/helpers/selectors.js
@@ -11,7 +11,8 @@ export default {
},
moduleAccessView: {
clientsSectionButton: `${components.vnModuleContainer}[ui-sref="clients"]`,
- itemsSectionButton: `${components.vnModuleContainer}[ui-sref="item.index"]`
+ itemsSectionButton: `${components.vnModuleContainer}[ui-sref="item.index"]`,
+ ticketsSectionButton: `${components.vnModuleContainer}[ui-sref="ticket.list"]`
},
clientsIndex: {
searchClientInput: `${components.vnTextfield}`,
@@ -56,9 +57,10 @@ export default {
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`,
+ 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`,
+ 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`,
@@ -188,24 +190,29 @@ export default {
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`,
+ firstTagDisabled: `vn-item-tags vn-horizontal:nth-child(2) > vn-textfield[label="Tag"] > div > input`,
firstTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(2) > ${components.vnAutocomplete}[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(1)`,
firstValueInput: `vn-item-tags vn-horizontal:nth-child(2) > vn-textfield[label="Value"] > div > input`,
firstRelevancyInput: `vn-horizontal:nth-child(2) > vn-textfield[label="Relevancy"] > div > input`,
secondTagSelect: `vn-item-tags vn-horizontal:nth-child(3) > ${components.vnAutocomplete}[field="itemTag.tagFk"] input`,
+ secondTagDisabled: `vn-item-tags vn-horizontal:nth-child(3) > vn-textfield[label="Tag"] > div > input`,
secondTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(3) > ${components.vnAutocomplete}[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(1)`,
secondValueInput: `vn-item-tags vn-horizontal:nth-child(3) > vn-textfield[label="Value"] > div > input`,
secondRelevancyInput: `vn-horizontal:nth-child(3) > vn-textfield[label="Relevancy"] > div > input`,
thirdTagSelect: `vn-item-tags vn-horizontal:nth-child(4) > ${components.vnAutocomplete}[field="itemTag.tagFk"] input`,
+ thirdTagDisabled: `vn-item-tags vn-horizontal:nth-child(4) > vn-textfield[label="Tag"] > div > input`,
thirdTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(4) > ${components.vnAutocomplete}[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(1)`,
thirdValueInput: `vn-item-tags vn-horizontal:nth-child(4) > vn-textfield[label="Value"] > div > input`,
thirdRelevancyInput: `vn-horizontal:nth-child(4) > vn-textfield[label="Relevancy"] > div > input`,
fourthTagSelect: `vn-item-tags vn-horizontal:nth-child(5) > ${components.vnAutocomplete}[field="itemTag.tagFk"] input`,
+ fourthTagDisabled: `vn-item-tags vn-horizontal:nth-child(5) > vn-textfield[label="Tag"] > div > input`,
fourthTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(5) > ${components.vnAutocomplete}[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(1)`,
fourthValueInput: `vn-item-tags vn-horizontal:nth-child(5) > vn-textfield[label="Value"] > div > input`,
fourthRelevancyInput: `vn-horizontal:nth-child(5) > vn-textfield[label="Relevancy"] > div > input`,
- fifthRemoveTagButton: `vn-item-tags vn-horizontal:nth-child(6) > ${components.vnIcon}[icon="remove_circle_outline"]`,
fifthTagSelect: `vn-item-tags vn-horizontal:nth-child(6) > ${components.vnAutocomplete}[field="itemTag.tagFk"] input`,
+ fifthTagDisabled: `vn-item-tags vn-horizontal:nth-child(6) > vn-textfield[label="Tag"] > div > input`,
fifthTagSelectOptionFive: `vn-item-tags vn-horizontal:nth-child(6) > ${components.vnAutocomplete}[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(5)`,
fifthValueInput: `vn-item-tags vn-horizontal:nth-child(6) > vn-textfield[label="Value"] > div > input`,
fifthRelevancyInput: `vn-horizontal:nth-child(6) > vn-textfield[label="Relevancy"] > div > input`,
@@ -233,14 +240,17 @@ export default {
nicheButton: `${components.vnMenuItem}[ui-sref="item.card.niche"]`,
addNicheButton: `${components.vnIcon}[icon="add_circle"]`,
firstWarehouseSelect: `${components.vnAutocomplete}[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)`,
+ firstCodeInput: `vn-horizontal:nth-child(2) > vn-textfield[label="code"] > div > input`,
secondWarehouseSelect: `vn-horizontal:nth-child(3) > ${components.vnAutocomplete}[field="itemNiche.warehouseFk"] input`,
- thirdWarehouseSelect: `vn-horizontal:nth-child(4) > ${components.vnAutocomplete}[field="itemNiche.warehouseFk"] input`,
- thirdWarehouseSelectFourthOption: `vn-horizontal:nth-child(4) > ${components.vnAutocomplete}[field="itemNiche.warehouseFk"] vn-drop-down ul > li:nth-child(4)`,
+ 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) > vn-one > ${components.vnIcon}[icon="remove_circle_outline"]`,
- firstCodeInput: `vn-horizontal:nth-child(2) > ${components.vnTextfield}`,
- secondCodeInput: `vn-horizontal:nth-child(3) > ${components.vnTextfield}`,
- thirdCodeInput: `vn-horizontal:nth-child(4) > ${components.vnTextfield}`,
+ thirdWarehouseSelect: `vn-horizontal:nth-child(4) > ${components.vnAutocomplete}[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)`,
+ thirdCodeInput: `vn-horizontal:nth-child(4) > vn-textfield[label="code"] > div > input`,
submitNichesButton: `${components.vnSubmit}`
},
itemBotanical: {
@@ -261,5 +271,25 @@ export default {
niche: `${components.vnItemSummary} > vn-horizontal:nth-child(2) > vn-one:nth-child(2) > vn-vertical > p:nth-child(2)`,
botanical: `${components.vnItemSummary} > vn-horizontal:nth-child(2) > vn-one:nth-child(3) > vn-vertical > p`,
barcode: `${components.vnItemSummary} > vn-horizontal:nth-child(2) > vn-one:nth-child(4) > vn-vertical > p`
+ },
+ ticketsIndex: {
+ createTicketButton: `${components.vnFloatButton}`,
+ searchResult: `vn-ticket-item a`,
+ searchTicketInput: `${components.vnTextfield}`,
+ searchButton: `${components.vnSearchBar} > vn-icon-button > button`
+ },
+ ticketNotes: {
+ notesButton: `${components.vnMenuItem}[ui-sref="ticket.card.observations"]`,
+ 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)`,
+ firstNoteDisabled: `vn-textfield[label="Observation type"] > div > input`,
+ firstDescriptionInput: `vn-textfield[label="Description"] > div > input`,
+ submitNotesButton: `${components.vnSubmit}`
+ },
+ ticketPackages: {
+ packagesButton: `${components.vnMenuItem}[ui-sref="ticket.card.package.list"]`,
+ firstPackageSelect: `${components.vnAutocomplete}[label="Package"] input`
}
};
diff --git a/e2e/paths/client-module/03_edit_fiscal_data.spec.js b/e2e/paths/client-module/03_edit_fiscal_data.spec.js
index 099c422ab9..5564bc51d4 100644
--- a/e2e/paths/client-module/03_edit_fiscal_data.spec.js
+++ b/e2e/paths/client-module/03_edit_fiscal_data.spec.js
@@ -99,6 +99,7 @@ describe('Edit fiscalData path', () => {
.waitToClick(selectors.clientFiscalData.provinceInput)
.waitToClick(selectors.clientFiscalData.provinceFifthOption)
.waitToClick(selectors.clientFiscalData.activeCheckboxLabel)
+ .waitToClick(selectors.clientFiscalData.frozenCheckboxLabel)
.waitToClick(selectors.clientFiscalData.invoiceByAddressCheckboxInput)
.waitToClick(selectors.clientFiscalData.verifiedDataCheckboxInput)
.waitToClick(selectors.clientFiscalData.hasToInvoiceCheckboxLabel)
@@ -227,6 +228,16 @@ describe('Edit fiscalData path', () => {
});
});
+ it('should confirm frozen checkbox is unchecked', () => {
+ return nightmare
+ .evaluate(selector => {
+ return document.querySelector(selector).checked;
+ }, selectors.clientFiscalData.frozenCheckboxLabel)
+ .then(value => {
+ expect(value).toBeFalsy();
+ });
+ });
+
it('should confirm invoice by address checkbox is unchecked', () => {
return nightmare
.evaluate(selector => {
diff --git a/e2e/paths/client-module/12_lock_of_verified_data.spec.js b/e2e/paths/client-module/12_lock_of_verified_data.spec.js
index 764476e62a..775e588b13 100644
--- a/e2e/paths/client-module/12_lock_of_verified_data.spec.js
+++ b/e2e/paths/client-module/12_lock_of_verified_data.spec.js
@@ -61,7 +61,7 @@ describe('lock verified data path', () => {
.wait(selectors.clientFiscalData.verifiedDataCheckboxInput)
.evaluate(selector => {
return document.querySelector(selector).className;
- }, 'body > vn-app > vn-vertical > vn-vertical > vn-client-card > vn-main-block > vn-horizontal > vn-one > vn-vertical > vn-client-fiscal-data > form > vn-card > div > vn-horizontal:nth-child(5) > vn-check:nth-child(3) > label')
+ }, 'body > vn-app > vn-vertical > vn-vertical > vn-client-card > vn-main-block > vn-horizontal > vn-one > vn-vertical > vn-client-fiscal-data > form > vn-card > div > vn-horizontal:nth-child(5) > vn-check:nth-child(4) > label')
.then(result => {
expect(result).toContain('is-disabled');
});
@@ -452,7 +452,7 @@ describe('lock verified data path', () => {
.wait(selectors.clientFiscalData.verifiedDataCheckboxInput)
.evaluate(selector => {
return document.querySelector(selector).className;
- }, 'body > vn-app > vn-vertical > vn-vertical > vn-client-card > vn-main-block > vn-horizontal > vn-one > vn-vertical > vn-client-fiscal-data > form > vn-card > div > vn-horizontal:nth-child(5) > vn-check:nth-child(3) > label')
+ }, 'body > vn-app > vn-vertical > vn-vertical > vn-client-card > vn-main-block > vn-horizontal > vn-one > vn-vertical > vn-client-fiscal-data > form > vn-card > div > vn-horizontal:nth-child(5) > vn-check:nth-child(4) > label')
.then(result => {
expect(result).toContain('is-disabled');
});
diff --git a/e2e/paths/item-module/02_edit_item_basic_data.spec.js b/e2e/paths/item-module/02_edit_item_basic_data.spec.js
index c2de03c068..36b7fb81e8 100644
--- a/e2e/paths/item-module/02_edit_item_basic_data.spec.js
+++ b/e2e/paths/item-module/02_edit_item_basic_data.spec.js
@@ -66,9 +66,10 @@ describe('edit item basic data path', () => {
it(`should confirm the item name was edited`, () => {
return nightmare
- .click(selectors.itemNiches.firstCodeInput)
- .wait(selectors.itemNiches.firstCodeInput)
+ .click(selectors.itemNiches.nicheButton)
+ .wait(selectors.itemNiches.firstWarehouseDisabled)
.waitToClick(selectors.itemBasicData.basicDataButton)
+ .waitForTextInInput(selectors.itemBasicData.nameInput, 'Rose of Purity')
.getInputValue(selectors.itemBasicData.nameInput)
.then(result => {
expect(result).toEqual('Rose of Purity');
diff --git a/e2e/paths/item-module/03_edit_item_tax.spec.js b/e2e/paths/item-module/03_edit_item_tax.spec.js
index 07bb754141..4347d17521 100644
--- a/e2e/paths/item-module/03_edit_item_tax.spec.js
+++ b/e2e/paths/item-module/03_edit_item_tax.spec.js
@@ -61,7 +61,7 @@ describe('add item tax path', () => {
it(`should confirm the item tax class was edited`, () => {
return nightmare
.click(selectors.itemTags.tagsButton)
- .wait(selectors.itemTags.firstTagSelect)
+ .wait(selectors.itemTags.firstTagDisabled)
.waitToClick(selectors.itemTax.taxButton)
.waitForTextInInput(selectors.itemTax.firstClassSelect, 'general')
.getInputValue(selectors.itemTax.firstClassSelect)
diff --git a/e2e/paths/item-module/04_create_item_tags.spec.js b/e2e/paths/item-module/04_create_item_tags.spec.js
index 19d9ef26ab..e83725bfaa 100644
--- a/e2e/paths/item-module/04_create_item_tags.spec.js
+++ b/e2e/paths/item-module/04_create_item_tags.spec.js
@@ -43,22 +43,14 @@ describe('create item tags path', () => {
});
});
- it(`should create a new tag, edit another and delete a former one`, () => {
+ it(`should create a new tag and delete a former one`, () => {
return nightmare
- .waitToClick(selectors.itemTags.firstTagSelect)
- .waitToClick(selectors.itemTags.firstTagSelectOptionOne)
- .clearInput(selectors.itemTags.firstValueInput)
- .type(selectors.itemTags.firstValueInput, 'Dark Blue')
- .clearInput(selectors.itemTags.firstRelevancyInput)
- .type(selectors.itemTags.firstRelevancyInput, '2')
- .waitToClick(selectors.itemTags.fifthRemoveTagButton)
+ .waitToClick(selectors.itemTags.firstRemoveTagButton)
.waitToClick(selectors.itemTags.addItemTagButton)
.waitToClick(selectors.itemTags.fifthTagSelect)
.waitToClick(selectors.itemTags.fifthTagSelectOptionFive)
.type(selectors.itemTags.fifthValueInput, 'Thanos')
.type(selectors.itemTags.fifthRelevancyInput, '1')
- .clearInput(selectors.itemTags.secondRelevancyInput)
- .type(selectors.itemTags.secondRelevancyInput, '5')
.click(selectors.itemTags.submitItemTagsButton)
.waitForSnackbar()
.then(result => {
@@ -71,8 +63,8 @@ describe('create item tags path', () => {
.click(selectors.itemBasicData.basicDataButton)
.wait(selectors.itemBasicData.nameInput)
.click(selectors.itemTags.tagsButton)
- .waitForTextInInput(selectors.itemTags.firstTagSelect, 'Owner')
- .getInputValue(selectors.itemTags.firstTagSelect)
+ .waitForTextInInput(selectors.itemTags.firstTagDisabled, 'Owner')
+ .getInputValue(selectors.itemTags.firstTagDisabled)
.then(result => {
expect(result).toEqual('Owner');
});
@@ -98,19 +90,19 @@ describe('create item tags path', () => {
it(`should confirm the second select is the expected one`, () => {
return nightmare
- .waitForTextInInput(selectors.itemTags.secondTagSelect, 'Color')
- .getInputValue(selectors.itemTags.secondTagSelect)
+ .waitForTextInInput(selectors.itemTags.secondTagDisabled, 'Location')
+ .getInputValue(selectors.itemTags.secondTagDisabled)
.then(result => {
- expect(result).toEqual('Color');
+ expect(result).toEqual('Location');
});
});
it(`should confirm the second value is the expected one`, () => {
return nightmare
- .waitForTextInInput(selectors.itemTags.secondValueInput, 'Dark Blue')
+ .waitForTextInInput(selectors.itemTags.secondValueInput, 'Gamoras hideout')
.getInputValue(selectors.itemTags.secondValueInput)
.then(result => {
- expect(result).toEqual('Dark Blue');
+ expect(result).toEqual('Gamoras hideout');
});
});
@@ -125,8 +117,8 @@ describe('create item tags path', () => {
it(`should confirm the third select is the expected one`, () => {
return nightmare
- .waitForTextInInput(selectors.itemTags.thirdTagSelect, 'Shape')
- .getInputValue(selectors.itemTags.thirdTagSelect)
+ .waitForTextInInput(selectors.itemTags.thirdTagDisabled, 'Shape')
+ .getInputValue(selectors.itemTags.thirdTagDisabled)
.then(result => {
expect(result).toEqual('Shape');
});
@@ -152,8 +144,8 @@ describe('create item tags path', () => {
it(`should confirm the fourth select is the expected one`, () => {
return nightmare
- .waitForTextInInput(selectors.itemTags.fourthTagSelect, 'Power')
- .getInputValue(selectors.itemTags.fourthTagSelect)
+ .waitForTextInInput(selectors.itemTags.fourthTagDisabled, 'Power')
+ .getInputValue(selectors.itemTags.fourthTagDisabled)
.then(result => {
expect(result).toEqual('Power');
});
@@ -179,19 +171,19 @@ describe('create item tags path', () => {
it(`should confirm the fifth select is the expected one`, () => {
return nightmare
- .waitForTextInInput(selectors.itemTags.fifthTagSelect, 'Location')
- .getInputValue(selectors.itemTags.fifthTagSelect)
+ .waitForTextInInput(selectors.itemTags.fifthTagDisabled, 'Color')
+ .getInputValue(selectors.itemTags.fifthTagDisabled)
.then(result => {
- expect(result).toEqual('Location');
+ expect(result).toEqual('Color');
});
});
it(`should confirm the fifth value is the expected one`, () => {
return nightmare
- .waitForTextInInput(selectors.itemTags.fifthValueInput, 'Gamoras hideout')
+ .waitForTextInInput(selectors.itemTags.fifthValueInput, 'Yellow')
.getInputValue(selectors.itemTags.fifthValueInput)
.then(result => {
- expect(result).toEqual('Gamoras hideout');
+ expect(result).toEqual('Yellow');
});
});
diff --git a/e2e/paths/item-module/05_create_item_niche.spec.js b/e2e/paths/item-module/05_create_item_niche.spec.js
index 588dad678d..cdadc7e0f1 100644
--- a/e2e/paths/item-module/05_create_item_niche.spec.js
+++ b/e2e/paths/item-module/05_create_item_niche.spec.js
@@ -43,13 +43,9 @@ describe('create item niche path', () => {
});
});
- it(`should click create a new niche, edit another and delete a former one`, () => {
+ it(`should click create a new niche and delete a former one`, () => {
return nightmare
.waitToClick(selectors.itemNiches.addNicheButton)
- .waitToClick(selectors.itemNiches.firstWarehouseSelect)
- .waitToClick(selectors.itemNiches.firstWarehouseSelectSecondOption)
- .clearInput(selectors.itemNiches.firstCodeInput)
- .type(selectors.itemNiches.firstCodeInput, 'A2')
.waitToClick(selectors.itemNiches.secondNicheRemoveButton)
.waitToClick(selectors.itemNiches.thirdWarehouseSelect)
.waitToClick(selectors.itemNiches.thirdWarehouseSelectFourthOption)
@@ -66,21 +62,21 @@ describe('create item niche path', () => {
.click(selectors.itemBasicData.basicDataButton)
.wait(selectors.itemBasicData.nameInput)
.click(selectors.itemNiches.nicheButton)
- .waitForTextInInput(selectors.itemNiches.firstWarehouseSelect, 'Warehouse Two')
- .getInputValue(selectors.itemNiches.firstWarehouseSelect)
+ .waitForTextInInput(selectors.itemNiches.firstWarehouseDisabled, 'Warehouse One')
+ .getInputValue(selectors.itemNiches.firstWarehouseDisabled)
.then(result => {
- expect(result).toEqual('Warehouse Two');
+ expect(result).toEqual('Warehouse One');
return nightmare
.getInputValue(selectors.itemNiches.firstCodeInput);
})
.then(result => {
- expect(result).toEqual('A2');
+ expect(result).toEqual('A1');
});
});
it(`should confirm the second niche is the expected one`, () => {
return nightmare
- .getInputValue(selectors.itemNiches.secondWarehouseSelect)
+ .getInputValue(selectors.itemNiches.secondWarehouseDisabled)
.then(result => {
expect(result).toEqual('Warehouse Three');
return nightmare
@@ -93,7 +89,7 @@ describe('create item niche path', () => {
it(`should confirm the third niche is the expected one`, () => {
return nightmare
- .getInputValue(selectors.itemNiches.thirdWarehouseSelect)
+ .getInputValue(selectors.itemNiches.thirdWarehouseDisabled)
.then(result => {
expect(result).toEqual('Warehouse Four');
return nightmare
diff --git a/e2e/paths/ticket-module/01_create_ticket_observations.spec.js b/e2e/paths/ticket-module/01_create_ticket_observations.spec.js
new file mode 100644
index 0000000000..dfc7053b2b
--- /dev/null
+++ b/e2e/paths/ticket-module/01_create_ticket_observations.spec.js
@@ -0,0 +1,77 @@
+import selectors from '../../helpers/selectors.js';
+import createNightmare from '../../helpers/helpers';
+
+describe('create item niche path', () => {
+ const nightmare = createNightmare();
+
+ beforeAll(() => {
+ return nightmare
+ .waitForLogin('developer');
+ });
+
+ it('should access to the tickets index by clicking the tickets button', () => {
+ return nightmare
+ .click(selectors.moduleAccessView.ticketsSectionButton)
+ .wait(selectors.ticketsIndex.createTicketButton)
+ .parsedUrl()
+ .then(url => {
+ expect(url.hash).toEqual('#!/ticket/list');
+ });
+ });
+
+ it('should search for the ticket with id 1', () => {
+ return nightmare
+ .wait(selectors.ticketsIndex.searchTicketInput)
+ .type(selectors.ticketsIndex.searchTicketInput, '1')
+ .click(selectors.ticketsIndex.searchButton)
+ .waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
+ .countSearchResults(selectors.ticketsIndex.searchResult)
+ .then(result => {
+ expect(result).toEqual(1);
+ });
+ });
+
+ it(`should click on the search result to access to the ticket notes`, () => {
+ return nightmare
+ .waitForTextInElement(selectors.ticketsIndex.searchResult, '1')
+ .waitToClick(selectors.ticketsIndex.searchResult)
+ .waitToClick(selectors.ticketNotes.notesButton)
+ .waitForURL('observations')
+ .url()
+ .then(url => {
+ expect(url).toContain('observations');
+ });
+ });
+
+ it(`should click create a new note and delete a former one`, () => {
+ return nightmare
+ .waitToClick(selectors.ticketNotes.firstNoteRemoveButton)
+ .waitToClick(selectors.ticketNotes.addNoteButton)
+ .waitToClick(selectors.ticketNotes.firstNoteSelect)
+ .waitForTextInElement(selectors.ticketNotes.firstNoteSelectSecondOption, 'observation two')
+ .waitToClick(selectors.ticketNotes.firstNoteSelectSecondOption)
+ .type(selectors.ticketNotes.firstDescriptionInput, 'description')
+ .click(selectors.ticketNotes.submitNotesButton)
+ .waitForSnackbar()
+ .then(result => {
+ expect(result).toContain('Data saved!');
+ });
+ });
+
+ it(`should confirm the note is the expected one`, () => {
+ return nightmare
+ .click(selectors.ticketPackages.packagesButton)
+ .wait(selectors.ticketPackages.firstPackageSelect)
+ .click(selectors.ticketNotes.notesButton)
+ .waitForTextInInput(selectors.ticketNotes.firstNoteDisabled, 'observation two')
+ .getInputValue(selectors.ticketNotes.firstNoteDisabled)
+ .then(result => {
+ expect(result).toEqual('observation two');
+ return nightmare
+ .getInputValue(selectors.ticketNotes.firstDescriptionInput);
+ })
+ .then(result => {
+ expect(result).toEqual('description');
+ });
+ });
+});
diff --git a/services/ticket/common/methods/ticket/crudTicketObservations.js b/services/ticket/common/methods/ticket/crudTicketObservations.js
new file mode 100644
index 0000000000..33949e1f40
--- /dev/null
+++ b/services/ticket/common/methods/ticket/crudTicketObservations.js
@@ -0,0 +1,3 @@
+module.exports = Self => {
+ Self.installCrudModel('crudTicketObservations');
+};
diff --git a/services/ticket/common/models/ticketObservation.js b/services/ticket/common/models/ticketObservation.js
new file mode 100644
index 0000000000..bed837bd35
--- /dev/null
+++ b/services/ticket/common/models/ticketObservation.js
@@ -0,0 +1,3 @@
+module.exports = function(Self) {
+ require('../methods/ticket/crudTicketObservations.js')(Self);
+};
diff --git a/services/ticket/common/models/ticketObservation.json b/services/ticket/common/models/ticketObservation.json
index a6e5e3029b..73fb711396 100644
--- a/services/ticket/common/models/ticketObservation.json
+++ b/services/ticket/common/models/ticketObservation.json
@@ -2,33 +2,34 @@
"name": "TicketObservation",
"base": "VnModel",
"options": {
- "mysql": {
- "table": "ticketObservation"
- }
+ "mysql": {
+ "table": "ticketObservation",
+ "database": "vn"
+ }
},
"properties": {
- "id": {
- "id": true,
- "type": "Number",
- "description": "Identifier"
- },
- "description": {
- "type": "String",
- "required": true
- }
+ "id": {
+ "id": true,
+ "type": "Number",
+ "description": "Identifier"
+ },
+ "description": {
+ "type": "String",
+ "required": true
+ }
},
"relations": {
- "ticket": {
- "type": "belongsTo",
- "model": "Ticket",
- "foreignKey": "ticketFk",
- "required": true
- },
- "observationType": {
- "type": "belongsTo",
- "model": "ObservationType",
- "foreignKey": "observationTypeFk",
- "required": true
- }
+ "ticket": {
+ "type": "belongsTo",
+ "model": "Ticket",
+ "foreignKey": "ticketFk",
+ "required": true
+ },
+ "observationType": {
+ "type": "belongsTo",
+ "model": "ObservationType",
+ "foreignKey": "observationTypeFk",
+ "required": true
+ }
}
- }
\ No newline at end of file
+}