From e314a67fe72f6112337330f7aefa1e46b7d7e84f Mon Sep 17 00:00:00 2001 From: jorgep Date: Thu, 23 Nov 2023 13:25:31 +0100 Subject: [PATCH 01/31] refs #6274 time control methods migrated --- .../methods/worker-time-control/clockIn.js | 34 ++++++++++++++++ .../methods/worker-time-control/getClockIn.js | 30 ++++++++++++++ .../back/methods/worker-time-control/login.js | 39 +++++++++++++++++++ .../worker/back/models/worker-time-control.js | 3 ++ 4 files changed, 106 insertions(+) create mode 100644 modules/worker/back/methods/worker-time-control/clockIn.js create mode 100644 modules/worker/back/methods/worker-time-control/getClockIn.js create mode 100644 modules/worker/back/methods/worker-time-control/login.js diff --git a/modules/worker/back/methods/worker-time-control/clockIn.js b/modules/worker/back/methods/worker-time-control/clockIn.js new file mode 100644 index 000000000..45de85f1d --- /dev/null +++ b/modules/worker/back/methods/worker-time-control/clockIn.js @@ -0,0 +1,34 @@ +module.exports = Self => { + Self.remoteMethodCtx('clockIn', { + description: 'Check if the employee can clock in', + accessType: 'READ', + accepts: [ + { + arg: 'workerFk', + type: 'integer', + required: true, + }, + { + arg: 'direction', + type: 'integer' + }, + { + arg: 'key', + type: 'string', + } + ], + http: { + path: `/clockIn`, + verb: 'POST' + } + }); + + Self.clockIn = async(ctx, pin, direction, key, options) => { + const myOptions = {}; + if (typeof options == 'object') + Object.assign(myOptions, options); + + const query = 'CALL vn.workerTimeControl_clockIn(?, NULL, ?)'; + return await Self.rawSql(query, [workerFk, direction], options); + }; +}; diff --git a/modules/worker/back/methods/worker-time-control/getClockIn.js b/modules/worker/back/methods/worker-time-control/getClockIn.js new file mode 100644 index 000000000..603914655 --- /dev/null +++ b/modules/worker/back/methods/worker-time-control/getClockIn.js @@ -0,0 +1,30 @@ +module.exports = Self => { + Self.remoteMethodCtx('getClockIn', { + description: 'Shows the clockings for each day, in columns per day', + accessType: 'READ', + accepts: [ + { + arg: 'workerFk', + type: 'int', + required: true, + }, + { + arg: 'key', + type: 'string', + } + ], + http: { + path: `/getClockIn`, + verb: 'POST' + } + }); + + Self.getClockIn = async(ctx, workerFk, key, options) => { + const myOptions = {}; + if (typeof options == 'object') + Object.assign(myOptions, options); + + const query = `CALL vn.workerTimeControl_getClockIn(?, CURDATE())`; + return await Self.rawSql(query, [workerFk], myOptions); + }; +}; diff --git a/modules/worker/back/methods/worker-time-control/login.js b/modules/worker/back/methods/worker-time-control/login.js new file mode 100644 index 000000000..75813411a --- /dev/null +++ b/modules/worker/back/methods/worker-time-control/login.js @@ -0,0 +1,39 @@ +const UserError = require('vn-loopback/util/user-error'); + +module.exports = Self => { + Self.remoteMethodCtx('login', { + description: 'Consult the user\'s information and the buttons that must be activated after logging in', + accessType: 'READ', + accepts: [ + { + arg: 'pin', + type: 'string', + required: true, + }, + { + arg: 'key', + type: 'string', + } + ], + returns: { + type: 'Object', + root: true + }, + http: { + path: `/login`, + verb: 'POST' + } + }); + + Self.login = async(ctx, pin, key, options) => { + const myOptions = {}; + if (typeof options == 'object') + Object.assign(myOptions, options); + + const query = `CALL vn.workerTimeControl_login(?)`; + const user = await Self.rawSql(query, [pin], myOptions); + + if (!user) throw new UserError('Indique el pin.'); + return user; + }; +}; diff --git a/modules/worker/back/models/worker-time-control.js b/modules/worker/back/models/worker-time-control.js index d5da680cf..1457c7a46 100644 --- a/modules/worker/back/models/worker-time-control.js +++ b/modules/worker/back/models/worker-time-control.js @@ -10,6 +10,9 @@ module.exports = Self => { require('../methods/worker-time-control/weeklyHourRecordEmail')(Self); require('../methods/worker-time-control/getMailStates')(Self); require('../methods/worker-time-control/resendWeeklyHourEmail')(Self); + require('../methods/worker-time-control/login')(Self); + require('../methods/worker-time-control/getClockIn')(Self); + require('../methods/worker-time-control/clockIn')(Self); Self.rewriteDbError(function(err) { if (err.code === 'ER_DUP_ENTRY') From 29fb36010cd303390b1f56b686d57d644f67ce88 Mon Sep 17 00:00:00 2001 From: jorgep Date: Tue, 28 Nov 2023 14:48:03 +0100 Subject: [PATCH 02/31] refs #6274 back methods created --- db/changes/235001/00-timecontrol.sql | 13 ++++++++++++ .../methods/worker-time-control/clockIn.js | 19 +++++++++--------- .../methods/worker-time-control/getClockIn.js | 20 ++++++++++--------- .../back/methods/worker-time-control/login.js | 10 +++------- 4 files changed, 37 insertions(+), 25 deletions(-) create mode 100644 db/changes/235001/00-timecontrol.sql diff --git a/db/changes/235001/00-timecontrol.sql b/db/changes/235001/00-timecontrol.sql new file mode 100644 index 000000000..ac7dc85d6 --- /dev/null +++ b/db/changes/235001/00-timecontrol.sql @@ -0,0 +1,13 @@ +INSERT INTO `account`.`role` (name, description) + VALUES ('timeControl','Tablet para fichar'); + +INSERT INTO `account`.`roleInherit` (role, inheritsFrom) + VALUES (127, 11); + +INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId) + VALUES + ('workerTimeControl', 'login', 'READ', 'ALLOW', 'ROLE', '*'), + ('workerTimeControl', 'getClockIn', 'READ', 'ALLOW', 'ROLE', '*'), + ('workerTimeControl', 'clockIn', 'WRITE', 'ALLOW', 'ROLE', '*'); + +CALL `account`.`role_sync`(); diff --git a/modules/worker/back/methods/worker-time-control/clockIn.js b/modules/worker/back/methods/worker-time-control/clockIn.js index 45de85f1d..3cc57d341 100644 --- a/modules/worker/back/methods/worker-time-control/clockIn.js +++ b/modules/worker/back/methods/worker-time-control/clockIn.js @@ -1,7 +1,7 @@ module.exports = Self => { - Self.remoteMethodCtx('clockIn', { + Self.remoteMethod('clockIn', { description: 'Check if the employee can clock in', - accessType: 'READ', + accessType: 'WRITE', accepts: [ { arg: 'workerFk', @@ -10,25 +10,26 @@ module.exports = Self => { }, { arg: 'direction', - type: 'integer' + type: 'string' }, - { - arg: 'key', - type: 'string', - } + ], http: { path: `/clockIn`, verb: 'POST' + }, + returns: { + type: 'Object', + root: true } }); - Self.clockIn = async(ctx, pin, direction, key, options) => { + Self.clockIn = async(workerFk, direction, options) => { const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); const query = 'CALL vn.workerTimeControl_clockIn(?, NULL, ?)'; - return await Self.rawSql(query, [workerFk, direction], options); + return await Self.rawSql(query, [workerFk, direction], myOptions); }; }; diff --git a/modules/worker/back/methods/worker-time-control/getClockIn.js b/modules/worker/back/methods/worker-time-control/getClockIn.js index 603914655..bc0675db8 100644 --- a/modules/worker/back/methods/worker-time-control/getClockIn.js +++ b/modules/worker/back/methods/worker-time-control/getClockIn.js @@ -1,5 +1,5 @@ module.exports = Self => { - Self.remoteMethodCtx('getClockIn', { + Self.remoteMethod('getClockIn', { description: 'Shows the clockings for each day, in columns per day', accessType: 'READ', accepts: [ @@ -8,23 +8,25 @@ module.exports = Self => { type: 'int', required: true, }, - { - arg: 'key', - type: 'string', - } + ], http: { path: `/getClockIn`, - verb: 'POST' - } + verb: 'GET' + }, + returns: { + type: ['Object'], + root: true + }, }); - Self.getClockIn = async(ctx, workerFk, key, options) => { + Self.getClockIn = async(workerFk, options) => { const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); const query = `CALL vn.workerTimeControl_getClockIn(?, CURDATE())`; - return await Self.rawSql(query, [workerFk], myOptions); + const [result] = await Self.rawSql(query, [workerFk], myOptions); + return result; }; }; diff --git a/modules/worker/back/methods/worker-time-control/login.js b/modules/worker/back/methods/worker-time-control/login.js index 75813411a..894b5ba17 100644 --- a/modules/worker/back/methods/worker-time-control/login.js +++ b/modules/worker/back/methods/worker-time-control/login.js @@ -1,7 +1,7 @@ const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { - Self.remoteMethodCtx('login', { + Self.remoteMethod('login', { description: 'Consult the user\'s information and the buttons that must be activated after logging in', accessType: 'READ', accepts: [ @@ -10,10 +10,6 @@ module.exports = Self => { type: 'string', required: true, }, - { - arg: 'key', - type: 'string', - } ], returns: { type: 'Object', @@ -25,7 +21,7 @@ module.exports = Self => { } }); - Self.login = async(ctx, pin, key, options) => { + Self.login = async(pin, options) => { const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); @@ -34,6 +30,6 @@ module.exports = Self => { const user = await Self.rawSql(query, [pin], myOptions); if (!user) throw new UserError('Indique el pin.'); - return user; + return user[0][0]; }; }; From 0186c2c80678f518de105192d1e306f2361f056a Mon Sep 17 00:00:00 2001 From: carlossa Date: Wed, 29 Nov 2023 07:33:49 +0100 Subject: [PATCH 03/31] refs #6085 aclMail back --- db/changes/235001/00-aclsMails.sql | 7 ++++ .../account/front/alias/acl/create/index.js | 33 +++++++++++++++++++ modules/account/front/alias/acl/index.js | 4 +++ .../account/front/alias/acl/index/index.js | 15 +++++++++ modules/account/front/alias/acl/main/index.js | 18 ++++++++++ 5 files changed, 77 insertions(+) create mode 100644 db/changes/235001/00-aclsMails.sql create mode 100644 modules/account/front/alias/acl/create/index.js create mode 100644 modules/account/front/alias/acl/index.js create mode 100644 modules/account/front/alias/acl/index/index.js create mode 100644 modules/account/front/alias/acl/main/index.js diff --git a/db/changes/235001/00-aclsMails.sql b/db/changes/235001/00-aclsMails.sql new file mode 100644 index 000000000..92603aec4 --- /dev/null +++ b/db/changes/235001/00-aclsMails.sql @@ -0,0 +1,7 @@ +-- Definición de la tabla mailAliasACL +CREATE TABLE `account`.`mailAliasACL` ( + `mailAliasFk` int(10) unsigned NOT NULL, + `roleFk` int(10) unsigned NOT NULL, + FOREIGN KEY (`mailAliasFk`) REFERENCES `account`.`mailAlias` (`id`), + FOREIGN KEY (`roleFk`) REFERENCES `account`.`role` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci; diff --git a/modules/account/front/alias/acl/create/index.js b/modules/account/front/alias/acl/create/index.js new file mode 100644 index 000000000..1f9d73272 --- /dev/null +++ b/modules/account/front/alias/acl/create/index.js @@ -0,0 +1,33 @@ +import ngModule from '../../module'; +import Section from 'salix/components/section'; + +export default class Controller extends Section { + constructor(...args) { + super(...args); + this.accessTypes = [ + {name: '*'}, + {name: 'READ'}, + {name: 'WRITE'} + ]; + this.permissions = [ + {name: 'ALLOW'}, + {name: 'DENY'} + ]; + + this.models = []; + for (let model in window.validations) + this.models.push({name: model}); + + this.acl = { + property: '*', + principalType: 'ROLE', + accessType: 'READ', + permission: 'ALLOW' + }; + } +} + +ngModule.component('vnAclMailCreate', { + template: require('./index.html'), + controller: Controller +}); diff --git a/modules/account/front/alias/acl/index.js b/modules/account/front/alias/acl/index.js new file mode 100644 index 000000000..8393859a5 --- /dev/null +++ b/modules/account/front/alias/acl/index.js @@ -0,0 +1,4 @@ +import './main'; +import './index/'; +import './create'; +import './search-panel'; diff --git a/modules/account/front/alias/acl/index/index.js b/modules/account/front/alias/acl/index/index.js new file mode 100644 index 000000000..b78dfa7f5 --- /dev/null +++ b/modules/account/front/alias/acl/index/index.js @@ -0,0 +1,15 @@ +import ngModule from '../../module'; +import Section from 'salix/components/section'; + +export default class Controller extends Section { + onDelete(row) { + return this.$http.delete(`ACLs/${row.id}`) + .then(() => this.$.model.refresh()) + .then(() => this.vnApp.showSuccess(this.$t('ACL removed'))); + } +} + +ngModule.component('vnAclMailIndex', { + template: require('./index.html'), + controller: Controller +}); diff --git a/modules/account/front/alias/acl/main/index.js b/modules/account/front/alias/acl/main/index.js new file mode 100644 index 000000000..431ef48c5 --- /dev/null +++ b/modules/account/front/alias/acl/main/index.js @@ -0,0 +1,18 @@ +import ngModule from '../../module'; +import ModuleMain from 'salix/components/module-main'; + +export default class ACL extends ModuleMain { + exprBuilder(param, value) { + switch (param) { + case 'search': + return {model: {like: `%${value}%`}}; + default: + return {[param]: value}; + } + } +} + +ngModule.vnComponent('vnAclMailComponent', { + controller: ACL, + template: require('./index.html') +}); From e548ef4dae1d056cfc2f34396a3e3e164ee2b9a8 Mon Sep 17 00:00:00 2001 From: carlossa Date: Wed, 29 Nov 2023 07:51:58 +0100 Subject: [PATCH 04/31] refs #6085 searchpanel and change path --- .../account/front/alias/acl/create/index.js | 4 +-- .../account/front/alias/acl/index/index.js | 4 +-- modules/account/front/alias/acl/main/index.js | 6 ++--- .../front/alias/acl/search-panel/index.js | 26 +++++++++++++++++++ modules/account/front/alias/index.js | 1 + 5 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 modules/account/front/alias/acl/search-panel/index.js diff --git a/modules/account/front/alias/acl/create/index.js b/modules/account/front/alias/acl/create/index.js index 1f9d73272..58e70e4aa 100644 --- a/modules/account/front/alias/acl/create/index.js +++ b/modules/account/front/alias/acl/create/index.js @@ -1,4 +1,4 @@ -import ngModule from '../../module'; +import ngModule from '../../../module'; import Section from 'salix/components/section'; export default class Controller extends Section { @@ -28,6 +28,6 @@ export default class Controller extends Section { } ngModule.component('vnAclMailCreate', { - template: require('./index.html'), + // template: require('./index.html'), controller: Controller }); diff --git a/modules/account/front/alias/acl/index/index.js b/modules/account/front/alias/acl/index/index.js index b78dfa7f5..5d8d49574 100644 --- a/modules/account/front/alias/acl/index/index.js +++ b/modules/account/front/alias/acl/index/index.js @@ -1,4 +1,4 @@ -import ngModule from '../../module'; +import ngModule from '../../../module'; import Section from 'salix/components/section'; export default class Controller extends Section { @@ -10,6 +10,6 @@ export default class Controller extends Section { } ngModule.component('vnAclMailIndex', { - template: require('./index.html'), + // template: require('./index.html'), controller: Controller }); diff --git a/modules/account/front/alias/acl/main/index.js b/modules/account/front/alias/acl/main/index.js index 431ef48c5..97f04ee50 100644 --- a/modules/account/front/alias/acl/main/index.js +++ b/modules/account/front/alias/acl/main/index.js @@ -1,4 +1,4 @@ -import ngModule from '../../module'; +import ngModule from '../../../module'; import ModuleMain from 'salix/components/module-main'; export default class ACL extends ModuleMain { @@ -13,6 +13,6 @@ export default class ACL extends ModuleMain { } ngModule.vnComponent('vnAclMailComponent', { - controller: ACL, - template: require('./index.html') + controller: ACL + // template: require('./index.html') }); diff --git a/modules/account/front/alias/acl/search-panel/index.js b/modules/account/front/alias/acl/search-panel/index.js new file mode 100644 index 000000000..67db33383 --- /dev/null +++ b/modules/account/front/alias/acl/search-panel/index.js @@ -0,0 +1,26 @@ +import ngModule from '../../../module'; +import SearchPanel from 'core/components/searchbar/search-panel'; + +export default class Controller extends SearchPanel { + constructor(...args) { + super(...args); + this.accessTypes = [ + {name: '*'}, + {name: 'READ'}, + {name: 'WRITE'} + ]; + this.permissions = [ + {name: 'ALLOW'}, + {name: 'DENY'} + ]; + + this.models = []; + for (let model in window.validations) + this.models.push({name: model}); + } +} + +ngModule.component('vnAclSearchPanel', { + // template: require('./index.html'), + controller: Controller +}); diff --git a/modules/account/front/alias/index.js b/modules/account/front/alias/index.js index 8eed3a3d3..598421749 100644 --- a/modules/account/front/alias/index.js +++ b/modules/account/front/alias/index.js @@ -7,3 +7,4 @@ import './descriptor'; import './create'; import './basic-data'; import './users'; +import './acl'; From 48dd068190e20819d9906b8212c5f1c74b58e00d Mon Sep 17 00:00:00 2001 From: jorgep Date: Wed, 29 Nov 2023 08:37:56 +0100 Subject: [PATCH 05/31] refs #6274 upperCase Model --- db/changes/235001/00-timecontrol.sql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/db/changes/235001/00-timecontrol.sql b/db/changes/235001/00-timecontrol.sql index ac7dc85d6..4e350b002 100644 --- a/db/changes/235001/00-timecontrol.sql +++ b/db/changes/235001/00-timecontrol.sql @@ -6,8 +6,8 @@ INSERT INTO `account`.`roleInherit` (role, inheritsFrom) INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId) VALUES - ('workerTimeControl', 'login', 'READ', 'ALLOW', 'ROLE', '*'), - ('workerTimeControl', 'getClockIn', 'READ', 'ALLOW', 'ROLE', '*'), - ('workerTimeControl', 'clockIn', 'WRITE', 'ALLOW', 'ROLE', '*'); + ('WorkerTimeControl', 'login', 'READ', 'ALLOW', 'ROLE', 'timeControl'), + ('WorkerTimeControl', 'getClockIn', 'READ', 'ALLOW', 'ROLE', 'timeControl'), + ('WorkerTimeControl', 'clockIn', 'WRITE', 'ALLOW', 'ROLE', 'timeControl'); CALL `account`.`role_sync`(); From 9a3efdd6fe9e29cf0dd6ca97c8c384e26bd99a53 Mon Sep 17 00:00:00 2001 From: carlossa Date: Wed, 29 Nov 2023 13:55:44 +0100 Subject: [PATCH 06/31] refs #6085 model y back --- modules/account/back/models/mail-alias-acl.js | 70 +++++++++++++++++++ .../account/back/models/mail-alias-acl.json | 29 ++++++++ 2 files changed, 99 insertions(+) create mode 100644 modules/account/back/models/mail-alias-acl.js create mode 100644 modules/account/back/models/mail-alias-acl.json diff --git a/modules/account/back/models/mail-alias-acl.js b/modules/account/back/models/mail-alias-acl.js new file mode 100644 index 000000000..4a74472fe --- /dev/null +++ b/modules/account/back/models/mail-alias-acl.js @@ -0,0 +1,70 @@ +const UserError = require('vn-loopback/util/user-error'); + +module.exports = Self => { + require('../methods/notification/getList')(Self); + + Self.observe('before save', async function(ctx) { + await checkModifyPermission(ctx); + }); + + Self.observe('before delete', async function(ctx) { + await checkModifyPermission(ctx); + }); + + async function checkModifyPermission(ctx) { + const models = Self.app.models; + const instance = ctx.instance; + const userId = ctx.options.accessToken.userId; + + let mailAliasFk; + let roleFk; + + if (instance) { + mailAliasFk = instance.mailAliasFk; + roleFk = instance.roleFk; + } else { + const mailAliasAcl = await models.MailAlias.findById(ctx.where.id); + mailAliasFk = mailAliasAcl.id; + roleFk = mailAliasAcl.roleFk; + } + + const role = await models.VnUser.findById(roleFk, {fields: ['id', 'role']}); + const available = await Self.getAvailable(roleFk); + const hasAcl = available.has(mailAliasFk); + + if (!hasAcl || (userId.role != role)) + throw new UserError('The alias cant be modified'); + } + + Self.getAvailable = async function(userId, options) { + const availableMailAliasMap = new Map(); + const models = Self.app.models; + + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + const roles = await models.RoleMapping.find({ + fields: ['roleId'], + where: {principalId: userId} + }, myOptions); + + const availableMailAlias = await models.MailAliasAcl.find({ + fields: ['mailAliasFk', 'roleFk'], + include: {relation: 'roleFk'}, + where: { + roleFk: { + inq: roles.map(role => role.roleId), + }, + } + }, myOptions); + + for (available of availableMailAlias) { + availableMailAliasMap.set(available.mailAliasFk, { + mailAliasFk: available.mailAliasFk, + }); + } + return availableMailAliasMap; + }; +}; diff --git a/modules/account/back/models/mail-alias-acl.json b/modules/account/back/models/mail-alias-acl.json new file mode 100644 index 000000000..2e44f38eb --- /dev/null +++ b/modules/account/back/models/mail-alias-acl.json @@ -0,0 +1,29 @@ +{ + "name": "mailAliasACL", + "base": "VnModel", + "options": { + "mysql": { + "table": "account.mailAliasACL" + } + }, + "properties": { + "mailAliasFk": { + "type": "number" + }, + "roleFk": { + "type": "number" + } + }, + "relations": { + "mailAlias": { + "type": "belongsTo", + "model": "VnUser", + "foreignKey": "mailAliasFk" + }, + "role": { + "type": "belongsTo", + "model": "VnUser", + "foreignKey": "roleFk" + } + } +} From 6d486fbec99ae2b471882a2b24530b5b34453f06 Mon Sep 17 00:00:00 2001 From: carlossa Date: Fri, 1 Dec 2023 13:58:45 +0100 Subject: [PATCH 07/31] refs #6085 trad, remove front, back test --- back/models/specs/mailAliasAccount.spec.js | 73 +++++++++++++++++++ db/changes/235001/00-aclsMails.sql | 3 +- db/dump/fixtures.sql | 7 ++ front/core/locale/es.yml | 1 + loopback/locale/es.json | 4 +- modules/account/back/model-config.json | 3 + .../account/back/models/mail-alias-account.js | 68 ++++++++--------- modules/account/back/models/mail-alias-acl.js | 59 ++++++--------- .../account/back/models/mail-alias-acl.json | 10 ++- .../account/front/alias/acl/create/index.js | 33 --------- modules/account/front/alias/acl/index.js | 4 - .../account/front/alias/acl/index/index.js | 15 ---- modules/account/front/alias/acl/main/index.js | 18 ----- .../front/alias/acl/search-panel/index.js | 26 ------- modules/account/front/alias/index.js | 1 - 15 files changed, 151 insertions(+), 174 deletions(-) create mode 100644 back/models/specs/mailAliasAccount.spec.js delete mode 100644 modules/account/front/alias/acl/create/index.js delete mode 100644 modules/account/front/alias/acl/index.js delete mode 100644 modules/account/front/alias/acl/index/index.js delete mode 100644 modules/account/front/alias/acl/main/index.js delete mode 100644 modules/account/front/alias/acl/search-panel/index.js diff --git a/back/models/specs/mailAliasAccount.spec.js b/back/models/specs/mailAliasAccount.spec.js new file mode 100644 index 000000000..46d447f90 --- /dev/null +++ b/back/models/specs/mailAliasAccount.spec.js @@ -0,0 +1,73 @@ +const models = require('vn-loopback/server/server').models; + +fdescribe('loopback model MailAliasAccount', () => { + it('should fail to add a mail Alias if the worker doesnt have ACLs', async() => { + const tx = await models.MailAliasAccount.beginTransaction({}); + let error; + + try { + const options = {transaction: tx, accessToken: {userId: 1}}; + await models.MailAliasAccount.create({mailAliasFk: 2, roleFk: 5}, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toEqual('The alias cant be modified'); + }); + + it('should add a mail Alias', async() => { + const tx = await models.MailAliasAccount.beginTransaction({}); + let error; + + try { + const options = {transaction: tx, accessToken: {userId: 9}}; + await models.MailAliasAccount.create({mailAliasFk: 2, roleFk: 5}, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error).toBeUndefined(); + }); + + it('should add a mail Alias of an inherit role', async() => { + const tx = await models.MailAliasAccount.beginTransaction({}); + let error; + + try { + const options = {transaction: tx, accessToken: {userId: 9}}; + await models.MailAliasAccount.create({mailAliasFk: 3, roleFk: 5}, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error).toBeUndefined(); + }); + + it('should delete a mail Alias', async() => { + const tx = await models.MailAliasAccount.beginTransaction({}); + let error; + + try { + const options = {transaction: tx, accessToken: {userId: 1}}; + const mailAclId = 2; + await models.MailAliasAccount.destroyAll({id: mailAclId}, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error).toBeUndefined(); + }); +}); + diff --git a/db/changes/235001/00-aclsMails.sql b/db/changes/235001/00-aclsMails.sql index 92603aec4..5cfea4030 100644 --- a/db/changes/235001/00-aclsMails.sql +++ b/db/changes/235001/00-aclsMails.sql @@ -1,5 +1,6 @@ -- Definición de la tabla mailAliasACL -CREATE TABLE `account`.`mailAliasACL` ( + +CREATE OR REPLACE TABLE `account`.`mailAliasAcl` ( `mailAliasFk` int(10) unsigned NOT NULL, `roleFk` int(10) unsigned NOT NULL, FOREIGN KEY (`mailAliasFk`) REFERENCES `account`.`mailAlias` (`id`), diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 93b7b796f..62f96b459 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -3002,3 +3002,10 @@ INSERT INTO `vn`.`invoiceCorrectionType` (`id`, `description`) (1, 'Error in VAT calculation'), (2, 'Error in sales details'), (3, 'Error in customer data'); + +INSERT INTO `account`.`mailAliasAcl` (`mailAliasFk`, `roleFk`) + VALUES + (1, 1), + (2, 9), + (3, 15); + diff --git a/front/core/locale/es.yml b/front/core/locale/es.yml index 96c34d98c..1b9bbb40b 100644 --- a/front/core/locale/es.yml +++ b/front/core/locale/es.yml @@ -68,3 +68,4 @@ Load more results: Cargar más resultados Send cau: Enviar cau By sending this ticket, all the data related to the error, the section, the user, etc., are already sent.: Al enviar este cau ya se envían todos los datos relacionados con el error, la sección, el usuario, etc ExplainReason: Explique el motivo por el que no deberia aparecer este fallo +You already have the mailAlias: Ya tienes este mail diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 01384efb4..2e516bf12 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -329,5 +329,7 @@ "The amount cannot be less than the minimum": "La cantidad no puede ser menor que la cantidad mínima", "quantityLessThanMin": "La cantidad no puede ser menor que la cantidad mínima", "Cannot past travels with entries": "No se pueden pasar envíos con entradas", - "It was not able to remove the next expeditions:": "No se pudo eliminar las siguientes expediciones: {{expeditions}}" + "It was not able to remove the next expeditions:": "No se pudo eliminar las siguientes expediciones: {{expeditions}}", + "You already have the mailAlias": "You already have the mailAlias", + "The alias cant be modified": "The alias cant be modified" } \ No newline at end of file diff --git a/modules/account/back/model-config.json b/modules/account/back/model-config.json index b4bd6dbaf..0cd43d0ce 100644 --- a/modules/account/back/model-config.json +++ b/modules/account/back/model-config.json @@ -14,6 +14,9 @@ "MailAliasAccount": { "dataSource": "vn" }, + "MailAliasAcl": { + "dataSource": "vn" + }, "MailConfig": { "dataSource": "vn" }, diff --git a/modules/account/back/models/mail-alias-account.js b/modules/account/back/models/mail-alias-account.js index 6f5213f24..a95189689 100644 --- a/modules/account/back/models/mail-alias-account.js +++ b/modules/account/back/models/mail-alias-account.js @@ -2,54 +2,54 @@ const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { + Self.rewriteDbError(function(err) { + if (err.code === 'ER_DUP_ENTRY') + return new UserError(`You already have the mailAlias`); + return err; + }); + Self.observe('before save', async ctx => { const changes = ctx.currentInstance || ctx.instance; - await Self.hasGrant(ctx, changes.mailAlias); + await checkModifyPermission(ctx, changes.mailAlias); }); Self.observe('before delete', async ctx => { const mailAliasAccount = await Self.findById(ctx.where.id); - await Self.hasGrant(ctx, mailAliasAccount.mailAlias); + await checkModifyPermission(ctx, mailAliasAccount.mailAlias); }); - /** - * Checks if current user has - * grant to add/remove alias - * - * @param {Object} ctx - Request context - * @param {Interger} mailAlias - mailAlias id - * @return {Boolean} True for user with grant - */ - Self.hasGrant = async function(ctx, mailAlias) { + async function checkModifyPermission(ctx, mailAliasFk) { + const userId = ctx.options.accessToken.userId; + const available = await Self.getAvailable(userId); + if (!available.has(mailAliasFk)) + throw new UserError('The alias cant be modified'); + } + + Self.getAvailable = async function(userId, options) { const models = Self.app.models; - const accessToken = {req: {accessToken: ctx.options.accessToken}}; - const userId = accessToken.req.accessToken.userId; - const canEditAlias = await models.ACL.checkAccessAcl(accessToken, 'MailAliasAccount', 'canEditAlias', 'WRITE'); - if (canEditAlias) return true; + const myOptions = {}; - const user = await models.VnUser.findById(userId, {fields: ['hasGrant']}); - if (!user.hasGrant) - throw new UserError(`You don't have grant privilege`); + if (typeof options == 'object') + Object.assign(myOptions, options); - const account = await models.Account.findById(userId, { - fields: ['id'], - include: { - relation: 'aliases', - scope: { - fields: ['mailAlias'] - } + const roles = await models.RoleMapping.find({ + fields: ['roleId'], + where: {principalId: userId} + }, myOptions); + + const availableMailAlias = await models.MailAliasAcl.find({ + fields: ['mailAliasFk'], + include: {relation: 'mailAlias'}, + where: { + roleFk: { + inq: roles.map(role => role.roleId), + }, } - }); - - const aliases = account.aliases().map(alias => alias.mailAlias); - - const hasAlias = aliases.includes(mailAlias); - if (!hasAlias) - throw new UserError(`You cannot assign/remove an alias that you are not assigned to`); - - return true; + }, myOptions); + const mailAliasArray = Array.from(availableMailAlias, alias => alias.mailAliasFk); + return new Set(mailAliasArray); }; }; diff --git a/modules/account/back/models/mail-alias-acl.js b/modules/account/back/models/mail-alias-acl.js index 4a74472fe..a95189689 100644 --- a/modules/account/back/models/mail-alias-acl.js +++ b/modules/account/back/models/mail-alias-acl.js @@ -1,43 +1,33 @@ + const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { - require('../methods/notification/getList')(Self); - - Self.observe('before save', async function(ctx) { - await checkModifyPermission(ctx); + Self.rewriteDbError(function(err) { + if (err.code === 'ER_DUP_ENTRY') + return new UserError(`You already have the mailAlias`); + return err; }); - Self.observe('before delete', async function(ctx) { - await checkModifyPermission(ctx); + Self.observe('before save', async ctx => { + const changes = ctx.currentInstance || ctx.instance; + + await checkModifyPermission(ctx, changes.mailAlias); }); - async function checkModifyPermission(ctx) { - const models = Self.app.models; - const instance = ctx.instance; + Self.observe('before delete', async ctx => { + const mailAliasAccount = await Self.findById(ctx.where.id); + + await checkModifyPermission(ctx, mailAliasAccount.mailAlias); + }); + + async function checkModifyPermission(ctx, mailAliasFk) { const userId = ctx.options.accessToken.userId; - - let mailAliasFk; - let roleFk; - - if (instance) { - mailAliasFk = instance.mailAliasFk; - roleFk = instance.roleFk; - } else { - const mailAliasAcl = await models.MailAlias.findById(ctx.where.id); - mailAliasFk = mailAliasAcl.id; - roleFk = mailAliasAcl.roleFk; - } - - const role = await models.VnUser.findById(roleFk, {fields: ['id', 'role']}); - const available = await Self.getAvailable(roleFk); - const hasAcl = available.has(mailAliasFk); - - if (!hasAcl || (userId.role != role)) + const available = await Self.getAvailable(userId); + if (!available.has(mailAliasFk)) throw new UserError('The alias cant be modified'); } Self.getAvailable = async function(userId, options) { - const availableMailAliasMap = new Map(); const models = Self.app.models; const myOptions = {}; @@ -51,20 +41,15 @@ module.exports = Self => { }, myOptions); const availableMailAlias = await models.MailAliasAcl.find({ - fields: ['mailAliasFk', 'roleFk'], - include: {relation: 'roleFk'}, + fields: ['mailAliasFk'], + include: {relation: 'mailAlias'}, where: { roleFk: { inq: roles.map(role => role.roleId), }, } }, myOptions); - - for (available of availableMailAlias) { - availableMailAliasMap.set(available.mailAliasFk, { - mailAliasFk: available.mailAliasFk, - }); - } - return availableMailAliasMap; + const mailAliasArray = Array.from(availableMailAlias, alias => alias.mailAliasFk); + return new Set(mailAliasArray); }; }; diff --git a/modules/account/back/models/mail-alias-acl.json b/modules/account/back/models/mail-alias-acl.json index 2e44f38eb..014b95d14 100644 --- a/modules/account/back/models/mail-alias-acl.json +++ b/modules/account/back/models/mail-alias-acl.json @@ -1,28 +1,30 @@ { - "name": "mailAliasACL", + "name": "MailAliasAcl", "base": "VnModel", "options": { "mysql": { - "table": "account.mailAliasACL" + "table": "account.mailAliasAcl" } }, "properties": { "mailAliasFk": { + "id": true, "type": "number" }, "roleFk": { + "id": true, "type": "number" } }, "relations": { "mailAlias": { "type": "belongsTo", - "model": "VnUser", + "model": "MailAlias", "foreignKey": "mailAliasFk" }, "role": { "type": "belongsTo", - "model": "VnUser", + "model": "Role", "foreignKey": "roleFk" } } diff --git a/modules/account/front/alias/acl/create/index.js b/modules/account/front/alias/acl/create/index.js deleted file mode 100644 index 58e70e4aa..000000000 --- a/modules/account/front/alias/acl/create/index.js +++ /dev/null @@ -1,33 +0,0 @@ -import ngModule from '../../../module'; -import Section from 'salix/components/section'; - -export default class Controller extends Section { - constructor(...args) { - super(...args); - this.accessTypes = [ - {name: '*'}, - {name: 'READ'}, - {name: 'WRITE'} - ]; - this.permissions = [ - {name: 'ALLOW'}, - {name: 'DENY'} - ]; - - this.models = []; - for (let model in window.validations) - this.models.push({name: model}); - - this.acl = { - property: '*', - principalType: 'ROLE', - accessType: 'READ', - permission: 'ALLOW' - }; - } -} - -ngModule.component('vnAclMailCreate', { - // template: require('./index.html'), - controller: Controller -}); diff --git a/modules/account/front/alias/acl/index.js b/modules/account/front/alias/acl/index.js deleted file mode 100644 index 8393859a5..000000000 --- a/modules/account/front/alias/acl/index.js +++ /dev/null @@ -1,4 +0,0 @@ -import './main'; -import './index/'; -import './create'; -import './search-panel'; diff --git a/modules/account/front/alias/acl/index/index.js b/modules/account/front/alias/acl/index/index.js deleted file mode 100644 index 5d8d49574..000000000 --- a/modules/account/front/alias/acl/index/index.js +++ /dev/null @@ -1,15 +0,0 @@ -import ngModule from '../../../module'; -import Section from 'salix/components/section'; - -export default class Controller extends Section { - onDelete(row) { - return this.$http.delete(`ACLs/${row.id}`) - .then(() => this.$.model.refresh()) - .then(() => this.vnApp.showSuccess(this.$t('ACL removed'))); - } -} - -ngModule.component('vnAclMailIndex', { - // template: require('./index.html'), - controller: Controller -}); diff --git a/modules/account/front/alias/acl/main/index.js b/modules/account/front/alias/acl/main/index.js deleted file mode 100644 index 97f04ee50..000000000 --- a/modules/account/front/alias/acl/main/index.js +++ /dev/null @@ -1,18 +0,0 @@ -import ngModule from '../../../module'; -import ModuleMain from 'salix/components/module-main'; - -export default class ACL extends ModuleMain { - exprBuilder(param, value) { - switch (param) { - case 'search': - return {model: {like: `%${value}%`}}; - default: - return {[param]: value}; - } - } -} - -ngModule.vnComponent('vnAclMailComponent', { - controller: ACL - // template: require('./index.html') -}); diff --git a/modules/account/front/alias/acl/search-panel/index.js b/modules/account/front/alias/acl/search-panel/index.js deleted file mode 100644 index 67db33383..000000000 --- a/modules/account/front/alias/acl/search-panel/index.js +++ /dev/null @@ -1,26 +0,0 @@ -import ngModule from '../../../module'; -import SearchPanel from 'core/components/searchbar/search-panel'; - -export default class Controller extends SearchPanel { - constructor(...args) { - super(...args); - this.accessTypes = [ - {name: '*'}, - {name: 'READ'}, - {name: 'WRITE'} - ]; - this.permissions = [ - {name: 'ALLOW'}, - {name: 'DENY'} - ]; - - this.models = []; - for (let model in window.validations) - this.models.push({name: model}); - } -} - -ngModule.component('vnAclSearchPanel', { - // template: require('./index.html'), - controller: Controller -}); diff --git a/modules/account/front/alias/index.js b/modules/account/front/alias/index.js index 598421749..8eed3a3d3 100644 --- a/modules/account/front/alias/index.js +++ b/modules/account/front/alias/index.js @@ -7,4 +7,3 @@ import './descriptor'; import './create'; import './basic-data'; import './users'; -import './acl'; From c0ce7e542febf97895ad6ff14e9869f182407e05 Mon Sep 17 00:00:00 2001 From: carlossa Date: Mon, 4 Dec 2023 09:40:57 +0100 Subject: [PATCH 08/31] refs #6085 solve testback --- back/models/specs/mailAliasAccount.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/back/models/specs/mailAliasAccount.spec.js b/back/models/specs/mailAliasAccount.spec.js index 46d447f90..c07e16d60 100644 --- a/back/models/specs/mailAliasAccount.spec.js +++ b/back/models/specs/mailAliasAccount.spec.js @@ -24,7 +24,7 @@ fdescribe('loopback model MailAliasAccount', () => { try { const options = {transaction: tx, accessToken: {userId: 9}}; - await models.MailAliasAccount.create({mailAliasFk: 2, roleFk: 5}, options); + await models.MailAliasAccount.create({mailAlias: 2, account: 5}, options); await tx.rollback(); } catch (e) { @@ -41,7 +41,7 @@ fdescribe('loopback model MailAliasAccount', () => { try { const options = {transaction: tx, accessToken: {userId: 9}}; - await models.MailAliasAccount.create({mailAliasFk: 3, roleFk: 5}, options); + await models.MailAliasAccount.create({mailAlias: 3, account: 5}, options); await tx.rollback(); } catch (e) { From 051c93a42cdee0ab6403924c95cc1dd4771e6859 Mon Sep 17 00:00:00 2001 From: carlossa Date: Mon, 4 Dec 2023 09:41:24 +0100 Subject: [PATCH 09/31] remove fdescribe --- back/models/specs/mailAliasAccount.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/back/models/specs/mailAliasAccount.spec.js b/back/models/specs/mailAliasAccount.spec.js index c07e16d60..d26ed2313 100644 --- a/back/models/specs/mailAliasAccount.spec.js +++ b/back/models/specs/mailAliasAccount.spec.js @@ -1,6 +1,6 @@ const models = require('vn-loopback/server/server').models; -fdescribe('loopback model MailAliasAccount', () => { +describe('loopback model MailAliasAccount', () => { it('should fail to add a mail Alias if the worker doesnt have ACLs', async() => { const tx = await models.MailAliasAccount.beginTransaction({}); let error; From 419ab418160579a6fa8f420a4fe098199d1f0a8e Mon Sep 17 00:00:00 2001 From: jorgep Date: Tue, 5 Dec 2023 09:55:22 +0100 Subject: [PATCH 10/31] refs #6276 Acl addTimeEntry --- db/changes/235001/00-timecontrol.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/changes/235001/00-timecontrol.sql b/db/changes/235001/00-timecontrol.sql index 4e350b002..8b59c1cac 100644 --- a/db/changes/235001/00-timecontrol.sql +++ b/db/changes/235001/00-timecontrol.sql @@ -8,6 +8,6 @@ INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalTyp VALUES ('WorkerTimeControl', 'login', 'READ', 'ALLOW', 'ROLE', 'timeControl'), ('WorkerTimeControl', 'getClockIn', 'READ', 'ALLOW', 'ROLE', 'timeControl'), - ('WorkerTimeControl', 'clockIn', 'WRITE', 'ALLOW', 'ROLE', 'timeControl'); + ('WorkerTimeControl', 'addTimeEntry', 'WRITE', 'ALLOW', 'ROLE', 'timeControl'); CALL `account`.`role_sync`(); From 25006a938be9214bcd62690d5c3c1709053a0e26 Mon Sep 17 00:00:00 2001 From: jorgep Date: Tue, 5 Dec 2023 11:53:27 +0100 Subject: [PATCH 11/31] refs #6274 refactor clockIn --- db/changes/235001/00-timecontrol.sql | 2 +- .../methods/worker-time-control/addTimeEntry.js | 5 +---- .../back/methods/worker-time-control/clockIn.js | 16 +++++++++++++--- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/db/changes/235001/00-timecontrol.sql b/db/changes/235001/00-timecontrol.sql index 8b59c1cac..4e350b002 100644 --- a/db/changes/235001/00-timecontrol.sql +++ b/db/changes/235001/00-timecontrol.sql @@ -8,6 +8,6 @@ INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalTyp VALUES ('WorkerTimeControl', 'login', 'READ', 'ALLOW', 'ROLE', 'timeControl'), ('WorkerTimeControl', 'getClockIn', 'READ', 'ALLOW', 'ROLE', 'timeControl'), - ('WorkerTimeControl', 'addTimeEntry', 'WRITE', 'ALLOW', 'ROLE', 'timeControl'); + ('WorkerTimeControl', 'clockIn', 'WRITE', 'ALLOW', 'ROLE', 'timeControl'); CALL `account`.`role_sync`(); diff --git a/modules/worker/back/methods/worker-time-control/addTimeEntry.js b/modules/worker/back/methods/worker-time-control/addTimeEntry.js index cc652fb90..f3b0127c4 100644 --- a/modules/worker/back/methods/worker-time-control/addTimeEntry.js +++ b/modules/worker/back/methods/worker-time-control/addTimeEntry.js @@ -46,10 +46,7 @@ module.exports = Self => { if (!isSubordinate || (isSubordinate && isHimself && !isTeamBoss)) throw new UserError(`You don't have enough privileges`); - query = `CALL vn.workerTimeControl_clockIn(?,?,?)`; - const [response] = await Self.rawSql(query, [workerId, args.timed, args.direction], myOptions); - if (response[0] && response[0].error) - throw new UserError(response[0].error); + const response = await Self.clockIn(workerId, args.timed, args.direction, myOptions); await models.WorkerTimeControl.resendWeeklyHourEmail(ctx, workerId, args.timed, myOptions); diff --git a/modules/worker/back/methods/worker-time-control/clockIn.js b/modules/worker/back/methods/worker-time-control/clockIn.js index 3cc57d341..6ed742778 100644 --- a/modules/worker/back/methods/worker-time-control/clockIn.js +++ b/modules/worker/back/methods/worker-time-control/clockIn.js @@ -1,3 +1,5 @@ +const UserError = require('vn-loopback/util/user-error'); + module.exports = Self => { Self.remoteMethod('clockIn', { description: 'Check if the employee can clock in', @@ -8,6 +10,10 @@ module.exports = Self => { type: 'integer', required: true, }, + { + arg: 'timed', + type: 'date' + }, { arg: 'direction', type: 'string' @@ -24,12 +30,16 @@ module.exports = Self => { } }); - Self.clockIn = async(workerFk, direction, options) => { + Self.clockIn = async(workerFk, timed, direction, options) => { const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); - const query = 'CALL vn.workerTimeControl_clockIn(?, NULL, ?)'; - return await Self.rawSql(query, [workerFk, direction], myOptions); + const query = 'CALL vn.workerTimeControl_clockIn(?, ?, ?)'; + const [response] = await Self.rawSql(query, [workerFk, timed, direction], myOptions); + if (response[0] && response[0].error) + throw new UserError(response[0].error); + + return response; }; }; From b50a6add0d5e7cc2678a35ff9707f20457dec769 Mon Sep 17 00:00:00 2001 From: jorgep Date: Tue, 5 Dec 2023 15:57:42 +0100 Subject: [PATCH 12/31] refs #6274 merge renewToken --- db/changes/235001/00-timecontrol.sql | 3 ++- db/changes/{234601 => 235001}/00-updateCourtesyTime.sql | 0 2 files changed, 2 insertions(+), 1 deletion(-) rename db/changes/{234601 => 235001}/00-updateCourtesyTime.sql (100%) diff --git a/db/changes/235001/00-timecontrol.sql b/db/changes/235001/00-timecontrol.sql index 4e350b002..0d3bd59b2 100644 --- a/db/changes/235001/00-timecontrol.sql +++ b/db/changes/235001/00-timecontrol.sql @@ -8,6 +8,7 @@ INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalTyp VALUES ('WorkerTimeControl', 'login', 'READ', 'ALLOW', 'ROLE', 'timeControl'), ('WorkerTimeControl', 'getClockIn', 'READ', 'ALLOW', 'ROLE', 'timeControl'), - ('WorkerTimeControl', 'clockIn', 'WRITE', 'ALLOW', 'ROLE', 'timeControl'); + ('WorkerTimeControl', 'clockIn', 'WRITE', 'ALLOW', 'ROLE', 'timeControl'), + ('VnUser', 'renewToken', 'WRITE', 'ALLOW', 'ROLE', 'timeControl'); CALL `account`.`role_sync`(); diff --git a/db/changes/234601/00-updateCourtesyTime.sql b/db/changes/235001/00-updateCourtesyTime.sql similarity index 100% rename from db/changes/234601/00-updateCourtesyTime.sql rename to db/changes/235001/00-updateCourtesyTime.sql From 968dc6523132aab070131880afe6bdad55c0931f Mon Sep 17 00:00:00 2001 From: jorgep Date: Thu, 7 Dec 2023 14:47:22 +0100 Subject: [PATCH 13/31] refs #6274 tests created --- .../worker-time-control/addTimeEntry.js | 8 ++---- .../methods/worker-time-control/clockIn.js | 2 +- .../methods/worker-time-control/getClockIn.js | 4 +-- .../resendWeeklyHourEmail.js | 2 +- .../worker-time-control/specs/clockIn.spec.js | 28 +++++++++++++++++++ .../specs/getClockIn.spec.js | 16 +++++++++++ .../worker-time-control/specs/login.spec.js | 20 +++++++++++++ 7 files changed, 70 insertions(+), 10 deletions(-) create mode 100644 modules/worker/back/methods/worker-time-control/specs/clockIn.spec.js create mode 100644 modules/worker/back/methods/worker-time-control/specs/getClockIn.spec.js create mode 100644 modules/worker/back/methods/worker-time-control/specs/login.spec.js diff --git a/modules/worker/back/methods/worker-time-control/addTimeEntry.js b/modules/worker/back/methods/worker-time-control/addTimeEntry.js index f3b0127c4..96e3a47d9 100644 --- a/modules/worker/back/methods/worker-time-control/addTimeEntry.js +++ b/modules/worker/back/methods/worker-time-control/addTimeEntry.js @@ -43,13 +43,9 @@ module.exports = Self => { const isTeamBoss = await models.ACL.checkAccessAcl(ctx, 'Worker', 'isTeamBoss', 'WRITE'); const isHimself = userId == workerId; - if (!isSubordinate || (isSubordinate && isHimself && !isTeamBoss)) + if (!isSubordinate || (isHimself && !isTeamBoss)) throw new UserError(`You don't have enough privileges`); - const response = await Self.clockIn(workerId, args.timed, args.direction, myOptions); - - await models.WorkerTimeControl.resendWeeklyHourEmail(ctx, workerId, args.timed, myOptions); - - return response; + return await Self.clockIn(workerId, args.timed, args.direction, myOptions); }; }; diff --git a/modules/worker/back/methods/worker-time-control/clockIn.js b/modules/worker/back/methods/worker-time-control/clockIn.js index 6ed742778..2e2441cc2 100644 --- a/modules/worker/back/methods/worker-time-control/clockIn.js +++ b/modules/worker/back/methods/worker-time-control/clockIn.js @@ -7,7 +7,7 @@ module.exports = Self => { accepts: [ { arg: 'workerFk', - type: 'integer', + type: 'number', required: true, }, { diff --git a/modules/worker/back/methods/worker-time-control/getClockIn.js b/modules/worker/back/methods/worker-time-control/getClockIn.js index bc0675db8..470700643 100644 --- a/modules/worker/back/methods/worker-time-control/getClockIn.js +++ b/modules/worker/back/methods/worker-time-control/getClockIn.js @@ -25,8 +25,8 @@ module.exports = Self => { if (typeof options == 'object') Object.assign(myOptions, options); - const query = `CALL vn.workerTimeControl_getClockIn(?, CURDATE())`; - const [result] = await Self.rawSql(query, [workerFk], myOptions); + const query = `CALL vn.workerTimeControl_getClockIn(?, ?)`; + const [result] = await Self.rawSql(query, [workerFk, Date.vnNew()], myOptions); return result; }; }; diff --git a/modules/worker/back/methods/worker-time-control/resendWeeklyHourEmail.js b/modules/worker/back/methods/worker-time-control/resendWeeklyHourEmail.js index 2452a29f9..896458455 100644 --- a/modules/worker/back/methods/worker-time-control/resendWeeklyHourEmail.js +++ b/modules/worker/back/methods/worker-time-control/resendWeeklyHourEmail.js @@ -1,6 +1,6 @@ module.exports = Self => { Self.remoteMethodCtx('resendWeeklyHourEmail', { - description: 'Adds a new hour registry', + description: 'Send the records for the week of the date provided', accessType: 'WRITE', accepts: [{ arg: 'id', diff --git a/modules/worker/back/methods/worker-time-control/specs/clockIn.spec.js b/modules/worker/back/methods/worker-time-control/specs/clockIn.spec.js new file mode 100644 index 000000000..970fd2fe2 --- /dev/null +++ b/modules/worker/back/methods/worker-time-control/specs/clockIn.spec.js @@ -0,0 +1,28 @@ +const models = require('vn-loopback/server/server').models; + +describe('workerTimeControl clockIn()', () => { + const workerId = 9; + const inTime = '2001-01-01T00:00:00.000Z'; + + it('should correctly clock in', async() => { + const tx = await models.WorkerTimeControl.beginTransaction({}); + + try { + const options = {transaction: tx}; + await models.WorkerTimeControl.clockIn(workerId, inTime, 'in', options); + const isClockIn = await models.WorkerTimeControl.findOne({ + where: { + userFk: workerId + } + }, options); + + expect(isClockIn).toBeDefined(); + expect(isClockIn.direction).toBe('in'); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); +}); + diff --git a/modules/worker/back/methods/worker-time-control/specs/getClockIn.spec.js b/modules/worker/back/methods/worker-time-control/specs/getClockIn.spec.js new file mode 100644 index 000000000..d75ffac70 --- /dev/null +++ b/modules/worker/back/methods/worker-time-control/specs/getClockIn.spec.js @@ -0,0 +1,16 @@ +const models = require('vn-loopback/server/server').models; + +describe('workerTimeControl getClockIn()', () => { + it('should correctly get the timetable of a worker', async() => { + const response = await models.WorkerTimeControl.getClockIn(1106, {}); + + expect(response.length).toEqual(4); + const [inHrs, middleOutHrs, middleInHrs, outHrs] = response; + + expect(inHrs['0daysAgo']).toEqual('07:00'); + expect(middleOutHrs['0daysAgo']).toEqual('10:00'); + expect(middleInHrs['0daysAgo']).toEqual('10:20'); + expect(outHrs['0daysAgo']).toEqual('14:50'); + }); +}); + diff --git a/modules/worker/back/methods/worker-time-control/specs/login.spec.js b/modules/worker/back/methods/worker-time-control/specs/login.spec.js new file mode 100644 index 000000000..88596f297 --- /dev/null +++ b/modules/worker/back/methods/worker-time-control/specs/login.spec.js @@ -0,0 +1,20 @@ +const UserError = require('vn-loopback/util/user-error'); +const models = require('vn-loopback/server/server').models; + +describe('workerTimeControl login()', () => { + it('should correctly login', async() => { + const response = await models.WorkerTimeControl.login(9, {}); + + expect(response.name).toBe('developer'); + }); + + it('should throw UserError if pin is not provided', async() => { + try { + await models.WorkerTimeControl.login(); + } catch (error) { + expect(error).toBeInstanceOf(UserError); + expect(error.message).toBe('Indique el pin.'); + } + }); +}); + From 584f3264edc86712c840998d5794c9b34c7fd632 Mon Sep 17 00:00:00 2001 From: carlossa Date: Mon, 11 Dec 2023 08:54:58 +0100 Subject: [PATCH 14/31] refs #6085 refactor sql trad --- .../{235001 => 235201}/00-aclsMails.sql | 0 front/core/locale/es.yml | 2 +- loopback/locale/es.json | 6 +- .../account/back/models/mail-alias-account.js | 14 ++--- modules/account/back/models/mail-alias-acl.js | 55 ------------------- 5 files changed, 9 insertions(+), 68 deletions(-) rename db/changes/{235001 => 235201}/00-aclsMails.sql (100%) delete mode 100644 modules/account/back/models/mail-alias-acl.js diff --git a/db/changes/235001/00-aclsMails.sql b/db/changes/235201/00-aclsMails.sql similarity index 100% rename from db/changes/235001/00-aclsMails.sql rename to db/changes/235201/00-aclsMails.sql diff --git a/front/core/locale/es.yml b/front/core/locale/es.yml index 1b9bbb40b..17e955ff5 100644 --- a/front/core/locale/es.yml +++ b/front/core/locale/es.yml @@ -68,4 +68,4 @@ Load more results: Cargar más resultados Send cau: Enviar cau By sending this ticket, all the data related to the error, the section, the user, etc., are already sent.: Al enviar este cau ya se envían todos los datos relacionados con el error, la sección, el usuario, etc ExplainReason: Explique el motivo por el que no deberia aparecer este fallo -You already have the mailAlias: Ya tienes este mail +You already have the mailAlias: Ya tienes este alias de correo diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 2e516bf12..c26bf3ebc 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -330,6 +330,6 @@ "quantityLessThanMin": "La cantidad no puede ser menor que la cantidad mínima", "Cannot past travels with entries": "No se pueden pasar envíos con entradas", "It was not able to remove the next expeditions:": "No se pudo eliminar las siguientes expediciones: {{expeditions}}", - "You already have the mailAlias": "You already have the mailAlias", - "The alias cant be modified": "The alias cant be modified" -} \ No newline at end of file + "You already have the mailAlias": "Ya tienes este alias de correo", + "The alias cant be modified": "Este alias de correo no puede ser modificado" +} diff --git a/modules/account/back/models/mail-alias-account.js b/modules/account/back/models/mail-alias-account.js index a95189689..91fc43008 100644 --- a/modules/account/back/models/mail-alias-account.js +++ b/modules/account/back/models/mail-alias-account.js @@ -22,12 +22,6 @@ module.exports = Self => { async function checkModifyPermission(ctx, mailAliasFk) { const userId = ctx.options.accessToken.userId; - const available = await Self.getAvailable(userId); - if (!available.has(mailAliasFk)) - throw new UserError('The alias cant be modified'); - } - - Self.getAvailable = async function(userId, options) { const models = Self.app.models; const myOptions = {}; @@ -47,9 +41,11 @@ module.exports = Self => { roleFk: { inq: roles.map(role => role.roleId), }, + mailAliasFk } }, myOptions); - const mailAliasArray = Array.from(availableMailAlias, alias => alias.mailAliasFk); - return new Set(mailAliasArray); - }; + + console.log(availableMailAlias); + if (!availableMailAlias.length) throw new UserError('The alias cant be modified'); + } }; diff --git a/modules/account/back/models/mail-alias-acl.js b/modules/account/back/models/mail-alias-acl.js deleted file mode 100644 index a95189689..000000000 --- a/modules/account/back/models/mail-alias-acl.js +++ /dev/null @@ -1,55 +0,0 @@ - -const UserError = require('vn-loopback/util/user-error'); - -module.exports = Self => { - Self.rewriteDbError(function(err) { - if (err.code === 'ER_DUP_ENTRY') - return new UserError(`You already have the mailAlias`); - return err; - }); - - Self.observe('before save', async ctx => { - const changes = ctx.currentInstance || ctx.instance; - - await checkModifyPermission(ctx, changes.mailAlias); - }); - - Self.observe('before delete', async ctx => { - const mailAliasAccount = await Self.findById(ctx.where.id); - - await checkModifyPermission(ctx, mailAliasAccount.mailAlias); - }); - - async function checkModifyPermission(ctx, mailAliasFk) { - const userId = ctx.options.accessToken.userId; - const available = await Self.getAvailable(userId); - if (!available.has(mailAliasFk)) - throw new UserError('The alias cant be modified'); - } - - Self.getAvailable = async function(userId, options) { - const models = Self.app.models; - - const myOptions = {}; - - if (typeof options == 'object') - Object.assign(myOptions, options); - - const roles = await models.RoleMapping.find({ - fields: ['roleId'], - where: {principalId: userId} - }, myOptions); - - const availableMailAlias = await models.MailAliasAcl.find({ - fields: ['mailAliasFk'], - include: {relation: 'mailAlias'}, - where: { - roleFk: { - inq: roles.map(role => role.roleId), - }, - } - }, myOptions); - const mailAliasArray = Array.from(availableMailAlias, alias => alias.mailAliasFk); - return new Set(mailAliasArray); - }; -}; From 57ed36cdfc3a0015da94a0eacc74bb0bbcef1505 Mon Sep 17 00:00:00 2001 From: carlossa Date: Mon, 11 Dec 2023 09:43:38 +0100 Subject: [PATCH 15/31] ref #6085 remove console options --- modules/account/back/models/mail-alias-account.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/account/back/models/mail-alias-account.js b/modules/account/back/models/mail-alias-account.js index 91fc43008..cf9c73f3b 100644 --- a/modules/account/back/models/mail-alias-account.js +++ b/modules/account/back/models/mail-alias-account.js @@ -26,8 +26,7 @@ module.exports = Self => { const myOptions = {}; - if (typeof options == 'object') - Object.assign(myOptions, options); + Object.assign(myOptions); const roles = await models.RoleMapping.find({ fields: ['roleId'], @@ -45,7 +44,6 @@ module.exports = Self => { } }, myOptions); - console.log(availableMailAlias); if (!availableMailAlias.length) throw new UserError('The alias cant be modified'); } }; From 6ac5d28c4003cd7a192955d5538e5074e45d8b11 Mon Sep 17 00:00:00 2001 From: carlossa Date: Mon, 11 Dec 2023 09:59:09 +0100 Subject: [PATCH 16/31] refs #6085 fix back --- back/models/specs/mailAliasAccount.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/back/models/specs/mailAliasAccount.spec.js b/back/models/specs/mailAliasAccount.spec.js index d26ed2313..c13cc7ae8 100644 --- a/back/models/specs/mailAliasAccount.spec.js +++ b/back/models/specs/mailAliasAccount.spec.js @@ -6,8 +6,8 @@ describe('loopback model MailAliasAccount', () => { let error; try { - const options = {transaction: tx, accessToken: {userId: 1}}; - await models.MailAliasAccount.create({mailAliasFk: 2, roleFk: 5}, options); + const options = {transaction: tx, accessToken: {userId: 57}}; + await models.MailAliasAccount.create({mailAlias: 2, account: 5}, options); await tx.rollback(); } catch (e) { From 53ff8784ffd8c388b3f3607a1d09977980fa4cf3 Mon Sep 17 00:00:00 2001 From: carlossa Date: Mon, 11 Dec 2023 10:16:46 +0100 Subject: [PATCH 17/31] refs #6085 remove myOptions --- modules/account/back/models/mail-alias-account.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/modules/account/back/models/mail-alias-account.js b/modules/account/back/models/mail-alias-account.js index cf9c73f3b..8f8e45ae8 100644 --- a/modules/account/back/models/mail-alias-account.js +++ b/modules/account/back/models/mail-alias-account.js @@ -24,14 +24,10 @@ module.exports = Self => { const userId = ctx.options.accessToken.userId; const models = Self.app.models; - const myOptions = {}; - - Object.assign(myOptions); - const roles = await models.RoleMapping.find({ fields: ['roleId'], where: {principalId: userId} - }, myOptions); + }); const availableMailAlias = await models.MailAliasAcl.find({ fields: ['mailAliasFk'], @@ -42,7 +38,7 @@ module.exports = Self => { }, mailAliasFk } - }, myOptions); + }); if (!availableMailAlias.length) throw new UserError('The alias cant be modified'); } From 2beb1f65f09847b78ec5e486af4f359a36887cb0 Mon Sep 17 00:00:00 2001 From: carlossa Date: Mon, 11 Dec 2023 12:45:55 +0100 Subject: [PATCH 18/31] refs #6085 findOne --- modules/account/back/models/mail-alias-account.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/account/back/models/mail-alias-account.js b/modules/account/back/models/mail-alias-account.js index 8f8e45ae8..5eb561408 100644 --- a/modules/account/back/models/mail-alias-account.js +++ b/modules/account/back/models/mail-alias-account.js @@ -29,7 +29,7 @@ module.exports = Self => { where: {principalId: userId} }); - const availableMailAlias = await models.MailAliasAcl.find({ + const availableMailAlias = await models.MailAliasAcl.findOne({ fields: ['mailAliasFk'], include: {relation: 'mailAlias'}, where: { @@ -40,6 +40,6 @@ module.exports = Self => { } }); - if (!availableMailAlias.length) throw new UserError('The alias cant be modified'); + if (!availableMailAlias) throw new UserError('The alias cant be modified'); } }; From 84270587cb8beeeab9db0aa56a5af1c1e26250d2 Mon Sep 17 00:00:00 2001 From: jorgep Date: Mon, 11 Dec 2023 13:42:19 +0100 Subject: [PATCH 19/31] refs #6274 refactor --- modules/worker/back/methods/worker-time-control/addTimeEntry.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/worker/back/methods/worker-time-control/addTimeEntry.js b/modules/worker/back/methods/worker-time-control/addTimeEntry.js index 96e3a47d9..5dbac51ca 100644 --- a/modules/worker/back/methods/worker-time-control/addTimeEntry.js +++ b/modules/worker/back/methods/worker-time-control/addTimeEntry.js @@ -46,6 +46,6 @@ module.exports = Self => { if (!isSubordinate || (isHimself && !isTeamBoss)) throw new UserError(`You don't have enough privileges`); - return await Self.clockIn(workerId, args.timed, args.direction, myOptions); + return Self.clockIn(workerId, args.timed, args.direction, myOptions); }; }; From 7777696cf75d7ce20c18bdc48f40ad251a0a5b6f Mon Sep 17 00:00:00 2001 From: alexm Date: Tue, 19 Dec 2023 13:58:08 +0100 Subject: [PATCH 20/31] refs #6589 fix(worker_absences): fix started hours --- modules/worker/back/methods/calendar/absences.js | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/worker/back/methods/calendar/absences.js b/modules/worker/back/methods/calendar/absences.js index 8420ed770..8a5d18987 100644 --- a/modules/worker/back/methods/calendar/absences.js +++ b/modules/worker/back/methods/calendar/absences.js @@ -39,6 +39,7 @@ module.exports = Self => { started.setFullYear(year); started.setMonth(0); started.setDate(1); + started.setHours(0, 0, 0, 0); const ended = Date.vnNew(); ended.setFullYear(year); From 542b09073e627bd4cc442c2a98979e370cdedf54 Mon Sep 17 00:00:00 2001 From: jorgep Date: Wed, 20 Dec 2023 14:02:05 +0100 Subject: [PATCH 21/31] changes moved: refs #6274 --- db/changes/{235001 => 235201}/00-timecontrol.sql | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename db/changes/{235001 => 235201}/00-timecontrol.sql (100%) diff --git a/db/changes/235001/00-timecontrol.sql b/db/changes/235201/00-timecontrol.sql similarity index 100% rename from db/changes/235001/00-timecontrol.sql rename to db/changes/235201/00-timecontrol.sql From f384616d693ae5c3121effb1baa815e4388c9865 Mon Sep 17 00:00:00 2001 From: jorgep Date: Thu, 21 Dec 2023 08:57:46 +0100 Subject: [PATCH 22/31] move changes: refs #6274 --- db/changes/{235001 => 240201}/00-updateCourtesyTime.sql | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename db/changes/{235001 => 240201}/00-updateCourtesyTime.sql (100%) diff --git a/db/changes/235001/00-updateCourtesyTime.sql b/db/changes/240201/00-updateCourtesyTime.sql similarity index 100% rename from db/changes/235001/00-updateCourtesyTime.sql rename to db/changes/240201/00-updateCourtesyTime.sql From 0f20f95dc581f9454f84f8f944812735083a411b Mon Sep 17 00:00:00 2001 From: guillermo Date: Thu, 21 Dec 2023 10:08:17 +0100 Subject: [PATCH 23/31] refactor: refs #6433 Deleted isPreviousPrepared* columns in model --- modules/shelving/back/models/sector.json | 8 -------- 1 file changed, 8 deletions(-) diff --git a/modules/shelving/back/models/sector.json b/modules/shelving/back/models/sector.json index 47d66bd8d..5ff67491b 100644 --- a/modules/shelving/back/models/sector.json +++ b/modules/shelving/back/models/sector.json @@ -20,18 +20,10 @@ "type": "number", "required": true }, - "isPreviousPreparedByPacking": { - "type": "boolean", - "required": true - }, "code": { "type": "string", "required": false }, - "isPreviousPrepared": { - "type": "boolean", - "required": true - }, "isPackagingArea": { "type": "boolean", "required": true From 0998b5bf2cfb59d4864cc24f8d6b1aceab9f2495 Mon Sep 17 00:00:00 2001 From: jorgep Date: Thu, 21 Dec 2023 13:58:33 +0100 Subject: [PATCH 24/31] add locale and refactor: refs #6274 --- loopback/locale/es.json | 5 +++-- .../worker/back/methods/worker-time-control/clockIn.js | 6 +++--- modules/worker/back/methods/worker-time-control/login.js | 9 ++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/loopback/locale/es.json b/loopback/locale/es.json index a8134909e..185212d51 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -329,5 +329,6 @@ "The amount cannot be less than the minimum": "La cantidad no puede ser menor que la cantidad mínima", "quantityLessThanMin": "La cantidad no puede ser menor que la cantidad mínima", "Cannot past travels with entries": "No se pueden pasar envíos con entradas", - "It was not able to remove the next expeditions:": "No se pudo eliminar las siguientes expediciones: {{expeditions}}" -} + "It was not able to remove the next expeditions:": "No se pudo eliminar las siguientes expediciones: {{expeditions}}", + "Incorrect pin.": "Pin incorrecto." +} \ No newline at end of file diff --git a/modules/worker/back/methods/worker-time-control/clockIn.js b/modules/worker/back/methods/worker-time-control/clockIn.js index 2e2441cc2..44e0c547a 100644 --- a/modules/worker/back/methods/worker-time-control/clockIn.js +++ b/modules/worker/back/methods/worker-time-control/clockIn.js @@ -36,9 +36,9 @@ module.exports = Self => { Object.assign(myOptions, options); const query = 'CALL vn.workerTimeControl_clockIn(?, ?, ?)'; - const [response] = await Self.rawSql(query, [workerFk, timed, direction], myOptions); - if (response[0] && response[0].error) - throw new UserError(response[0].error); + const [[response]] = await Self.rawSql(query, [workerFk, timed, direction], myOptions); + if (response && response.error) + throw new UserError(response.error); return response; }; diff --git a/modules/worker/back/methods/worker-time-control/login.js b/modules/worker/back/methods/worker-time-control/login.js index 894b5ba17..b2a17b4e4 100644 --- a/modules/worker/back/methods/worker-time-control/login.js +++ b/modules/worker/back/methods/worker-time-control/login.js @@ -8,7 +8,7 @@ module.exports = Self => { { arg: 'pin', type: 'string', - required: true, + required: true }, ], returns: { @@ -27,9 +27,8 @@ module.exports = Self => { Object.assign(myOptions, options); const query = `CALL vn.workerTimeControl_login(?)`; - const user = await Self.rawSql(query, [pin], myOptions); - - if (!user) throw new UserError('Indique el pin.'); - return user[0][0]; + const [[user]] = await Self.rawSql(query, [pin], myOptions); + if (!user) throw new UserError('Incorrect pin.'); + return user; }; }; From 86db5a931d8b047fb55ca0c2139599737deb74b5 Mon Sep 17 00:00:00 2001 From: jorgep Date: Fri, 22 Dec 2023 10:44:21 +0100 Subject: [PATCH 25/31] arrange test suites: refs #6274 --- .../worker-time-control/specs/clockIn.spec.js | 553 +++++++++++++++++ .../worker-time-control/specs/login.spec.js | 2 +- .../specs/timeEntry.spec.js | 578 +----------------- 3 files changed, 555 insertions(+), 578 deletions(-) diff --git a/modules/worker/back/methods/worker-time-control/specs/clockIn.spec.js b/modules/worker/back/methods/worker-time-control/specs/clockIn.spec.js index 970fd2fe2..9cd3ed1c0 100644 --- a/modules/worker/back/methods/worker-time-control/specs/clockIn.spec.js +++ b/modules/worker/back/methods/worker-time-control/specs/clockIn.spec.js @@ -1,8 +1,29 @@ const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); describe('workerTimeControl clockIn()', () => { const workerId = 9; + const salesBossId = 19; + const hankPymId = 1107; + const jessicaJonesId = 1110; + const HHRRId = 37; + const teamBossId = 13; + const monday = 1; + const tuesday = 2; + const thursday = 4; + const friday = 5; + const sunday = 7; const inTime = '2001-01-01T00:00:00.000Z'; + const activeCtx = { + accessToken: {userId: 50}, + }; + const ctx = {req: activeCtx}; + + beforeAll(() => { + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); it('should correctly clock in', async() => { const tx = await models.WorkerTimeControl.beginTransaction({}); @@ -24,5 +45,537 @@ describe('workerTimeControl clockIn()', () => { throw e; } }); + + describe('as Role errors', () => { + it('should add if the current user is team boss and the target user is himself', async() => { + activeCtx.accessToken.userId = teamBossId; + const workerId = teamBossId; + + const tx = await models.WorkerTimeControl.beginTransaction({}); + try { + const options = {transaction: tx}; + + const todayAtOne = Date.vnNew(); + todayAtOne.setHours(1, 0, 0, 0); + + ctx.args = {timed: todayAtOne, direction: 'in'}; + const createdTimeEntry = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + expect(createdTimeEntry.id).toBeDefined(); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should delete the created time entry for the team boss as himself', async() => { + activeCtx.accessToken.userId = teamBossId; + const workerId = teamBossId; + + const tx = await models.WorkerTimeControl.beginTransaction({}); + try { + const options = {transaction: tx}; + + const todayAtOne = Date.vnNew(); + todayAtOne.setHours(1, 0, 0, 0); + + ctx.args = {timed: todayAtOne, direction: 'in'}; + const createdTimeEntry = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + expect(createdTimeEntry.id).toBeDefined(); + + await models.WorkerTimeControl.deleteTimeEntry(ctx, createdTimeEntry.id, options); + + const deletedTimeEntry = await models.WorkerTimeControl.findById(createdTimeEntry.id, null, options); + + expect(deletedTimeEntry).toBeNull(); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should edit the created time entry for the team boss as HHRR', async() => { + activeCtx.accessToken.userId = HHRRId; + const workerId = teamBossId; + + const tx = await models.WorkerTimeControl.beginTransaction({}); + try { + const options = {transaction: tx}; + + const todayAtOne = Date.vnNew(); + todayAtOne.setHours(1, 0, 0, 0); + + ctx.args = {timed: todayAtOne, direction: 'in'}; + const createdTimeEntry = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + expect(createdTimeEntry.id).toBeDefined(); + + ctx.args = {direction: 'out'}; + const updatedTimeEntry = await models.WorkerTimeControl.updateTimeEntry( + ctx, createdTimeEntry.id, options + ); + + expect(updatedTimeEntry.direction).toEqual('out'); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + }); + + describe('as saleBoss editor', () => { + let workerId; + beforeEach(() => { + activeCtx.accessToken.userId = salesBossId; + workerId = hankPymId; + }); + + it('should fail to add a time entry if the target user has an absence that day', async() => { + const date = Date.vnNew(); + date.setHours(8, 0, 0); + date.setDate(date.getDate() - 16); + const tx = await models.WorkerTimeControl.beginTransaction({}); + const options = {transaction: tx}; + try { + ctx.args = {timed: date, direction: 'in'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toBe(`No está permitido trabajar`); + }); + + it('should fail to add a time entry for a worker without an existing contract', async() => { + const date = Date.vnNew(); + date.setFullYear(date.getFullYear() - 2); + + const tx = await models.WorkerTimeControl.beginTransaction({}); + const options = {transaction: tx}; + try { + ctx.args = {timed: date, direction: 'in'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toBe(`No hay un contrato en vigor`); + }); + + it('should fail to add a time entry for a worker without an existing contract and exceeding time', async() => { + let date = Date.vnNew(); + date.setDate(date.getDate() - 2); + let error; + + const tx = await models.WorkerTimeControl.beginTransaction({}); + const options = {transaction: tx}; + date.setHours(0, 0, 0); + ctx.args = {timed: date, direction: 'in'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + try { + date.setHours(20, 0, 1); + ctx.args = {timed: date, direction: 'out'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toBe(`Superado el tiempo máximo entre entrada y salida`); + }); + + describe('direction errors', () => { + let date = Date.vnNew(); + date.setDate(date.getDate() - 1); + let error; + it('should throw an error when trying "in" direction twice', async() => { + const tx = await models.WorkerTimeControl.beginTransaction({}); + const options = {transaction: tx}; + + date.setHours(8, 0, 0); + ctx.args = {timed: date, direction: 'in'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + try { + date.setHours(10, 0, 0); + ctx.args = {timed: date, direction: 'in'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toBe(`Dirección incorrecta`); + }); + + it('should throw an error when trying "in" direction after insert "in" and "middle"', async() => { + const tx = await models.WorkerTimeControl.beginTransaction({}); + const options = {transaction: tx}; + + date.setHours(8, 0, 0); + ctx.args = {timed: date, direction: 'in'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + date.setHours(9, 0, 0); + ctx.args = {timed: date, direction: 'middle'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + try { + date.setHours(10, 0, 0); + ctx.args = {timed: date, direction: 'in'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toBe(`Dirección incorrecta`); + }); + + it('Should throw an error when trying "out" before closing a "middle" couple', async() => { + const tx = await models.WorkerTimeControl.beginTransaction({}); + const options = {transaction: tx}; + + date.setHours(8, 0, 0); + ctx.args = {timed: date, direction: 'in'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + date.setHours(9, 0, 0); + ctx.args = {timed: date, direction: 'middle'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + try { + date.setHours(10, 0, 0); + ctx.args = {timed: date, direction: 'out'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toBe(`Dirección incorrecta`); + }); + + it('should throw an error when trying "middle" after "out"', async() => { + const tx = await models.WorkerTimeControl.beginTransaction({}); + const options = {transaction: tx}; + + date.setHours(8, 0, 0); + ctx.args = {timed: date, direction: 'in'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + date.setHours(9, 0, 0); + ctx.args = {timed: date, direction: 'out'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + try { + date.setHours(10, 0, 0); + ctx.args = {timed: date, direction: 'middle'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toBe(`Dirección incorrecta`); + }); + + it('should throw an error when trying "out" direction twice', async() => { + const tx = await models.WorkerTimeControl.beginTransaction({}); + const options = {transaction: tx}; + + date.setHours(8, 0, 0); + ctx.args = {timed: date, direction: 'in'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + date.setHours(9, 0, 0); + ctx.args = {timed: date, direction: 'out'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + try { + date.setHours(10, 0, 0); + ctx.args = {timed: date, direction: 'out'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toBe(`Dirección incorrecta`); + }); + }); + + describe('12h rest', () => { + activeCtx.accessToken.userId = salesBossId; + const workerId = hankPymId; + it('should throw an error when the 12h rest is not fulfilled yet', async() => { + let date = Date.vnNew(); + date.setDate(date.getDate() - 2); + date = weekDay(date, monday); + let error; + + const tx = await models.WorkerTimeControl.beginTransaction({}); + const options = {transaction: tx}; + + date.setHours(8, 0, 0); + ctx.args = {timed: date, direction: 'in'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + date.setHours(16, 0, 0); + ctx.args = {timed: date, direction: 'out'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + try { + date = weekDay(date, tuesday); + date.setHours(4, 0, 0); + ctx.args = {timed: date, direction: 'in'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toBe(`Descanso diario`); + }); + + it('should not fail as the 12h rest is fulfilled', async() => { + let date = Date.vnNew(); + date.setDate(date.getDate() - 2); + date = weekDay(date, monday); + let error; + + const tx = await models.WorkerTimeControl.beginTransaction({}); + const options = {transaction: tx}; + + date.setHours(8, 0, 0); + ctx.args = {timed: date, direction: 'in'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + date.setHours(16, 0, 0); + ctx.args = {timed: date, direction: 'out'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + try { + date = weekDay(date, tuesday); + date.setHours(4, 1, 0); + ctx.args = {timed: date, direction: 'in'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error).not.toBeDefined; + }); + }); + + describe('for 3500kg drivers with enforced 9h rest', () => { + activeCtx.accessToken.userId = salesBossId; + const workerId = jessicaJonesId; + it('should throw an error when the 9h enforced rest is not fulfilled', async() => { + let date = Date.vnNew(); + date.setDate(date.getDate() - 2); + date = weekDay(date, monday); + let error; + + const tx = await models.WorkerTimeControl.beginTransaction({}); + const options = {transaction: tx}; + + date.setHours(8, 0, 0); + ctx.args = {timed: date, direction: 'in'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + date.setHours(16, 0, 0); + ctx.args = {timed: date, direction: 'out'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + try { + date = weekDay(date, tuesday); + date.setHours(1, 0, 0); + ctx.args = {timed: date, direction: 'in'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toBe(`Descanso diario`); + }); + + it('should not fail when the 9h enforced rest is fulfilled', async() => { + let date = Date.vnNew(); + date.setDate(date.getDate() - 2); + date = weekDay(date, monday); + let error; + + const tx = await models.WorkerTimeControl.beginTransaction({}); + const options = {transaction: tx}; + + date.setHours(8, 0, 0); + ctx.args = {timed: date, direction: 'in'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + date.setHours(16, 0, 0); + ctx.args = {timed: date, direction: 'out'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + try { + date = weekDay(date, tuesday); + date.setHours(1, 1, 0); + ctx.args = {timed: date, direction: 'in'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error).not.toBeDefined; + }); + }); + + describe('for 72h weekly rest', () => { + + it('should throw an error when work 11 consecutive days', async() => { + let date = Date.vnNew(); + date.setMonth(date.getMonth() - 1); + date.setDate(1); + let error; + + const tx = await models.WorkerTimeControl.beginTransaction({}); + const options = {transaction: tx}; + + await populateWeek(date, monday, sunday, ctx, workerId, options); + date = nextWeek(date); + await populateWeek(date, monday, thursday, ctx, workerId, options); + try { + date = weekDay(date, friday); + date.setHours(10, 0, 1); + ctx.args = {timed: date, direction: 'in'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toBe(`Descanso semanal`); + }); + + it('should throw an error when the 72h weekly rest is not fulfilled', async() => { + + let date = Date.vnNew(); + date.setMonth(date.getMonth() - 1); + date.setDate(1); + let error; + + const tx = await models.WorkerTimeControl.beginTransaction({}); + const options = {transaction: tx}; + + await populateWeek(date, monday, sunday, ctx, workerId, options); + date = nextWeek(date); + await populateWeek(date, monday, thursday, ctx, workerId, options); + + try { + date = weekDay(date, sunday); + date.setHours(17, 59, 0); + ctx.args = {timed: date, direction: 'in'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error.message).toBe(`Descanso semanal`); + }); + + it('should throw an error when the 72h weekly rest is fulfilled', async() => { + + let date = Date.vnNew(); + date.setMonth(date.getMonth() - 1); + date.setDate(1); + let error; + + const tx = await models.WorkerTimeControl.beginTransaction({}); + const options = {transaction: tx}; + + await populateWeek(date, monday, sunday, ctx, workerId, options); + date = nextWeek(date); + await populateWeek(date, monday, thursday, ctx, workerId, options); + + try { + date = weekDay(date, sunday); + date.setHours(18, 00, 0); + ctx.args = {timed: date, direction: 'in'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + error = e; + } + + expect(error).not.toBeDefined; + }); + }); + }); }); +function weekDay(date, dayToSet) { + const currentDay = date.getDay(); + const distance = dayToSet - currentDay; + + date.setDate(date.getDate() + distance); + return date; +} + +function nextWeek(date) { + const sunday = 7; + const currentDay = date.getDay(); + let newDate = date; + if (currentDay != 0) + newDate = weekDay(date, sunday); + + newDate.setDate(newDate.getDate() + 1); + return newDate; +} + +async function populateWeek(date, dayStart, dayEnd, ctx, workerId, options) { + const dateStart = new Date(weekDay(date, dayStart)); + const dateEnd = new Date(dateStart); + dateEnd.setDate(dateStart.getDate() + dayEnd); + + for (let i = dayStart; i <= dayEnd; i++) { + dateStart.setHours(10, 0, 0); + ctx.args = {timed: dateStart, direction: 'in'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + dateStart.setHours(18, 0, 0); + ctx.args = {timed: dateStart, direction: 'out'}; + await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + dateStart.setDate(dateStart.getDate() + 1); + } +} diff --git a/modules/worker/back/methods/worker-time-control/specs/login.spec.js b/modules/worker/back/methods/worker-time-control/specs/login.spec.js index 88596f297..392d9a66b 100644 --- a/modules/worker/back/methods/worker-time-control/specs/login.spec.js +++ b/modules/worker/back/methods/worker-time-control/specs/login.spec.js @@ -13,7 +13,7 @@ describe('workerTimeControl login()', () => { await models.WorkerTimeControl.login(); } catch (error) { expect(error).toBeInstanceOf(UserError); - expect(error.message).toBe('Indique el pin.'); + expect(error.message).toBe('Incorrect pin.'); } }); }); diff --git a/modules/worker/back/methods/worker-time-control/specs/timeEntry.spec.js b/modules/worker/back/methods/worker-time-control/specs/timeEntry.spec.js index 42ec6290a..92c01792f 100644 --- a/modules/worker/back/methods/worker-time-control/specs/timeEntry.spec.js +++ b/modules/worker/back/methods/worker-time-control/specs/timeEntry.spec.js @@ -3,18 +3,10 @@ const models = require('vn-loopback/server/server').models; const LoopBackContext = require('loopback-context'); describe('workerTimeControl add/delete timeEntry()', () => { - const HHRRId = 37; - const teamBossId = 13; const employeeId = 1; - const salesPersonId = 1106; const salesBossId = 19; const hankPymId = 1107; - const jessicaJonesId = 1110; const monday = 1; - const tuesday = 2; - const thursday = 4; - const friday = 5; - const sunday = 7; const activeCtx = { accessToken: {userId: 50}, }; @@ -61,560 +53,11 @@ describe('workerTimeControl add/delete timeEntry()', () => { expect(error.statusCode).toBe(400); expect(error.message).toBe(`You don't have enough privileges`); }); - - it('should add if the current user is team boss and the target user is himself', async() => { - activeCtx.accessToken.userId = teamBossId; - const workerId = teamBossId; - - const tx = await models.WorkerTimeControl.beginTransaction({}); - try { - const options = {transaction: tx}; - - const todayAtOne = Date.vnNew(); - todayAtOne.setHours(1, 0, 0, 0); - - ctx.args = {timed: todayAtOne, direction: 'in'}; - const [createdTimeEntry] = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - expect(createdTimeEntry.id).toBeDefined(); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); - - it('should try but fail to delete his own time entry', async() => { - activeCtx.accessToken.userId = salesBossId; - const workerId = salesBossId; - - let error; - const tx = await models.WorkerTimeControl.beginTransaction({}); - try { - const options = {transaction: tx}; - - const todayAtOne = Date.vnNew(); - todayAtOne.setHours(1, 0, 0, 0); - - ctx.args = {timed: todayAtOne, direction: 'in'}; - const [createdTimeEntry] = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - activeCtx.accessToken.userId = salesPersonId; - await models.WorkerTimeControl.deleteTimeEntry(ctx, createdTimeEntry.id, options); - - await tx.rollback(); - } catch (e) { - error = e; - await tx.rollback(); - } - - expect(error).toBeDefined(); - expect(error.statusCode).toBe(400); - expect(error.message).toBe(`You don't have enough privileges`); - }); - - it('should delete the created time entry for the team boss as himself', async() => { - activeCtx.accessToken.userId = teamBossId; - const workerId = teamBossId; - - const tx = await models.WorkerTimeControl.beginTransaction({}); - try { - const options = {transaction: tx}; - - const todayAtOne = Date.vnNew(); - todayAtOne.setHours(1, 0, 0, 0); - - ctx.args = {timed: todayAtOne, direction: 'in'}; - const [createdTimeEntry] = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - expect(createdTimeEntry.id).toBeDefined(); - - await models.WorkerTimeControl.deleteTimeEntry(ctx, createdTimeEntry.id, options); - - const deletedTimeEntry = await models.WorkerTimeControl.findById(createdTimeEntry.id, null, options); - - expect(deletedTimeEntry).toBeNull(); - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); - - it('should delete the created time entry for the team boss as HHRR', async() => { - activeCtx.accessToken.userId = HHRRId; - const workerId = teamBossId; - - const tx = await models.WorkerTimeControl.beginTransaction({}); - try { - const options = {transaction: tx}; - - const todayAtOne = Date.vnNew(); - todayAtOne.setHours(1, 0, 0, 0); - - ctx.args = {timed: todayAtOne, direction: 'in'}; - const [createdTimeEntry] = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - expect(createdTimeEntry.id).toBeDefined(); - - await models.WorkerTimeControl.deleteTimeEntry(ctx, createdTimeEntry.id, options); - - const deletedTimeEntry = await models.WorkerTimeControl.findById(createdTimeEntry.id, null, options); - - expect(deletedTimeEntry).toBeNull(); - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); - - it('should edit the created time entry for the team boss as HHRR', async() => { - activeCtx.accessToken.userId = HHRRId; - const workerId = teamBossId; - - const tx = await models.WorkerTimeControl.beginTransaction({}); - try { - const options = {transaction: tx}; - - const todayAtOne = Date.vnNew(); - todayAtOne.setHours(1, 0, 0, 0); - - ctx.args = {timed: todayAtOne, direction: 'in'}; - const [createdTimeEntry] = await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - expect(createdTimeEntry.id).toBeDefined(); - - ctx.args = {direction: 'out'}; - const updatedTimeEntry = await models.WorkerTimeControl.updateTimeEntry(ctx, createdTimeEntry.id, options); - - expect(updatedTimeEntry.direction).toEqual('out'); - await tx.rollback(); - } catch (e) { - await tx.rollback(); - throw e; - } - }); }); describe('WorkerTimeControl_clockIn calls', () => { - let workerId; - beforeEach(() => { - activeCtx.accessToken.userId = salesBossId; - workerId = hankPymId; - }); - it('should fail to add a time entry if the target user has an absence that day', async() => { - const date = Date.vnNew(); - date.setHours(8, 0, 0); - date.setDate(date.getDate() - 16); - const tx = await models.WorkerTimeControl.beginTransaction({}); - const options = {transaction: tx}; - try { - ctx.args = {timed: date, direction: 'in'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); + beforeEach(() => activeCtx.accessToken.userId = salesBossId); - await tx.rollback(); - } catch (e) { - await tx.rollback(); - error = e; - } - - expect(error.message).toBe(`No está permitido trabajar`); - }); - - it('should fail to add a time entry for a worker without an existing contract', async() => { - const date = Date.vnNew(); - date.setFullYear(date.getFullYear() - 2); - - const tx = await models.WorkerTimeControl.beginTransaction({}); - const options = {transaction: tx}; - try { - ctx.args = {timed: date, direction: 'in'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - error = e; - } - - expect(error.message).toBe(`No hay un contrato en vigor`); - }); - - it('should fail to add a time entry for a worker without an existing contract', async() => { - let date = Date.vnNew(); - date.setDate(date.getDate() - 2); - let error; - - const tx = await models.WorkerTimeControl.beginTransaction({}); - const options = {transaction: tx}; - date.setHours(0, 0, 0); - ctx.args = {timed: date, direction: 'in'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - try { - date.setHours(20,0, 1); - ctx.args = {timed: date, direction: 'out'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - error = e; - } - - expect(error.message).toBe(`Superado el tiempo máximo entre entrada y salida`); - }); - - describe('direction errors', () => { - let date = Date.vnNew(); - date.setDate(date.getDate() - 1); - let error; - it('should throw an error when trying "in" direction twice', async() => { - const tx = await models.WorkerTimeControl.beginTransaction({}); - const options = {transaction: tx}; - - date.setHours(8, 0, 0); - ctx.args = {timed: date, direction: 'in'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - try { - date.setHours(10, 0, 0); - ctx.args = {timed: date, direction: 'in'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - error = e; - } - - expect(error.message).toBe(`Dirección incorrecta`); - }); - - it('should throw an error when trying "in" direction after insert "in" and "middle"', async() => { - const tx = await models.WorkerTimeControl.beginTransaction({}); - const options = {transaction: tx}; - - date.setHours(8, 0, 0); - ctx.args = {timed: date, direction: 'in'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - date.setHours(9, 0, 0); - ctx.args = {timed: date, direction: 'middle'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - try { - date.setHours(10, 0, 0); - ctx.args = {timed: date, direction: 'in'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - error = e; - } - - expect(error.message).toBe(`Dirección incorrecta`); - }); - - it('Should throw an error when trying "out" before closing a "middle" couple', async() => { - const tx = await models.WorkerTimeControl.beginTransaction({}); - const options = {transaction: tx}; - - date.setHours(8, 0, 0); - ctx.args = {timed: date, direction: 'in'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - date.setHours(9, 0, 0); - ctx.args = {timed: date, direction: 'middle'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - try { - date.setHours(10, 0, 0); - ctx.args = {timed: date, direction: 'out'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - error = e; - } - - expect(error.message).toBe(`Dirección incorrecta`); - }); - - it('should throw an error when trying "middle" after "out"', async() => { - const tx = await models.WorkerTimeControl.beginTransaction({}); - const options = {transaction: tx}; - - date.setHours(8, 0, 0); - ctx.args = {timed: date, direction: 'in'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - date.setHours(9, 0, 0); - ctx.args = {timed: date, direction: 'out'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - try { - date.setHours(10, 0, 0); - ctx.args = {timed: date, direction: 'middle'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - error = e; - } - - expect(error.message).toBe(`Dirección incorrecta`); - }); - - it('should throw an error when trying "out" direction twice', async() => { - const tx = await models.WorkerTimeControl.beginTransaction({}); - const options = {transaction: tx}; - - date.setHours(8, 0, 0); - ctx.args = {timed: date, direction: 'in'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - date.setHours(9, 0, 0); - ctx.args = {timed: date, direction: 'out'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - try { - date.setHours(10, 0, 0); - ctx.args = {timed: date, direction: 'out'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - error = e; - } - - expect(error.message).toBe(`Dirección incorrecta`); - }); - }); - - describe('12h rest', () => { - activeCtx.accessToken.userId = salesBossId; - const workerId = hankPymId; - it('should throw an error when the 12h rest is not fulfilled yet', async() => { - - let date = Date.vnNew(); - date.setDate(date.getDate() - 2); - date = weekDay(date, monday); - let error; - - const tx = await models.WorkerTimeControl.beginTransaction({}); - const options = {transaction: tx}; - - date.setHours(8, 0, 0); - ctx.args = {timed: date, direction: 'in'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - date.setHours(16, 0, 0); - ctx.args = {timed: date, direction: 'out'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - try { - date = weekDay(date, tuesday); - date.setHours(4, 0, 0); - ctx.args = {timed: date, direction: 'in'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - error = e; - } - - expect(error.message).toBe(`Descanso diario`); - }); - - it('should not fail as the 12h rest is fulfilled', async() => { - let date = Date.vnNew(); - date.setDate(date.getDate() - 2); - date = weekDay(date, monday); - let error; - - const tx = await models.WorkerTimeControl.beginTransaction({}); - const options = {transaction: tx}; - - date.setHours(8, 0, 0); - ctx.args = {timed: date, direction: 'in'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - date.setHours(16, 0, 0); - ctx.args = {timed: date, direction: 'out'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - try { - date = weekDay(date, tuesday); - date.setHours(4, 1, 0); - ctx.args = {timed: date, direction: 'in'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - error = e; - } - - expect(error).not.toBeDefined; - }); - }); - - describe('for 3500kg drivers with enforced 9h rest', () => { - activeCtx.accessToken.userId = salesBossId; - const workerId = jessicaJonesId; - it('should throw an error when the 9h enforced rest is not fulfilled', async() => { - - let date = Date.vnNew(); - date.setDate(date.getDate() - 2); - date = weekDay(date, monday); - let error; - - const tx = await models.WorkerTimeControl.beginTransaction({}); - const options = {transaction: tx}; - - date.setHours(8, 0, 0); - ctx.args = {timed: date, direction: 'in'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - date.setHours(16, 0, 0); - ctx.args = {timed: date, direction: 'out'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - try { - date = weekDay(date, tuesday); - date.setHours(1, 0, 0); - ctx.args = {timed: date, direction: 'in'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - error = e; - } - - expect(error.message).toBe(`Descanso diario`); - }); - - it('should not fail when the 9h enforced rest is fulfilled', async() => { - - let date = Date.vnNew(); - date.setDate(date.getDate() - 2); - date = weekDay(date, monday); - let error; - - const tx = await models.WorkerTimeControl.beginTransaction({}); - const options = {transaction: tx}; - - date.setHours(8, 0, 0); - ctx.args = {timed: date, direction: 'in'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - date.setHours(16, 0, 0); - ctx.args = {timed: date, direction: 'out'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - try { - date = weekDay(date, tuesday); - date.setHours(1, 1, 0); - ctx.args = {timed: date, direction: 'in'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - - await tx.rollback(); - } catch (e) { - await tx.rollback(); - error = e; - } - - expect(error).not.toBeDefined; - }); - }); - - describe('for 72h weekly rest', () => { - - it('should throw an error when work 11 consecutive days', async() => { - let date = Date.vnNew(); - date.setMonth(date.getMonth() - 1); - date.setDate(1); - let error; - - const tx = await models.WorkerTimeControl.beginTransaction({}); - const options = {transaction: tx}; - - await populateWeek(date, monday, sunday, ctx, workerId, options); - date = nextWeek(date); - await populateWeek(date, monday, thursday, ctx, workerId, options); - try { - date = weekDay(date, friday); - date.setHours(10, 0, 1); - ctx.args = {timed: date, direction: 'in'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - await tx.rollback(); - } catch (e) { - await tx.rollback(); - error = e; - } - - expect(error.message).toBe(`Descanso semanal`); - }); - - it('should throw an error when the 72h weekly rest is not fulfilled', async() => { - - let date = Date.vnNew(); - date.setMonth(date.getMonth() - 1); - date.setDate(1); - let error; - - const tx = await models.WorkerTimeControl.beginTransaction({}); - const options = {transaction: tx}; - - await populateWeek(date, monday, sunday, ctx, workerId, options); - date = nextWeek(date); - await populateWeek(date, monday, thursday, ctx, workerId, options); - - try { - date = weekDay(date, sunday); - date.setHours(17, 59, 0); - ctx.args = {timed: date, direction: 'in'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - await tx.rollback(); - } catch (e) { - await tx.rollback(); - error = e; - } - - expect(error.message).toBe(`Descanso semanal`); - }); - - it('should throw an error when the 72h weekly rest is fulfilled', async() => { - - let date = Date.vnNew(); - date.setMonth(date.getMonth() - 1); - date.setDate(1); - let error; - - const tx = await models.WorkerTimeControl.beginTransaction({}); - const options = {transaction: tx}; - - await populateWeek(date, monday, sunday, ctx, workerId, options); - date = nextWeek(date); - await populateWeek(date, monday, thursday, ctx, workerId, options); - - try { - date = weekDay(date, sunday); - date.setHours(18, 00, 0); - ctx.args = {timed: date, direction: 'in'}; - await models.WorkerTimeControl.addTimeEntry(ctx, workerId, options); - await tx.rollback(); - } catch (e) { - await tx.rollback(); - error = e; - } - - expect(error).not.toBeDefined; - }); - }); - describe('WorkerTimeControl_calculate calls', () => { let dated = Date.vnNew(); dated.setDate(dated.getDate() - 7); @@ -836,25 +279,6 @@ function weekDay(date, dayToSet) { return date; } -function nextWeek(date) { - const sunday = 7; - const currentDay = date.getDay(); - let newDate = date; - if (currentDay != 0) - newDate = weekDay(date, sunday); - - newDate.setDate(newDate.getDate() + 1); - return newDate; -} - -function lastWeek(date) { - const monday = 1; - newDate = weekDay(date, monday); - - newDate.setDate(newDate.getDate() - 1); - return newDate; -} - async function populateWeek(date, dayStart, dayEnd, ctx, workerId, options) { const dateStart = new Date(weekDay(date, dayStart)); const dateEnd = new Date(dateStart); From 2e1715a968fdfac0977952d3939cfe1b3f34190a Mon Sep 17 00:00:00 2001 From: jorgep Date: Fri, 22 Dec 2023 15:19:45 +0100 Subject: [PATCH 26/31] refactor renewToken & replace ACL: refs #6274 --- back/methods/vn-user/renew-token.js | 41 ++++++++----------- .../methods/vn-user/specs/renew-token.spec.js | 1 - back/models/vn-user.json | 27 ++++++------ db/changes/240201/00-timecontrol.sql | 7 +++- 4 files changed, 37 insertions(+), 39 deletions(-) diff --git a/back/methods/vn-user/renew-token.js b/back/methods/vn-user/renew-token.js index 194747949..d00085d8a 100644 --- a/back/methods/vn-user/renew-token.js +++ b/back/methods/vn-user/renew-token.js @@ -1,14 +1,5 @@ -const UserError = require('vn-loopback/util/user-error'); const {models} = require('vn-loopback/server/server'); -const handlePromiseLogout = (Self, {id}, courtesyTime) => { - new Promise(res => { - setTimeout(() => { - res(Self.logout(id)); - } - , courtesyTime * 1000); - }); -}; module.exports = Self => { Self.remoteMethodCtx('renewToken', { description: 'Checks if the token has more than renewPeriod seconds to live and if so, renews it', @@ -28,14 +19,26 @@ module.exports = Self => { const {accessToken: token} = ctx.req; // Check if current token is valid - const isValid = await validateToken(token); - if (isValid) + + const {renewPeriod, courtesyTime} = await models.AccessTokenConfig.findOne({ + fields: ['renewPeriod', 'courtesyTime'] + }); + const now = Date.now(); + const differenceMilliseconds = now - token.created; + const differenceSeconds = Math.floor(differenceMilliseconds / 1000); + const isNotExceeded = differenceSeconds < renewPeriod - courtesyTime; + if (isNotExceeded) return token; - const {courtesyTime} = await models.AccessTokenConfig.findOne({fields: ['courtesyTime']}); - // Schedule to remove current token - handlePromiseLogout(Self, token, courtesyTime); + setTimeout(async() => { + try { + await Self.logout(token.id); + } catch (err) { + // eslint-disable-next-line no-console + console.error(err); + } + }, courtesyTime * 1000); // Create new accessToken const user = await Self.findById(token.userId); @@ -43,14 +46,4 @@ module.exports = Self => { return {id: accessToken.id, ttl: accessToken.ttl}; }; - - async function validateToken(token) { - const accessTokenConfig = await models.AccessTokenConfig.findOne({fields: ['renewPeriod', 'courtesyTime']}); - const now = Date.now(); - const differenceMilliseconds = now - token.created; - const differenceSeconds = Math.floor(differenceMilliseconds / 1000); - const isValid = differenceSeconds < accessTokenConfig.renewPeriod - accessTokenConfig.courtesyTime; - - return isValid; - } }; diff --git a/back/methods/vn-user/specs/renew-token.spec.js b/back/methods/vn-user/specs/renew-token.spec.js index 146f6eb0c..8d9bbf11c 100644 --- a/back/methods/vn-user/specs/renew-token.spec.js +++ b/back/methods/vn-user/specs/renew-token.spec.js @@ -30,7 +30,6 @@ describe('Renew Token', () => { it('should renew token', async() => { const mockDate = new Date(startingTime + 26600000); jasmine.clock().mockDate(mockDate); - console.log(startingTime, mockDate) const {id} = await models.VnUser.renewToken(ctx); expect(id).not.toEqual(ctx.req.accessToken.id); diff --git a/back/models/vn-user.json b/back/models/vn-user.json index 86ffac2bb..d0687098d 100644 --- a/back/models/vn-user.json +++ b/back/models/vn-user.json @@ -95,27 +95,30 @@ "principalType": "ROLE", "principalId": "$everyone", "permission": "ALLOW" - }, - { - "property": "recoverPassword", - "accessType": "EXECUTE", - "principalType": "ROLE", - "principalId": "$everyone", - "permission": "ALLOW" - }, - { - "property": "validateAuth", + }, { + "property": "recoverPassword", "accessType": "EXECUTE", "principalType": "ROLE", "principalId": "$everyone", "permission": "ALLOW" - }, - { + }, { + "property": "validateAuth", + "accessType": "EXECUTE", + "principalType": "ROLE", + "principalId": "$everyone", + "permission": "ALLOW" + }, { "property": "privileges", "accessType": "*", "principalType": "ROLE", "principalId": "$authenticated", "permission": "ALLOW" + }, { + "property": "renewToken", + "accessType": "WRITE", + "principalType": "ROLE", + "principalId": "$authenticated", + "permission": "ALLOW" } ], "scopes": { diff --git a/db/changes/240201/00-timecontrol.sql b/db/changes/240201/00-timecontrol.sql index 0d3bd59b2..c3ddf5d96 100644 --- a/db/changes/240201/00-timecontrol.sql +++ b/db/changes/240201/00-timecontrol.sql @@ -1,3 +1,7 @@ +DELETE FROM `salix`.`ACL` + WHERE model = 'VnUser' + AND property = 'renewToken'; + INSERT INTO `account`.`role` (name, description) VALUES ('timeControl','Tablet para fichar'); @@ -8,7 +12,6 @@ INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalTyp VALUES ('WorkerTimeControl', 'login', 'READ', 'ALLOW', 'ROLE', 'timeControl'), ('WorkerTimeControl', 'getClockIn', 'READ', 'ALLOW', 'ROLE', 'timeControl'), - ('WorkerTimeControl', 'clockIn', 'WRITE', 'ALLOW', 'ROLE', 'timeControl'), - ('VnUser', 'renewToken', 'WRITE', 'ALLOW', 'ROLE', 'timeControl'); + ('WorkerTimeControl', 'clockIn', 'WRITE', 'ALLOW', 'ROLE', 'timeControl'); CALL `account`.`role_sync`(); From 801037da64bf3c02d8017ba29e2dc7cf698448b6 Mon Sep 17 00:00:00 2001 From: jorgep Date: Tue, 2 Jan 2024 08:47:12 +0100 Subject: [PATCH 27/31] fix changes: refs #6274 --- db/changes/{240201 => 234601}/00-updateCourtesyTime.sql | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename db/changes/{240201 => 234601}/00-updateCourtesyTime.sql (100%) diff --git a/db/changes/240201/00-updateCourtesyTime.sql b/db/changes/234601/00-updateCourtesyTime.sql similarity index 100% rename from db/changes/240201/00-updateCourtesyTime.sql rename to db/changes/234601/00-updateCourtesyTime.sql From 763af7da2d17c14ec49d34f4455b6a2de95f111a Mon Sep 17 00:00:00 2001 From: jorgep Date: Tue, 2 Jan 2024 08:58:41 +0100 Subject: [PATCH 28/31] fix test: refs #6274 --- .../worker/back/methods/worker-time-control/specs/login.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/worker/back/methods/worker-time-control/specs/login.spec.js b/modules/worker/back/methods/worker-time-control/specs/login.spec.js index 392d9a66b..8e992de96 100644 --- a/modules/worker/back/methods/worker-time-control/specs/login.spec.js +++ b/modules/worker/back/methods/worker-time-control/specs/login.spec.js @@ -3,7 +3,7 @@ const models = require('vn-loopback/server/server').models; describe('workerTimeControl login()', () => { it('should correctly login', async() => { - const response = await models.WorkerTimeControl.login(9, {}); + const response = await models.WorkerTimeControl.login(9); expect(response.name).toBe('developer'); }); From 6b8a4a512bc58067c2efd00b141e8a45a0d99e8c Mon Sep 17 00:00:00 2001 From: jorgep Date: Tue, 2 Jan 2024 10:42:50 +0100 Subject: [PATCH 29/31] adding filter: refs #6606 --- .../back/methods/invoiceOut/negativeBasesCsv.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/modules/invoiceOut/back/methods/invoiceOut/negativeBasesCsv.js b/modules/invoiceOut/back/methods/invoiceOut/negativeBasesCsv.js index d70a8fce5..87e9a67ea 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/negativeBasesCsv.js +++ b/modules/invoiceOut/back/methods/invoiceOut/negativeBasesCsv.js @@ -10,13 +10,17 @@ module.exports = Self => { type: 'date', description: 'From date', required: true - }, - { + }, { arg: 'to', type: 'date', description: 'To date', required: true - }], + }, { + arg: 'filter', + type: 'object', + description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string' + }, + ], returns: [ { arg: 'body', From 5dc49d226ad4450b130ff47231702593a69ddc00 Mon Sep 17 00:00:00 2001 From: jorgep Date: Wed, 3 Jan 2024 10:13:56 +0100 Subject: [PATCH 30/31] refs #6274 fix locale --- loopback/locale/en.json | 3 ++- loopback/locale/es.json | 7 +++--- .../back/methods/worker-time-control/login.js | 7 +++--- .../worker-time-control/specs/login.spec.js | 24 +++++++++++++++---- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/loopback/locale/en.json b/loopback/locale/en.json index c5e8d4fcf..508c17344 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -200,5 +200,6 @@ "Try again": "Try again", "keepPrice": "keepPrice", "Cannot past travels with entries": "Cannot past travels with entries", - "It was not able to remove the next expeditions:": "It was not able to remove the next expeditions: {{expeditions}}" + "It was not able to remove the next expeditions:": "It was not able to remove the next expeditions: {{expeditions}}", + "Incorrect pin": "Incorrect pin." } diff --git a/loopback/locale/es.json b/loopback/locale/es.json index fc209a9cd..e2b90983b 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -330,9 +330,8 @@ "quantityLessThanMin": "La cantidad no puede ser menor que la cantidad mínima", "Cannot past travels with entries": "No se pueden pasar envíos con entradas", "It was not able to remove the next expeditions:": "No se pudo eliminar las siguientes expediciones: {{expeditions}}", - "This user does not have an assigned tablet": "Este usuario no tiene tablet asignada", - "Incorrect pin.": "Pin incorrecto.", + "This user does not have an assigned tablet": "Este usuario no tiene tablet asignada", + "Incorrect pin": "Pin incorrecto.", "You already have the mailAlias": "Ya tienes este alias de correo", "The alias cant be modified": "Este alias de correo no puede ser modificado" -} - +} \ No newline at end of file diff --git a/modules/worker/back/methods/worker-time-control/login.js b/modules/worker/back/methods/worker-time-control/login.js index b2a17b4e4..9aa4bd145 100644 --- a/modules/worker/back/methods/worker-time-control/login.js +++ b/modules/worker/back/methods/worker-time-control/login.js @@ -1,7 +1,7 @@ const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { - Self.remoteMethod('login', { + Self.remoteMethodCtx('login', { description: 'Consult the user\'s information and the buttons that must be activated after logging in', accessType: 'READ', accepts: [ @@ -21,14 +21,15 @@ module.exports = Self => { } }); - Self.login = async(pin, options) => { + Self.login = async(ctx, pin, options) => { const myOptions = {}; + const $t = ctx.req.__; if (typeof options == 'object') Object.assign(myOptions, options); const query = `CALL vn.workerTimeControl_login(?)`; const [[user]] = await Self.rawSql(query, [pin], myOptions); - if (!user) throw new UserError('Incorrect pin.'); + if (!user) throw new UserError($t('Incorrect pin')); return user; }; }; diff --git a/modules/worker/back/methods/worker-time-control/specs/login.spec.js b/modules/worker/back/methods/worker-time-control/specs/login.spec.js index 8e992de96..d9f2dbb39 100644 --- a/modules/worker/back/methods/worker-time-control/specs/login.spec.js +++ b/modules/worker/back/methods/worker-time-control/specs/login.spec.js @@ -1,20 +1,34 @@ -const UserError = require('vn-loopback/util/user-error'); const models = require('vn-loopback/server/server').models; +const LoopBackContext = require('loopback-context'); +const UserError = require('vn-loopback/util/user-error'); describe('workerTimeControl login()', () => { + let ctx; + beforeAll(async() => { + ctx = { + accessToken: {userId: 9}, + req: { + headers: {origin: 'http://localhost'}, + __: key => key + } + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: ctx + }); + }); + it('should correctly login', async() => { - const response = await models.WorkerTimeControl.login(9); + const response = await models.WorkerTimeControl.login(ctx, 9); expect(response.name).toBe('developer'); }); it('should throw UserError if pin is not provided', async() => { try { - await models.WorkerTimeControl.login(); + await models.WorkerTimeControl.login(ctx); } catch (error) { expect(error).toBeInstanceOf(UserError); - expect(error.message).toBe('Incorrect pin.'); + expect(error.message).toBe('Incorrect pin'); } }); }); - From f73a447391b7541f41e3be2ccc05327c1254578e Mon Sep 17 00:00:00 2001 From: guillermo Date: Wed, 3 Jan 2024 11:57:49 +0100 Subject: [PATCH 31/31] refs #6398 Hotfix 1/2 --- modules/ticket/back/models/ticket-tracking.json | 3 --- modules/ticket/front/tracking/index/index.html | 6 +++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/modules/ticket/back/models/ticket-tracking.json b/modules/ticket/back/models/ticket-tracking.json index 4b5a4d473..ac0eb9a69 100644 --- a/modules/ticket/back/models/ticket-tracking.json +++ b/modules/ticket/back/models/ticket-tracking.json @@ -20,9 +20,6 @@ }, "stateFk": { "type": "number" - }, - "userFk": { - "type": "number" } }, "relations": { diff --git a/modules/ticket/front/tracking/index/index.html b/modules/ticket/front/tracking/index/index.html index 12c4778c9..10ee6d848 100644 --- a/modules/ticket/front/tracking/index/index.html +++ b/modules/ticket/front/tracking/index/index.html @@ -23,9 +23,9 @@ {{::tracking.state.name}} - {{::tracking.worker.user.name || 'System' | translate}} + ng-class="{'link': tracking.user.id}" + ng-click="workerDescriptor.show($event, tracking.user.id)"> + {{::tracking.user.name || 'System' | translate}} {{::tracking.created | date:'dd/MM/yyyy HH:mm'}}