import type { CurrencyCode, Instant } from '@household/domain' export interface FinanceMemberRecord { id: string telegramUserId: string displayName: string rentShareWeight: number isAdmin: boolean } export interface FinanceCycleRecord { id: string period: string currency: CurrencyCode } export interface FinanceCycleExchangeRateRecord { cycleId: string sourceCurrency: CurrencyCode targetCurrency: CurrencyCode rateMicros: bigint effectiveDate: string source: 'nbg' } export interface FinanceRentRuleRecord { amountMinor: bigint currency: CurrencyCode } export interface FinanceParsedPurchaseRecord { id: string payerMemberId: string amountMinor: bigint currency: CurrencyCode description: string | null occurredAt: Instant | null splitMode?: 'equal' | 'custom_amounts' participants?: readonly { id?: string memberId: string included?: boolean shareAmountMinor: bigint | null }[] } export interface FinanceUtilityBillRecord { id: string billName: string amountMinor: bigint currency: CurrencyCode createdByMemberId: string | null createdAt: Instant } export type FinancePaymentKind = 'rent' | 'utilities' export interface FinancePaymentRecord { id: string memberId: string kind: FinancePaymentKind amountMinor: bigint currency: CurrencyCode recordedAt: Instant } export interface FinanceSettlementSnapshotLineRecord { memberId: string rentShareMinor: bigint utilityShareMinor: bigint purchaseOffsetMinor: bigint netDueMinor: bigint } export interface FinancePaymentConfirmationMessage { senderTelegramUserId: string rawText: string normalizedText: string telegramChatId: string telegramMessageId: string telegramThreadId: string telegramUpdateId: string attachmentCount: number messageSentAt: Instant | null } export type FinancePaymentConfirmationReviewReason = | 'member_not_found' | 'cycle_not_found' | 'settlement_not_ready' | 'intent_missing' | 'kind_ambiguous' | 'multiple_members' | 'non_positive_amount' export type FinancePaymentConfirmationSaveInput = | (FinancePaymentConfirmationMessage & { status: 'recorded' cycleId: string memberId: string kind: FinancePaymentKind amountMinor: bigint currency: CurrencyCode explicitAmountMinor: bigint | null explicitCurrency: CurrencyCode | null recordedAt: Instant }) | (FinancePaymentConfirmationMessage & { status: 'needs_review' cycleId: string | null memberId: string | null kind: FinancePaymentKind | null amountMinor: bigint | null currency: CurrencyCode | null explicitAmountMinor: bigint | null explicitCurrency: CurrencyCode | null reviewReason: FinancePaymentConfirmationReviewReason }) export type FinancePaymentConfirmationSaveResult = | { status: 'duplicate' } | { status: 'recorded' paymentRecord: FinancePaymentRecord } | { status: 'needs_review' reviewReason: FinancePaymentConfirmationReviewReason } export interface SettlementSnapshotLineRecord { memberId: string rentShareMinor: bigint utilityShareMinor: bigint purchaseOffsetMinor: bigint netDueMinor: bigint explanations: readonly string[] } export interface SettlementSnapshotRecord { cycleId: string inputHash: string totalDueMinor: bigint currency: CurrencyCode metadata: Record lines: readonly SettlementSnapshotLineRecord[] } export interface FinanceRepository { getMemberByTelegramUserId(telegramUserId: string): Promise listMembers(): Promise getOpenCycle(): Promise getCycleByPeriod(period: string): Promise getLatestCycle(): Promise openCycle(period: string, currency: CurrencyCode): Promise closeCycle(cycleId: string, closedAt: Instant): Promise saveRentRule(period: string, amountMinor: bigint, currency: CurrencyCode): Promise getCycleExchangeRate( cycleId: string, sourceCurrency: CurrencyCode, targetCurrency: CurrencyCode ): Promise saveCycleExchangeRate( input: FinanceCycleExchangeRateRecord ): Promise addUtilityBill(input: { cycleId: string billName: string amountMinor: bigint currency: CurrencyCode createdByMemberId: string }): Promise addParsedPurchase(input: { cycleId: string payerMemberId: string amountMinor: bigint currency: CurrencyCode description: string | null occurredAt: Instant splitMode?: 'equal' | 'custom_amounts' participants?: readonly { memberId: string included?: boolean shareAmountMinor: bigint | null }[] }): Promise updateParsedPurchase(input: { purchaseId: string amountMinor: bigint currency: CurrencyCode description: string | null splitMode?: 'equal' | 'custom_amounts' participants?: readonly { memberId: string included?: boolean shareAmountMinor: bigint | null }[] }): Promise deleteParsedPurchase(purchaseId: string): Promise updateUtilityBill(input: { billId: string billName: string amountMinor: bigint currency: CurrencyCode }): Promise deleteUtilityBill(billId: string): Promise addPaymentRecord(input: { cycleId: string memberId: string kind: FinancePaymentKind amountMinor: bigint currency: CurrencyCode recordedAt: Instant }): Promise updatePaymentRecord(input: { paymentId: string memberId: string kind: FinancePaymentKind amountMinor: bigint currency: CurrencyCode }): Promise deletePaymentRecord(paymentId: string): Promise getRentRuleForPeriod(period: string): Promise getUtilityTotalForCycle(cycleId: string): Promise listUtilityBillsForCycle(cycleId: string): Promise listPaymentRecordsForCycle(cycleId: string): Promise listParsedPurchasesForRange( start: Instant, end: Instant ): Promise getSettlementSnapshotLines( cycleId: string ): Promise savePaymentConfirmation( input: FinancePaymentConfirmationSaveInput ): Promise replaceSettlementSnapshot(snapshot: SettlementSnapshotRecord): Promise }