diff --git a/apps/bot/src/miniapp-billing.ts b/apps/bot/src/miniapp-billing.ts
index a6ba350..87fb554 100644
--- a/apps/bot/src/miniapp-billing.ts
+++ b/apps/bot/src/miniapp-billing.ts
@@ -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) {
diff --git a/apps/miniapp/src/i18n.ts b/apps/miniapp/src/i18n.ts
index a3ea245..0a5986c 100644
--- a/apps/miniapp/src/i18n.ts
+++ b/apps/miniapp/src/i18n.ts
@@ -169,6 +169,7 @@ export const dictionary = {
participantExcluded: 'Excluded',
purchaseCustomShareLabel: 'Custom amount',
purchaseEditorBody: 'Review the purchase details and adjust the split only when needed.',
+ purchasePayerLabel: 'Paid by',
paymentsAdminTitle: 'Payments',
paymentsAdminBody: 'Add, fix, or remove payment records for the current cycle.',
paymentsAddAction: 'Add payment',
@@ -516,6 +517,7 @@ export const dictionary = {
purchaseCustomShareLabel: 'Своя сумма',
purchaseEditorBody:
'Проверь покупку и меняй детали разделения только если это действительно нужно.',
+ purchasePayerLabel: 'Оплатил',
paymentsAdminTitle: 'Оплаты',
paymentsAdminBody: 'Добавляй, исправляй или удаляй оплаты за текущий цикл.',
paymentsAddAction: 'Добавить оплату',
diff --git a/apps/miniapp/src/lib/ledger-helpers.ts b/apps/miniapp/src/lib/ledger-helpers.ts
index 61bedc2..e13c5a3 100644
--- a/apps/miniapp/src/lib/ledger-helpers.ts
+++ b/apps/miniapp/src/lib/ledger-helpers.ts
@@ -33,6 +33,7 @@ export type PurchaseDraft = {
description: string
amountMajor: string
currency: 'USD' | 'GEL'
+ payerMemberId?: string
splitMode: 'equal' | 'custom_amounts'
splitInputMode: 'equal' | 'exact' | 'percentage'
participants: ParticipantShare[]
@@ -110,6 +111,7 @@ export function purchaseDrafts(
description: entry.title,
amountMajor: entry.amountMajor,
currency: entry.currency,
+ ...(entry.payerMemberId !== undefined ? { payerMemberId: entry.payerMemberId } : {}),
splitMode: entry.purchaseSplitMode ?? 'equal',
splitInputMode: (entry.purchaseSplitMode ?? 'equal') === 'equal' ? 'equal' : 'exact',
participants:
@@ -129,6 +131,7 @@ export function purchaseDraftForEntry(entry: MiniAppDashboard['ledger'][number])
description: entry.title,
amountMajor: entry.amountMajor,
currency: entry.currency,
+ ...(entry.payerMemberId !== undefined ? { payerMemberId: entry.payerMemberId } : {}),
splitMode: entry.purchaseSplitMode ?? 'equal',
splitInputMode: (entry.purchaseSplitMode ?? 'equal') === 'equal' ? 'equal' : 'exact',
participants:
diff --git a/apps/miniapp/src/miniapp-api.ts b/apps/miniapp/src/miniapp-api.ts
index 833373d..ebbb84d 100644
--- a/apps/miniapp/src/miniapp-api.ts
+++ b/apps/miniapp/src/miniapp-api.ts
@@ -152,6 +152,7 @@ export interface MiniAppDashboard {
included: boolean
shareAmountMajor: string | null
}[]
+ payerMemberId?: string
}[]
}
@@ -996,6 +997,7 @@ export async function addMiniAppPurchase(
description: string
amountMajor: string
currency: 'USD' | 'GEL'
+ payerMemberId?: string
split?: {
mode: 'equal' | 'custom_amounts'
participants: readonly {
@@ -1030,6 +1032,7 @@ export async function updateMiniAppPurchase(
description: string
amountMajor: string
currency: 'USD' | 'GEL'
+ payerMemberId?: string
split?: {
mode: 'equal' | 'custom_amounts'
participants: readonly {
diff --git a/apps/miniapp/src/routes/ledger.tsx b/apps/miniapp/src/routes/ledger.tsx
index 8a74526..d574614 100644
--- a/apps/miniapp/src/routes/ledger.tsx
+++ b/apps/miniapp/src/routes/ledger.tsx
@@ -202,7 +202,7 @@ function ParticipantSplitInputs(props: ParticipantSplitInputsProps) {
}
export default function LedgerRoute() {
- const { initData, refreshHouseholdData } = useSession()
+ const { initData, refreshHouseholdData, session } = useSession()
const { copy } = useI18n()
const { dashboard, loading, effectiveIsAdmin, purchaseLedger, utilityLedger, paymentLedger } =
useDashboard()
@@ -384,6 +384,11 @@ export default function LedgerRoute() {
description: draft.description,
amountMajor: draft.amountMajor,
currency: draft.currency,
+ ...(draft.payerMemberId
+ ? {
+ payerMemberId: draft.payerMemberId
+ }
+ : {}),
split: {
mode: draft.splitMode,
participants: draft.participants.map((p) => ({
@@ -428,6 +433,11 @@ export default function LedgerRoute() {
description: draft.description,
amountMajor: draft.amountMajor,
currency: draft.currency,
+ ...(draft.payerMemberId
+ ? {
+ payerMemberId: draft.payerMemberId
+ }
+ : {}),
...(draft.participants.length > 0
? {
split: {
@@ -444,10 +454,12 @@ export default function LedgerRoute() {
: {})
})
setAddPurchaseOpen(false)
+ const currentSession = session()
setNewPurchase({
description: '',
amountMajor: '',
currency: (dashboard()?.currency as 'USD' | 'GEL') ?? 'GEL',
+ ...(currentSession.status === 'ready' ? { payerMemberId: currentSession.member.id } : {}),
splitMode: 'equal',
splitInputMode: 'equal',
participants: []
@@ -785,6 +797,25 @@ export default function LedgerRoute() {
}
/>
+