Commit Graph

259 Commits

Author SHA1 Message Date
Chris Chen caed5091f0 Enhance offering session 2026-05-30 00:15:10 -07:00
Chris Chen 769597d769 refactor finance. 2026-05-29 23:56:29 -07:00
Chris Chen 241870fe48 docs: align plan test command with project (ng test headless)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 22:29:19 -07:00
Chris Chen e817801e14 docs: record dropdown bilingual display convention
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 22:27:06 -07:00
Chris Chen aef5454202 feat(i18n): bilingual language dropdown on member form dialog
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 22:27:03 -07:00
Chris Chen 9a94e3b09e feat(i18n): bilingual ministry/category/status dropdowns on expense pages
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 22:27:00 -07:00
Chris Chen fba0b63214 feat(i18n): bilingual language + roles selectors in user dialogs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 22:13:41 -07:00
Chris Chen e5296e79dc feat(i18n): bilingual gender/status dropdowns on member form + members page 2026-05-29 22:11:39 -07:00
Chris Chen 61e34d343a feat(i18n): bilingual category + method dropdowns on givings page 2026-05-29 22:09:19 -07:00
Chris Chen 126e640731 feat(i18n): bilingual Type/Method dropdowns + line echo on offering session
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 22:07:57 -07:00
Chris Chen 4e15e9f630 feat(i18n): compute bilingual label on giving/ministry/expense-category lookups 2026-05-29 22:06:09 -07:00
Chris Chen 4bee06addb feat(i18n): add central bilingual option lists for enum dropdowns 2026-05-29 22:04:18 -07:00
Chris Chen a99755a5db feat(i18n): add bilingual() display helper 2026-05-29 22:02:50 -07:00
Chris Chen fef3b76a31 docs: implementation plan for bilingual dropdown options
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 21:56:22 -07:00
Chris Chen e37aade69f docs: spec for bilingual (English/Chinese) dropdown options
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 21:50:31 -07:00
Chris Chen fe50ea3d30 WIP 2026-05-29 20:54:08 -07:00
Chris Chen 95fa37ebdf fix(expense): open category read to all authed users; statement lookups via FirstOrDefaultAsync
Final-review findings:
- ExpenseCategoriesController was finance-only at the class level, but the member
  self-service reimbursement form reads the category list to populate its dropdown,
  so members got 403 and could not submit. Open GET to any authenticated user;
  keep group/subcategory writes finance-only (mirrors MinistriesController).
  Verified live with a member-role account: reads 200, writes 403, self-submit 200.
- MonthlyStatementService Update/Finalize now use FirstOrDefaultAsync for
  convention consistency with the rest of the service layer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 19:14:18 -07:00
Chris Chen e1f99158aa fix(expense): resolve current user id from 'sub' JWT claim
Live verification revealed the JWT carries the user id in the 'sub' claim
(NameClaimType=sub, MapInboundClaims=false), so ClaimTypes.NameIdentifier is
null at runtime. This caused ExpensesController.GetMine/GetById to throw
NullReferenceException (500) on the '!.Value', and made the services fall back
to 'system' — silently defeating the self-ownership guard. Resolve via
NameIdentifier (unit tests) then 'sub' (real tokens). Adds a regression test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 19:08:21 -07:00
Chris Chen 95008788f3 feat(expense): wire routes + sidebar nav for expense pages
Also fix kendo-grid [total] binding in expenses-page template by
switching to GridDataResult object form ({ data, total }) on [data].

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:59:25 -07:00
Chris Chen f5ff03260b feat(expense): add monthly reconciliation statement page
Implements Task 16 — MonthlyStatementPageComponent with Kendo Grid list
(year filter), create/edit dialog (server-computed totals preview), and
finalize action that locks the statement.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:56:14 -07:00
Chris Chen aa77f2051a feat(expense): add finance expenses overview + review page 2026-05-29 18:53:39 -07:00
Chris Chen 4704d33b4a fix(expense): authenticated receipt download + correct delete confirm
The receipt <a href target=_blank> was an unauthenticated browser navigation
that the API's [Authorize] rejects with 401. Replace with a HttpClient blob
download (downloadReceipt) so the auth interceptor attaches the JWT, opened
via an object URL. Also fix the delete button: confirm() must run inside the
component method (matching givings-page), not as a template expression where
confirm is not a component member.
2026-05-29 18:51:04 -07:00
Chris Chen 18b9707e44 feat(expense): add member self-service My Reimbursements page
Standalone Angular component (Kendo Grid + ExpenseFormDialog) that lets
any logged-in user list, create, submit, and delete their own draft
reimbursements, with optional receipt upload.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:48:42 -07:00
Chris Chen 1bb9da16d4 feat(expense): add reusable expense form dialog with category cascade
Standalone ExpenseFormDialogComponent with Ministry → Category Group → SubCategory
cascade, vendor/reimbursement modes, optional member picker (MemberApiService
search-as-you-type), and receipt file input. Emits CreateExpenseRequest + File.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:46:34 -07:00
Chris Chen 3188064335 feat(expense): add expense categories management page 2026-05-29 18:43:19 -07:00
Chris Chen 04b05617b8 feat(expense): add frontend models + API services
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:40:22 -07:00
Chris Chen 9933c180b7 feat(expense): add controllers + register services
Adds ExpenseCategoriesController, ExpensesController, MonthlyStatementsController
and registers IExpenseCategoryService, IExpenseService, IMonthlyStatementService in DI.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:37:25 -07:00
Chris Chen 86d9879a6d feat(expense): add MonthlyStatementService with server-side recompute + tests
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:34:39 -07:00
Chris Chen d9289008f6 feat(expense): add ExpenseService with state machine + receipt storage + tests
TDD: wrote 8 tests first (red), then implemented IExpenseService + ExpenseService
covering CRUD, Draft→PendingApproval→Approved→Paid state machine, soft-delete,
per-owner access guards, and receipt blob round-trip via IFileStorage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:28:38 -07:00
Chris Chen 015f689d9b feat(expense): add ExpenseCategoryService + tests
TDD cycle: wrote 3 xUnit tests first (red), then implemented
IExpenseCategoryService + ExpenseCategoryService (green).
2026-05-29 18:24:07 -07:00
Chris Chen 15cdfe6f92 feat(expense): add expense, category, and monthly-statement DTOs 2026-05-29 18:21:52 -07:00
Chris Chen e7bf07c2ad feat(storage): add IFileStorage + local-disk implementation
Adds IFileStorage abstraction and LocalDiskFileStorage for receipt file storage with path-traversal protection, and registers it in DI. Includes 3 TDD-verified xUnit tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:18:28 -07:00
Chris Chen ac65c68e18 feat(expense): add AddExpenseModule EF migration
Creates Ministries, ExpenseCategoryGroups, ExpenseSubCategories,
Expenses (with filtered Status index, MinistryId/ExpenseDate indexes,
Restrict FKs + SetNull on Member), and MonthlyStatements (unique
Year+Month index) tables. No existing tables modified.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:15:16 -07:00
Chris Chen cf929557fe feat(expense): add Expense + MonthlyStatement entities and EF config 2026-05-29 18:11:56 -07:00
Chris Chen cc58d06723 docs(expense): correct subcategory seed count to 39 (matches DB_SCHEMA §8) 2026-05-29 18:10:42 -07:00
Chris Chen b3eb9d297a feat(expense): add expense category entities + seed (11 groups / 38 subs)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 18:08:12 -07:00
Chris Chen f6f06d841c feat(ministry): add Ministry entity, seed (10), and read endpoint 2026-05-29 18:03:28 -07:00
Chris Chen 50e518095e docs(expense): add expense tracking implementation plan
18 TDD tasks: Ministry prerequisite (entity/seed/endpoint), expense category
entities + seed, Expense + MonthlyStatement entities, EF migration,
IFileStorage + local-disk impl, DTOs, three services with tests, controllers
with auth split, and four Angular pages + nav/routes wiring.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 17:54:13 -07:00
Chris Chen fdd0d7c8e1 docs(expense): add expense tracking & reimbursement design spec
Covers all five PLANNING §3.6d items: category seed (11 groups/38 subs),
vendor direct payment, staff reimbursement with receipt upload + self-service
submission, finance approval workflow (Draft→PendingApproval→Approved→Paid),
and monthly reconciliation statement. Per DB_SCHEMA §8.

