feat: enhance balance calculation to include total balance from all months and exclude sick days
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m57s
All checks were successful
Build and Push Docker Image / build (push) Successful in 9m57s
This commit is contained in:
@@ -1279,8 +1279,8 @@ async function updateStatistics(entries) {
|
||||
// Calculate previous month balance
|
||||
const previousBalance = await calculatePreviousBalance();
|
||||
|
||||
// Total balance = previous balance + current month balance
|
||||
const totalBalance = previousBalance + balance;
|
||||
// Total balance = all months from first entry up to today (independent of displayed month)
|
||||
const totalBalance = await calculateTotalBalance();
|
||||
|
||||
// Count actual work entries (excluding vacation/flextime/sickday, only up to today)
|
||||
const workEntriesCount = entries.filter(e => {
|
||||
@@ -1513,10 +1513,11 @@ async function addBridgeDaysAsVacation(days) {
|
||||
|
||||
/**
|
||||
* Calculate balance from all previous months (starting from first month with entries)
|
||||
* up to (but not including) the given month. Defaults to the currently displayed month.
|
||||
*/
|
||||
async function calculatePreviousBalance() {
|
||||
const currentYear = displayYear;
|
||||
const currentMonth = displayMonth;
|
||||
async function calculatePreviousBalance(upToYear, upToMonth) {
|
||||
const currentYear = (upToYear !== undefined) ? upToYear : displayYear;
|
||||
const currentMonth = (upToMonth !== undefined) ? upToMonth : displayMonth;
|
||||
|
||||
// Find the first month with any entries by checking all entries
|
||||
const allEntries = await fetchEntries();
|
||||
@@ -1576,6 +1577,13 @@ async function calculatePreviousBalance() {
|
||||
.map(e => e.date)
|
||||
);
|
||||
|
||||
// Count sick days to exclude from workdays
|
||||
const sickDays = new Set(
|
||||
entries
|
||||
.filter(e => e.entryType === 'sickday')
|
||||
.map(e => e.date)
|
||||
);
|
||||
|
||||
// Count flextime days (they are workdays with 0 hours worked)
|
||||
const flextimeDays = new Set(
|
||||
entries
|
||||
@@ -1599,8 +1607,8 @@ async function calculatePreviousBalance() {
|
||||
const dateISO = `${year}-${month}-${dayStr}`;
|
||||
|
||||
if (!isWeekendOrHoliday(dateObj)) {
|
||||
// Exclude vacation days from workdays count
|
||||
if (!vacationDays.has(dateISO)) {
|
||||
// Exclude vacation and sick days from workdays count
|
||||
if (!vacationDays.has(dateISO) && !sickDays.has(dateISO)) {
|
||||
workdaysPassed++;
|
||||
}
|
||||
} else if (flextimeDays.has(dateISO)) {
|
||||
@@ -1629,6 +1637,58 @@ async function calculatePreviousBalance() {
|
||||
return totalBalance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the total balance from first entry up to and including the displayed month.
|
||||
* For the current or future months the calculation is capped at today.
|
||||
*/
|
||||
async function calculateTotalBalance() {
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
|
||||
// End of the displayed month
|
||||
const displayedMonthEnd = new Date(displayYear, displayMonth + 1, 0);
|
||||
displayedMonthEnd.setHours(0, 0, 0, 0);
|
||||
|
||||
// Effective cut-off: end of displayed month, but never beyond today
|
||||
const effectiveCutoff = displayedMonthEnd < today ? displayedMonthEnd : today;
|
||||
const effectiveYear = effectiveCutoff.getFullYear();
|
||||
const effectiveMonth = effectiveCutoff.getMonth();
|
||||
|
||||
// All months before the effective month
|
||||
const previousBalance = await calculatePreviousBalance(effectiveYear, effectiveMonth);
|
||||
|
||||
// Add the effective month up to the effective cut-off date
|
||||
const firstDay = `${effectiveYear}-${String(effectiveMonth + 1).padStart(2, '0')}-01`;
|
||||
const lastDayNum = new Date(effectiveYear, effectiveMonth + 1, 0).getDate();
|
||||
const lastDayStr = `${effectiveYear}-${String(effectiveMonth + 1).padStart(2, '0')}-${String(lastDayNum).padStart(2, '0')}`;
|
||||
const entries = await fetchEntries(firstDay, lastDayStr);
|
||||
|
||||
const vacationDays = new Set(entries.filter(e => e.entryType === 'vacation').map(e => e.date));
|
||||
const sickDays = new Set(entries.filter(e => e.entryType === 'sickday').map(e => e.date));
|
||||
const flextimeDays = new Set(entries.filter(e => e.entryType === 'flextime').map(e => e.date));
|
||||
|
||||
let workdaysPassed = 0;
|
||||
for (let day = 1; day <= lastDayNum; day++) {
|
||||
const dateObj = new Date(effectiveYear, effectiveMonth, day);
|
||||
dateObj.setHours(0, 0, 0, 0);
|
||||
if (dateObj > effectiveCutoff) break;
|
||||
const dateISO = `${effectiveYear}-${String(effectiveMonth + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
|
||||
if (!isWeekendOrHoliday(dateObj)) {
|
||||
if (!vacationDays.has(dateISO) && !sickDays.has(dateISO)) workdaysPassed++;
|
||||
} else if (flextimeDays.has(dateISO)) {
|
||||
workdaysPassed++;
|
||||
}
|
||||
}
|
||||
|
||||
const targetHours = workdaysPassed * 8;
|
||||
const actualHours = entries.reduce((sum, entry) => sum + entry.netHours, 0);
|
||||
const monthBalance = actualHours - targetHours;
|
||||
|
||||
const total = previousBalance + monthBalance;
|
||||
console.log(`calculateTotalBalance: displayed=${displayYear}-${displayMonth + 1}, cutoff=${effectiveYear}-${effectiveMonth + 1}, previousBalance=${previousBalance.toFixed(1)}h, effectiveMonth=${monthBalance.toFixed(1)}h, total=${total.toFixed(1)}h`);
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open modal for adding/editing entry
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user