@hed-hog/finance 0.0.299 → 0.0.300

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 (44) 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 +3 -0
  10. package/dist/finance-bank-accounts.controller.d.ts.map +1 -1
  11. package/dist/finance-data.controller.d.ts +1 -0
  12. package/dist/finance-data.controller.d.ts.map +1 -1
  13. package/dist/finance.service.d.ts +4 -0
  14. package/dist/finance.service.d.ts.map +1 -1
  15. package/dist/finance.service.js +5 -0
  16. package/dist/finance.service.js.map +1 -1
  17. package/hedhog/data/dashboard.yaml +6 -0
  18. package/hedhog/data/dashboard_component.yaml +72 -17
  19. package/hedhog/data/dashboard_component_role.yaml +30 -0
  20. package/hedhog/data/dashboard_item.yaml +155 -0
  21. package/hedhog/data/dashboard_role.yaml +6 -0
  22. package/hedhog/data/role_menu.yaml +6 -0
  23. package/hedhog/data/role_route.yaml +127 -0
  24. package/hedhog/frontend/app/cash-and-banks/bank-accounts/page.tsx.ejs +328 -12
  25. package/hedhog/frontend/messages/en.json +48 -2
  26. package/hedhog/frontend/messages/pt.json +48 -2
  27. package/hedhog/frontend/widgets/alerts.tsx.ejs +1 -1
  28. package/hedhog/frontend/widgets/bank-reconciliation-status.tsx.ejs +142 -0
  29. package/hedhog/frontend/widgets/cash-balance-kpi.tsx.ejs +9 -9
  30. package/hedhog/frontend/widgets/cash-flow-chart.tsx.ejs +1 -1
  31. package/hedhog/frontend/widgets/default-kpi.tsx.ejs +9 -9
  32. package/hedhog/frontend/widgets/payable-30d-kpi.tsx.ejs +9 -9
  33. package/hedhog/frontend/widgets/pending-approvals-kpi.tsx.ejs +78 -0
  34. package/hedhog/frontend/widgets/pending-approvals-list.tsx.ejs +147 -0
  35. package/hedhog/frontend/widgets/pending-reconciliation-kpi.tsx.ejs +84 -0
  36. package/hedhog/frontend/widgets/receivable-30d-kpi.tsx.ejs +9 -9
  37. package/hedhog/frontend/widgets/receivable-aging-analysis.tsx.ejs +163 -0
  38. package/hedhog/frontend/widgets/upcoming-payable.tsx.ejs +1 -1
  39. package/hedhog/frontend/widgets/upcoming-receivable.tsx.ejs +1 -1
  40. package/hedhog/table/bank_account.yaml +8 -0
  41. package/package.json +5 -5
  42. package/src/dto/create-bank-account.dto.ts +7 -1
  43. package/src/dto/update-bank-account.dto.ts +7 -1
  44. package/src/finance.service.ts +4 -0
