261 lines
6.8 KiB
JavaScript
261 lines
6.8 KiB
JavaScript
const polishMonths = {
|
||
styczeń: 1,
|
||
luty: 2,
|
||
marzec: 3,
|
||
kwiecień: 4,
|
||
maj: 5,
|
||
czerwiec: 6,
|
||
lipiec: 7,
|
||
sierpień: 8,
|
||
wrzesień: 9,
|
||
październik: 10,
|
||
listopad: 11,
|
||
grudzień: 12,
|
||
}
|
||
|
||
const months = [
|
||
'styczeń',
|
||
'luty',
|
||
'marzec',
|
||
'kwiecień',
|
||
'maj',
|
||
'czerwiec',
|
||
'lipiec',
|
||
'sierpień',
|
||
'wrzesień',
|
||
'październik',
|
||
'listopad',
|
||
'grudzień',
|
||
]
|
||
|
||
const daysOfWeek = ['Nd', 'Pn', 'Wt', 'Śr', 'Cz', 'Pt', 'So']
|
||
|
||
// function getLastThreeMonth(monthName) {
|
||
// const months = Object.keys(polishMonths) // ["styczeń", "luty", ..., "grudzień"]
|
||
// const index = months.indexOf(monthName)
|
||
// if (index === -1) return [] // jeśli nie znaleziono miesiąca
|
||
|
||
// return [months[(index - 2 + 12) % 12], months[(index - 1 + 12) % 12], months[index]]
|
||
// }
|
||
|
||
// function getLastThreeMonth(monthName) {
|
||
// const index = months.indexOf(monthName)
|
||
// if (index === -1) return [] // jeśli nie znaleziono miesiąca
|
||
|
||
// return [months[(index - 2 + 12) % 12], months[(index - 1 + 12) % 12], months[index]]
|
||
// }
|
||
function getLastMonths(startMonth, count) {
|
||
const result = []
|
||
for (let i = 0; i < count; i++) {
|
||
// Obliczamy numer miesiąca (1–12), uwzględniając cofanie się w roku
|
||
let month = ((startMonth - i - 1 + 12) % 12) + 1
|
||
result.push(month)
|
||
}
|
||
return result
|
||
}
|
||
|
||
function getLastThreeMonth(month) {
|
||
if (!month || typeof month !== 'number' || month < 1 || month > 12) {
|
||
return null
|
||
}
|
||
return [((month - 3 + 12) % 12) + 1, ((month - 2 + 12) % 12) + 1, month]
|
||
}
|
||
|
||
function getMonthName(month) {
|
||
if (!month || typeof month !== 'number' || month < 1 || month > 12) {
|
||
return null
|
||
}
|
||
return months[month - 1]
|
||
}
|
||
|
||
function getMonthNumber(monthName) {
|
||
const monthNum = polishMonths[monthName.toLowerCase()]
|
||
if (!monthNum) {
|
||
console.error('❌ Unknown month:', monthName)
|
||
return null
|
||
}
|
||
return String(monthNum).padStart(2, '0')
|
||
}
|
||
|
||
function getDayOfWeek(dateStr) {
|
||
const date = new Date(dateStr)
|
||
return daysOfWeek[date.getDay()]
|
||
}
|
||
|
||
function extractTimeFromDateString(isoString) {
|
||
if (!isoString || typeof isoString !== 'string') return ''
|
||
const date = new Date(isoString + 'Z')
|
||
if (isNaN(date.getTime())) return ''
|
||
return date.toTimeString().slice(0, 5) // 'HH:MM:SS'
|
||
}
|
||
|
||
function isValidWorkDay(day) {
|
||
if (!day || typeof day !== 'object') return false
|
||
if (!('dayOfWeek' in day) || !('isPublicHoliday' in day)) return false
|
||
return day.dayOfWeek !== 'So' && day.dayOfWeek !== 'Nd' && !day.isPublicHoliday
|
||
}
|
||
|
||
function calculateWorkedTime(entryTimes, exitTimes) {
|
||
if (
|
||
!entryTimes ||
|
||
!exitTimes ||
|
||
!Array.isArray(entryTimes) ||
|
||
!Array.isArray(exitTimes) ||
|
||
entryTimes.length === 0
|
||
) {
|
||
return 0
|
||
}
|
||
|
||
let totalWorkedMinutes = 0
|
||
for (let i = 0; i < entryTimes.length; i++) {
|
||
const entryTime = entryTimes[i]
|
||
// Use the corresponding exit time, or skip if it doesn't exist
|
||
const exitTime = exitTimes[i]
|
||
|
||
if (!entryTime || !exitTime || typeof entryTime !== 'string' || typeof exitTime !== 'string') {
|
||
continue
|
||
}
|
||
|
||
const [eh, em] = entryTime.split(':').map(Number)
|
||
const [xh, xm] = exitTime.split(':').map(Number)
|
||
|
||
if ([eh, em, xh, xm].some((v) => typeof v !== 'number' || isNaN(v))) {
|
||
continue
|
||
}
|
||
|
||
const start = eh * 60 + em
|
||
const end = xh * 60 + xm
|
||
totalWorkedMinutes += end - start
|
||
}
|
||
|
||
const worked = totalWorkedMinutes / 60
|
||
return parseFloat(worked.toFixed(9))
|
||
}
|
||
|
||
function floatHoursToHHMM(decimalHours) {
|
||
if (typeof decimalHours !== 'number' || isNaN(decimalHours)) return ''
|
||
// if (decimalHours === 0) return ''
|
||
const negative = decimalHours < 0
|
||
const abs = Math.abs(decimalHours)
|
||
|
||
const m_total = Math.round(abs * 60)
|
||
const h = Math.floor(m_total / 60)
|
||
const m = m_total % 60
|
||
|
||
const hh = String(h).padStart(2, '0')
|
||
const mm = String(m).padStart(2, '0')
|
||
|
||
return `${negative ? '-' : ''}${hh}:${mm}`
|
||
}
|
||
|
||
function calculateDay(day) {
|
||
// Create a mutable copy of exit times to potentially add the current time.
|
||
// const exitTimes = [...day.exitTime]
|
||
|
||
// If there's one more entry than exits, it means the user is currently clocked in.
|
||
if (day.entryTime.length > 0 && day.entryTime.length === day.exitTime.length + 1) {
|
||
const now = new Date()
|
||
const hh = String(now.getHours()).padStart(2, '0')
|
||
const mm = String(now.getMinutes()).padStart(2, '0')
|
||
const ss = String(now.getSeconds()).padStart(2, '0')
|
||
// Add the current time as the "exit" for the last entry.
|
||
day.exitTime.push(`${hh}:${mm}:${ss}`)
|
||
}
|
||
|
||
if (day.entryTime.length === 0) {
|
||
day.workedHours = 0
|
||
} else {
|
||
// The -0.25 for a 15-minute break seems to be a business rule.
|
||
// It should probably only be subtracted once per day, not per interval.
|
||
// Let's subtract it from the total.
|
||
let totalHours = calculateWorkedTime(day.entryTime, day.exitTime)
|
||
if (totalHours > 0) {
|
||
totalHours -= 0.25
|
||
}
|
||
day.workedHours = parseFloat(totalHours.toFixed(9))
|
||
}
|
||
|
||
if (isValidWorkDay(day) && !day.isHolidayLeave && !day.isSickLeave) {
|
||
day.overtime = day.workedHours - 8
|
||
} else {
|
||
day.overtime = day.workedHours
|
||
}
|
||
day.overtime = parseFloat(day.overtime.toFixed(9))
|
||
|
||
let sumHours = day.workedHours
|
||
if (day.isHolidayLeave) {
|
||
sumHours += 8
|
||
}
|
||
if (day.isSickLeave) {
|
||
sumHours += 6.4
|
||
}
|
||
|
||
return parseFloat(sumHours.toFixed(9))
|
||
}
|
||
|
||
function calculateMonth(days) {
|
||
let accumulated = 0
|
||
let workingDaysCount = 0
|
||
let balance = 0
|
||
|
||
for (let i = 0; i < days.length; i++) {
|
||
const day = days[i]
|
||
const workedHours = calculateDay(day)
|
||
|
||
accumulated += workedHours
|
||
if (isValidWorkDay(day)) {
|
||
workingDaysCount++
|
||
}
|
||
|
||
balance = parseFloat((accumulated - workingDaysCount * 8).toFixed(9))
|
||
day.accumulatedHours = parseFloat(accumulated.toFixed(9))
|
||
day.balanceHours = balance
|
||
}
|
||
}
|
||
|
||
function calculateMonthFromDay(startDay, days) {
|
||
let startIndex = days.indexOf(startDay)
|
||
if (startIndex === -1) return
|
||
|
||
let accumulated = 0
|
||
let workingDaysCount = 0
|
||
let balance = 0
|
||
|
||
if (startIndex > 0) {
|
||
const previousDay = days[startIndex - 1]
|
||
accumulated = previousDay.accumulatedHours || 0
|
||
balance = previousDay.balanceHours || 0
|
||
workingDaysCount = days.slice(0, startIndex).filter(isValidWorkDay).length
|
||
}
|
||
|
||
for (let i = startIndex; i < days.length; i++) {
|
||
const day = days[i]
|
||
const workedHours = calculateDay(day)
|
||
|
||
accumulated += workedHours
|
||
if (isValidWorkDay(day)) {
|
||
workingDaysCount++
|
||
}
|
||
|
||
balance = parseFloat((accumulated - workingDaysCount * 8).toFixed(9))
|
||
day.accumulatedHours = parseFloat(accumulated.toFixed(9))
|
||
day.balanceHours = balance
|
||
}
|
||
}
|
||
|
||
export default {
|
||
getDayOfWeek,
|
||
extractTimeFromDateString,
|
||
isValidWorkDay,
|
||
calculateWorkedTime,
|
||
floatHoursToHHMM,
|
||
calculateDay,
|
||
calculateMonth,
|
||
calculateMonthFromDay,
|
||
getLastThreeMonth,
|
||
getLastMonths,
|
||
getMonthNumber,
|
||
getMonthName,
|
||
daysOfWeek,
|
||
}
|