mirror of
https://github.com/felipegcoutinho/openmonetis.git
synced 2026-05-09 02:51:46 +00:00
Compare commits
9 Commits
v2.5.0
...
1df2ba787d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1df2ba787d | ||
|
|
e5d9b66cca | ||
|
|
37edb1b76d | ||
|
|
6288f5f8d4 | ||
|
|
57ac326c2a | ||
|
|
dccc18b1c1 | ||
|
|
0cb01a1d4c | ||
|
|
51652da4f8 | ||
|
|
7a74f9405e |
23
CHANGELOG.md
23
CHANGELOG.md
@@ -5,6 +5,29 @@ 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/),
|
||||
e este projeto adere ao [Versionamento Semântico](https://semver.org/lang/pt-BR/).
|
||||
|
||||
## [2.5.2] - 2026-05-04
|
||||
|
||||
Esta versão traz melhorias visuais e de usabilidade em contas, lançamentos, orçamentos, cartões e anotações: novos tipos de conta, ícones no seletor, feedback visual de limite excedido nas progress bars e refinamentos nos ícones de tarefas em anotações.
|
||||
|
||||
### Adicionado
|
||||
- Novos tipos de conta `"Dinheiro"` e `"Outros"` na lista padrão do diálogo de contas (issue #50).
|
||||
- Ícones por tipo de conta no seletor (Conta Corrente, Poupança, Carteira Digital, Investimento, Pré-Pago, Dinheiro, Outros).
|
||||
- Filtro automático: ao selecionar `"Dinheiro"` como forma de pagamento em lançamentos, o select de conta exibe apenas contas do tipo `"Dinheiro"`.
|
||||
- Sinal `+` no valor de transferências recebidas na tabela de lançamentos (mantém cor azul).
|
||||
|
||||
### Alterado
|
||||
- Forma de pagamento de novas transferências entre contas alterada de `"Pix"` para `"Transferência bancária"`.
|
||||
- Progress bar de orçamentos excedidos agora exibe indicador e fundo na cor `destructive`.
|
||||
- Progress bar de cartões com 100% do limite utilizado agora exibe indicador e fundo na cor `destructive`.
|
||||
- Ícone de tarefa não concluída no card e no modal de detalhes de anotações substituído por `RiSubtractLine` (locais sem interação de marcação).
|
||||
|
||||
## [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
|
||||
|
||||
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.
|
||||
|
||||
[](CHANGELOG.md)
|
||||
[](CHANGELOG.md)
|
||||
[](https://nextjs.org/)
|
||||
[](https://www.typescriptlang.org/)
|
||||
[](https://www.postgresql.org/)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,209 +1,209 @@
|
||||
{
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"entries": [
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "7",
|
||||
"when": 1762993507299,
|
||||
"tag": "0000_flashy_manta",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 1,
|
||||
"version": "7",
|
||||
"when": 1765199006435,
|
||||
"tag": "0001_young_mister_fear",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 2,
|
||||
"version": "7",
|
||||
"when": 1765200545692,
|
||||
"tag": "0002_slimy_flatman",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 3,
|
||||
"version": "7",
|
||||
"when": 1767102605526,
|
||||
"tag": "0003_green_korg",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 4,
|
||||
"version": "7",
|
||||
"when": 1767104066872,
|
||||
"tag": "0004_acoustic_mach_iv",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 5,
|
||||
"version": "7",
|
||||
"when": 1767106121811,
|
||||
"tag": "0005_adorable_bruce_banner",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 6,
|
||||
"version": "7",
|
||||
"when": 1767107487318,
|
||||
"tag": "0006_youthful_mister_fear",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 7,
|
||||
"version": "7",
|
||||
"when": 1767118780033,
|
||||
"tag": "0007_sturdy_kate_bishop",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 8,
|
||||
"version": "7",
|
||||
"when": 1767125796314,
|
||||
"tag": "0008_fat_stick",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 9,
|
||||
"version": "7",
|
||||
"when": 1768925100873,
|
||||
"tag": "0009_add_dashboard_widgets",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 10,
|
||||
"version": "7",
|
||||
"when": 1769369834242,
|
||||
"tag": "0010_lame_psynapse",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 11,
|
||||
"version": "7",
|
||||
"when": 1769447087678,
|
||||
"tag": "0011_remove_unused_inbox_columns",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 12,
|
||||
"version": "7",
|
||||
"when": 1769533200000,
|
||||
"tag": "0012_rename_tables_to_portuguese",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 13,
|
||||
"version": "7",
|
||||
"when": 1769523352777,
|
||||
"tag": "0013_fancy_rick_jones",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 14,
|
||||
"version": "7",
|
||||
"when": 1769619226903,
|
||||
"tag": "0014_yielding_jack_flag",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 15,
|
||||
"version": "7",
|
||||
"when": 1770332054481,
|
||||
"tag": "0015_concerned_kat_farrell",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 16,
|
||||
"version": "7",
|
||||
"when": 1771166328908,
|
||||
"tag": "0016_complete_randall",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 17,
|
||||
"version": "7",
|
||||
"when": 1772400510326,
|
||||
"tag": "0017_previous_warstar",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 18,
|
||||
"version": "7",
|
||||
"when": 1773020417482,
|
||||
"tag": "0018_rainy_epoch",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 19,
|
||||
"version": "7",
|
||||
"when": 1773699152928,
|
||||
"tag": "0019_ordinary_wild_pack",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 20,
|
||||
"version": "7",
|
||||
"when": 1773841892114,
|
||||
"tag": "0020_add-budget-invoice-unique-constraints",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 21,
|
||||
"version": "7",
|
||||
"when": 1774033320053,
|
||||
"tag": "0021_careful_malcolm_colcord",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 22,
|
||||
"version": "7",
|
||||
"when": 1748000000000,
|
||||
"tag": "0022_import-category-mappings",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 23,
|
||||
"version": "7",
|
||||
"when": 1774529878374,
|
||||
"tag": "0023_sturdy_wolfpack",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 24,
|
||||
"version": "7",
|
||||
"when": 1774891206703,
|
||||
"tag": "0024_petite_lucky_pierre",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 25,
|
||||
"version": "7",
|
||||
"when": 1776351838548,
|
||||
"tag": "0025_burly_colonel_america",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 26,
|
||||
"version": "7",
|
||||
"when": 1777042423451,
|
||||
"tag": "0026_bored_eternity",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 28,
|
||||
"version": "7",
|
||||
"when": 1777153372633,
|
||||
"tag": "0028_fancy_reaper",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 29,
|
||||
"version": "7",
|
||||
"when": 1777648189399,
|
||||
"tag": "0029_friendly_spitfire",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"entries": [
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "7",
|
||||
"when": 1762993507299,
|
||||
"tag": "0000_flashy_manta",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 1,
|
||||
"version": "7",
|
||||
"when": 1765199006435,
|
||||
"tag": "0001_young_mister_fear",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 2,
|
||||
"version": "7",
|
||||
"when": 1765200545692,
|
||||
"tag": "0002_slimy_flatman",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 3,
|
||||
"version": "7",
|
||||
"when": 1767102605526,
|
||||
"tag": "0003_green_korg",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 4,
|
||||
"version": "7",
|
||||
"when": 1767104066872,
|
||||
"tag": "0004_acoustic_mach_iv",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 5,
|
||||
"version": "7",
|
||||
"when": 1767106121811,
|
||||
"tag": "0005_adorable_bruce_banner",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 6,
|
||||
"version": "7",
|
||||
"when": 1767107487318,
|
||||
"tag": "0006_youthful_mister_fear",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 7,
|
||||
"version": "7",
|
||||
"when": 1767118780033,
|
||||
"tag": "0007_sturdy_kate_bishop",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 8,
|
||||
"version": "7",
|
||||
"when": 1767125796314,
|
||||
"tag": "0008_fat_stick",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 9,
|
||||
"version": "7",
|
||||
"when": 1768925100873,
|
||||
"tag": "0009_add_dashboard_widgets",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 10,
|
||||
"version": "7",
|
||||
"when": 1769369834242,
|
||||
"tag": "0010_lame_psynapse",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 11,
|
||||
"version": "7",
|
||||
"when": 1769447087678,
|
||||
"tag": "0011_remove_unused_inbox_columns",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 12,
|
||||
"version": "7",
|
||||
"when": 1769533200000,
|
||||
"tag": "0012_rename_tables_to_portuguese",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 13,
|
||||
"version": "7",
|
||||
"when": 1769523352777,
|
||||
"tag": "0013_fancy_rick_jones",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 14,
|
||||
"version": "7",
|
||||
"when": 1769619226903,
|
||||
"tag": "0014_yielding_jack_flag",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 15,
|
||||
"version": "7",
|
||||
"when": 1770332054481,
|
||||
"tag": "0015_concerned_kat_farrell",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 16,
|
||||
"version": "7",
|
||||
"when": 1771166328908,
|
||||
"tag": "0016_complete_randall",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 17,
|
||||
"version": "7",
|
||||
"when": 1772400510326,
|
||||
"tag": "0017_previous_warstar",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 18,
|
||||
"version": "7",
|
||||
"when": 1773020417482,
|
||||
"tag": "0018_rainy_epoch",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 19,
|
||||
"version": "7",
|
||||
"when": 1773699152928,
|
||||
"tag": "0019_ordinary_wild_pack",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 20,
|
||||
"version": "7",
|
||||
"when": 1773841892114,
|
||||
"tag": "0020_add-budget-invoice-unique-constraints",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 21,
|
||||
"version": "7",
|
||||
"when": 1774033320053,
|
||||
"tag": "0021_careful_malcolm_colcord",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 22,
|
||||
"version": "7",
|
||||
"when": 1748000000000,
|
||||
"tag": "0022_import-category-mappings",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 23,
|
||||
"version": "7",
|
||||
"when": 1774529878374,
|
||||
"tag": "0023_sturdy_wolfpack",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 24,
|
||||
"version": "7",
|
||||
"when": 1774891206703,
|
||||
"tag": "0024_petite_lucky_pierre",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 25,
|
||||
"version": "7",
|
||||
"when": 1776351838548,
|
||||
"tag": "0025_burly_colonel_america",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 26,
|
||||
"version": "7",
|
||||
"when": 1777042423451,
|
||||
"tag": "0026_bored_eternity",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 28,
|
||||
"version": "7",
|
||||
"when": 1777153372633,
|
||||
"tag": "0028_fancy_reaper",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 29,
|
||||
"version": "7",
|
||||
"when": 1777648189399,
|
||||
"tag": "0029_friendly_spitfire",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "openmonetis",
|
||||
"version": "2.5.0",
|
||||
"version": "2.5.2",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@10.33.0",
|
||||
"scripts": {
|
||||
|
||||
BIN
public/logos/dinheiro.png
Normal file
BIN
public/logos/dinheiro.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 72 KiB |
@@ -37,7 +37,9 @@ const DEFAULT_ACCOUNT_TYPES = [
|
||||
"Conta Poupança",
|
||||
"Carteira Digital",
|
||||
"Conta Investimento",
|
||||
"Dinheiro",
|
||||
"Pré-Pago | VR/VA",
|
||||
"Outros",
|
||||
] as const;
|
||||
|
||||
const DEFAULT_ACCOUNT_STATUS = ["Ativa", "Inativa"] as const;
|
||||
|
||||
@@ -12,7 +12,10 @@ import {
|
||||
SelectValue,
|
||||
} from "@/shared/components/ui/select";
|
||||
import { Textarea } from "@/shared/components/ui/textarea";
|
||||
import { StatusSelectContent } from "./account-select-items";
|
||||
import {
|
||||
AccountTypeSelectContent,
|
||||
StatusSelectContent,
|
||||
} from "./account-select-items";
|
||||
|
||||
import type { AccountFormValues } from "./types";
|
||||
|
||||
@@ -54,12 +57,16 @@ export function AccountFormFields({
|
||||
onValueChange={(value) => onChange("accountType", value)}
|
||||
>
|
||||
<SelectTrigger id="account-type" className="w-full">
|
||||
<SelectValue placeholder="Selecione o tipo" />
|
||||
<SelectValue placeholder="Selecione o tipo">
|
||||
{values.accountType && (
|
||||
<AccountTypeSelectContent label={values.accountType} />
|
||||
)}
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{accountTypes.map((type) => (
|
||||
<SelectItem key={type} value={type}>
|
||||
{type}
|
||||
<AccountTypeSelectContent label={type} />
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
"use client";
|
||||
|
||||
import StatusDot from "@/shared/components/status-dot";
|
||||
import { getAccountTypeIcon } from "@/shared/utils/icons";
|
||||
|
||||
export function AccountTypeSelectContent({ label }: { label: string }) {
|
||||
const icon = getAccountTypeIcon(label);
|
||||
|
||||
return (
|
||||
<span className="flex items-center gap-2">
|
||||
{icon}
|
||||
<span>{label}</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
export function StatusSelectContent({ label }: { label: string }) {
|
||||
const isActive = label === "Ativa";
|
||||
|
||||
@@ -90,6 +90,7 @@ export function BudgetCard({ budget, onEdit, onRemove }: BudgetCardProps) {
|
||||
<Progress
|
||||
value={usagePercent}
|
||||
className={cn("h-2.5", exceeded && "bg-destructive/20!")}
|
||||
indicatorClassName={cn(exceeded && "bg-destructive")}
|
||||
aria-label={`${usagePercent.toFixed(1)}% do orçamento utilizado`}
|
||||
/>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
|
||||
@@ -69,6 +69,7 @@ export function CardItem({
|
||||
|
||||
const usagePercent =
|
||||
limit > 0 ? Math.min(Math.max((used / limit) * 100, 0), 100) : 0;
|
||||
const exceeded = usagePercent >= 100;
|
||||
|
||||
const logoPath = resolveLogoSrc(logo);
|
||||
const brandAsset = resolveCardBrandAsset(brand);
|
||||
@@ -194,7 +195,8 @@ export function CardItem({
|
||||
<div className="flex flex-col gap-2">
|
||||
<Progress
|
||||
value={usagePercent}
|
||||
className="h-2.5"
|
||||
className={cn("h-2.5", exceeded && "bg-destructive/20!")}
|
||||
indicatorClassName={cn(exceeded && "bg-destructive")}
|
||||
aria-label={`${usagePercent.toFixed(0)}% do limite utilizado`}
|
||||
/>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} 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";
|
||||
|
||||
type BillListItemProps = {
|
||||
|
||||
@@ -13,7 +13,7 @@ const formatOccurrences = (value: number | null) => {
|
||||
return "Recorrência contínua";
|
||||
}
|
||||
|
||||
return `${value} recorrências`;
|
||||
return `${value} recorrências mensais`;
|
||||
};
|
||||
|
||||
export function RecurringExpensesWidget({
|
||||
|
||||
@@ -114,12 +114,14 @@ export async function fetchDashboardPeriodOverview(
|
||||
.select({
|
||||
period: transactions.period,
|
||||
transactionType: transactions.transactionType,
|
||||
totalAmount: 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",
|
||||
),
|
||||
totalAmount:
|
||||
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",
|
||||
),
|
||||
accountExcludeFromBalance: financialAccounts.excludeFromBalance,
|
||||
})
|
||||
.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 { fetchTransactionsWithRelations } from "@/features/transactions/queries";
|
||||
import { buildInvoicePaymentNote } from "@/shared/lib/accounts/constants";
|
||||
import { db } from "@/shared/lib/db";
|
||||
import {
|
||||
@@ -104,14 +105,5 @@ export async function fetchInvoiceData(
|
||||
}
|
||||
|
||||
export async function fetchCardTransactions(filters: SQL[]) {
|
||||
return db.query.transactions.findMany({
|
||||
where: and(...filters),
|
||||
with: {
|
||||
payer: true,
|
||||
financialAccount: true,
|
||||
card: true,
|
||||
category: true,
|
||||
},
|
||||
orderBy: desc(transactions.purchaseDate),
|
||||
});
|
||||
return fetchTransactionsWithRelations({ filters });
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
RiFileList2Line,
|
||||
RiInboxUnarchiveLine,
|
||||
RiPencilLine,
|
||||
RiSubtractLine,
|
||||
} from "@remixicon/react";
|
||||
import {
|
||||
buildNoteDisplayTitle,
|
||||
@@ -101,7 +102,7 @@ export function NoteCard({
|
||||
{task.completed ? (
|
||||
<RiCheckLine className="h-4 w-4 text-success" />
|
||||
) : (
|
||||
<div className="h-4 w-4 rounded-sm border border-input" />
|
||||
<RiSubtractLine className="h-4 w-4 text-muted-foreground" />
|
||||
)}
|
||||
</div>
|
||||
<span
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { RiCheckLine } from "@remixicon/react";
|
||||
import { RiCheckLine, RiSubtractLine } from "@remixicon/react";
|
||||
import {
|
||||
buildNoteDisplayTitle,
|
||||
formatNoteCreatedAtLong,
|
||||
@@ -69,7 +69,7 @@ export function NoteDetailsDialog({
|
||||
{task.completed ? (
|
||||
<RiCheckLine className="h-4 w-4 text-success" />
|
||||
) : (
|
||||
<div className="h-4 w-4 rounded-sm border border-input" />
|
||||
<RiSubtractLine className="h-4 w-4 text-muted-foreground" />
|
||||
)}
|
||||
</div>
|
||||
<span
|
||||
|
||||
@@ -3,10 +3,7 @@
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import { z } from "zod";
|
||||
import { cards, categories, transactions } from "@/db/schema";
|
||||
import {
|
||||
buildRefundNote,
|
||||
isRefundNote,
|
||||
} from "@/shared/lib/accounts/constants";
|
||||
import { buildRefundNote, isRefundNote } from "@/shared/lib/accounts/constants";
|
||||
import { getUser } from "@/shared/lib/auth/server";
|
||||
import { db } from "@/shared/lib/db";
|
||||
import { PERIOD_FORMAT_REGEX } from "@/shared/lib/invoices";
|
||||
|
||||
@@ -93,7 +93,9 @@ export function PaymentMethodSection({
|
||||
? accountOptions.filter(
|
||||
(option) => option.accountType === "Pré-Pago | VR/VA",
|
||||
)
|
||||
: accountOptions;
|
||||
: formState.paymentMethod === "Dinheiro"
|
||||
? accountOptions.filter((option) => option.accountType === "Dinheiro")
|
||||
: accountOptions;
|
||||
|
||||
const hasSecondaryColumn = isCartaoSelected || showContaSelect;
|
||||
|
||||
|
||||
@@ -348,10 +348,12 @@ function buildColumns({
|
||||
cell: ({ row }) => {
|
||||
const isReceita = row.original.transactionType === "Receita";
|
||||
const isTransfer = row.original.transactionType === "Transferência";
|
||||
const isIncomingTransfer =
|
||||
isTransfer && Number(row.original.amount) > 0;
|
||||
return (
|
||||
<MoneyValues
|
||||
amount={row.original.amount}
|
||||
showPositiveSign={isReceita}
|
||||
showPositiveSign={isReceita || isIncomingTransfer}
|
||||
className={cn(
|
||||
"whitespace-nowrap",
|
||||
isReceita ? "text-success" : "text-foreground",
|
||||
|
||||
@@ -7,9 +7,12 @@ import { cn } from "@/shared/utils/ui";
|
||||
|
||||
function Progress({
|
||||
className,
|
||||
indicatorClassName,
|
||||
value,
|
||||
...props
|
||||
}: React.ComponentProps<typeof ProgressPrimitive.Root>) {
|
||||
}: React.ComponentProps<typeof ProgressPrimitive.Root> & {
|
||||
indicatorClassName?: string;
|
||||
}) {
|
||||
return (
|
||||
<ProgressPrimitive.Root
|
||||
data-slot="progress"
|
||||
@@ -21,7 +24,10 @@ function Progress({
|
||||
>
|
||||
<ProgressPrimitive.Indicator
|
||||
data-slot="progress-indicator"
|
||||
className="bg-primary h-full w-full flex-1 transition-all"
|
||||
className={cn(
|
||||
"bg-primary h-full w-full flex-1 transition-all",
|
||||
indicatorClassName,
|
||||
)}
|
||||
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
|
||||
/>
|
||||
</ProgressPrimitive.Root>
|
||||
|
||||
@@ -45,7 +45,8 @@ export const requiredDecimalSchema = (fieldName: string = "valor") =>
|
||||
.transform((value) => value.replace(",", ".")),
|
||||
])
|
||||
.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)) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export const TRANSFER_CATEGORY_NAME = "Transferência interna";
|
||||
export const TRANSFER_ESTABLISHMENT_SAIDA = "Saída - Transf. entre contas";
|
||||
export const TRANSFER_ESTABLISHMENT_ENTRADA = "Entrada - Transf. entre contas";
|
||||
export const TRANSFER_PAYMENT_METHOD = "Pix";
|
||||
export const TRANSFER_PAYMENT_METHOD = "Transferência bancária";
|
||||
export const TRANSFER_CONDITION = "À vista";
|
||||
|
||||
@@ -36,13 +36,37 @@ export const getConditionIcon = (condition: string): ReactNode => {
|
||||
return registry[key] ?? null;
|
||||
};
|
||||
|
||||
export const getAccountTypeIcon = (accountType: string): ReactNode => {
|
||||
const key = normalizeKey(accountType);
|
||||
|
||||
const registry: Record<string, ReactNode> = {
|
||||
contacorrente: <RemixIcons.RiBankLine className={ICON_CLASS} aria-hidden />,
|
||||
contapoupanca: (
|
||||
<RemixIcons.RiSafe2Line className={ICON_CLASS} aria-hidden />
|
||||
),
|
||||
carteiradigital: (
|
||||
<RemixIcons.RiWalletLine className={ICON_CLASS} aria-hidden />
|
||||
),
|
||||
containvestimento: (
|
||||
<RemixIcons.RiFundsLine className={ICON_CLASS} aria-hidden />
|
||||
),
|
||||
prepagovrva: <RemixIcons.RiCouponLine className={ICON_CLASS} aria-hidden />,
|
||||
dinheiro: <RemixIcons.RiCashLine className={ICON_CLASS} aria-hidden />,
|
||||
outros: <RemixIcons.RiMoreFill className={ICON_CLASS} aria-hidden />,
|
||||
};
|
||||
|
||||
return (
|
||||
registry[key] ?? (
|
||||
<RemixIcons.RiBankLine className={ICON_CLASS} aria-hidden />
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export const getPaymentMethodIcon = (paymentMethod: string): ReactNode => {
|
||||
const key = normalizeKey(paymentMethod);
|
||||
|
||||
const registry: Record<string, ReactNode> = {
|
||||
dinheiro: (
|
||||
<RemixIcons.RiMoneyDollarCircleLine className={ICON_CLASS} aria-hidden />
|
||||
),
|
||||
dinheiro: <RemixIcons.RiCashLine className={ICON_CLASS} aria-hidden />,
|
||||
pix: <RemixIcons.RiPixLine className={ICON_CLASS} aria-hidden />,
|
||||
boleto: <RemixIcons.RiBarcodeLine className={ICON_CLASS} aria-hidden />,
|
||||
credito: (
|
||||
|
||||
Reference in New Issue
Block a user