- Replace ESLint with Biome for linting and formatting - Configure Biome with tabs, double quotes, and organized imports - Move all SQL/Drizzle queries from page.tsx files to data.ts files - Create new data.ts files for: ajustes, dashboard, relatorios/categorias - Update existing data.ts files: extrato, fatura (add lancamentos queries) - Remove all drizzle-orm imports from page.tsx files - Update README.md with new tooling info Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
118 lines
2.8 KiB
TypeScript
118 lines
2.8 KiB
TypeScript
import { and, desc, eq, type SQL, sum } from "drizzle-orm";
|
|
import { cartoes, faturas, lancamentos } from "@/db/schema";
|
|
import { buildInvoicePaymentNote } from "@/lib/accounts/constants";
|
|
import { db } from "@/lib/db";
|
|
import {
|
|
INVOICE_PAYMENT_STATUS,
|
|
type InvoicePaymentStatus,
|
|
} from "@/lib/faturas";
|
|
|
|
const toNumber = (value: string | number | null | undefined) => {
|
|
if (typeof value === "number") {
|
|
return value;
|
|
}
|
|
if (value === null || value === undefined) {
|
|
return 0;
|
|
}
|
|
const parsed = Number(value);
|
|
return Number.isNaN(parsed) ? 0 : parsed;
|
|
};
|
|
|
|
export async function fetchCardData(userId: string, cartaoId: string) {
|
|
const card = await db.query.cartoes.findFirst({
|
|
columns: {
|
|
id: true,
|
|
name: true,
|
|
brand: true,
|
|
closingDay: true,
|
|
dueDay: true,
|
|
logo: true,
|
|
limit: true,
|
|
status: true,
|
|
note: true,
|
|
contaId: true,
|
|
},
|
|
where: and(eq(cartoes.id, cartaoId), eq(cartoes.userId, userId)),
|
|
});
|
|
|
|
return card;
|
|
}
|
|
|
|
export async function fetchInvoiceData(
|
|
userId: string,
|
|
cartaoId: string,
|
|
selectedPeriod: string,
|
|
): Promise<{
|
|
totalAmount: number;
|
|
invoiceStatus: InvoicePaymentStatus;
|
|
paymentDate: Date | null;
|
|
}> {
|
|
const [invoiceRow, totalRow] = await Promise.all([
|
|
db.query.faturas.findFirst({
|
|
columns: {
|
|
id: true,
|
|
period: true,
|
|
paymentStatus: true,
|
|
},
|
|
where: and(
|
|
eq(faturas.cartaoId, cartaoId),
|
|
eq(faturas.userId, userId),
|
|
eq(faturas.period, selectedPeriod),
|
|
),
|
|
}),
|
|
db
|
|
.select({ totalAmount: sum(lancamentos.amount) })
|
|
.from(lancamentos)
|
|
.where(
|
|
and(
|
|
eq(lancamentos.userId, userId),
|
|
eq(lancamentos.cartaoId, cartaoId),
|
|
eq(lancamentos.period, selectedPeriod),
|
|
),
|
|
),
|
|
]);
|
|
|
|
const totalAmount = toNumber(totalRow[0]?.totalAmount);
|
|
const isInvoiceStatus = (
|
|
value: string | null | undefined,
|
|
): value is InvoicePaymentStatus =>
|
|
!!value && ["pendente", "pago"].includes(value);
|
|
|
|
const invoiceStatus = isInvoiceStatus(invoiceRow?.paymentStatus)
|
|
? invoiceRow?.paymentStatus
|
|
: INVOICE_PAYMENT_STATUS.PENDING;
|
|
|
|
// 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({
|
|
columns: {
|
|
purchaseDate: true,
|
|
},
|
|
where: and(
|
|
eq(lancamentos.userId, userId),
|
|
eq(lancamentos.note, invoiceNote),
|
|
),
|
|
});
|
|
paymentDate = paymentLancamento?.purchaseDate
|
|
? new Date(paymentLancamento.purchaseDate)
|
|
: null;
|
|
}
|
|
|
|
return { totalAmount, invoiceStatus, paymentDate };
|
|
}
|
|
|
|
export async function fetchCardLancamentos(filters: SQL[]) {
|
|
return db.query.lancamentos.findMany({
|
|
where: and(...filters),
|
|
with: {
|
|
pagador: true,
|
|
conta: true,
|
|
cartao: true,
|
|
categoria: true,
|
|
},
|
|
orderBy: desc(lancamentos.purchaseDate),
|
|
});
|
|
}
|