From ece2fd384db19b74e34fde70c4c6a94d40cade15 Mon Sep 17 00:00:00 2001
From: Carlos Jimenez <=>
Date: Fri, 16 Mar 2018 15:06:42 +0100
Subject: [PATCH] #179 listar notas de ticket
---
client/ticket/routes.json | 12 ++
.../ticket/src/notes/ticket-observations.html | 60 ++++++++
.../ticket/src/notes/ticket-observations.js | 140 +++++++++++++++++
.../src/notes/ticket-observations.spec.js | 143 ++++++++++++++++++
client/ticket/src/ticket.js | 1 +
.../methods/ticket/crudTicketObservations.js | 3 +
.../ticket/common/models/ticketObservation.js | 3 +
.../common/models/ticketObservation.json | 50 +++---
8 files changed, 387 insertions(+), 25 deletions(-)
create mode 100644 client/ticket/src/notes/ticket-observations.html
create mode 100644 client/ticket/src/notes/ticket-observations.js
create mode 100644 client/ticket/src/notes/ticket-observations.spec.js
create mode 100644 services/ticket/common/methods/ticket/crudTicketObservations.js
create mode 100644 services/ticket/common/models/ticketObservation.js
diff --git a/client/ticket/routes.json b/client/ticket/routes.json
index 060d0c772..e0c476028 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,
diff --git a/client/ticket/src/notes/ticket-observations.html b/client/ticket/src/notes/ticket-observations.html
new file mode 100644
index 000000000..b48ec5a72
--- /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 000000000..793865fde
--- /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 000000000..982cfb61b
--- /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/ticket.js b/client/ticket/src/ticket.js
index d269a5fbd..4a7af6e58 100644
--- a/client/ticket/src/ticket.js
+++ b/client/ticket/src/ticket.js
@@ -5,5 +5,6 @@ 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 './review/review';
diff --git a/services/ticket/common/methods/ticket/crudTicketObservations.js b/services/ticket/common/methods/ticket/crudTicketObservations.js
new file mode 100644
index 000000000..33949e1f4
--- /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 000000000..bed837bd3
--- /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 a6e5e3029..e5b0169c1 100644
--- a/services/ticket/common/models/ticketObservation.json
+++ b/services/ticket/common/models/ticketObservation.json
@@ -2,33 +2,33 @@
"name": "TicketObservation",
"base": "VnModel",
"options": {
- "mysql": {
- "table": "ticketObservation"
- }
+ "mysql": {
+ "table": "ticketObservation"
+ }
},
"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
+}