@hed-hog/finance 0.0.300 → 0.0.302

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 (41) hide show
  1. package/dist/finance.contract-activated.subscriber.d.ts +24 -0
  2. package/dist/finance.contract-activated.subscriber.d.ts.map +1 -0
  3. package/dist/finance.contract-activated.subscriber.js +519 -0
  4. package/dist/finance.contract-activated.subscriber.js.map +1 -0
  5. package/dist/finance.contract-activated.subscriber.spec.d.ts +2 -0
  6. package/dist/finance.contract-activated.subscriber.spec.d.ts.map +1 -0
  7. package/dist/finance.contract-activated.subscriber.spec.js +302 -0
  8. package/dist/finance.contract-activated.subscriber.spec.js.map +1 -0
  9. package/dist/finance.module.d.ts.map +1 -1
  10. package/dist/finance.module.js +6 -1
  11. package/dist/finance.module.js.map +1 -1
  12. package/hedhog/data/menu.yaml +0 -17
  13. package/hedhog/frontend/app/_components/finance-layout.tsx.ejs +108 -0
  14. package/hedhog/frontend/app/accounts-payable/approvals/page.tsx.ejs +51 -69
  15. package/hedhog/frontend/app/accounts-payable/installments/page.tsx.ejs +1312 -1138
  16. package/hedhog/frontend/app/accounts-receivable/collections-default/page.tsx.ejs +288 -268
  17. package/hedhog/frontend/app/accounts-receivable/installments/page.tsx.ejs +1175 -1016
  18. package/hedhog/frontend/app/administration/audit-logs/page.tsx.ejs +157 -173
  19. package/hedhog/frontend/app/administration/categories/page.tsx.ejs +44 -62
  20. package/hedhog/frontend/app/administration/cost-centers/page.tsx.ejs +62 -80
  21. package/hedhog/frontend/app/administration/period-close/page.tsx.ejs +151 -170
  22. package/hedhog/frontend/app/cash-and-banks/bank-accounts/page.tsx.ejs +369 -322
  23. package/hedhog/frontend/app/cash-and-banks/bank-reconciliation/page.tsx.ejs +204 -226
  24. package/hedhog/frontend/app/cash-and-banks/statements/page.tsx.ejs +122 -140
  25. package/hedhog/frontend/app/cash-and-banks/transfers/page.tsx.ejs +31 -49
  26. package/hedhog/frontend/app/page.tsx.ejs +3 -370
  27. package/hedhog/frontend/app/planning/cash-flow-forecast/page.tsx.ejs +150 -182
  28. package/hedhog/frontend/app/planning/receivables-calendar/page.tsx.ejs +52 -70
  29. package/hedhog/frontend/app/planning/scenarios/page.tsx.ejs +101 -95
  30. package/hedhog/frontend/app/reports/actual-vs-forecast/page.tsx.ejs +100 -125
  31. package/hedhog/frontend/app/reports/aging-default/page.tsx.ejs +77 -105
  32. package/hedhog/frontend/app/reports/cash-position/page.tsx.ejs +99 -134
  33. package/hedhog/frontend/app/reports/overview-results/page.tsx.ejs +147 -182
  34. package/hedhog/frontend/app/reports/top-customers/page.tsx.ejs +49 -61
  35. package/hedhog/frontend/app/reports/top-operational-expenses/page.tsx.ejs +49 -67
  36. package/hedhog/frontend/messages/en.json +176 -68
  37. package/hedhog/frontend/messages/pt.json +176 -68
  38. package/package.json +6 -5
  39. package/src/finance.contract-activated.subscriber.spec.ts +392 -0
  40. package/src/finance.contract-activated.subscriber.ts +780 -0
  41. package/src/finance.module.ts +6 -1
@@ -1,14 +1,10 @@
1
1
  'use client';
2
2
 
3
+ import { FinancePageSection } from '@/app/(app)/(libraries)/finance/_components/finance-layout';
3
4
  import { Page, PageHeader } from '@/components/entity-list';
4
5
  import { Button } from '@/components/ui/button';
