diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 068ced790..0cbbcad53 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -2018,11 +2018,13 @@ INSERT INTO `vn`.`thermograph`(`id`, `model`) VALUES ('TMM190901395', 'TEMPMATE'), ('TL.BBA85422', 'TL30'), - ('TZ1905012010', 'DISPOSABLE'); + ('TZ1905012010', 'DISPOSABLE'), + ('138350-0', 'DISPOSABLE'); INSERT INTO `vn`.`travelThermograph`(`thermographFk`, `created`, `warehouseFk`, `travelFk`, `temperature`, `result`, `dmsFk`) VALUES - ('TMM190901395', CURDATE(), 1, 1, 'WARM', 'Ok', NULL), - ('TL.BBA85422', DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 2, 2, 'COOL', 'Ok', NULL), - ('TL.BBA85422', CURDATE(), 2, 1, 'COOL', 'can not read the temperature', NULL), - ('TZ1905012010', CURDATE(), 1, 1, 'WARM', 'Temperature in range', 5); \ No newline at end of file + ('TMM190901395', CURDATE(), 1, 1, 'WARM', 'Ok', NULL), + ('TL.BBA85422', DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 2, 2, 'COOL', 'Ok', NULL), + ('TL.BBA85422', CURDATE(), 2, 1, 'COOL', 'can not read the temperature', NULL), + ('TZ1905012010', CURDATE(), 1, 1, 'WARM', 'Temperature in range', 5), + ('138350-0', CURDATE(), 1, NULL, 'WARM', NULL, 5); \ No newline at end of file diff --git a/modules/travel/back/methods/travel-thermograph/uploadFile.js b/modules/travel/back/methods/travel-thermograph/uploadFile.js new file mode 100644 index 000000000..e5ea465cb --- /dev/null +++ b/modules/travel/back/methods/travel-thermograph/uploadFile.js @@ -0,0 +1,76 @@ +module.exports = Self => { + Self.remoteMethodCtx('uploadFile', { + description: 'Upload and attach a document', + accessType: 'WRITE', + accepts: [{ + arg: 'id', + type: 'Number', + description: 'The ticket id', + http: {source: 'path'} + }, { + arg: 'warehouseId', + type: 'Number', + description: 'The warehouse id', + required: true + }, { + arg: 'companyId', + type: 'Number', + description: 'The company id', + required: true + }, { + arg: 'dmsTypeId', + type: 'Number', + description: 'The dms type id', + required: true + }, { + arg: 'reference', + type: 'String', + required: true + }, { + arg: 'description', + type: 'String', + required: true + }, { + arg: 'hasFile', + type: 'Boolean', + description: 'True if has an attached file', + required: true + }], + returns: { + type: 'Object', + root: true + }, + http: { + path: `/:id/uploadFile`, + verb: 'POST' + } + }); + + Self.uploadFile = async(ctx, id) => { + const models = Self.app.models; + const promises = []; + const tx = await Self.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const uploadedFiles = await models.Dms.uploadFile(ctx, options); + uploadedFiles.forEach(dms => { + const newTicketDms = models.TicketDms.create({ + ticketFk: id, + dmsFk: dms.id + }, options); + + promises.push(newTicketDms); + }); + const resolvedPromises = await Promise.all(promises); + + await tx.commit(); + + return resolvedPromises; + } catch (err) { + await tx.rollback(); + throw err; + } + }; +}; diff --git a/modules/travel/back/models/travel-thermograph.js b/modules/travel/back/models/travel-thermograph.js new file mode 100644 index 000000000..8eab0ab7b --- /dev/null +++ b/modules/travel/back/models/travel-thermograph.js @@ -0,0 +1,3 @@ +module.exports = Self => { + require('../methods/travel-thermograph/uploadFile')(Self); +}; diff --git a/modules/travel/front/index.js b/modules/travel/front/index.js index 4bf935a8c..1f5346e98 100644 --- a/modules/travel/front/index.js +++ b/modules/travel/front/index.js @@ -9,5 +9,6 @@ import './summary'; import './basic-data'; import './log'; import './create'; -import './thermograph'; +import './thermograph/index/'; +import './thermograph/create/'; diff --git a/modules/travel/front/locale/es.yml b/modules/travel/front/locale/es.yml index 31e4e452b..931f79ab8 100644 --- a/modules/travel/front/locale/es.yml +++ b/modules/travel/front/locale/es.yml @@ -16,4 +16,4 @@ New travel: Nuevo envío # Sections Travels: Envíos Log: Historial -Thermographs: Termómetros \ No newline at end of file +Thermographs: Termógrafos \ No newline at end of file diff --git a/modules/travel/front/routes.json b/modules/travel/front/routes.json index d7d5b52df..fcbe5b92f 100644 --- a/modules/travel/front/routes.json +++ b/modules/travel/front/routes.json @@ -11,7 +11,7 @@ "card": [ {"state": "travel.card.basicData", "icon": "settings"}, {"state": "travel.card.log", "icon": "history"}, - {"state": "travel.card.thermograph", "icon": "icon-thermometer"} + {"state": "travel.card.thermograph.index", "icon": "icon-thermometer"} ] }, "routes": [ @@ -59,14 +59,28 @@ "component": "vn-travel-create", "description": "New travel" }, { - "url" : "/thermograph", + "url": "/thermograph", "state": "travel.card.thermograph", - "component": "vn-travel-thermograph", + "abstract": true, + "component": "ui-view" + }, { + "url" : "/index", + "state": "travel.card.thermograph.index", + "component": "vn-travel-thermograph-index", "description": "Thermographs", "params": { "travel": "$ctrl.travel" }, "acl": ["buyer"] + }, { + "url" : "/create", + "state": "travel.card.thermograph.create", + "component": "vn-travel-thermograph-create", + "description": "Add thermograph", + "params": { + "travel": "$ctrl.travel" + }, + "acl": ["buyer"] } ] } \ No newline at end of file diff --git a/modules/travel/front/thermograph/create/index.html b/modules/travel/front/thermograph/create/index.html new file mode 100644 index 000000000..327c6e629 --- /dev/null +++ b/modules/travel/front/thermograph/create/index.html @@ -0,0 +1,80 @@ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
diff --git a/modules/travel/front/thermograph/create/index.js b/modules/travel/front/thermograph/create/index.js new file mode 100644 index 000000000..2f3f3f807 --- /dev/null +++ b/modules/travel/front/thermograph/create/index.js @@ -0,0 +1,114 @@ +import ngModule from '../../module'; + +class Controller { + constructor($scope, $http, $state, $translate, vnApp, vnConfig) { + this.$ = $scope; + this.$http = $http; + this.$state = $state; + this.$translate = $translate; + this.vnApp = vnApp; + this.vnConfig = vnConfig; + this.dms = { + files: [], + hasFile: false, + hasFileAttached: false + }; + } + + get travel() { + return this._travel; + } + + set travel(value) { + this._travel = value; + + if (value) { + this.setDefaultParams(); + this.getAllowedContentTypes(); + } + } + + getAllowedContentTypes() { + // Replace with TravelThermographs + this.$http.get('ticketDms/allowedContentTypes').then(res => { + const contentTypes = res.data.join(', '); + this.allowedContentTypes = contentTypes; + }); + } + + get contentTypesInfo() { + return this.$translate.instant('ContentTypesInfo', { + allowedContentTypes: this.allowedContentTypes + }); + } + + setDefaultParams() { + const params = {filter: { + where: {code: 'miscellaneous'} + }}; + this.$http.get('DmsTypes/findOne', {params}).then(res => { + const dmsTypeId = res.data && res.data.id; + const companyId = this.vnConfig.companyFk; + const warehouseId = this.vnConfig.warehouseFk; + const defaultParams = { + reference: this.travel.id, + warehouseId: warehouseId, + companyId: companyId, + dmsTypeId: dmsTypeId, + description: this.$translate.instant('FileDescription', { + travelId: this.travel.id + }).toUpperCase() + }; + + this.dms = Object.assign(this.dms, defaultParams); + }); + } + + onSubmit() { + const query = `TravelThermographs/${this.dms.thermographId}/uploadFile`; + const options = { + method: 'POST', + url: query, + params: this.dms, + headers: { + 'Content-Type': undefined + }, + transformRequest: files => { + const formData = new FormData(); + + for (let i = 0; i < files.length; i++) + formData.append(files[i].name, files[i]); + + return formData; + }, + data: this.dms.files + }; + this.$http(options).then(res => { + if (res) { + this.vnApp.showSuccess(this.$translate.instant('Data saved!')); + this.$.watcher.updateOriginalData(); + this.$state.go('travel.card.thermograph.index'); + } + }); + } + + onFileChange(files) { + let hasFileAttached = false; + if (files.length > 0) + hasFileAttached = true; + + this.$.$applyAsync(() => { + this.dms.hasFileAttached = hasFileAttached; + }); + } +} + +Controller.$inject = ['$scope', '$http', '$state', '$translate', 'vnApp', 'vnConfig']; + +ngModule.component('vnTravelThermographCreate', { + template: require('./index.html'), + controller: Controller, + bindings: { + travel: '<' + } +}); diff --git a/modules/travel/front/thermograph/create/index.spec.js b/modules/travel/front/thermograph/create/index.spec.js new file mode 100644 index 000000000..c8b63358f --- /dev/null +++ b/modules/travel/front/thermograph/create/index.spec.js @@ -0,0 +1,80 @@ +import './index'; + +describe('Ticket', () => { + describe('Component vnTicketDmsCreate', () => { + let controller; + let $scope; + let $httpBackend; + let $httpParamSerializer; + + beforeEach(ngModule('ticket')); + + beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_, _$httpParamSerializer_) => { + $scope = $rootScope.$new(); + $httpBackend = _$httpBackend_; + $httpParamSerializer = _$httpParamSerializer_; + controller = $componentController('vnTicketDmsCreate', {$scope}); + controller._ticket = { + id: 15, + client: {id: 101, name: 'Bruce wayne'}, + warehouseFk: 1, + companyFk: 1 + }; + })); + + describe('client() setter', () => { + it('should set the ticket data and then call setDefaultParams() and getAllowedContentTypes()', () => { + spyOn(controller, 'setDefaultParams'); + spyOn(controller, 'getAllowedContentTypes'); + controller.ticket = { + id: 15, + name: 'Bruce wayne' + }; + + expect(controller.ticket).toBeDefined(); + expect(controller.setDefaultParams).toHaveBeenCalledWith(); + expect(controller.getAllowedContentTypes).toHaveBeenCalledWith(); + }); + }); + + describe('setDefaultParams()', () => { + it('should perform a GET query and define the dms property on controller', () => { + const params = {filter: { + where: {code: 'ticket'} + }}; + let serializedParams = $httpParamSerializer(params); + $httpBackend.when('GET', `DmsTypes/findOne?${serializedParams}`).respond({id: 14, code: 'ticket'}); + $httpBackend.expect('GET', `DmsTypes/findOne?${serializedParams}`); + controller.setDefaultParams(); + $httpBackend.flush(); + + expect(controller.dms).toBeDefined(); + expect(controller.dms.reference).toEqual(15); + expect(controller.dms.dmsTypeId).toEqual(14); + }); + }); + + describe('onFileChange()', () => { + it('should set dms hasFileAttached property to true if has any files', () => { + const files = [{id: 1, name: 'MyFile'}]; + controller.onFileChange(files); + $scope.$apply(); + + expect(controller.dms.hasFileAttached).toBeTruthy(); + }); + }); + + describe('getAllowedContentTypes()', () => { + it('should make an HTTP GET request to get the allowed content types', () => { + const expectedResponse = ['image/png', 'image/jpg']; + $httpBackend.when('GET', `ticketDms/allowedContentTypes`).respond(expectedResponse); + $httpBackend.expect('GET', `ticketDms/allowedContentTypes`); + controller.getAllowedContentTypes(); + $httpBackend.flush(); + + expect(controller.allowedContentTypes).toBeDefined(); + expect(controller.allowedContentTypes).toEqual('image/png, image/jpg'); + }); + }); + }); +}); diff --git a/modules/travel/front/thermograph/index.html b/modules/travel/front/thermograph/index/index.html similarity index 91% rename from modules/travel/front/thermograph/index.html rename to modules/travel/front/thermograph/index/index.html index 67d836d73..09814e5e9 100644 --- a/modules/travel/front/thermograph/index.html +++ b/modules/travel/front/thermograph/index/index.html @@ -48,3 +48,11 @@ question="Delete thermograph from travel?" on-response="$ctrl.removeThermographFromTravel($response)"> + + + + \ No newline at end of file diff --git a/modules/travel/front/thermograph/index.js b/modules/travel/front/thermograph/index/index.js similarity index 86% rename from modules/travel/front/thermograph/index.js rename to modules/travel/front/thermograph/index/index.js index 394bebdb8..5a4f13a7b 100644 --- a/modules/travel/front/thermograph/index.js +++ b/modules/travel/front/thermograph/index/index.js @@ -1,4 +1,4 @@ -import ngModule from '../module'; +import ngModule from '../../module'; import './style.scss'; import Component from 'core/lib/component'; @@ -16,7 +16,7 @@ class Controller extends Component { } } -ngModule.component('vnTravelThermograph', { +ngModule.component('vnTravelThermographIndex', { template: require('./index.html'), controller: Controller, require: { diff --git a/modules/travel/front/thermograph/style.scss b/modules/travel/front/thermograph/index/style.scss similarity index 100% rename from modules/travel/front/thermograph/style.scss rename to modules/travel/front/thermograph/index/style.scss diff --git a/modules/travel/front/thermograph/locale/es.yml b/modules/travel/front/thermograph/locale/es.yml index 9f5e04b72..d37be5102 100644 --- a/modules/travel/front/thermograph/locale/es.yml +++ b/modules/travel/front/thermograph/locale/es.yml @@ -3,4 +3,12 @@ Temperature: Temperatura State: Estado Destination: Destino Created: Creado -Remove thermograph: Eliminar termómetro \ No newline at end of file +Remove thermograph: Eliminar termómetro +Upload file: Subir fichero +Edit file: Editar fichero +Upload: Subir +File: Fichero +FileDescription: Travel id {{ticketId}} +ContentTypesInfo: 'Tipos de archivo permitidos: {{allowedContentTypes}}' +Are you sure you want to continue?: ¿Seguro que quieres continuar? +Add thermograph: Añadir termógrafo \ No newline at end of file