import { and, eq, ilike, not, sql } from "drizzle-orm"; import { financialAccounts, transactions } from "@/db/schema"; import { INITIAL_BALANCE_NOTE } from "@/shared/lib/accounts/constants"; import { db } from "@/shared/lib/db"; import { loadLogoOptions } from "@/shared/lib/logo/options"; import { getAdminPayerId } from "@/shared/lib/payers/get-admin-id"; export type AccountData = { id: string; name: string; accountType: string; status: string; note: string | null; logo: string | null; initialBalance: number; balance: number; excludeFromBalance: boolean; excludeInitialBalanceFromIncome: boolean; }; async function fetchAccountsByStatus( userId: string, archived: boolean, ): Promise<{ accounts: AccountData[]; logoOptions: string[] }> { const adminPayerId = await getAdminPayerId(userId); const [accountRows, logoOptions] = await Promise.all([ db .select({ id: financialAccounts.id, name: financialAccounts.name, accountType: financialAccounts.accountType, status: financialAccounts.status, note: financialAccounts.note, logo: financialAccounts.logo, initialBalance: financialAccounts.initialBalance, excludeFromBalance: financialAccounts.excludeFromBalance, excludeInitialBalanceFromIncome: financialAccounts.excludeInitialBalanceFromIncome, balanceMovements: sql` coalesce( sum( case when ${transactions.note} = ${INITIAL_BALANCE_NOTE} then 0 else ${transactions.amount} end ), 0 ) `, }) .from(financialAccounts) .leftJoin( transactions, and( eq(transactions.accountId, financialAccounts.id), eq(transactions.userId, userId), eq(transactions.isSettled, true), adminPayerId ? eq(transactions.payerId, adminPayerId) : sql`false`, ), ) .where( and( eq(financialAccounts.userId, userId), archived ? ilike(financialAccounts.status, "inativa") : not(ilike(financialAccounts.status, "inativa")), ), ) .groupBy( financialAccounts.id, financialAccounts.name, financialAccounts.accountType, financialAccounts.status, financialAccounts.note, financialAccounts.logo, financialAccounts.initialBalance, financialAccounts.excludeFromBalance, financialAccounts.excludeInitialBalanceFromIncome, ), loadLogoOptions(), ]); const accounts = accountRows.map((account) => ({ id: account.id, name: account.name, accountType: account.accountType, status: account.status, note: account.note, logo: account.logo, initialBalance: Number(account.initialBalance ?? 0), balance: Number(account.initialBalance ?? 0) + Number(account.balanceMovements ?? 0), excludeFromBalance: account.excludeFromBalance, excludeInitialBalanceFromIncome: account.excludeInitialBalanceFromIncome, })); return { accounts, logoOptions }; } async function fetchAccountsForUser( userId: string, ): Promise<{ accounts: AccountData[]; logoOptions: string[] }> { return fetchAccountsByStatus(userId, false); } async function fetchInactiveForUser( userId: string, ): Promise<{ accounts: AccountData[]; logoOptions: string[] }> { return fetchAccountsByStatus(userId, true); } export async function fetchAllAccountsForUser(userId: string): Promise<{ activeAccounts: AccountData[]; archivedAccounts: AccountData[]; logoOptions: string[]; }> { const [activeData, archivedData] = await Promise.all([ fetchAccountsForUser(userId), fetchInactiveForUser(userId), ]); return { activeAccounts: activeData.accounts, archivedAccounts: archivedData.accounts, logoOptions: activeData.logoOptions, }; }