import { eq, desc, gt, count } from 'drizzle-orm' import type { PostgresJsDatabase } from 'drizzle-orm/postgres-js' import { accountBalances } from '../db/schema/accounting.js' import { accounts } from '../db/schema/accounts.js' import type { PaginationInput } from '@lunarfront/shared/schemas' export const AccountBalanceService = { async getBalance(db: PostgresJsDatabase, accountId: string) { const [existing] = await db.select().from(accountBalances).where(eq(accountBalances.accountId, accountId)).limit(1) if (existing) return existing // Create balance record if it doesn't exist const [created] = await db.insert(accountBalances).values({ accountId }).returning() return created }, async adjustBalance( db: PostgresJsDatabase, accountId: string, adjustment: number, reason: 'invoice' | 'payment' | 'void' | 'write_off', ) { const balance = await this.getBalance(db, accountId) const newBalance = parseFloat(balance.currentBalance) + adjustment const updates: Record = { currentBalance: newBalance.toFixed(2), updatedAt: new Date(), } if (reason === 'invoice' && adjustment > 0) { updates.lastInvoiceDate = new Date().toISOString().slice(0, 10) } if (reason === 'payment' && adjustment < 0) { updates.lastPaymentDate = new Date().toISOString().slice(0, 10) } await db.update(accountBalances).set(updates).where(eq(accountBalances.accountId, accountId)) }, async getOutstandingAccounts(db: PostgresJsDatabase, params: PaginationInput) { const where = gt(accountBalances.currentBalance, '0') const offset = ((params.page ?? 1) - 1) * (params.limit ?? 25) const [data, [{ total }]] = await Promise.all([ db.select({ accountId: accountBalances.accountId, currentBalance: accountBalances.currentBalance, lastInvoiceDate: accountBalances.lastInvoiceDate, lastPaymentDate: accountBalances.lastPaymentDate, accountName: accounts.name, accountEmail: accounts.email, }) .from(accountBalances) .innerJoin(accounts, eq(accountBalances.accountId, accounts.id)) .where(where) .orderBy(desc(accountBalances.currentBalance)) .limit(params.limit ?? 25) .offset(offset), db.select({ total: count() }) .from(accountBalances) .where(where), ]) return { data, pagination: { page: params.page ?? 1, limit: params.limit ?? 25, total, totalPages: Math.ceil(total / (params.limit ?? 25)), }, } }, async recalculateFromInvoices(db: PostgresJsDatabase, accountId: string) { // Safety valve: recalculate balance from all invoices const { invoices } = await import('../db/schema/accounting.js') const rows = await db .select({ balance: invoices.balance, status: invoices.status }) .from(invoices) .where(eq(invoices.accountId, accountId)) const totalOutstanding = rows .filter(r => ['sent', 'partial', 'overdue'].includes(r.status)) .reduce((sum, r) => sum + parseFloat(r.balance), 0) await db.update(accountBalances).set({ currentBalance: totalOutstanding.toFixed(2), updatedAt: new Date(), }).where(eq(accountBalances.accountId, accountId)) }, }