5
- import {
6
- Card,
7
- CardContent,
8
- CardDescription,
9
- CardHeader,
10
- CardTitle,
11
- } from '@/components/ui/card';
6
+ import { Card, CardContent } from '@/components/ui/card';
7
+ import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
12
8
  import { Money } from '@/components/ui/money';
13
9
  import {
14
10
  Select,
@@ -73,6 +69,42 @@ export default function FluxoCaixaPage() {
73
69
  const totalEntradas = entradasPrevistas.reduce((acc, e) => acc + e.valor, 0);
74
70
  const totalSaidas = saidasPrevistas.reduce((acc, s) => acc + s.valor, 0);
75
71
  const saldoFinal = kpis.saldoCaixa + totalEntradas - totalSaidas;
72
+ const summaryCards = [
73
+ {
74
+ key: 'currentBalance',
75
+ title: t('cards.currentBalance'),
76
+ value: <Money value={kpis.saldoCaixa} />,
77
+ icon: Wallet,
78
+ layout: 'compact' as const,
79
+ },
80
+ {
81
+ key: 'expectedInflows',
82
+ title: t('cards.expectedInflows'),
83
+ value: <Money value={totalEntradas} />,
84
+ icon: TrendingUp,
85
+ layout: 'compact' as const,
86
+ valueClassName: 'text-green-600',
87
+ iconContainerClassName: 'bg-green-500/10 text-green-700',
88
+ accentClassName: 'from-green-500/20 via-emerald-500/10 to-transparent',
89
+ },
90
+ {
91
+ key: 'expectedOutflows',
92
+ title: t('cards.expectedOutflows'),
93
+ value: <Money value={totalSaidas} />,
94
+ icon: TrendingDown,
95
+ layout: 'compact' as const,
96
+ valueClassName: 'text-red-600',
97
+ iconContainerClassName: 'bg-red-500/10 text-red-700',
98
+ accentClassName: 'from-red-500/20 via-rose-500/10 to-transparent',
99
+ },
100
+ {
101
+ key: 'projectedBalance',
102
+ title: t('cards.projectedBalance'),
103
+ value: <Money value={saldoFinal} />,
104
+ layout: 'compact' as const,
105
+ valueClassName: saldoFinal >= 0 ? 'text-green-600' : 'text-red-600',
106
+ },
107
+ ];
76
108
 
77
109
  return (
78
110
  <Page>
@@ -98,7 +130,7 @@ export default function FluxoCaixaPage() {
98
130
  onValueChange={setHorizonte}
99
131
  disabled={isFetching}
100
132
  >
101
- <SelectTrigger className="w-[180px]">
133
+ <SelectTrigger className="w-45">
102
134
  <SelectValue placeholder={t('filters.horizon')} />
103
135
  </SelectTrigger>
104
136
  <SelectContent>
@@ -116,7 +148,7 @@ export default function FluxoCaixaPage() {
116
148
  }
117
149
  disabled={isFetching}
118
150
  >
119
- <SelectTrigger className="w-[180px]">
151
+ <SelectTrigger className="w-45">
120
152
  <SelectValue placeholder={t('filters.scenario')} />
121
153
  </SelectTrigger>
122
154
  <SelectContent>
@@ -137,106 +169,50 @@ export default function FluxoCaixaPage() {
137
169
  ) : null}
138
170
  </div>
139
171
 
140
- <div className="grid gap-4 md:grid-cols-4">
141
- <Card>
142
- <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
143
- <CardTitle className="text-sm font-medium">
144
- {t('cards.currentBalance')}
145
- </CardTitle>
146
- <Wallet className="h-4 w-4 text-muted-foreground" />
147
- </CardHeader>
148
- <CardContent>
149
- <div className="text-2xl font-bold">
150
- <Money value={kpis.saldoCaixa} />
151
- </div>
152
- </CardContent>
153
- </Card>
154
- <Card>
155
- <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
156
- <CardTitle className="text-sm font-medium">
157
- {t('cards.expectedInflows')}
158
- </CardTitle>
159
- <TrendingUp className="h-4 w-4 text-green-500" />
160
- </CardHeader>
161
- <CardContent>
162
- <div className="text-2xl font-bold text-green-600">
163
- <Money value={totalEntradas} />
164
- </div>
165
- </CardContent>
166
- </Card>
167
- <Card>
168
- <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
169
- <CardTitle className="text-sm font-medium">
170
- {t('cards.expectedOutflows')}
171
- </CardTitle>
172
- <TrendingDown className="h-4 w-4 text-red-500" />
173
- </CardHeader>
174
- <CardContent>
175
- <div className="text-2xl font-bold text-red-600">
176
- <Money value={totalSaidas} />
177
- </div>
178
- </CardContent>
179
- </Card>
180
- <Card>
181
- <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
182
- <CardTitle className="text-sm font-medium">
183
- {t('cards.projectedBalance')}
184
- </CardTitle>
185
- </CardHeader>
186
- <CardContent>
187
- <div
188
- className={`text-2xl font-bold ${saldoFinal >= 0 ? 'text-green-600' : 'text-red-600'}`}
189
- >
190
- <Money value={saldoFinal} />
191
- </div>
192
- </CardContent>
193
- </Card>
194
- </div>
172
+ <KpiCardsGrid items={summaryCards} columns={4} />
195
173
 
196
- <Card>
197
- <CardHeader>
198
- <CardTitle>{t('projection.title')}</CardTitle>
199
- <CardDescription>{t('projection.description')}</CardDescription>
200
- </CardHeader>
201
- <CardContent>
202
- <ResponsiveContainer width="100%" height={350}>
203
- <AreaChart data={chartData}>
204
- <CartesianGrid strokeDasharray="3 3" className="stroke-muted" />
205
- <XAxis dataKey="data" tick={{ fontSize: 12 }} />
206
- <YAxis
207
- tick={{ fontSize: 12 }}
208
- tickFormatter={(value) => `${(value / 1000).toFixed(0)}k`}
209
- />
210
- <Tooltip
211
- formatter={(value: number) => formatarMoeda(value)}
212
- contentStyle={{
213
- backgroundColor: 'hsl(var(--background))',
214
- border: '1px solid hsl(var(--border))',
215
- borderRadius: '8px',
216
- }}
217
- />
218
- <Legend />
219
- <Area
220
- type="monotone"
221
- dataKey="saldoPrevisto"
222
- name={t('projection.predictedBalance')}
223
- stroke="hsl(var(--primary))"
224
- fill="hsl(var(--primary))"
225
- fillOpacity={0.2}
226
- />
227
- <Area
228
- type="monotone"
229
- dataKey="saldoRealizado"
230
- name={t('projection.actualBalance')}
231
- stroke="hsl(var(--chart-2))"
232
- fill="hsl(var(--chart-2))"
233
- fillOpacity={0.2}
234
- connectNulls
235
- />
236
- </AreaChart>
237
- </ResponsiveContainer>
238
- </CardContent>
239
- </Card>
174
+ <FinancePageSection
175
+ title={t('projection.title')}
176
+ description={t('projection.description')}
177
+ contentClassName="p-4 sm:p-5"
178
+ >
179
+ <ResponsiveContainer width="100%" height={350}>
180
+ <AreaChart data={chartData}>
181
+ <CartesianGrid strokeDasharray="3 3" className="stroke-muted" />
182
+ <XAxis dataKey="data" tick={{ fontSize: 12 }} />
183
+ <YAxis
184
+ tick={{ fontSize: 12 }}
185
+ tickFormatter={(value) => `${(value / 1000).toFixed(0)}k`}
186
+ />
187
+ <Tooltip
188
+ formatter={(value: number) => formatarMoeda(value)}
189
+ contentStyle={{
190
+ backgroundColor: 'hsl(var(--background))',
191
+ border: '1px solid hsl(var(--border))',
192
+ borderRadius: '8px',
193
+ }}
194
+ />
195
+ <Legend />
196
+ <Area
197
+ type="monotone"
198
+ dataKey="saldoPrevisto"
199
+ name={t('projection.predictedBalance')}
200
+ stroke="hsl(var(--primary))"
201
+ fill="hsl(var(--primary))"
202
+ fillOpacity={0.2}
203
+ />
204
+ <Area
205
+ type="monotone"
206
+ dataKey="saldoRealizado"
207
+ name={t('projection.actualBalance')}
208
+ stroke="hsl(var(--chart-2))"
209
+ fill="hsl(var(--chart-2))"
210
+ fillOpacity={0.2}
211
+ connectNulls
212
+ />
213
+ </AreaChart>
214
+ </ResponsiveContainer>
215
+ </FinancePageSection>
240
216
 
241
217
  <Tabs defaultValue="entradas">
242
218
  <TabsList>
@@ -246,82 +222,74 @@ export default function FluxoCaixaPage() {
246
222
  <TabsTrigger value="saidas">{t('tabs.expectedOutflows')}</TabsTrigger>
247
223
  </TabsList>
248
224
 
249
- <TabsContent value="entradas" className="mt-4">
250
- <Card>
251
- <CardContent className="pt-6">
252
- <Table>
253
- <TableHeader>
254
- <TableRow>
255
- <TableHead>{t('table.headers.category')}</TableHead>
256
- <TableHead>{t('table.headers.dueDate')}</TableHead>
257
- <TableHead className="text-right">
258
- {t('table.headers.value')}
259
- </TableHead>
260
- </TableRow>
261
- </TableHeader>
262
- <TableBody>
263
- {entradasPrevistas.map((entrada, i) => (
264
- <TableRow key={i}>
265
- <TableCell className="font-medium">
266
- {entrada.categoria}
267
- </TableCell>
268
- <TableCell>{formatarData(entrada.vencimento)}</TableCell>
269
- <TableCell className="text-right text-green-600 font-semibold">
270
- <Money value={entrada.valor} />
271
- </TableCell>
272
- </TableRow>
273
- ))}
274
- <TableRow className="bg-muted/50">
275
- <TableCell className="font-bold" colSpan={2}>
276
- {t('table.total')}
277
- </TableCell>
278
- <TableCell className="text-right font-bold text-green-600">
279
- <Money value={totalEntradas} />
280
- </TableCell>
281
- </TableRow>
282
- </TableBody>
283
- </Table>
284
- </CardContent>
285
- </Card>
225
+ <TabsContent value="entradas">
226
+ <Table>
227
+ <TableHeader>
228
+ <TableRow>
229
+ <TableHead>{t('table.headers.category')}</TableHead>
230
+ <TableHead>{t('table.headers.dueDate')}</TableHead>
231
+ <TableHead className="text-right">
232
+ {t('table.headers.value')}
233
+ </TableHead>
234
+ </TableRow>
235
+ </TableHeader>
236
+ <TableBody>
237
+ {entradasPrevistas.map((entrada, i) => (
238
+ <TableRow key={i}>
239
+ <TableCell className="font-medium">
240
+ {entrada.categoria}
241
+ </TableCell>
242
+ <TableCell>{formatarData(entrada.vencimento)}</TableCell>
243
+ <TableCell className="text-right text-green-600 font-semibold">
244
+ <Money value={entrada.valor} />
245
+ </TableCell>
246
+ </TableRow>
247
+ ))}
248
+ <TableRow className="bg-muted/50">
249
+ <TableCell className="font-bold" colSpan={2}>
250
+ {t('table.total')}
251
+ </TableCell>
252
+ <TableCell className="text-right font-bold text-green-600">
253
+ <Money value={totalEntradas} />
254
+ </TableCell>
255
+ </TableRow>
256
+ </TableBody>
257
+ </Table>
286
258
  </TabsContent>
287
259
 
288
- <TabsContent value="saidas" className="mt-4">
289
- <Card>
290
- <CardContent className="pt-6">
291
- <Table>
292
- <TableHeader>
293
- <TableRow>
294
- <TableHead>{t('table.headers.category')}</TableHead>
295
- <TableHead>{t('table.headers.dueDate')}</TableHead>
296
- <TableHead className="text-right">
297
- {t('table.headers.value')}
298
- </TableHead>
299
- </TableRow>
300
- </TableHeader>
301
- <TableBody>
302
- {saidasPrevistas.map((saida, i) => (
303
- <TableRow key={i}>
304
- <TableCell className="font-medium">
305
- {saida.categoria}
306
- </TableCell>
307
- <TableCell>{formatarData(saida.vencimento)}</TableCell>
308
- <TableCell className="text-right text-red-600 font-semibold">
309
- <Money value={saida.valor} />
310
- </TableCell>
311
- </TableRow>
312
- ))}
313
- <TableRow className="bg-muted/50">
314
- <TableCell className="font-bold" colSpan={2}>
315
- {t('table.total')}
316
- </TableCell>
317
- <TableCell className="text-right font-bold text-red-600">
318
- <Money value={totalSaidas} />
319
- </TableCell>
320
- </TableRow>
321
- </TableBody>
322
- </Table>
323
- </CardContent>
324
- </Card>
260
+ <TabsContent value="saidas">
261
+ <Table>
262
+ <TableHeader>
263
+ <TableRow>
264
+ <TableHead>{t('table.headers.category')}</TableHead>
265
+ <TableHead>{t('table.headers.dueDate')}</TableHead>
266
+ <TableHead className="text-right">
267
+ {t('table.headers.value')}
268
+ </TableHead>
269
+ </TableRow>
270
+ </TableHeader>
271
+ <TableBody>
272
+ {saidasPrevistas.map((saida, i) => (
273
+ <TableRow key={i}>
274
+ <TableCell className="font-medium">
275
+ {saida.categoria}
276
+ </TableCell>
277
+ <TableCell>{formatarData(saida.vencimento)}</TableCell>
278
+ <TableCell className="text-right text-red-600 font-semibold">
279
+ <Money value={saida.valor} />
280
+ </TableCell>
281
+ </TableRow>
282
+ ))}
283
+ <TableRow className="bg-muted/50">
284
+ <TableCell className="font-bold" colSpan={2}>
285
+ {t('table.total')}
286
+ </TableCell>
287
+ <TableCell className="text-right font-bold text-red-600">
288
+ <Money value={totalSaidas} />
289
+ </TableCell>
290
+ </TableRow>
291
+ </TableBody>
292
+ </Table>
325
293
  </TabsContent>
326
294
  </Tabs>
327
295
  </Page>
@@ -1,5 +1,6 @@
1
1
  'use client';
2
2
 
3
+ import { FinancePageSection } from '@/app/(app)/(libraries)/finance/_components/finance-layout';
3
4
  import { Page, PageHeader } from '@/components/entity-list';
4
5
  import { Badge } from '@/components/ui/badge';
5
6
  import {
@@ -9,6 +10,7 @@ import {
9
10
  CardHeader,
10
11
  CardTitle,
11
12
  } from '@/components/ui/card';
13
+ import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
12
14
  import { Money } from '@/components/ui/money';
13
15
  import {
14
16
  Table,
@@ -48,6 +50,48 @@ export default function RecebiveisPage() {
48
50
  const totalLiquido = recebiveis.reduce((acc, r) => acc + r.liquido, 0);
49
51
  const taxasPercentual =
50
52
  totalBruto > 0 ? ((totalTaxas / totalBruto) * 100).toFixed(2) : '0.00';
53
+ const summaryCards = [
54
+ {
55
+ key: 'totalGross',
56
+ title: t('cards.totalGross'),
57
+ value: <Money value={totalBruto} />,
58
+ description: t('cards.receivablesCount', { count: recebiveis.length }),
59
+ icon: CalendarDays,
60
+ layout: 'compact' as const,
61
+ },
62
+ {
63
+ key: 'fees',
64
+ title: t('cards.fees'),
65
+ value: (
66
+ <span>
67
+ - <Money value={totalTaxas} />
68
+ </span>
69
+ ),
70
+ description: t('cards.percentOfGross', {
71
+ percent: taxasPercentual,
72
+ }),
73
+ layout: 'compact' as const,
74
+ valueClassName: 'text-red-600',
75
+ iconContainerClassName: 'bg-red-500/10 text-red-700',
76
+ accentClassName: 'from-red-500/20 via-rose-500/10 to-transparent',
77
+ },
78
+ {
79
+ key: 'totalNet',
80
+ title: t('cards.totalNet'),
81
+ value: <Money value={totalLiquido} />,
82
+ layout: 'compact' as const,
83
+ valueClassName: 'text-green-600',
84
+ iconContainerClassName: 'bg-green-500/10 text-green-700',
85
+ accentClassName: 'from-green-500/20 via-emerald-500/10 to-transparent',
86
+ },
87
+ {
88
+ key: 'confirmed',
89
+ title: t('cards.confirmed'),
90
+ value: recebiveis.filter((r) => r.status === 'confirmado').length,
91
+ description: t('cards.ofTotal', { total: recebiveis.length }),
92
+ layout: 'compact' as const,
93
+ },
94
+ ];
51
95
 
52
96
  return (
53
97
  <Page>
@@ -61,68 +105,7 @@ export default function RecebiveisPage() {
61
105
  ]}
62
106
  />
63
107
 
64
- <div className="grid gap-4 md:grid-cols-4">
65
- <Card>
66
- <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
67
- <CardTitle className="text-sm font-medium">
68
- {t('cards.totalGross')}
69
- </CardTitle>
70
- <CalendarDays className="h-4 w-4 text-muted-foreground" />
71
- </CardHeader>
72
- <CardContent>
73
- <div className="text-2xl font-bold">
74
- <Money value={totalBruto} />
75
- </div>
76
- <p className="text-xs text-muted-foreground">
77
- {t('cards.receivablesCount', { count: recebiveis.length })}
78
- </p>
79
- </CardContent>
80
- </Card>
81
- <Card>
82
- <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
83
- <CardTitle className="text-sm font-medium">
84
- {t('cards.fees')}
85
- </CardTitle>
86
- </CardHeader>
87
- <CardContent>
88
- <div className="text-2xl font-bold text-red-600">
89
- - <Money value={totalTaxas} />
90
- </div>
91
- <p className="text-xs text-muted-foreground">
92
- {t('cards.percentOfGross', {
93
- percent: taxasPercentual,
94
- })}
95
- </p>
96
- </CardContent>
97
- </Card>
98
- <Card>
99
- <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
100
- <CardTitle className="text-sm font-medium">
101
- {t('cards.totalNet')}
102
- </CardTitle>
103
- </CardHeader>
104
- <CardContent>
105
- <div className="text-2xl font-bold text-green-600">
106
- <Money value={totalLiquido} />
107
- </div>
108
- </CardContent>
109
- </Card>
110
- <Card>
111
- <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
112
- <CardTitle className="text-sm font-medium">
113
- {t('cards.confirmed')}
114
- </CardTitle>
115
- </CardHeader>
116
- <CardContent>
117
- <div className="text-2xl font-bold">
118
- {recebiveis.filter((r) => r.status === 'confirmado').length}
119
- </div>
120
- <p className="text-xs text-muted-foreground">
121
- {t('cards.ofTotal', { total: recebiveis.length })}
122
- </p>
123
- </CardContent>
124
- </Card>
125
- </div>
108
+ <KpiCardsGrid items={summaryCards} columns={4} />
126
109
 
127
110
  <div className="grid gap-6 lg:grid-cols-3">
128
111
  {adquirentes.map((adquirente) => {
@@ -164,12 +147,11 @@ export default function RecebiveisPage() {
164
147
  })}
165
148
  </div>
166
149
 
167
- <Card>
168
- <CardHeader>
169
- <CardTitle>{t('table.title')}</CardTitle>
170
- <CardDescription>{t('table.description')}</CardDescription>
171
- </CardHeader>
172
- <CardContent>
150
+ <FinancePageSection
151
+ contentClassName="p-0"
152
+ className="border-none shadow-none"
153
+ >
154
+ <div className="overflow-x-auto">
173
155
  <Table>
174
156
  <TableHeader>
175
157
  <TableRow>
@@ -220,8 +202,8 @@ export default function RecebiveisPage() {
220
202
  })}
221
203
  </TableBody>
222
204
  </Table>
223
- </CardContent>
224
- </Card>
205
+ </div>
206
+ </FinancePageSection>
225
207
  </Page>
226
208
  );
227
209
  }