diff --git a/back/methods/dms/uploadFile.js b/back/methods/dms/uploadFile.js
index e077eea30..27e5169c9 100644
--- a/back/methods/dms/uploadFile.js
+++ b/back/methods/dms/uploadFile.js
@@ -63,7 +63,7 @@ module.exports = Self => {
}
try {
- const hasWriteRole = await models.DmsType.hasWriteRole(ctx, args.dmsTypeId);
+ const hasWriteRole = await models.DmsType.hasWriteRole(ctx, args.dmsTypeId, myOptions);
if (!hasWriteRole)
throw new UserError(`You don't have enough privileges`);
@@ -83,7 +83,7 @@ module.exports = Self => {
const originPath = `${tempContainer.client.root}/${tempContainer.name}/${file.name}`;
const destinationPath = `${container.client.root}/${pathHash}/${newDms.file}`;
- fs.rename(originPath, destinationPath);
+ await fs.rename(originPath, destinationPath);
addedDms.push(newDms);
}
diff --git a/back/models/account.js b/back/models/account.js
index 00c583d31..92ec589c5 100644
--- a/back/models/account.js
+++ b/back/models/account.js
@@ -60,8 +60,8 @@ module.exports = Self => {
* @param {String} name The role name
* @return {Boolean} %true if user has the role, %false otherwise
*/
- Self.hasRole = async function(userId, name) {
- let roles = await Self.getRoles(userId);
+ Self.hasRole = async function(userId, name, options) {
+ let roles = await Self.getRoles(userId, options);
return roles.some(role => role == name);
};
@@ -71,13 +71,13 @@ module.exports = Self => {
* @param {Integer} userId The user id
* @return {Object} User role list
*/
- Self.getRoles = async userId => {
+ Self.getRoles = async(userId, options) => {
let result = await Self.rawSql(
`SELECT r.name
FROM account.user u
JOIN account.roleRole rr ON rr.role = u.role
JOIN account.role r ON r.id = rr.inheritsFrom
- WHERE u.id = ?`, [userId]);
+ WHERE u.id = ?`, [userId], options);
let roles = [];
for (role of result)
diff --git a/back/models/dmsType.js b/back/models/dmsType.js
index f76b095df..267c905e9 100644
--- a/back/models/dmsType.js
+++ b/back/models/dmsType.js
@@ -5,17 +5,18 @@ module.exports = Self => {
*
* @param {Object} ctx - Request context
* @param {Interger} id - DmsType id
+ * @param {Object} options - Query options
* @return {Boolean} True for user with read privileges
*/
- Self.hasReadRole = async(ctx, id) => {
+ Self.hasReadRole = async(ctx, id, options) => {
const models = Self.app.models;
const dmsType = await models.DmsType.findById(id, {
include: {
relation: 'readRole'
}
- });
+ }, options);
- return await hasRole(ctx, dmsType);
+ return await hasRole(ctx, dmsType, options);
};
/**
@@ -24,17 +25,18 @@ module.exports = Self => {
*
* @param {Object} ctx - Request context
* @param {Interger} id - DmsType id
+ * @param {Object} options - Query options
* @return {Boolean} True for user with write privileges
*/
- Self.hasWriteRole = async(ctx, id) => {
+ Self.hasWriteRole = async(ctx, id, options) => {
const models = Self.app.models;
const dmsType = await models.DmsType.findById(id, {
include: {
relation: 'writeRole'
}
- });
+ }, options);
- return await hasRole(ctx, dmsType);
+ return await hasRole(ctx, dmsType, options);
};
/**
@@ -42,8 +44,9 @@ module.exports = Self => {
* read or write privileges
* @param {Object} ctx - Context
* @param {Object} dmsType - Dms type [read/write]
+ * @param {Object} options - Query options
*/
- async function hasRole(ctx, dmsType) {
+ async function hasRole(ctx, dmsType, options) {
const models = Self.app.models;
const myUserId = ctx.req.accessToken.userId;
@@ -51,8 +54,8 @@ module.exports = Self => {
const writeRole = dmsType.writeRole() && dmsType.writeRole().name;
const requiredRole = readRole || writeRole;
- const hasRequiredRole = await models.Account.hasRole(myUserId, requiredRole);
- const isRoot = await models.Account.hasRole(myUserId, 'root');
+ const hasRequiredRole = await models.Account.hasRole(myUserId, requiredRole, options);
+ const isRoot = await models.Account.hasRole(myUserId, 'root', options);
if (isRoot || hasRequiredRole)
return true;
diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index 86ee0a612..a437a4727 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -1869,7 +1869,8 @@ INSERT INTO `vn`.`dms`(`id`, `dmsTypeFk`, `file`, `contentType`, `workerFk`, `wa
VALUES
(1, 14, '1.txt', 'text/plain', 5, 1, 442, NULL, FALSE, 'Ticket:11', 'Ticket:11 dms for the ticket', CURDATE()),
(2, 5, '2.txt', 'text/plain', 5, 1, 442, 1, TRUE, 'Client:104', 'Client:104 dms for the client', CURDATE()),
- (3, 5, '3.txt', 'text/plain', 5, 1, 442, NULL, TRUE, 'Client: 104', 'Client:104 readme', CURDATE());
+ (3, 5, '3.txt', 'text/plain', 5, 1, 442, NULL, TRUE, 'Client: 104', 'Client:104 readme', CURDATE()),
+ (4, 3, '3.txt', 'text/plain', 5, 1, 442, NULL, TRUE, 'Worker: 106', 'Worker:106 readme', CURDATE());
INSERT INTO `vn`.`ticketDms`(`ticketFk`, `dmsFk`)
VALUES
@@ -1880,6 +1881,10 @@ INSERT INTO `vn`.`clientDms`(`clientFk`, `dmsFk`)
(104, 2),
(104, 3);
+INSERT INTO `vn`.`workerDocument`(`id`, `worker`, `document`)
+ VALUES
+ (1, 106, 4);
+
INSERT INTO `vn`.`device` (`sn`, `model`, `userFk`)
VALUES
('aaa', 'android', '9');
diff --git a/modules/claim/back/methods/claim-dms/removeFile.js b/modules/claim/back/methods/claim-dms/removeFile.js
index 8de764db0..ac546455a 100644
--- a/modules/claim/back/methods/claim-dms/removeFile.js
+++ b/modules/claim/back/methods/claim-dms/removeFile.js
@@ -1,6 +1,6 @@
module.exports = Self => {
Self.remoteMethodCtx('removeFile', {
- description: 'Removes a ticket document',
+ description: 'Removes a claim document',
accessType: 'WRITE',
accepts: {
arg: 'id',
diff --git a/modules/client/back/methods/client-dms/removeFile.js b/modules/client/back/methods/client-dms/removeFile.js
index 6cf7ccc41..5ff123630 100644
--- a/modules/client/back/methods/client-dms/removeFile.js
+++ b/modules/client/back/methods/client-dms/removeFile.js
@@ -20,7 +20,7 @@ module.exports = Self => {
Self.removeFile = async(ctx, id) => {
const models = Self.app.models;
- const clientDms = await models.ClientDms.findById(id);
+ const clientDms = await Self.findById(id);
await models.Dms.removeFile(ctx, clientDms.dmsFk);
diff --git a/modules/worker/back/methods/worker-dms/allowedContentTypes.js b/modules/worker/back/methods/worker-dms/allowedContentTypes.js
new file mode 100644
index 000000000..2f5183f92
--- /dev/null
+++ b/modules/worker/back/methods/worker-dms/allowedContentTypes.js
@@ -0,0 +1,23 @@
+module.exports = Self => {
+ Self.remoteMethodCtx('allowedContentTypes', {
+ description: 'Returns a list of allowed contentTypes',
+ accessType: 'READ',
+ returns: {
+ type: ['Object'],
+ root: true
+ },
+ http: {
+ path: `/allowedContentTypes`,
+ verb: 'GET'
+ }
+ });
+
+ Self.allowedContentTypes = async() => {
+ const storageConnector = Self.app.dataSources.storage.connector;
+ const allowedContentTypes = storageConnector.allowedContentTypes;
+ const modelAllowedContentTypes = Self.definition.settings.allowedContentTypes;
+
+ return modelAllowedContentTypes || allowedContentTypes;
+ };
+};
+
diff --git a/modules/worker/back/methods/worker-dms/removeFile.js b/modules/worker/back/methods/worker-dms/removeFile.js
new file mode 100644
index 000000000..d0116c3c2
--- /dev/null
+++ b/modules/worker/back/methods/worker-dms/removeFile.js
@@ -0,0 +1,30 @@
+module.exports = Self => {
+ Self.remoteMethodCtx('removeFile', {
+ description: 'Removes a worker document',
+ accessType: 'WRITE',
+ accepts: {
+ arg: 'id',
+ type: 'Number',
+ description: 'The document id',
+ http: {source: 'path'}
+ },
+ returns: {
+ type: 'Object',
+ root: true
+ },
+ http: {
+ path: `/:id/removeFile`,
+ verb: 'POST'
+ }
+ });
+
+ Self.removeFile = async(ctx, id) => {
+ const models = Self.app.models;
+ const workerDms = await Self.findById(id);
+
+ await models.Dms.removeFile(ctx, workerDms.dmsFk);
+
+ return workerDms.destroy();
+ };
+};
+
diff --git a/modules/worker/back/methods/worker-dms/specs/removeFile.spec.js b/modules/worker/back/methods/worker-dms/specs/removeFile.spec.js
new file mode 100644
index 000000000..7039d4f3e
--- /dev/null
+++ b/modules/worker/back/methods/worker-dms/specs/removeFile.spec.js
@@ -0,0 +1,18 @@
+const app = require('vn-loopback/server/server');
+
+describe('WorkerDms removeFile()', () => {
+ const workerDmsFk = 1;
+ it(`should return an error for a user without enough privileges`, async() => {
+ let clientId = 101;
+ let ctx = {req: {accessToken: {userId: clientId}}};
+
+ let error;
+ await app.models.WorkerDms.removeFile(ctx, workerDmsFk).catch(e => {
+ error = e;
+ }).finally(() => {
+ expect(error.message).toEqual(`You don't have enough privileges`);
+ });
+
+ expect(error).toBeDefined();
+ });
+});
diff --git a/modules/worker/back/methods/worker/specs/uploadFile.spec.js b/modules/worker/back/methods/worker/specs/uploadFile.spec.js
new file mode 100644
index 000000000..26a50252d
--- /dev/null
+++ b/modules/worker/back/methods/worker/specs/uploadFile.spec.js
@@ -0,0 +1,19 @@
+const app = require('vn-loopback/server/server');
+
+describe('Worker uploadFile()', () => {
+ it(`should return an error for a user without enough privileges`, async() => {
+ let workerId = 106;
+ let currentUserId = 102;
+ let hhrrDataId = 3;
+ let ctx = {req: {accessToken: {userId: currentUserId}}, args: {dmsTypeId: hhrrDataId}};
+
+ let error;
+ await app.models.Worker.uploadFile(ctx, workerId).catch(e => {
+ error = e;
+ }).finally(() => {
+ expect(error.message).toEqual(`You don't have enough privileges`);
+ });
+
+ expect(error).toBeDefined();
+ });
+});
diff --git a/modules/worker/back/methods/worker/uploadFile.js b/modules/worker/back/methods/worker/uploadFile.js
new file mode 100644
index 000000000..588cfe4bd
--- /dev/null
+++ b/modules/worker/back/methods/worker/uploadFile.js
@@ -0,0 +1,76 @@
+module.exports = Self => {
+ Self.remoteMethodCtx('uploadFile', {
+ description: 'Upload and attach a file to a client',
+ accessType: 'WRITE',
+ accepts: [{
+ arg: 'id',
+ type: 'Number',
+ description: 'The worker 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 newWorkerDms = models.WorkerDms.create({
+ workerFk: id,
+ dmsFk: dms.id
+ }, options);
+
+ promises.push(newWorkerDms);
+ });
+ const resolvedPromises = await Promise.all(promises);
+
+ await tx.commit();
+
+ return resolvedPromises;
+ } catch (err) {
+ await tx.rollback();
+ throw err;
+ }
+ };
+};
diff --git a/modules/worker/back/model-config.json b/modules/worker/back/model-config.json
index 35a039d3c..4948231b9 100644
--- a/modules/worker/back/model-config.json
+++ b/modules/worker/back/model-config.json
@@ -20,6 +20,9 @@
"WorkCenterHoliday": {
"dataSource": "vn"
},
+ "WorkerDms": {
+ "dataSource": "vn"
+ },
"Worker": {
"dataSource": "vn"
},
diff --git a/modules/worker/back/models/worker-dms.js b/modules/worker/back/models/worker-dms.js
new file mode 100644
index 000000000..4504b4ed4
--- /dev/null
+++ b/modules/worker/back/models/worker-dms.js
@@ -0,0 +1,4 @@
+module.exports = Self => {
+ require('../methods/worker-dms/removeFile')(Self);
+ require('../methods/worker-dms/allowedContentTypes')(Self);
+};
diff --git a/modules/worker/back/models/worker-dms.json b/modules/worker/back/models/worker-dms.json
new file mode 100644
index 000000000..56cad65a6
--- /dev/null
+++ b/modules/worker/back/models/worker-dms.json
@@ -0,0 +1,47 @@
+{
+ "name": "WorkerDms",
+ "base": "Loggable",
+ "log": {
+ "model":"ClientLog",
+ "relation": "worker",
+ "showField": "dmsFk"
+ },
+ "options": {
+ "mysql": {
+ "table": "workerDocument"
+ }
+ },
+ "properties": {
+ "id": {
+ "type": "Number",
+ "id": true
+ },
+ "dmsFk": {
+ "type": "Number",
+ "required": true,
+ "mysql": {
+ "columnName": "document"
+ }
+ },
+ "workerFk": {
+ "type": "Number",
+ "required": true,
+ "mysql": {
+ "columnName": "worker"
+ }
+ }
+ },
+ "relations": {
+ "worker": {
+ "type": "belongsTo",
+ "model": "Worker",
+ "foreignKey": "workerFk"
+ },
+ "dms": {
+ "type": "belongsTo",
+ "model": "Dms",
+ "foreignKey": "dmsFk"
+ }
+ }
+}
+
diff --git a/modules/worker/back/models/worker.js b/modules/worker/back/models/worker.js
index 5abf65513..692c8c735 100644
--- a/modules/worker/back/models/worker.js
+++ b/modules/worker/back/models/worker.js
@@ -3,4 +3,5 @@ module.exports = Self => {
require('../methods/worker/mySubordinates')(Self);
require('../methods/worker/isSubordinate')(Self);
require('../methods/worker/getWorkedHours')(Self);
+ require('../methods/worker/uploadFile')(Self);
};
diff --git a/modules/worker/front/dms/create/index.html b/modules/worker/front/dms/create/index.html
new file mode 100644
index 000000000..dcafa5986
--- /dev/null
+++ b/modules/worker/front/dms/create/index.html
@@ -0,0 +1,83 @@
+
+
+
+
diff --git a/modules/worker/front/dms/create/index.js b/modules/worker/front/dms/create/index.js
new file mode 100644
index 000000000..e7bfe7bfd
--- /dev/null
+++ b/modules/worker/front/dms/create/index.js
@@ -0,0 +1,114 @@
+import ngModule from '../../module';
+import Component from 'core/lib/component';
+import './style.scss';
+
+class Controller extends Component {
+ constructor($element, $, vnConfig) {
+ super($element, $);
+ this.vnConfig = vnConfig;
+ this.dms = {
+ files: [],
+ hasFile: false,
+ hasFileAttached: false
+ };
+ }
+
+ get worker() {
+ return this._worker;
+ }
+
+ set worker(value) {
+ this._worker = value;
+
+ if (value) {
+ this.setDefaultParams();
+ this.getAllowedContentTypes();
+ }
+ }
+
+ getAllowedContentTypes() {
+ this.$http.get('workerDms/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: 'hhrrData'}
+ }};
+ this.$http.get('DmsTypes/findOne', {params}).then(res => {
+ const dmsType = res.data && res.data;
+ const companyId = this.vnConfig.companyFk;
+ const warehouseId = this.vnConfig.warehouseFk;
+ const defaultParams = {
+ reference: this.worker.id,
+ warehouseId: warehouseId,
+ companyId: companyId,
+ dmsTypeId: dmsType.id,
+ description: this.$translate.instant('WorkerFileDescription', {
+ dmsTypeName: dmsType.name,
+ workerId: this.worker.id,
+ workerName: this.worker.name
+ }).toUpperCase()
+ };
+
+ this.dms = Object.assign(this.dms, defaultParams);
+ });
+ }
+
+ onSubmit() {
+ const query = `Workers/${this.worker.id}/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('worker.card.dms.index');
+ }
+ });
+ }
+
+ onFileChange(files) {
+ let hasFileAttached = false;
+
+ if (files.length > 0)
+ hasFileAttached = true;
+
+ this.$.$applyAsync(() => {
+ this.dms.hasFileAttached = hasFileAttached;
+ });
+ }
+}
+
+Controller.$inject = ['$element', '$scope', 'vnConfig'];
+
+ngModule.component('vnWorkerDmsCreate', {
+ template: require('./index.html'),
+ controller: Controller,
+ bindings: {
+ worker: '<'
+ }
+});
diff --git a/modules/worker/front/dms/create/index.spec.js b/modules/worker/front/dms/create/index.spec.js
new file mode 100644
index 000000000..41fe0e0ca
--- /dev/null
+++ b/modules/worker/front/dms/create/index.spec.js
@@ -0,0 +1,77 @@
+import './index';
+
+describe('Client', () => {
+ describe('Component vnWorkerDmsCreate', () => {
+ let $element;
+ let controller;
+ let $scope;
+ let $httpBackend;
+ let $httpParamSerializer;
+
+ beforeEach(ngModule('worker'));
+
+ beforeEach(angular.mock.inject(($compile, $rootScope, _$httpBackend_, _$httpParamSerializer_) => {
+ $scope = $rootScope.$new();
+ $httpBackend = _$httpBackend_;
+ $httpParamSerializer = _$httpParamSerializer_;
+ $element = $compile(``)($rootScope);
+ controller = $element.controller('vnWorkerDmsCreate');
+ controller._worker = {id: 101, name: 'Bruce wayne'};
+ }));
+
+ describe('worker() setter', () => {
+ it('should set the worker data and then call setDefaultParams() and getAllowedContentTypes()', () => {
+ spyOn(controller, 'setDefaultParams');
+ spyOn(controller, 'getAllowedContentTypes');
+ controller.worker = {
+ id: 15,
+ name: 'Bruce wayne'
+ };
+
+ expect(controller.worker).toBeDefined();
+ expect(controller.setDefaultParams).toHaveBeenCalledWith();
+ expect(controller.getAllowedContentTypes).toHaveBeenCalledWith();
+ });
+ });
+
+ describe('setDefaultParams()', () => {
+ it('should perform a GET query and define the dms property on controller', () => {
+ $httpBackend.whenRoute('GET', `DmsTypes`).respond({id: 12, code: 'hhrrData'});
+ const params = {filter: {
+ where: {code: 'hhrrData'}
+ }};
+ let serializedParams = $httpParamSerializer(params);
+ $httpBackend.when('GET', `DmsTypes/findOne?${serializedParams}`).respond({id: 12, code: 'hhrrData'});
+ controller.setDefaultParams();
+ $httpBackend.flush();
+
+ expect(controller.dms).toBeDefined();
+ expect(controller.dms.reference).toEqual(101);
+ expect(controller.dms.dmsTypeId).toEqual(12);
+ });
+ });
+
+ 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', `workerDms/allowedContentTypes`).respond(expectedResponse);
+ $httpBackend.expect('GET', `workerDms/allowedContentTypes`);
+ controller.getAllowedContentTypes();
+ $httpBackend.flush();
+
+ expect(controller.allowedContentTypes).toBeDefined();
+ expect(controller.allowedContentTypes).toEqual('image/png, image/jpg');
+ });
+ });
+ });
+});
diff --git a/modules/worker/front/dms/create/style.scss b/modules/worker/front/dms/create/style.scss
new file mode 100644
index 000000000..73f136fc1
--- /dev/null
+++ b/modules/worker/front/dms/create/style.scss
@@ -0,0 +1,7 @@
+vn-ticket-request {
+ .vn-textfield {
+ margin: 0!important;
+ max-width: 100px;
+ }
+}
+
diff --git a/modules/worker/front/dms/edit/index.html b/modules/worker/front/dms/edit/index.html
new file mode 100644
index 000000000..13bf6f953
--- /dev/null
+++ b/modules/worker/front/dms/edit/index.html
@@ -0,0 +1,82 @@
+
+
+
diff --git a/modules/worker/front/dms/edit/index.js b/modules/worker/front/dms/edit/index.js
new file mode 100644
index 000000000..1a593414a
--- /dev/null
+++ b/modules/worker/front/dms/edit/index.js
@@ -0,0 +1,94 @@
+import ngModule from '../../module';
+import Component from 'core/lib/component';
+import './style.scss';
+
+class Controller extends Component {
+ get worker() {
+ return this._worker;
+ }
+
+ set worker(value) {
+ this._worker = value;
+
+ if (value) {
+ this.setDefaultParams();
+ this.getAllowedContentTypes();
+ }
+ }
+
+ getAllowedContentTypes() {
+ this.$http.get('WorkerDms/allowedContentTypes').then(res => {
+ const contentTypes = res.data.join(', ');
+ this.allowedContentTypes = contentTypes;
+ });
+ }
+
+ get contentTypesInfo() {
+ return this.$translate.instant('ContentTypesInfo', {
+ allowedContentTypes: this.allowedContentTypes
+ });
+ }
+
+ setDefaultParams() {
+ const path = `Dms/${this.$params.dmsId}`;
+ this.$http.get(path).then(res => {
+ const dms = res.data && res.data;
+ this.dms = {
+ reference: dms.reference,
+ warehouseId: dms.warehouseFk,
+ companyId: dms.companyFk,
+ dmsTypeId: dms.dmsTypeFk,
+ description: dms.description,
+ hasFile: dms.hasFile,
+ hasFileAttached: false,
+ files: []
+ };
+ });
+ }
+
+ onSubmit() {
+ const query = `dms/${this.$params.dmsId}/updateFile`;
+ 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('worker.card.dms.index');
+ }
+ });
+ }
+
+ onFileChange(files) {
+ let hasFileAttached = false;
+ if (files.length > 0)
+ hasFileAttached = true;
+
+ this.$.$applyAsync(() => {
+ this.dms.hasFileAttached = hasFileAttached;
+ });
+ }
+}
+
+ngModule.component('vnWorkerDmsEdit', {
+ template: require('./index.html'),
+ controller: Controller,
+ bindings: {
+ worker: '<'
+ }
+});
diff --git a/modules/worker/front/dms/edit/index.spec.js b/modules/worker/front/dms/edit/index.spec.js
new file mode 100644
index 000000000..b883d4472
--- /dev/null
+++ b/modules/worker/front/dms/edit/index.spec.js
@@ -0,0 +1,84 @@
+import './index';
+
+describe('Worker', () => {
+ describe('Component vnClientDmsEdit', () => {
+ let controller;
+ let $scope;
+ let $element;
+ let $httpBackend;
+
+ beforeEach(ngModule('worker'));
+
+ beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_) => {
+ $scope = $rootScope.$new();
+ $httpBackend = _$httpBackend_;
+ $element = angular.element(` {
+ it('should set the worker data and then call setDefaultParams() and getAllowedContentTypes()', () => {
+ spyOn(controller, 'setDefaultParams');
+ spyOn(controller, 'getAllowedContentTypes');
+ controller._worker = undefined;
+ controller.worker = {
+ id: 106
+ };
+
+ expect(controller.setDefaultParams).toHaveBeenCalledWith();
+ expect(controller.worker).toBeDefined();
+ expect(controller.getAllowedContentTypes).toHaveBeenCalledWith();
+ });
+ });
+
+ describe('setDefaultParams()', () => {
+ it('should perform a GET query and define the dms property on controller', () => {
+ const dmsId = 4;
+ const expectedResponse = {
+ reference: 101,
+ warehouseFk: 1,
+ companyFk: 442,
+ dmsTypeFk: 3,
+ description: 'Test',
+ hasFile: false,
+ hasFileAttached: false
+ };
+
+ $httpBackend.when('GET', `Dms/${dmsId}`).respond(expectedResponse);
+ $httpBackend.expect('GET', `Dms/${dmsId}`).respond(expectedResponse);
+ controller.setDefaultParams();
+ $httpBackend.flush();
+
+ expect(controller.dms).toBeDefined();
+ expect(controller.dms.reference).toEqual(101);
+ expect(controller.dms.dmsTypeId).toEqual(3);
+ });
+ });
+
+ describe('onFileChange()', () => {
+ it('should set dms hasFileAttached property to true if has any files', () => {
+ const files = [{id: 1, name: 'MyFile'}];
+ controller.dms = {hasFileAttached: false};
+ 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', `WorkerDms/allowedContentTypes`).respond(expectedResponse);
+ $httpBackend.expect('GET', `WorkerDms/allowedContentTypes`);
+ controller.getAllowedContentTypes();
+ $httpBackend.flush();
+
+ expect(controller.allowedContentTypes).toBeDefined();
+ expect(controller.allowedContentTypes).toEqual('image/png, image/jpg');
+ });
+ });
+ });
+});
diff --git a/modules/worker/front/dms/edit/style.scss b/modules/worker/front/dms/edit/style.scss
new file mode 100644
index 000000000..73f136fc1
--- /dev/null
+++ b/modules/worker/front/dms/edit/style.scss
@@ -0,0 +1,7 @@
+vn-ticket-request {
+ .vn-textfield {
+ margin: 0!important;
+ max-width: 100px;
+ }
+}
+
diff --git a/modules/worker/front/dms/index/index.html b/modules/worker/front/dms/index/index.html
new file mode 100644
index 000000000..7859a50a4
--- /dev/null
+++ b/modules/worker/front/dms/index/index.html
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+ Id
+ Type
+ Order
+ Reference
+ Description
+ Original
+ File
+ Employee
+ Created
+
+
+
+
+
+
+
+ {{::document.dmsFk}}
+
+
+ {{::document.dms.dmsType.name}}
+
+
+
+
+ {{::document.dms.hardCopyNumber}}
+
+
+
+
+ {{::document.dms.reference}}
+
+
+
+
+ {{::document.dms.description}}
+
+
+
+
+
+
+
+ {{::document.dms.file}}
+
+
+
+
+ {{::document.dms.worker.user.nickname | dashIfEmpty}}
+
+
+ {{::document.dms.created | date:'dd/MM/yyyy HH:mm'}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/worker/front/dms/index/index.js b/modules/worker/front/dms/index/index.js
new file mode 100644
index 000000000..907047f97
--- /dev/null
+++ b/modules/worker/front/dms/index/index.js
@@ -0,0 +1,76 @@
+import ngModule from '../../module';
+import Component from 'core/lib/component';
+import './style.scss';
+
+class Controller extends Component {
+ constructor($element, $, vnToken) {
+ super($element, $);
+ this.accessToken = vnToken.token;
+ this.filter = {
+ include: {
+ relation: 'dms',
+ scope: {
+ fields: [
+ 'dmsTypeFk',
+ 'reference',
+ 'hardCopyNumber',
+ 'workerFk',
+ 'description',
+ 'hasFile',
+ 'file',
+ 'created',
+ ],
+ include: [{
+ relation: 'dmsType',
+ scope: {
+ fields: ['name']
+ }
+ },
+ {
+ relation: 'worker',
+ scope: {
+ fields: ['userFk'],
+ include: {
+ relation: 'user',
+ scope: {
+ fields: ['nickname']
+ }
+ },
+ }
+ }]
+ },
+ }
+ };
+ }
+
+ showWorkerDescriptor(event, workerFk) {
+ event.preventDefault();
+ event.stopImmediatePropagation();
+ this.$.workerDescriptor.parent = event.target;
+ this.$.workerDescriptor.workerFk = workerFk;
+ this.$.workerDescriptor.show();
+ }
+
+ showDeleteConfirm(index) {
+ this.dmsIndex = index;
+ this.$.confirm.show();
+ }
+
+ deleteDms(response) {
+ if (response === 'accept') {
+ const dmsFk = this.workerDms[this.dmsIndex].dmsFk;
+ const query = `WorkerDms/${dmsFk}/removeFile`;
+ this.$http.post(query).then(() => {
+ this.$.model.remove(this.dmsIndex);
+ this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
+ });
+ }
+ }
+}
+
+Controller.$inject = ['$element', '$scope', 'vnToken'];
+
+ngModule.component('vnWorkerDmsIndex', {
+ template: require('./index.html'),
+ controller: Controller,
+});
diff --git a/modules/worker/front/dms/index/index.spec.js b/modules/worker/front/dms/index/index.spec.js
new file mode 100644
index 000000000..6220d051c
--- /dev/null
+++ b/modules/worker/front/dms/index/index.spec.js
@@ -0,0 +1,42 @@
+import './index';
+import crudModel from 'core/mocks/crud-model';
+
+describe('Worker', () => {
+ describe('Component vnWorkerDmsIndex', () => {
+ let $componentController;
+ let $scope;
+ let $element;
+ let $httpBackend;
+ let controller;
+
+ beforeEach(ngModule('worker'));
+
+ beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_) => {
+ $componentController = _$componentController_;
+ $httpBackend = _$httpBackend_;
+ $scope = $rootScope.$new();
+ $element = angular.element(` {
+ it('should make an HTTP Post query', () => {
+ const dmsId = 4;
+ const dmsIndex = 0;
+ spyOn(controller.vnApp, 'showSuccess');
+ spyOn(controller.$.model, 'remove');
+ controller.workerDms = [{dmsFk: 4}];
+ controller.dmsIndex = dmsIndex;
+
+ $httpBackend.when('POST', `WorkerDms/${dmsId}/removeFile`).respond({});
+ $httpBackend.expect('POST', `WorkerDms/${dmsId}/removeFile`);
+ controller.deleteDms('accept');
+ $httpBackend.flush();
+
+ expect(controller.$.model.remove).toHaveBeenCalledWith(dmsIndex);
+ expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
+ });
+ });
+ });
+});
diff --git a/modules/worker/front/dms/index/locale/es.yml b/modules/worker/front/dms/index/locale/es.yml
new file mode 100644
index 000000000..0994c7d86
--- /dev/null
+++ b/modules/worker/front/dms/index/locale/es.yml
@@ -0,0 +1,9 @@
+Type: Tipo
+File management: Gestión documental
+File: Fichero
+Hard copy: Copia
+This file will be deleted: Este fichero va a ser borrado
+Are you sure?: Estas seguro?
+File deleted: Fichero eliminado
+Remove file: Eliminar fichero
+Download file: Descargar fichero
\ No newline at end of file
diff --git a/modules/worker/front/dms/index/style.scss b/modules/worker/front/dms/index/style.scss
new file mode 100644
index 000000000..a6758e2e6
--- /dev/null
+++ b/modules/worker/front/dms/index/style.scss
@@ -0,0 +1,6 @@
+vn-client-risk-index {
+ .totalBox {
+ display: table;
+ float: right;
+ }
+}
\ No newline at end of file
diff --git a/modules/worker/front/dms/locale/en.yml b/modules/worker/front/dms/locale/en.yml
new file mode 100644
index 000000000..766853fca
--- /dev/null
+++ b/modules/worker/front/dms/locale/en.yml
@@ -0,0 +1,2 @@
+ClientFileDescription: "{{dmsTypeName}} from client {{clientName}} id {{clientId}}"
+ContentTypesInfo: Allowed file types {{allowedContentTypes}}
\ No newline at end of file
diff --git a/modules/worker/front/dms/locale/es.yml b/modules/worker/front/dms/locale/es.yml
new file mode 100644
index 000000000..fa4178d35
--- /dev/null
+++ b/modules/worker/front/dms/locale/es.yml
@@ -0,0 +1,20 @@
+Reference: Referencia
+Description: Descripción
+Company: Empresa
+Upload file: Subir fichero
+Edit file: Editar fichero
+Upload: Subir
+File: Fichero
+WorkerFileDescription: "{{dmsTypeName}} del empleado {{workerName}} id {{workerId}}"
+ContentTypesInfo: "Tipos de archivo permitidos: {{allowedContentTypes}}"
+Generate identifier for original file: Generar identificador para archivo original
+Are you sure you want to continue?: ¿Seguro que quieres continuar?
+File management: Gestión documental
+Hard copy: Copia
+This file will be deleted: Este fichero va a ser borrado
+Are you sure?: ¿Seguro?
+File deleted: Fichero eliminado
+Remove file: Eliminar fichero
+Download file: Descargar fichero
+Created: Creado
+Employee: Empleado
\ No newline at end of file
diff --git a/modules/worker/front/index.js b/modules/worker/front/index.js
index 3ef1c9217..775524a3d 100644
--- a/modules/worker/front/index.js
+++ b/modules/worker/front/index.js
@@ -14,3 +14,6 @@ import './calendar';
import './time-control';
import './log';
import './phones';
+import './dms/index';
+import './dms/create';
+import './dms/edit';
diff --git a/modules/worker/front/routes.json b/modules/worker/front/routes.json
index 7cd5fda20..d117cf18c 100644
--- a/modules/worker/front/routes.json
+++ b/modules/worker/front/routes.json
@@ -13,7 +13,8 @@
{"state": "worker.card.pbx", "icon": "icon-pbx"},
{"state": "worker.card.calendar", "icon": "icon-calendar"},
{"state": "worker.card.timeControl", "icon": "access_time"},
- {"state": "worker.card.phones", "icon": "contact_phone"}
+ {"state": "worker.card.phones", "icon": "contact_phone"},
+ {"state": "worker.card.dms.index", "icon": "cloud_upload"}
]
},
"routes": [
@@ -89,6 +90,36 @@
"params": {
"worker": "$ctrl.worker"
}
+ },
+ {
+ "url": "/dms",
+ "state": "worker.card.dms",
+ "abstract": true,
+ "component": "ui-view"
+ },
+ {
+ "url": "/index",
+ "state": "worker.card.dms.index",
+ "component": "vn-worker-dms-index",
+ "description": "File management"
+ },
+ {
+ "url": "/create",
+ "state": "worker.card.dms.create",
+ "component": "vn-worker-dms-create",
+ "description": "Upload file",
+ "params": {
+ "worker": "$ctrl.worker"
+ }
+ },
+ {
+ "url": "/:dmsId/edit",
+ "state": "worker.card.dms.edit",
+ "component": "vn-worker-dms-edit",
+ "description": "Edit file",
+ "params": {
+ "worker": "$ctrl.worker"
+ }
}
]
}
\ No newline at end of file