mirror of
https://github.com/felipegcoutinho/openmonetis.git
synced 2026-07-09 19:36:02 +00:00
refactor: alinha features financeiras ao novo naming
This commit is contained in:
@@ -2,7 +2,12 @@
|
||||
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import { categorias, contas, lancamentos, pagadores } from "@/db/schema";
|
||||
import {
|
||||
categories,
|
||||
financialAccounts,
|
||||
payers,
|
||||
transactions,
|
||||
} from "@/db/schema";
|
||||
import {
|
||||
INITIAL_BALANCE_CATEGORY_NAME,
|
||||
INITIAL_BALANCE_CONDITION,
|
||||
@@ -17,7 +22,7 @@ import {
|
||||
} from "@/shared/lib/actions/helpers";
|
||||
import { getUser } from "@/shared/lib/auth/server";
|
||||
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 { noteSchema, uuidSchema } from "@/shared/lib/schemas/common";
|
||||
import {
|
||||
TRANSFER_CATEGORY_NAME,
|
||||
@@ -67,10 +72,10 @@ const accountBaseSchema = z.object({
|
||||
|
||||
const createAccountSchema = accountBaseSchema;
|
||||
const updateAccountSchema = accountBaseSchema.extend({
|
||||
id: uuidSchema("Conta"),
|
||||
id: uuidSchema("FinancialAccount"),
|
||||
});
|
||||
const deleteAccountSchema = z.object({
|
||||
id: uuidSchema("Conta"),
|
||||
id: uuidSchema("FinancialAccount"),
|
||||
});
|
||||
|
||||
type AccountCreateInput = z.infer<typeof createAccountSchema>;
|
||||
@@ -91,7 +96,7 @@ export async function createAccountAction(
|
||||
|
||||
await db.transaction(async (tx: typeof db) => {
|
||||
const [createdAccount] = await tx
|
||||
.insert(contas)
|
||||
.insert(financialAccounts)
|
||||
.values({
|
||||
name: data.name,
|
||||
accountType: data.accountType,
|
||||
@@ -103,7 +108,7 @@ export async function createAccountAction(
|
||||
excludeInitialBalanceFromIncome: data.excludeInitialBalanceFromIncome,
|
||||
userId: user.id,
|
||||
})
|
||||
.returning({ id: contas.id, name: contas.name });
|
||||
.returning({ id: financialAccounts.id, name: financialAccounts.name });
|
||||
|
||||
if (!createdAccount) {
|
||||
throw new Error("Não foi possível criar a conta.");
|
||||
@@ -114,37 +119,37 @@ export async function createAccountAction(
|
||||
}
|
||||
|
||||
const [category, adminPagador] = await Promise.all([
|
||||
tx.query.categorias.findFirst({
|
||||
tx.query.categories.findFirst({
|
||||
columns: { id: true },
|
||||
where: and(
|
||||
eq(categorias.userId, user.id),
|
||||
eq(categorias.name, INITIAL_BALANCE_CATEGORY_NAME),
|
||||
eq(categories.userId, user.id),
|
||||
eq(categories.name, INITIAL_BALANCE_CATEGORY_NAME),
|
||||
),
|
||||
}),
|
||||
tx.query.pagadores.findFirst({
|
||||
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),
|
||||
),
|
||||
}),
|
||||
]);
|
||||
|
||||
if (!category) {
|
||||
throw new Error(
|
||||
'Categoria "Saldo inicial" não encontrada. Crie-a antes de definir um saldo inicial.',
|
||||
'Category "Saldo inicial" não encontrada. Crie-a antes de definir um saldo inicial.',
|
||||
);
|
||||
}
|
||||
|
||||
if (!adminPagador) {
|
||||
throw new Error(
|
||||
"Pagador com papel administrador não encontrado. Crie um pagador admin antes de definir um saldo inicial.",
|
||||
"Payer com papel administrador não encontrado. Crie um pagador admin antes de definir um saldo inicial.",
|
||||
);
|
||||
}
|
||||
|
||||
const { date, period } = getTodayInfo();
|
||||
|
||||
await tx.insert(lancamentos).values({
|
||||
await tx.insert(transactions).values({
|
||||
condition: INITIAL_BALANCE_CONDITION,
|
||||
name: `Saldo inicial - ${createdAccount.name}`,
|
||||
paymentMethod: INITIAL_BALANCE_PAYMENT_METHOD,
|
||||
@@ -155,17 +160,17 @@ export async function createAccountAction(
|
||||
period,
|
||||
isSettled: true,
|
||||
userId: user.id,
|
||||
contaId: createdAccount.id,
|
||||
categoriaId: category.id,
|
||||
pagadorId: adminPagador.id,
|
||||
accountId: createdAccount.id,
|
||||
categoryId: category.id,
|
||||
payerId: adminPagador.id,
|
||||
});
|
||||
});
|
||||
|
||||
revalidateForEntity("contas");
|
||||
revalidateForEntity("accounts");
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Conta criada com sucesso.",
|
||||
message: "FinancialAccount criada com sucesso.",
|
||||
};
|
||||
} catch (error) {
|
||||
return handleActionError(error);
|
||||
@@ -182,7 +187,7 @@ export async function updateAccountAction(
|
||||
const logoFile = normalizeFilePath(data.logo);
|
||||
|
||||
const [updated] = await db
|
||||
.update(contas)
|
||||
.update(financialAccounts)
|
||||
.set({
|
||||
name: data.name,
|
||||
accountType: data.accountType,
|
||||
@@ -193,21 +198,26 @@ export async function updateAccountAction(
|
||||
excludeFromBalance: data.excludeFromBalance,
|
||||
excludeInitialBalanceFromIncome: data.excludeInitialBalanceFromIncome,
|
||||
})
|
||||
.where(and(eq(contas.id, data.id), eq(contas.userId, user.id)))
|
||||
.where(
|
||||
and(
|
||||
eq(financialAccounts.id, data.id),
|
||||
eq(financialAccounts.userId, user.id),
|
||||
),
|
||||
)
|
||||
.returning();
|
||||
|
||||
if (!updated) {
|
||||
return {
|
||||
success: false,
|
||||
error: "Conta não encontrada.",
|
||||
error: "FinancialAccount não encontrada.",
|
||||
};
|
||||
}
|
||||
|
||||
revalidateForEntity("contas");
|
||||
revalidateForEntity("accounts");
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Conta atualizada com sucesso.",
|
||||
message: "FinancialAccount atualizada com sucesso.",
|
||||
};
|
||||
} catch (error) {
|
||||
return handleActionError(error);
|
||||
@@ -222,22 +232,27 @@ export async function deleteAccountAction(
|
||||
const data = deleteAccountSchema.parse(input);
|
||||
|
||||
const [deleted] = await db
|
||||
.delete(contas)
|
||||
.where(and(eq(contas.id, data.id), eq(contas.userId, user.id)))
|
||||
.returning({ id: contas.id });
|
||||
.delete(financialAccounts)
|
||||
.where(
|
||||
and(
|
||||
eq(financialAccounts.id, data.id),
|
||||
eq(financialAccounts.userId, user.id),
|
||||
),
|
||||
)
|
||||
.returning({ id: financialAccounts.id });
|
||||
|
||||
if (!deleted) {
|
||||
return {
|
||||
success: false,
|
||||
error: "Conta não encontrada.",
|
||||
error: "FinancialAccount não encontrada.",
|
||||
};
|
||||
}
|
||||
|
||||
revalidateForEntity("contas");
|
||||
revalidateForEntity("accounts");
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Conta removida com sucesso.",
|
||||
message: "FinancialAccount removida com sucesso.",
|
||||
};
|
||||
} catch (error) {
|
||||
return handleActionError(error);
|
||||
@@ -246,8 +261,8 @@ export async function deleteAccountAction(
|
||||
|
||||
// Transfer between accounts
|
||||
const transferSchema = z.object({
|
||||
fromAccountId: uuidSchema("Conta de origem"),
|
||||
toAccountId: uuidSchema("Conta de destino"),
|
||||
fromAccountId: uuidSchema("FinancialAccount de origem"),
|
||||
toAccountId: uuidSchema("FinancialAccount de destino"),
|
||||
amount: z
|
||||
.string()
|
||||
.trim()
|
||||
@@ -265,7 +280,7 @@ const transferSchema = z.object({
|
||||
.min(1, "Informe o período."),
|
||||
});
|
||||
|
||||
type TransferInput = z.infer<typeof transferSchema>;
|
||||
type TransferInput = z.input<typeof transferSchema>;
|
||||
|
||||
export async function transferBetweenAccountsAction(
|
||||
input: TransferInput,
|
||||
@@ -288,64 +303,64 @@ export async function transferBetweenAccountsAction(
|
||||
await db.transaction(async (tx: typeof db) => {
|
||||
// Verify both accounts exist and belong to the user
|
||||
const [fromAccount, toAccount] = await Promise.all([
|
||||
tx.query.contas.findFirst({
|
||||
tx.query.financialAccounts.findFirst({
|
||||
columns: { id: true, name: true },
|
||||
where: and(
|
||||
eq(contas.id, data.fromAccountId),
|
||||
eq(contas.userId, user.id),
|
||||
eq(financialAccounts.id, data.fromAccountId),
|
||||
eq(financialAccounts.userId, user.id),
|
||||
),
|
||||
}),
|
||||
tx.query.contas.findFirst({
|
||||
tx.query.financialAccounts.findFirst({
|
||||
columns: { id: true, name: true },
|
||||
where: and(
|
||||
eq(contas.id, data.toAccountId),
|
||||
eq(contas.userId, user.id),
|
||||
eq(financialAccounts.id, data.toAccountId),
|
||||
eq(financialAccounts.userId, user.id),
|
||||
),
|
||||
}),
|
||||
]);
|
||||
|
||||
if (!fromAccount) {
|
||||
throw new Error("Conta de origem não encontrada.");
|
||||
throw new Error("FinancialAccount de origem não encontrada.");
|
||||
}
|
||||
|
||||
if (!toAccount) {
|
||||
throw new Error("Conta de destino não encontrada.");
|
||||
throw new Error("FinancialAccount de destino não encontrada.");
|
||||
}
|
||||
|
||||
// Get the transfer category
|
||||
const transferCategory = await tx.query.categorias.findFirst({
|
||||
const transferCategory = await tx.query.categories.findFirst({
|
||||
columns: { id: true },
|
||||
where: and(
|
||||
eq(categorias.userId, user.id),
|
||||
eq(categorias.name, TRANSFER_CATEGORY_NAME),
|
||||
eq(categories.userId, user.id),
|
||||
eq(categories.name, TRANSFER_CATEGORY_NAME),
|
||||
),
|
||||
});
|
||||
|
||||
if (!transferCategory) {
|
||||
throw new Error(
|
||||
`Categoria "${TRANSFER_CATEGORY_NAME}" não encontrada. Por favor, crie esta categoria antes de fazer transferências.`,
|
||||
`Category "${TRANSFER_CATEGORY_NAME}" não encontrada. Por favor, crie esta categoria antes de fazer transferências.`,
|
||||
);
|
||||
}
|
||||
|
||||
// Get the admin payer
|
||||
const adminPagador = await tx.query.pagadores.findFirst({
|
||||
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),
|
||||
),
|
||||
});
|
||||
|
||||
if (!adminPagador) {
|
||||
throw new Error(
|
||||
"Pagador administrador não encontrado. Por favor, crie um pagador admin.",
|
||||
"Payer administrador não encontrado. Por favor, crie um pagador admin.",
|
||||
);
|
||||
}
|
||||
|
||||
const transferNote = `de ${fromAccount.name} -> ${toAccount.name}`;
|
||||
|
||||
// Create outgoing transaction (transfer from source account)
|
||||
await tx.insert(lancamentos).values({
|
||||
await tx.insert(transactions).values({
|
||||
condition: TRANSFER_CONDITION,
|
||||
name: TRANSFER_ESTABLISHMENT_SAIDA,
|
||||
paymentMethod: TRANSFER_PAYMENT_METHOD,
|
||||
@@ -356,14 +371,14 @@ export async function transferBetweenAccountsAction(
|
||||
period: data.period,
|
||||
isSettled: true,
|
||||
userId: user.id,
|
||||
contaId: fromAccount.id,
|
||||
categoriaId: transferCategory.id,
|
||||
pagadorId: adminPagador.id,
|
||||
accountId: fromAccount.id,
|
||||
categoryId: transferCategory.id,
|
||||
payerId: adminPagador.id,
|
||||
transferId,
|
||||
});
|
||||
|
||||
// Create incoming transaction (transfer to destination account)
|
||||
await tx.insert(lancamentos).values({
|
||||
await tx.insert(transactions).values({
|
||||
condition: TRANSFER_CONDITION,
|
||||
name: TRANSFER_ESTABLISHMENT_ENTRADA,
|
||||
paymentMethod: TRANSFER_PAYMENT_METHOD,
|
||||
@@ -374,15 +389,15 @@ export async function transferBetweenAccountsAction(
|
||||
period: data.period,
|
||||
isSettled: true,
|
||||
userId: user.id,
|
||||
contaId: toAccount.id,
|
||||
categoriaId: transferCategory.id,
|
||||
pagadorId: adminPagador.id,
|
||||
accountId: toAccount.id,
|
||||
categoryId: transferCategory.id,
|
||||
payerId: adminPagador.id,
|
||||
transferId,
|
||||
});
|
||||
});
|
||||
|
||||
revalidateForEntity("contas");
|
||||
revalidateForEntity("lancamentos");
|
||||
revalidateForEntity("accounts");
|
||||
revalidateForEntity("transactions");
|
||||
|
||||
return {
|
||||
success: true,
|
||||
|
||||
@@ -33,10 +33,10 @@ import { AccountFormFields } from "./account-form-fields";
|
||||
import type { Account, AccountFormValues } from "./types";
|
||||
|
||||
const DEFAULT_ACCOUNT_TYPES = [
|
||||
"Conta Corrente",
|
||||
"Conta Poupança",
|
||||
"FinancialAccount Corrente",
|
||||
"FinancialAccount Poupança",
|
||||
"Carteira Digital",
|
||||
"Conta Investimento",
|
||||
"FinancialAccount Investimento",
|
||||
"Pré-Pago | VR/VA",
|
||||
] as const;
|
||||
|
||||
@@ -167,7 +167,7 @@ export function AccountDialog({
|
||||
const accountId = account?.id;
|
||||
|
||||
if (mode === "update" && !accountId) {
|
||||
const message = "Conta inválida.";
|
||||
const message = "FinancialAccount inválida.";
|
||||
setErrorMessage(message);
|
||||
toast.error(message);
|
||||
return;
|
||||
|
||||
@@ -110,10 +110,7 @@ export function AccountFormFields({
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
id="exclude-from-balance"
|
||||
checked={
|
||||
values.excludeFromBalance === true ||
|
||||
values.excludeFromBalance === "true"
|
||||
}
|
||||
checked={Boolean(values.excludeFromBalance)}
|
||||
onCheckedChange={(checked) =>
|
||||
onChange("excludeFromBalance", checked ? "true" : "false")
|
||||
}
|
||||
@@ -130,10 +127,7 @@ export function AccountFormFields({
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
id="exclude-initial-balance-from-income"
|
||||
checked={
|
||||
values.excludeInitialBalanceFromIncome === true ||
|
||||
values.excludeInitialBalanceFromIncome === "true"
|
||||
}
|
||||
checked={Boolean(values.excludeInitialBalanceFromIncome)}
|
||||
onCheckedChange={(checked) =>
|
||||
onChange(
|
||||
"excludeInitialBalanceFromIncome",
|
||||
|
||||
@@ -142,7 +142,7 @@ export function AccountStatementCard({
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Informações da Conta */}
|
||||
{/* Informações da FinancialAccount */}
|
||||
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 pt-2 border-t border-border/60 border-dashed">
|
||||
<DetailItem
|
||||
label="Tipo da conta"
|
||||
|
||||
@@ -115,9 +115,7 @@ export function AccountsPage({
|
||||
<EmptyState
|
||||
media={<RiBankLine className="size-6 text-primary" />}
|
||||
title={
|
||||
isArchived
|
||||
? "Nenhuma conta arquivada"
|
||||
: "Nenhuma conta cadastrada"
|
||||
isArchived ? "Nenhuma conta archived" : "Nenhuma conta cadastrada"
|
||||
}
|
||||
description={
|
||||
isArchived
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useState, useTransition } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { transferBetweenAccountsAction } from "@/features/accounts/actions";
|
||||
import type { AccountData } from "@/features/accounts/queries";
|
||||
import { ContaCartaoSelectContent } from "@/features/transactions/components/select-items";
|
||||
import { AccountCardSelectContent } from "@/features/transactions/components/select-items";
|
||||
import { PeriodPicker } from "@/shared/components/period-picker";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
import { CurrencyInput } from "@/shared/components/ui/currency-input";
|
||||
@@ -157,12 +157,12 @@ export function TransferDialog({
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2 sm:col-span-2">
|
||||
<Label htmlFor="from-account">Conta de origem</Label>
|
||||
<Label htmlFor="from-account">FinancialAccount de origem</Label>
|
||||
<Select value={fromAccountId} disabled>
|
||||
<SelectTrigger id="from-account" className="w-full">
|
||||
<SelectValue>
|
||||
{fromAccount && (
|
||||
<ContaCartaoSelectContent
|
||||
<AccountCardSelectContent
|
||||
label={fromAccount.name}
|
||||
logo={fromAccount.logo}
|
||||
isCartao={false}
|
||||
@@ -173,7 +173,7 @@ export function TransferDialog({
|
||||
<SelectContent>
|
||||
{fromAccount && (
|
||||
<SelectItem value={fromAccount.id}>
|
||||
<ContaCartaoSelectContent
|
||||
<AccountCardSelectContent
|
||||
label={fromAccount.name}
|
||||
logo={fromAccount.logo}
|
||||
isCartao={false}
|
||||
@@ -185,7 +185,7 @@ export function TransferDialog({
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2 sm:col-span-2">
|
||||
<Label htmlFor="to-account">Conta de destino</Label>
|
||||
<Label htmlFor="to-account">FinancialAccount de destino</Label>
|
||||
{availableAccounts.length === 0 ? (
|
||||
<div className="rounded-md border border-border bg-muted p-3 text-sm text-muted-foreground">
|
||||
É necessário ter mais de uma conta cadastrada para realizar
|
||||
@@ -201,7 +201,7 @@ export function TransferDialog({
|
||||
(acc) => acc.id === toAccountId,
|
||||
);
|
||||
return selectedAccount ? (
|
||||
<ContaCartaoSelectContent
|
||||
<AccountCardSelectContent
|
||||
label={selectedAccount.name}
|
||||
logo={selectedAccount.logo}
|
||||
isCartao={false}
|
||||
@@ -213,7 +213,7 @@ export function TransferDialog({
|
||||
<SelectContent className="w-full">
|
||||
{availableAccounts.map((account) => (
|
||||
<SelectItem key={account.id} value={account.id}>
|
||||
<ContaCartaoSelectContent
|
||||
<AccountCardSelectContent
|
||||
label={account.name}
|
||||
logo={account.logo}
|
||||
isCartao={false}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { and, eq, ilike, not, 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 { loadLogoOptions } from "@/shared/lib/logo/options";
|
||||
import { PAGADOR_ROLE_ADMIN } from "@/shared/lib/payers/constants";
|
||||
import { PAYER_ROLE_ADMIN } from "@/shared/lib/payers/constants";
|
||||
|
||||
export type AccountData = {
|
||||
id: string;
|
||||
@@ -20,58 +20,59 @@ export type AccountData = {
|
||||
|
||||
export async function fetchAccountsForUser(
|
||||
userId: string,
|
||||
): Promise<{ accounts: AccountData[]; logoOptions: LogoOption[] }> {
|
||||
): Promise<{ accounts: AccountData[]; logoOptions: string[] }> {
|
||||
const [accountRows, logoOptions] = await Promise.all([
|
||||
db
|
||||
.select({
|
||||
id: contas.id,
|
||||
name: contas.name,
|
||||
accountType: contas.accountType,
|
||||
status: contas.status,
|
||||
note: contas.note,
|
||||
logo: contas.logo,
|
||||
initialBalance: contas.initialBalance,
|
||||
excludeFromBalance: contas.excludeFromBalance,
|
||||
excludeInitialBalanceFromIncome: contas.excludeInitialBalanceFromIncome,
|
||||
id: financialAccounts.id,
|
||||
name: financialAccounts.name,
|
||||
accountType: financialAccounts.accountType,
|
||||
status: financialAccounts.status,
|
||||
note: financialAccounts.note,
|
||||
logo: financialAccounts.logo,
|
||||
initialBalance: financialAccounts.initialBalance,
|
||||
excludeFromBalance: financialAccounts.excludeFromBalance,
|
||||
excludeInitialBalanceFromIncome:
|
||||
financialAccounts.excludeInitialBalanceFromIncome,
|
||||
balanceMovements: sql<number>`
|
||||
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),
|
||||
not(ilike(contas.status, "inativa")),
|
||||
sql`(${lancamentos.id} IS NULL OR ${pagadores.role} = ${PAGADOR_ROLE_ADMIN})`,
|
||||
eq(financialAccounts.userId, userId),
|
||||
not(ilike(financialAccounts.status, "inativa")),
|
||||
sql`(${transactions.id} IS NULL OR ${payers.role} = ${PAYER_ROLE_ADMIN})`,
|
||||
),
|
||||
)
|
||||
.groupBy(
|
||||
contas.id,
|
||||
contas.name,
|
||||
contas.accountType,
|
||||
contas.status,
|
||||
contas.note,
|
||||
contas.logo,
|
||||
contas.initialBalance,
|
||||
contas.excludeFromBalance,
|
||||
contas.excludeInitialBalanceFromIncome,
|
||||
financialAccounts.id,
|
||||
financialAccounts.name,
|
||||
financialAccounts.accountType,
|
||||
financialAccounts.status,
|
||||
financialAccounts.note,
|
||||
financialAccounts.logo,
|
||||
financialAccounts.initialBalance,
|
||||
financialAccounts.excludeFromBalance,
|
||||
financialAccounts.excludeInitialBalanceFromIncome,
|
||||
),
|
||||
loadLogoOptions(),
|
||||
]);
|
||||
@@ -94,60 +95,61 @@ export async function fetchAccountsForUser(
|
||||
return { accounts, logoOptions };
|
||||
}
|
||||
|
||||
export async function fetchInativosForUser(
|
||||
export async function fetchInactiveForUser(
|
||||
userId: string,
|
||||
): Promise<{ accounts: AccountData[]; logoOptions: LogoOption[] }> {
|
||||
): Promise<{ accounts: AccountData[]; logoOptions: string[] }> {
|
||||
const [accountRows, logoOptions] = await Promise.all([
|
||||
db
|
||||
.select({
|
||||
id: contas.id,
|
||||
name: contas.name,
|
||||
accountType: contas.accountType,
|
||||
status: contas.status,
|
||||
note: contas.note,
|
||||
logo: contas.logo,
|
||||
initialBalance: contas.initialBalance,
|
||||
excludeFromBalance: contas.excludeFromBalance,
|
||||
excludeInitialBalanceFromIncome: contas.excludeInitialBalanceFromIncome,
|
||||
id: financialAccounts.id,
|
||||
name: financialAccounts.name,
|
||||
accountType: financialAccounts.accountType,
|
||||
status: financialAccounts.status,
|
||||
note: financialAccounts.note,
|
||||
logo: financialAccounts.logo,
|
||||
initialBalance: financialAccounts.initialBalance,
|
||||
excludeFromBalance: financialAccounts.excludeFromBalance,
|
||||
excludeInitialBalanceFromIncome:
|
||||
financialAccounts.excludeInitialBalanceFromIncome,
|
||||
balanceMovements: sql<number>`
|
||||
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),
|
||||
ilike(contas.status, "inativa"),
|
||||
sql`(${lancamentos.id} IS NULL OR ${pagadores.role} = ${PAGADOR_ROLE_ADMIN})`,
|
||||
eq(financialAccounts.userId, userId),
|
||||
ilike(financialAccounts.status, "inativa"),
|
||||
sql`(${transactions.id} IS NULL OR ${payers.role} = ${PAYER_ROLE_ADMIN})`,
|
||||
),
|
||||
)
|
||||
.groupBy(
|
||||
contas.id,
|
||||
contas.name,
|
||||
contas.accountType,
|
||||
contas.status,
|
||||
contas.note,
|
||||
contas.logo,
|
||||
contas.initialBalance,
|
||||
contas.excludeFromBalance,
|
||||
contas.excludeInitialBalanceFromIncome,
|
||||
financialAccounts.id,
|
||||
financialAccounts.name,
|
||||
financialAccounts.accountType,
|
||||
financialAccounts.status,
|
||||
financialAccounts.note,
|
||||
financialAccounts.logo,
|
||||
financialAccounts.initialBalance,
|
||||
financialAccounts.excludeFromBalance,
|
||||
financialAccounts.excludeInitialBalanceFromIncome,
|
||||
),
|
||||
loadLogoOptions(),
|
||||
]);
|
||||
@@ -173,11 +175,11 @@ export async function fetchInativosForUser(
|
||||
export async function fetchAllAccountsForUser(userId: string): Promise<{
|
||||
activeAccounts: AccountData[];
|
||||
archivedAccounts: AccountData[];
|
||||
logoOptions: LogoOption[];
|
||||
logoOptions: string[];
|
||||
}> {
|
||||
const [activeData, archivedData] = await Promise.all([
|
||||
fetchAccountsForUser(userId),
|
||||
fetchInativosForUser(userId),
|
||||
fetchInactiveForUser(userId),
|
||||
]);
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { and, desc, eq, lt, type SQL, 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";
|
||||
|
||||
export type AccountSummaryData = {
|
||||
openingBalance: number;
|
||||
@@ -11,8 +11,8 @@ export type AccountSummaryData = {
|
||||
totalExpenses: number;
|
||||
};
|
||||
|
||||
export async function fetchAccountData(userId: string, contaId: string) {
|
||||
const account = await db.query.contas.findFirst({
|
||||
export async function fetchAccountData(userId: string, accountId: string) {
|
||||
const account = await db.query.financialAccounts.findFirst({
|
||||
columns: {
|
||||
id: true,
|
||||
name: true,
|
||||
@@ -22,7 +22,10 @@ export async function fetchAccountData(userId: string, contaId: string) {
|
||||
logo: true,
|
||||
note: true,
|
||||
},
|
||||
where: and(eq(contas.id, contaId), eq(contas.userId, userId)),
|
||||
where: and(
|
||||
eq(financialAccounts.id, accountId),
|
||||
eq(financialAccounts.userId, userId),
|
||||
),
|
||||
});
|
||||
|
||||
return account;
|
||||
@@ -30,7 +33,7 @@ export async function fetchAccountData(userId: string, contaId: string) {
|
||||
|
||||
export async function fetchAccountSummary(
|
||||
userId: string,
|
||||
contaId: string,
|
||||
accountId: string,
|
||||
selectedPeriod: string,
|
||||
): Promise<AccountSummaryData> {
|
||||
const [periodSummary] = await db
|
||||
@@ -39,8 +42,8 @@ export async function fetchAccountSummary(
|
||||
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
|
||||
@@ -50,8 +53,8 @@ export async function fetchAccountSummary(
|
||||
coalesce(
|
||||
sum(
|
||||
case
|
||||
when ${lancamentos.note} = ${INITIAL_BALANCE_NOTE} then 0
|
||||
when ${lancamentos.transactionType} = 'Receita' then ${lancamentos.amount}
|
||||
when ${transactions.note} = ${INITIAL_BALANCE_NOTE} then 0
|
||||
when ${transactions.transactionType} = 'Receita' then ${transactions.amount}
|
||||
else 0
|
||||
end
|
||||
),
|
||||
@@ -62,8 +65,8 @@ export async function fetchAccountSummary(
|
||||
coalesce(
|
||||
sum(
|
||||
case
|
||||
when ${lancamentos.note} = ${INITIAL_BALANCE_NOTE} then 0
|
||||
when ${lancamentos.transactionType} = 'Despesa' then ${lancamentos.amount}
|
||||
when ${transactions.note} = ${INITIAL_BALANCE_NOTE} then 0
|
||||
when ${transactions.transactionType} = 'Despesa' then ${transactions.amount}
|
||||
else 0
|
||||
end
|
||||
),
|
||||
@@ -71,15 +74,15 @@ export async function fetchAccountSummary(
|
||||
)
|
||||
`,
|
||||
})
|
||||
.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.contaId, contaId),
|
||||
eq(lancamentos.period, selectedPeriod),
|
||||
eq(lancamentos.isSettled, true),
|
||||
eq(pagadores.role, PAGADOR_ROLE_ADMIN),
|
||||
eq(transactions.userId, userId),
|
||||
eq(transactions.accountId, accountId),
|
||||
eq(transactions.period, selectedPeriod),
|
||||
eq(transactions.isSettled, true),
|
||||
eq(payers.role, PAYER_ROLE_ADMIN),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -89,27 +92,27 @@ export async function fetchAccountSummary(
|
||||
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(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.contaId, contaId),
|
||||
lt(lancamentos.period, selectedPeriod),
|
||||
eq(lancamentos.isSettled, true),
|
||||
eq(pagadores.role, PAGADOR_ROLE_ADMIN),
|
||||
eq(transactions.userId, userId),
|
||||
eq(transactions.accountId, accountId),
|
||||
lt(transactions.period, selectedPeriod),
|
||||
eq(transactions.isSettled, true),
|
||||
eq(payers.role, PAYER_ROLE_ADMIN),
|
||||
),
|
||||
);
|
||||
|
||||
const account = await fetchAccountData(userId, contaId);
|
||||
const account = await fetchAccountData(userId, accountId);
|
||||
if (!account) {
|
||||
throw new Error("Account not found");
|
||||
}
|
||||
@@ -135,17 +138,17 @@ export async function fetchAccountLancamentos(
|
||||
settledOnly = true,
|
||||
) {
|
||||
const allFilters = settledOnly
|
||||
? [...filters, eq(lancamentos.isSettled, true)]
|
||||
? [...filters, eq(transactions.isSettled, true)]
|
||||
: filters;
|
||||
|
||||
return db.query.lancamentos.findMany({
|
||||
return db.query.transactions.findMany({
|
||||
where: and(...allFilters),
|
||||
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),
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user