- 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>
Add optional payeeId to CreateExpenseRequest + ExpenseListItemDto
frontend models. In the expense form dialog: inject Payee1099ApiService,
load active payees on init, add payeeId to the form state, pre-populate
it from expense.payeeId in edit mode, and include it in the emitSave
payload. Render a "1099 Recipient / 1099 收款人" Kendo DropdownList
(textField=legalName, valueField=id, [valuePrimitive]="true",
md:col-span-2) inside the vendor-mode ng-container below Vendor Name
and Check #.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mirror the 990-line dropdown in both the group and subcategory edit
dialogs: add form1099BoxId to the frontend group/subcategory DTOs and
request interfaces, load boxes via a new getForm1099Boxes() method on
ExpenseCategoryApiService (same label pattern as getForm990Lines:
"boxCode — name_en / name_zh"), wire form1099BoxId into all
open/edit/save paths, and render a side-by-side "1099 Box / 1099 框"
Kendo DropdownList with [valuePrimitive]="true" and "— none —" default.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mirror Form990LineId: add Form1099BoxId + Form1099BoxCode to all four
category DTOs (response + request, group + sub); load a boxCodes lookup
dictionary in GetAllAsync and project it; set/copy the field in
CreateGroupAsync, UpdateGroupAsync, CreateSubCategoryAsync, and
UpdateSubCategoryAsync. All 4 category-service unit tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add Form1099ReportPageComponent (year selector, summary chips with a
prominent missing-W-9 flag, desktop grid + mobile cards, recipient detail
dialog). Per-row Copy B PDF via right-click context menu and a header
Export filing CSV action, both downloaded as auth-correct blobs. Wire the
eager route + sidebar nav item, gated on Form1099:read. Also convert the
neighboring finance/payee-1099 route from lazy loadComponent to an eager
component import so both 1099 routes match the surrounding convention.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add downloadCsv/downloadCopyB returning Blob via HttpClient so the auth
interceptor attaches the bearer token (raw window.open would 401). Remove
the now-unused copyBUrl/exportCsvUrl raw-URL builders.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Injects I1099FormService into Form1099ReportController and adds two
Read-gated GET endpoints: recipient/{payeeId}/copy-b (Copy B PDF) and
export-csv (filing-data CSV). Registers Form1099FormService in DI.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds I1099FormService and Form1099FormService: an IRIS/accountant filing-data
CSV (one row per reportable recipient) and a plain-paper recipient Copy B
1099-NEC PDF rendered via the DevExpress RichEdit/Office API (mirroring
CheckPrintService). Includes a CSV-export unit test over a stub report service.
Service lives in namespace ROLAC.API.Services (not ...Services.Form1099) to
avoid shadowing the ROLAC.API.Entities.Form1099 constants class.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Creates Form1099Boxes and Payee1099s tables; adds Form1099BoxId to
ExpenseSubCategories and ExpenseCategoryGroups; adds PayeeId to
Expenses. All new columns nullable, all FKs with SetNull, unique index
on Form1099Boxes.BoxCode. No data backfill.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds Form1099BoxSeed (NEC-1, MISC-1) and Form1099SubMappingSeed
(6 service/rent subcategories), SeedForm1099BoxesAsync method with
null-fill idempotency (never clobbers admin edits), and wires it into
SeedAsync after SeedForm990ExpenseLinesAsync.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add int? PayeeId to CreateExpenseRequest (UpdateExpenseRequest inherits)
and to ExpenseListItemDto (so it round-trips to the form). Set e.PayeeId
unconditionally in CreateAsync and UpdateAsync so 1099 attribution is
independent of VendorPayment vs StaffReimbursement type. Map PayeeId in
both DTO projections: the paged-list lambda and GetByIdAsync.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add Form1099 const to Modules.cs (after Form990Report) and insert it
into the All display-order list. Register IForm1099ReportService and
IPayee1099Service in Program.cs beside the existing Form990Report entry.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Implement IPayee1099Service and Payee1099Service: list/get/create/update/
soft-delete and RevealTin. TIN is encrypted via ITinProtector on write;
TinLast4 is the only clear-text fragment stored. Null Tin on update
preserves the existing ciphertext. Four xUnit tests cover encrypt-on-create,
null-tin-keeps-ciphertext, list-masks-to-last4, and soft-delete hides from list.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add Payee1099ListItemDto, Payee1099Dto, and SavePayee1099Request in
DTOs/Payee for the 1099 recipient CRUD surface.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Save a vendor payment as a reusable named snapshot and re-apply it later,
pre-filling every field except the Expense Date. Shared church-wide with a
creator tag; quick picker in the vendor form + a management page (rename/delete).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The snapshot management page backs an API that gates every action on
Expenses:Write, so a read-only user reaching it via a read-gated nav/route
would hit a silent 403 and a blank page. Require write for both.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add an AI assist button to the Edit/New Group (大項) and Subcategory
(小項) dialogs: the user enters a Chinese name, and the model refines
the Chinese, translates it to English, and suggests the matching IRS
Form 990 Part IX line. Suggestions surface in a confirm card; Apply
fills the Chinese name, English name, and 990 line fields.
Backend mirrors the existing expense-classification AI family but over
the Form 990 line catalog: IExpenseCategoryAiService + base (catalog
load, prompt, id validation) + Claude/Gemini providers + factory that
picks the provider from ChurchProfile.AiProvider. New write-gated
POST api/expense-categories/ai-suggest endpoint; sub-category requests
pass the parent group + its 990 line to bias the choice.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>