From 2af169fa6019fc87194e1032118a4144f99e77f7 Mon Sep 17 00:00:00 2001 From: Chris Chen Date: Sat, 20 Jun 2026 18:05:22 -0700 Subject: [PATCH] Fix null payee. --- .../Services/ExpenseServiceTests.cs | 34 +++++++++++++++++-- API/ROLAC.API/Services/ExpenseService.cs | 15 +++++--- .../check-register-page.component.html | 2 +- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/API/ROLAC.API.Tests/Services/ExpenseServiceTests.cs b/API/ROLAC.API.Tests/Services/ExpenseServiceTests.cs index a82393b..2ed6867 100644 --- a/API/ROLAC.API.Tests/Services/ExpenseServiceTests.cs +++ b/API/ROLAC.API.Tests/Services/ExpenseServiceTests.cs @@ -107,11 +107,39 @@ public class ExpenseServiceTests } [Fact] - public async Task Create_Reimbursement_AsFinance_IsPendingApproval() + public async Task Create_Reimbursement_AsFinance_OnBehalf_IsPendingApproval_AndLinksPickedMember() { + // Finance entering on behalf of a member (member explicitly picked) goes straight to the + // approval queue and links the picked member. var (svc, db, _) = Build(); - var id = await svc.CreateAsync(Reimb(), isFinance: true); - Assert.Equal("PendingApproval", (await db.Expenses.FindAsync(id))!.Status); + db.Members.Add(new Member { Id = 9, FirstName_en = "Pat", LastName_en = "Vendor" }); + await db.SaveChangesAsync(); + var r = Reimb(); r.MemberId = 9; + + var id = await svc.CreateAsync(r, isFinance: true); + + var e = await db.Expenses.FindAsync(id); + Assert.Equal("PendingApproval", e!.Status); + Assert.Equal(9, e.MemberId); + } + + [Fact] + public async Task Create_Reimbursement_AsFinance_SelfService_LinksCallerMember_AndIsDraft() + { + // Regression: a finance/super_admin user filing their OWN reimbursement via "My Reimbursements" + // sends no MemberId. The entry must link to the caller's own member (so the Payee shows their + // legal name) and stay a Draft until they explicitly Submit — not jump to PendingApproval with + // a null member. + var (svc, db, _) = Build("u1"); + db.Members.Add(new Member { Id = 7, FirstName_en = "Grace", LastName_en = "Lee" }); + db.Users.Add(new AppUser { Id = "u1", MemberId = 7 }); + await db.SaveChangesAsync(); + + var id = await svc.CreateAsync(Reimb(), isFinance: true); // no MemberId on the request + + var e = await db.Expenses.FindAsync(id); + Assert.Equal(7, e!.MemberId); + Assert.Equal("Draft", e.Status); } [Fact] diff --git a/API/ROLAC.API/Services/ExpenseService.cs b/API/ROLAC.API/Services/ExpenseService.cs index b08f53e..6ad8893 100644 --- a/API/ROLAC.API/Services/ExpenseService.cs +++ b/API/ROLAC.API/Services/ExpenseService.cs @@ -141,12 +141,17 @@ public class ExpenseService : IExpenseService } else // StaffReimbursement { - // Finance entering on behalf of a member goes straight to the approval queue; - // a member's own self-service entry stays a Draft until they explicitly Submit it. - e.Status = isFinance ? "PendingApproval" : "Draft"; + // Distinguish the two flows by whether a member was explicitly picked, NOT by role: + // - On-behalf: finance picks a member (Expenses page) -> straight into the approval queue. + // - Self-service: no member picked ("My Reimbursements") -> link to the caller's own member + // so the Payee shows their legal name, and keep it a Draft until they explicitly Submit. + // A finance/super_admin user files their own reimbursements through the self-service flow too, + // so keying off the role alone would leave their entries with a null member (empty Payee). + var isOnBehalf = isFinance && r.MemberId.HasValue; + e.Status = isOnBehalf ? "PendingApproval" : "Draft"; e.SubmittedBy = CurrentUserId; - if (isFinance) e.SubmittedAt = DateTimeOffset.UtcNow; - e.MemberId = isFinance ? r.MemberId : await CallerMemberIdAsync(); + if (isOnBehalf) e.SubmittedAt = DateTimeOffset.UtcNow; + e.MemberId = isOnBehalf ? r.MemberId : await CallerMemberIdAsync(); e.VendorName = null; } diff --git a/APP/src/app/features/disbursement/pages/check-register-page/check-register-page.component.html b/APP/src/app/features/disbursement/pages/check-register-page/check-register-page.component.html index 4f88fd2..d5c6816 100644 --- a/APP/src/app/features/disbursement/pages/check-register-page/check-register-page.component.html +++ b/APP/src/app/features/disbursement/pages/check-register-page/check-register-page.component.html @@ -51,7 +51,7 @@ - +