@hed-hog/finance 0.0.322 → 0.0.326

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/dist/dto/create-bank-account.dto.d.ts +1 -0
  2. package/dist/dto/create-bank-account.dto.d.ts.map +1 -1
  3. package/dist/dto/create-bank-account.dto.js +7 -0
  4. package/dist/dto/create-bank-account.dto.js.map +1 -1
  5. package/dist/dto/update-bank-account.dto.d.ts +1 -0
  6. package/dist/dto/update-bank-account.dto.d.ts.map +1 -1
  7. package/dist/dto/update-bank-account.dto.js +7 -0
  8. package/dist/dto/update-bank-account.dto.js.map +1 -1
  9. package/dist/finance-bank-accounts.controller.d.ts +21 -0
  10. package/dist/finance-bank-accounts.controller.d.ts.map +1 -1
  11. package/dist/finance-data.controller.d.ts +13 -0
  12. package/dist/finance-data.controller.d.ts.map +1 -1
  13. package/dist/finance.service.d.ts +37 -2
  14. package/dist/finance.service.d.ts.map +1 -1
  15. package/dist/finance.service.js +125 -19
  16. package/dist/finance.service.js.map +1 -1
  17. package/hedhog/data/integration_event_catalog.yaml +274 -0
  18. package/hedhog/frontend/app/administration/categories/page.tsx.ejs +1 -1
  19. package/hedhog/frontend/app/administration/cost-centers/page.tsx.ejs +1 -1
  20. package/hedhog/frontend/app/administration/currencies/page.tsx.ejs +1 -1
  21. package/hedhog/frontend/app/administration/period-close/page.tsx.ejs +1 -1
  22. package/hedhog/frontend/app/cash-and-banks/bank-accounts/page.tsx.ejs +83 -37
  23. package/hedhog/frontend/widgets/bank-reconciliation-status.tsx.ejs +33 -9
  24. package/hedhog/frontend/widgets/cash-balance-kpi.tsx.ejs +30 -9
  25. package/package.json +7 -7
  26. package/src/dto/create-bank-account.dto.ts +12 -6
  27. package/src/dto/update-bank-account.dto.ts +6 -0
  28. package/src/finance.service.ts +156 -26
