@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.
- package/dist/dto/create-bank-account.dto.d.ts +1 -0
- package/dist/dto/create-bank-account.dto.d.ts.map +1 -1
- package/dist/dto/create-bank-account.dto.js +7 -0
- package/dist/dto/create-bank-account.dto.js.map +1 -1
- package/dist/dto/update-bank-account.dto.d.ts +1 -0
- package/dist/dto/update-bank-account.dto.d.ts.map +1 -1
- package/dist/dto/update-bank-account.dto.js +7 -0
- package/dist/dto/update-bank-account.dto.js.map +1 -1
- package/dist/finance-bank-accounts.controller.d.ts +3 -0
- package/dist/finance-bank-accounts.controller.d.ts.map +1 -1
- package/dist/finance-data.controller.d.ts +1 -0
- package/dist/finance-data.controller.d.ts.map +1 -1
- package/dist/finance.service.d.ts +4 -0
- package/dist/finance.service.d.ts.map +1 -1
- package/dist/finance.service.js +5 -0
- package/dist/finance.service.js.map +1 -1
- package/hedhog/data/dashboard.yaml +6 -0
- package/hedhog/data/dashboard_component.yaml +72 -17
- package/hedhog/data/dashboard_component_role.yaml +30 -0
- package/hedhog/data/dashboard_item.yaml +155 -0
- package/hedhog/data/dashboard_role.yaml +6 -0
- package/hedhog/data/role_menu.yaml +6 -0
- package/hedhog/data/role_route.yaml +127 -0
- package/hedhog/frontend/app/cash-and-banks/bank-accounts/page.tsx.ejs +328 -12
- package/hedhog/frontend/messages/en.json +48 -2
- package/hedhog/frontend/messages/pt.json +48 -2
- package/hedhog/frontend/widgets/alerts.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/bank-reconciliation-status.tsx.ejs +142 -0
- package/hedhog/frontend/widgets/cash-balance-kpi.tsx.ejs +9 -9
- package/hedhog/frontend/widgets/cash-flow-chart.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/default-kpi.tsx.ejs +9 -9
- package/hedhog/frontend/widgets/payable-30d-kpi.tsx.ejs +9 -9
- package/hedhog/frontend/widgets/pending-approvals-kpi.tsx.ejs +78 -0
- package/hedhog/frontend/widgets/pending-approvals-list.tsx.ejs +147 -0
- package/hedhog/frontend/widgets/pending-reconciliation-kpi.tsx.ejs +84 -0
- package/hedhog/frontend/widgets/receivable-30d-kpi.tsx.ejs +9 -9
- package/hedhog/frontend/widgets/receivable-aging-analysis.tsx.ejs +163 -0
- package/hedhog/frontend/widgets/upcoming-payable.tsx.ejs +1 -1
- package/hedhog/frontend/widgets/upcoming-receivable.tsx.ejs +1 -1
- package/hedhog/table/bank_account.yaml +8 -0
- package/package.json +5 -5
- package/src/dto/create-bank-account.dto.ts +7 -1
- package/src/dto/update-bank-account.dto.ts +7 -1
- 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 '
|
|
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 '
|
|
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.
|
|
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/
|
|
15
|
-
"@hed-hog/
|
|
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) =>
|
package/src/finance.service.ts
CHANGED
|
@@ -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',
|