diff --git a/src/app/(dashboard)/dashboard/page.tsx b/src/app/(dashboard)/dashboard/page.tsx index 33a5296..cc9b408 100644 --- a/src/app/(dashboard)/dashboard/page.tsx +++ b/src/app/(dashboard)/dashboard/page.tsx @@ -10,8 +10,8 @@ import { getSingleParam, } from "@/features/transactions/page-helpers"; import { - fetchLancamentoFilterSources, fetchRecentEstablishments, + fetchTransactionFilterSources, } from "@/features/transactions/queries"; import MonthNavigation from "@/shared/components/month-picker/month-navigation"; import { getUser } from "@/shared/lib/auth/server"; @@ -34,21 +34,21 @@ export default async function Page({ searchParams }: PageProps) { await Promise.all([ fetchDashboardData(user.id, selectedPeriod), fetchUserDashboardPreferences(user.id), - fetchLancamentoFilterSources(user.id), + fetchTransactionFilterSources(user.id), fetchRecentEstablishments(user.id), ]); const { dashboardWidgets } = preferences; const sluggedFilters = buildSluggedFilters(filterSources); const { - pagadorOptions, - splitPagadorOptions, - defaultPagadorId, - contaOptions, - cartaoOptions, - categoriaOptions, + payerOptions, + splitPayerOptions, + defaultPayerId, + accountOptions, + cardOptions, + categoryOptions, } = buildOptionSets({ ...sluggedFilters, - pagadorRows: filterSources.pagadorRows, + payerRows: filterSources.payerRows, }); return ( @@ -61,12 +61,12 @@ export default async function Page({ searchParams }: PageProps) { period={selectedPeriod} initialPreferences={dashboardWidgets} quickActionOptions={{ - pagadorOptions, - splitPagadorOptions, - defaultPagadorId, - contaOptions, - cartaoOptions, - categoriaOptions, + payerOptions, + splitPayerOptions, + defaultPayerId, + accountOptions, + cardOptions, + categoryOptions, estabelecimentos, }} /> diff --git a/src/app/(dashboard)/reports/category-trends/page.tsx b/src/app/(dashboard)/reports/category-trends/page.tsx index c90ddc3..b68969d 100644 --- a/src/app/(dashboard)/reports/category-trends/page.tsx +++ b/src/app/(dashboard)/reports/category-trends/page.tsx @@ -1,5 +1,5 @@ import { redirect } from "next/navigation"; -import type { Categoria } from "@/db/schema"; +import type { Category } from "@/db/schema"; import { fetchCategoryChartData } from "@/features/reports/category-chart-queries"; import { fetchCategoryReport } from "@/features/reports/category-report-queries"; import { fetchUserCategories } from "@/features/reports/category-trends-queries"; @@ -38,7 +38,7 @@ export default async function Page({ searchParams }: PageProps) { // Extract query params const inicioParam = getSingleParam(resolvedSearchParams, "inicio"); const fimParam = getSingleParam(resolvedSearchParams, "fim"); - const categoriasParam = getSingleParam(resolvedSearchParams, "categorias"); + const categoriasParam = getSingleParam(resolvedSearchParams, "categories"); // Calculate default period (last 6 months) const currentPeriod = getCurrentPeriod(); @@ -63,11 +63,11 @@ export default async function Page({ searchParams }: PageProps) { } // Fetch all categories for the user - const categoriaRows = await fetchUserCategories(userId); + const categoryRows = await fetchUserCategories(userId); // Map to CategoryOption format - const categoryOptions: CategoryOption[] = categoriaRows.map( - (cat: Categoria): CategoryOption => ({ + const categoryOptions: CategoryOption[] = categoryRows.map( + (cat: Category): CategoryOption => ({ id: cat.id, name: cat.name, icon: cat.icon, diff --git a/src/app/(dashboard)/reports/establishments/page.tsx b/src/app/(dashboard)/reports/establishments/page.tsx index 16e0d79..8b257bc 100644 --- a/src/app/(dashboard)/reports/establishments/page.tsx +++ b/src/app/(dashboard)/reports/establishments/page.tsx @@ -4,7 +4,7 @@ import { PeriodFilterButtons } from "@/features/reports/components/establishment import { SummaryCards } from "@/features/reports/components/establishments/summary-cards"; import { TopCategories } from "@/features/reports/components/establishments/top-categories"; import { - fetchTopEstabelecimentosData, + fetchTopEstablishmentsData, type PeriodFilter, } from "@/features/reports/establishments/queries"; import { Card } from "@/shared/components/ui/card"; @@ -44,7 +44,7 @@ export default async function TopEstabelecimentosPage({ const { period: currentPeriod } = parsePeriodParam(periodoParam); const periodFilter = validatePeriodFilter(mesesParam); - const data = await fetchTopEstabelecimentosData( + const data = await fetchTopEstablishmentsData( user.id, currentPeriod, periodFilter, diff --git a/src/app/(dashboard)/transactions/page.tsx b/src/app/(dashboard)/transactions/page.tsx index 2a2281a..c268af0 100644 --- a/src/app/(dashboard)/transactions/page.tsx +++ b/src/app/(dashboard)/transactions/page.tsx @@ -1,20 +1,20 @@ import { triggerRecurringGeneration } from "@/features/recurring/trigger-recurring-generation"; import { fetchUserPreferences } from "@/features/settings/queries"; -import { LancamentosPage } from "@/features/transactions/components/page/transactions-page"; +import { TransactionsPage } from "@/features/transactions/components/page/transactions-page"; import { - buildLancamentoWhere, + buildTransactionWhere, buildOptionSets, buildSluggedFilters, buildSlugMaps, - extractLancamentoSearchFilters, + extractTransactionSearchFilters, getSingleParam, - mapLancamentosData, + mapTransactionsData, type ResolvedSearchParams, } from "@/features/transactions/page-helpers"; import { - fetchLancamentoFilterSources, - fetchLancamentos, fetchRecentEstablishments, + fetchTransactionFilterSources, + fetchTransactions, } from "@/features/transactions/queries"; import MonthNavigation from "@/shared/components/month-picker/month-navigation"; import { getUserId } from "@/shared/lib/auth/server"; @@ -34,63 +34,63 @@ export default async function Page({ searchParams }: PageProps) { const periodoParamRaw = getSingleParam(resolvedSearchParams, "periodo"); const { period: selectedPeriod } = parsePeriodParam(periodoParamRaw); - const searchFilters = extractLancamentoSearchFilters(resolvedSearchParams); + const searchFilters = extractTransactionSearchFilters(resolvedSearchParams); const [filterSources, userPreferences] = await Promise.all([ - fetchLancamentoFilterSources(userId), + fetchTransactionFilterSources(userId), fetchUserPreferences(userId), ]); const sluggedFilters = buildSluggedFilters(filterSources); const slugMaps = buildSlugMaps(sluggedFilters); - const filters = buildLancamentoWhere({ + const filters = buildTransactionWhere({ userId, period: selectedPeriod, filters: searchFilters, slugMaps, }); - const [lancamentoRows, estabelecimentos] = await Promise.all([ - fetchLancamentos(filters), + const [transactionRows, estabelecimentos] = await Promise.all([ + fetchTransactions(filters), fetchRecentEstablishments(userId), ]); - const lancamentosData = mapLancamentosData(lancamentoRows); + const transactionData = mapTransactionsData(transactionRows); const { - pagadorOptions, - splitPagadorOptions, - defaultPagadorId, - contaOptions, - cartaoOptions, - categoriaOptions, - pagadorFilterOptions, - categoriaFilterOptions, - contaCartaoFilterOptions, + payerOptions, + splitPayerOptions, + defaultPayerId, + accountOptions, + cardOptions, + categoryOptions, + payerFilterOptions, + categoryFilterOptions, + accountCardFilterOptions, } = buildOptionSets({ ...sluggedFilters, - pagadorRows: filterSources.pagadorRows, + payerRows: filterSources.payerRows, }); return (
-
); diff --git a/src/features/calendar/components/calendar-legend.tsx b/src/features/calendar/components/calendar-legend.tsx index 12a1e38..dcc763d 100644 --- a/src/features/calendar/components/calendar-legend.tsx +++ b/src/features/calendar/components/calendar-legend.tsx @@ -10,9 +10,9 @@ const LEGEND_ITEMS: Array<{ label: string; dotColor?: string; }> = [ - { type: "lancamento", label: "Lançamentos" }, + { type: "transaction", label: "Lançamentos" }, { type: "boleto", label: "Boleto com vencimento" }, - { type: "cartao", label: "Vencimento de cartão" }, + { type: "card", label: "Vencimento de cartão" }, { label: "Pagamento fatura", dotColor: "bg-success" }, ]; diff --git a/src/features/calendar/components/day-cell.tsx b/src/features/calendar/components/day-cell.tsx index cd4b7b7..41093b5 100644 --- a/src/features/calendar/components/day-cell.tsx +++ b/src/features/calendar/components/day-cell.tsx @@ -16,7 +16,7 @@ export const EVENT_TYPE_STYLES: Record< CalendarEvent["type"], { wrapper: string; dot: string; accent?: string } > = { - lancamento: { + transaction: { wrapper: "bg-warning/10 text-warning dark:bg-warning/5 dark:text-warning border-l-4 border-warning", dot: "bg-warning", @@ -26,7 +26,7 @@ export const EVENT_TYPE_STYLES: Record< "bg-info/10 text-info dark:bg-info/5 dark:text-info border-l-4 border-info", dot: "bg-info", }, - cartao: { + card: { wrapper: "bg-violet-100 text-violet-600 dark:bg-violet-900/10 dark:text-violet-50 border-l-4 border-violet-500", dot: "bg-violet-600", @@ -38,18 +38,18 @@ const eventStyles = EVENT_TYPE_STYLES; const formatCurrencyValue = (value: number | null | undefined) => currencyFormatter.format(Math.abs(value ?? 0)); -const formatAmount = (event: Extract) => - formatCurrencyValue(event.lancamento.amount); +const formatAmount = (event: Extract) => + formatCurrencyValue(event.transaction.amount); const buildEventLabel = (event: CalendarEvent) => { switch (event.type) { - case "lancamento": { - return event.lancamento.name; + case "transaction": { + return event.transaction.name; } case "boleto": { - return event.lancamento.name; + return event.transaction.name; } - case "cartao": { + case "card": { return event.card.name; } default: @@ -59,13 +59,13 @@ const buildEventLabel = (event: CalendarEvent) => { const buildEventComplement = (event: CalendarEvent) => { switch (event.type) { - case "lancamento": { + case "transaction": { return formatAmount(event); } case "boleto": { - return formatCurrencyValue(event.lancamento.amount); + return formatCurrencyValue(event.transaction.amount); } - case "cartao": { + case "card": { if (event.card.totalDue !== null) { return formatCurrencyValue(event.card.totalDue); } @@ -78,8 +78,8 @@ const buildEventComplement = (event: CalendarEvent) => { const isPagamentoFatura = (event: CalendarEvent) => { return ( - event.type === "lancamento" && - event.lancamento.name.startsWith("Pagamento fatura -") + event.type === "transaction" && + event.transaction.name.startsWith("Pagamento fatura -") ); }; diff --git a/src/features/calendar/components/event-modal.tsx b/src/features/calendar/components/event-modal.tsx index d7885ab..4898afa 100644 --- a/src/features/calendar/components/event-modal.tsx +++ b/src/features/calendar/components/event-modal.tsx @@ -50,14 +50,14 @@ const EventCard = ({ }; const renderLancamento = ( - event: Extract, + event: Extract, ) => { - const isReceita = event.lancamento.transactionType === "Receita"; + const isReceita = event.transaction.transactionType === "Receita"; const isPagamentoFatura = - event.lancamento.name.startsWith("Pagamento fatura -"); + event.transaction.name.startsWith("Pagamento fatura -"); return ( - +
- {event.lancamento.name} + {event.transaction.name}
- {event.lancamento.condition} - {event.lancamento.paymentMethod} - {event.lancamento.categoriaName} + {event.transaction.condition} + {event.transaction.paymentMethod} + {event.transaction.categoriaName}
@@ -92,8 +92,8 @@ const renderLancamento = ( }; const renderBoleto = (event: Extract) => { - const isPaid = Boolean(event.lancamento.isSettled); - const dueDate = event.lancamento.dueDate; + const isPaid = Boolean(event.transaction.isSettled); + const dueDate = event.transaction.dueDate; const dueDateLabel = formatFinancialDateLabel(dueDate, "Vence em", { day: "2-digit", month: "2-digit", @@ -106,7 +106,7 @@ const renderBoleto = (event: Extract) => {
- {event.lancamento.name} + {event.transaction.name} {dueDateLabel && ( @@ -119,24 +119,24 @@ const renderBoleto = (event: Extract) => { {isPaid ? "Pago" : "Pendente"}
- +
); }; -const renderCard = (event: Extract) => ( - +const renderCard = (event: Extract) => ( +
- Vencimento Fatura - {event.card.name} + Vencimento Invoice - {event.card.name}
- {event.card.status ?? "Fatura"} + {event.card.status ?? "Invoice"}
{event.card.totalDue !== null ? ( @@ -149,11 +149,11 @@ const renderCard = (event: Extract) => ( const renderEvent = (event: CalendarEvent) => { switch (event.type) { - case "lancamento": + case "transaction": return renderLancamento(event); case "boleto": return renderBoleto(event); - case "cartao": + case "card": return renderCard(event); default: return null; diff --git a/src/features/calendar/components/monthly-calendar.tsx b/src/features/calendar/components/monthly-calendar.tsx index 819ac1f..6f7d9c5 100644 --- a/src/features/calendar/components/monthly-calendar.tsx +++ b/src/features/calendar/components/monthly-calendar.tsx @@ -4,7 +4,7 @@ import { useMemo, useState } from "react"; import { CalendarGrid } from "@/features/calendar/components/calendar-grid"; import { CalendarLegend } from "@/features/calendar/components/calendar-legend"; import { EventModal } from "@/features/calendar/components/event-modal"; -import { LancamentoDialog } from "@/features/transactions/components/dialogs/transaction-dialog/transaction-dialog"; +import { TransactionDialog } from "@/features/transactions/components/dialogs/transaction-dialog/transaction-dialog"; import type { CalendarDay, CalendarEvent, @@ -93,16 +93,16 @@ export function MonthlyCalendar({ onCreate={handleOpenCreate} /> - (); - for (const item of lancamentosData) { + for (const item of transactionData) { if ( - !item.cartaoId || + !item.cardId || item.period !== period || - item.pagadorRole !== PAGADOR_ROLE_ADMIN + item.pagadorRole !== PAYER_ROLE_ADMIN ) { continue; } const amount = Math.abs(item.amount ?? 0); - cardTotals.set( - item.cartaoId, - (cardTotals.get(item.cartaoId) ?? 0) + amount, - ); + cardTotals.set(item.cardId, (cardTotals.get(item.cardId) ?? 0) + amount); } - for (const item of lancamentosData) { + for (const item of transactionData) { const isBoleto = item.paymentMethod === PAYMENT_METHOD_BOLETO; - const isAdminPagador = item.pagadorRole === PAGADOR_ROLE_ADMIN; + const isAdminPagador = item.pagadorRole === PAYER_ROLE_ADMIN; // Para boletos, exibir apenas na data de vencimento e apenas se for pagador admin if (isBoleto) { @@ -117,7 +114,7 @@ export const fetchCalendarData = async ({ id: `${item.id}:boleto`, type: "boleto", date: item.dueDate, - lancamento: item, + transaction: item, }); } } else { @@ -129,9 +126,9 @@ export const fetchCalendarData = async ({ if (isWithinRange(purchaseDateKey, rangeStartKey, rangeEndKey)) { events.push({ id: item.id, - type: "lancamento", + type: "transaction", date: purchaseDateKey, - lancamento: item, + transaction: item, }); } } @@ -155,7 +152,7 @@ export const fetchCalendarData = async ({ events.push({ id: `${card.id}:cartao`, - type: "cartao", + type: "card", date: dueDateKey, card: { id: card.id, @@ -171,9 +168,9 @@ export const fetchCalendarData = async ({ } const typePriority: Record = { - lancamento: 0, + transaction: 0, boleto: 1, - cartao: 2, + card: 2, }; events.sort((a, b) => { @@ -186,7 +183,7 @@ export const fetchCalendarData = async ({ const sluggedFilters = buildSluggedFilters(filterSources); const optionSets = buildOptionSets({ ...sluggedFilters, - pagadorRows: filterSources.pagadorRows, + payerRows: filterSources.payerRows, }); const estabelecimentos = await fetchRecentEstablishments(userId); @@ -194,12 +191,12 @@ export const fetchCalendarData = async ({ return { events, formOptions: { - pagadorOptions: optionSets.pagadorOptions, - splitPagadorOptions: optionSets.splitPagadorOptions, - defaultPagadorId: optionSets.defaultPagadorId, - contaOptions: optionSets.contaOptions, - cartaoOptions: optionSets.cartaoOptions, - categoriaOptions: optionSets.categoriaOptions, + payerOptions: optionSets.payerOptions, + splitPayerOptions: optionSets.splitPayerOptions, + defaultPayerId: optionSets.defaultPayerId, + accountOptions: optionSets.accountOptions, + cardOptions: optionSets.cardOptions, + categoryOptions: optionSets.categoryOptions, estabelecimentos, }, }; diff --git a/src/features/dashboard/accounts-queries.ts b/src/features/dashboard/accounts-queries.ts index dbb5f94..bf50fcc 100644 --- a/src/features/dashboard/accounts-queries.ts +++ b/src/features/dashboard/accounts-queries.ts @@ -1,8 +1,8 @@ import { and, eq, sql } from "drizzle-orm"; -import { contas, lancamentos, pagadores } from "@/db/schema"; +import { financialAccounts, payers, transactions } from "@/db/schema"; import { INITIAL_BALANCE_NOTE } from "@/shared/lib/accounts/constants"; import { db } from "@/shared/lib/db"; -import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; +import { PAYER_ROLE_ADMIN } from "@/shared/lib/payers/constants"; import { safeToNumber as toNumber } from "@/shared/utils/number"; type RawDashboardAccount = { @@ -36,49 +36,49 @@ export async function fetchDashboardAccounts( ): Promise { const rows = await db .select({ - id: contas.id, - name: contas.name, - accountType: contas.accountType, - status: contas.status, - logo: contas.logo, - initialBalance: contas.initialBalance, - excludeFromBalance: contas.excludeFromBalance, + id: financialAccounts.id, + name: financialAccounts.name, + accountType: financialAccounts.accountType, + status: financialAccounts.status, + logo: financialAccounts.logo, + initialBalance: financialAccounts.initialBalance, + excludeFromBalance: financialAccounts.excludeFromBalance, balanceMovements: sql` coalesce( sum( case - when ${lancamentos.note} = ${INITIAL_BALANCE_NOTE} then 0 - else ${lancamentos.amount} + when ${transactions.note} = ${INITIAL_BALANCE_NOTE} then 0 + else ${transactions.amount} end ), 0 ) `, }) - .from(contas) + .from(financialAccounts) .leftJoin( - lancamentos, + transactions, and( - eq(lancamentos.contaId, contas.id), - eq(lancamentos.userId, userId), - eq(lancamentos.isSettled, true), + eq(transactions.accountId, financialAccounts.id), + eq(transactions.userId, userId), + eq(transactions.isSettled, true), ), ) - .leftJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) + .leftJoin(payers, eq(transactions.payerId, payers.id)) .where( and( - eq(contas.userId, userId), - sql`(${lancamentos.id} IS NULL OR ${pagadores.role} = ${PAGADOR_ROLE_ADMIN})`, + eq(financialAccounts.userId, userId), + sql`(${transactions.id} IS NULL OR ${payers.role} = ${PAYER_ROLE_ADMIN})`, ), ) .groupBy( - contas.id, - contas.name, - contas.accountType, - contas.status, - contas.logo, - contas.initialBalance, - contas.excludeFromBalance, + financialAccounts.id, + financialAccounts.name, + financialAccounts.accountType, + financialAccounts.status, + financialAccounts.logo, + financialAccounts.initialBalance, + financialAccounts.excludeFromBalance, ); const accounts = rows diff --git a/src/features/dashboard/bills-queries.ts b/src/features/dashboard/bills-queries.ts index 39fef73..6ed5efd 100644 --- a/src/features/dashboard/bills-queries.ts +++ b/src/features/dashboard/bills-queries.ts @@ -1,9 +1,9 @@ "use server"; import { and, asc, eq } from "drizzle-orm"; -import { lancamentos } from "@/db/schema"; +import { transactions } from "@/db/schema"; import { db } from "@/shared/lib/db"; -import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { getAdminPayerId } from "@/shared/lib/payers/get-admin-id"; import { toDateOnlyString } from "@/shared/utils/date"; import { safeToNumber as toNumber } from "@/shared/utils/number"; @@ -37,33 +37,33 @@ export async function fetchDashboardBills( userId: string, period: string, ): Promise { - const adminPagadorId = await getAdminPagadorId(userId); - if (!adminPagadorId) { + const adminPayerId = await getAdminPayerId(userId); + if (!adminPayerId) { return { bills: [], totalPendingAmount: 0, pendingCount: 0 }; } const rows = await db .select({ - id: lancamentos.id, - name: lancamentos.name, - amount: lancamentos.amount, - dueDate: lancamentos.dueDate, - boletoPaymentDate: lancamentos.boletoPaymentDate, - isSettled: lancamentos.isSettled, + id: transactions.id, + name: transactions.name, + amount: transactions.amount, + dueDate: transactions.dueDate, + boletoPaymentDate: transactions.boletoPaymentDate, + isSettled: transactions.isSettled, }) - .from(lancamentos) + .from(transactions) .where( and( - eq(lancamentos.userId, userId), - eq(lancamentos.period, period), - eq(lancamentos.paymentMethod, PAYMENT_METHOD_BOLETO), - eq(lancamentos.pagadorId, adminPagadorId), + eq(transactions.userId, userId), + eq(transactions.period, period), + eq(transactions.paymentMethod, PAYMENT_METHOD_BOLETO), + eq(transactions.payerId, adminPayerId), ), ) .orderBy( - asc(lancamentos.isSettled), - asc(lancamentos.dueDate), - asc(lancamentos.name), + asc(transactions.isSettled), + asc(transactions.dueDate), + asc(transactions.name), ); const bills = rows.map((row: RawDashboardBill): DashboardBill => { diff --git a/src/features/dashboard/categories/category-breakdown.ts b/src/features/dashboard/categories/category-breakdown.ts index 8751d33..d9c441d 100644 --- a/src/features/dashboard/categories/category-breakdown.ts +++ b/src/features/dashboard/categories/category-breakdown.ts @@ -28,7 +28,7 @@ type CategoryBreakdownRow = { }; type CategoryBudgetRow = { - categoriaId: string | null; + categoryId: string | null; amount: unknown; }; @@ -43,8 +43,8 @@ export function buildCategoryBreakdownData({ }): DashboardCategoryBreakdownData { const budgetMap = new Map(); for (const row of budgetRows) { - if (row.categoriaId) { - budgetMap.set(row.categoriaId, toNumber(row.amount)); + if (row.categoryId) { + budgetMap.set(row.categoryId, toNumber(row.amount)); } } diff --git a/src/features/dashboard/categories/category-details-queries.ts b/src/features/dashboard/categories/category-details-queries.ts index 78fae91..d7093a6 100644 --- a/src/features/dashboard/categories/category-details-queries.ts +++ b/src/features/dashboard/categories/category-details-queries.ts @@ -1,18 +1,23 @@ import { and, desc, eq, isNull, ne, or, sql } from "drizzle-orm"; -import { categorias, contas, lancamentos, pagadores } from "@/db/schema"; -import { mapLancamentosData } from "@/features/transactions/page-helpers"; +import { + categories, + financialAccounts, + payers, + transactions, +} from "@/db/schema"; +import { mapTransactionsData } from "@/features/transactions/page-helpers"; import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX, INITIAL_BALANCE_NOTE, } from "@/shared/lib/accounts/constants"; import type { CategoryType } from "@/shared/lib/categories/constants"; import { db } from "@/shared/lib/db"; -import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; +import { PAYER_ROLE_ADMIN } from "@/shared/lib/payers/constants"; import { calculatePercentageChange } from "@/shared/utils/math"; import { safeToNumber as toNumber } from "@/shared/utils/number"; import { getPreviousPeriod } from "@/shared/utils/period"; -type MappedLancamentos = ReturnType; +type MappedLancamentos = ReturnType; export type CategoryDetailData = { category: { @@ -34,8 +39,8 @@ export async function fetchCategoryDetails( categoryId: string, period: string, ): Promise { - const category = await db.query.categorias.findFirst({ - where: and(eq(categorias.userId, userId), eq(categorias.id, categoryId)), + const category = await db.query.categories.findFirst({ + where: and(eq(categories.userId, userId), eq(categories.id, categoryId)), }); if (!category) { @@ -46,35 +51,35 @@ export async function fetchCategoryDetails( const transactionType = category.type === "receita" ? "Receita" : "Despesa"; const sanitizedNote = or( - isNull(lancamentos.note), - sql`${lancamentos.note} NOT LIKE ${`${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`}`, + isNull(transactions.note), + sql`${transactions.note} NOT LIKE ${`${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`}`, ); - const currentRows = await db.query.lancamentos.findMany({ + const currentRows = await db.query.transactions.findMany({ where: and( - eq(lancamentos.userId, userId), - eq(lancamentos.categoriaId, categoryId), - eq(lancamentos.transactionType, transactionType), - eq(lancamentos.period, period), + eq(transactions.userId, userId), + eq(transactions.categoryId, categoryId), + eq(transactions.transactionType, transactionType), + eq(transactions.period, period), sanitizedNote, ), with: { - pagador: true, - conta: true, - cartao: true, - categoria: true, + payer: true, + financialAccount: true, + card: true, + category: true, }, - orderBy: [desc(lancamentos.purchaseDate), desc(lancamentos.createdAt)], + orderBy: [desc(transactions.purchaseDate), desc(transactions.createdAt)], }); const filteredRows = currentRows.filter((row) => { - // Filtrar apenas pagadores admin - if (row.pagador?.role !== PAGADOR_ROLE_ADMIN) return false; + // Filtrar apenas payers admin + if (row.payer?.role !== PAYER_ROLE_ADMIN) return false; // Excluir saldos iniciais se a conta tiver o flag ativo if ( row.note === INITIAL_BALANCE_NOTE && - row.conta?.excludeInitialBalanceFromIncome + row.financialAccount?.excludeInitialBalanceFromIncome ) { return false; } @@ -82,33 +87,36 @@ export async function fetchCategoryDetails( return true; }); - const transactions = mapLancamentosData(filteredRows); + const transactionList = mapTransactionsData(filteredRows); - const currentTotal = transactions.reduce( + const currentTotal = transactionList.reduce( (total, transaction) => total + Math.abs(toNumber(transaction.amount)), 0, ); const [previousTotalRow] = await db .select({ - total: sql`coalesce(sum(${lancamentos.amount}), 0)`, + total: sql`coalesce(sum(${transactions.amount}), 0)`, }) - .from(lancamentos) - .innerJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) - .leftJoin(contas, eq(lancamentos.contaId, contas.id)) + .from(transactions) + .innerJoin(payers, eq(transactions.payerId, payers.id)) + .leftJoin( + financialAccounts, + eq(transactions.accountId, financialAccounts.id), + ) .where( and( - eq(lancamentos.userId, userId), - eq(lancamentos.categoriaId, categoryId), - eq(lancamentos.transactionType, transactionType), - eq(pagadores.role, PAGADOR_ROLE_ADMIN), + eq(transactions.userId, userId), + eq(transactions.categoryId, categoryId), + eq(transactions.transactionType, transactionType), + eq(payers.role, PAYER_ROLE_ADMIN), sanitizedNote, - eq(lancamentos.period, previousPeriod), + eq(transactions.period, previousPeriod), // Excluir saldos iniciais se a conta tiver o flag ativo or( - ne(lancamentos.note, INITIAL_BALANCE_NOTE), - isNull(contas.excludeInitialBalanceFromIncome), - eq(contas.excludeInitialBalanceFromIncome, false), + ne(transactions.note, INITIAL_BALANCE_NOTE), + isNull(financialAccounts.excludeInitialBalanceFromIncome), + eq(financialAccounts.excludeInitialBalanceFromIncome, false), ), ), ); @@ -131,6 +139,6 @@ export async function fetchCategoryDetails( currentTotal, previousTotal, percentageChange, - transactions, + transactions: transactionList, }; } diff --git a/src/features/dashboard/categories/category-history-queries.ts b/src/features/dashboard/categories/category-history-queries.ts index 999d159..507ec33 100644 --- a/src/features/dashboard/categories/category-history-queries.ts +++ b/src/features/dashboard/categories/category-history-queries.ts @@ -1,8 +1,8 @@ import { and, eq, inArray, isNull, or, sql } from "drizzle-orm"; -import { categorias, lancamentos, pagadores } from "@/db/schema"; +import { categories, payers, transactions } from "@/db/schema"; import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/shared/lib/accounts/constants"; import { db } from "@/shared/lib/db"; -import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; +import { PAYER_ROLE_ADMIN } from "@/shared/lib/payers/constants"; import { CATEGORY_COLORS } from "@/shared/utils/category-colors"; import { safeToNumber as toNumber } from "@/shared/utils/number"; import { @@ -56,14 +56,14 @@ export async function fetchAllCategories( ): Promise { const result = await db .select({ - id: categorias.id, - name: categorias.name, - icon: categorias.icon, - type: categorias.type, + id: categories.id, + name: categories.name, + icon: categories.icon, + type: categories.type, }) - .from(categorias) - .where(eq(categorias.userId, userId)) - .orderBy(categorias.type, categorias.name); + .from(categories) + .where(eq(categories.userId, userId)) + .orderBy(categories.type, categories.name); return result as CategoryOption[]; } @@ -88,36 +88,36 @@ export async function fetchCategoryHistory( // Fetch monthly data for ALL categories with transactions const monthlyDataQuery = (await db .select({ - categoryId: categorias.id, - categoryName: categorias.name, - categoryIcon: categorias.icon, - period: lancamentos.period, - totalAmount: sql`SUM(ABS(${lancamentos.amount}))`.as( + categoryId: categories.id, + categoryName: categories.name, + categoryIcon: categories.icon, + period: transactions.period, + totalAmount: sql`SUM(ABS(${transactions.amount}))`.as( "total_amount", ), }) - .from(lancamentos) - .innerJoin(categorias, eq(lancamentos.categoriaId, categorias.id)) - .innerJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) + .from(transactions) + .innerJoin(categories, eq(transactions.categoryId, categories.id)) + .innerJoin(payers, eq(transactions.payerId, payers.id)) .where( and( - eq(lancamentos.userId, userId), - eq(categorias.userId, userId), - inArray(lancamentos.period, periods), - eq(pagadores.role, PAGADOR_ROLE_ADMIN), + eq(transactions.userId, userId), + eq(categories.userId, userId), + inArray(transactions.period, periods), + eq(payers.role, PAYER_ROLE_ADMIN), or( - isNull(lancamentos.note), + isNull(transactions.note), sql`${ - lancamentos.note + transactions.note } NOT LIKE ${`${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`}`, ), ), ) .groupBy( - categorias.id, - categorias.name, - categorias.icon, - lancamentos.period, + categories.id, + categories.name, + categories.icon, + transactions.period, )) as MonthlyCategoryRow[]; if (monthlyDataQuery.length === 0) { diff --git a/src/features/dashboard/categories/expenses-by-category-queries.ts b/src/features/dashboard/categories/expenses-by-category-queries.ts index 925a4a9..ef37b43 100644 --- a/src/features/dashboard/categories/expenses-by-category-queries.ts +++ b/src/features/dashboard/categories/expenses-by-category-queries.ts @@ -1,5 +1,5 @@ import { and, eq, inArray, sql } from "drizzle-orm"; -import { categorias, lancamentos, orcamentos } from "@/db/schema"; +import { budgets, categories, transactions } from "@/db/schema"; import { buildCategoryBreakdownData, type DashboardCategoryBreakdownData, @@ -8,9 +8,9 @@ import { import { buildDashboardAdminFilters, excludeAutoInvoiceEntries, -} from "@/features/dashboard/lancamento-filters"; +} from "@/features/dashboard/transaction-filters"; import { db } from "@/shared/lib/db"; -import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { getAdminPayerId } from "@/shared/lib/payers/get-admin-id"; import { getPreviousPeriod } from "@/shared/utils/period"; export type CategoryExpenseItem = DashboardCategoryBreakdownItem; @@ -22,45 +22,45 @@ export async function fetchExpensesByCategory( ): Promise { const previousPeriod = getPreviousPeriod(period); - const adminPagadorId = await getAdminPagadorId(userId); - if (!adminPagadorId) { + const adminPayerId = await getAdminPayerId(userId); + if (!adminPayerId) { return { categories: [], currentTotal: 0, previousTotal: 0 }; } - // Single query: GROUP BY categoriaId + period for both current and previous periods + // Single query: GROUP BY categoryId + period for both current and previous periods const [rows, budgetRows] = await Promise.all([ db .select({ - categoryId: categorias.id, - categoryName: categorias.name, - categoryIcon: categorias.icon, - period: lancamentos.period, - total: sql`coalesce(sum(${lancamentos.amount}), 0)`, + categoryId: categories.id, + categoryName: categories.name, + categoryIcon: categories.icon, + period: transactions.period, + total: sql`coalesce(sum(${transactions.amount}), 0)`, }) - .from(lancamentos) - .innerJoin(categorias, eq(lancamentos.categoriaId, categorias.id)) + .from(transactions) + .innerJoin(categories, eq(transactions.categoryId, categories.id)) .where( and( - ...buildDashboardAdminFilters({ userId, adminPagadorId }), - inArray(lancamentos.period, [period, previousPeriod]), - eq(lancamentos.transactionType, "Despesa"), - eq(categorias.type, "despesa"), + ...buildDashboardAdminFilters({ userId, adminPayerId }), + inArray(transactions.period, [period, previousPeriod]), + eq(transactions.transactionType, "Despesa"), + eq(categories.type, "despesa"), excludeAutoInvoiceEntries(), ), ) .groupBy( - categorias.id, - categorias.name, - categorias.icon, - lancamentos.period, + categories.id, + categories.name, + categories.icon, + transactions.period, ), db .select({ - categoriaId: orcamentos.categoriaId, - amount: orcamentos.amount, + categoryId: budgets.categoryId, + amount: budgets.amount, }) - .from(orcamentos) - .where(and(eq(orcamentos.userId, userId), eq(orcamentos.period, period))), + .from(budgets) + .where(and(eq(budgets.userId, userId), eq(budgets.period, period))), ]); return buildCategoryBreakdownData({ diff --git a/src/features/dashboard/categories/income-by-category-queries.ts b/src/features/dashboard/categories/income-by-category-queries.ts index cb2e9ec..7c2084b 100644 --- a/src/features/dashboard/categories/income-by-category-queries.ts +++ b/src/features/dashboard/categories/income-by-category-queries.ts @@ -1,5 +1,10 @@ import { and, eq, inArray, sql } from "drizzle-orm"; -import { categorias, contas, lancamentos, orcamentos } from "@/db/schema"; +import { + budgets, + categories, + financialAccounts, + transactions, +} from "@/db/schema"; import { buildCategoryBreakdownData, type DashboardCategoryBreakdownData, @@ -9,9 +14,9 @@ import { buildDashboardAdminFilters, excludeAutoInvoiceEntries, excludeInitialBalanceWhenConfigured, -} from "@/features/dashboard/lancamento-filters"; +} from "@/features/dashboard/transaction-filters"; import { db } from "@/shared/lib/db"; -import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { getAdminPayerId } from "@/shared/lib/payers/get-admin-id"; import { getPreviousPeriod } from "@/shared/utils/period"; export type CategoryIncomeItem = DashboardCategoryBreakdownItem; @@ -23,47 +28,50 @@ export async function fetchIncomeByCategory( ): Promise { const previousPeriod = getPreviousPeriod(period); - const adminPagadorId = await getAdminPagadorId(userId); - if (!adminPagadorId) { + const adminPayerId = await getAdminPayerId(userId); + if (!adminPayerId) { return { categories: [], currentTotal: 0, previousTotal: 0 }; } - // Single query: GROUP BY categoriaId + period for both current and previous periods + // Single query: GROUP BY categoryId + period for both current and previous periods const [rows, budgetRows] = await Promise.all([ db .select({ - categoryId: categorias.id, - categoryName: categorias.name, - categoryIcon: categorias.icon, - period: lancamentos.period, - total: sql`coalesce(sum(${lancamentos.amount}), 0)`, + categoryId: categories.id, + categoryName: categories.name, + categoryIcon: categories.icon, + period: transactions.period, + total: sql`coalesce(sum(${transactions.amount}), 0)`, }) - .from(lancamentos) - .innerJoin(categorias, eq(lancamentos.categoriaId, categorias.id)) - .leftJoin(contas, eq(lancamentos.contaId, contas.id)) + .from(transactions) + .innerJoin(categories, eq(transactions.categoryId, categories.id)) + .leftJoin( + financialAccounts, + eq(transactions.accountId, financialAccounts.id), + ) .where( and( - ...buildDashboardAdminFilters({ userId, adminPagadorId }), - inArray(lancamentos.period, [period, previousPeriod]), - eq(lancamentos.transactionType, "Receita"), - eq(categorias.type, "receita"), + ...buildDashboardAdminFilters({ userId, adminPayerId }), + inArray(transactions.period, [period, previousPeriod]), + eq(transactions.transactionType, "Receita"), + eq(categories.type, "receita"), excludeAutoInvoiceEntries(), excludeInitialBalanceWhenConfigured(), ), ) .groupBy( - categorias.id, - categorias.name, - categorias.icon, - lancamentos.period, + categories.id, + categories.name, + categories.icon, + transactions.period, ), db .select({ - categoriaId: orcamentos.categoriaId, - amount: orcamentos.amount, + categoryId: budgets.categoryId, + amount: budgets.amount, }) - .from(orcamentos) - .where(and(eq(orcamentos.userId, userId), eq(orcamentos.period, period))), + .from(budgets) + .where(and(eq(budgets.userId, userId), eq(budgets.period, period))), ]); return buildCategoryBreakdownData({ diff --git a/src/features/dashboard/components/dashboard-grid-editable.tsx b/src/features/dashboard/components/dashboard-grid-editable.tsx index 8373292..d12cf26 100644 --- a/src/features/dashboard/components/dashboard-grid-editable.tsx +++ b/src/features/dashboard/components/dashboard-grid-editable.tsx @@ -38,7 +38,7 @@ import { widgetsConfig, } from "@/features/dashboard/widgets/widgets-config"; import { NoteDialog } from "@/features/notes/components/note-dialog"; -import { LancamentoDialog } from "@/features/transactions/components/dialogs/transaction-dialog/transaction-dialog"; +import { TransactionDialog } from "@/features/transactions/components/dialogs/transaction-dialog/transaction-dialog"; import type { SelectOption } from "@/features/transactions/components/types"; import { ExpandableWidgetCard } from "@/shared/components/expandable-widget-card"; import { Button } from "@/shared/components/ui/button"; @@ -48,12 +48,12 @@ type DashboardGridEditableProps = { period: string; initialPreferences: WidgetPreferences | null; quickActionOptions: { - pagadorOptions: SelectOption[]; - splitPagadorOptions: SelectOption[]; - defaultPagadorId: string | null; - contaOptions: SelectOption[]; - cartaoOptions: SelectOption[]; - categoriaOptions: SelectOption[]; + payerOptions: SelectOption[]; + splitPayerOptions: SelectOption[]; + defaultPayerId: string | null; + accountOptions: SelectOption[]; + cardOptions: SelectOption[]; + categoryOptions: SelectOption[]; estabelecimentos: string[]; }; }; @@ -203,14 +203,14 @@ export function DashboardGridEditable({ Ações rápidas
- } /> - (
  • diff --git a/src/features/dashboard/components/invoices/invoice-payment-dialog.tsx b/src/features/dashboard/components/invoices/invoice-payment-dialog.tsx index 5abc47f..731ca17 100644 --- a/src/features/dashboard/components/invoices/invoice-payment-dialog.tsx +++ b/src/features/dashboard/components/invoices/invoice-payment-dialog.tsx @@ -146,7 +146,7 @@ export function InvoicePaymentDialog({
    - Valor da Fatura + Valor da Invoice
    - {`Logo + {logoSrc ? ( + {`Logo + ) : null}
    diff --git a/src/features/dashboard/components/payers-widget.tsx b/src/features/dashboard/components/payers-widget.tsx index f36771a..d358a27 100644 --- a/src/features/dashboard/components/payers-widget.tsx +++ b/src/features/dashboard/components/payers-widget.tsx @@ -21,7 +21,7 @@ import { getAvatarSrc } from "@/shared/lib/payers/utils"; import { formatPercentage } from "@/shared/utils/percentage"; type PayersWidgetProps = { - pagadores: DashboardPagador[]; + payers: DashboardPagador[]; }; const buildInitials = (value: string) => { @@ -38,10 +38,10 @@ const buildInitials = (value: string) => { return `${firstChar}${secondChar}`.toUpperCase() || "??"; }; -export function PayersWidget({ pagadores }: PayersWidgetProps) { +export function PayersWidget({ payers }: PayersWidgetProps) { return ( - {pagadores.length === 0 ? ( + {payers.length === 0 ? ( } title="Nenhum pagador para o período" @@ -49,25 +49,25 @@ export function PayersWidget({ pagadores }: PayersWidgetProps) { /> ) : (
      - {pagadores.map((pagador) => { - const initials = buildInitials(pagador.name); + {payers.map((payer) => { + const initials = buildInitials(payer.name); const hasValidPercentageChange = - typeof pagador.percentageChange === "number" && - Number.isFinite(pagador.percentageChange); + typeof payer.percentageChange === "number" && + Number.isFinite(payer.percentageChange); const percentageChange = hasValidPercentageChange - ? pagador.percentageChange + ? payer.percentageChange : null; return (
    • {initials} @@ -75,13 +75,11 @@ export function PayersWidget({ pagadores }: PayersWidgetProps) {
      - - {pagador.name} - - {pagador.isAdmin && ( + {payer.name} + {payer.isAdmin && (

      - {pagador.email ?? "Sem email cadastrado"} + {payer.email ?? "Sem email cadastrado"}

      - + {percentageChange !== null && ( { const previousPeriod = getPreviousPeriod(period); - const adminPagadorId = await getAdminPagadorId(userId); - if (!adminPagadorId) { + const adminPayerId = await getAdminPayerId(userId); + if (!adminPayerId) { return { period, previousPeriod, @@ -88,24 +88,27 @@ export async function fetchDashboardCardMetrics( const rows = await db .select({ - period: lancamentos.period, - transactionType: lancamentos.transactionType, - totalAmount: sum(lancamentos.amount).as("total"), + period: transactions.period, + transactionType: transactions.transactionType, + totalAmount: sum(transactions.amount).as("total"), }) - .from(lancamentos) - .leftJoin(contas, eq(lancamentos.contaId, contas.id)) + .from(transactions) + .leftJoin( + financialAccounts, + eq(transactions.accountId, financialAccounts.id), + ) .where( and( - ...buildDashboardAdminFilters({ userId, adminPagadorId }), - gte(lancamentos.period, startPeriod), - lte(lancamentos.period, period), - ne(lancamentos.transactionType, TRANSFERENCIA), + ...buildDashboardAdminFilters({ userId, adminPayerId }), + gte(transactions.period, startPeriod), + lte(transactions.period, period), + ne(transactions.transactionType, TRANSFERENCIA), excludeAutoInvoiceEntries(), excludeInitialBalanceWhenConfigured(), ), ) - .groupBy(lancamentos.period, lancamentos.transactionType) - .orderBy(asc(lancamentos.period), asc(lancamentos.transactionType)); + .groupBy(transactions.period, transactions.transactionType) + .orderBy(asc(transactions.period), asc(transactions.transactionType)); const periodTotals = new Map(); diff --git a/src/features/dashboard/expenses/installment-analysis-queries.ts b/src/features/dashboard/expenses/installment-analysis-queries.ts index 8eac629..7a2102e 100644 --- a/src/features/dashboard/expenses/installment-analysis-queries.ts +++ b/src/features/dashboard/expenses/installment-analysis-queries.ts @@ -1,11 +1,11 @@ import { and, eq, isNotNull, isNull, or, sql } from "drizzle-orm"; -import { cartoes, lancamentos, pagadores } from "@/db/schema"; +import { cards, payers, transactions } from "@/db/schema"; import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX, INITIAL_BALANCE_NOTE, } from "@/shared/lib/accounts/constants"; import { db } from "@/shared/lib/db"; -import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; +import { PAYER_ROLE_ADMIN } from "@/shared/lib/payers/constants"; import { buildDateOnlyStringFromPeriodDay, parseLocalDateString, @@ -46,7 +46,7 @@ export type InstallmentGroup = { seriesId: string; name: string; paymentMethod: string; - cartaoId: string | null; + cardId: string | null; cartaoName: string | null; cartaoDueDay: string | null; cartaoLogo: string | null; @@ -68,44 +68,44 @@ export async function fetchInstallmentAnalysis( // 1. Buscar todos os lançamentos parcelados não antecipados do pagador admin const installmentRows = await db .select({ - id: lancamentos.id, - seriesId: lancamentos.seriesId, - name: lancamentos.name, - amount: lancamentos.amount, - paymentMethod: lancamentos.paymentMethod, - currentInstallment: lancamentos.currentInstallment, - installmentCount: lancamentos.installmentCount, - dueDate: lancamentos.dueDate, - period: lancamentos.period, - isAnticipated: lancamentos.isAnticipated, - isSettled: lancamentos.isSettled, - purchaseDate: lancamentos.purchaseDate, - cartaoId: lancamentos.cartaoId, - cartaoName: cartoes.name, - cartaoDueDay: cartoes.dueDay, - cartaoLogo: cartoes.logo, + id: transactions.id, + seriesId: transactions.seriesId, + name: transactions.name, + amount: transactions.amount, + paymentMethod: transactions.paymentMethod, + currentInstallment: transactions.currentInstallment, + installmentCount: transactions.installmentCount, + dueDate: transactions.dueDate, + period: transactions.period, + isAnticipated: transactions.isAnticipated, + isSettled: transactions.isSettled, + purchaseDate: transactions.purchaseDate, + cardId: transactions.cardId, + cartaoName: cards.name, + cartaoDueDay: cards.dueDay, + cartaoLogo: cards.logo, }) - .from(lancamentos) - .leftJoin(cartoes, eq(lancamentos.cartaoId, cartoes.id)) - .leftJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) + .from(transactions) + .leftJoin(cards, eq(transactions.cardId, cards.id)) + .leftJoin(payers, eq(transactions.payerId, payers.id)) .where( and( - eq(lancamentos.userId, userId), - eq(lancamentos.transactionType, "Despesa"), - eq(lancamentos.condition, "Parcelado"), - eq(lancamentos.isAnticipated, false), - isNotNull(lancamentos.seriesId), - eq(pagadores.role, PAGADOR_ROLE_ADMIN), + eq(transactions.userId, userId), + eq(transactions.transactionType, "Despesa"), + eq(transactions.condition, "Parcelado"), + eq(transactions.isAnticipated, false), + isNotNull(transactions.seriesId), + eq(payers.role, PAYER_ROLE_ADMIN), or( - isNull(lancamentos.note), + isNull(transactions.note), and( - sql`${lancamentos.note} != ${INITIAL_BALANCE_NOTE}`, - sql`${lancamentos.note} NOT LIKE ${`${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`}`, + sql`${transactions.note} != ${INITIAL_BALANCE_NOTE}`, + sql`${transactions.note} NOT LIKE ${`${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`}`, ), ), ), ) - .orderBy(lancamentos.purchaseDate, lancamentos.currentInstallment); + .orderBy(transactions.purchaseDate, transactions.currentInstallment); // Agrupar por seriesId const seriesMap = new Map(); @@ -140,7 +140,7 @@ export async function fetchInstallmentAnalysis( seriesId: row.seriesId, name: row.name, paymentMethod: row.paymentMethod, - cartaoId: row.cartaoId, + cardId: row.cardId, cartaoName: row.cartaoName, cartaoDueDay: row.cartaoDueDay, cartaoLogo: row.cartaoLogo, diff --git a/src/features/dashboard/expenses/installment-expenses-queries.ts b/src/features/dashboard/expenses/installment-expenses-queries.ts index 0117891..f239215 100644 --- a/src/features/dashboard/expenses/installment-expenses-queries.ts +++ b/src/features/dashboard/expenses/installment-expenses-queries.ts @@ -1,11 +1,11 @@ import { and, desc, eq, isNull, or, sql } from "drizzle-orm"; -import { lancamentos } from "@/db/schema"; +import { transactions } from "@/db/schema"; import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX, INITIAL_BALANCE_NOTE, } from "@/shared/lib/accounts/constants"; import { db } from "@/shared/lib/db"; -import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { getAdminPayerId } from "@/shared/lib/payers/get-admin-id"; import { safeToNumber as toNumber } from "@/shared/utils/number"; export type InstallmentExpense = { @@ -28,42 +28,42 @@ export async function fetchInstallmentExpenses( userId: string, period: string, ): Promise { - const adminPagadorId = await getAdminPagadorId(userId); - if (!adminPagadorId) { + const adminPayerId = await getAdminPayerId(userId); + if (!adminPayerId) { return { expenses: [] }; } const rows = await db .select({ - id: lancamentos.id, - name: lancamentos.name, - amount: lancamentos.amount, - paymentMethod: lancamentos.paymentMethod, - currentInstallment: lancamentos.currentInstallment, - installmentCount: lancamentos.installmentCount, - dueDate: lancamentos.dueDate, - purchaseDate: lancamentos.purchaseDate, - period: lancamentos.period, + id: transactions.id, + name: transactions.name, + amount: transactions.amount, + paymentMethod: transactions.paymentMethod, + currentInstallment: transactions.currentInstallment, + installmentCount: transactions.installmentCount, + dueDate: transactions.dueDate, + purchaseDate: transactions.purchaseDate, + period: transactions.period, }) - .from(lancamentos) + .from(transactions) .where( and( - eq(lancamentos.userId, userId), - eq(lancamentos.period, period), - eq(lancamentos.transactionType, "Despesa"), - eq(lancamentos.condition, "Parcelado"), - eq(lancamentos.isAnticipated, false), - eq(lancamentos.pagadorId, adminPagadorId), + eq(transactions.userId, userId), + eq(transactions.period, period), + eq(transactions.transactionType, "Despesa"), + eq(transactions.condition, "Parcelado"), + eq(transactions.isAnticipated, false), + eq(transactions.payerId, adminPayerId), or( - isNull(lancamentos.note), + isNull(transactions.note), and( - sql`${lancamentos.note} != ${INITIAL_BALANCE_NOTE}`, - sql`${lancamentos.note} NOT LIKE ${`${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`}`, + sql`${transactions.note} != ${INITIAL_BALANCE_NOTE}`, + sql`${transactions.note} NOT LIKE ${`${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`}`, ), ), ), ) - .orderBy(desc(lancamentos.purchaseDate), desc(lancamentos.createdAt)); + .orderBy(desc(transactions.purchaseDate), desc(transactions.createdAt)); type InstallmentExpenseRow = (typeof rows)[number]; diff --git a/src/features/dashboard/expenses/recurring-expenses-queries.ts b/src/features/dashboard/expenses/recurring-expenses-queries.ts index 9639915..2cfe5cf 100644 --- a/src/features/dashboard/expenses/recurring-expenses-queries.ts +++ b/src/features/dashboard/expenses/recurring-expenses-queries.ts @@ -1,11 +1,11 @@ import { and, desc, eq, isNull, or, sql } from "drizzle-orm"; -import { lancamentos } from "@/db/schema"; +import { transactions } from "@/db/schema"; import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX, INITIAL_BALANCE_NOTE, } from "@/shared/lib/accounts/constants"; import { db } from "@/shared/lib/db"; -import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { getAdminPayerId } from "@/shared/lib/payers/get-admin-id"; import { safeToNumber as toNumber } from "@/shared/utils/number"; export type RecurringExpense = { @@ -24,37 +24,37 @@ export async function fetchRecurringExpenses( userId: string, period: string, ): Promise { - const adminPagadorId = await getAdminPagadorId(userId); - if (!adminPagadorId) { + const adminPayerId = await getAdminPayerId(userId); + if (!adminPayerId) { return { expenses: [] }; } const results = await db .select({ - id: lancamentos.id, - name: lancamentos.name, - amount: lancamentos.amount, - paymentMethod: lancamentos.paymentMethod, - recurrenceCount: lancamentos.recurrenceCount, + id: transactions.id, + name: transactions.name, + amount: transactions.amount, + paymentMethod: transactions.paymentMethod, + recurrenceCount: transactions.recurrenceCount, }) - .from(lancamentos) + .from(transactions) .where( and( - eq(lancamentos.userId, userId), - eq(lancamentos.period, period), - eq(lancamentos.transactionType, "Despesa"), - eq(lancamentos.condition, "Recorrente"), - eq(lancamentos.pagadorId, adminPagadorId), + eq(transactions.userId, userId), + eq(transactions.period, period), + eq(transactions.transactionType, "Despesa"), + eq(transactions.condition, "Recorrente"), + eq(transactions.payerId, adminPayerId), or( - isNull(lancamentos.note), + isNull(transactions.note), and( - sql`${lancamentos.note} != ${INITIAL_BALANCE_NOTE}`, - sql`${lancamentos.note} NOT LIKE ${`${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`}`, + sql`${transactions.note} != ${INITIAL_BALANCE_NOTE}`, + sql`${transactions.note} NOT LIKE ${`${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`}`, ), ), ), ) - .orderBy(desc(lancamentos.purchaseDate), desc(lancamentos.createdAt)); + .orderBy(desc(transactions.purchaseDate), desc(transactions.createdAt)); const expenses = results.map( (row): RecurringExpense => ({ diff --git a/src/features/dashboard/expenses/top-expenses-queries.ts b/src/features/dashboard/expenses/top-expenses-queries.ts index b68828b..59edd76 100644 --- a/src/features/dashboard/expenses/top-expenses-queries.ts +++ b/src/features/dashboard/expenses/top-expenses-queries.ts @@ -1,11 +1,11 @@ import { and, asc, eq } from "drizzle-orm"; -import { cartoes, contas, lancamentos } from "@/db/schema"; +import { cards, financialAccounts, transactions } from "@/db/schema"; import { buildDashboardAdminPeriodFilters, excludeAutoGeneratedEntryNotes, -} from "@/features/dashboard/lancamento-filters"; +} from "@/features/dashboard/transaction-filters"; import { db } from "@/shared/lib/db"; -import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { getAdminPayerId } from "@/shared/lib/payers/get-admin-id"; import { safeToNumber as toNumber } from "@/shared/utils/number"; export type TopExpense = { @@ -26,8 +26,8 @@ export async function fetchTopExpenses( period: string, cardOnly: boolean = false, ): Promise { - const adminPagadorId = await getAdminPagadorId(userId); - if (!adminPagadorId) { + const adminPayerId = await getAdminPayerId(userId); + if (!adminPayerId) { return { expenses: [] }; } @@ -35,34 +35,37 @@ export async function fetchTopExpenses( ...buildDashboardAdminPeriodFilters({ userId, period, - adminPagadorId, + adminPayerId, }), - eq(lancamentos.transactionType, "Despesa"), + eq(transactions.transactionType, "Despesa"), excludeAutoGeneratedEntryNotes(), ]; // Se cardOnly for true, filtra apenas pagamentos com cartão if (cardOnly) { - conditions.push(eq(lancamentos.paymentMethod, "Cartão de Crédito")); + conditions.push(eq(transactions.paymentMethod, "Cartão de Crédito")); } const results = await db .select({ - id: lancamentos.id, - name: lancamentos.name, - amount: lancamentos.amount, - purchaseDate: lancamentos.purchaseDate, - paymentMethod: lancamentos.paymentMethod, - cartaoId: lancamentos.cartaoId, - contaId: lancamentos.contaId, - cardLogo: cartoes.logo, - accountLogo: contas.logo, + id: transactions.id, + name: transactions.name, + amount: transactions.amount, + purchaseDate: transactions.purchaseDate, + paymentMethod: transactions.paymentMethod, + cardId: transactions.cardId, + accountId: transactions.accountId, + cardLogo: cards.logo, + accountLogo: financialAccounts.logo, }) - .from(lancamentos) - .leftJoin(cartoes, eq(lancamentos.cartaoId, cartoes.id)) - .leftJoin(contas, eq(lancamentos.contaId, contas.id)) + .from(transactions) + .leftJoin(cards, eq(transactions.cardId, cards.id)) + .leftJoin( + financialAccounts, + eq(transactions.accountId, financialAccounts.id), + ) .where(and(...conditions)) - .orderBy(asc(lancamentos.amount)) + .orderBy(asc(transactions.amount)) .limit(10); const expenses = results.map( diff --git a/src/features/dashboard/fetch-dashboard-data.ts b/src/features/dashboard/fetch-dashboard-data.ts index ae8b2c8..b9be2b0 100644 --- a/src/features/dashboard/fetch-dashboard-data.ts +++ b/src/features/dashboard/fetch-dashboard-data.ts @@ -11,7 +11,7 @@ import { fetchGoalsProgressData } from "./goals-progress-queries"; import { fetchIncomeExpenseBalance } from "./income-expense-balance-queries"; import { fetchDashboardInvoices } from "./invoices-queries"; import { fetchDashboardNotes } from "./notes-queries"; -import { fetchDashboardPagadores } from "./payers-queries"; +import { fetchDashboardPayers } from "./payers-queries"; import { fetchPaymentConditions } from "./payments/payment-conditions-queries"; import { fetchPaymentMethods } from "./payments/payment-methods-queries"; import { fetchPaymentStatus } from "./payments/payment-status-queries"; @@ -49,7 +49,7 @@ async function fetchDashboardDataInternal(userId: string, period: string) { fetchGoalsProgressData(userId, period), fetchPaymentStatus(userId, period), fetchIncomeExpenseBalance(userId, period), - fetchDashboardPagadores(userId, period), + fetchDashboardPayers(userId, period), fetchDashboardNotes(userId), fetchPaymentConditions(userId, period), fetchPaymentMethods(userId, period), diff --git a/src/features/dashboard/goals-progress-queries.ts b/src/features/dashboard/goals-progress-queries.ts index d5946c1..d739b32 100644 --- a/src/features/dashboard/goals-progress-queries.ts +++ b/src/features/dashboard/goals-progress-queries.ts @@ -1,7 +1,7 @@ import { and, eq, ne, sql } from "drizzle-orm"; -import { categorias, lancamentos, orcamentos } from "@/db/schema"; +import { budgets, categories, transactions } from "@/db/schema"; import { db } from "@/shared/lib/db"; -import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { getAdminPayerId } from "@/shared/lib/payers/get-admin-id"; import { safeToNumber as toNumber } from "@/shared/utils/number"; const BUDGET_CRITICAL_THRESHOLD = 80; @@ -49,9 +49,9 @@ export async function fetchGoalsProgressData( userId: string, period: string, ): Promise { - const adminPagadorId = await getAdminPagadorId(userId); + const adminPayerId = await getAdminPayerId(userId); - if (!adminPagadorId) { + if (!adminPayerId) { return { items: [], categories: [], @@ -64,45 +64,45 @@ export async function fetchGoalsProgressData( const [rows, categoryRows] = await Promise.all([ db .select({ - orcamentoId: orcamentos.id, - categoryId: categorias.id, - categoryName: categorias.name, - categoryIcon: categorias.icon, - period: orcamentos.period, - createdAt: orcamentos.createdAt, - budgetAmount: orcamentos.amount, - spentAmount: sql`COALESCE(SUM(ABS(${lancamentos.amount})), 0)`, + orcamentoId: budgets.id, + categoryId: categories.id, + categoryName: categories.name, + categoryIcon: categories.icon, + period: budgets.period, + createdAt: budgets.createdAt, + budgetAmount: budgets.amount, + spentAmount: sql`COALESCE(SUM(ABS(${transactions.amount})), 0)`, }) - .from(orcamentos) - .innerJoin(categorias, eq(orcamentos.categoriaId, categorias.id)) + .from(budgets) + .innerJoin(categories, eq(budgets.categoryId, categories.id)) .leftJoin( - lancamentos, + transactions, and( - eq(lancamentos.categoriaId, orcamentos.categoriaId), - eq(lancamentos.userId, orcamentos.userId), - eq(lancamentos.period, orcamentos.period), - eq(lancamentos.pagadorId, adminPagadorId), - eq(lancamentos.transactionType, "Despesa"), - ne(lancamentos.condition, "cancelado"), + eq(transactions.categoryId, budgets.categoryId), + eq(transactions.userId, budgets.userId), + eq(transactions.period, budgets.period), + eq(transactions.payerId, adminPayerId), + eq(transactions.transactionType, "Despesa"), + ne(transactions.condition, "cancelado"), ), ) - .where(and(eq(orcamentos.userId, userId), eq(orcamentos.period, period))) + .where(and(eq(budgets.userId, userId), eq(budgets.period, period))) .groupBy( - orcamentos.id, - categorias.id, - categorias.name, - categorias.icon, - orcamentos.period, - orcamentos.createdAt, - orcamentos.amount, + budgets.id, + categories.id, + categories.name, + categories.icon, + budgets.period, + budgets.createdAt, + budgets.amount, ), - db.query.categorias.findMany({ - where: and(eq(categorias.userId, userId), eq(categorias.type, "despesa")), + db.query.categories.findMany({ + where: and(eq(categories.userId, userId), eq(categories.type, "despesa")), orderBy: (category, { asc }) => [asc(category.name)], }), ]); - const categories: GoalProgressCategory[] = categoryRows.map((category) => ({ + const categoryList: GoalProgressCategory[] = categoryRows.map((category) => ({ id: category.id, name: category.name, icon: category.icon, @@ -139,7 +139,7 @@ export async function fetchGoalsProgressData( return { items, - categories, + categories: categoryList, totalBudgets: items.length, exceededCount, criticalCount, diff --git a/src/features/dashboard/income-expense-balance-queries.ts b/src/features/dashboard/income-expense-balance-queries.ts index 28fc763..529843e 100644 --- a/src/features/dashboard/income-expense-balance-queries.ts +++ b/src/features/dashboard/income-expense-balance-queries.ts @@ -1,12 +1,12 @@ import { and, eq, inArray, sql } from "drizzle-orm"; -import { contas, lancamentos } from "@/db/schema"; +import { financialAccounts, transactions } from "@/db/schema"; import { buildDashboardAdminFilters, excludeAutoInvoiceEntries, excludeInitialBalanceWhenConfigured, -} from "@/features/dashboard/lancamento-filters"; +} from "@/features/dashboard/transaction-filters"; import { db } from "@/shared/lib/db"; -import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { getAdminPayerId } from "@/shared/lib/payers/get-admin-id"; import { safeToNumber as toNumber } from "@/shared/utils/number"; import { buildPeriodWindow, @@ -38,8 +38,8 @@ export async function fetchIncomeExpenseBalance( userId: string, currentPeriod: string, ): Promise { - const adminPagadorId = await getAdminPagadorId(userId); - if (!adminPagadorId) { + const adminPayerId = await getAdminPayerId(userId); + if (!adminPayerId) { return { months: [] }; } @@ -48,22 +48,25 @@ export async function fetchIncomeExpenseBalance( // Single query: GROUP BY period + transactionType instead of 12 separate queries const rows = await db .select({ - period: lancamentos.period, - transactionType: lancamentos.transactionType, - total: sql`coalesce(sum(${lancamentos.amount}), 0)`, + period: transactions.period, + transactionType: transactions.transactionType, + total: sql`coalesce(sum(${transactions.amount}), 0)`, }) - .from(lancamentos) - .leftJoin(contas, eq(lancamentos.contaId, contas.id)) + .from(transactions) + .leftJoin( + financialAccounts, + eq(transactions.accountId, financialAccounts.id), + ) .where( and( - ...buildDashboardAdminFilters({ userId, adminPagadorId }), - inArray(lancamentos.period, periods), - inArray(lancamentos.transactionType, ["Receita", "Despesa"]), + ...buildDashboardAdminFilters({ userId, adminPayerId }), + inArray(transactions.period, periods), + inArray(transactions.transactionType, ["Receita", "Despesa"]), excludeAutoInvoiceEntries(), excludeInitialBalanceWhenConfigured(), ), ) - .groupBy(lancamentos.period, lancamentos.transactionType); + .groupBy(transactions.period, transactions.transactionType); // Build lookup from query results const dataMap = new Map(); diff --git a/src/features/dashboard/invoices-queries.ts b/src/features/dashboard/invoices-queries.ts index 54ffd7b..8d9a4d9 100644 --- a/src/features/dashboard/invoices-queries.ts +++ b/src/features/dashboard/invoices-queries.ts @@ -1,5 +1,5 @@ import { and, eq, ilike, isNotNull, sql } from "drizzle-orm"; -import { cartoes, faturas, lancamentos, pagadores } from "@/db/schema"; +import { cards, invoices, payers, transactions } from "@/db/schema"; import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/shared/lib/accounts/constants"; import { db } from "@/shared/lib/db"; import { @@ -28,14 +28,14 @@ type RawDashboardInvoice = { type RawInvoiceBreakdownRow = { cardId: string | null; period: string | null; - pagadorId: string | null; + payerId: string | null; pagadorName: string | null; pagadorAvatar: string | null; amount: number | string | null; }; export type InvoicePagadorBreakdown = { - pagadorId: string | null; + payerId: string | null; pagadorName: string; pagadorAvatar: string | null; amount: number; @@ -74,15 +74,15 @@ export async function fetchDashboardInvoices( ): Promise { const paymentRows = await db .select({ - note: lancamentos.note, - purchaseDate: lancamentos.purchaseDate, - createdAt: lancamentos.createdAt, + note: transactions.note, + purchaseDate: transactions.purchaseDate, + createdAt: transactions.createdAt, }) - .from(lancamentos) + .from(transactions) .where( and( - eq(lancamentos.userId, userId), - ilike(lancamentos.note, `${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`), + eq(transactions.userId, userId), + ilike(transactions.note, `${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`), ), ); @@ -117,80 +117,77 @@ export async function fetchDashboardInvoices( } } - const [rows, breakdownRows]: [ - RawDashboardInvoice[], - RawInvoiceBreakdownRow[], - ] = await Promise.all([ + const [rows, breakdownRows] = (await Promise.all([ db .select({ - invoiceId: faturas.id, - cardId: cartoes.id, - cardName: cartoes.name, - logo: cartoes.logo, - dueDay: cartoes.dueDay, - period: faturas.period, - paymentStatus: faturas.paymentStatus, - invoiceCreatedAt: faturas.createdAt, + invoiceId: invoices.id, + cardId: cards.id, + cardName: cards.name, + logo: cards.logo, + dueDay: cards.dueDay, + period: invoices.period, + paymentStatus: invoices.paymentStatus, + invoiceCreatedAt: invoices.createdAt, totalAmount: sql` - COALESCE(SUM(${lancamentos.amount}), 0) + COALESCE(SUM(${transactions.amount}), 0) `, - transactionCount: sql`COUNT(${lancamentos.id})`, + transactionCount: sql`COUNT(${transactions.id})`, }) - .from(cartoes) + .from(cards) .leftJoin( - faturas, + invoices, and( - eq(faturas.cartaoId, cartoes.id), - eq(faturas.userId, userId), - eq(faturas.period, period), + eq(invoices.cardId, cards.id), + eq(invoices.userId, userId), + eq(invoices.period, period), ), ) .leftJoin( - lancamentos, + transactions, and( - eq(lancamentos.cartaoId, cartoes.id), - eq(lancamentos.userId, userId), - eq(lancamentos.period, period), + eq(transactions.cardId, cards.id), + eq(transactions.userId, userId), + eq(transactions.period, period), ), ) - .where(eq(cartoes.userId, userId)) + .where(eq(cards.userId, userId)) .groupBy( - faturas.id, - cartoes.id, - cartoes.name, - cartoes.brand, - cartoes.status, - cartoes.logo, - cartoes.dueDay, - faturas.period, - faturas.paymentStatus, + invoices.id, + cards.id, + cards.name, + cards.brand, + cards.status, + cards.logo, + cards.dueDay, + invoices.period, + invoices.paymentStatus, ), db .select({ - cardId: lancamentos.cartaoId, - period: lancamentos.period, - pagadorId: lancamentos.pagadorId, - pagadorName: pagadores.name, - pagadorAvatar: pagadores.avatarUrl, - amount: sql`coalesce(sum(${lancamentos.amount}), 0)`, + cardId: transactions.cardId, + period: transactions.period, + payerId: transactions.payerId, + pagadorName: payers.name, + pagadorAvatar: payers.avatarUrl, + amount: sql`coalesce(sum(${transactions.amount}), 0)`, }) - .from(lancamentos) - .leftJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) + .from(transactions) + .leftJoin(payers, eq(transactions.payerId, payers.id)) .where( and( - eq(lancamentos.userId, userId), - eq(lancamentos.period, period), - isNotNull(lancamentos.cartaoId), + eq(transactions.userId, userId), + eq(transactions.period, period), + isNotNull(transactions.cardId), ), ) .groupBy( - lancamentos.cartaoId, - lancamentos.period, - lancamentos.pagadorId, - pagadores.name, - pagadores.avatarUrl, + transactions.cardId, + transactions.period, + transactions.payerId, + payers.name, + payers.avatarUrl, ), - ]); + ])) as [RawDashboardInvoice[], RawInvoiceBreakdownRow[]]; const breakdownMap = new Map(); for (const row of breakdownRows) { @@ -205,7 +202,7 @@ export async function fetchDashboardInvoices( const key = `${row.cardId}:${resolvedPeriod}`; const current = breakdownMap.get(key) ?? []; current.push({ - pagadorId: row.pagadorId ?? null, + payerId: row.payerId ?? null, pagadorName: row.pagadorName?.trim() || "Sem pagador", pagadorAvatar: row.pagadorAvatar ?? null, amount, @@ -213,7 +210,7 @@ export async function fetchDashboardInvoices( breakdownMap.set(key, current); } - const invoices: DashboardInvoice[] = []; + const invoiceList: DashboardInvoice[] = []; for (const row of rows) { if (!row) { @@ -242,7 +239,7 @@ export async function fetchDashboardInvoices( ? (paymentMap.get(paymentKey) ?? toDateOnlyString(row.invoiceCreatedAt)) : null; - invoices.push({ + invoiceList.push({ id: row.invoiceId ?? buildFallbackId(row.cardId, period), cardId: row.cardId, cardName: row.cardName, @@ -260,12 +257,12 @@ export async function fetchDashboardInvoices( }); } - invoices.sort((a, b) => { + invoiceList.sort((a, b) => { // Ordena do maior valor para o menor return Math.abs(b.totalAmount) - Math.abs(a.totalAmount); }); - const totalPending = invoices.reduce((total, invoice) => { + const totalPending = invoiceList.reduce((total, invoice) => { if (invoice.paymentStatus !== INVOICE_PAYMENT_STATUS.PENDING) { return total; } @@ -273,7 +270,7 @@ export async function fetchDashboardInvoices( }, 0); return { - invoices, + invoices: invoiceList, totalPending, }; } diff --git a/src/features/dashboard/notes-mappers.ts b/src/features/dashboard/notes-mappers.ts index 546e903..a9a178b 100644 --- a/src/features/dashboard/notes-mappers.ts +++ b/src/features/dashboard/notes-mappers.ts @@ -7,7 +7,7 @@ export const mapDashboardNoteToNote = (note: DashboardNote): Note => ({ description: note.description, type: note.type, tasks: note.tasks, - arquivada: note.arquivada, + archived: note.archived, createdAt: note.createdAt, }); diff --git a/src/features/dashboard/notes-queries.ts b/src/features/dashboard/notes-queries.ts index 64ff22d..0cc3fda 100644 --- a/src/features/dashboard/notes-queries.ts +++ b/src/features/dashboard/notes-queries.ts @@ -1,5 +1,5 @@ import { and, eq } from "drizzle-orm"; -import { anotacoes } from "@/db/schema"; +import { notes } from "@/db/schema"; import { db } from "@/shared/lib/db"; export type DashboardTask = { @@ -14,7 +14,7 @@ export type DashboardNote = { description: string; type: "nota" | "tarefa"; tasks?: DashboardTask[]; - arquivada: boolean; + archived: boolean; createdAt: string; }; @@ -55,19 +55,19 @@ const parseTasks = (value: string | null): DashboardTask[] | undefined => { export async function fetchDashboardNotes( userId: string, ): Promise { - const notes = await db.query.anotacoes.findMany({ - where: and(eq(anotacoes.userId, userId), eq(anotacoes.arquivada, false)), + const noteRows = await db.query.notes.findMany({ + where: and(eq(notes.userId, userId), eq(notes.archived, false)), orderBy: (note, { desc }) => [desc(note.createdAt)], limit: 5, }); - return notes.map((note) => ({ + return noteRows.map((note) => ({ id: note.id, title: (note.title ?? "").trim(), description: (note.description ?? "").trim(), type: (note.type ?? "nota") as "nota" | "tarefa", tasks: parseTasks(note.tasks), - arquivada: note.arquivada, + archived: note.archived, createdAt: note.createdAt.toISOString(), })); } diff --git a/src/features/dashboard/notifications-queries.ts b/src/features/dashboard/notifications-queries.ts index b3e073d..fb04c36 100644 --- a/src/features/dashboard/notifications-queries.ts +++ b/src/features/dashboard/notifications-queries.ts @@ -2,15 +2,15 @@ import { and, eq, lt, ne, sql } from "drizzle-orm"; import { - cartoes, - categorias, - faturas, - lancamentos, - orcamentos, + budgets, + cards, + categories, + invoices, + transactions, } from "@/db/schema"; import { db } from "@/shared/lib/db"; import { INVOICE_PAYMENT_STATUS } from "@/shared/lib/invoices"; -import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { getAdminPayerId } from "@/shared/lib/payers/get-admin-id"; import { buildDateOnlyStringFromPeriodDay, getBusinessDateString, @@ -67,128 +67,126 @@ export async function fetchDashboardNotifications( const today = getBusinessDateString(); const DAYS_THRESHOLD = 5; - const adminPagadorId = await getAdminPagadorId(userId); + const adminPayerId = await getAdminPayerId(userId); // --- Faturas atrasadas (períodos anteriores) --- const overdueInvoices = await db .select({ - invoiceId: faturas.id, - cardId: cartoes.id, - cardName: cartoes.name, - cardLogo: cartoes.logo, - dueDay: cartoes.dueDay, - period: faturas.period, + invoiceId: invoices.id, + cardId: cards.id, + cardName: cards.name, + cardLogo: cards.logo, + dueDay: cards.dueDay, + period: invoices.period, totalAmount: sql` COALESCE( - (SELECT SUM(${lancamentos.amount}) - FROM ${lancamentos} - WHERE ${lancamentos.cartaoId} = ${cartoes.id} - AND ${lancamentos.period} = ${faturas.period} - AND ${lancamentos.userId} = ${faturas.userId}), + (SELECT SUM(${transactions.amount}) + FROM ${transactions} + WHERE ${transactions.cardId} = ${cards.id} + AND ${transactions.period} = ${invoices.period} + AND ${transactions.userId} = ${invoices.userId}), 0 ) `, }) - .from(faturas) - .innerJoin(cartoes, eq(faturas.cartaoId, cartoes.id)) + .from(invoices) + .innerJoin(cards, eq(invoices.cardId, cards.id)) .where( and( - eq(faturas.userId, userId), - eq(faturas.paymentStatus, INVOICE_PAYMENT_STATUS.PENDING), - lt(faturas.period, currentPeriod), + eq(invoices.userId, userId), + eq(invoices.paymentStatus, INVOICE_PAYMENT_STATUS.PENDING), + lt(invoices.period, currentPeriod), ), ); // --- Faturas do período atual --- const currentInvoices = await db .select({ - invoiceId: faturas.id, - cardId: cartoes.id, - cardName: cartoes.name, - cardLogo: cartoes.logo, - dueDay: cartoes.dueDay, - period: sql`COALESCE(${faturas.period}, ${currentPeriod})`, - paymentStatus: faturas.paymentStatus, + invoiceId: invoices.id, + cardId: cards.id, + cardName: cards.name, + cardLogo: cards.logo, + dueDay: cards.dueDay, + period: sql`COALESCE(${invoices.period}, ${currentPeriod})`, + paymentStatus: invoices.paymentStatus, totalAmount: sql` - COALESCE(SUM(${lancamentos.amount}), 0) + COALESCE(SUM(${transactions.amount}), 0) `, - transactionCount: sql`COUNT(${lancamentos.id})`, + transactionCount: sql`COUNT(${transactions.id})`, }) - .from(cartoes) + .from(cards) .leftJoin( - faturas, + invoices, and( - eq(faturas.cartaoId, cartoes.id), - eq(faturas.userId, userId), - eq(faturas.period, currentPeriod), + eq(invoices.cardId, cards.id), + eq(invoices.userId, userId), + eq(invoices.period, currentPeriod), ), ) .leftJoin( - lancamentos, + transactions, and( - eq(lancamentos.cartaoId, cartoes.id), - eq(lancamentos.userId, userId), - eq(lancamentos.period, currentPeriod), + eq(transactions.cardId, cards.id), + eq(transactions.userId, userId), + eq(transactions.period, currentPeriod), ), ) - .where(eq(cartoes.userId, userId)) + .where(eq(cards.userId, userId)) .groupBy( - faturas.id, - cartoes.id, - cartoes.name, - cartoes.logo, - cartoes.dueDay, - faturas.period, - faturas.paymentStatus, + invoices.id, + cards.id, + cards.name, + cards.logo, + cards.dueDay, + invoices.period, + invoices.paymentStatus, ); // --- Boletos não pagos --- const boletosConditions = [ - eq(lancamentos.userId, userId), - eq(lancamentos.paymentMethod, PAYMENT_METHOD_BOLETO), - eq(lancamentos.isSettled, false), + eq(transactions.userId, userId), + eq(transactions.paymentMethod, PAYMENT_METHOD_BOLETO), + eq(transactions.isSettled, false), ]; - if (adminPagadorId) { - boletosConditions.push(eq(lancamentos.pagadorId, adminPagadorId)); + if (adminPayerId) { + boletosConditions.push(eq(transactions.payerId, adminPayerId)); } const boletosRows = await db .select({ - id: lancamentos.id, - name: lancamentos.name, - amount: lancamentos.amount, - dueDate: lancamentos.dueDate, - period: lancamentos.period, + id: transactions.id, + name: transactions.name, + amount: transactions.amount, + dueDate: transactions.dueDate, + period: transactions.period, }) - .from(lancamentos) + .from(transactions) .where(and(...boletosConditions)); // --- Orçamentos do período atual --- const budgetJoinConditions = [ - eq(lancamentos.categoriaId, orcamentos.categoriaId), - eq(lancamentos.userId, orcamentos.userId), - eq(lancamentos.period, orcamentos.period), - eq(lancamentos.transactionType, "Despesa"), - ne(lancamentos.condition, "cancelado"), + eq(transactions.categoryId, budgets.categoryId), + eq(transactions.userId, budgets.userId), + eq(transactions.period, budgets.period), + eq(transactions.transactionType, "Despesa"), + ne(transactions.condition, "cancelado"), ]; - if (adminPagadorId) { - budgetJoinConditions.push(eq(lancamentos.pagadorId, adminPagadorId)); + if (adminPayerId) { + budgetJoinConditions.push(eq(transactions.payerId, adminPayerId)); } const budgetRows = await db .select({ - orcamentoId: orcamentos.id, - budgetAmount: orcamentos.amount, - categoriaName: categorias.name, - spentAmount: sql`COALESCE(SUM(ABS(${lancamentos.amount})), 0)`, + orcamentoId: budgets.id, + budgetAmount: budgets.amount, + categoriaName: categories.name, + spentAmount: sql`COALESCE(SUM(ABS(${transactions.amount})), 0)`, }) - .from(orcamentos) - .innerJoin(categorias, eq(orcamentos.categoriaId, categorias.id)) - .leftJoin(lancamentos, and(...budgetJoinConditions)) - .where( - and(eq(orcamentos.userId, userId), eq(orcamentos.period, currentPeriod)), - ) - .groupBy(orcamentos.id, orcamentos.amount, categorias.name); + .from(budgets) + .innerJoin(categories, eq(budgets.categoryId, categories.id)) + .leftJoin(transactions, and(...budgetJoinConditions)) + .where(and(eq(budgets.userId, userId), eq(budgets.period, currentPeriod))) + .groupBy(budgets.id, budgets.amount, categories.name); // ===================== // Processar notificações diff --git a/src/features/dashboard/payers-queries.ts b/src/features/dashboard/payers-queries.ts index d5fd084..f08fecf 100644 --- a/src/features/dashboard/payers-queries.ts +++ b/src/features/dashboard/payers-queries.ts @@ -1,8 +1,8 @@ import { and, desc, eq, inArray, isNull, or, sql } from "drizzle-orm"; -import { lancamentos, pagadores } from "@/db/schema"; +import { payers, transactions } from "@/db/schema"; import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/shared/lib/accounts/constants"; import { db } from "@/shared/lib/db"; -import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; +import { PAYER_ROLE_ADMIN } from "@/shared/lib/payers/constants"; import { calculatePercentageChange } from "@/shared/utils/math"; import { safeToNumber as toNumber } from "@/shared/utils/number"; import { getPreviousPeriod } from "@/shared/utils/period"; @@ -18,49 +18,49 @@ export type DashboardPagador = { isAdmin: boolean; }; -export type DashboardPagadoresSnapshot = { - pagadores: DashboardPagador[]; +export type DashboardPayersSnapshot = { + payers: DashboardPagador[]; totalExpenses: number; }; -export async function fetchDashboardPagadores( +export async function fetchDashboardPayers( userId: string, period: string, -): Promise { +): Promise { const previousPeriod = getPreviousPeriod(period); const rows = await db .select({ - id: pagadores.id, - name: pagadores.name, - email: pagadores.email, - avatarUrl: pagadores.avatarUrl, - role: pagadores.role, - period: lancamentos.period, - totalExpenses: sql`COALESCE(SUM(ABS(${lancamentos.amount})), 0)`, + id: payers.id, + name: payers.name, + email: payers.email, + avatarUrl: payers.avatarUrl, + role: payers.role, + period: transactions.period, + totalExpenses: sql`COALESCE(SUM(ABS(${transactions.amount})), 0)`, }) - .from(lancamentos) - .innerJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) + .from(transactions) + .innerJoin(payers, eq(transactions.payerId, payers.id)) .where( and( - eq(lancamentos.userId, userId), - inArray(lancamentos.period, [period, previousPeriod]), - eq(lancamentos.transactionType, "Despesa"), + eq(transactions.userId, userId), + inArray(transactions.period, [period, previousPeriod]), + eq(transactions.transactionType, "Despesa"), or( - isNull(lancamentos.note), - sql`${lancamentos.note} NOT LIKE ${`${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`}`, + isNull(transactions.note), + sql`${transactions.note} NOT LIKE ${`${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`}`, ), ), ) .groupBy( - pagadores.id, - pagadores.name, - pagadores.email, - pagadores.avatarUrl, - pagadores.role, - lancamentos.period, + payers.id, + payers.name, + payers.email, + payers.avatarUrl, + payers.role, + transactions.period, ) - .orderBy(desc(sql`SUM(ABS(${lancamentos.amount}))`)); + .orderBy(desc(sql`SUM(ABS(${transactions.amount}))`)); const groupedPagadores = new Map< string, @@ -81,7 +81,7 @@ export async function fetchDashboardPagadores( name: row.name, email: row.email, avatarUrl: row.avatarUrl, - isAdmin: row.role === PAGADOR_ROLE_ADMIN, + isAdmin: row.role === PAYER_ROLE_ADMIN, currentExpenses: 0, previousExpenses: 0, }; @@ -96,7 +96,7 @@ export async function fetchDashboardPagadores( groupedPagadores.set(row.id, entry); } - const pagadoresList = Array.from(groupedPagadores.values()) + const payerList = Array.from(groupedPagadores.values()) .filter((p) => p.currentExpenses > 0) .map((pagador) => ({ id: pagador.id, @@ -113,13 +113,13 @@ export async function fetchDashboardPagadores( })) .sort((a, b) => b.totalExpenses - a.totalExpenses); - const totalExpenses = pagadoresList.reduce( + const totalExpenses = payerList.reduce( (sum, p) => sum + p.totalExpenses, 0, ); return { - pagadores: pagadoresList, + payers: payerList, totalExpenses, }; } diff --git a/src/features/dashboard/payments/payment-conditions-queries.ts b/src/features/dashboard/payments/payment-conditions-queries.ts index 079b19a..68b9189 100644 --- a/src/features/dashboard/payments/payment-conditions-queries.ts +++ b/src/features/dashboard/payments/payment-conditions-queries.ts @@ -1,11 +1,11 @@ import { and, eq, sql } from "drizzle-orm"; -import { lancamentos } from "@/db/schema"; +import { transactions } from "@/db/schema"; import { buildDashboardAdminPeriodFilters, excludeAutoGeneratedEntryNotes, -} from "@/features/dashboard/lancamento-filters"; +} from "@/features/dashboard/transaction-filters"; import { db } from "@/shared/lib/db"; -import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { getAdminPayerId } from "@/shared/lib/payers/get-admin-id"; import { safeToNumber as toNumber } from "@/shared/utils/number"; export type PaymentConditionSummary = { @@ -23,30 +23,30 @@ export async function fetchPaymentConditions( userId: string, period: string, ): Promise { - const adminPagadorId = await getAdminPagadorId(userId); - if (!adminPagadorId) { + const adminPayerId = await getAdminPayerId(userId); + if (!adminPayerId) { return { conditions: [] }; } const rows = await db .select({ - condition: lancamentos.condition, - totalAmount: sql`coalesce(sum(${lancamentos.amount}), 0)`, - transactions: sql`count(${lancamentos.id})`, + condition: transactions.condition, + totalAmount: sql`coalesce(sum(${transactions.amount}), 0)`, + transactions: sql`count(${transactions.id})`, }) - .from(lancamentos) + .from(transactions) .where( and( ...buildDashboardAdminPeriodFilters({ userId, period, - adminPagadorId, + adminPayerId, }), - eq(lancamentos.transactionType, "Despesa"), + eq(transactions.transactionType, "Despesa"), excludeAutoGeneratedEntryNotes(), ), ) - .groupBy(lancamentos.condition); + .groupBy(transactions.condition); const summaries = rows.map((row: (typeof rows)[number]) => { const totalAmount = Math.abs(toNumber(row.totalAmount)); diff --git a/src/features/dashboard/payments/payment-methods-queries.ts b/src/features/dashboard/payments/payment-methods-queries.ts index 0fd1094..98713ef 100644 --- a/src/features/dashboard/payments/payment-methods-queries.ts +++ b/src/features/dashboard/payments/payment-methods-queries.ts @@ -1,11 +1,11 @@ import { and, eq, sql } from "drizzle-orm"; -import { lancamentos } from "@/db/schema"; +import { transactions } from "@/db/schema"; import { buildDashboardAdminPeriodFilters, excludeAutoGeneratedEntryNotes, -} from "@/features/dashboard/lancamento-filters"; +} from "@/features/dashboard/transaction-filters"; import { db } from "@/shared/lib/db"; -import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { getAdminPayerId } from "@/shared/lib/payers/get-admin-id"; import { safeToNumber as toNumber } from "@/shared/utils/number"; export type PaymentMethodSummary = { @@ -23,30 +23,30 @@ export async function fetchPaymentMethods( userId: string, period: string, ): Promise { - const adminPagadorId = await getAdminPagadorId(userId); - if (!adminPagadorId) { + const adminPayerId = await getAdminPayerId(userId); + if (!adminPayerId) { return { methods: [] }; } const rows = await db .select({ - paymentMethod: lancamentos.paymentMethod, - totalAmount: sql`coalesce(sum(${lancamentos.amount}), 0)`, - transactions: sql`count(${lancamentos.id})`, + paymentMethod: transactions.paymentMethod, + totalAmount: sql`coalesce(sum(${transactions.amount}), 0)`, + transactions: sql`count(${transactions.id})`, }) - .from(lancamentos) + .from(transactions) .where( and( ...buildDashboardAdminPeriodFilters({ userId, period, - adminPagadorId, + adminPayerId, }), - eq(lancamentos.transactionType, "Despesa"), + eq(transactions.transactionType, "Despesa"), excludeAutoGeneratedEntryNotes(), ), ) - .groupBy(lancamentos.paymentMethod); + .groupBy(transactions.paymentMethod); const summaries = rows.map((row: (typeof rows)[number]) => { const amount = Math.abs(toNumber(row.totalAmount)); diff --git a/src/features/dashboard/payments/payment-status-queries.ts b/src/features/dashboard/payments/payment-status-queries.ts index f573a0d..f7f110c 100644 --- a/src/features/dashboard/payments/payment-status-queries.ts +++ b/src/features/dashboard/payments/payment-status-queries.ts @@ -1,11 +1,11 @@ import { and, inArray, sql } from "drizzle-orm"; -import { lancamentos } from "@/db/schema"; +import { transactions } from "@/db/schema"; import { buildDashboardAdminPeriodFilters, excludeAutoInvoiceEntries, -} from "@/features/dashboard/lancamento-filters"; +} from "@/features/dashboard/transaction-filters"; import { db } from "@/shared/lib/db"; -import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { getAdminPayerId } from "@/shared/lib/payers/get-admin-id"; import { safeToNumber as toNumber } from "@/shared/utils/number"; export type PaymentStatusCategory = { @@ -29,41 +29,41 @@ export async function fetchPaymentStatus( userId: string, period: string, ): Promise { - const adminPagadorId = await getAdminPagadorId(userId); - if (!adminPagadorId) { + const adminPayerId = await getAdminPayerId(userId); + if (!adminPayerId) { return { income: emptyCategory(), expenses: emptyCategory() }; } // Single query: GROUP BY transactionType instead of 2 separate queries const rows = await db .select({ - transactionType: lancamentos.transactionType, + transactionType: transactions.transactionType, confirmed: sql` coalesce( - sum(case when ${lancamentos.isSettled} = true then ${lancamentos.amount} else 0 end), + sum(case when ${transactions.isSettled} = true then ${transactions.amount} else 0 end), 0 ) `, pending: sql` coalesce( - sum(case when ${lancamentos.isSettled} = false or ${lancamentos.isSettled} is null then ${lancamentos.amount} else 0 end), + sum(case when ${transactions.isSettled} = false or ${transactions.isSettled} is null then ${transactions.amount} else 0 end), 0 ) `, }) - .from(lancamentos) + .from(transactions) .where( and( ...buildDashboardAdminPeriodFilters({ userId, period, - adminPagadorId, + adminPayerId, }), - inArray(lancamentos.transactionType, ["Receita", "Despesa"]), + inArray(transactions.transactionType, ["Receita", "Despesa"]), excludeAutoInvoiceEntries(), ), ) - .groupBy(lancamentos.transactionType); + .groupBy(transactions.transactionType); const result = { income: emptyCategory(), expenses: emptyCategory() }; diff --git a/src/features/dashboard/preferences-queries.ts b/src/features/dashboard/preferences-queries.ts index 88b7d58..0c0b550 100644 --- a/src/features/dashboard/preferences-queries.ts +++ b/src/features/dashboard/preferences-queries.ts @@ -11,10 +11,10 @@ export async function fetchUserDashboardPreferences( ): Promise { const result = await db .select({ - dashboardWidgets: schema.preferenciasUsuario.dashboardWidgets, + dashboardWidgets: schema.userPreferences.dashboardWidgets, }) - .from(schema.preferenciasUsuario) - .where(eq(schema.preferenciasUsuario.userId, userId)) + .from(schema.userPreferences) + .where(eq(schema.userPreferences.userId, userId)) .limit(1); return { diff --git a/src/features/dashboard/purchases-by-category-queries.ts b/src/features/dashboard/purchases-by-category-queries.ts index 81077ac..3c4ddb8 100644 --- a/src/features/dashboard/purchases-by-category-queries.ts +++ b/src/features/dashboard/purchases-by-category-queries.ts @@ -1,11 +1,16 @@ import { and, desc, eq, inArray } from "drizzle-orm"; -import { cartoes, categorias, contas, lancamentos } from "@/db/schema"; +import { + cards, + categories, + financialAccounts, + transactions, +} from "@/db/schema"; import { buildDashboardAdminPeriodFilters, excludeAutoGeneratedEntryNotes, -} from "@/features/dashboard/lancamento-filters"; +} from "@/features/dashboard/transaction-filters"; import { db } from "@/shared/lib/db"; -import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { getAdminPayerId } from "@/shared/lib/payers/get-admin-id"; import { safeToNumber as toNumber } from "@/shared/utils/number"; export type CategoryOption = { @@ -45,39 +50,42 @@ export async function fetchPurchasesByCategory( userId: string, period: string, ): Promise { - const adminPagadorId = await getAdminPagadorId(userId); - if (!adminPagadorId) { + const adminPayerId = await getAdminPayerId(userId); + if (!adminPayerId) { return { categories: [], transactionsByCategory: {} }; } const transactionsRows = await db .select({ - id: lancamentos.id, - name: lancamentos.name, - amount: lancamentos.amount, - purchaseDate: lancamentos.purchaseDate, - categoryId: lancamentos.categoriaId, - categoryName: categorias.name, - categoryType: categorias.type, - cardLogo: cartoes.logo, - accountLogo: contas.logo, + id: transactions.id, + name: transactions.name, + amount: transactions.amount, + purchaseDate: transactions.purchaseDate, + categoryId: transactions.categoryId, + categoryName: categories.name, + categoryType: categories.type, + cardLogo: cards.logo, + accountLogo: financialAccounts.logo, }) - .from(lancamentos) - .innerJoin(categorias, eq(lancamentos.categoriaId, categorias.id)) - .leftJoin(cartoes, eq(lancamentos.cartaoId, cartoes.id)) - .leftJoin(contas, eq(lancamentos.contaId, contas.id)) + .from(transactions) + .innerJoin(categories, eq(transactions.categoryId, categories.id)) + .leftJoin(cards, eq(transactions.cardId, cards.id)) + .leftJoin( + financialAccounts, + eq(transactions.accountId, financialAccounts.id), + ) .where( and( ...buildDashboardAdminPeriodFilters({ userId, period, - adminPagadorId, + adminPayerId, }), - inArray(categorias.type, ["despesa", "receita"]), + inArray(categories.type, ["despesa", "receita"]), excludeAutoGeneratedEntryNotes(), ), ) - .orderBy(desc(lancamentos.purchaseDate)); + .orderBy(desc(transactions.purchaseDate)); const transactionsByCategory: Record = {}; const categoriesMap = new Map(); @@ -120,8 +128,8 @@ export async function fetchPurchasesByCategory( } } - // Ordena as categorias: receitas primeiro, depois despesas (alfabeticamente dentro de cada tipo) - const categories = Array.from(categoriesMap.values()).sort((a, b) => { + // Ordena as categories: receitas primeiro, depois despesas (alfabeticamente dentro de cada tipo) + const categoryList = Array.from(categoriesMap.values()).sort((a, b) => { // Receita vem antes de despesa if (a.type !== b.type) { return a.type === "receita" ? -1 : 1; @@ -131,7 +139,7 @@ export async function fetchPurchasesByCategory( }); return { - categories, + categories: categoryList, transactionsByCategory, }; } diff --git a/src/features/dashboard/recurring/recurring-series-queries.ts b/src/features/dashboard/recurring/recurring-series-queries.ts index ee72579..ea97571 100644 --- a/src/features/dashboard/recurring/recurring-series-queries.ts +++ b/src/features/dashboard/recurring/recurring-series-queries.ts @@ -1,8 +1,8 @@ import { and, eq, inArray } from "drizzle-orm"; import type { RecurringSeriesTemplate } from "@/db/schema"; -import { categorias, recurringSeries } from "@/db/schema"; +import { categories, recurringSeries } from "@/db/schema"; import { db } from "@/shared/lib/db"; -import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { getAdminPayerId } from "@/shared/lib/payers/get-admin-id"; import { safeToNumber as toNumber } from "@/shared/utils/number"; import { addMonthsToPeriod } from "@/shared/utils/period"; @@ -26,7 +26,7 @@ export type RecurringSeriesData = { export async function fetchRecurringSeries( userId: string, ): Promise { - const adminPagadorId = await getAdminPagadorId(userId); + const adminPayerId = await getAdminPayerId(userId); const rows = await db .select({ @@ -50,19 +50,19 @@ export async function fetchRecurringSeries( // Fetch category names for all series in one query const categoryIds = rows - .map((r) => (r.templateData as RecurringSeriesTemplate).categoriaId) + .map((r) => (r.templateData as RecurringSeriesTemplate).categoryId) .filter((id): id is string => id !== null); const categoryMap = new Map(); if (categoryIds.length > 0) { const cats = await db .select({ - id: categorias.id, - name: categorias.name, - icon: categorias.icon, + id: categories.id, + name: categories.name, + icon: categories.icon, }) - .from(categorias) - .where(inArray(categorias.id, categoryIds)); + .from(categories) + .where(inArray(categories.id, categoryIds)); for (const cat of cats) { categoryMap.set(cat.id, { name: cat.name, icon: cat.icon }); } @@ -71,16 +71,14 @@ export async function fetchRecurringSeries( const series = rows .filter((row) => { // If admin pagador exists, only show series belonging to admin - if (!adminPagadorId) return true; + if (!adminPayerId) return true; const template = row.templateData as RecurringSeriesTemplate; - return ( - template.pagadorId === adminPagadorId || template.pagadorId === null - ); + return template.payerId === adminPayerId || template.payerId === null; }) .map((row): RecurringSeriesItem => { const template = row.templateData as RecurringSeriesTemplate; - const category = template.categoriaId - ? categoryMap.get(template.categoriaId) + const category = template.categoryId + ? categoryMap.get(template.categoryId) : null; return { id: row.id, diff --git a/src/features/dashboard/top-establishments-queries.ts b/src/features/dashboard/top-establishments-queries.ts index 6a8c69f..fb86482 100644 --- a/src/features/dashboard/top-establishments-queries.ts +++ b/src/features/dashboard/top-establishments-queries.ts @@ -1,11 +1,11 @@ import { and, eq, sql } from "drizzle-orm"; -import { cartoes, contas, lancamentos } from "@/db/schema"; +import { cards, financialAccounts, transactions } from "@/db/schema"; import { buildDashboardAdminPeriodFilters, excludeAutoGeneratedEntryNotes, -} from "@/features/dashboard/lancamento-filters"; +} from "@/features/dashboard/transaction-filters"; import { db } from "@/shared/lib/db"; -import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { getAdminPayerId } from "@/shared/lib/payers/get-admin-id"; import { safeToNumber as toNumber } from "@/shared/utils/number"; export type TopEstablishment = { @@ -38,36 +38,41 @@ export async function fetchTopEstablishments( userId: string, period: string, ): Promise { - const adminPagadorId = await getAdminPagadorId(userId); - if (!adminPagadorId) { + const adminPayerId = await getAdminPayerId(userId); + if (!adminPayerId) { return { establishments: [] }; } const rows = await db .select({ - name: lancamentos.name, - totalAmount: sql`coalesce(sum(${lancamentos.amount}), 0)`, - occurrences: sql`count(${lancamentos.id})`, - logo: sql`max(coalesce(${cartoes.logo}, ${contas.logo}))`, + name: transactions.name, + totalAmount: sql`coalesce(sum(${transactions.amount}), 0)`, + occurrences: sql`count(${transactions.id})`, + logo: sql< + string | null + >`max(coalesce(${cards.logo}, ${financialAccounts.logo}))`, }) - .from(lancamentos) - .leftJoin(cartoes, eq(lancamentos.cartaoId, cartoes.id)) - .leftJoin(contas, eq(lancamentos.contaId, contas.id)) + .from(transactions) + .leftJoin(cards, eq(transactions.cardId, cards.id)) + .leftJoin( + financialAccounts, + eq(transactions.accountId, financialAccounts.id), + ) .where( and( ...buildDashboardAdminPeriodFilters({ userId, period, - adminPagadorId, + adminPayerId, }), - eq(lancamentos.transactionType, "Despesa"), + eq(transactions.transactionType, "Despesa"), excludeAutoGeneratedEntryNotes(), ), ) - .groupBy(lancamentos.name) + .groupBy(transactions.name) .orderBy( - sql`count(${lancamentos.id}) DESC`, - sql`ABS(sum(${lancamentos.amount})) DESC`, + sql`count(${transactions.id}) DESC`, + sql`ABS(sum(${transactions.amount})) DESC`, ) .limit(10); diff --git a/src/features/dashboard/lancamento-filters.ts b/src/features/dashboard/transaction-filters.ts similarity index 52% rename from src/features/dashboard/lancamento-filters.ts rename to src/features/dashboard/transaction-filters.ts index f907e81..808b819 100644 --- a/src/features/dashboard/lancamento-filters.ts +++ b/src/features/dashboard/transaction-filters.ts @@ -1,5 +1,5 @@ import { and, eq, ilike, isNull, ne, not, or } from "drizzle-orm"; -import { contas, lancamentos } from "@/db/schema"; +import { financialAccounts, transactions } from "@/db/schema"; import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX, INITIAL_BALANCE_NOTE, @@ -7,7 +7,7 @@ import { type DashboardAdminFiltersParams = { userId: string; - adminPagadorId: string; + adminPayerId: string; }; type DashboardAdminPeriodFiltersParams = DashboardAdminFiltersParams & { @@ -16,41 +16,41 @@ type DashboardAdminPeriodFiltersParams = DashboardAdminFiltersParams & { export const buildDashboardAdminFilters = ({ userId, - adminPagadorId, + adminPayerId, }: DashboardAdminFiltersParams) => [ - eq(lancamentos.userId, userId), - eq(lancamentos.pagadorId, adminPagadorId), + eq(transactions.userId, userId), + eq(transactions.payerId, adminPayerId), ] as const; export const buildDashboardAdminPeriodFilters = ({ userId, period, - adminPagadorId, + adminPayerId, }: DashboardAdminPeriodFiltersParams) => [ - ...buildDashboardAdminFilters({ userId, adminPagadorId }), - eq(lancamentos.period, period), + ...buildDashboardAdminFilters({ userId, adminPayerId }), + eq(transactions.period, period), ] as const; export const excludeAutoInvoiceEntries = () => or( - isNull(lancamentos.note), - not(ilike(lancamentos.note, `${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`)), + isNull(transactions.note), + not(ilike(transactions.note, `${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`)), ); export const excludeAutoGeneratedEntryNotes = () => or( - isNull(lancamentos.note), + isNull(transactions.note), and( - ne(lancamentos.note, INITIAL_BALANCE_NOTE), - not(ilike(lancamentos.note, `${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`)), + ne(transactions.note, INITIAL_BALANCE_NOTE), + not(ilike(transactions.note, `${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`)), ), ); export const excludeInitialBalanceWhenConfigured = () => or( - ne(lancamentos.note, INITIAL_BALANCE_NOTE), - isNull(contas.excludeInitialBalanceFromIncome), - eq(contas.excludeInitialBalanceFromIncome, false), + ne(transactions.note, INITIAL_BALANCE_NOTE), + isNull(financialAccounts.excludeInitialBalanceFromIncome), + eq(financialAccounts.excludeInitialBalanceFromIncome, false), ); diff --git a/src/features/dashboard/use-bill-widget-controller.ts b/src/features/dashboard/use-bill-widget-controller.ts index 5d53449..da2e316 100644 --- a/src/features/dashboard/use-bill-widget-controller.ts +++ b/src/features/dashboard/use-bill-widget-controller.ts @@ -10,7 +10,7 @@ import { type PaymentDialogController, usePaymentDialogController, } from "@/features/dashboard/use-payment-dialog-controller"; -import { toggleLancamentoSettlementAction } from "@/features/transactions/actions"; +import { toggleTransactionSettlementAction } from "@/features/transactions/actions"; const EMPTY_BILLS: DashboardBill[] = []; @@ -31,7 +31,7 @@ export function useBillWidgetController( getItemId: (bill) => bill.id, isItemConfirmed: (bill) => bill.isSettled, executeConfirm: (bill) => - toggleLancamentoSettlementAction({ + toggleTransactionSettlementAction({ id: bill.id, value: true, }), diff --git a/src/features/dashboard/use-invoices-widget-controller.ts b/src/features/dashboard/use-invoices-widget-controller.ts index 2003568..fe00137 100644 --- a/src/features/dashboard/use-invoices-widget-controller.ts +++ b/src/features/dashboard/use-invoices-widget-controller.ts @@ -31,7 +31,7 @@ export function useInvoicesWidgetController( isItemConfirmed: (invoice) => isInvoicePaid(invoice.paymentStatus), executeConfirm: (invoice) => updateInvoicePaymentStatusAction({ - cartaoId: invoice.cardId, + cardId: invoice.cardId, period: invoice.period, status: INVOICE_PAYMENT_STATUS.PAID, }), diff --git a/src/features/dashboard/widgets/actions.ts b/src/features/dashboard/widgets/actions.ts index a316242..e89d244 100644 --- a/src/features/dashboard/widgets/actions.ts +++ b/src/features/dashboard/widgets/actions.ts @@ -18,21 +18,21 @@ export async function updateWidgetPreferences( // Check if preferences exist const existing = await db - .select({ id: schema.preferenciasUsuario.id }) - .from(schema.preferenciasUsuario) - .where(eq(schema.preferenciasUsuario.userId, user.id)) + .select({ id: schema.userPreferences.id }) + .from(schema.userPreferences) + .where(eq(schema.userPreferences.userId, user.id)) .limit(1); if (existing.length > 0) { await db - .update(schema.preferenciasUsuario) + .update(schema.userPreferences) .set({ dashboardWidgets: preferences, updatedAt: new Date(), }) - .where(eq(schema.preferenciasUsuario.userId, user.id)); + .where(eq(schema.userPreferences.userId, user.id)); } else { - await db.insert(schema.preferenciasUsuario).values({ + await db.insert(schema.userPreferences).values({ userId: user.id, dashboardWidgets: preferences, }); @@ -54,12 +54,12 @@ export async function resetWidgetPreferences(): Promise<{ const user = await getUser(); await db - .update(schema.preferenciasUsuario) + .update(schema.userPreferences) .set({ dashboardWidgets: null, updatedAt: new Date(), }) - .where(eq(schema.preferenciasUsuario.userId, user.id)); + .where(eq(schema.userPreferences.userId, user.id)); revalidatePath("/dashboard"); return { success: true }; diff --git a/src/features/dashboard/widgets/widgets-config.tsx b/src/features/dashboard/widgets/widgets-config.tsx index 8eb78a9..38fbf72 100644 --- a/src/features/dashboard/widgets/widgets-config.tsx +++ b/src/features/dashboard/widgets/widgets-config.tsx @@ -97,7 +97,7 @@ export const widgetsConfig: WidgetConfig[] = [ subtitle: "Despesas por pagador no período", icon: , component: ({ data }) => ( - + ), action: ( `coalesce(sum(${lancamentos.amount}), 0)`, + transactionType: transactions.transactionType, + totalAmount: sql`coalesce(sum(${transactions.amount}), 0)`, }) - .from(lancamentos) - .innerJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) + .from(transactions) + .innerJoin(payers, eq(transactions.payerId, payers.id)) .where( and( - eq(lancamentos.userId, userId), - eq(lancamentos.period, period), - eq(pagadores.role, PAGADOR_ROLE_ADMIN), - ne(lancamentos.transactionType, TRANSFERENCIA), + eq(transactions.userId, userId), + eq(transactions.period, period), + eq(payers.role, PAYER_ROLE_ADMIN), + ne(transactions.transactionType, TRANSFERENCIA), or( - isNull(lancamentos.note), + isNull(transactions.note), sql`${ - lancamentos.note + transactions.note } NOT LIKE ${`${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`}`, ), ), ) - .groupBy(lancamentos.transactionType), + .groupBy(transactions.transactionType), db .select({ - transactionType: lancamentos.transactionType, - totalAmount: sql`coalesce(sum(${lancamentos.amount}), 0)`, + transactionType: transactions.transactionType, + totalAmount: sql`coalesce(sum(${transactions.amount}), 0)`, }) - .from(lancamentos) - .innerJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) + .from(transactions) + .innerJoin(payers, eq(transactions.payerId, payers.id)) .where( and( - eq(lancamentos.userId, userId), - eq(lancamentos.period, previousPeriod), - eq(pagadores.role, PAGADOR_ROLE_ADMIN), - ne(lancamentos.transactionType, TRANSFERENCIA), + eq(transactions.userId, userId), + eq(transactions.period, previousPeriod), + eq(payers.role, PAYER_ROLE_ADMIN), + ne(transactions.transactionType, TRANSFERENCIA), or( - isNull(lancamentos.note), + isNull(transactions.note), sql`${ - lancamentos.note + transactions.note } NOT LIKE ${`${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`}`, ), ), ) - .groupBy(lancamentos.transactionType), + .groupBy(transactions.transactionType), db .select({ - transactionType: lancamentos.transactionType, - totalAmount: sql`coalesce(sum(${lancamentos.amount}), 0)`, + transactionType: transactions.transactionType, + totalAmount: sql`coalesce(sum(${transactions.amount}), 0)`, }) - .from(lancamentos) - .innerJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) + .from(transactions) + .innerJoin(payers, eq(transactions.payerId, payers.id)) .where( and( - eq(lancamentos.userId, userId), - eq(lancamentos.period, twoMonthsAgo), - eq(pagadores.role, PAGADOR_ROLE_ADMIN), - ne(lancamentos.transactionType, TRANSFERENCIA), + eq(transactions.userId, userId), + eq(transactions.period, twoMonthsAgo), + eq(payers.role, PAYER_ROLE_ADMIN), + ne(transactions.transactionType, TRANSFERENCIA), or( - isNull(lancamentos.note), + isNull(transactions.note), sql`${ - lancamentos.note + transactions.note } NOT LIKE ${`${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`}`, ), ), ) - .groupBy(lancamentos.transactionType), + .groupBy(transactions.transactionType), db .select({ - transactionType: lancamentos.transactionType, - totalAmount: sql`coalesce(sum(${lancamentos.amount}), 0)`, + transactionType: transactions.transactionType, + totalAmount: sql`coalesce(sum(${transactions.amount}), 0)`, }) - .from(lancamentos) - .innerJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) + .from(transactions) + .innerJoin(payers, eq(transactions.payerId, payers.id)) .where( and( - eq(lancamentos.userId, userId), - eq(lancamentos.period, threeMonthsAgo), - eq(pagadores.role, PAGADOR_ROLE_ADMIN), - ne(lancamentos.transactionType, TRANSFERENCIA), + eq(transactions.userId, userId), + eq(transactions.period, threeMonthsAgo), + eq(payers.role, PAYER_ROLE_ADMIN), + ne(transactions.transactionType, TRANSFERENCIA), or( - isNull(lancamentos.note), + isNull(transactions.note), sql`${ - lancamentos.note + transactions.note } NOT LIKE ${`${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`}`, ), ), ) - .groupBy(lancamentos.transactionType), + .groupBy(transactions.transactionType), ]); // Calcular totais dos últimos 3 meses @@ -187,107 +187,107 @@ async function aggregateMonthData(userId: string, period: string) { // Buscar despesas por categoria (top 5) const expensesByCategory = await db .select({ - categoryName: categorias.name, - total: sql`coalesce(sum(${lancamentos.amount}), 0)`, + categoryName: categories.name, + total: sql`coalesce(sum(${transactions.amount}), 0)`, }) - .from(lancamentos) - .innerJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) - .innerJoin(categorias, eq(lancamentos.categoriaId, categorias.id)) + .from(transactions) + .innerJoin(payers, eq(transactions.payerId, payers.id)) + .innerJoin(categories, eq(transactions.categoryId, categories.id)) .where( and( - eq(lancamentos.userId, userId), - eq(lancamentos.period, period), - eq(lancamentos.transactionType, "Despesa"), - eq(pagadores.role, PAGADOR_ROLE_ADMIN), - eq(categorias.type, "despesa"), + eq(transactions.userId, userId), + eq(transactions.period, period), + eq(transactions.transactionType, "Despesa"), + eq(payers.role, PAYER_ROLE_ADMIN), + eq(categories.type, "despesa"), or( - isNull(lancamentos.note), + isNull(transactions.note), sql`${ - lancamentos.note + transactions.note } NOT LIKE ${`${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`}`, ), ), ) - .groupBy(categorias.name) - .orderBy(sql`sum(${lancamentos.amount}) ASC`) + .groupBy(categories.name) + .orderBy(sql`sum(${transactions.amount}) ASC`) .limit(5); // Buscar orçamentos e uso const budgetsData = await db .select({ - categoryName: categorias.name, - budgetAmount: orcamentos.amount, - spent: sql`coalesce(sum(${lancamentos.amount}), 0)`, + categoryName: categories.name, + budgetAmount: budgets.amount, + spent: sql`coalesce(sum(${transactions.amount}), 0)`, }) - .from(orcamentos) - .innerJoin(categorias, eq(orcamentos.categoriaId, categorias.id)) + .from(budgets) + .innerJoin(categories, eq(budgets.categoryId, categories.id)) .leftJoin( - lancamentos, + transactions, and( - eq(lancamentos.categoriaId, categorias.id), - eq(lancamentos.period, period), - eq(lancamentos.userId, userId), - eq(lancamentos.transactionType, "Despesa"), + eq(transactions.categoryId, categories.id), + eq(transactions.period, period), + eq(transactions.userId, userId), + eq(transactions.transactionType, "Despesa"), ), ) - .where(and(eq(orcamentos.userId, userId), eq(orcamentos.period, period))) - .groupBy(categorias.name, orcamentos.amount); + .where(and(eq(budgets.userId, userId), eq(budgets.period, period))) + .groupBy(categories.name, budgets.amount); // Buscar métricas de cartões const cardsData = await db .select({ - totalLimit: sql`coalesce(sum(${cartoes.limit}), 0)`, + totalLimit: sql`coalesce(sum(${cards.limit}), 0)`, cardCount: sql`count(*)`, }) - .from(cartoes) - .where(and(eq(cartoes.userId, userId), eq(cartoes.status, "ativo"))); + .from(cards) + .where(and(eq(cards.userId, userId), eq(cards.status, "ativo"))); - // Buscar saldo total das contas + // Buscar saldo total das financialAccounts const accountsData = await db .select({ - totalBalance: sql`coalesce(sum(${contas.initialBalance}), 0)`, + totalBalance: sql`coalesce(sum(${financialAccounts.initialBalance}), 0)`, accountCount: sql`count(*)`, }) - .from(contas) + .from(financialAccounts) .where( and( - eq(contas.userId, userId), - eq(contas.status, "ativa"), - eq(contas.excludeFromBalance, false), + eq(financialAccounts.userId, userId), + eq(financialAccounts.status, "ativa"), + eq(financialAccounts.excludeFromBalance, false), ), ); // Calcular ticket médio das transações const avgTicketData = await db .select({ - avgAmount: sql`coalesce(avg(abs(${lancamentos.amount})), 0)`, + avgAmount: sql`coalesce(avg(abs(${transactions.amount})), 0)`, transactionCount: sql`count(*)`, }) - .from(lancamentos) - .innerJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) + .from(transactions) + .innerJoin(payers, eq(transactions.payerId, payers.id)) .where( and( - eq(lancamentos.userId, userId), - eq(lancamentos.period, period), - eq(pagadores.role, PAGADOR_ROLE_ADMIN), - ne(lancamentos.transactionType, TRANSFERENCIA), + eq(transactions.userId, userId), + eq(transactions.period, period), + eq(payers.role, PAYER_ROLE_ADMIN), + ne(transactions.transactionType, TRANSFERENCIA), ), ); // Buscar gastos por dia da semana const dayOfWeekSpending = await db .select({ - purchaseDate: lancamentos.purchaseDate, - amount: lancamentos.amount, + purchaseDate: transactions.purchaseDate, + amount: transactions.amount, }) - .from(lancamentos) - .innerJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) + .from(transactions) + .innerJoin(payers, eq(transactions.payerId, payers.id)) .where( and( - eq(lancamentos.userId, userId), - eq(lancamentos.period, period), - eq(lancamentos.transactionType, "Despesa"), - eq(pagadores.role, PAGADOR_ROLE_ADMIN), + eq(transactions.userId, userId), + eq(transactions.period, period), + eq(transactions.transactionType, "Despesa"), + eq(payers.role, PAYER_ROLE_ADMIN), ), ); @@ -303,45 +303,45 @@ async function aggregateMonthData(userId: string, period: string) { // Buscar métodos de pagamento (agregado) const paymentMethodsData = await db .select({ - paymentMethod: lancamentos.paymentMethod, - total: sql`coalesce(sum(abs(${lancamentos.amount})), 0)`, + paymentMethod: transactions.paymentMethod, + total: sql`coalesce(sum(abs(${transactions.amount})), 0)`, }) - .from(lancamentos) - .innerJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) + .from(transactions) + .innerJoin(payers, eq(transactions.payerId, payers.id)) .where( and( - eq(lancamentos.userId, userId), - eq(lancamentos.period, period), - eq(lancamentos.transactionType, "Despesa"), - eq(pagadores.role, PAGADOR_ROLE_ADMIN), + eq(transactions.userId, userId), + eq(transactions.period, period), + eq(transactions.transactionType, "Despesa"), + eq(payers.role, PAYER_ROLE_ADMIN), ), ) - .groupBy(lancamentos.paymentMethod); + .groupBy(transactions.paymentMethod); // Buscar transações dos últimos 3 meses para análise de recorrência const last3MonthsTransactions = await db .select({ - name: lancamentos.name, - amount: lancamentos.amount, - period: lancamentos.period, - condition: lancamentos.condition, - installmentCount: lancamentos.installmentCount, - currentInstallment: lancamentos.currentInstallment, - categoryName: categorias.name, + name: transactions.name, + amount: transactions.amount, + period: transactions.period, + condition: transactions.condition, + installmentCount: transactions.installmentCount, + currentInstallment: transactions.currentInstallment, + categoryName: categories.name, }) - .from(lancamentos) - .innerJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) - .leftJoin(categorias, eq(lancamentos.categoriaId, categorias.id)) + .from(transactions) + .innerJoin(payers, eq(transactions.payerId, payers.id)) + .leftJoin(categories, eq(transactions.categoryId, categories.id)) .where( and( - eq(lancamentos.userId, userId), - sql`${lancamentos.period} IN (${period}, ${previousPeriod}, ${twoMonthsAgo})`, - eq(lancamentos.transactionType, "Despesa"), - eq(pagadores.role, PAGADOR_ROLE_ADMIN), - ne(lancamentos.transactionType, TRANSFERENCIA), + eq(transactions.userId, userId), + sql`${transactions.period} IN (${period}, ${previousPeriod}, ${twoMonthsAgo})`, + eq(transactions.transactionType, "Despesa"), + eq(payers.role, PAYER_ROLE_ADMIN), + ne(transactions.transactionType, TRANSFERENCIA), ), ) - .orderBy(lancamentos.name); + .orderBy(transactions.name); // Análise de recorrência const transactionsByName = new Map< @@ -656,7 +656,7 @@ DADOS IMPORTANTES PARA SUA ANÁLISE: - Comprometimento futuro de R$ ${aggregatedData.installments.futureCommitment.toFixed(2)} - Use isso para alertas sobre comprometimento de renda futura -Organize suas observações nas 4 categorias especificadas no prompt do sistema: +Organize suas observações nas 4 categories especificadas no prompt do sistema: 1. Comportamentos Observados (behaviors): 3-6 itens 2. Gatilhos de Consumo (triggers): 3-6 itens 3. Recomendações Práticas (recommendations): 3-6 itens @@ -697,11 +697,11 @@ export async function saveInsightsAction( // Verificar se já existe um insight salvo para este período const existing = await db .select() - .from(insightsSalvos) + .from(savedInsights) .where( and( - eq(insightsSalvos.userId, user.id), - eq(insightsSalvos.period, period), + eq(savedInsights.userId, user.id), + eq(savedInsights.period, period), ), ) .limit(1); @@ -709,7 +709,7 @@ export async function saveInsightsAction( if (existing.length > 0) { // Atualizar existente const updated = await db - .update(insightsSalvos) + .update(savedInsights) .set({ modelId, data: JSON.stringify(data), @@ -717,13 +717,13 @@ export async function saveInsightsAction( }) .where( and( - eq(insightsSalvos.userId, user.id), - eq(insightsSalvos.period, period), + eq(savedInsights.userId, user.id), + eq(savedInsights.period, period), ), ) .returning({ - id: insightsSalvos.id, - createdAt: insightsSalvos.createdAt, + id: savedInsights.id, + createdAt: savedInsights.createdAt, }); const updatedRecord = updated[0]; @@ -745,7 +745,7 @@ export async function saveInsightsAction( // Criar novo const result = await db - .insert(insightsSalvos) + .insert(savedInsights) .values({ userId: user.id, period, @@ -753,8 +753,8 @@ export async function saveInsightsAction( data: JSON.stringify(data), }) .returning({ - id: insightsSalvos.id, - createdAt: insightsSalvos.createdAt, + id: savedInsights.id, + createdAt: savedInsights.createdAt, }); const insertedRecord = result[0]; @@ -796,11 +796,11 @@ export async function loadSavedInsightsAction(period: string): Promise< const result = await db .select() - .from(insightsSalvos) + .from(savedInsights) .where( and( - eq(insightsSalvos.userId, user.id), - eq(insightsSalvos.period, period), + eq(savedInsights.userId, user.id), + eq(savedInsights.period, period), ), ) .limit(1); @@ -849,11 +849,11 @@ export async function deleteSavedInsightsAction( const user = await getUser(); await db - .delete(insightsSalvos) + .delete(savedInsights) .where( and( - eq(insightsSalvos.userId, user.id), - eq(insightsSalvos.period, period), + eq(savedInsights.userId, user.id), + eq(savedInsights.period, period), ), ); diff --git a/src/features/recurring/actions.ts b/src/features/recurring/actions.ts index af7f0a6..b38ec2f 100644 --- a/src/features/recurring/actions.ts +++ b/src/features/recurring/actions.ts @@ -12,7 +12,7 @@ import { db } from "@/shared/lib/db"; import { recurringSeriesActionSchema } from "@/shared/lib/schemas/recurring-series"; import type { ActionResult } from "@/shared/lib/types/actions"; -const revalidate = () => revalidateForEntity("recorrentes"); +const revalidate = () => revalidateForEntity("recurring"); async function findRecurringSeriesForUser(userId: string, seriesId: string) { const [series] = await db diff --git a/src/features/recurring/generate-recurring.ts b/src/features/recurring/generate-recurring.ts index a01c12f..3dc6a86 100644 --- a/src/features/recurring/generate-recurring.ts +++ b/src/features/recurring/generate-recurring.ts @@ -1,5 +1,5 @@ import { and, eq } from "drizzle-orm"; -import { lancamentos, recurringSeries } from "@/db/schema"; +import { recurringSeries, transactions } from "@/db/schema"; import { db } from "@/shared/lib/db"; import { addMonthsToPeriod, @@ -76,7 +76,7 @@ export async function generateRecurringTransactions( const template = series.templateData; - // Create all lancamentos for missing periods in a transaction + // Create all transactions for missing periods in a transaction await db.transaction(async (tx: typeof db) => { const records = periodsToGenerate.map((period) => { const purchaseDate = computePurchaseDate(period, series.dayOfMonth); @@ -86,10 +86,10 @@ export async function generateRecurringTransactions( transactionType: template.transactionType, paymentMethod: template.paymentMethod, condition: "Recorrente" as const, - categoriaId: template.categoriaId, - contaId: template.contaId, - cartaoId: template.cartaoId, - pagadorId: template.pagadorId, + categoryId: template.categoryId, + accountId: template.accountId, + cardId: template.cardId, + payerId: template.payerId, note: template.note, purchaseDate, period, @@ -104,7 +104,7 @@ export async function generateRecurringTransactions( }; }); - await tx.insert(lancamentos).values(records); + await tx.insert(transactions).values(records); // Update lastGeneratedPeriod to the last period we generated const lastPeriod = diff --git a/src/features/reports/cards-report-queries.ts b/src/features/reports/cards-report-queries.ts index b271256..a3b690d 100644 --- a/src/features/reports/cards-report-queries.ts +++ b/src/features/reports/cards-report-queries.ts @@ -11,15 +11,9 @@ import { sql, sum, } from "drizzle-orm"; -import { - cartoes, - categorias, - faturas, - lancamentos, - pagadores, -} from "@/db/schema"; +import { cards, categories, invoices, payers, transactions } from "@/db/schema"; import { db } from "@/shared/lib/db"; -import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants"; +import { PAYER_ROLE_ADMIN } from "@/shared/lib/payers/constants"; import { formatDateOnly } from "@/shared/utils/date"; import { safeToNumber } from "@/shared/utils/number"; import { @@ -90,7 +84,7 @@ type CardRow = { }; type CardUsageRow = { - cartaoId: string | null; + cardId: string | null; totalAmount: unknown; }; @@ -100,7 +94,7 @@ type MonthlyUsageRow = { }; type CategoryAmountRow = { - categoriaId: string | null; + categoryId: string | null; totalAmount: unknown; }; @@ -115,7 +109,7 @@ type TopExpenseRow = { name: string; amount: unknown; purchaseDate: Date | string | null; - categoriaId: string | null; + categoryId: string | null; }; type InvoiceStatusRow = { @@ -133,16 +127,16 @@ export async function fetchCartoesReportData( // Fetch all active cards (not inactive) const allCards = (await db .select({ - id: cartoes.id, - name: cartoes.name, - brand: cartoes.brand, - logo: cartoes.logo, - limit: cartoes.limit, - status: cartoes.status, + id: cards.id, + name: cards.name, + brand: cards.brand, + logo: cards.logo, + limit: cards.limit, + status: cards.status, }) - .from(cartoes) + .from(cards) .where( - and(eq(cartoes.userId, userId), not(ilike(cartoes.status, "inativo"))), + and(eq(cards.userId, userId), not(ilike(cards.status, "inativo"))), )) as CardRow[]; if (allCards.length === 0) { @@ -160,67 +154,61 @@ export async function fetchCartoesReportData( // Fetch current period usage by card (recorrente só conta quando a data da ocorrência já passou) const currentUsageData = (await db .select({ - cartaoId: lancamentos.cartaoId, - totalAmount: sum(lancamentos.amount).as("total"), + cardId: transactions.cardId, + totalAmount: sum(transactions.amount).as("total"), }) - .from(lancamentos) - .innerJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) + .from(transactions) + .innerJoin(payers, eq(transactions.payerId, payers.id)) .where( and( - eq(lancamentos.userId, userId), - eq(lancamentos.period, currentPeriod), - eq(pagadores.role, PAGADOR_ROLE_ADMIN), - eq(lancamentos.transactionType, DESPESA), - inArray(lancamentos.cartaoId, cardIds), + eq(transactions.userId, userId), + eq(transactions.period, currentPeriod), + eq(payers.role, PAYER_ROLE_ADMIN), + eq(transactions.transactionType, DESPESA), + inArray(transactions.cardId, cardIds), or( - ne(lancamentos.condition, "Recorrente"), - sql`${lancamentos.purchaseDate} <= current_date`, + ne(transactions.condition, "Recorrente"), + sql`${transactions.purchaseDate} <= current_date`, ), ), ) - .groupBy(lancamentos.cartaoId)) as CardUsageRow[]; + .groupBy(transactions.cardId)) as CardUsageRow[]; // Fetch previous period usage by card const previousUsageData = (await db .select({ - cartaoId: lancamentos.cartaoId, - totalAmount: sum(lancamentos.amount).as("total"), + cardId: transactions.cardId, + totalAmount: sum(transactions.amount).as("total"), }) - .from(lancamentos) - .innerJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) + .from(transactions) + .innerJoin(payers, eq(transactions.payerId, payers.id)) .where( and( - eq(lancamentos.userId, userId), - eq(lancamentos.period, previousPeriod), - eq(pagadores.role, PAGADOR_ROLE_ADMIN), - eq(lancamentos.transactionType, DESPESA), - inArray(lancamentos.cartaoId, cardIds), + eq(transactions.userId, userId), + eq(transactions.period, previousPeriod), + eq(payers.role, PAYER_ROLE_ADMIN), + eq(transactions.transactionType, DESPESA), + inArray(transactions.cardId, cardIds), ), ) - .groupBy(lancamentos.cartaoId)) as CardUsageRow[]; + .groupBy(transactions.cardId)) as CardUsageRow[]; const currentUsageMap = new Map(); for (const row of currentUsageData) { - if (row.cartaoId) { - currentUsageMap.set( - row.cartaoId, - Math.abs(safeToNumber(row.totalAmount)), - ); + if (row.cardId) { + currentUsageMap.set(row.cardId, Math.abs(safeToNumber(row.totalAmount))); } } const previousUsageMap = new Map(); for (const row of previousUsageData) { - if (row.cartaoId) { - previousUsageMap.set( - row.cartaoId, - Math.abs(safeToNumber(row.totalAmount)), - ); + if (row.cardId) { + previousUsageMap.set(row.cardId, Math.abs(safeToNumber(row.totalAmount))); } } // Build card summaries - const cards: CardSummary[] = allCards.map((card) => { + const cardSummaries: CardSummary[] = allCards.map((card) => { const limit = safeToNumber(card.limit); const currentUsage = currentUsageMap.get(card.id) || 0; const previousUsage = previousUsageMap.get(card.id) || 0; @@ -252,22 +240,22 @@ export async function fetchCartoesReportData( }; }); - // Sort cards by usage (descending) - cards.sort((a, b) => b.currentUsage - a.currentUsage); + // Sort cardSummaries by usage (descending) + cardSummaries.sort((a, b) => b.currentUsage - a.currentUsage); // Calculate totals - const totalLimit = cards.reduce((acc, c) => acc + c.limit, 0); - const totalUsage = cards.reduce((acc, c) => acc + c.currentUsage, 0); + const totalLimit = cardSummaries.reduce((acc, c) => acc + c.limit, 0); + const totalUsage = cardSummaries.reduce((acc, c) => acc + c.currentUsage, 0); const totalUsagePercent = totalLimit > 0 ? (totalUsage / totalLimit) * 100 : 0; // Fetch selected card details if provided let selectedCard: CardDetailData | null = null; const targetCardId = - selectedCartaoId || (cards.length > 0 ? cards[0].id : null); + selectedCartaoId || (cardSummaries.length > 0 ? cardSummaries[0].id : null); if (targetCardId) { - const cardSummary = cards.find((c) => c.id === targetCardId); + const cardSummary = cardSummaries.find((c) => c.id === targetCardId); if (cardSummary) { selectedCard = await fetchCardDetail( userId, @@ -279,7 +267,7 @@ export async function fetchCartoesReportData( } return { - cards, + cards: cardSummaries, totalLimit, totalUsage, totalUsagePercent, @@ -301,23 +289,23 @@ async function fetchCardDetail( // Fetch monthly usage const monthlyData = (await db .select({ - period: lancamentos.period, - totalAmount: sum(lancamentos.amount).as("total"), + period: transactions.period, + totalAmount: sum(transactions.amount).as("total"), }) - .from(lancamentos) - .innerJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) + .from(transactions) + .innerJoin(payers, eq(transactions.payerId, payers.id)) .where( and( - eq(lancamentos.userId, userId), - eq(lancamentos.cartaoId, cardId), - gte(lancamentos.period, startPeriod), - lte(lancamentos.period, currentPeriod), - eq(pagadores.role, PAGADOR_ROLE_ADMIN), - eq(lancamentos.transactionType, DESPESA), + eq(transactions.userId, userId), + eq(transactions.cardId, cardId), + gte(transactions.period, startPeriod), + lte(transactions.period, currentPeriod), + eq(payers.role, PAYER_ROLE_ADMIN), + eq(transactions.transactionType, DESPESA), ), ) - .groupBy(lancamentos.period) - .orderBy(lancamentos.period)) as MonthlyUsageRow[]; + .groupBy(transactions.period) + .orderBy(transactions.period)) as MonthlyUsageRow[]; const monthlyUsage = periods.map((period) => { const data = monthlyData.find((d) => d.period === period); @@ -331,37 +319,37 @@ async function fetchCardDetail( // Fetch category breakdown for current period const categoryData = (await db .select({ - categoriaId: lancamentos.categoriaId, - totalAmount: sum(lancamentos.amount).as("total"), + categoryId: transactions.categoryId, + totalAmount: sum(transactions.amount).as("total"), }) - .from(lancamentos) - .innerJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) + .from(transactions) + .innerJoin(payers, eq(transactions.payerId, payers.id)) .where( and( - eq(lancamentos.userId, userId), - eq(lancamentos.cartaoId, cardId), - eq(lancamentos.period, currentPeriod), - eq(pagadores.role, PAGADOR_ROLE_ADMIN), - eq(lancamentos.transactionType, DESPESA), + eq(transactions.userId, userId), + eq(transactions.cardId, cardId), + eq(transactions.period, currentPeriod), + eq(payers.role, PAYER_ROLE_ADMIN), + eq(transactions.transactionType, DESPESA), ), ) - .groupBy(lancamentos.categoriaId)) as CategoryAmountRow[]; + .groupBy(transactions.categoryId)) as CategoryAmountRow[]; // Fetch category names const categoryIds = categoryData - .map((c) => c.categoriaId) + .map((c) => c.categoryId) .filter((id): id is string => id !== null); const categoryNames = categoryIds.length > 0 ? ((await db .select({ - id: categorias.id, - name: categorias.name, - icon: categorias.icon, + id: categories.id, + name: categories.name, + icon: categories.icon, }) - .from(categorias) - .where(inArray(categorias.id, categoryIds))) as CategoryInfoRow[]) + .from(categories) + .where(inArray(categories.id, categoryIds))) as CategoryInfoRow[]) : ([] as CategoryInfoRow[]); const categoryNameMap = new Map(categoryNames.map((c) => [c.id, c])); @@ -374,11 +362,11 @@ async function fetchCardDetail( const categoryBreakdown = categoryData .map((cat) => { const amount = Math.abs(safeToNumber(cat.totalAmount)); - const catInfo = cat.categoriaId - ? categoryNameMap.get(cat.categoriaId) + const catInfo = cat.categoryId + ? categoryNameMap.get(cat.categoryId) : null; return { - id: cat.categoriaId || "sem-categoria", + id: cat.categoryId || "sem-categoria", name: catInfo?.name || "Sem categoria", icon: catInfo?.icon || null, amount, @@ -392,29 +380,29 @@ async function fetchCardDetail( // Fetch top expenses for current period const topExpensesData = (await db .select({ - id: lancamentos.id, - name: lancamentos.name, - amount: lancamentos.amount, - purchaseDate: lancamentos.purchaseDate, - categoriaId: lancamentos.categoriaId, + id: transactions.id, + name: transactions.name, + amount: transactions.amount, + purchaseDate: transactions.purchaseDate, + categoryId: transactions.categoryId, }) - .from(lancamentos) - .innerJoin(pagadores, eq(lancamentos.pagadorId, pagadores.id)) + .from(transactions) + .innerJoin(payers, eq(transactions.payerId, payers.id)) .where( and( - eq(lancamentos.userId, userId), - eq(lancamentos.cartaoId, cardId), - eq(lancamentos.period, currentPeriod), - eq(pagadores.role, PAGADOR_ROLE_ADMIN), - eq(lancamentos.transactionType, DESPESA), + eq(transactions.userId, userId), + eq(transactions.cardId, cardId), + eq(transactions.period, currentPeriod), + eq(payers.role, PAYER_ROLE_ADMIN), + eq(transactions.transactionType, DESPESA), ), ) - .orderBy(lancamentos.amount) + .orderBy(transactions.amount) .limit(10)) as TopExpenseRow[]; const topExpenses = topExpensesData.map((expense) => { - const catInfo = expense.categoriaId - ? categoryNameMap.get(expense.categoriaId) + const catInfo = expense.categoryId + ? categoryNameMap.get(expense.categoryId) : null; return { id: expense.id, @@ -433,19 +421,19 @@ async function fetchCardDetail( // Fetch invoice status for last 6 months const invoiceData = (await db .select({ - period: faturas.period, - status: faturas.paymentStatus, + period: invoices.period, + status: invoices.paymentStatus, }) - .from(faturas) + .from(invoices) .where( and( - eq(faturas.userId, userId), - eq(faturas.cartaoId, cardId), - gte(faturas.period, startPeriod), - lte(faturas.period, currentPeriod), + eq(invoices.userId, userId), + eq(invoices.cardId, cardId), + gte(invoices.period, startPeriod), + lte(invoices.period, currentPeriod), ), ) - .orderBy(faturas.period)) as InvoiceStatusRow[]; + .orderBy(invoices.period)) as InvoiceStatusRow[]; const invoiceStatus = periods.map((period) => { const invoice = invoiceData.find((i) => i.period === period); diff --git a/src/features/reports/category-chart-queries.ts b/src/features/reports/category-chart-queries.ts index 5ea8f86..6dc7191 100644 --- a/src/features/reports/category-chart-queries.ts +++ b/src/features/reports/category-chart-queries.ts @@ -1,8 +1,8 @@ import { and, eq, inArray, isNull, or, sql } from "drizzle-orm"; -import { categorias, lancamentos } from "@/db/schema"; +import { categories, transactions } from "@/db/schema"; import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/shared/lib/accounts/constants"; import { db } from "@/shared/lib/db"; -import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { getAdminPayerId } from "@/shared/lib/payers/get-admin-id"; import { safeToNumber as toNumber } from "@/shared/utils/number"; import { formatPeriodMonthShort } from "@/shared/utils/period"; import { generatePeriodRange } from "./utils"; @@ -35,56 +35,56 @@ export async function fetchCategoryChartData( ): Promise { const periods = generatePeriodRange(startPeriod, endPeriod); - const adminPagadorId = await getAdminPagadorId(userId); - if (!adminPagadorId) { + const adminPayerId = await getAdminPayerId(userId); + if (!adminPayerId) { return { months: [], categories: [], chartData: [], allCategories: [] }; } const whereConditions = [ - eq(lancamentos.userId, userId), - eq(lancamentos.pagadorId, adminPagadorId), - inArray(lancamentos.period, periods), - or(eq(categorias.type, "despesa"), eq(categorias.type, "receita")), + eq(transactions.userId, userId), + eq(transactions.payerId, adminPayerId), + inArray(transactions.period, periods), + or(eq(categories.type, "despesa"), eq(categories.type, "receita")), or( - isNull(lancamentos.note), - sql`${lancamentos.note} NOT LIKE ${`${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`}`, + isNull(transactions.note), + sql`${transactions.note} NOT LIKE ${`${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`}`, ), ]; if (categoryIds && categoryIds.length > 0) { - whereConditions.push(inArray(categorias.id, categoryIds)); + whereConditions.push(inArray(categories.id, categoryIds)); } const [rows, allCategoriesRows] = await Promise.all([ db .select({ - categoryId: categorias.id, - categoryName: categorias.name, - categoryIcon: categorias.icon, - categoryType: categorias.type, - period: lancamentos.period, - total: sql`coalesce(sum(abs(${lancamentos.amount})), 0)`, + categoryId: categories.id, + categoryName: categories.name, + categoryIcon: categories.icon, + categoryType: categories.type, + period: transactions.period, + total: sql`coalesce(sum(abs(${transactions.amount})), 0)`, }) - .from(lancamentos) - .innerJoin(categorias, eq(lancamentos.categoriaId, categorias.id)) + .from(transactions) + .innerJoin(categories, eq(transactions.categoryId, categories.id)) .where(and(...whereConditions)) .groupBy( - categorias.id, - categorias.name, - categorias.icon, - categorias.type, - lancamentos.period, + categories.id, + categories.name, + categories.icon, + categories.type, + transactions.period, ), db .select({ - id: categorias.id, - name: categorias.name, - icon: categorias.icon, - type: categorias.type, + id: categories.id, + name: categories.name, + icon: categories.icon, + type: categories.type, }) - .from(categorias) - .where(eq(categorias.userId, userId)) - .orderBy(categorias.type, categorias.name), + .from(categories) + .where(eq(categories.userId, userId)) + .orderBy(categories.type, categories.name), ]); const allCategories = allCategoriesRows.map( @@ -143,12 +143,12 @@ export async function fetchCategoryChartData( formatPeriodMonthShort(period).toUpperCase(), ); - const categories = Array.from(categoryMap.values()).map((cat) => ({ + const categoryList = Array.from(categoryMap.values()).map((cat) => ({ id: cat.id, name: cat.name, icon: cat.icon, type: cat.type, })); - return { months, categories, chartData, allCategories }; + return { months, categories: categoryList, chartData, allCategories }; } diff --git a/src/features/reports/category-report-queries.ts b/src/features/reports/category-report-queries.ts index 797cc22..64c1eee 100644 --- a/src/features/reports/category-report-queries.ts +++ b/src/features/reports/category-report-queries.ts @@ -1,8 +1,8 @@ import { and, eq, inArray, isNull, or, sql } from "drizzle-orm"; -import { categorias, lancamentos } from "@/db/schema"; +import { categories, transactions } from "@/db/schema"; import { ACCOUNT_AUTO_INVOICE_NOTE_PREFIX } from "@/shared/lib/accounts/constants"; import { db } from "@/shared/lib/db"; -import { getAdminPagadorId } from "@/shared/lib/payers/get-admin-id"; +import { getAdminPayerId } from "@/shared/lib/payers/get-admin-id"; import { safeToNumber as toNumber } from "@/shared/utils/number"; import type { CategoryReportData, @@ -28,47 +28,47 @@ export async function fetchCategoryReport( // Generate all periods in the range const periods = generatePeriodRange(startPeriod, endPeriod); - const adminPagadorId = await getAdminPagadorId(userId); - if (!adminPagadorId) { + const adminPayerId = await getAdminPayerId(userId); + if (!adminPayerId) { return { categories: [], periods, totals: new Map(), grandTotal: 0 }; } // Build WHERE conditions const whereConditions = [ - eq(lancamentos.userId, userId), - eq(lancamentos.pagadorId, adminPagadorId), - inArray(lancamentos.period, periods), - or(eq(categorias.type, "despesa"), eq(categorias.type, "receita")), + eq(transactions.userId, userId), + eq(transactions.payerId, adminPayerId), + inArray(transactions.period, periods), + or(eq(categories.type, "despesa"), eq(categories.type, "receita")), or( - isNull(lancamentos.note), - sql`${lancamentos.note} NOT LIKE ${`${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`}`, + isNull(transactions.note), + sql`${transactions.note} NOT LIKE ${`${ACCOUNT_AUTO_INVOICE_NOTE_PREFIX}%`}`, ), ]; // Add optional category filter if (categoryIds && categoryIds.length > 0) { - whereConditions.push(inArray(categorias.id, categoryIds)); + whereConditions.push(inArray(categories.id, categoryIds)); } // Query to get aggregated data by category and period const rows = await db .select({ - categoryId: categorias.id, - categoryName: categorias.name, - categoryIcon: categorias.icon, - categoryType: categorias.type, - period: lancamentos.period, - total: sql`coalesce(sum(${lancamentos.amount}), 0)`, + categoryId: categories.id, + categoryName: categories.name, + categoryIcon: categories.icon, + categoryType: categories.type, + period: transactions.period, + total: sql`coalesce(sum(${transactions.amount}), 0)`, }) - .from(lancamentos) - .innerJoin(categorias, eq(lancamentos.categoriaId, categorias.id)) + .from(transactions) + .innerJoin(categories, eq(transactions.categoryId, categories.id)) .where(and(...whereConditions)) .groupBy( - categorias.id, - categorias.name, - categorias.icon, - categorias.type, - lancamentos.period, + categories.id, + categories.name, + categories.icon, + categories.type, + transactions.period, ); // Process results into CategoryReportData structure @@ -171,10 +171,10 @@ export async function fetchCategoryReport( } // Convert to array and sort - const categories = Array.from(categoryMap.values()); + const categoryList = Array.from(categoryMap.values()); // Sort: despesas first (by total desc), then receitas (by total desc) - categories.sort((a, b) => { + categoryList.sort((a, b) => { // First by type: despesa comes before receita if (a.type !== b.type) { return a.type === "despesa" ? -1 : 1; @@ -185,12 +185,12 @@ export async function fetchCategoryReport( // Calculate grand total let grandTotal = 0; - for (const categoryItem of categories) { + for (const categoryItem of categoryList) { grandTotal += categoryItem.total; } return { - categories, + categories: categoryList, periods, totals: periodTotalsMap, grandTotal, diff --git a/src/features/reports/category-trends-queries.ts b/src/features/reports/category-trends-queries.ts index 89d78e4..d85d766 100644 --- a/src/features/reports/category-trends-queries.ts +++ b/src/features/reports/category-trends-queries.ts @@ -1,12 +1,10 @@ import { asc, eq } from "drizzle-orm"; -import { type Categoria, categorias } from "@/db/schema"; +import { type Category, categories } from "@/db/schema"; import { db } from "@/shared/lib/db"; -export async function fetchUserCategories( - userId: string, -): Promise { - return db.query.categorias.findMany({ - where: eq(categorias.userId, userId), - orderBy: [asc(categorias.name)], +export async function fetchUserCategories(userId: string): Promise { + return db.query.categories.findMany({ + where: eq(categories.userId, userId), + orderBy: [asc(categories.name)], }); } diff --git a/src/features/reports/components/cards/card-category-breakdown.tsx b/src/features/reports/components/cards/card-category-breakdown.tsx index 09032d8..51b01fc 100644 --- a/src/features/reports/components/cards/card-category-breakdown.tsx +++ b/src/features/reports/components/cards/card-category-breakdown.tsx @@ -24,7 +24,7 @@ export function CardCategoryBreakdown({ data }: CardCategoryBreakdownProps) { - Gastos por Categoria + Gastos por Category @@ -45,7 +45,7 @@ export function CardCategoryBreakdown({ data }: CardCategoryBreakdownProps) { - Gastos por Categoria + Gastos por Category diff --git a/src/features/reports/components/category-report-chart.tsx b/src/features/reports/components/category-report-chart.tsx index 3393e20..f3678ee 100644 --- a/src/features/reports/components/category-report-chart.tsx +++ b/src/features/reports/components/category-report-chart.tsx @@ -150,7 +150,7 @@ export function CategoryReportChart({ data }: CategoryReportChartProps) {
      - Evolução por Categoria + Evolução por Category {periodLabel}
      updateField("pagadorId", value)} + value={formState.payerId} + onValueChange={(value) => updateField("payerId", value)} disabled={isPending} > @@ -292,12 +292,12 @@ export function AnticipateInstallmentsDialog({ - Categoria + Category + + + + + + - {cartaoId && + {cardId && (() => { - const selectedOption = cartaoOptions.find( - (opt) => opt.value === cartaoId, + const selectedOption = cardOptions.find( + (opt) => opt.value === cardId, ); return selectedOption ? ( - - {cartaoOptions.length === 0 ? ( + {cardOptions.length === 0 ? (

      Nenhum cartão cadastrado

      ) : ( - cartaoOptions + cardOptions .filter( (option) => !isLockedToCartao || - option.value === defaultCartaoId, + option.value === defaultCardId, ) .map((option) => ( - - {cartaoId ? ( + {cardId ? ( ) : null} - {/* Conta (for non-credit-card methods) */} + {/* FinancialAccount (for non-credit-card methods) */} {!isCartaoSelected ? (
      - - - {contaId && + {accountId && (() => { - const selectedOption = contaOptions.find( - (opt) => opt.value === contaId, + const selectedOption = accountOptions.find( + (opt) => opt.value === accountId, ); return selectedOption ? ( - - {contaOptions.length === 0 ? ( + {accountOptions.length === 0 ? (

      Nenhuma conta cadastrada

      ) : ( - contaOptions.map((option) => ( + accountOptions.map((option) => ( - - Pagador {index + 1} + Payer {index + 1} - updateTransaction( - transaction.id, - "categoriaId", - value, - ) + updateTransaction(transaction.id, "categoryId", value) } > - + {groupedCategorias.map((group) => ( @@ -608,7 +602,7 @@ export function MassAddDialog({ key={option.value} value={option.value} > - diff --git a/src/features/transactions/components/dialogs/transaction-details-dialog.tsx b/src/features/transactions/components/dialogs/transaction-details-dialog.tsx index 614d2a1..3ec865f 100644 --- a/src/features/transactions/components/dialogs/transaction-details-dialog.tsx +++ b/src/features/transactions/components/dialogs/transaction-details-dialog.tsx @@ -25,29 +25,29 @@ import { Separator } from "@/shared/components/ui/separator"; import { parseLocalDateString } from "@/shared/utils/date"; import { getPaymentMethodIcon } from "@/shared/utils/icons"; import { InstallmentTimeline } from "../shared/installment-timeline"; -import type { LancamentoItem } from "../types"; +import type { TransactionItem } from "../types"; -interface LancamentoDetailsDialogProps { +interface TransactionDetailsDialogProps { open: boolean; onOpenChange: (open: boolean) => void; - lancamento: LancamentoItem | null; + transaction: TransactionItem | null; } -export function LancamentoDetailsDialog({ +export function TransactionDetailsDialog({ open, onOpenChange, - lancamento, -}: LancamentoDetailsDialogProps) { - if (!lancamento) return null; + transaction, +}: TransactionDetailsDialogProps) { + if (!transaction) return null; const isInstallment = - lancamento.condition?.toLowerCase() === "parcelado" && - lancamento.currentInstallment && - lancamento.installmentCount; + transaction.condition?.toLowerCase() === "parcelado" && + transaction.currentInstallment && + transaction.installmentCount; - const valorParcela = Math.abs(lancamento.amount); - const totalParcelas = lancamento.installmentCount ?? 1; - const parcelaAtual = lancamento.currentInstallment ?? 1; + const valorParcela = Math.abs(transaction.amount); + const totalParcelas = transaction.installmentCount ?? 1; + const parcelaAtual = transaction.currentInstallment ?? 1; const valorTotal = isInstallment ? valorParcela * totalParcelas : valorParcela; @@ -62,10 +62,10 @@ export function LancamentoDetailsDialog({
      - #{lancamento.id} + #{transaction.id} - {formatDate(lancamento.purchaseDate)} + {formatDate(transaction.purchaseDate)}
      @@ -73,11 +73,11 @@ export function LancamentoDetailsDialog({
        - +
      • @@ -85,21 +85,21 @@ export function LancamentoDetailsDialog({ Forma de Pagamento - {getPaymentMethodIcon(lancamento.paymentMethod)} + {getPaymentMethodIcon(transaction.paymentMethod)} - {lancamento.paymentMethod} + {transaction.paymentMethod}
      • @@ -109,37 +109,37 @@ export function LancamentoDetailsDialog({ - {lancamento.categoriaName === "Saldo inicial" + {transaction.categoriaName === "Saldo inicial" ? "Saldo Inicial" - : lancamento.transactionType} + : transaction.transactionType}
      • Responsável - {lancamento.pagadorName} + {transaction.pagadorName}
      • - {lancamento.note && ( - + {transaction.note && ( + )}
      @@ -148,11 +148,11 @@ export function LancamentoDetailsDialog({
    • )} @@ -169,10 +169,10 @@ export function LancamentoDetailsDialog({ /> )} - {lancamento.recurrenceCount && ( + {transaction.recurrenceCount && ( )} diff --git a/src/features/transactions/components/dialogs/transaction-dialog/category-section.tsx b/src/features/transactions/components/dialogs/transaction-dialog/category-section.tsx index 5c780b5..bb7d111 100644 --- a/src/features/transactions/components/dialogs/transaction-dialog/category-section.tsx +++ b/src/features/transactions/components/dialogs/transaction-dialog/category-section.tsx @@ -1,6 +1,6 @@ "use client"; -import { LANCAMENTO_TRANSACTION_TYPES } from "@/features/transactions/constants"; +import { TRANSACTION_TYPES } from "@/features/transactions/constants"; import { Label } from "@/shared/components/ui/label"; import { Select, @@ -13,7 +13,7 @@ import { } from "@/shared/components/ui/select"; import { cn } from "@/shared/utils/ui"; import { - CategoriaSelectContent, + CategorySelectContent, TransactionTypeSelectContent, } from "../../select-items"; import type { CategorySectionProps } from "./transaction-dialog-types"; @@ -21,8 +21,8 @@ import type { CategorySectionProps } from "./transaction-dialog-types"; export function CategorySection({ formState, onFieldChange, - categoriaOptions, - categoriaGroups, + categoryOptions, + categoryGroups, isUpdateMode, hideTransactionType = false, }: CategorySectionProps) { @@ -47,13 +47,13 @@ export function CategorySection({ - {LANCAMENTO_TRANSACTION_TYPES.filter( - (type) => type !== "Transferência", - ).map((type) => ( - - - - ))} + {TRANSACTION_TYPES.filter((type) => type !== "Transferência").map( + (type) => ( + + + + ), + )}
    @@ -65,20 +65,20 @@ export function CategorySection({ showTransactionTypeField ? "md:w-1/2" : "md:w-full", )} > - + onFieldChange("pagadorId", value)} + value={formState.payerId} + onValueChange={(value) => onFieldChange("payerId", value)} > - {formState.pagadorId && + {formState.payerId && (() => { - const selectedOption = pagadorOptions.find( - (opt) => opt.value === formState.pagadorId, + const selectedOption = payerOptions.find( + (opt) => opt.value === formState.payerId, ); return selectedOption ? ( - @@ -62,9 +62,9 @@ export function PagadorSection({ - {pagadorOptions.map((option) => ( + {payerOptions.map((option) => ( - @@ -85,27 +85,27 @@ export function PagadorSection({ {formState.isSplit ? (
    - +
    onFieldChange("cartaoId", value)} - disabled={disableCartaoSelect} + value={formState.cardId} + onValueChange={(value) => onFieldChange("cardId", value)} + disabled={disableCardSelect} > - {formState.cartaoId && + {formState.cardId && (() => { - const selectedOption = cartaoOptions.find( - (opt) => opt.value === formState.cartaoId, + const selectedOption = cardOptions.find( + (opt) => opt.value === formState.cardId, ); return selectedOption ? ( - - {cartaoOptions.length === 0 ? ( + {cardOptions.length === 0 ? (

    Nenhum cartão cadastrado

    ) : ( - cartaoOptions.map((option) => ( + cardOptions.map((option) => ( - - {formState.cartaoId ? ( + {formState.cardId ? ( onFieldChange("period", value)} @@ -194,20 +194,20 @@ export function PaymentMethodSection({ !isUpdateMode ? "md:w-1/2" : "md:w-full", )} > - + onFieldChange("cartaoId", value)} + value={formState.cardId} + onValueChange={(value) => onFieldChange("cardId", value)} > - {formState.cartaoId && + {formState.cardId && (() => { - const selectedOption = cartaoOptions.find( - (opt) => opt.value === formState.cartaoId, + const selectedOption = cardOptions.find( + (opt) => opt.value === formState.cardId, ); return selectedOption ? ( - - {cartaoOptions.length === 0 ? ( + {cardOptions.length === 0 ? (

    Nenhum cartão cadastrado

    ) : ( - cartaoOptions.map((option) => ( + cardOptions.map((option) => ( - - {formState.cartaoId ? ( + {formState.cardId ? ( onFieldChange("period", value)} @@ -308,20 +308,20 @@ export function PaymentMethodSection({ !isUpdateMode ? "md:w-1/2" : "md:w-full", )} > - + handleFilterChange( - "pagador", + "payer", value === FILTER_EMPTY_VALUE ? null : value, ) } @@ -381,10 +384,10 @@ export function LancamentosFilters({ disabled={isPending} > - {selectedPagador ? ( - ) : ( "Todos" @@ -393,9 +396,9 @@ export function LancamentosFilters({ Todos - {pagadorSelectOptions.map((option) => ( + {payerSelectOptions.map((option) => ( - @@ -406,25 +409,25 @@ export function LancamentosFilters({
    - +