Key decisions: IFileStorage abstraction + local-disk impl for receipts
(Azure Blob deferred), member self-submission alongside finance entry,
soft-delete Expense, cash-basis (Paid-only) monthly expense totals.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 17:23:21 -07:00
Chris Chen 0639d1fe83 WIP 2026-05-28 22:29:13 -07:00
Chris Chen a2d394029a fix(giving): render Finance nav section in UserPortal sidebar
Task 11 added the finance nav to user-navbar.component, but the active
sidebar is rendered inline by UserPortalComponent (app-user-navbar is
not mounted). Added the role-gated Finance section (Offering Entry /
Givings / Giving Types) to UserPortalComponent, matching its
Administration pattern. Verified at runtime: section renders for
super_admin and links load the giving pages.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-28 18:22:50 -07:00
Chris Chen 5f8676f962 Merge feature/giving-module: manual giving/donation tracking module
Giving-category config, single giving entry, and keyboard-first Sunday
offering batch entry (OfferingSession) with server-side reconciliation,
lock-after-submit, and finance reopen/replace. 53 backend tests; runtime
E2E verified against dev DB.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-28 18:10:40 -07:00
Chris Chen 48885dba83 fix(giving): reset in-buffer line-edit index on reopen/cancel/submit 2026-05-28 17:44:43 -07:00
Chris Chen af21e50d9f feat(giving): add reopen-and-edit flow + recent sessions list to offering page 2026-05-28 17:41:19 -07:00
Chris Chen a573179714 feat(giving): match giver member name in single-giving search (spec §4.2)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 17:24:47 -07:00
Chris Chen 66640d1fd0 fix(giving): keep giver name visible when editing a buffered offering line 2026-05-28 17:18:40 -07:00
Chris Chen 001db35cef feat(giving): keyboard-first Sunday offering batch entry page + routes
- Add MemberQuickAddDialogComponent for fast in-session member creation
- Add OfferingSessionPageComponent: client-side buffer, reconcile totals, date-conflict check, submit to API
- Wire finance/giving-categories, finance/givings, finance/offering-session routes (RoleGuard: finance + super_admin)
- Fix givings-page: replace [total] + data[] with GridDataResult for Kendo v20 server-side paging

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 17:14:56 -07:00
Chris Chen 81a0b5a038 feat(giving): single giving entry page 2026-05-28 17:10:07 -07:00
Chris Chen 7260e5c115 feat(giving): giving categories management page
Add GivingCategoriesPageComponent — standalone Angular 18 component with Kendo Grid (list/deactivate) and Kendo Dialog (add/edit form) for managing giving types.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 17:04:55 -07:00
Chris Chen 91247a7c69 feat(giving): add role-gated finance nav section 2026-05-28 17:00:49 -07:00