feat: add yearly summary page with navigation and formatting improvements
All checks were successful
Publish Container / publish (push) Successful in 3m17s
All checks were successful
Publish Container / publish (push) Successful in 3m17s
This commit is contained in:
parent
0991128b30
commit
0d003903cf
12 changed files with 406 additions and 70 deletions
|
|
@ -180,36 +180,20 @@ public sealed class CouchbaseLiteWorkDayService : IWorkDayService
|
|||
public async Task<MonthlySummaryModel> GetMonthlySummaryAsync(int year, int month, bool includePreview, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var from = new DateOnly(year, month, 1);
|
||||
var to = from.AddMonths(1).AddDays(-1);
|
||||
var days = await GetRangeAsync(from, to, cancellationToken);
|
||||
return await BuildMonthlySummaryAsync(from, includePreview, cancellationToken);
|
||||
}
|
||||
|
||||
var includedUnits = days
|
||||
.SelectMany(day => day.WorkUnits.Where(unit => includePreview || !unit.IsPreview).Select(unit => new { day.Date, Unit = unit }))
|
||||
.ToList();
|
||||
public async Task<IReadOnlyList<MonthlySummaryModel>> GetYearlySummaryAsync(int year, bool includePreview, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var summaries = new List<MonthlySummaryModel>(12);
|
||||
|
||||
var previewUnits = days
|
||||
.SelectMany(day => day.WorkUnits.Where(unit => unit.IsPreview).Select(unit => new { day.Date, Unit = unit }))
|
||||
.ToList();
|
||||
|
||||
return new MonthlySummaryModel
|
||||
for (var month = 1; month <= 12; month++)
|
||||
{
|
||||
Year = year,
|
||||
Month = month,
|
||||
TotalWorkedHours = includedUnits.Sum(item => item.Unit.ManualWorkedHours),
|
||||
TotalPreviewWorkedHours = previewUnits.Sum(item => item.Unit.ManualWorkedHours),
|
||||
CountedWorkUnits = includedUnits.Count,
|
||||
PreviewWorkUnits = previewUnits.Count,
|
||||
OfficeDays = includedUnits.Where(item => item.Unit.Location == WorkUnitLocation.Office).Select(item => item.Date).Distinct().Count(),
|
||||
HomeDays = includedUnits.Where(item => item.Unit.Location == WorkUnitLocation.Home).Select(item => item.Date).Distinct().Count(),
|
||||
HolidayDays = CountDaysWithEvent(days, CalendarEventType.Holiday),
|
||||
SickDays = CountDaysWithEvent(days, CalendarEventType.Illness),
|
||||
DaysOff = CountDaysWithEvent(days, CalendarEventType.DayOff),
|
||||
ClosureDays = CountDaysWithEvent(days, CalendarEventType.Closure),
|
||||
TotalHoursOff = days.Sum(day => GetHoursOff(day, includePreview)),
|
||||
TotalGrossIncome = includedUnits.Sum(item => item.Unit.GrossIncome),
|
||||
TotalNetIncome = includedUnits.Sum(item => item.Unit.NetIncome),
|
||||
TotalWorkingDays = includedUnits.Select(item => item.Date).Distinct().Count()
|
||||
};
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
summaries.Add(await BuildMonthlySummaryAsync(new DateOnly(year, month, 1), includePreview, cancellationToken));
|
||||
}
|
||||
|
||||
return summaries;
|
||||
}
|
||||
|
||||
public async Task<MonthlyTimesheetModel> GetMonthlyTimesheetAsync(int year, int month, bool includePreview, CancellationToken cancellationToken = default)
|
||||
|
|
@ -480,6 +464,40 @@ public sealed class CouchbaseLiteWorkDayService : IWorkDayService
|
|||
return days.Count(day => day.CalendarEvents.Any(calendarEvent => calendarEvent.EventType == eventType));
|
||||
}
|
||||
|
||||
private async Task<MonthlySummaryModel> BuildMonthlySummaryAsync(DateOnly from, bool includePreview, CancellationToken cancellationToken)
|
||||
{
|
||||
var to = from.AddMonths(1).AddDays(-1);
|
||||
var days = await GetRangeAsync(from, to, cancellationToken);
|
||||
|
||||
var includedUnits = days
|
||||
.SelectMany(day => day.WorkUnits.Where(unit => includePreview || !unit.IsPreview).Select(unit => new { day.Date, Unit = unit }))
|
||||
.ToList();
|
||||
|
||||
var previewUnits = days
|
||||
.SelectMany(day => day.WorkUnits.Where(unit => unit.IsPreview).Select(unit => new { day.Date, Unit = unit }))
|
||||
.ToList();
|
||||
|
||||
return new MonthlySummaryModel
|
||||
{
|
||||
Year = from.Year,
|
||||
Month = from.Month,
|
||||
TotalWorkedHours = includedUnits.Sum(item => item.Unit.ManualWorkedHours),
|
||||
TotalPreviewWorkedHours = previewUnits.Sum(item => item.Unit.ManualWorkedHours),
|
||||
CountedWorkUnits = includedUnits.Count,
|
||||
PreviewWorkUnits = previewUnits.Count,
|
||||
OfficeDays = includedUnits.Where(item => item.Unit.Location == WorkUnitLocation.Office).Select(item => item.Date).Distinct().Count(),
|
||||
HomeDays = includedUnits.Where(item => item.Unit.Location == WorkUnitLocation.Home).Select(item => item.Date).Distinct().Count(),
|
||||
HolidayDays = CountDaysWithEvent(days, CalendarEventType.Holiday),
|
||||
SickDays = CountDaysWithEvent(days, CalendarEventType.Illness),
|
||||
DaysOff = CountDaysWithEvent(days, CalendarEventType.DayOff),
|
||||
ClosureDays = CountDaysWithEvent(days, CalendarEventType.Closure),
|
||||
TotalHoursOff = days.Sum(day => GetHoursOff(day, includePreview)),
|
||||
TotalGrossIncome = includedUnits.Sum(item => item.Unit.GrossIncome),
|
||||
TotalNetIncome = includedUnits.Sum(item => item.Unit.NetIncome),
|
||||
TotalWorkingDays = includedUnits.Select(item => item.Date).Distinct().Count()
|
||||
};
|
||||
}
|
||||
|
||||
private static MonthlyTimesheetDaySummary CreateTimesheetDaySummary(WorkDayDocument? day, DateOnly date, bool includePreview, decimal defaultStandardHours)
|
||||
{
|
||||
var includedUnits = day?.WorkUnits.Where(unit => includePreview || !unit.IsPreview).ToList() ?? [];
|
||||
|
|
@ -585,9 +603,7 @@ public sealed class CouchbaseLiteWorkDayService : IWorkDayService
|
|||
|
||||
private static string FormatCompactHours(decimal value)
|
||||
{
|
||||
return value == decimal.Truncate(value)
|
||||
? value.ToString("0")
|
||||
: value.ToString("0.##", System.Globalization.CultureInfo.InvariantCulture);
|
||||
return Formatting.DurationFormatter.FormatHours(value);
|
||||
}
|
||||
|
||||
private static decimal GetNightHours(WorkUnitDocument unit)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ public interface IWorkDayService
|
|||
|
||||
Task<MonthlySummaryModel> GetMonthlySummaryAsync(int year, int month, bool includePreview, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<IReadOnlyList<MonthlySummaryModel>> GetYearlySummaryAsync(int year, bool includePreview, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<MonthlyTimesheetModel> GetMonthlyTimesheetAsync(int year, int month, bool includePreview, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<int> GenerateMonthlyPreviewWorkUnitsAsync(int year, int month, CancellationToken cancellationToken = default);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue