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
|
// Calculate previous month balance
|
||||||
const previousBalance = await calculatePreviousBalance();
|
const previousBalance = await calculatePreviousBalance();
|
||||||
|
|
||||||
// Total balance = previous balance + current month balance
|
// Total balance = all months from first entry up to today (independent of displayed month)
|
||||||
const totalBalance = previousBalance + balance;
|
const totalBalance = await calculateTotalBalance();
|
||||||
|
|
||||||
// Count actual work entries (excluding vacation/flextime/sickday, only up to today)
|
// Count actual work entries (excluding vacation/flextime/sickday, only up to today)
|
||||||
const workEntriesCount = entries.filter(e => {
|
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)
|
* 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() {
|
async function calculatePreviousBalance(upToYear, upToMonth) {
|
||||||
const currentYear = displayYear;
|
const currentYear = (upToYear !== undefined) ? upToYear : displayYear;
|
||||||
const currentMonth = displayMonth;
|
const currentMonth = (upToMonth !== undefined) ? upToMonth : displayMonth;
|
||||||
|
|
||||||
// Find the first month with any entries by checking all entries
|
// Find the first month with any entries by checking all entries
|
||||||
const allEntries = await fetchEntries();
|
const allEntries = await fetchEntries();
|
||||||
@@ -1576,6 +1577,13 @@ async function calculatePreviousBalance() {
|
|||||||
.map(e => e.date)
|
.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)
|
// Count flextime days (they are workdays with 0 hours worked)
|
||||||
const flextimeDays = new Set(
|
const flextimeDays = new Set(
|
||||||
entries
|
entries
|
||||||
@@ -1599,8 +1607,8 @@ async function calculatePreviousBalance() {
|
|||||||
const dateISO = `${year}-${month}-${dayStr}`;
|
const dateISO = `${year}-${month}-${dayStr}`;
|
||||||
|
|
||||||
if (!isWeekendOrHoliday(dateObj)) {
|
if (!isWeekendOrHoliday(dateObj)) {
|
||||||
// Exclude vacation days from workdays count
|
// Exclude vacation and sick days from workdays count
|
||||||
if (!vacationDays.has(dateISO)) {
|
if (!vacationDays.has(dateISO) && !sickDays.has(dateISO)) {
|
||||||
workdaysPassed++;
|
workdaysPassed++;
|
||||||
}
|
}
|
||||||
} else if (flextimeDays.has(dateISO)) {
|
} else if (flextimeDays.has(dateISO)) {
|
||||||
@@ -1629,6 +1637,58 @@ async function calculatePreviousBalance() {
|
|||||||
return totalBalance;
|
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
|
* Open modal for adding/editing entry
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user