salix/modules/worker/front/time-control/index.js

513 lines
15 KiB
JavaScript
Raw Normal View History

2019-05-17 11:27:51 +00:00
import ngModule from '../module';
2020-03-18 11:55:22 +00:00
import Section from 'salix/components/section';
2019-05-17 11:27:51 +00:00
import './style.scss';
import UserError from 'core/lib/user-error';
2020-03-18 11:55:22 +00:00
class Controller extends Section {
2019-11-05 10:57:05 +00:00
constructor($element, $, vnWeekDays) {
super($element, $);
2019-05-17 11:27:51 +00:00
this.weekDays = [];
2019-10-23 15:38:35 +00:00
this.weekdayNames = vnWeekDays.locales;
2021-06-17 13:09:04 +00:00
this.entryDirections = [
{code: 'in', description: this.$t('In')},
{code: 'middle', description: this.$t('Intermediate')},
{code: 'out', description: this.$t('Out')}
];
2019-05-17 11:27:51 +00:00
}
2019-10-23 15:38:35 +00:00
$postLink() {
const timestamp = this.$params.timestamp;
2023-01-16 14:18:24 +00:00
let initialDate = Date.vnNew();
if (timestamp) {
initialDate = new Date(timestamp * 1000);
this.$.calendar.defaultDate = initialDate;
}
this.date = initialDate;
this.getMailStates(this.date);
2019-10-23 15:38:35 +00:00
}
2019-05-17 11:27:51 +00:00
2023-02-23 07:21:59 +00:00
get isHr() {
return this.aclService.hasAny(['hr']);
}
get isHimSelf() {
const userId = window.localStorage.currentUserWorkerId;
return userId == this.$params.id;
}
2021-06-11 08:58:00 +00:00
get worker() {
return this._worker;
}
2023-02-23 07:21:59 +00:00
get weekNumber() {
return this.getWeekNumber(this.date);
}
set weekNumber(value) {
this._weekNumber = value;
}
2021-06-11 08:58:00 +00:00
set worker(value) {
this._worker = value;
2023-09-28 09:36:03 +00:00
this.fetchHours();
if (this.date)
this.getWeekData();
2023-09-28 09:36:03 +00:00
}
/**
* Worker hours data
*/
get hours() {
return this._hours;
}
set hours(value) {
this._hours = value;
for (const weekDay of this.weekDays) {
if (value) {
let day = weekDay.dated.getDay();
weekDay.hours = value
.filter(hour => new Date(hour.timed).getDay() == day)
.sort((a, b) => new Date(a.timed) - new Date(b.timed));
} else
weekDay.hours = null;
}
2021-06-11 08:58:00 +00:00
}
2019-05-17 11:27:51 +00:00
/**
2019-10-23 15:38:35 +00:00
* The current selected date
2019-05-17 11:27:51 +00:00
*/
2019-10-23 15:38:35 +00:00
get date() {
return this._date;
2019-05-17 11:27:51 +00:00
}
2019-10-23 15:38:35 +00:00
set date(value) {
this._date = value;
value.setHours(0, 0, 0, 0);
2019-05-17 11:27:51 +00:00
2019-10-23 15:38:35 +00:00
let weekOffset = value.getDay() - 1;
if (weekOffset < 0) weekOffset = 6;
let started = new Date(value.getTime());
started.setDate(started.getDate() - weekOffset);
this.started = started;
let ended = new Date(started.getTime());
2019-11-05 07:59:48 +00:00
ended.setHours(23, 59, 59, 59);
ended.setDate(ended.getDate() + 6);
2019-10-23 15:38:35 +00:00
this.ended = ended;
2019-11-05 07:59:48 +00:00
this.weekDays = [];
let dayIndex = new Date(started.getTime());
while (dayIndex < ended) {
this.weekDays.push({
dated: new Date(dayIndex.getTime())
});
dayIndex.setDate(dayIndex.getDate() + 1);
}
2023-09-28 09:53:09 +00:00
if (!this.weekTotalHours) this.fetchHours();
if (this.worker)
this.getWeekData();
}
2023-09-28 09:36:03 +00:00
set weekTotalHours(totalHours) {
this._weekTotalHours = this.formatHours(totalHours);
}
get weekTotalHours() {
return this._weekTotalHours;
}
getWeekData() {
const filter = {
where: {
workerFk: this.$params.id,
year: this._date.getFullYear(),
week: this.getWeekNumber(this._date)
},
};
this.$http.get('WorkerTimeControlMails', {filter})
.then(res => {
if (!res.data.length) {
this.state = null;
return;
}
const [mail] = res.data;
this.state = mail.state;
this.reason = mail.reason;
});
this.canBeResend();
2019-05-17 11:27:51 +00:00
}
canBeResend() {
this.canResend = false;
const filter = {
where: {
year: this._date.getFullYear(),
week: this.getWeekNumber(this._date)
},
limit: 1
};
this.$http.get('WorkerTimeControlMails', {filter})
.then(res => {
if (res.data.length)
this.canResend = true;
});
}
2019-10-23 15:38:35 +00:00
fetchHours() {
2023-09-28 09:36:03 +00:00
if (!this.worker || !this.date) return;
2019-05-17 11:27:51 +00:00
2019-11-05 10:57:05 +00:00
const params = {workerFk: this.$params.id};
2019-10-23 15:38:35 +00:00
const filter = {
where: {and: [
{timed: {gte: this.started}},
2019-11-05 07:59:48 +00:00
{timed: {lte: this.ended}}
2019-10-23 15:38:35 +00:00
]}
};
2019-12-31 13:01:05 +00:00
this.$.model.applyFilter(filter, params).then(() => {
2023-07-14 09:51:15 +00:00
if (!this.card.hasWorkCenter) return;
2019-12-31 13:01:05 +00:00
this.getWorkedHours(this.started, this.ended);
this.getAbsences();
2019-12-31 13:01:05 +00:00
});
2019-05-17 11:27:51 +00:00
}
2023-09-28 09:36:03 +00:00
getWorkedHours(from, to) {
this.weekTotalHours = null;
let weekTotalHours = 0;
let params = {
id: this.$params.id,
from: from,
to: to
};
const query = `Workers/${this.$params.id}/getWorkedHours`;
return this.$http.get(query, {params}).then(res => {
const workDays = res.data;
const map = new Map();
for (const workDay of workDays) {
workDay.dated = new Date(workDay.dated);
map.set(workDay.dated, workDay);
weekTotalHours += workDay.workedHours;
}
for (const weekDay of this.weekDays) {
const workDay = workDays.find(day => {
let from = new Date(day.dated);
from.setHours(0, 0, 0, 0);
let to = new Date(day.dated);
to.setHours(23, 59, 59, 59);
return weekDay.dated >= from && weekDay.dated <= to;
});
if (workDay) {
weekDay.expectedHours = workDay.expectedHours;
weekDay.workedHours = workDay.workedHours;
}
}
this.weekTotalHours = weekTotalHours;
});
2019-05-17 11:27:51 +00:00
}
2019-12-31 13:01:05 +00:00
getAbsences() {
2021-06-11 08:58:00 +00:00
const fullYear = this.started.getFullYear();
2019-12-31 13:01:05 +00:00
let params = {
workerFk: this.$params.id,
businessFk: null,
2021-06-11 08:58:00 +00:00
year: fullYear
2019-12-31 13:01:05 +00:00
};
2020-08-10 12:29:25 +00:00
return this.$http.get(`Calendars/absences`, {params})
2019-12-31 13:01:05 +00:00
.then(res => this.onData(res.data));
}
2023-09-28 09:36:03 +00:00
hasEvents(day) {
return day >= this.started && day < this.ended;
}
2019-12-31 13:01:05 +00:00
onData(data) {
const events = {};
const addEvent = (day, event) => {
2019-12-31 13:01:05 +00:00
events[new Date(day).getTime()] = event;
};
if (data.holidays) {
data.holidays.forEach(holiday => {
const holidayDetail = holiday.detail && holiday.detail.description;
const holidayType = holiday.type && holiday.type.name;
const holidayName = holidayDetail || holidayType;
addEvent(holiday.dated, {
name: holidayName,
color: '#ff0'
});
});
}
if (data.absences) {
data.absences.forEach(absence => {
const type = absence.absenceType;
addEvent(absence.dated, {
name: type.name,
color: type.rgb
});
});
}
this.weekDays.forEach(day => {
const timestamp = day.dated.getTime();
if (events[timestamp])
day.event = events[timestamp];
});
}
2019-11-05 07:59:48 +00:00
getFinishTime() {
2019-11-05 10:57:05 +00:00
if (!this.weekDays) return;
2023-01-16 14:18:24 +00:00
let today = Date.vnNew();
2019-11-05 10:57:05 +00:00
today.setHours(0, 0, 0, 0);
2019-05-17 11:27:51 +00:00
2019-11-05 10:57:05 +00:00
let todayInWeek = this.weekDays.find(day => day.dated.getTime() === today.getTime());
2019-11-14 13:20:05 +00:00
if (todayInWeek && todayInWeek.hours && todayInWeek.hours.length) {
const remainingTime = todayInWeek.workedHours ?
((todayInWeek.expectedHours - todayInWeek.workedHours) * 1000) : null;
2019-11-14 13:20:05 +00:00
const lastKnownEntry = todayInWeek.hours[todayInWeek.hours.length - 1];
const lastKnownTime = new Date(lastKnownEntry.timed).getTime();
const finishTimeStamp = lastKnownTime && remainingTime ? lastKnownTime + remainingTime : null;
2019-05-17 11:27:51 +00:00
2019-11-14 13:20:05 +00:00
if (finishTimeStamp) {
let finishDate = new Date(finishTimeStamp);
let hour = finishDate.getHours();
let minute = finishDate.getMinutes();
2019-05-17 11:27:51 +00:00
2019-11-14 13:20:05 +00:00
if (hour < 10) hour = `0${hour}`;
if (minute < 10) minute = `0${minute}`;
2019-05-17 11:27:51 +00:00
2019-11-14 13:20:05 +00:00
return `${hour}:${minute} h.`;
}
2019-11-05 07:59:48 +00:00
}
2019-05-17 11:27:51 +00:00
}
2020-10-29 12:46:36 +00:00
formatHours(timestamp = 0) {
2019-11-05 07:59:48 +00:00
let hour = Math.floor(timestamp / 3600);
let min = Math.floor(timestamp / 60 - 60 * hour);
2019-05-17 11:27:51 +00:00
if (hour < 10) hour = `0${hour}`;
if (min < 10) min = `0${min}`;
return `${hour}:${min}`;
}
showAddTimeDialog(weekday) {
const timed = new Date(weekday.dated.getTime());
timed.setHours(0, 0, 0, 0);
2019-05-21 10:56:29 +00:00
2021-06-17 13:09:04 +00:00
this.newTimeEntry = {
workerFk: this.$params.id,
timed: timed
};
2019-05-17 11:27:51 +00:00
this.selectedWeekday = weekday;
this.$.addTimeDialog.show();
}
2020-07-29 08:47:48 +00:00
addTime() {
2021-06-18 10:32:37 +00:00
try {
const entry = this.newTimeEntry;
if (!entry.direction)
throw new Error(`The entry type can't be empty`);
const query = `WorkerTimeControls/${this.worker.id}/addTimeEntry`;
this.$http.post(query, entry)
.then(() => {
this.fetchHours();
this.getMailStates(this.date);
});
2021-06-18 10:32:37 +00:00
} catch (e) {
this.vnApp.showError(this.$t(e.message));
return false;
}
return true;
2019-05-17 11:27:51 +00:00
}
2019-11-05 07:59:48 +00:00
2021-06-17 13:09:04 +00:00
showDeleteDialog($event, hour) {
$event.preventDefault();
2019-11-05 07:59:48 +00:00
this.timeEntryToDelete = hour;
this.$.deleteEntryDialog.show();
}
2019-11-05 10:57:05 +00:00
deleteTimeEntry() {
2019-11-05 07:59:48 +00:00
const entryId = this.timeEntryToDelete.id;
2019-11-05 10:57:05 +00:00
this.$http.post(`WorkerTimeControls/${entryId}/deleteTimeEntry`).then(() => {
2019-11-05 07:59:48 +00:00
this.fetchHours();
this.getMailStates(this.date);
2019-11-05 10:57:05 +00:00
this.vnApp.showSuccess(this.$t('Entry removed'));
2019-11-05 07:59:48 +00:00
});
}
2021-06-17 13:09:04 +00:00
edit($event, hour) {
if ($event.defaultPrevented) return;
this.selectedRow = hour;
this.$.editEntry.show($event);
}
2023-02-22 14:12:25 +00:00
getWeekNumber(date) {
const tempDate = new Date(date);
let dayOfWeek = tempDate.getDay();
dayOfWeek = (dayOfWeek === 0) ? 7 : dayOfWeek;
const firstDayOfWeek = new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() - (dayOfWeek - 1));
const firstDayOfYear = new Date(tempDate.getFullYear(), 0, 1);
const differenceInMilliseconds = firstDayOfWeek.getTime() - firstDayOfYear.getTime();
const weekNumber = Math.floor(differenceInMilliseconds / (1000 * 60 * 60 * 24 * 7)) + 1;
return weekNumber;
}
isSatisfied() {
this.updateWorkerTimeControlMail('CONFIRMED');
}
isUnsatisfied() {
if (!this.reason) throw new UserError(`You must indicate a reason`);
this.updateWorkerTimeControlMail('REVISE', this.reason);
}
updateWorkerTimeControlMail(state, reason) {
const params = {
workerId: this.worker.id,
year: this.date.getFullYear(),
2023-02-23 07:21:59 +00:00
week: this.weekNumber,
state
};
if (reason)
params.reason = reason;
const query = `WorkerTimeControls/updateWorkerTimeControlMail`;
this.$http.post(query, params).then(() => {
this.getMailStates(this.date);
this.getWeekData();
this.vnApp.showSuccess(this.$t('Data saved!'));
});
}
changeState(state, reason) {
this.state = state;
this.reason = reason;
this.repaint();
}
2021-06-17 13:09:04 +00:00
save() {
2021-06-18 10:32:37 +00:00
try {
const entry = this.selectedRow;
if (!entry.direction)
throw new Error(`The entry type can't be empty`);
const query = `WorkerTimeControls/${entry.id}/updateTimeEntry`;
this.$http.post(query, {direction: entry.direction})
.then(() => this.vnApp.showSuccess(this.$t('Data saved!')))
.then(() => this.$.editEntry.hide())
.then(() => this.fetchHours())
.then(() => this.getMailStates(this.date));
2021-06-18 10:32:37 +00:00
} catch (e) {
this.vnApp.showError(this.$t(e.message));
}
2021-06-17 13:09:04 +00:00
}
2023-02-22 14:12:25 +00:00
resendEmail() {
2023-02-23 07:21:59 +00:00
const params = {
recipient: this.worker.user.emailUser.email,
week: this.weekNumber,
2023-02-23 07:21:59 +00:00
year: this.date.getFullYear(),
workerId: this.worker.id,
state: 'SENDED'
2023-02-22 14:12:25 +00:00
};
2023-02-23 07:21:59 +00:00
this.$http.post(`WorkerTimeControls/weekly-hour-hecord-email`, params)
2023-03-08 11:06:20 +00:00
.then(() => {
this.getMailStates(this.date);
2023-02-23 07:21:59 +00:00
this.vnApp.showSuccess(this.$t('Email sended'));
});
}
2023-02-22 14:12:25 +00:00
getTime(timeString) {
const [hours, minutes, seconds] = timeString.split(':');
return [parseInt(hours), parseInt(minutes), parseInt(seconds)];
}
getMailStates(date) {
const params = {
month: date.getMonth() + 1,
year: date.getFullYear()
};
const query = `WorkerTimeControls/${this.$params.id}/getMailStates`;
this.$http.get(query, {params})
.then(res => {
this.workerTimeControlMails = res.data;
this.repaint();
});
}
formatWeek($element) {
const weekNumberHTML = $element.firstElementChild;
const weekNumberValue = weekNumberHTML.innerHTML;
if (!this.workerTimeControlMails) return;
const workerTimeControlMail = this.workerTimeControlMails.find(
workerTimeControlMail => workerTimeControlMail.week == weekNumberValue
);
if (!workerTimeControlMail) return;
const state = workerTimeControlMail.state;
if (state == 'CONFIRMED') {
weekNumberHTML.classList.remove('revise');
weekNumberHTML.classList.remove('sended');
weekNumberHTML.classList.add('confirmed');
weekNumberHTML.setAttribute('title', 'Conforme');
}
if (state == 'REVISE') {
weekNumberHTML.classList.remove('confirmed');
weekNumberHTML.classList.remove('sended');
weekNumberHTML.classList.add('revise');
weekNumberHTML.setAttribute('title', 'No conforme');
}
if (state == 'SENDED') {
weekNumberHTML.classList.add('sended');
weekNumberHTML.setAttribute('title', 'Pendiente');
}
}
repaint() {
let calendars = this.element.querySelectorAll('vn-calendar');
for (let calendar of calendars)
calendar.$ctrl.repaint();
}
2019-05-17 11:27:51 +00:00
}
2019-11-05 10:57:05 +00:00
Controller.$inject = ['$element', '$scope', 'vnWeekDays'];
2019-05-17 11:27:51 +00:00
ngModule.vnComponent('vnWorkerTimeControl', {
2019-05-17 11:27:51 +00:00
template: require('./index.html'),
2021-06-11 08:58:00 +00:00
controller: Controller,
bindings: {
worker: '<'
2023-07-14 09:51:15 +00:00
},
require: {
card: '^vnWorkerCard'
2021-06-11 08:58:00 +00:00
}
2019-05-17 11:27:51 +00:00
});