Files
ROLAC/docs/superpowers/specs/2026-06-24-offering-session-attendance-design.md
2026-06-24 11:35:34 -07:00

4.1 KiB
Raw Permalink Blame History

Offering Session — 顯示與修改主日參加人數

Date: 2026-06-24

Goal

在 finance/offering-session 的 Recent Sessions 表格中,每筆 session 顯示該日的「主日參加人數」總數,並新增一個 Action 可修改該日的參加人數。

Confirmed Decisions

  1. 資料來源 — 沿用既有 MealAttendance。主日參加人數 = 該日 AdultCount + YouthCount + KidCount。修改 Action 改的是同一筆 MealAttendance 紀錄。
  2. 顯示 — 後端 joinDTO 加 nullable 欄位;該日無紀錄時顯示
  3. 編輯介面 — Kendo Dialog 分別編輯三個分類(成人/青年/兒童),總數即時計算。
  4. Action 擺放 — 依既有慣例,Date 欄位可點擊觸發 View;View 與「修改主日人數」都進右鍵 context menu(沿用 expense-categories 範式)。

Key Constraint

AttendanceHub.SetCount 只作用在 ServiceDay(本週日),無法改任意日期。因此編輯過去某場 session 的日期,必須走新的 REST 端點,不可用 SignalR。

Backend Changes

1. DTO

API/ROLAC.API/DTOs/Giving/OfferingSessionListItemDto.cs

  • 新增 public int? SundayAttendanceCount { get; set; }nullable:該日無 attendance row 為 null)。

2. OfferingSessionService.GetPaged

  • 取得當頁 sessions 後,以這些 SessionDate 一次查 MealAttendance(單一 set-based 查詢,依日期分組求和),把總數填入各 DTO 的 SundayAttendanceCount;無紀錄者留 null。
  • 不可對每筆 session 各發一次查詢(避免 N+1)。

3. IMealAttendanceService + MealAttendanceService

  • 新增 Task<AttendanceCountsDto> SetCountsAsync(DateOnly date, int adult, int youth, int kid)
  • 沿用既有 clamp-at-zero 語意,一次寫三欄並回傳 AttendanceCountsDto;該日無 row 則建立(沿用 GetOrCreateAsync 的建立邏輯)。

4. MealAttendanceController

  • 新增 PUT /api/meal-attendance/{date}[Authorize](與既有 GetRange 一致),body { adult, youth, kid } → 回傳 AttendanceCountsDto
  • Optionalplan 階段決定):若 date == ServiceDay,順手透過 AttendanceHub 廣播 ReceiveCounts,讓正在跑的即時計數器同步。預設先不做,避免增加耦合。

Frontend Changes

1. Model

APP/.../giving/models/giving.model.ts

  • OfferingSessionListItemDtosundayAttendanceCount?: number | null

2. Attendance API service

APP/.../meal-attendance/services/meal-attendance-api.service.ts

  • 新增 setCounts(date: string, counts: { adult: number; youth: number; kid: number }): Observable<AttendanceCounts> → 呼叫 PUT /api/meal-attendance/{date}

3. offering-session-page component

APP/.../giving/pages/offering-session-page/offering-session-page.component.{ts,html}

  • imports 加 ContextMenuModuleDialogsModuleInputsModuleNumericTextBox)。
  • Recent Sessions grid
    • 在 "Lines" 後新增欄 Attendance · 主日人數,顯示 s.sundayAttendanceCount ?? '—'
    • 移除原本獨立的 "View" 按鈕欄;改為 (cellClick)event.type === 'contextmenu' → 開 context menu;否則 openView。Date 欄加可點擊樣式(clickable-rows)。
    • kendo-contextmenuitemsView修改主日人數
  • 修改主日人數 Dialog
    • 開啟時以 mealAttendanceApi.getRange(date, date) 取該日 breakdown 預填(無紀錄則三欄為 0)。
    • 三個 kendo-numerictextbox(成人/青年/兒童,min 0),即時顯示總數。
    • Save → setCounts(date, …);成功後就地把該列 sundayAttendanceCount 更新為三者之和。Cancel 關閉。

Permissions

PUT 端點用 [Authorize],與既有 GetRange 一致。

Out of Scope

  • Recent Sessions grid 目前尚無手機卡片版;本次只新增欄位與 action,不一併重構 mobile 版面(可另開 task)。

Testing

  • BackendSetCountsAsync 對負值 clamp 為 0、該日無 row 時建立;GetPaged 正確帶入 attendance 總數且無 N+1。
  • Frontenddialog 總數計算(成人+青年+兒童)與存檔後就地更新該列。(前端測試環境較脆弱,採最小範圍 inline-template 測試。)