@@ -0,0 +1,274 @@
1
+ - slug: finance.payable.created_from_contract
2
+ name: Finance payable created from contract
3
+ module: finance
4
+ aggregate_type: financial_title
5
+ description: Disparado quando um título de contas a pagar é criado a partir de um contrato ativado.
6
+ status: active
7
+ payload_schema:
8
+ correlationId:
9
+ type: string
10
+ description: ID de correlação para rastreamento entre eventos
11
+ contractId:
12
+ type: number
13
+ description: ID do contrato de origem
14
+ proposalId:
15
+ type: number
16
+ nullable: true
17
+ description: ID da proposta de origem (quando aplicável)
18
+ personId:
19
+ type: number
20
+ description: ID da pessoa (fornecedor/credor)
21
+ financialTitle:
22
+ type: object
23
+ description: Dados do título financeiro criado
24
+ installments:
25
+ type: array
26
+ description: Lista de parcelas geradas
27
+ contract:
28
+ type: object
29
+ description: Dados do contrato de origem
30
+ metadata_schema: null
31
+
32
+ - slug: finance.receivable.created_from_contract
33
+ name: Finance receivable created from contract
34
+ module: finance
35
+ aggregate_type: financial_title
36
+ description: Disparado quando um título de contas a receber é criado a partir de um contrato ativado.
37
+ status: active
38
+ payload_schema:
39
+ correlationId:
40
+ type: string
41
+ description: ID de correlação para rastreamento entre eventos
42
+ contractId:
43
+ type: number
44
+ description: ID do contrato de origem
45
+ proposalId:
46
+ type: number
47
+ nullable: true
48
+ description: ID da proposta de origem (quando aplicável)
49
+ personId:
50
+ type: number
51
+ description: ID da pessoa (cliente/devedor)
52
+ financialTitle:
53
+ type: object
54
+ description: Dados do título financeiro criado
55
+ installments:
56
+ type: array
57
+ description: Lista de parcelas geradas
58
+ contract:
59
+ type: object
60
+ description: Dados do contrato de origem
61
+ metadata_schema: null
62
+
63
+ - slug: finance.payable.created
64
+ name: Finance payable created
65
+ module: finance
66
+ aggregate_type: financial_title
67
+ description: Disparado quando um título a pagar é criado manualmente.
68
+ status: active
69
+ payload_schema:
70
+ id:
71
+ type: number
72
+ description: ID do título a pagar criado
73
+ personId:
74
+ type: number
75
+ description: ID da pessoa (fornecedor/credor)
76
+ totalAmount:
77
+ type: number
78
+ description: Valor total do título
79
+ dueDate:
80
+ type: string
81
+ format: date-time
82
+ description: Data de vencimento
83
+ status:
84
+ type: string
85
+ description: Status do título
86
+ metadata_schema: null
87
+
88
+ - slug: finance.payable.updated
89
+ name: Finance payable updated
90
+ module: finance
91
+ aggregate_type: financial_title
92
+ description: Disparado quando um título a pagar é atualizado.
93
+ status: active
94
+ payload_schema:
95
+ id:
96
+ type: number
97
+ description: ID do título atualizado
98
+ status:
99
+ type: string
100
+ nullable: true
101
+ description: Novo status do título
102
+ totalAmount:
103
+ type: number
104
+ nullable: true
105
+ description: Novo valor total
106
+ metadata_schema: null
107
+
108
+ - slug: finance.receivable.created
109
+ name: Finance receivable created
110
+ module: finance
111
+ aggregate_type: financial_title
112
+ description: Disparado quando um título a receber é criado manualmente.
113
+ status: active
114
+ payload_schema:
115
+ id:
116
+ type: number
117
+ description: ID do título a receber criado
118
+ personId:
119
+ type: number
120
+ description: ID da pessoa (cliente/devedor)
121
+ totalAmount:
122
+ type: number
123
+ description: Valor total do título
124
+ dueDate:
125
+ type: string
126
+ format: date-time
127
+ description: Data de vencimento
128
+ status:
129
+ type: string
130
+ description: Status do título
131
+ metadata_schema: null
132
+
133
+ - slug: finance.receivable.updated
134
+ name: Finance receivable updated
135
+ module: finance
136
+ aggregate_type: financial_title
137
+ description: Disparado quando um título a receber é atualizado.
138
+ status: active
139
+ payload_schema:
140
+ id:
141
+ type: number
142
+ description: ID do título atualizado
143
+ status:
144
+ type: string
145
+ nullable: true
146
+ description: Novo status do título
147
+ totalAmount:
148
+ type: number
149
+ nullable: true
150
+ description: Novo valor total
151
+ metadata_schema: null
152
+
153
+ - slug: finance.bank_account.created
154
+ name: Finance bank account created
155
+ module: finance
156
+ aggregate_type: bank_account
157
+ description: Disparado quando uma conta bancária é criada.
158
+ status: active
159
+ payload_schema:
160
+ id:
161
+ type: number
162
+ description: ID da conta bancária criada
163
+ name:
164
+ type: string
165
+ description: Nome da conta bancária
166
+ bankCode:
167
+ type: string
168
+ nullable: true
169
+ description: Código do banco
170
+ accountNumber:
171
+ type: string
172
+ nullable: true
173
+ description: Número da conta
174
+ metadata_schema: null
175
+
176
+ - slug: finance.bank_account.updated
177
+ name: Finance bank account updated
178
+ module: finance
179
+ aggregate_type: bank_account
180
+ description: Disparado quando uma conta bancária é atualizada.
181
+ status: active
182
+ payload_schema:
183
+ id:
184
+ type: number
185
+ description: ID da conta bancária atualizada
186
+ name:
187
+ type: string
188
+ nullable: true
189
+ description: Novo nome da conta
190
+ metadata_schema: null
191
+
192
+ - slug: finance.bank_account.deleted
193
+ name: Finance bank account deleted
194
+ module: finance
195
+ aggregate_type: bank_account
196
+ description: Disparado quando uma conta bancária é excluída.
197
+ status: active
198
+ payload_schema:
199
+ id:
200
+ type: number
201
+ description: ID da conta bancária excluída
202
+ metadata_schema: null
203
+
204
+ - slug: finance.cost_center.created
205
+ name: Finance cost center created
206
+ module: finance
207
+ aggregate_type: cost_center
208
+ description: Disparado quando um centro de custo é criado.
209
+ status: active
210
+ payload_schema:
211
+ id:
212
+ type: number
213
+ description: ID do centro de custo criado
214
+ name:
215
+ type: string
216
+ description: Nome do centro de custo
217
+ code:
218
+ type: string
219
+ nullable: true
220
+ description: Código do centro de custo
221
+ metadata_schema: null
222
+
223
+ - slug: finance.cost_center.updated
224
+ name: Finance cost center updated
225
+ module: finance
226
+ aggregate_type: cost_center
227
+ description: Disparado quando um centro de custo é atualizado.
228
+ status: active
229
+ payload_schema:
230
+ id:
231
+ type: number
232
+ description: ID do centro de custo atualizado
233
+ name:
234
+ type: string
235
+ nullable: true
236
+ description: Novo nome do centro de custo
237
+ metadata_schema: null
238
+
239
+ - slug: finance.cost_center.deleted
240
+ name: Finance cost center deleted
241
+ module: finance
242
+ aggregate_type: cost_center
243
+ description: Disparado quando um centro de custo é excluído.
244
+ status: active
245
+ payload_schema:
246
+ id:
247
+ type: number
248
+ description: ID do centro de custo excluído
249
+ metadata_schema: null
250
+
251
+ - slug: finance.transfer.created
252
+ name: Finance transfer created
253
+ module: finance
254
+ aggregate_type: transfer
255
+ description: Disparado quando uma transferência entre contas é registrada.
256
+ status: active
257
+ payload_schema:
258
+ id:
259
+ type: number
260
+ description: ID da transferência criada
261
+ fromAccountId:
262
+ type: number
263
+ description: ID da conta de origem
264
+ toAccountId:
265
+ type: number
266
+ description: ID da conta de destino
267
+ amount:
268
+ type: number
269
+ description: Valor transferido
270
+ transferDate:
271
+ type: string
272
+ format: date-time
273
+ description: Data da transferência
274
+ metadata_schema: null
@@ -300,7 +300,7 @@ function CategoriaSheet({
300
300
 
301
301
  return (
302
302
  <Sheet open={open} onOpenChange={handleOpenChange}>
303
- <SheetContent className="w-full sm:max-w-lg">
303
+ <SheetContent className="w-full overflow-y-auto sm:max-w-lg">
304
304
  <SheetHeader>
305
305
  <SheetTitle>
306
306
  {editing ? t('sheet.editTitle') : t('sheet.newTitle')}
@@ -216,7 +216,7 @@ function CentroCustoSheet({
216
216
 
217
217
  return (
218
218
  <Sheet open={open} onOpenChange={handleOpenChange}>
219
- <SheetContent className="w-full sm:max-w-lg">
219
+ <SheetContent className="w-full overflow-y-auto sm:max-w-lg">
220
220
  <SheetHeader>
221
221
  <SheetTitle>
222
222
  {editingCostCenter ? t('sheet.editTitle') : t('sheet.newTitle')}
@@ -225,7 +225,7 @@ function CurrencySheet({
225
225
 
226
226
  return (
227
227
  <Sheet open={open} onOpenChange={handleOpenChange}>
228
- <SheetContent className="w-full sm:max-w-lg">
228
+ <SheetContent className="w-full overflow-y-auto sm:max-w-lg">
229
229
  <SheetHeader>
230
230
  <SheetTitle>
231
231
  {editingCurrency ? t('sheet.editTitle') : t('sheet.newTitle')}
@@ -212,7 +212,7 @@ function ClosePeriodSheet({
212
212
  onOpenChange(nextOpen);
213
213
  }}
214
214
  >
215
- <SheetContent className="w-full sm:max-w-lg">
215
+ <SheetContent className="w-full overflow-y-auto sm:max-w-lg">
216
216
  <SheetHeader>
217
217
  <SheetTitle>{t('sheet.title')}</SheetTitle>
218
218
  <SheetDescription>{t('sheet.description')}</SheetDescription>
@@ -37,7 +37,6 @@ import {
37
37
  import { Input } from '@/components/ui/input';
38
38
  import { InputMoney } from '@/components/ui/input-money';
39
39
  import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
40
- import { Money } from '@/components/ui/money';
41
40
  import {
42
41
  Select,
43
42
  SelectContent,
@@ -105,6 +104,13 @@ type Currency = {
105
104
  ativo: boolean;
106
105
  };
107
106
 
107
+ type BankAccountCurrency = {
108
+ id: string;
109
+ code: string;
110
+ symbol: string;
111
+ name: string;
112
+ };
113
+
108
114
  type BankAccount = {
109
115
  id: string;
110
116
  codigo: string;
@@ -115,7 +121,7 @@ type BankAccount = {
115
121
  tipo: 'corrente' | 'poupanca' | 'investimento' | 'caixa';
116
122
  logoFileId: number | null;
117
123
  currencyId: number | null;
118
- currency: Currency | null;
124
+ currency: BankAccountCurrency | null;
119
125
  saldoAtual: number;
120
126
  saldoConciliado: number;
121
127
  ativo: boolean;
@@ -147,6 +153,14 @@ type BankAccountDraftPayload = {
147
153
 
148
154
  const BANK_ACCOUNT_FORM_DRAFT_STORAGE_KEY = 'finance-bank-account-form-draft';
149
155
 
156
+ function formatCurrency(value: number, currencyCode: string, locale: string) {
157
+ const localeTag = locale.startsWith('pt') ? 'pt-BR' : 'en-US';
158
+ return new Intl.NumberFormat(localeTag, {
159
+ style: 'currency',
160
+ currency: currencyCode,
161
+ }).format(value);
162
+ }
163
+
150
164
  function BankAccountLogo({
151
165
  account,
152
166
  icon: Icon,
@@ -1049,40 +1063,52 @@ export default function ContasBancariasPage() {
1049
1063
  caixa: { label: t('types.caixa'), icon: Wallet },
1050
1064
  };
1051
1065
 
1052
- const saldoTotal = accounts
1053
- .filter((c) => c.ativo)
1054
- .reduce((acc, c) => acc + c.saldoAtual, 0);
1055
-
1056
- const saldoConciliadoTotal = accounts
1057
- .filter((c) => c.ativo)
1058
- .reduce((acc, c) => acc + c.saldoConciliado, 0);
1059
1066
  const activeAccountsCount = accounts.filter((c) => c.ativo).length;
1060
1067
  const inactiveAccountsCount = accounts.length - activeAccountsCount;
1061
- const summaryCards = [
1062
- {
1063
- key: 'balance',
1064
- title: t('cards.totalBalance'),
1065
- value: <Money value={saldoTotal} />,
1066
- description: t('cards.activeAccounts', {
1067
- count: activeAccountsCount,
1068
- }),
1069
- icon: Landmark,
1070
- layout: 'compact' as const,
1071
- },
1072
- {
1073
- key: 'reconciled',
1074
- title: t('cards.reconciledBalance'),
1075
- value: <Money value={saldoConciliadoTotal} />,
1076
- description: `${t('cards.difference')}: ${new Intl.NumberFormat(
1077
- currentLocaleCode === 'pt' ? 'pt-BR' : 'en-US',
1068
+
1069
+ // Group active account balances by currency (accounts without currency default to BRL)
1070
+ const balanceByCurrency = accounts
1071
+ .filter((c) => c.ativo)
1072
+ .reduce<
1073
+ Record<
1074
+ string,
1078
1075
  {
1079
- style: 'currency',
1080
- currency: 'BRL',
1076
+ total: number;
1077
+ reconciled: number;
1078
+ symbol: string;
1079
+ code: string;
1080
+ name: string;
1081
+ count: number;
1081
1082
  }
1082
- ).format(saldoTotal - saldoConciliadoTotal)}`,
1083
- icon: RefreshCw,
1083
+ >
1084
+ >((acc, c) => {
1085
+ const code = c.currency?.code ?? 'BRL';
1086
+ const symbol = c.currency?.symbol ?? 'R$';
1087
+ const name = c.currency?.name ?? 'Real Brasileiro';
1088
+ if (!acc[code]) {
1089
+ acc[code] = { total: 0, reconciled: 0, symbol, code, name, count: 0 };
1090
+ }
1091
+ acc[code].total += c.saldoAtual;
1092
+ acc[code].reconciled += c.saldoConciliado;
1093
+ acc[code].count += 1;
1094
+ return acc;
1095
+ }, {});
1096
+
1097
+ const currencyGroups = Object.values(balanceByCurrency);
1098
+
1099
+ const summaryCards = [
1100
+ ...currencyGroups.map((g) => ({
1101
+ key: `balance-${g.code}`,
1102
+ title: `${t('cards.totalBalance')} (${g.code})`,
1103
+ value: (
1104
+ <span className="tabular-nums">
1105
+ {formatCurrency(g.total, g.code, currentLocaleCode)}
1106
+ </span>
1107
+ ),
1108
+ description: `${t('cards.reconciledBalance')}: ${formatCurrency(g.reconciled, g.code, currentLocaleCode)}`,
1109
+ icon: Landmark,
1084
1110
  layout: 'compact' as const,
1085
- },
1111
+ })),
1086
1112
  {
1087
1113
  key: 'accounts',
1088
1114
  title: t('cards.accountsOverview'),
@@ -1175,7 +1201,10 @@ export default function ContasBancariasPage() {
1175
1201
  </AlertDialogContent>
1176
1202
  </AlertDialog>
1177
1203
 
1178
- <KpiCardsGrid items={summaryCards} columns={3} />
1204
+ <KpiCardsGrid
1205
+ items={summaryCards}
1206
+ columns={Math.min(summaryCards.length, 4) as 2 | 3 | 4}
1207
+ />
1179
1208
 
1180
1209
  <FinancePageSection variant="flat" contentClassName="p-0">
1181
1210
  {accounts.length > 0 ? (
@@ -1236,15 +1265,25 @@ export default function ContasBancariasPage() {
1236
1265
  <p className="text-sm text-muted-foreground">
1237
1266
  {t('accountCard.currentBalance')}
1238
1267
  </p>
1239
- <p className="text-2xl font-bold">
1240
- <Money value={conta.saldoAtual} />
1268
+ <p className="text-2xl font-bold tabular-nums">
1269
+ {formatCurrency(
1270
+ conta.saldoAtual,
1271
+ conta.currency?.code ?? 'BRL',
1272
+ currentLocaleCode
1273
+ )}
1241
1274
  </p>
1242
1275
  </div>
1243
1276
  <div className="flex items-center justify-between text-sm">
1244
1277
  <span className="text-muted-foreground">
1245
1278
  {t('accountCard.reconciledBalance')}
1246
1279
  </span>
1247
- <Money value={conta.saldoConciliado} />
1280
+ <span className="tabular-nums">
1281
+ {formatCurrency(
1282
+ conta.saldoConciliado,
1283
+ conta.currency?.code ?? 'BRL',
1284
+ currentLocaleCode
1285
+ )}
1286
+ </span>
1248
1287
  </div>
1249
1288
  {diferenca !== 0 ? (
1250
1289
  <div className="flex items-center justify-between text-sm">
@@ -1253,10 +1292,17 @@ export default function ContasBancariasPage() {
1253
1292
  </span>
1254
1293
  <span
1255
1294
  className={
1256
- diferenca > 0 ? 'text-green-600' : 'text-red-600'
1295
+ diferenca > 0
1296
+ ? 'tabular-nums text-green-600'
1297
+ : 'tabular-nums text-red-600'
1257
1298
  }
1258
1299
  >
1259
- <Money value={diferenca} showSign />
1300
+ {diferenca > 0 ? '+' : '-'}
1301
+ {formatCurrency(
1302
+ Math.abs(diferenca),
1303
+ conta.currency?.code ?? 'BRL',
1304
+ currentLocaleCode
1305
+ )}
1260
1306
  </span>
1261
1307
  </div>
1262
1308
  ) : null}
@@ -30,6 +30,7 @@ interface FinanceData {
30
30
  saldoAtual?: number | null;
31
31
  saldoConciliado?: number | null;
32
32
  ativo?: boolean | null;
33
+ currency?: { code: string; symbol: string } | null;
33
34
  }>;
34
35
  }
35
36
 
@@ -68,13 +69,22 @@ export default function BankReconciliationStatus({
68
69
  difference: Math.abs(
69
70
  Number(account.saldoAtual || 0) - Number(account.saldoConciliado || 0)
70
71
  ),
72
+ currencyCode: account.currency?.code ?? 'BRL',
73
+ currencySymbol: account.currency?.symbol ?? 'R$',
71
74
  }))
72
75
  .sort((a, b) => b.difference - a.difference);
73
76
 
74
- const totalDifference = accountDiffs.reduce(
75
- (acc, account) => acc + account.difference,
76
- 0
77
- );
77
+ // Group differences by currency — never mix different currencies in a single total
78
+ const differencesByCurrency = accountDiffs.reduce<
79
+ Record<string, { total: number; symbol: string }>
80
+ >((acc, account) => {
81
+ const code = account.currencyCode;
82
+ if (!acc[code]) {
83
+ acc[code] = { total: 0, symbol: account.currencySymbol };
84
+ }
85
+ acc[code].total += account.difference;
86
+ return acc;
87
+ }, {});
78
88
 
79
89
  return (
80
90
  <WidgetWrapper
@@ -109,9 +119,20 @@ export default function BankReconciliationStatus({
109
119
  <p className="text-[11px] font-medium uppercase tracking-[0.18em] text-muted-foreground">
110
120
  {t('bankReconciliation.difference')}
111
121
  </p>
112
- <p className="text-lg font-semibold text-foreground">
113
- <Money value={totalDifference} />
114
- </p>
122
+ {Object.entries(differencesByCurrency).length > 0 ? (
123
+ Object.entries(differencesByCurrency).map(([code, entry]) => (
124
+ <p key={code} className="text-lg font-semibold text-foreground tabular-nums">
125
+ {new Intl.NumberFormat('pt-BR', {
126
+ style: 'currency',
127
+ currency: code,
128
+ }).format(entry.total)}
129
+ </p>
130
+ ))
131
+ ) : (
132
+ <p className="text-lg font-semibold text-foreground tabular-nums">
133
+ <Money value={0} />
134
+ </p>
135
+ )}
115
136
  </div>
116
137
 
117
138
  <div className="space-y-2">
@@ -123,8 +144,11 @@ export default function BankReconciliationStatus({
123
144
  <span className="truncate pr-3 text-sm text-foreground">
124
145
  {account.name}
125
146
  </span>
126
- <span className="text-sm font-medium text-muted-foreground">
127
- <Money value={account.difference} />
147
+ <span className="text-sm font-medium text-muted-foreground tabular-nums">
148
+ {new Intl.NumberFormat('pt-BR', {
149
+ style: 'currency',
150
+ currency: account.currencyCode,
151
+ }).format(account.difference)}
128
152
  </span>
129
153
  </div>
130
154
  ))}
@@ -14,6 +14,10 @@ interface CashBalanceKpiProps {
14
14
  interface FinanceData {
15
15
  kpis?: {
16
16
  saldoCaixa: number;
17
+ saldoCaixaPorMoeda?: Record<
18
+ string,
19
+ { total: number; reconciled: number; symbol: string; name: string }
20
+ >;
17
21
  };
18
22
  }
19
23
 
@@ -29,11 +33,11 @@ export default function CashBalanceKpi({
29
33
  queryKey: 'finance-kpi-cash-balance',
30
34
  });
31
35
 
32
- const value = data?.kpis?.saldoCaixa ?? 0;
33
- const formatted = new Intl.NumberFormat('pt-BR', {
34
- style: 'currency',
35
- currency: 'BRL',
36
- }).format(value);
36
+ const saldoCaixaPorMoeda = data?.kpis?.saldoCaixaPorMoeda ?? {};
37
+ const currencyEntries = Object.entries(saldoCaixaPorMoeda);
38
+ // Fallback to the legacy single-value when the new field is absent
39
+ const legacyValue = data?.kpis?.saldoCaixa ?? 0;
40
+ const hasCurrencyBreakdown = currencyEntries.length > 0;
37
41
 
38
42
  return (
39
43
  <WidgetWrapper
@@ -48,13 +52,30 @@ export default function CashBalanceKpi({
48
52
  <div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-emerald-100/80">
49
53
  <Wallet className="h-4.5 w-4.5 text-emerald-600" />
50
54
  </div>
51
- <div className="flex min-w-0 flex-1 flex-col justify-center">
55
+ <div className="flex min-w-0 flex-1 flex-col justify-center gap-0.5">
52
56
  <span className="text-[9px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">
53
57
  {t('kpis.cashBalance.title')}
54
58
  </span>
55
- <span className="truncate text-base font-bold leading-none tracking-tight text-foreground sm:text-lg">
56
- {formatted}
57
- </span>
59
+ {hasCurrencyBreakdown ? (
60
+ currencyEntries.map(([code, entry]) => (
61
+ <span
62
+ key={code}
63
+ className="truncate text-base font-bold leading-none tracking-tight text-foreground sm:text-lg"
64
+ >
65
+ {new Intl.NumberFormat('pt-BR', {
66
+ style: 'currency',
67
+ currency: code,
68
+ }).format(entry.total)}
69
+ </span>
70
+ ))
71
+ ) : (
72
+ <span className="truncate text-base font-bold leading-none tracking-tight text-foreground sm:text-lg">
73
+ {new Intl.NumberFormat('pt-BR', {
74
+ style: 'currency',
75
+ currency: 'BRL',
76
+ }).format(legacyValue)}
77
+ </span>
78
+ )}
58
79
  <span className="truncate text-[9px] text-muted-foreground">
59
80
  {t('kpis.cashBalance.description')}
60
81
  </span>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hed-hog/finance",
3
- "version": "0.0.322",
3
+ "version": "0.0.326",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "dependencies": {
@@ -9,14 +9,14 @@
9
9
  "@nestjs/core": "^11",
10
10
  "@nestjs/jwt": "^11",
11
11
  "@nestjs/mapped-types": "*",
12
- "@hed-hog/api": "0.0.8",
12
+ "@hed-hog/api-prisma": "0.0.6",
13
13
  "@hed-hog/api-locale": "0.0.14",
14
+ "@hed-hog/contact": "0.0.326",
15
+ "@hed-hog/tag": "0.0.326",
16
+ "@hed-hog/api": "0.0.8",
14
17
  "@hed-hog/api-pagination": "0.0.7",
15
- "@hed-hog/core": "0.0.322",
16
- "@hed-hog/api-types": "0.0.1",
17
- "@hed-hog/contact": "0.0.322",
18
- "@hed-hog/api-prisma": "0.0.6",
19
- "@hed-hog/tag": "0.0.322"
18
+ "@hed-hog/core": "0.0.326",
19
+ "@hed-hog/api-types": "0.0.1"
20
20
  },
21
21
  "exports": {
22
22
  ".": {