mirror of
https://github.com/felipegcoutinho/openmonetis.git
synced 2026-05-09 11:01:45 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51652da4f8 | ||
|
|
7a74f9405e |
@@ -5,6 +5,13 @@ Todas as mudanças notáveis deste projeto serão documentadas neste arquivo.
|
|||||||
O formato é baseado em [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1.0/),
|
O formato é baseado em [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1.0/),
|
||||||
e este projeto adere ao [Versionamento Semântico](https://semver.org/lang/pt-BR/).
|
e este projeto adere ao [Versionamento Semântico](https://semver.org/lang/pt-BR/).
|
||||||
|
|
||||||
|
## [2.5.1] - 2026-05-04
|
||||||
|
|
||||||
|
Versão de correção pontual focada na exibição do indicador de anexo nas tabelas de lançamentos da fatura do cartão. Em `/cards/[cardId]/invoice`, lançamentos com anexos não mostravam o ícone porque o fetcher dedicado da fatura não calculava o flag `hasAttachments`. A primeira tentativa de adicionar o EXISTS via `extras` na query relacional gerou SQL inválido (Drizzle re-aliasava `transactionAttachments.transactionId` para o alias da tabela externa). A correção definitiva troca o fetcher pela função compartilhada `fetchTransactionsWithRelations` de `features/transactions`, que já implementa o EXISTS corretamente via `select`.
|
||||||
|
|
||||||
|
### Corrigido
|
||||||
|
- Ícone de anexo voltou a aparecer na tabela de lançamentos da fatura do cartão (`/cards/[cardId]/invoice`). `fetchCardTransactions` em `features/invoices/queries.ts` agora delega para `fetchTransactionsWithRelations`, garantindo que o flag `hasAttachments` seja preenchido com a mesma EXISTS subquery usada no restante do app.
|
||||||
|
|
||||||
## [2.5.0] - 2026-05-01
|
## [2.5.0] - 2026-05-01
|
||||||
|
|
||||||
Esta versão melhora o fechamento de faturas, a correção de lançamentos já registrados e a conferência de saldos contra o extrato do banco. O novo **ajuste de fatura** fecha a conta entre o total calculado pelo sistema e o valor real cobrado pelo banco, sem exigir que o usuário reabra lançamentos individuais. A mesma ideia foi estendida para **contas correntes**: na página do extrato, ao lado de "Saldo ao final do período", o usuário informa o saldo real e o sistema cria (ou atualiza) um lançamento de ajuste no período visualizado. Também entra o fluxo de **reembolso** para despesas à vista: pelo menu de ações do lançamento, o usuário informa a data do reembolso e o sistema cria uma receita espelhada no extrato ou na fatura correta. O widget de boletos do dashboard ganhou paridade com o widget de faturas — confirmação de pagamento agora pede conta de origem e data antes de quitar o boleto. Por fim, o **limite do cartão** passou a ser obrigatório e o sistema bloqueia despesas em cartão que ultrapassem o limite disponível, retornando uma mensagem com o valor exato disponível. As operações mantêm rastro no lançamento gerado e respeitam a proteção de faturas já pagas.
|
Esta versão melhora o fechamento de faturas, a correção de lançamentos já registrados e a conferência de saldos contra o extrato do banco. O novo **ajuste de fatura** fecha a conta entre o total calculado pelo sistema e o valor real cobrado pelo banco, sem exigir que o usuário reabra lançamentos individuais. A mesma ideia foi estendida para **contas correntes**: na página do extrato, ao lado de "Saldo ao final do período", o usuário informa o saldo real e o sistema cria (ou atualiza) um lançamento de ajuste no período visualizado. Também entra o fluxo de **reembolso** para despesas à vista: pelo menu de ações do lançamento, o usuário informa a data do reembolso e o sistema cria uma receita espelhada no extrato ou na fatura correta. O widget de boletos do dashboard ganhou paridade com o widget de faturas — confirmação de pagamento agora pede conta de origem e data antes de quitar o boleto. Por fim, o **limite do cartão** passou a ser obrigatório e o sistema bloqueia despesas em cartão que ultrapassem o limite disponível, retornando uma mensagem com o valor exato disponível. As operações mantêm rastro no lançamento gerado e respeitam a proteção de faturas já pagas.
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
> **⚠️ Não há versão online hospedada.** Você precisa clonar o repositório e rodar localmente ou no seu próprio servidor.
|
> **⚠️ Não há versão online hospedada.** Você precisa clonar o repositório e rodar localmente ou no seu próprio servidor.
|
||||||
|
|
||||||
[](CHANGELOG.md)
|
[](CHANGELOG.md)
|
||||||
[](https://nextjs.org/)
|
[](https://nextjs.org/)
|
||||||
[](https://www.typescriptlang.org/)
|
[](https://www.typescriptlang.org/)
|
||||||
[](https://www.postgresql.org/)
|
[](https://www.postgresql.org/)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,209 +1,209 @@
|
|||||||
{
|
{
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"dialect": "postgresql",
|
"dialect": "postgresql",
|
||||||
"entries": [
|
"entries": [
|
||||||
{
|
{
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1762993507299,
|
"when": 1762993507299,
|
||||||
"tag": "0000_flashy_manta",
|
"tag": "0000_flashy_manta",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1765199006435,
|
"when": 1765199006435,
|
||||||
"tag": "0001_young_mister_fear",
|
"tag": "0001_young_mister_fear",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 2,
|
"idx": 2,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1765200545692,
|
"when": 1765200545692,
|
||||||
"tag": "0002_slimy_flatman",
|
"tag": "0002_slimy_flatman",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 3,
|
"idx": 3,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1767102605526,
|
"when": 1767102605526,
|
||||||
"tag": "0003_green_korg",
|
"tag": "0003_green_korg",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 4,
|
"idx": 4,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1767104066872,
|
"when": 1767104066872,
|
||||||
"tag": "0004_acoustic_mach_iv",
|
"tag": "0004_acoustic_mach_iv",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 5,
|
"idx": 5,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1767106121811,
|
"when": 1767106121811,
|
||||||
"tag": "0005_adorable_bruce_banner",
|
"tag": "0005_adorable_bruce_banner",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 6,
|
"idx": 6,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1767107487318,
|
"when": 1767107487318,
|
||||||
"tag": "0006_youthful_mister_fear",
|
"tag": "0006_youthful_mister_fear",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 7,
|
"idx": 7,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1767118780033,
|
"when": 1767118780033,
|
||||||
"tag": "0007_sturdy_kate_bishop",
|
"tag": "0007_sturdy_kate_bishop",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 8,
|
"idx": 8,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1767125796314,
|
"when": 1767125796314,
|
||||||
"tag": "0008_fat_stick",
|
"tag": "0008_fat_stick",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 9,
|
"idx": 9,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1768925100873,
|
"when": 1768925100873,
|
||||||
"tag": "0009_add_dashboard_widgets",
|
"tag": "0009_add_dashboard_widgets",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 10,
|
"idx": 10,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1769369834242,
|
"when": 1769369834242,
|
||||||
"tag": "0010_lame_psynapse",
|
"tag": "0010_lame_psynapse",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 11,
|
"idx": 11,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1769447087678,
|
"when": 1769447087678,
|
||||||
"tag": "0011_remove_unused_inbox_columns",
|
"tag": "0011_remove_unused_inbox_columns",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 12,
|
"idx": 12,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1769533200000,
|
"when": 1769533200000,
|
||||||
"tag": "0012_rename_tables_to_portuguese",
|
"tag": "0012_rename_tables_to_portuguese",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 13,
|
"idx": 13,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1769523352777,
|
"when": 1769523352777,
|
||||||
"tag": "0013_fancy_rick_jones",
|
"tag": "0013_fancy_rick_jones",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 14,
|
"idx": 14,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1769619226903,
|
"when": 1769619226903,
|
||||||
"tag": "0014_yielding_jack_flag",
|
"tag": "0014_yielding_jack_flag",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 15,
|
"idx": 15,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1770332054481,
|
"when": 1770332054481,
|
||||||
"tag": "0015_concerned_kat_farrell",
|
"tag": "0015_concerned_kat_farrell",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 16,
|
"idx": 16,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1771166328908,
|
"when": 1771166328908,
|
||||||
"tag": "0016_complete_randall",
|
"tag": "0016_complete_randall",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 17,
|
"idx": 17,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1772400510326,
|
"when": 1772400510326,
|
||||||
"tag": "0017_previous_warstar",
|
"tag": "0017_previous_warstar",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 18,
|
"idx": 18,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1773020417482,
|
"when": 1773020417482,
|
||||||
"tag": "0018_rainy_epoch",
|
"tag": "0018_rainy_epoch",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 19,
|
"idx": 19,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1773699152928,
|
"when": 1773699152928,
|
||||||
"tag": "0019_ordinary_wild_pack",
|
"tag": "0019_ordinary_wild_pack",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 20,
|
"idx": 20,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1773841892114,
|
"when": 1773841892114,
|
||||||
"tag": "0020_add-budget-invoice-unique-constraints",
|
"tag": "0020_add-budget-invoice-unique-constraints",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 21,
|
"idx": 21,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1774033320053,
|
"when": 1774033320053,
|
||||||
"tag": "0021_careful_malcolm_colcord",
|
"tag": "0021_careful_malcolm_colcord",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 22,
|
"idx": 22,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1748000000000,
|
"when": 1748000000000,
|
||||||
"tag": "0022_import-category-mappings",
|
"tag": "0022_import-category-mappings",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 23,
|
"idx": 23,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1774529878374,
|
"when": 1774529878374,
|
||||||
"tag": "0023_sturdy_wolfpack",
|
"tag": "0023_sturdy_wolfpack",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 24,
|
"idx": 24,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1774891206703,
|
"when": 1774891206703,
|
||||||
"tag": "0024_petite_lucky_pierre",
|
"tag": "0024_petite_lucky_pierre",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 25,
|
"idx": 25,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1776351838548,
|
"when": 1776351838548,
|
||||||
"tag": "0025_burly_colonel_america",
|
"tag": "0025_burly_colonel_america",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 26,
|
"idx": 26,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1777042423451,
|
"when": 1777042423451,
|
||||||
"tag": "0026_bored_eternity",
|
"tag": "0026_bored_eternity",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 28,
|
"idx": 28,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1777153372633,
|
"when": 1777153372633,
|
||||||
"tag": "0028_fancy_reaper",
|
"tag": "0028_fancy_reaper",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 29,
|
"idx": 29,
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"when": 1777648189399,
|
"when": 1777648189399,
|
||||||
"tag": "0029_friendly_spitfire",
|
"tag": "0029_friendly_spitfire",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "openmonetis",
|
"name": "openmonetis",
|
||||||
"version": "2.5.0",
|
"version": "2.5.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"packageManager": "pnpm@10.33.0",
|
"packageManager": "pnpm@10.33.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
TooltipContent,
|
TooltipContent,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/shared/components/ui/tooltip";
|
} from "@/shared/components/ui/tooltip";
|
||||||
import { getCurrentPeriod, formatPeriodForUrl } from "@/shared/utils/period";
|
import { formatPeriodForUrl, getCurrentPeriod } from "@/shared/utils/period";
|
||||||
import { cn } from "@/shared/utils/ui";
|
import { cn } from "@/shared/utils/ui";
|
||||||
|
|
||||||
type BillListItemProps = {
|
type BillListItemProps = {
|
||||||
|
|||||||
@@ -114,12 +114,14 @@ export async function fetchDashboardPeriodOverview(
|
|||||||
.select({
|
.select({
|
||||||
period: transactions.period,
|
period: transactions.period,
|
||||||
transactionType: transactions.transactionType,
|
transactionType: transactions.transactionType,
|
||||||
totalAmount: sql<number>`coalesce(sum(case when ${transactions.note} ilike ${refundPattern} then 0 else ${transactions.amount} end), 0)`.as(
|
totalAmount:
|
||||||
"total",
|
sql<number>`coalesce(sum(case when ${transactions.note} ilike ${refundPattern} then 0 else ${transactions.amount} end), 0)`.as(
|
||||||
),
|
"total",
|
||||||
refundAmount: sql<number>`coalesce(sum(case when ${transactions.note} ilike ${refundPattern} then ${transactions.amount} else 0 end), 0)`.as(
|
),
|
||||||
"refund",
|
refundAmount:
|
||||||
),
|
sql<number>`coalesce(sum(case when ${transactions.note} ilike ${refundPattern} then ${transactions.amount} else 0 end), 0)`.as(
|
||||||
|
"refund",
|
||||||
|
),
|
||||||
accountExcludeFromBalance: financialAccounts.excludeFromBalance,
|
accountExcludeFromBalance: financialAccounts.excludeFromBalance,
|
||||||
})
|
})
|
||||||
.from(transactions)
|
.from(transactions)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { and, desc, eq, type SQL, sum } from "drizzle-orm";
|
import { and, eq, type SQL, sum } from "drizzle-orm";
|
||||||
import { cards, invoices, transactions } from "@/db/schema";
|
import { cards, invoices, transactions } from "@/db/schema";
|
||||||
|
import { fetchTransactionsWithRelations } from "@/features/transactions/queries";
|
||||||
import { buildInvoicePaymentNote } from "@/shared/lib/accounts/constants";
|
import { buildInvoicePaymentNote } from "@/shared/lib/accounts/constants";
|
||||||
import { db } from "@/shared/lib/db";
|
import { db } from "@/shared/lib/db";
|
||||||
import {
|
import {
|
||||||
@@ -104,14 +105,5 @@ export async function fetchInvoiceData(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchCardTransactions(filters: SQL[]) {
|
export async function fetchCardTransactions(filters: SQL[]) {
|
||||||
return db.query.transactions.findMany({
|
return fetchTransactionsWithRelations({ filters });
|
||||||
where: and(...filters),
|
|
||||||
with: {
|
|
||||||
payer: true,
|
|
||||||
financialAccount: true,
|
|
||||||
card: true,
|
|
||||||
category: true,
|
|
||||||
},
|
|
||||||
orderBy: desc(transactions.purchaseDate),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,7 @@
|
|||||||
import { and, eq } from "drizzle-orm";
|
import { and, eq } from "drizzle-orm";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { cards, categories, transactions } from "@/db/schema";
|
import { cards, categories, transactions } from "@/db/schema";
|
||||||
import {
|
import { buildRefundNote, isRefundNote } from "@/shared/lib/accounts/constants";
|
||||||
buildRefundNote,
|
|
||||||
isRefundNote,
|
|
||||||
} from "@/shared/lib/accounts/constants";
|
|
||||||
import { getUser } from "@/shared/lib/auth/server";
|
import { getUser } from "@/shared/lib/auth/server";
|
||||||
import { db } from "@/shared/lib/db";
|
import { db } from "@/shared/lib/db";
|
||||||
import { PERIOD_FORMAT_REGEX } from "@/shared/lib/invoices";
|
import { PERIOD_FORMAT_REGEX } from "@/shared/lib/invoices";
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ export const requiredDecimalSchema = (fieldName: string = "valor") =>
|
|||||||
.transform((value) => value.replace(",", ".")),
|
.transform((value) => value.replace(",", ".")),
|
||||||
])
|
])
|
||||||
.transform((value, ctx) => {
|
.transform((value, ctx) => {
|
||||||
const parsed = typeof value === "number" ? value : Number.parseFloat(value);
|
const parsed =
|
||||||
|
typeof value === "number" ? value : Number.parseFloat(value);
|
||||||
if (Number.isNaN(parsed)) {
|
if (Number.isNaN(parsed)) {
|
||||||
ctx.addIssue({
|
ctx.addIssue({
|
||||||
code: z.ZodIssueCode.custom,
|
code: z.ZodIssueCode.custom,
|
||||||
|
|||||||
Reference in New Issue
Block a user