refs #6553 changes models #2522
|
@ -22,7 +22,7 @@ module.exports = Self => {
|
||||||
description: 'The user email'
|
description: 'The user email'
|
||||||
}, {
|
}, {
|
||||||
arg: 'lang',
|
arg: 'lang',
|
||||||
type: 'string',
|
type: 'any',
|
||||||
description: 'The user lang'
|
description: 'The user lang'
|
||||||
}, {
|
}, {
|
||||||
arg: 'twoFactor',
|
arg: 'twoFactor',
|
||||||
|
|
|
@ -10,18 +10,26 @@ BEGIN
|
||||||
* @param vDateFrom Fecha desde
|
* @param vDateFrom Fecha desde
|
||||||
* @param vDateTo Fecha hasta
|
* @param vDateTo Fecha hasta
|
||||||
*/
|
*/
|
||||||
IF vDateFrom IS NULL THEN
|
DECLARE vDaysInYear INT;
|
||||||
SET vDateFrom = util.VN_CURDATE() - INTERVAL WEEKDAY(util.VN_CURDATE()) DAY;
|
SET vDaysInYear = DATEDIFF(util.lastDayOfYear(CURDATE()), util.firstDayOfYear(CURDATE()));
|
||||||
|
|
||||||
|
SET vDateFrom = COALESCE(vDateFrom, util.VN_CURDATE());
|
||||||
|
SET vDateTo = COALESCE(vDateTo, util.VN_CURDATE());
|
||||||
|
|
||||||
|
IF DATEDIFF(vDateTo, vDateFrom) > vDaysInYear THEN
|
||||||
|
CALL util.throw('The period cannot be longer than one year');
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
IF vDateTo IS NULL THEN
|
-- Obtiene el primer día de la semana de esa fecha
|
||||||
SET vDateTo = vDateFrom + INTERVAL 6 DAY;
|
SET vDateFrom = DATE_SUB(vDateFrom, INTERVAL ((WEEKDAY(vDateFrom) + 1) % 7) DAY);
|
||||||
END IF;
|
|
||||||
|
-- Obtiene el último día de la semana de esa fecha
|
||||||
|
SET vDateTo = DATE_ADD(vDateTo, INTERVAL (6 - ((WEEKDAY(vDateTo) + 1) % 7)) DAY);
|
||||||
|
|
||||||
CALL cache.last_buy_refresh(FALSE);
|
CALL cache.last_buy_refresh(FALSE);
|
||||||
|
|
||||||
REPLACE bs.waste
|
REPLACE bs.waste
|
||||||
SELECT YEAR(t.shipped),
|
SELECT YEARWEEK(t.shipped, 6) DIV 100,
|
||||||
WEEK(t.shipped, 6),
|
WEEK(t.shipped, 6),
|
||||||
it.workerFk,
|
it.workerFk,
|
||||||
it.id,
|
it.id,
|
||||||
|
@ -68,8 +76,8 @@ BEGIN
|
||||||
JOIN cache.last_buy lb ON lb.item_id = i.id
|
JOIN cache.last_buy lb ON lb.item_id = i.id
|
||||||
AND lb.warehouse_id = w.id
|
AND lb.warehouse_id = w.id
|
||||||
JOIN vn.buy b ON b.id = lb.buy_id
|
JOIN vn.buy b ON b.id = lb.buy_id
|
||||||
WHERE t.shipped BETWEEN vDateFrom AND vDateTo
|
WHERE t.shipped BETWEEN vDateFrom AND util.dayEnd(vDateTo)
|
||||||
AND w.isManaged
|
AND w.isManaged
|
||||||
GROUP BY YEAR(t.shipped), WEEK(t.shipped, 6), i.id;
|
GROUP BY YEARWEEK(t.shipped, 6) DIV 100, WEEK(t.shipped, 6), i.id;
|
||||||
END$$
|
END$$
|
||||||
DELIMITER ;
|
DELIMITER ;
|
||||||
|
|
|
@ -3,10 +3,12 @@ CREATE OR REPLACE DEFINER=`vn`@`localhost` TRIGGER `vn`.`workerTimeControl_after
|
||||||
AFTER DELETE ON `workerTimeControl`
|
AFTER DELETE ON `workerTimeControl`
|
||||||
FOR EACH ROW
|
FOR EACH ROW
|
||||||
BEGIN
|
BEGIN
|
||||||
|
IF account.myUser_getId() IS NOT NULL THEN
|
||||||
INSERT INTO workerLog
|
INSERT INTO workerLog
|
||||||
SET `action` = 'delete',
|
SET `action` = 'delete',
|
||||||
`changedModel` = 'WorkerTimeControl',
|
`changedModel` = 'WorkerTimeControl',
|
||||||
`changedModelId` = OLD.id,
|
`changedModelId` = OLD.id,
|
||||||
`userFk` = account.myUser_getId();
|
`userFk` = account.myUser_getId();
|
||||||
|
END IF;
|
||||||
END$$
|
END$$
|
||||||
DELIMITER ;
|
DELIMITER ;
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
DELETE FROM salix.ACL WHERE property = 'canCreateAbsenceInPast';
|
||||||
|
|
||||||
|
INSERT INTO salix.ACL (model,property,accessType,permission,principalType,principalId)
|
||||||
|
VALUES ('Worker','canModifyAbsenceInPast','WRITE','ALLOW','ROLE','hr');
|
|
@ -30,7 +30,7 @@ module.exports = Self => {
|
||||||
Object.assign(myOptions, options);
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
const query =
|
const query =
|
||||||
`SELECT DISTINCT u.id, u.nickname
|
`SELECT DISTINCT u.id, u.nickname, w.firstName, w.lastName
|
||||||
FROM itemType it
|
FROM itemType it
|
||||||
JOIN worker w ON w.id = it.workerFk
|
JOIN worker w ON w.id = it.workerFk
|
||||||
JOIN account.user u ON u.id = w.id`;
|
JOIN account.user u ON u.id = w.id`;
|
||||||
|
|
|
@ -58,12 +58,10 @@ module.exports = Self => {
|
||||||
if (!isSubordinate || (isSubordinate && userId == id && !isTeamBoss))
|
if (!isSubordinate || (isSubordinate && userId == id && !isTeamBoss))
|
||||||
throw new UserError(`You don't have enough privileges`);
|
throw new UserError(`You don't have enough privileges`);
|
||||||
|
|
||||||
const canCreateAbsenceInPast =
|
|
||||||
await models.ACL.checkAccessAcl(ctx, 'Worker', 'canCreateAbsenceInPast', 'WRITE');
|
|
||||||
const now = Date.vnNew();
|
const now = Date.vnNew();
|
||||||
const newDate = new Date(args.dated).getTime();
|
const newDate = new Date(args.dated).getTime();
|
||||||
|
|
||||||
if ((now.getTime() > newDate) && !canCreateAbsenceInPast)
|
if (!await Self.canModifyAbsenceInPast(ctx, newDate))
|
||||||
throw new UserError(`Holidays to past days not available`);
|
throw new UserError(`Holidays to past days not available`);
|
||||||
|
|
||||||
const labour = await models.WorkerLabour.findById(args.businessFk,
|
const labour = await models.WorkerLabour.findById(args.businessFk,
|
||||||
|
|
|
@ -53,6 +53,10 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
|
|
||||||
|
if (!await Self.canModifyAbsenceInPast(ctx, absence.dated.getTime()))
|
||||||
|
throw new UserError(`Holidays to past days not available`);
|
||||||
|
|
||||||
const result = await absence.destroy(myOptions);
|
const result = await absence.destroy(myOptions);
|
||||||
const labour = absence.labour();
|
const labour = absence.labour();
|
||||||
const department = labour && labour.department();
|
const department = labour && labour.department();
|
||||||
|
|
|
@ -4,6 +4,8 @@ const LoopBackContext = require('loopback-context');
|
||||||
describe('Worker deleteAbsence()', () => {
|
describe('Worker deleteAbsence()', () => {
|
||||||
const businessId = 18;
|
const businessId = 18;
|
||||||
const workerId = 18;
|
const workerId = 18;
|
||||||
|
const hrId = 37;
|
||||||
|
const salesBossId = 19;
|
||||||
const activeCtx = {
|
const activeCtx = {
|
||||||
accessToken: {userId: 1106},
|
accessToken: {userId: 1106},
|
||||||
headers: {origin: 'http://localhost'}
|
headers: {origin: 'http://localhost'}
|
||||||
|
@ -50,16 +52,16 @@ describe('Worker deleteAbsence()', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should successfully delete an absence', async() => {
|
it('should successfully delete an absence', async() => {
|
||||||
activeCtx.accessToken.userId = 19;
|
activeCtx.accessToken.userId = salesBossId;
|
||||||
|
|
||||||
const tx = await app.models.Calendar.beginTransaction({});
|
const tx = await app.models.Calendar.beginTransaction({});
|
||||||
|
const pastDate = new Date(Date.vnNow() + 24 * 60 * 60 * 1000);
|
||||||
try {
|
try {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
const createdAbsence = await app.models.Calendar.create({
|
const createdAbsence = await app.models.Calendar.create({
|
||||||
businessFk: businessId,
|
businessFk: businessId,
|
||||||
dayOffTypeFk: 1,
|
dayOffTypeFk: 1,
|
||||||
dated: Date.vnNew()
|
dated: pastDate
|
||||||
}, options);
|
}, options);
|
||||||
|
|
||||||
ctx.args = {absenceId: createdAbsence.id};
|
ctx.args = {absenceId: createdAbsence.id};
|
||||||
|
@ -76,4 +78,61 @@ describe('Worker deleteAbsence()', () => {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should successfully delete an absence if the user is HR even if the date is in the past', async() => {
|
||||||
|
activeCtx.accessToken.userId = hrId;
|
||||||
|
const tx = await app.models.Calendar.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
const pastDate = new Date(Date.vnNow() - 24 * 60 * 60 * 1000); // Restar un día
|
||||||
|
const createdAbsence = await app.models.Calendar.create({
|
||||||
|
businessFk: businessId,
|
||||||
|
dayOffTypeFk: 1,
|
||||||
|
dated: pastDate
|
||||||
|
}, options);
|
||||||
|
|
||||||
|
ctx.args = {absenceId: createdAbsence.id};
|
||||||
|
await app.models.Worker.deleteAbsence(ctx, workerId, options);
|
||||||
|
|
||||||
|
const deletedAbsence = await app.models.Calendar.findById(createdAbsence.id, null, options);
|
||||||
|
|
||||||
|
expect(deletedAbsence).toBeNull();
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error if the date is in the past', async() => {
|
||||||
|
activeCtx.accessToken.userId = salesBossId;
|
||||||
|
const tx = await app.models.Calendar.beginTransaction({});
|
||||||
|
|
||||||
|
let error;
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
const pastDate = new Date(Date.vnNow() - 24 * 60 * 60 * 1000);
|
||||||
|
const createdAbsence = await app.models.Calendar.create({
|
||||||
|
businessFk: businessId,
|
||||||
|
dayOffTypeFk: 1,
|
||||||
|
dated: pastDate
|
||||||
|
}, options);
|
||||||
|
|
||||||
|
ctx.args = {absenceId: createdAbsence.id};
|
||||||
|
await app.models.Worker.deleteAbsence(ctx, workerId, options);
|
||||||
|
|
||||||
|
const deletedAbsence = await app.models.Calendar.findById(createdAbsence.id, null, options);
|
||||||
|
|
||||||
|
expect(deletedAbsence).toBeNull();
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toBe('Holidays to past days not available');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -26,6 +26,13 @@ module.exports = Self => {
|
||||||
message: 'Invalid TIN'
|
message: 'Invalid TIN'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Self.canModifyAbsenceInPast = async(ctx, time) => {
|
||||||
|
const hasPrivs = await Self.app.models.ACL.checkAccessAcl(ctx, 'Worker', 'canModifyAbsenceInPast', 'WRITE');
|
||||||
|
const today = Date.vnNew();
|
||||||
|
today.setHours(0, 0, 0, 0);
|
||||||
|
return hasPrivs || today.getTime() < time;
|
||||||
|
};
|
||||||
|
|
||||||
async function tinIsValid(err, done) {
|
async function tinIsValid(err, done) {
|
||||||
const country = await Self.app.models.Country.findOne({
|
const country = await Self.app.models.Country.findOne({
|
||||||
fields: ['code'],
|
fields: ['code'],
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
html {
|
html {
|
||||||
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
|
font-family: "Roboto", "Helvetica", "Arial", sans-serif;
|
||||||
margin-top: -7px;
|
margin-top: -7px;
|
||||||
font-size: 28px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
table {
|
table {
|
||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
|
@ -10,22 +10,22 @@ table {
|
||||||
}
|
}
|
||||||
td {
|
td {
|
||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
padding: 5px;
|
padding: 2px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
span {
|
span {
|
||||||
font-size: 48px;
|
font-size: 34px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
.lbl {
|
.lbl {
|
||||||
color: gray;
|
color: gray;
|
||||||
font-weight: lighter;
|
font-weight: lighter;
|
||||||
font-size: 18px;
|
font-size: 12px;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.cell {
|
.cell {
|
||||||
width: 157px;
|
width: 157px;
|
||||||
height: 50px;
|
height: 35px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|
|
@ -10,7 +10,7 @@ module.exports = {
|
||||||
async serverPrefetch() {
|
async serverPrefetch() {
|
||||||
const buy = await models.Buy.findById(this.id, null);
|
const buy = await models.Buy.findById(this.id, null);
|
||||||
this.buys = await this.rawSqlFromDef('buy', [buy.entryFk, buy.entryFk, buy.entryFk, this.id, this.id]);
|
this.buys = await this.rawSqlFromDef('buy', [buy.entryFk, buy.entryFk, buy.entryFk, this.id, this.id]);
|
||||||
const date = new Date();
|
const date = Date.vnNew();
|
||||||
this.weekNum = moment(date).isoWeek();
|
this.weekNum = moment(date).isoWeek();
|
||||||
this.dayNum = moment(date).day();
|
this.dayNum = moment(date).day();
|
||||||
},
|
},
|
||||||
|
@ -24,7 +24,8 @@ module.exports = {
|
||||||
format: 'code128',
|
format: 'code128',
|
||||||
displayValue: false,
|
displayValue: false,
|
||||||
width: 3.8,
|
width: 3.8,
|
||||||
height: 115,
|
height: 60,
|
||||||
|
margin: 3,
|
||||||
});
|
});
|
||||||
return new XMLSerializer().serializeToString(svgNode);
|
return new XMLSerializer().serializeToString(svgNode);
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"width": "10cm",
|
"width": "10cm",
|
||||||
"height": "10cm",
|
"height": "6.5cm",
|
||||||
"margin": {
|
"margin": {
|
||||||
"top": "0.17cm",
|
"top": "0.17cm",
|
||||||
"right": "0.2cm",
|
"right": "0.2cm",
|
||||||
|
|
Loading…
Reference in New Issue