feat(1099): add 1099 recipient picker to expense form
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>
This commit is contained in:
+7
-1
@@ -158,7 +158,7 @@
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Vendor mode: vendor name + check number -->
|
||||
<!-- Vendor mode: vendor name + check number + optional 1099 recipient -->
|
||||
<ng-container *ngIf="mode === 'vendor'">
|
||||
<label class="flex flex-col gap-1">Vendor Name
|
||||
<kendo-textbox [(ngModel)]="form.vendorName" placeholder="Payee / vendor name"></kendo-textbox>
|
||||
@@ -166,6 +166,12 @@
|
||||
<label class="flex flex-col gap-1">Check #
|
||||
<kendo-textbox [(ngModel)]="form.checkNumber" placeholder="Check number (optional)"></kendo-textbox>
|
||||
</label>
|
||||
<label class="flex flex-col gap-1 md:col-span-2">1099 Recipient / 1099 收款人 <span class="text-gray-400 font-normal">(optional)</span>
|
||||
<kendo-dropdownlist [data]="payees" textField="legalName" valueField="id" [valuePrimitive]="true"
|
||||
[defaultItem]="{ id: null, legalName: '— none —' }"
|
||||
[(ngModel)]="form.payeeId">
|
||||
</kendo-dropdownlist>
|
||||
</label>
|
||||
</ng-container>
|
||||
|
||||
<!-- Reimbursement mode: receipt file input -->
|
||||
|
||||
+9
@@ -15,6 +15,8 @@ import { ExpenseSnapshotDto, CreateExpenseSnapshotRequest } from '../../models/e
|
||||
import { ExpenseAiService } from '../../services/expense-ai.service';
|
||||
import { MemberApiService } from '../../../members/services/member-api.service';
|
||||
import { MemberListItemDto, memberDisplayName } from '../../../members/models/member.model';
|
||||
import { Payee1099ApiService } from '../../../payee1099/services/payee1099-api.service';
|
||||
import { Payee1099ListItem } from '../../../payee1099/models/payee1099.model';
|
||||
import {
|
||||
MinistryDto, ExpenseCategoryGroupDto, ExpenseSubCategoryDto, ExpenseType, CreateExpenseRequest,
|
||||
ExpenseDto, FunctionalClass, ExpenseAiSuggestion,
|
||||
@@ -66,6 +68,8 @@ export class ExpenseFormDialogComponent implements OnInit, OnDestroy {
|
||||
ministries: MinistryDto[] = [];
|
||||
groups: ExpenseCategoryGroupDto[] = [];
|
||||
|
||||
payees: Payee1099ListItem[] = [];
|
||||
|
||||
/** Saved snapshots (vendor mode only) for the "Load from snapshot" picker. */
|
||||
snapshots: ExpenseSnapshotDto[] = [];
|
||||
/** Picker binding; reset to null after each apply so the same snapshot can be re-picked. */
|
||||
@@ -95,6 +99,7 @@ export class ExpenseFormDialogComponent implements OnInit, OnDestroy {
|
||||
vendorName: '',
|
||||
checkNumber: '',
|
||||
memberId: null as number | null,
|
||||
payeeId: null as number | null,
|
||||
expenseDate: new Date(),
|
||||
};
|
||||
/** At least one line always; "+ Add line" appends, each line is independently removable down to one. */
|
||||
@@ -133,11 +138,13 @@ export class ExpenseFormDialogComponent implements OnInit, OnDestroy {
|
||||
private expenseApi: ExpenseApiService,
|
||||
private snapshotApi: ExpenseSnapshotApiService,
|
||||
private aiApi: ExpenseAiService,
|
||||
private payeeApi: Payee1099ApiService,
|
||||
private sanitizer: DomSanitizer,
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.ministryApi.getAll().subscribe(m => (this.ministries = m));
|
||||
this.payeeApi.getAll(false).subscribe(list => (this.payees = list));
|
||||
if (this.showSnapshotTools) this.loadSnapshots();
|
||||
this.catApi.getAll(false).subscribe(groups => {
|
||||
this.groups = groups;
|
||||
@@ -169,6 +176,7 @@ export class ExpenseFormDialogComponent implements OnInit, OnDestroy {
|
||||
vendorName: expense.vendorName ?? '',
|
||||
checkNumber: expense.checkNumber ?? '',
|
||||
memberId: expense.memberId,
|
||||
payeeId: expense.payeeId ?? null,
|
||||
expenseDate: new Date(year, month - 1, day),
|
||||
};
|
||||
this.lines = (expense.lines ?? []).map(l => ({
|
||||
@@ -424,6 +432,7 @@ export class ExpenseFormDialogComponent implements OnInit, OnDestroy {
|
||||
checkNumber: this.mode === 'vendor' ? (this.form.checkNumber || null) : null,
|
||||
expenseDate,
|
||||
notes: null,
|
||||
payeeId: this.form.payeeId,
|
||||
};
|
||||
// The request and receipt are snapshotted here, so resetting the form right
|
||||
// after emitting is safe even though the parent saves asynchronously.
|
||||
|
||||
Reference in New Issue
Block a user