@@ -0,0 +1,163 @@
1
+ 'use client';
2
+
3
+ import { WidgetWrapper } from '@/app/(app)/(libraries)/core/dashboard/components';
4
+ import {
5
+ Card,
6
+ CardContent,
7
+ CardDescription,
8
+ CardHeader,
9
+ CardTitle,
10
+ } from '@/components/ui/card';
11
+ import { Money } from '@/components/ui/money';
12
+ import { useWidgetData } from '@/hooks/use-widget-data';
13
+ import { BarChart3 } from 'lucide-react';
14
+ import { useTranslations } from 'next-intl';
15
+
16
+ interface AgingWidgetProps {
17
+ widget?: { name?: string };
18
+ onRemove?: () => void;
19
+ }
20
+
21
+ interface AgingItem {
22
+ bucket0_30?: number | null;
23
+ bucket31_60?: number | null;
24
+ bucket61_90?: number | null;
25
+ bucket90plus?: number | null;
26
+ total?: number | null;
27
+ }
28
+
29
+ interface FinanceData {
30
+ agingInadimplencia?: AgingItem[];
31
+ }
32
+
33
+ export default function ReceivableAgingAnalysis({
34
+ widget,
35
+ onRemove,
36
+ }: AgingWidgetProps) {
37
+ const t = useTranslations('finance.DashboardPage');
38
+
39
+ const { data, isLoading, isAccessDenied, isError } =
40
+ useWidgetData<FinanceData>({
41
+ endpoint: '/finance/data',
42
+ queryKey: 'finance-receivable-aging-analysis',
43
+ });
44
+
45
+ const agingItems = data?.agingInadimplencia || [];
46
+
47
+ const totals = {
48
+ bucket0to30: agingItems.reduce(
49
+ (acc, item) => acc + Number(item?.bucket0_30 || 0),
50
+ 0
51
+ ),
52
+ bucket31to60: agingItems.reduce(
53
+ (acc, item) => acc + Number(item?.bucket31_60 || 0),
54
+ 0
55
+ ),
56
+ bucket61to90: agingItems.reduce(
57
+ (acc, item) => acc + Number(item?.bucket61_90 || 0),
58
+ 0
59
+ ),
60
+ bucket90plus: agingItems.reduce(
61
+ (acc, item) => acc + Number(item?.bucket90plus || 0),
62
+ 0
63
+ ),
64
+ total: agingItems.reduce((acc, item) => acc + Number(item?.total || 0), 0),
65
+ clients: agingItems.length,
66
+ };
67
+
68
+ const buckets = [
69
+ {
70
+ label: t('aging.range0to30'),
71
+ value: totals.bucket0to30,
72
+ colorClass: 'bg-amber-400',
73
+ },
74
+ {
75
+ label: t('aging.range31to60'),
76
+ value: totals.bucket31to60,
77
+ colorClass: 'bg-orange-400',
78
+ },
79
+ {
80
+ label: t('aging.range61to90'),
81
+ value: totals.bucket61to90,
82
+ colorClass: 'bg-rose-400',
83
+ },
84
+ {
85
+ label: t('aging.range90plus'),
86
+ value: totals.bucket90plus,
87
+ colorClass: 'bg-red-500',
88
+ },
89
+ ];
90
+
91
+ return (
92
+ <WidgetWrapper
93
+ isLoading={isLoading}
94
+ isAccessDenied={isAccessDenied}
95
+ isError={isError}
96
+ widgetName={widget?.name || t('aging.title')}
97
+ onRemove={onRemove}
98
+ >
99
+ <Card className="flex h-full flex-col overflow-hidden">
100
+ <CardHeader className="pb-1.5">
101
+ <CardTitle className="flex items-center gap-2 text-sm font-semibold">
102
+ <BarChart3 className="h-4 w-4 text-rose-500" />
103
+ {t('aging.title')}
104
+ </CardTitle>
105
+ <CardDescription className="line-clamp-1 text-xs">
106
+ {t('aging.description')}
107
+ </CardDescription>
108
+ </CardHeader>
109
+ <CardContent className="flex flex-1 flex-col gap-2 overflow-hidden pt-0">
110
+ <div className="grid grid-cols-2 gap-2 rounded-lg bg-muted/40 p-2.5">
111
+ <div>
112
+ <p className="text-[10px] uppercase tracking-[0.16em] text-muted-foreground">
113
+ {t('aging.totalLabel')}
114
+ </p>
115
+ <p className="text-sm font-semibold text-foreground sm:text-base">
116
+ <Money value={totals.total} />
117
+ </p>
118
+ </div>
119
+ <div>
120
+ <p className="text-[10px] uppercase tracking-[0.16em] text-muted-foreground">
121
+ {t('aging.clientsLabel')}
122
+ </p>
123
+ <p className="text-sm font-semibold text-foreground sm:text-base">
124
+ {totals.clients}
125
+ </p>
126
+ </div>
127
+ </div>
128
+
129
+ <div className="grid min-h-0 grid-cols-2 gap-2">
130
+ {buckets.map((bucket) => {
131
+ const percentage =
132
+ totals.total > 0 ? (bucket.value / totals.total) * 100 : 0;
133
+
134
+ return (
135
+ <div
136
+ key={bucket.label}
137
+ className="rounded-md border border-border/60 bg-background/70 p-2"
138
+ >
139
+ <div className="mb-1 flex items-start justify-between gap-2">
140
+ <span className="text-[11px] leading-4 text-muted-foreground">
141
+ {bucket.label}
142
+ </span>
143
+ <span className="shrink-0 text-[11px] font-medium text-foreground">
144
+ <Money value={bucket.value} />
145
+ </span>
146
+ </div>
147
+ <div className="h-1.5 overflow-hidden rounded-full bg-muted">
148
+ <div
149
+ className={`h-full rounded-full ${bucket.colorClass}`}
150
+ style={{
151
+ width: `${Math.max(percentage, bucket.value > 0 ? 8 : 0)}%`,
152
+ }}
153
+ />
154
+ </div>
155
+ </div>
156
+ );
157
+ })}
158
+ </div>
159
+ </CardContent>
160
+ </Card>
161
+ </WidgetWrapper>
162
+ );
163
+ }
@@ -13,7 +13,7 @@ import { useWidgetData } from '@/hooks/use-widget-data';
13
13
  import { ArrowDownRight } from 'lucide-react';
14
14
  import { useTranslations } from 'next-intl';
15
15
  import Link from 'next/link';
16
- import { WidgetWrapper } from '../widget-wrapper';
16
+ import { WidgetWrapper } from '@/app/(app)/(libraries)/core/dashboard/components';
17
17
 
18
18
  interface FinanceData {
19
19
  titulosPagar?: Array<{
@@ -13,7 +13,7 @@ import { useWidgetData } from '@/hooks/use-widget-data';
13
13
  import { ArrowUpRight } from 'lucide-react';
14
14
  import { useTranslations } from 'next-intl';
15
15
  import Link from 'next/link';
16
- import { WidgetWrapper } from '../widget-wrapper';
16
+ import { WidgetWrapper } from '@/app/(app)/(libraries)/core/dashboard/components';
17
17
 
18
18
  interface FinanceData {
19
19
  titulosReceber?: Array<{
@@ -25,6 +25,13 @@ columns:
25
25
  - name: account_type
26
26
  type: enum
27
27
  values: [checking, savings, investment, cash, other]
28
+ - name: logo_file_id
29
+ type: fk
30
+ isNullable: true
31
+ references:
32
+ table: file
33
+ column: id
34
+ onDelete: SET NULL
28
35
  - name: status
29
36
  type: enum
30
37
  values: [active, inactive]
@@ -34,4 +41,5 @@ columns:
34
41
  indices:
35
42
  - columns: [code]
36
43
  isUnique: true
44
+ - columns: [logo_file_id]
37
45
  - columns: [status]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hed-hog/finance",
3
- "version": "0.0.299",
3
+ "version": "0.0.300",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "dependencies": {
@@ -11,11 +11,11 @@
11
11
  "@nestjs/mapped-types": "*",
12
12
  "@hed-hog/api": "0.0.6",
13
13
  "@hed-hog/api-locale": "0.0.14",
14
- "@hed-hog/api-pagination": "0.0.7",
15
- "@hed-hog/tag": "0.0.299",
16
- "@hed-hog/core": "0.0.299",
17
- "@hed-hog/contact": "0.0.299",
14
+ "@hed-hog/tag": "0.0.300",
15
+ "@hed-hog/contact": "0.0.300",
18
16
  "@hed-hog/api-prisma": "0.0.6",
17
+ "@hed-hog/api-pagination": "0.0.7",
18
+ "@hed-hog/core": "0.0.300",
19
19
  "@hed-hog/api-types": "0.0.1"
20
20
  },
21
21
  "exports": {
@@ -1,5 +1,5 @@
1
1
  import { getLocaleText } from '@hed-hog/api-locale';
2
- import { IsNumber, IsOptional, IsString, Min } from 'class-validator';
2
+ import { IsInt, IsNumber, IsOptional, IsString, Min } from 'class-validator';
3
3
 
4
4
  export class CreateBankAccountDto {
5
5
  @IsString({
@@ -34,6 +34,12 @@ export class CreateBankAccountDto {
34
34
  })
35
35
  description?: string;
36
36
 
37
+ @IsOptional()
38
+ @IsInt({
39
+ message: (args) => getLocaleText('validation.idMustBeInteger', args.value),
40
+ })
41
+ logo_file_id?: number | null;
42
+
37
43
  @IsOptional()
38
44
  @IsNumber(
39
45
  {},
@@ -1,5 +1,5 @@
1
1
  import { getLocaleText } from '@hed-hog/api-locale';
2
- import { IsOptional, IsString } from 'class-validator';
2
+ import { IsInt, IsOptional, IsString } from 'class-validator';
3
3
 
4
4
  export class UpdateBankAccountDto {
5
5
  @IsOptional()
@@ -36,6 +36,12 @@ export class UpdateBankAccountDto {
36
36
  })
37
37
  description?: string;
38
38
 
39
+ @IsOptional()
40
+ @IsInt({
41
+ message: (args) => getLocaleText('validation.idMustBeInteger', args.value),
42
+ })
43
+ logo_file_id?: number | null;
44
+
39
45
  @IsOptional()
40
46
  @IsString({
41
47
  message: (args) =>
@@ -4013,6 +4013,7 @@ export class FinanceService {
4013
4013
  agency: data.branch || null,
4014
4014
  account_number: data.account || null,
4015
4015
  account_type: accountType,
4016
+ logo_file_id: data.logo_file_id ?? null,
4016
4017
  status: 'active',
4017
4018
  },
4018
4019
  });
@@ -4166,6 +4167,8 @@ export class FinanceService {
4166
4167
  account_number: data.account,
4167
4168
  name: data.description,
4168
4169
  account_type: data.type ? this.mapAccountTypeFromPt(data.type) : undefined,
4170
+ logo_file_id:
4171
+ data.logo_file_id === undefined ? undefined : data.logo_file_id,
4169
4172
  status: data.status,
4170
4173
  },
4171
4174
  include: {
@@ -6447,6 +6450,7 @@ export class FinanceService {
6447
6450
  agencia: bankAccount.agency || '-',
6448
6451
  conta: bankAccount.account_number || '-',
6449
6452
  tipo: this.mapAccountTypeToPt(bankAccount.account_type),
6453
+ logoFileId: bankAccount.logo_file_id ?? null,
6450
6454
  saldoAtual: this.fromCents(currentCents),
6451
6455
  saldoConciliado: this.fromCents(reconciledCents),
6452
6456
  ativo: bankAccount.status === 'active',