import { and, eq, ilike, not, sql } from "drizzle-orm"; import { contas, lancamentos, pagadores } from "@/db/schema"; import { INITIAL_BALANCE_NOTE } from "@/lib/contas/constants"; import { db } from "@/lib/db"; import { loadLogoOptions } from "@/lib/logo/options"; import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants"; 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; }; export async function fetchAccountsForUser( userId: string, ): Promise<{ accounts: AccountData[]; logoOptions: LogoOption[] }> { const [accountRows, logoOptions] = await Promise.all([ db .select({ id: contas.id, name: contas.name, accountType: contas.accountType, status: contas.status, note: contas.note, logo: contas.logo, initialBalance: contas.initialBalance, excludeFromBalance: contas.excludeFromBalance, excludeInitialBalanceFromIncome: contas.excludeInitialBalanceFromIncome, balanceMovements: sql` coalesce( sum( case when ${lancamentos.note} = ${INITIAL_BALANCE_NOTE} then 0 else ${lancamentos.amount} end ), 0 ) `, }) .from(contas) .leftJoin( lancamentos, and( eq(lancamentos.contaId, contas.id), eq(lancamentos.userId, userId), eq(lancamentos.isSettled, true), ), ) .leftJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) .where( and( eq(contas.userId, userId), not(ilike(contas.status, "inativa")), sql`(${lancamentos.id} IS NULL OR ${pagadores.role} = ${PAGADOR_ROLE_ADMIN})`, ), ) .groupBy( contas.id, contas.name, contas.accountType, contas.status, contas.note, contas.logo, contas.initialBalance, contas.excludeFromBalance, contas.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 }; } export async function fetchInativosForUser( userId: string, ): Promise<{ accounts: AccountData[]; logoOptions: LogoOption[] }> { const [accountRows, logoOptions] = await Promise.all([ db .select({ id: contas.id, name: contas.name, accountType: contas.accountType, status: contas.status, note: contas.note, logo: contas.logo, initialBalance: contas.initialBalance, excludeFromBalance: contas.excludeFromBalance, excludeInitialBalanceFromIncome: contas.excludeInitialBalanceFromIncome, balanceMovements: sql` coalesce( sum( case when ${lancamentos.note} = ${INITIAL_BALANCE_NOTE} then 0 else ${lancamentos.amount} end ), 0 ) `, }) .from(contas) .leftJoin( lancamentos, and( eq(lancamentos.contaId, contas.id), eq(lancamentos.userId, userId), eq(lancamentos.isSettled, true), ), ) .leftJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) .where( and( eq(contas.userId, userId), ilike(contas.status, "inativa"), sql`(${lancamentos.id} IS NULL OR ${pagadores.role} = ${PAGADOR_ROLE_ADMIN})`, ), ) .groupBy( contas.id, contas.name, contas.accountType, contas.status, contas.note, contas.logo, contas.initialBalance, contas.excludeFromBalance, contas.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 }; } export async function fetchAllAccountsForUser(userId: string): Promise<{ activeAccounts: AccountData[]; archivedAccounts: AccountData[]; logoOptions: LogoOption[]; }> { const [activeData, archivedData] = await Promise.all([ fetchAccountsForUser(userId), fetchInativosForUser(userId), ]); return { activeAccounts: activeData.accounts, archivedAccounts: archivedData.accounts, logoOptions: activeData.logoOptions, }; }