import ngModule from '../module'; import Section from 'salix/components/section'; import './style.scss'; import UserError from 'core/lib/user-error'; class Controller extends Section { constructor($element, $, vnWeekDays) { super($element, $); this.weekDays = []; this.weekdayNames = vnWeekDays.locales; this.entryDirections = [ {code: 'in', description: this.$t('In')}, {code: 'middle', description: this.$t('Intermediate')}, {code: 'out', description: this.$t('Out')} ]; } $postLink() { const timestamp = this.$params.timestamp; let initialDate = Date.vnNew(); if (timestamp) { initialDate = new Date(timestamp * 1000); this.$.calendar.defaultDate = initialDate; } this.date = initialDate; this.getMailStates(this.date); } get isHr() { return this.aclService.hasAny(['hr']); } get isHimSelf() { const userId = window.localStorage.currentUserWorkerId; return userId == this.$params.id; } get worker() { return this._worker; } get weekNumber() { return this.getWeekNumber(this.date); } set weekNumber(value) { this._weekNumber = value; } set worker(value) { this._worker = value; } /** * The current selected date */ get date() { return this._date; } set date(value) { this._date = value; value.setHours(0, 0, 0, 0); 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()); ended.setHours(23, 59, 59, 59); ended.setDate(ended.getDate() + 6); this.ended = ended; this.weekDays = []; let dayIndex = new Date(started.getTime()); while (dayIndex < ended) { this.weekDays.push({ dated: new Date(dayIndex.getTime()) }); dayIndex.setDate(dayIndex.getDate() + 1); } this.fetchHours(); this.getWeekData(); } getWeekData() { const filter = { where: { workerFk: this.$params.id, year: this._date.getFullYear(), week: this.getWeekNumber(this._date) } }; this.$http.get('WorkerTimeControlMails', {filter}) .then(res => { const workerTimeControlMail = res.data; if (!workerTimeControlMail.length) { this.state = null; return; } this.state = workerTimeControlMail[0].state; this.reason = workerTimeControlMail[0].reason; }); } /** * 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; } } fetchHours() { const params = {workerFk: this.$params.id}; const filter = { where: {and: [ {timed: {gte: this.started}}, {timed: {lte: this.ended}} ]} }; this.$.model.applyFilter(filter, params).then(() => { this.getWorkedHours(this.started, this.ended); this.getAbsences(); }); } hasEvents(day) { return day >= this.started && day < this.ended; } getAbsences() { const fullYear = this.started.getFullYear(); let params = { workerFk: this.$params.id, businessFk: null, year: fullYear }; return this.$http.get(`Calendars/absences`, {params}) .then(res => this.onData(res.data)); } onData(data) { const events = {}; const addEvent = (day, event) => { 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]; }); } 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; }); } getFinishTime() { if (!this.weekDays) return; let today = Date.vnNew(); today.setHours(0, 0, 0, 0); let todayInWeek = this.weekDays.find(day => day.dated.getTime() === today.getTime()); if (todayInWeek && todayInWeek.hours && todayInWeek.hours.length) { const remainingTime = todayInWeek.workedHours ? ((todayInWeek.expectedHours - todayInWeek.workedHours) * 1000) : null; const lastKnownEntry = todayInWeek.hours[todayInWeek.hours.length - 1]; const lastKnownTime = new Date(lastKnownEntry.timed).getTime(); const finishTimeStamp = lastKnownTime && remainingTime ? lastKnownTime + remainingTime : null; if (finishTimeStamp) { let finishDate = new Date(finishTimeStamp); let hour = finishDate.getHours(); let minute = finishDate.getMinutes(); if (hour < 10) hour = `0${hour}`; if (minute < 10) minute = `0${minute}`; return `${hour}:${minute} h.`; } } } set weekTotalHours(totalHours) { this._weekTotalHours = this.formatHours(totalHours); } get weekTotalHours() { return this._weekTotalHours; } formatHours(timestamp = 0) { let hour = Math.floor(timestamp / 3600); let min = Math.floor(timestamp / 60 - 60 * hour); 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); this.newTimeEntry = { workerFk: this.$params.id, timed: timed }; this.selectedWeekday = weekday; this.$.addTimeDialog.show(); } addTime() { 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()); } catch (e) { this.vnApp.showError(this.$t(e.message)); return false; } return true; } showDeleteDialog($event, hour) { $event.preventDefault(); this.timeEntryToDelete = hour; this.$.deleteEntryDialog.show(); } deleteTimeEntry() { const entryId = this.timeEntryToDelete.id; this.$http.post(`WorkerTimeControls/${entryId}/deleteTimeEntry`).then(() => { this.fetchHours(); this.vnApp.showSuccess(this.$t('Entry removed')); }); } edit($event, hour) { if ($event.defaultPrevented) return; this.selectedRow = hour; this.$.editEntry.show($event); } 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() { const params = { workerId: this.worker.id, year: this.date.getFullYear(), week: this.weekNumber, state: 'CONFIRMED' }; const query = `WorkerTimeControls/updateWorkerTimeControlMail`; this.$http.post(query, params).then(() => { this.getMailStates(this.date); this.getWeekData(); this.vnApp.showSuccess(this.$t('Data saved!')); }); } isUnsatisfied() { if (!this.reason) throw new UserError(`You must indicate a reason`); const params = { workerId: this.worker.id, year: this.date.getFullYear(), week: this.weekNumber, state: 'REVISE', reason: this.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(); } save() { 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()); } catch (e) { this.vnApp.showError(this.$t(e.message)); } } resendEmail() { const timestamp = this.date.getTime() / 1000; const url = `${window.location.origin}/#!/worker/${this.worker.id}/time-control?timestamp=${timestamp}`; const params = { recipient: this.worker.user.emailUser.email, week: this.weekNumber, year: this.date.getFullYear(), url: url, }; this.$http.post(`WorkerTimeControls/weekly-hour-hecord-email`, params) .then(() => { this.vnApp.showSuccess(this.$t('Email sended')); }); } 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(); } } Controller.$inject = ['$element', '$scope', 'vnWeekDays']; ngModule.vnComponent('vnWorkerTimeControl', { template: require('./index.html'), controller: Controller, bindings: { worker: '<' } });