refactor: alinha features financeiras ao novo naming

This commit is contained in:
Felipe Coutinho
2026-03-14 12:50:55 +00:00
parent ef918a3667
commit 67ad4b9d02
51 changed files with 876 additions and 898 deletions

View File

@@ -2,13 +2,7 @@
import { and, eq, sql } from "drizzle-orm";
import { z } from "zod";
import {
cartoes,
categorias,
faturas,
lancamentos,
pagadores,
} from "@/db/schema";
import { cards, categories, invoices, payers, transactions } from "@/db/schema";
import { buildInvoicePaymentNote } from "@/shared/lib/accounts/constants";
import { revalidateForEntity } from "@/shared/lib/actions/helpers";
import { getUser } from "@/shared/lib/auth/server";
@@ -19,7 +13,7 @@ import {
type InvoicePaymentStatus,
PERIOD_FORMAT_REGEX,
} from "@/shared/lib/invoices";
import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants";
import { PAYER_ROLE_ADMIN } from "@/shared/lib/payers/constants";
import {
getBusinessTodayDate,
parseLocalDateString,
@@ -29,7 +23,7 @@ const isValidPaymentDate = (value: string) =>
!Number.isNaN(parseLocalDateString(value).getTime());
const updateInvoicePaymentStatusSchema = z.object({
cartaoId: z.string({ message: "Cartão inválido." }).uuid("Cartão inválido."),
cardId: z.string({ message: "Cartão inválido." }).uuid("Cartão inválido."),
period: z
.string({ message: "Período inválido." })
.regex(PERIOD_FORMAT_REGEX, "Período inválido."),
@@ -53,7 +47,7 @@ type ActionResult =
| { success: false; error: string };
const successMessageByStatus: Record<InvoicePaymentStatus, string> = {
[INVOICE_PAYMENT_STATUS.PAID]: "Fatura marcada como paga.",
[INVOICE_PAYMENT_STATUS.PAID]: "Invoice marcada como paga.",
[INVOICE_PAYMENT_STATUS.PENDING]: "Pagamento da fatura foi revertido.",
};
@@ -68,36 +62,36 @@ export async function updateInvoicePaymentStatusAction(
const data = updateInvoicePaymentStatusSchema.parse(input);
await db.transaction(async (tx: typeof db) => {
const card = await tx.query.cartoes.findFirst({
columns: { id: true, contaId: true, name: true },
where: and(eq(cartoes.id, data.cartaoId), eq(cartoes.userId, user.id)),
const card = await tx.query.cards.findFirst({
columns: { id: true, accountId: true, name: true },
where: and(eq(cards.id, data.cardId), eq(cards.userId, user.id)),
});
if (!card) {
throw new Error("Cartão não encontrado.");
}
const existingInvoice = await tx.query.faturas.findFirst({
const existingInvoice = await tx.query.invoices.findFirst({
columns: {
id: true,
},
where: and(
eq(faturas.cartaoId, data.cartaoId),
eq(faturas.userId, user.id),
eq(faturas.period, data.period),
eq(invoices.cardId, data.cardId),
eq(invoices.userId, user.id),
eq(invoices.period, data.period),
),
});
if (existingInvoice) {
await tx
.update(faturas)
.update(invoices)
.set({
paymentStatus: data.status,
})
.where(eq(faturas.id, existingInvoice.id));
.where(eq(invoices.id, existingInvoice.id));
} else {
await tx.insert(faturas).values({
cartaoId: data.cartaoId,
await tx.insert(invoices).values({
cardId: data.cardId,
period: data.period,
paymentStatus: data.status,
userId: user.id,
@@ -107,13 +101,13 @@ export async function updateInvoicePaymentStatusAction(
const shouldMarkAsPaid = data.status === INVOICE_PAYMENT_STATUS.PAID;
await tx
.update(lancamentos)
.update(transactions)
.set({ isSettled: shouldMarkAsPaid })
.where(
and(
eq(lancamentos.userId, user.id),
eq(lancamentos.cartaoId, card.id),
eq(lancamentos.period, data.period),
eq(transactions.userId, user.id),
eq(transactions.cardId, card.id),
eq(transactions.period, data.period),
),
);
@@ -124,39 +118,39 @@ export async function updateInvoicePaymentStatusAction(
.select({
total: sql<number>`
coalesce(
sum(${lancamentos.amount}),
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, user.id),
eq(lancamentos.cartaoId, card.id),
eq(lancamentos.period, data.period),
eq(pagadores.role, PAGADOR_ROLE_ADMIN),
eq(transactions.userId, user.id),
eq(transactions.cardId, card.id),
eq(transactions.period, data.period),
eq(payers.role, PAYER_ROLE_ADMIN),
),
);
const adminShare = Number(adminShareRow?.total ?? 0);
const adminPayableAmount = Math.abs(Math.min(adminShare, 0));
if (adminPayableAmount > 0 && card.contaId) {
const adminPagador = await tx.query.pagadores.findFirst({
if (adminPayableAmount > 0 && card.accountId) {
const adminPagador = await tx.query.payers.findFirst({
columns: { id: true },
where: and(
eq(pagadores.userId, user.id),
eq(pagadores.role, PAGADOR_ROLE_ADMIN),
eq(payers.userId, user.id),
eq(payers.role, PAYER_ROLE_ADMIN),
),
});
const paymentCategory = await tx.query.categorias.findFirst({
const paymentCategory = await tx.query.categories.findFirst({
columns: { id: true },
where: and(
eq(categorias.userId, user.id),
eq(categorias.name, "Pagamentos"),
eq(categories.userId, user.id),
eq(categories.name, "Pagamentos"),
),
});
@@ -178,42 +172,42 @@ export async function updateInvoicePaymentStatusAction(
period: data.period,
isSettled: true,
userId: user.id,
contaId: card.contaId,
categoriaId: paymentCategory?.id ?? null,
pagadorId: adminPagador.id,
accountId: card.accountId,
categoryId: paymentCategory?.id ?? null,
payerId: adminPagador.id,
};
const existingPayment = await tx.query.lancamentos.findFirst({
const existingPayment = await tx.query.transactions.findFirst({
columns: { id: true },
where: and(
eq(lancamentos.userId, user.id),
eq(lancamentos.note, invoiceNote),
eq(transactions.userId, user.id),
eq(transactions.note, invoiceNote),
),
});
if (existingPayment) {
await tx
.update(lancamentos)
.update(transactions)
.set(payload)
.where(eq(lancamentos.id, existingPayment.id));
.where(eq(transactions.id, existingPayment.id));
} else {
await tx.insert(lancamentos).values(payload);
await tx.insert(transactions).values(payload);
}
}
}
} else {
await tx
.delete(lancamentos)
.delete(transactions)
.where(
and(
eq(lancamentos.userId, user.id),
eq(lancamentos.note, invoiceNote),
eq(transactions.userId, user.id),
eq(transactions.note, invoiceNote),
),
);
}
});
revalidateForEntity("cartoes");
revalidateForEntity("cards");
return { success: true, message: successMessageByStatus[data.status] };
} catch (error) {
@@ -232,7 +226,7 @@ export async function updateInvoicePaymentStatusAction(
}
const updatePaymentDateSchema = z.object({
cartaoId: z.string({ message: "Cartão inválido." }).uuid("Cartão inválido."),
cardId: z.string({ message: "Cartão inválido." }).uuid("Cartão inválido."),
period: z
.string({ message: "Período inválido." })
.regex(PERIOD_FORMAT_REGEX, "Período inválido."),
@@ -253,9 +247,9 @@ export async function updatePaymentDateAction(
const data = updatePaymentDateSchema.parse(input);
await db.transaction(async (tx: typeof db) => {
const card = await tx.query.cartoes.findFirst({
const card = await tx.query.cards.findFirst({
columns: { id: true },
where: and(eq(cartoes.id, data.cartaoId), eq(cartoes.userId, user.id)),
where: and(eq(cards.id, data.cardId), eq(cards.userId, user.id)),
});
if (!card) {
@@ -264,11 +258,11 @@ export async function updatePaymentDateAction(
const invoiceNote = buildInvoicePaymentNote(card.id, data.period);
const existingPayment = await tx.query.lancamentos.findFirst({
const existingPayment = await tx.query.transactions.findFirst({
columns: { id: true },
where: and(
eq(lancamentos.userId, user.id),
eq(lancamentos.note, invoiceNote),
eq(transactions.userId, user.id),
eq(transactions.note, invoiceNote),
),
});
@@ -277,14 +271,14 @@ export async function updatePaymentDateAction(
}
await tx
.update(lancamentos)
.update(transactions)
.set({
purchaseDate: parseLocalDateString(data.paymentDate),
})
.where(eq(lancamentos.id, existingPayment.id));
.where(eq(transactions.id, existingPayment.id));
});
revalidateForEntity("cartoes");
revalidateForEntity("cards");
return { success: true, message: "Data de pagamento atualizada." };
} catch (error) {

View File

@@ -33,7 +33,7 @@ import { cn } from "@/shared/utils/ui";
import { EditPaymentDateDialog } from "./edit-payment-date-dialog";
type InvoiceSummaryCardProps = {
cartaoId: string;
cardId: string;
period: string;
cardName: string;
cardBrand: string | null;
@@ -74,7 +74,7 @@ const getCardStatusDotColor = (status: string | null) => {
};
export function InvoiceSummaryCard({
cartaoId,
cardId,
period,
cardName,
cardBrand,
@@ -113,7 +113,7 @@ export function InvoiceSummaryCard({
const handleAction = () => {
startTransition(async () => {
const result = await updateInvoicePaymentStatusAction({
cartaoId,
cardId,
period,
status: targetStatus,
paymentDate:
@@ -136,7 +136,7 @@ export function InvoiceSummaryCard({
setPaymentDate(newDate);
startTransition(async () => {
const result = await updatePaymentDateAction({
cartaoId,
cardId,
period,
paymentDate: newDate.toISOString().split("T")[0] ?? "",
});
@@ -177,7 +177,7 @@ export function InvoiceSummaryCard({
{cardName}
</CardTitle>
<p className="text-sm text-muted-foreground">
Fatura de {periodLabel}
Invoice de {periodLabel}
</p>
</div>
{actions ? <div className="shrink-0">{actions}</div> : null}

View File

@@ -1,5 +1,5 @@
import { and, desc, eq, type SQL, sum } from "drizzle-orm";
import { cartoes, faturas, lancamentos } from "@/db/schema";
import { cards, invoices, transactions } from "@/db/schema";
import { buildInvoicePaymentNote } from "@/shared/lib/accounts/constants";
import { db } from "@/shared/lib/db";
import {
@@ -18,8 +18,8 @@ const toNumber = (value: string | number | null | undefined) => {
return Number.isNaN(parsed) ? 0 : parsed;
};
export async function fetchCardData(userId: string, cartaoId: string) {
const card = await db.query.cartoes.findFirst({
export async function fetchCardData(userId: string, cardId: string) {
const card = await db.query.cards.findFirst({
columns: {
id: true,
name: true,
@@ -30,9 +30,9 @@ export async function fetchCardData(userId: string, cartaoId: string) {
limit: true,
status: true,
note: true,
contaId: true,
accountId: true,
},
where: and(eq(cartoes.id, cartaoId), eq(cartoes.userId, userId)),
where: and(eq(cards.id, cardId), eq(cards.userId, userId)),
});
return card;
@@ -40,7 +40,7 @@ export async function fetchCardData(userId: string, cartaoId: string) {
export async function fetchInvoiceData(
userId: string,
cartaoId: string,
cardId: string,
selectedPeriod: string,
): Promise<{
totalAmount: number;
@@ -48,26 +48,26 @@ export async function fetchInvoiceData(
paymentDate: Date | null;
}> {
const [invoiceRow, totalRow] = await Promise.all([
db.query.faturas.findFirst({
db.query.invoices.findFirst({
columns: {
id: true,
period: true,
paymentStatus: true,
},
where: and(
eq(faturas.cartaoId, cartaoId),
eq(faturas.userId, userId),
eq(faturas.period, selectedPeriod),
eq(invoices.cardId, cardId),
eq(invoices.userId, userId),
eq(invoices.period, selectedPeriod),
),
}),
db
.select({ totalAmount: sum(lancamentos.amount) })
.from(lancamentos)
.select({ totalAmount: sum(transactions.amount) })
.from(transactions)
.where(
and(
eq(lancamentos.userId, userId),
eq(lancamentos.cartaoId, cartaoId),
eq(lancamentos.period, selectedPeriod),
eq(transactions.userId, userId),
eq(transactions.cardId, cardId),
eq(transactions.period, selectedPeriod),
),
),
]);
@@ -85,14 +85,14 @@ export async function fetchInvoiceData(
// Buscar data do pagamento se a fatura estiver paga
let paymentDate: Date | null = null;
if (invoiceStatus === INVOICE_PAYMENT_STATUS.PAID) {
const invoiceNote = buildInvoicePaymentNote(cartaoId, selectedPeriod);
const paymentLancamento = await db.query.lancamentos.findFirst({
const invoiceNote = buildInvoicePaymentNote(cardId, selectedPeriod);
const paymentLancamento = await db.query.transactions.findFirst({
columns: {
purchaseDate: true,
},
where: and(
eq(lancamentos.userId, userId),
eq(lancamentos.note, invoiceNote),
eq(transactions.userId, userId),
eq(transactions.note, invoiceNote),
),
});
paymentDate = paymentLancamento?.purchaseDate
@@ -103,15 +103,15 @@ export async function fetchInvoiceData(
return { totalAmount, invoiceStatus, paymentDate };
}
export async function fetchCardLancamentos(filters: SQL[]) {
return db.query.lancamentos.findMany({
export async function fetchCardTransactions(filters: SQL[]) {
return db.query.transactions.findMany({
where: and(...filters),
with: {
pagador: true,
conta: true,
cartao: true,
categoria: true,
payer: true,
financialAccount: true,
card: true,
category: true,
},
orderBy: desc(lancamentos.purchaseDate),
orderBy: desc(transactions.purchaseDate),
});
}