docs(1099): document Payee1099s/Form1099Boxes schema and seed Form1099 permissions

- DB_SCHEMA.md §8: add Form1099Box catalog table, Payee1099 recipient master
  (with TIN at-rest encryption note), and new FK columns on Expenses /
  ExpenseSubCategories / ExpenseCategoryGroups; update TOC and Seed Data section
- DbSeeder.cs: grant Modules.Form1099 to finance (R/W/D), pastor (R), and
  board_member (R), mirroring the Form990Report + Disbursements pattern;
  idempotent (only inserts if row absent, never clobbers admin edits)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Chris Chen
2026-06-25 17:56:09 -07:00
parent fb95bf0048
commit ad276c01f3
2 changed files with 101 additions and 0 deletions
+5
View File
@@ -207,6 +207,11 @@ public static class DbSeeder
("finance", Modules.ChurchProfile, true, true, false, false), ("finance", Modules.ChurchProfile, true, true, false, false),
("finance", Modules.Disbursements, true, true, true, true), ("finance", Modules.Disbursements, true, true, true, true),
("finance", Modules.Form990Report, true, false, false, false), ("finance", Modules.Form990Report, true, false, false, false),
// Form1099 — finance manages recipients and tracks filings; pastor and board_member
// get read-only oversight (same pattern as Form990Report). No Approve semantics.
("finance", Modules.Form1099, true, true, true, false),
("pastor", Modules.Form1099, true, false, false, false),
("board_member", Modules.Form1099, true, false, false, false),
// Logs — read-only. System logs are technical (pastor only); audit logs have // Logs — read-only. System logs are technical (pastor only); audit logs have
// governance value, so finance and board members can read them too. // governance value, so finance and board members can read them too.
+96
View File
@@ -17,6 +17,9 @@
6. [Phase 1 — CMS](#6-cms) 6. [Phase 1 — CMS](#6-cms)
7. [Phase 1 — Giving & Donations(奉獻)](#7-giving--donations-奉獻) 7. [Phase 1 — Giving & Donations(奉獻)](#7-giving--donations-奉獻)
8. [Phase 1 — Expense Tracking(支出)](#8-expense-tracking-支出) 8. [Phase 1 — Expense Tracking(支出)](#8-expense-tracking-支出)
- [Form1099Box1099 欄位目錄)](#form1099box-irs-1099-報告欄位目錄)
- [Payee1099(收款人主檔)](#payee1099-1099-申報收款人主檔)
- [現有表新增欄位(1099 歸屬)](#現有表新增欄位1099-歸屬)
9. [Phase 1 — Prayer Requests(代禱)](#9-prayer-requests-代禱) 9. [Phase 1 — Prayer Requests(代禱)](#9-prayer-requests-代禱)
10. [Phase 1 — Audit Log](#10-audit-log) 10. [Phase 1 — Audit Log](#10-audit-log)
11. [Phase 1 — Notifications](#11-notifications) 11. [Phase 1 — Notifications](#11-notifications)
@@ -704,6 +707,91 @@ Table: MonthlyStatements
| UpdatedBy | varchar(450) NOT NULL | FK → AspNetUsers.Id | | UpdatedBy | varchar(450) NOT NULL | FK → AspNetUsers.Id |
| **UNIQUE** | (Year, Month) | 每個月只有一份月結報表 | | **UNIQUE** | (Year, Month) | 每個月只有一份月結報表 |
### Form1099BoxIRS 1099 報告欄位目錄)
```
Table: Form1099Boxes
```
| 欄位 | 型別 | 說明 |
|------|------|------|
| Id | int PK | |
| BoxCode | varchar(20) NOT NULL UNIQUE | 欄位代碼,如 "NEC-1"、"MISC-1" |
| Name_en | varchar(200) NOT NULL | 英文欄位名稱 |
| Name_zh | varchar(200)? | 中文欄位名稱 |
| FormType | varchar(20) NOT NULL | '1099-NEC' \| '1099-MISC' |
| SortOrder | int NOT NULL DEFAULT 0 | 顯示排序 |
| IsActive | bool NOT NULL DEFAULT true | |
| CreatedAt | timestamp NOT NULL | |
| CreatedBy | varchar(450) NOT NULL | FK → AspNetUsers.Id |
| UpdatedAt | timestamp NOT NULL | |
| UpdatedBy | varchar(450) NOT NULL | FK → AspNetUsers.Id |
> **說明:** IRS 1099 申報欄位目錄(catalog)。Seed 預設兩個欄位:`NEC-1`Nonemployee compensation — 非員工報酬,1099-NEC 第 1 欄)與 `MISC-1`Rents — 租金,1099-MISC 第 1 欄)。此表為唯讀參考資料,僅透過 seed 管理;新增欄位須更新 seed 並重新執行 migration。
### Payee10991099 申報收款人主檔)
```
Table: Payee1099s
```
| 欄位 | 型別 | 說明 |
|------|------|------|
| Id | int PK | |
| LegalName | varchar(200) NOT NULL | IRS 法定全名(個人或公司)|
| DisplayName | varchar(200)? | 顯示用簡稱(選填)|
| MemberId | int? | FK → Members.IdON DELETE SET NULL。收款人同時為教友時可選填關聯 |
| TaxClassification | varchar(50) NOT NULL | 稅務分類,如 'Individual'、'SoleProprietor'、'Corporation'、'Partnership' 等 |
| Is1099Tracked | bool NOT NULL DEFAULT true | 是否需要申報 1099 |
| TinType | varchar(10)? | 'SSN' \| 'EIN'null = 尚未收到 W-9 |
| **TinEncrypted** | varchar(MAX)? | **TIN 加密密文(使用 ASP.NET Data Protection API 加密靜態儲存,明文永不入庫)** |
| **TinLast4** | varchar(4)? | **TIN 末四碼明文(僅供遮罩顯示用,如 \*\*\*-\*\*-1234** |
| AddressLine1 | varchar(200)? | |
| AddressLine2 | varchar(200)? | |
| City | varchar(100)? | |
| State | varchar(50)? | |
| Zip | varchar(20)? | |
| Email | varchar(200)? | |
| Phone | varchar(30)? | |
| W9Status | varchar(20) NOT NULL DEFAULT 'Missing' | 'Missing' \| 'Requested' \| 'OnFile' \| 'Expired' |
| W9ReceivedDate | date? | W-9 文件收到日期 |
| W9BlobPath | varchar(500)? | 上傳的 W-9 文件 Azure Blob 路徑 |
| IsActive | bool NOT NULL DEFAULT true | |
| Notes | text? | 內部備注 |
| IsDeleted | bool NOT NULL DEFAULT false | 軟刪除 |
| DeletedAt | timestamp? | |
| DeletedBy | varchar(450)? | FK → AspNetUsers.Id |
| CreatedAt | timestamp NOT NULL | |
| CreatedBy | varchar(450) NOT NULL | FK → AspNetUsers.Id |
| UpdatedAt | timestamp NOT NULL | |
| UpdatedBy | varchar(450) NOT NULL | FK → AspNetUsers.Id |
> **TIN 靜態加密(Encryption at Rest):** 納稅識別碼(SSN / EIN)屬高敏感個人資料。`TinEncrypted` 欄位儲存使用 ASP.NET Data Protection API`IDataProtector`)加密後的密文;`TinLast4` 僅儲存末四碼明文供前端遮罩顯示(\*\*\*-\*\*-XXXX)。明文 TIN 永遠不寫入資料庫,也不出現在 Audit Log 快照中。
### 現有表新增欄位(1099 歸屬)
以下欄位由 1099 功能新增至現有表,透過 EF Core Migration 套用:
**`Expenses`(新增欄位)**
| 欄位 | 型別 | 說明 |
|------|------|------|
| **PayeeId** | int? | FK → Payee1099s.IdON DELETE SET NULL。費用標題層級 1099 收款人歸屬;null = 不申報 1099 |
**`ExpenseSubCategories`(新增欄位)**
| 欄位 | 型別 | 說明 |
|------|------|------|
| **Form1099BoxId** | int? | FK → Form1099Boxes.IdON DELETE SET NULL。子項目層級 1099 申報欄位映射(優先於大類值)|
**`ExpenseCategoryGroups`(新增欄位)**
| 欄位 | 型別 | 說明 |
|------|------|------|
| **Form1099BoxId** | int? | FK → Form1099Boxes.IdON DELETE SET NULL。大類層級 1099 申報欄位備援映射 |
> **有效 1099 欄位解析順序:** `SubCategory.Form1099BoxId ?? Group.Form1099BoxId ?? null`(先取子項目欄位;若為 null 則取大類欄位;仍為 null = 該費用不需申報 1099)。此解析邏輯與 Form 990 行號解析(`SubCategory.Form990LineId ?? Group.Form990LineId ?? "24"`)平行,但語意不同:1099 的 null 代表「不申報」,而 990 的 null 會回退至行 "24"(其他費用)。
--- ---
## 9. Prayer Requests(代禱) ## 9. Prayer Requests(代禱)
@@ -1033,6 +1121,14 @@ super_admin, pastor, board_member, coworker_chair, ministry_leader, district_lea
Form990Report — 唯讀報表權限,授予角色:finance、pastor、board_member Form990Report — 唯讀報表權限,授予角色:finance、pastor、board_member
``` ```
### Form1099 權限模組
```
Form1099 — 1099 收款人管理與申報,授予角色:
finance — Read / Write / Delete(完整管理)
pastor — Read(唯讀總覽)
board_member — Read(唯讀總覽)
```
### CmsPages(靜態頁面 Slug ### CmsPages(靜態頁面 Slug
``` ```
about, vision, service-times, contact about, vision, service-times, contact