diff --git a/db/changes/10230-oktoberFest/00-ACL.sql b/db/changes/10230-oktoberFest/00-ACL.sql
new file mode 100644
index 000000000..0e5c9e1dc
--- /dev/null
+++ b/db/changes/10230-oktoberFest/00-ACL.sql
@@ -0,0 +1 @@
+UPDATE salix.ACL t SET t.principalId = 'salesAssistant' WHERE t.id = 234
\ No newline at end of file
diff --git a/db/changes/10230-oktoberFest/00-department.sql b/db/changes/10230-oktoberFest/00-department.sql
new file mode 100644
index 000000000..38d4f6875
--- /dev/null
+++ b/db/changes/10230-oktoberFest/00-department.sql
@@ -0,0 +1,4 @@
+ALTER TABLE `vn`.department
+ ADD notificationEmail VARCHAR(150) null;
+
+UPDATE vn.department t SET t.notificationEmail = 'direccioncomercial@verdnatura.es' WHERE t.id = 43
\ No newline at end of file
diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index ac0386876..62a5b7ca2 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -42,8 +42,8 @@ INSERT INTO `vn`.`worker`(`id`,`code`, `firstName`, `lastName`, `userFk`, `bossF
FROM `vn`.`user`;
UPDATE `vn`.`worker` SET bossFk = NULL WHERE id = 20;
-UPDATE `vn`.`worker` SET bossFk = 20
- WHERE id = 1 OR id = 9;
+UPDATE `vn`.`worker` SET bossFk = 20 WHERE id = 1 OR id = 9;
+UPDATE `vn`.`worker` SET bossFk = 19 WHERE id = 18;
DELETE FROM `vn`.`worker` WHERE firstName ='customer';
@@ -1696,6 +1696,10 @@ UPDATE `postgresql`.`business_labour` bl
SET bl.`professional_category_id` = 31
WHERE p.`Id_trabajador` = 110;
+UPDATE `postgresql`.`business_labour` bl
+ SET bl.`department_id` = 43
+WHERE business_id IN(18, 19);
+
INSERT INTO `postgresql`.`media`(`media_id`, `media_type_id`, `value`, `sort`)
VALUES
(1, 10, 600123321, 0),
diff --git a/loopback/locale/en.json b/loopback/locale/en.json
index 114b07edf..4a970190d 100644
--- a/loopback/locale/en.json
+++ b/loopback/locale/en.json
@@ -68,5 +68,7 @@
"Incoterms is required for a non UEE member": "Incoterms is required for a non UEE member",
"Client checked as validated despite of duplication": "Client checked as validated despite of duplication from client id {{clientId}}",
"Landing cannot be lesser than shipment": "Landing cannot be lesser than shipment",
- "NOT_ZONE_WITH_THIS_PARAMETERS": "NOT_ZONE_WITH_THIS_PARAMETERS"
+ "NOT_ZONE_WITH_THIS_PARAMETERS": "NOT_ZONE_WITH_THIS_PARAMETERS",
+ "Created absence": "The worker {{author}} has added an absence of type '{{absenceType}}' to {{employee}} for day {{dated}}.",
+ "Deleted absence": "The worker {{author}} has deleted an absence of type '{{absenceType}}' to {{employee}} for day {{dated}}."
}
\ No newline at end of file
diff --git a/loopback/locale/es.json b/loopback/locale/es.json
index ea5a09952..1f536c3ce 100644
--- a/loopback/locale/es.json
+++ b/loopback/locale/es.json
@@ -143,5 +143,8 @@
"Role name must be written in camelCase": "Role name must be written in camelCase",
"can't be set": "can't be set",
"Email already exists": "Email already exists",
- "User already exists": "User already exists"
+ "User already exists": "User already exists",
+ "Absence change notification on the labour calendar": "Notificacion de cambio de ausencia en el calendario laboral",
+ "Created absence": "El empleado {{author}} ha añadido una ausencia de tipo '{{absenceType}}' a {{employee}} para el día {{dated}}.",
+ "Deleted absence": "El empleado {{author}} ha eliminado una ausencia de tipo '{{absenceType}}' a {{employee}} del día {{dated}}."
}
\ No newline at end of file
diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js
index 636e32ffa..36bc60dfa 100644
--- a/modules/client/back/models/client.js
+++ b/modules/client/back/models/client.js
@@ -186,10 +186,16 @@ module.exports = Self => {
let payMethodWithIban = 4;
// Validate socialName format
- const socialNameChanged = orgData && changes
- && orgData.socialName != changes.socialName;
+ const hasChanges = orgData && changes;
+ const socialName = changes.socialName || orgData.socialName;
+ const isTaxDataChecked = hasChanges && (changes.isTaxDataChecked || orgData.isTaxDataChecked);
- if (socialNameChanged && !isAlpha(changes.socialName))
+ const socialNameChanged = hasChanges
+ && orgData.socialName != socialName;
+ const dataCheckedChanged = hasChanges
+ && orgData.isTaxDataChecked != isTaxDataChecked;
+
+ if ((socialNameChanged || dataCheckedChanged) && !isAlpha(socialName))
throw new UserError('The socialName has an invalid format');
if (changes.salesPerson === null) {
diff --git a/modules/worker/back/methods/worker/createAbsence.js b/modules/worker/back/methods/worker/createAbsence.js
index 3163e697d..cc0ee13a6 100644
--- a/modules/worker/back/methods/worker/createAbsence.js
+++ b/modules/worker/back/methods/worker/createAbsence.js
@@ -31,6 +31,7 @@ module.exports = Self => {
Self.createAbsence = async(ctx, id, absenceTypeId, dated) => {
const models = Self.app.models;
+ const $t = ctx.req.__; // $translate
const userId = ctx.req.accessToken.userId;
const isSubordinate = await models.Worker.isSubordinate(ctx, id);
const isTeamBoss = await models.Account.hasRole(userId, 'teamBoss');
@@ -39,6 +40,7 @@ module.exports = Self => {
throw new UserError(`You don't have enough privileges`);
const labour = await models.WorkerLabour.findOne({
+ include: {relation: 'department'},
where: {
and: [
{workerFk: id},
@@ -49,10 +51,42 @@ module.exports = Self => {
}
});
- return models.Calendar.create({
+ const absence = await models.Calendar.create({
businessFk: labour.businessFk,
dayOffTypeFk: absenceTypeId,
dated: dated
});
+
+ const department = labour.department();
+ if (department && department.notificationEmail) {
+ const absenceType = await models.AbsenceType.findById(absenceTypeId);
+ const account = await models.Account.findById(userId);
+ const subordinated = await models.Account.findById(id);
+ const origin = ctx.req.headers.origin;
+ const body = $t('Created absence', {
+ author: account.nickname,
+ employee: subordinated.nickname,
+ absenceType: absenceType.name,
+ dated: formatDate(dated),
+ workerUrl: `${origin}/#!/worker/${id}/calendar`
+ });
+ await models.Mail.create({
+ subject: $t('Absence change notification on the labour calendar'),
+ body: body,
+ sender: department.notificationEmail
+ });
+ }
+
+ return absence;
};
+
+ function formatDate(date) {
+ let day = date.getDate();
+ if (day < 10) day = `0${day}`;
+ let month = date.getMonth();
+ if (month < 10) month = `0${month}`;
+ let year = date.getFullYear();
+
+ return `${day}-${month}-${year}`;
+ }
};
diff --git a/modules/worker/back/methods/worker/deleteAbsence.js b/modules/worker/back/methods/worker/deleteAbsence.js
index 0fe8f7dc8..c7e24fa58 100644
--- a/modules/worker/back/methods/worker/deleteAbsence.js
+++ b/modules/worker/back/methods/worker/deleteAbsence.js
@@ -23,6 +23,7 @@ module.exports = Self => {
Self.deleteAbsence = async(ctx, id, absenceId) => {
const models = Self.app.models;
+ const $t = ctx.req.__; // $translate
const userId = ctx.req.accessToken.userId;
const isSubordinate = await models.Worker.isSubordinate(ctx, id);
const isTeamBoss = await models.Account.hasRole(userId, 'teamBoss');
@@ -30,8 +31,46 @@ module.exports = Self => {
if (!isSubordinate || (isSubordinate && userId == id && !isTeamBoss))
throw new UserError(`You don't have enough privileges`);
- const absence = await models.Calendar.findById(absenceId);
+ const absence = await models.Calendar.findById(absenceId, {
+ include: {
+ relation: 'labour',
+ scope: {
+ include: {relation: 'department'}
+ }
+ }
+ });
+ const result = await absence.destroy();
+ const labour = absence.labour();
+ const department = labour && labour.department();
+ if (department && department.notificationEmail) {
+ const absenceType = await models.AbsenceType.findById(absence.dayOffTypeFk);
+ const account = await models.Account.findById(userId);
+ const subordinated = await models.Account.findById(labour.workerFk);
+ const origin = ctx.req.headers.origin;
+ const body = $t('Deleted absence', {
+ author: account.nickname,
+ employee: subordinated.nickname,
+ absenceType: absenceType.name,
+ dated: formatDate(absence.dated),
+ workerUrl: `${origin}/#!/worker/${id}/calendar`
+ });
+ await models.Mail.create({
+ subject: $t('Absence change notification on the labour calendar'),
+ body: body,
+ sender: department.notificationEmail
+ });
+ }
- return absence.destroy();
+ return result;
};
+
+ function formatDate(date) {
+ let day = date.getDate();
+ if (day < 10) day = `0${day}`;
+ let month = date.getMonth();
+ if (month < 10) month = `0${month}`;
+ let year = date.getFullYear();
+
+ return `${day}-${month}-${year}`;
+ }
};
diff --git a/modules/worker/back/methods/worker/specs/createAbsence.spec.js b/modules/worker/back/methods/worker/specs/createAbsence.spec.js
index df48cf80b..324dab99d 100644
--- a/modules/worker/back/methods/worker/specs/createAbsence.spec.js
+++ b/modules/worker/back/methods/worker/specs/createAbsence.spec.js
@@ -1,7 +1,8 @@
const app = require('vn-loopback/server/server');
+const LoopBackContext = require('loopback-context');
describe('Worker createAbsence()', () => {
- const workerId = 106;
+ const workerId = 18;
let createdAbsence;
afterAll(async() => {
@@ -10,7 +11,7 @@ describe('Worker createAbsence()', () => {
});
it('should return an error for a user without enough privileges', async() => {
- const ctx = {req: {accessToken: {userId: 106}}};
+ const ctx = {req: {accessToken: {userId: 18}}};
const absenceTypeId = 1;
const dated = new Date();
@@ -25,12 +26,23 @@ describe('Worker createAbsence()', () => {
});
it('should create a new absence', async() => {
- const ctx = {req: {accessToken: {userId: 37}}};
+ const activeCtx = {
+ accessToken: {userId: 19},
+ headers: {origin: 'http://localhost'}
+ };
+ const ctx = {req: activeCtx};
+ ctx.req.__ = value => {
+ return value;
+ };
+ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
+ active: activeCtx
+ });
+
const absenceTypeId = 1;
const dated = new Date();
createdAbsence = await app.models.Worker.createAbsence(ctx, workerId, absenceTypeId, dated);
- const expectedBusinessId = 106;
+ const expectedBusinessId = 18;
const expectedAbsenceTypeId = 1;
expect(createdAbsence.businessFk).toEqual(expectedBusinessId);
diff --git a/modules/worker/back/methods/worker/specs/deleteAbsence.spec.js b/modules/worker/back/methods/worker/specs/deleteAbsence.spec.js
index 140edada8..2f72a8435 100644
--- a/modules/worker/back/methods/worker/specs/deleteAbsence.spec.js
+++ b/modules/worker/back/methods/worker/specs/deleteAbsence.spec.js
@@ -1,12 +1,25 @@
const app = require('vn-loopback/server/server');
+const LoopBackContext = require('loopback-context');
describe('Worker deleteAbsence()', () => {
- const workerId = 106;
+ const workerId = 18;
let createdAbsence;
+ const activeCtx = {
+ accessToken: {userId: 19},
+ headers: {origin: 'http://localhost'}
+ };
+ const ctx = {req: activeCtx};
+ ctx.req.__ = value => {
+ return value;
+ };
it('should return an error for a user without enough privileges', async() => {
- const ctx = {req: {accessToken: {userId: 106}}};
- const businessId = 106;
+ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
+ active: activeCtx
+ });
+
+ activeCtx.accessToken.userId = 106;
+ const businessId = 18;
createdAbsence = await app.models.Calendar.create({
businessFk: businessId,
dayOffTypeFk: 1,
@@ -14,7 +27,7 @@ describe('Worker deleteAbsence()', () => {
});
let error;
- await app.models.Worker.deleteAbsence(ctx, workerId, createdAbsence.id).catch(e => {
+ await app.models.Worker.deleteAbsence(ctx, 18, createdAbsence.id).catch(e => {
error = e;
}).finally(() => {
expect(error.message).toEqual(`You don't have enough privileges`);
@@ -24,8 +37,12 @@ describe('Worker deleteAbsence()', () => {
});
it('should create a new absence', async() => {
- const ctx = {req: {accessToken: {userId: 37}}};
- const businessId = 106;
+ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
+ active: activeCtx
+ });
+
+ activeCtx.accessToken.userId = 19;
+ const businessId = 18;
expect(createdAbsence.businessFk).toEqual(businessId);
diff --git a/modules/worker/back/models/calendar.json b/modules/worker/back/models/calendar.json
index 417442571..199d81e6c 100644
--- a/modules/worker/back/models/calendar.json
+++ b/modules/worker/back/models/calendar.json
@@ -1,6 +1,10 @@
{
"name": "Calendar",
- "base": "VnModel",
+ "base": "Loggable",
+ "log": {
+ "model": "WorkerLog",
+ "relation": "labour"
+ },
"options": {
"mysql": {
"table": "calendar"
@@ -23,6 +27,11 @@
"type": "belongsTo",
"model": "AbsenceType",
"foreignKey": "dayOffTypeFk"
+ },
+ "labour": {
+ "type": "belongsTo",
+ "model": "WorkerLabour",
+ "foreignKey": "businessFk"
}
}
}
diff --git a/modules/worker/back/models/department.json b/modules/worker/back/models/department.json
index d8ec7313a..31ebbb09a 100644
--- a/modules/worker/back/models/department.json
+++ b/modules/worker/back/models/department.json
@@ -28,6 +28,9 @@
},
"chatName": {
"type": "String"
+ },
+ "notificationEmail": {
+ "type": "String"
}
}
}
diff --git a/modules/worker/front/routes.json b/modules/worker/front/routes.json
index 7825e9735..9ab2f597e 100644
--- a/modules/worker/front/routes.json
+++ b/modules/worker/front/routes.json
@@ -63,7 +63,7 @@
"state": "worker.card.workerLog",
"component": "vn-worker-log",
"description": "Log",
- "acl": ["hr"]
+ "acl": ["salesAssistant"]
}, {
"url": "/pbx",
"state": "worker.card.pbx",