feat: add payer control for purchases

- Add explicit payerMemberId field to purchase ledger entries
- Add 'Paid by' selector in mini app purchase add/edit forms
- Default payer to current user when creating new purchases
- Allow admins to change who made existing purchases
- Update backend handlers to accept and persist payerMemberId
- Add i18n translations for 'Paid by' label (EN/RU)

All quality gates pass: build, typecheck, lint, format, test

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
2026-03-16 17:44:20 +04:00
parent 64dc3a3813
commit 02c79ae629
8 changed files with 95 additions and 5 deletions

View File

@@ -322,6 +322,7 @@ async function readAddPurchasePayload(request: Request): Promise<{
description: string
amountMajor: string
currency?: string
payerMemberId?: string
split?: {
mode: 'equal' | 'custom_amounts'
participants: {
@@ -336,6 +337,7 @@ async function readAddPurchasePayload(request: Request): Promise<{
description?: string
amountMajor?: string
currency?: string
payerMemberId?: string
split?: {
mode?: string
participants?: {
@@ -367,6 +369,11 @@ async function readAddPurchasePayload(request: Request): Promise<{
currency: parsed.currency
}
: {}),
...(parsed.payerMemberId !== undefined
? {
payerMemberId: parsed.payerMemberId
}
: {}),
...(parsed.split !== undefined
? {
split: {
@@ -387,6 +394,7 @@ async function readPurchaseMutationPayload(request: Request): Promise<{
description?: string
amountMajor?: string
currency?: string
payerMemberId?: string
split?: {
mode: 'equal' | 'custom_amounts'
participants: {
@@ -401,6 +409,7 @@ async function readPurchaseMutationPayload(request: Request): Promise<{
description?: string
amountMajor?: string
currency?: string
payerMemberId?: string
split?: {
mode?: string
participants?: {
@@ -436,6 +445,11 @@ async function readPurchaseMutationPayload(request: Request): Promise<{
currency: parsed.currency.trim()
}
: {}),
...(parsed.payerMemberId !== undefined
? {
payerMemberId: parsed.payerMemberId
}
: {}),
...(parsed.split &&
(parsed.split.mode === 'equal' || parsed.split.mode === 'custom_amounts') &&
Array.isArray(parsed.split.participants)
@@ -1187,10 +1201,11 @@ export function createMiniAppAddPurchaseHandler(options: {
}
const service = options.financeServiceForHousehold(auth.member.householdId)
const payerMemberId = payload.payerMemberId ?? auth.member.id
await service.addPurchase(
payload.description,
payload.amountMajor,
auth.member.id,
payerMemberId,
payload.currency,
payload.split
)
@@ -1243,12 +1258,14 @@ export function createMiniAppUpdatePurchaseHandler(options: {
}
const service = options.financeServiceForHousehold(auth.member.householdId)
const payerMemberId = payload.payerMemberId
const updated = await service.updatePurchase(
payload.purchaseId,
payload.description,
payload.amountMajor,
payload.currency,
payload.split
payload.split,
payerMemberId
)
if (!updated) {