mirror of
https://github.com/felipegcoutinho/openmonetis.git
synced 2026-05-10 03:11:46 +00:00
feat(faturas/extrato): ajuste de fatura, reembolso e ajuste de saldo da conta
- botão "Ajustar fatura" na página da fatura abre dialog com input do valor real e preview da diferença; action faz upsert/delete idempotente do lançamento de ajuste - opção "Reembolso" no dropdown de ações de despesas à vista cria receita espelhada no extrato ou fatura correta, vinculada ao lançamento original - botão "Ajustar saldo" no extrato da conta compara saldo real informado e gera lançamento de ajuste por (accountId, period) via upsert/delete idempotente - constantes INVOICE_ADJUSTMENT_NAME, ACCOUNT_BALANCE_ADJUSTMENT_NAME, REFUND_NOTE_PREFIX e buildRefundNote() centralizadas em shared/lib/accounts/constants.ts - extrato agora contabiliza transferências internas em Entradas e Saídas corretamente Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -42,6 +42,7 @@ import {
|
||||
type UpdateInput,
|
||||
updateSchema,
|
||||
validateAllOwnership,
|
||||
validateCardLimit,
|
||||
} from "./core";
|
||||
|
||||
export async function createTransactionAction(
|
||||
@@ -132,6 +133,20 @@ export async function createTransactionAction(
|
||||
)} já estão pagas. Desfaça o pagamento antes de adicionar este lançamento.`,
|
||||
} as ActionResult<{ ids: string[] }>;
|
||||
}
|
||||
|
||||
if (data.transactionType === "Despesa") {
|
||||
const limitCheck = await validateCardLimit({
|
||||
userId: user.id,
|
||||
cardId: data.cardId,
|
||||
addAmount: Math.abs(data.amount),
|
||||
});
|
||||
if (!limitCheck.ok) {
|
||||
return {
|
||||
success: false,
|
||||
error: limitCheck.error,
|
||||
} as ActionResult<{ ids: string[] }>;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const inserted = await db
|
||||
@@ -287,6 +302,22 @@ export async function updateTransactionAction(
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
data.paymentMethod === "Cartão de crédito" &&
|
||||
data.cardId &&
|
||||
data.transactionType === "Despesa"
|
||||
) {
|
||||
const limitCheck = await validateCardLimit({
|
||||
userId: user.id,
|
||||
cardId: data.cardId,
|
||||
addAmount: Math.abs(data.amount),
|
||||
excludeTransactionIds: [data.id],
|
||||
});
|
||||
if (!limitCheck.ok) {
|
||||
return { success: false, error: limitCheck.error };
|
||||
}
|
||||
}
|
||||
|
||||
await db
|
||||
.update(transactions)
|
||||
.set({
|
||||
@@ -582,7 +613,7 @@ export async function toggleTransactionSettlementAction(
|
||||
const data = toggleSettlementSchema.parse(input);
|
||||
|
||||
const existing = await db.query.transactions.findFirst({
|
||||
columns: { id: true, paymentMethod: true },
|
||||
columns: { id: true, paymentMethod: true, accountId: true },
|
||||
where: and(
|
||||
eq(transactions.id, data.id),
|
||||
eq(transactions.userId, user.id),
|
||||
@@ -601,18 +632,52 @@ export async function toggleTransactionSettlementAction(
|
||||
}
|
||||
|
||||
const isBoleto = existing.paymentMethod === "Boleto";
|
||||
const customPaymentDate =
|
||||
isBoleto && data.value && data.paymentDate
|
||||
? parseLocalDateString(data.paymentDate)
|
||||
: null;
|
||||
const boletoPaymentDate = isBoleto
|
||||
? data.value
|
||||
? getBusinessTodayDate()
|
||||
? (customPaymentDate ?? getBusinessTodayDate())
|
||||
: null
|
||||
: null;
|
||||
|
||||
const shouldUpdateAccount =
|
||||
isBoleto && data.value && data.paymentAccountId !== undefined;
|
||||
|
||||
if (shouldUpdateAccount && data.paymentAccountId) {
|
||||
const paymentAccount = await db.query.financialAccounts.findFirst({
|
||||
columns: { id: true },
|
||||
where: and(
|
||||
eq(financialAccounts.id, data.paymentAccountId),
|
||||
eq(financialAccounts.userId, user.id),
|
||||
),
|
||||
});
|
||||
|
||||
if (!paymentAccount) {
|
||||
return {
|
||||
success: false,
|
||||
error: "Conta de pagamento não encontrada.",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const updatePayload: {
|
||||
isSettled: boolean;
|
||||
boletoPaymentDate: Date | null;
|
||||
accountId?: string | null;
|
||||
} = {
|
||||
isSettled: data.value,
|
||||
boletoPaymentDate,
|
||||
};
|
||||
|
||||
if (shouldUpdateAccount) {
|
||||
updatePayload.accountId = data.paymentAccountId ?? null;
|
||||
}
|
||||
|
||||
await db
|
||||
.update(transactions)
|
||||
.set({
|
||||
isSettled: data.value,
|
||||
boletoPaymentDate,
|
||||
})
|
||||
.set(updatePayload)
|
||||
.where(
|
||||
and(eq(transactions.id, data.id), eq(transactions.userId, user.id)),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user