forked from git.gladyson/openmonetis
chore: remover seções vazias de mudanças de código
Este commit remove seções vazias de mudanças de código do arquivo de mudanças. Isso ajuda a manter o histórico de mudanças mais limpo e organizado, facilitando a leitura e a compreensão das alterações realizadas no projeto.
This commit is contained in:
@@ -1,16 +1,19 @@
|
||||
import { getRecentEstablishmentsAction } from "@/app/(dashboard)/lancamentos/actions";
|
||||
import { cartoes, lancamentos } from "@/db/schema";
|
||||
import { db } from "@/lib/db";
|
||||
import {
|
||||
buildOptionSets,
|
||||
buildSluggedFilters,
|
||||
fetchLancamentoFilterSources,
|
||||
mapLancamentosData,
|
||||
} from "@/lib/lancamentos/page-helpers";
|
||||
import { db } from "@/lib/db";
|
||||
import { PAGADOR_ROLE_ADMIN } from "@/lib/pagadores/constants";
|
||||
import { and, eq, gte, lte, ne, or } from "drizzle-orm";
|
||||
import { getRecentEstablishmentsAction } from "@/app/(dashboard)/lancamentos/actions";
|
||||
|
||||
import type { CalendarData, CalendarEvent } from "@/components/calendario/types";
|
||||
import type {
|
||||
CalendarData,
|
||||
CalendarEvent,
|
||||
} from "@/components/calendario/types";
|
||||
|
||||
const PAYMENT_METHOD_BOLETO = "Boleto";
|
||||
const TRANSACTION_TYPE_TRANSFERENCIA = "Transferência";
|
||||
@@ -98,7 +101,11 @@ export const fetchCalendarData = async ({
|
||||
|
||||
const cardTotals = new Map<string, number>();
|
||||
for (const item of lancamentosData) {
|
||||
if (!item.cartaoId || item.period !== period || item.pagadorRole !== PAGADOR_ROLE_ADMIN) {
|
||||
if (
|
||||
!item.cartaoId ||
|
||||
item.period !== period ||
|
||||
item.pagadorRole !== PAGADOR_ROLE_ADMIN
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
const amount = Math.abs(item.amount ?? 0);
|
||||
|
||||
@@ -10,11 +10,7 @@ export default async function HistoricoCategoriasPage() {
|
||||
const data = await fetchCategoryHistory(user.id, currentPeriod);
|
||||
|
||||
return (
|
||||
<main className="flex flex-col gap-6">
|
||||
<p className="text-muted-foreground">
|
||||
Acompanhe o histórico de desempenho das suas categorias ao longo de 9
|
||||
meses.
|
||||
</p>
|
||||
<main>
|
||||
<CategoryHistoryWidget data={data} />
|
||||
</main>
|
||||
);
|
||||
|
||||
@@ -15,7 +15,7 @@ export default function RootLayout({
|
||||
<PageDescription
|
||||
icon={<RiPriceTag3Line />}
|
||||
title="Categorias"
|
||||
subtitle="Gerencie suas categorias de despesas e receitas. Acompanhe o desempenho financeiro por categoria e faça ajustes conforme necessário."
|
||||
subtitle="Gerencie suas categorias de despesas e receitas acompanhando o histórico de desempenho dos últimos 9 meses, permitindo ajustes financeiros precisos conforme necessário."
|
||||
/>
|
||||
{children}
|
||||
</section>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use server";
|
||||
|
||||
import { contas, lancamentos } from "@/db/schema";
|
||||
import { contas, lancamentos, pagadores, categorias, cartoes } from "@/db/schema";
|
||||
import {
|
||||
INITIAL_BALANCE_CONDITION,
|
||||
INITIAL_BALANCE_NOTE,
|
||||
@@ -31,6 +31,78 @@ import { and, asc, desc, eq, gte, inArray, sql } from "drizzle-orm";
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { z } from "zod";
|
||||
|
||||
// ============================================================================
|
||||
// Authorization Validation Functions
|
||||
// ============================================================================
|
||||
|
||||
async function validatePagadorOwnership(
|
||||
userId: string,
|
||||
pagadorId: string | null | undefined
|
||||
): Promise<boolean> {
|
||||
if (!pagadorId) return true; // Se não tem pagadorId, não precisa validar
|
||||
|
||||
const pagador = await db.query.pagadores.findFirst({
|
||||
where: and(
|
||||
eq(pagadores.id, pagadorId),
|
||||
eq(pagadores.userId, userId)
|
||||
),
|
||||
});
|
||||
|
||||
return !!pagador;
|
||||
}
|
||||
|
||||
async function validateCategoriaOwnership(
|
||||
userId: string,
|
||||
categoriaId: string | null | undefined
|
||||
): Promise<boolean> {
|
||||
if (!categoriaId) return true;
|
||||
|
||||
const categoria = await db.query.categorias.findFirst({
|
||||
where: and(
|
||||
eq(categorias.id, categoriaId),
|
||||
eq(categorias.userId, userId)
|
||||
),
|
||||
});
|
||||
|
||||
return !!categoria;
|
||||
}
|
||||
|
||||
async function validateContaOwnership(
|
||||
userId: string,
|
||||
contaId: string | null | undefined
|
||||
): Promise<boolean> {
|
||||
if (!contaId) return true;
|
||||
|
||||
const conta = await db.query.contas.findFirst({
|
||||
where: and(
|
||||
eq(contas.id, contaId),
|
||||
eq(contas.userId, userId)
|
||||
),
|
||||
});
|
||||
|
||||
return !!conta;
|
||||
}
|
||||
|
||||
async function validateCartaoOwnership(
|
||||
userId: string,
|
||||
cartaoId: string | null | undefined
|
||||
): Promise<boolean> {
|
||||
if (!cartaoId) return true;
|
||||
|
||||
const cartao = await db.query.cartoes.findFirst({
|
||||
where: and(
|
||||
eq(cartoes.id, cartaoId),
|
||||
eq(cartoes.userId, userId)
|
||||
),
|
||||
});
|
||||
|
||||
return !!cartao;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Utility Functions
|
||||
// ============================================================================
|
||||
|
||||
const resolvePeriod = (purchaseDate: string, period?: string | null) => {
|
||||
if (period && /^\d{4}-\d{2}$/.test(period)) {
|
||||
return period;
|
||||
@@ -472,6 +544,42 @@ export async function createLancamentoAction(
|
||||
const user = await getUser();
|
||||
const data = createSchema.parse(input);
|
||||
|
||||
// Validar propriedade dos recursos referenciados
|
||||
if (data.pagadorId) {
|
||||
const isValid = await validatePagadorOwnership(user.id, data.pagadorId);
|
||||
if (!isValid) {
|
||||
return { success: false, error: "Pagador não encontrado ou sem permissão." };
|
||||
}
|
||||
}
|
||||
|
||||
if (data.secondaryPagadorId) {
|
||||
const isValid = await validatePagadorOwnership(user.id, data.secondaryPagadorId);
|
||||
if (!isValid) {
|
||||
return { success: false, error: "Pagador secundário não encontrado ou sem permissão." };
|
||||
}
|
||||
}
|
||||
|
||||
if (data.categoriaId) {
|
||||
const isValid = await validateCategoriaOwnership(user.id, data.categoriaId);
|
||||
if (!isValid) {
|
||||
return { success: false, error: "Categoria não encontrada." };
|
||||
}
|
||||
}
|
||||
|
||||
if (data.contaId) {
|
||||
const isValid = await validateContaOwnership(user.id, data.contaId);
|
||||
if (!isValid) {
|
||||
return { success: false, error: "Conta não encontrada." };
|
||||
}
|
||||
}
|
||||
|
||||
if (data.cartaoId) {
|
||||
const isValid = await validateCartaoOwnership(user.id, data.cartaoId);
|
||||
if (!isValid) {
|
||||
return { success: false, error: "Cartão não encontrado." };
|
||||
}
|
||||
}
|
||||
|
||||
const period = resolvePeriod(data.purchaseDate, data.period);
|
||||
const purchaseDate = parseLocalDateString(data.purchaseDate);
|
||||
const dueDate = data.dueDate ? parseLocalDateString(data.dueDate) : null;
|
||||
@@ -556,6 +664,42 @@ export async function updateLancamentoAction(
|
||||
const user = await getUser();
|
||||
const data = updateSchema.parse(input);
|
||||
|
||||
// Validar propriedade dos recursos referenciados
|
||||
if (data.pagadorId) {
|
||||
const isValid = await validatePagadorOwnership(user.id, data.pagadorId);
|
||||
if (!isValid) {
|
||||
return { success: false, error: "Pagador não encontrado ou sem permissão." };
|
||||
}
|
||||
}
|
||||
|
||||
if (data.secondaryPagadorId) {
|
||||
const isValid = await validatePagadorOwnership(user.id, data.secondaryPagadorId);
|
||||
if (!isValid) {
|
||||
return { success: false, error: "Pagador secundário não encontrado ou sem permissão." };
|
||||
}
|
||||
}
|
||||
|
||||
if (data.categoriaId) {
|
||||
const isValid = await validateCategoriaOwnership(user.id, data.categoriaId);
|
||||
if (!isValid) {
|
||||
return { success: false, error: "Categoria não encontrada." };
|
||||
}
|
||||
}
|
||||
|
||||
if (data.contaId) {
|
||||
const isValid = await validateContaOwnership(user.id, data.contaId);
|
||||
if (!isValid) {
|
||||
return { success: false, error: "Conta não encontrada." };
|
||||
}
|
||||
}
|
||||
|
||||
if (data.cartaoId) {
|
||||
const isValid = await validateCartaoOwnership(user.id, data.cartaoId);
|
||||
if (!isValid) {
|
||||
return { success: false, error: "Cartão não encontrado." };
|
||||
}
|
||||
}
|
||||
|
||||
const existing = await db.query.lancamentos.findFirst({
|
||||
columns: {
|
||||
id: true,
|
||||
@@ -1124,12 +1268,12 @@ const massAddTransactionSchema = z.object({
|
||||
.number({ message: "Informe o valor da transação." })
|
||||
.min(0, "Informe um valor maior ou igual a zero."),
|
||||
categoriaId: uuidSchema("Categoria").nullable().optional(),
|
||||
pagadorId: uuidSchema("Pagador").nullable().optional(),
|
||||
});
|
||||
|
||||
const massAddSchema = z.object({
|
||||
fixedFields: z.object({
|
||||
transactionType: z.enum(LANCAMENTO_TRANSACTION_TYPES).optional(),
|
||||
pagadorId: uuidSchema("Pagador").nullable().optional(),
|
||||
paymentMethod: z.enum(LANCAMENTO_PAYMENT_METHODS).optional(),
|
||||
condition: z.enum(LANCAMENTO_CONDITIONS).optional(),
|
||||
period: z
|
||||
@@ -1156,6 +1300,46 @@ export async function createMassLancamentosAction(
|
||||
const user = await getUser();
|
||||
const data = massAddSchema.parse(input);
|
||||
|
||||
// Validar campos fixos
|
||||
if (data.fixedFields.contaId) {
|
||||
const isValid = await validateContaOwnership(user.id, data.fixedFields.contaId);
|
||||
if (!isValid) {
|
||||
return { success: false, error: "Conta não encontrada." };
|
||||
}
|
||||
}
|
||||
|
||||
if (data.fixedFields.cartaoId) {
|
||||
const isValid = await validateCartaoOwnership(user.id, data.fixedFields.cartaoId);
|
||||
if (!isValid) {
|
||||
return { success: false, error: "Cartão não encontrado." };
|
||||
}
|
||||
}
|
||||
|
||||
// Validar cada transação individual
|
||||
for (let i = 0; i < data.transactions.length; i++) {
|
||||
const transaction = data.transactions[i];
|
||||
|
||||
if (transaction.pagadorId) {
|
||||
const isValid = await validatePagadorOwnership(user.id, transaction.pagadorId);
|
||||
if (!isValid) {
|
||||
return {
|
||||
success: false,
|
||||
error: `Pagador não encontrado na transação ${i + 1}.`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (transaction.categoriaId) {
|
||||
const isValid = await validateCategoriaOwnership(user.id, transaction.categoriaId);
|
||||
if (!isValid) {
|
||||
return {
|
||||
success: false,
|
||||
error: `Categoria não encontrada na transação ${i + 1}.`
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Default values for non-fixed fields
|
||||
const defaultTransactionType = LANCAMENTO_TRANSACTION_TYPES[0];
|
||||
const defaultCondition = LANCAMENTO_CONDITIONS[0];
|
||||
@@ -1181,7 +1365,7 @@ export async function createMassLancamentosAction(
|
||||
const condition = data.fixedFields.condition ?? defaultCondition;
|
||||
const paymentMethod =
|
||||
data.fixedFields.paymentMethod ?? defaultPaymentMethod;
|
||||
const pagadorId = data.fixedFields.pagadorId ?? null;
|
||||
const pagadorId = transaction.pagadorId ?? null;
|
||||
const contaId =
|
||||
paymentMethod === "Cartão de crédito"
|
||||
? null
|
||||
|
||||
Reference in New Issue
Block a user