@hed-hog/finance 0.0.252 → 0.0.253
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/reverse-settlement.dto.d.ts +1 -0
- package/dist/dto/reverse-settlement.dto.d.ts.map +1 -1
- package/dist/dto/reverse-settlement.dto.js +5 -0
- package/dist/dto/reverse-settlement.dto.js.map +1 -1
- package/dist/finance-installments.controller.d.ts +40 -2
- package/dist/finance-installments.controller.d.ts.map +1 -1
- package/dist/finance-installments.controller.js +38 -2
- package/dist/finance-installments.controller.js.map +1 -1
- package/dist/finance.service.d.ts +38 -0
- package/dist/finance.service.d.ts.map +1 -1
- package/dist/finance.service.js +307 -118
- package/dist/finance.service.js.map +1 -1
- package/hedhog/data/route.yaml +27 -0
- package/hedhog/frontend/app/accounts-payable/installments/[id]/page.tsx.ejs +308 -99
- package/hedhog/query/settlement-auditability.sql +175 -0
- package/hedhog/table/bank_reconciliation.yaml +11 -0
- package/hedhog/table/settlement.yaml +17 -1
- package/hedhog/table/settlement_allocation.yaml +3 -0
- package/package.json +5 -5
- package/src/dto/reverse-settlement.dto.ts +4 -0
- package/src/finance-installments.controller.ts +45 -12
- package/src/finance.service.ts +439 -139
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
AlertDialogFooter,
|
|
11
11
|
AlertDialogHeader,
|
|
12
12
|
AlertDialogTitle,
|
|
13
|
-
AlertDialogTrigger,
|
|
14
13
|
} from '@/components/ui/alert-dialog';
|
|
15
14
|
import { AuditTimeline } from '@/components/ui/audit-timeline';
|
|
16
15
|
import { Button } from '@/components/ui/button';
|
|
@@ -64,13 +63,16 @@ import {
|
|
|
64
63
|
} from '@/components/ui/table';
|
|
65
64
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
66
65
|
import { TagSelectorSheet } from '@/components/ui/tag-selector-sheet';
|
|
67
|
-
import { useApp } from '@hed-hog/next-app-provider';
|
|
66
|
+
import { useApp, useQuery } from '@hed-hog/next-app-provider';
|
|
68
67
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
69
68
|
import {
|
|
70
69
|
CheckCircle,
|
|
70
|
+
ChevronDown,
|
|
71
|
+
ChevronUp,
|
|
71
72
|
Download,
|
|
72
73
|
Edit,
|
|
73
74
|
FileText,
|
|
75
|
+
Loader2,
|
|
74
76
|
MoreHorizontal,
|
|
75
77
|
Undo,
|
|
76
78
|
XCircle,
|
|
@@ -78,7 +80,7 @@ import {
|
|
|
78
80
|
import { useTranslations } from 'next-intl';
|
|
79
81
|
import Link from 'next/link';
|
|
80
82
|
import { useParams, useRouter, useSearchParams } from 'next/navigation';
|
|
81
|
-
import { useEffect, useMemo, useState } from 'react';
|
|
83
|
+
import { Fragment, useEffect, useMemo, useState } from 'react';
|
|
82
84
|
import { useForm } from 'react-hook-form';
|
|
83
85
|
import { z } from 'zod';
|
|
84
86
|
import { formatarData } from '../../../_lib/formatters';
|
|
@@ -90,6 +92,40 @@ type SettleFormValues = {
|
|
|
90
92
|
description?: string;
|
|
91
93
|
};
|
|
92
94
|
|
|
95
|
+
type SettlementHistoryAllocation = {
|
|
96
|
+
installmentId: string;
|
|
97
|
+
installmentSeq: number;
|
|
98
|
+
amountCents: number;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
type SettlementHistoryItem = {
|
|
102
|
+
normal: {
|
|
103
|
+
id: string;
|
|
104
|
+
paidAt: string | null;
|
|
105
|
+
amountCents: number;
|
|
106
|
+
type: 'NORMAL';
|
|
107
|
+
method?: string | null;
|
|
108
|
+
account?: string | null;
|
|
109
|
+
accountId?: string | null;
|
|
110
|
+
createdAt?: string | null;
|
|
111
|
+
createdBy?: string | null;
|
|
112
|
+
memo?: string | null;
|
|
113
|
+
reconciled: boolean;
|
|
114
|
+
reconciliationId?: string | null;
|
|
115
|
+
};
|
|
116
|
+
reversal?: {
|
|
117
|
+
id: string;
|
|
118
|
+
paidAt: string | null;
|
|
119
|
+
amountCents: number;
|
|
120
|
+
type: 'REVERSAL';
|
|
121
|
+
createdAt?: string | null;
|
|
122
|
+
createdBy?: string | null;
|
|
123
|
+
memo?: string | null;
|
|
124
|
+
} | null;
|
|
125
|
+
allocations: SettlementHistoryAllocation[];
|
|
126
|
+
statusLabel: 'ATIVO' | 'ESTORNADO';
|
|
127
|
+
};
|
|
128
|
+
|
|
93
129
|
export default function TituloDetalhePage() {
|
|
94
130
|
const t = useTranslations('finance.PayableInstallmentDetailPage');
|
|
95
131
|
const settleSchema = useMemo(
|
|
@@ -112,12 +148,30 @@ export default function TituloDetalhePage() {
|
|
|
112
148
|
pessoas,
|
|
113
149
|
categorias,
|
|
114
150
|
centrosCusto,
|
|
115
|
-
contasBancarias,
|
|
116
151
|
logsAuditoria,
|
|
117
152
|
tags,
|
|
118
153
|
} = data;
|
|
119
154
|
|
|
120
155
|
const titulo = titulosPagar.find((t) => t.id === id);
|
|
156
|
+
|
|
157
|
+
const {
|
|
158
|
+
data: settlementsHistory = [],
|
|
159
|
+
refetch: refetchSettlementsHistory,
|
|
160
|
+
isFetching: isFetchingSettlementsHistory,
|
|
161
|
+
} = useQuery<SettlementHistoryItem[]>({
|
|
162
|
+
queryKey: ['finance-title-settlements-history', id],
|
|
163
|
+
enabled: !!id,
|
|
164
|
+
queryFn: async () => {
|
|
165
|
+
const response = await request<SettlementHistoryItem[]>({
|
|
166
|
+
url: `/finance/titles/${id}/settlements-history`,
|
|
167
|
+
method: 'GET',
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
return (response.data || []) as SettlementHistoryItem[];
|
|
171
|
+
},
|
|
172
|
+
placeholderData: (old) => old,
|
|
173
|
+
});
|
|
174
|
+
|
|
121
175
|
const canSettle = ['aberto', 'parcial', 'vencido'].includes(
|
|
122
176
|
titulo?.status || ''
|
|
123
177
|
);
|
|
@@ -149,9 +203,14 @@ export default function TituloDetalhePage() {
|
|
|
149
203
|
const [isReverseDialogOpen, setIsReverseDialogOpen] = useState(false);
|
|
150
204
|
const [selectedSettlementIdToReverse, setSelectedSettlementIdToReverse] =
|
|
151
205
|
useState<string | null>(null);
|
|
206
|
+
const [reverseReason, setReverseReason] = useState('');
|
|
152
207
|
const [reversingSettlementId, setReversingSettlementId] = useState<
|
|
153
208
|
string | null
|
|
154
209
|
>(null);
|
|
210
|
+
const [unreconcilingId, setUnreconcilingId] = useState<string | null>(null);
|
|
211
|
+
const [expandedSettlementRows, setExpandedSettlementRows] = useState<
|
|
212
|
+
Record<string, boolean>
|
|
213
|
+
>({});
|
|
155
214
|
|
|
156
215
|
useEffect(() => {
|
|
157
216
|
setAvailableTags(tags || []);
|
|
@@ -225,8 +284,6 @@ export default function TituloDetalhePage() {
|
|
|
225
284
|
categorias.find((c) => c.id === categoryId);
|
|
226
285
|
const getCentroCustoById = (costCenterId?: string) =>
|
|
227
286
|
centrosCusto.find((c) => c.id === costCenterId);
|
|
228
|
-
const getContaBancariaById = (bankId?: string) =>
|
|
229
|
-
contasBancarias.find((c) => c.id === bankId);
|
|
230
287
|
|
|
231
288
|
const fornecedor = getPessoaById(titulo.fornecedorId);
|
|
232
289
|
const categoria = getCategoriaById(titulo.categoriaId);
|
|
@@ -388,15 +445,12 @@ export default function TituloDetalhePage() {
|
|
|
388
445
|
const canApprove = titulo.status === 'rascunho';
|
|
389
446
|
const canEdit = titulo.status === 'rascunho';
|
|
390
447
|
const canCancel = !['cancelado', 'liquidado'].includes(titulo.status);
|
|
391
|
-
const reversibleSettlements =
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
liquidacao?.status !== 'estornado'
|
|
398
|
-
);
|
|
399
|
-
});
|
|
448
|
+
const reversibleSettlements = settlementsHistory.filter(
|
|
449
|
+
(group) =>
|
|
450
|
+
group.normal?.id &&
|
|
451
|
+
group.statusLabel === 'ATIVO' &&
|
|
452
|
+
!group.normal?.reconciled
|
|
453
|
+
);
|
|
400
454
|
const canReverse = reversibleSettlements.length > 0;
|
|
401
455
|
|
|
402
456
|
const getErrorMessage = (error: any, fallback: string) => {
|
|
@@ -475,12 +529,16 @@ export default function TituloDetalhePage() {
|
|
|
475
529
|
setReversingSettlementId(settlementId);
|
|
476
530
|
try {
|
|
477
531
|
await request({
|
|
478
|
-
url: `/finance/
|
|
479
|
-
method: '
|
|
480
|
-
data: {
|
|
532
|
+
url: `/finance/settlements/${settlementId}/reverse`,
|
|
533
|
+
method: 'POST',
|
|
534
|
+
data: {
|
|
535
|
+
reason: reverseReason?.trim() || undefined,
|
|
536
|
+
memo: reverseReason?.trim() || undefined,
|
|
537
|
+
},
|
|
481
538
|
});
|
|
482
539
|
|
|
483
|
-
await refetch();
|
|
540
|
+
await Promise.all([refetch(), refetchSettlementsHistory()]);
|
|
541
|
+
setReverseReason('');
|
|
484
542
|
showToastHandler?.('success', t('messages.reverseSuccess'));
|
|
485
543
|
} catch (error) {
|
|
486
544
|
showToastHandler?.(
|
|
@@ -492,6 +550,37 @@ export default function TituloDetalhePage() {
|
|
|
492
550
|
}
|
|
493
551
|
};
|
|
494
552
|
|
|
553
|
+
const handleUnreconcileSettlement = async (reconciliationId: string) => {
|
|
554
|
+
if (!reconciliationId || unreconcilingId) {
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
setUnreconcilingId(reconciliationId);
|
|
559
|
+
try {
|
|
560
|
+
await request({
|
|
561
|
+
url: `/finance/bank-reconciliations/${reconciliationId}`,
|
|
562
|
+
method: 'DELETE',
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
await Promise.all([refetch(), refetchSettlementsHistory()]);
|
|
566
|
+
showToastHandler?.('success', 'Conciliação removida com sucesso');
|
|
567
|
+
} catch (error) {
|
|
568
|
+
showToastHandler?.(
|
|
569
|
+
'error',
|
|
570
|
+
getErrorMessage(error, 'Não foi possível desconciliar a liquidação')
|
|
571
|
+
);
|
|
572
|
+
} finally {
|
|
573
|
+
setUnreconcilingId(null);
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
|
|
577
|
+
const toggleSettlementExpanded = (settlementId: string) => {
|
|
578
|
+
setExpandedSettlementRows((current) => ({
|
|
579
|
+
...current,
|
|
580
|
+
[settlementId]: !current[settlementId],
|
|
581
|
+
}));
|
|
582
|
+
};
|
|
583
|
+
|
|
495
584
|
const handleCancel = async () => {
|
|
496
585
|
if (!canCancel || isCanceling) {
|
|
497
586
|
return;
|
|
@@ -570,14 +659,15 @@ export default function TituloDetalhePage() {
|
|
|
570
659
|
<DropdownMenuItem
|
|
571
660
|
disabled={!canReverse || !!reversingSettlementId}
|
|
572
661
|
onClick={() => {
|
|
573
|
-
const latestSettlement = reversibleSettlements
|
|
574
|
-
if (!latestSettlement?.
|
|
662
|
+
const latestSettlement = reversibleSettlements[0];
|
|
663
|
+
if (!latestSettlement?.normal?.id) {
|
|
575
664
|
return;
|
|
576
665
|
}
|
|
577
666
|
|
|
578
667
|
setSelectedSettlementIdToReverse(
|
|
579
|
-
String(latestSettlement.
|
|
668
|
+
String(latestSettlement.normal.id)
|
|
580
669
|
);
|
|
670
|
+
setReverseReason('');
|
|
581
671
|
setIsReverseDialogOpen(true);
|
|
582
672
|
}}
|
|
583
673
|
>
|
|
@@ -630,6 +720,7 @@ export default function TituloDetalhePage() {
|
|
|
630
720
|
|
|
631
721
|
if (!open) {
|
|
632
722
|
setSelectedSettlementIdToReverse(null);
|
|
723
|
+
setReverseReason('');
|
|
633
724
|
}
|
|
634
725
|
}}
|
|
635
726
|
>
|
|
@@ -642,6 +733,16 @@ export default function TituloDetalhePage() {
|
|
|
642
733
|
{t('dialogs.reverse.description')}
|
|
643
734
|
</AlertDialogDescription>
|
|
644
735
|
</AlertDialogHeader>
|
|
736
|
+
<div className="space-y-2">
|
|
737
|
+
<FormLabel>Motivo do estorno</FormLabel>
|
|
738
|
+
<Input
|
|
739
|
+
value={reverseReason}
|
|
740
|
+
onChange={(event) => setReverseReason(event.target.value)}
|
|
741
|
+
placeholder="Ex.: baixa duplicada"
|
|
742
|
+
maxLength={255}
|
|
743
|
+
disabled={!!reversingSettlementId}
|
|
744
|
+
/>
|
|
745
|
+
</div>
|
|
645
746
|
<AlertDialogFooter>
|
|
646
747
|
<AlertDialogCancel disabled={!!reversingSettlementId}>
|
|
647
748
|
{t('dialogs.reverse.cancel')}
|
|
@@ -660,6 +761,7 @@ export default function TituloDetalhePage() {
|
|
|
660
761
|
).finally(() => {
|
|
661
762
|
setIsReverseDialogOpen(false);
|
|
662
763
|
setSelectedSettlementIdToReverse(null);
|
|
764
|
+
setReverseReason('');
|
|
663
765
|
});
|
|
664
766
|
}}
|
|
665
767
|
>
|
|
@@ -985,105 +1087,212 @@ export default function TituloDetalhePage() {
|
|
|
985
1087
|
<TabsContent value="liquidacoes" className="mt-4">
|
|
986
1088
|
<Card>
|
|
987
1089
|
<CardContent className="pt-6">
|
|
988
|
-
{
|
|
1090
|
+
{isFetchingSettlementsHistory ? (
|
|
1091
|
+
<div className="flex items-center justify-center py-8 text-muted-foreground">
|
|
1092
|
+
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
1093
|
+
Carregando histórico de liquidações...
|
|
1094
|
+
</div>
|
|
1095
|
+
) : settlementsHistory.length > 0 ? (
|
|
989
1096
|
<Table>
|
|
990
1097
|
<TableHeader>
|
|
991
1098
|
<TableRow>
|
|
992
|
-
<TableHead>
|
|
993
|
-
<TableHead
|
|
994
|
-
|
|
995
|
-
</TableHead>
|
|
996
|
-
<TableHead
|
|
997
|
-
|
|
998
|
-
</TableHead>
|
|
999
|
-
<TableHead className="text-right">
|
|
1000
|
-
{t('settlementsTable.discount')}
|
|
1001
|
-
</TableHead>
|
|
1002
|
-
<TableHead className="text-right">
|
|
1003
|
-
{t('settlementsTable.fine')}
|
|
1004
|
-
</TableHead>
|
|
1005
|
-
<TableHead>{t('settlementsTable.account')}</TableHead>
|
|
1006
|
-
<TableHead>{t('settlementsTable.method')}</TableHead>
|
|
1007
|
-
<TableHead className="text-right">
|
|
1008
|
-
{t('settlementsTable.actions')}
|
|
1009
|
-
</TableHead>
|
|
1099
|
+
<TableHead>Date</TableHead>
|
|
1100
|
+
<TableHead>Type</TableHead>
|
|
1101
|
+
<TableHead>Status</TableHead>
|
|
1102
|
+
<TableHead className="text-right">Net Amount</TableHead>
|
|
1103
|
+
<TableHead>Method</TableHead>
|
|
1104
|
+
<TableHead>Account</TableHead>
|
|
1105
|
+
<TableHead>Reconciled</TableHead>
|
|
1106
|
+
<TableHead className="text-right">Actions</TableHead>
|
|
1010
1107
|
</TableRow>
|
|
1011
1108
|
</TableHeader>
|
|
1012
1109
|
<TableBody>
|
|
1013
|
-
{
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1110
|
+
{settlementsHistory.map((group) => {
|
|
1111
|
+
const normalId = group.normal.id;
|
|
1112
|
+
const isExpanded = !!expandedSettlementRows[normalId];
|
|
1113
|
+
const canReverseNormal =
|
|
1114
|
+
group.statusLabel === 'ATIVO' &&
|
|
1115
|
+
!group.normal.reconciled &&
|
|
1116
|
+
!reversingSettlementId;
|
|
1117
|
+
|
|
1118
|
+
return (
|
|
1119
|
+
<Fragment key={normalId}>
|
|
1120
|
+
<TableRow>
|
|
1121
|
+
<TableCell>
|
|
1122
|
+
{formatarData(group.normal.paidAt)}
|
|
1021
1123
|
</TableCell>
|
|
1022
|
-
<TableCell
|
|
1023
|
-
<
|
|
1124
|
+
<TableCell>
|
|
1125
|
+
<span className="rounded-md border px-2 py-1 text-xs font-medium">
|
|
1126
|
+
NORMAL
|
|
1127
|
+
</span>
|
|
1024
1128
|
</TableCell>
|
|
1025
|
-
<TableCell
|
|
1026
|
-
<
|
|
1129
|
+
<TableCell>
|
|
1130
|
+
<span
|
|
1131
|
+
className={`rounded-md px-2 py-1 text-xs font-medium ${
|
|
1132
|
+
group.statusLabel === 'ESTORNADO'
|
|
1133
|
+
? 'bg-muted text-muted-foreground'
|
|
1134
|
+
: 'bg-primary/10 text-primary'
|
|
1135
|
+
}`}
|
|
1136
|
+
>
|
|
1137
|
+
{group.statusLabel}
|
|
1138
|
+
</span>
|
|
1027
1139
|
</TableCell>
|
|
1028
|
-
<TableCell className="text-right">
|
|
1029
|
-
|
|
1140
|
+
<TableCell className="text-right font-medium">
|
|
1141
|
+
+
|
|
1142
|
+
<Money
|
|
1143
|
+
value={
|
|
1144
|
+
Math.abs(group.normal.amountCents || 0) / 100
|
|
1145
|
+
}
|
|
1146
|
+
/>
|
|
1030
1147
|
</TableCell>
|
|
1031
|
-
<TableCell>{conta?.descricao}</TableCell>
|
|
1032
1148
|
<TableCell className="capitalize">
|
|
1033
|
-
{
|
|
1149
|
+
{group.normal.method || '-'}
|
|
1150
|
+
</TableCell>
|
|
1151
|
+
<TableCell>{group.normal.account || '-'}</TableCell>
|
|
1152
|
+
<TableCell>
|
|
1153
|
+
<span
|
|
1154
|
+
className={`rounded-md px-2 py-1 text-xs font-medium ${
|
|
1155
|
+
group.normal.reconciled
|
|
1156
|
+
? 'bg-primary/10 text-primary'
|
|
1157
|
+
: 'bg-muted text-muted-foreground'
|
|
1158
|
+
}`}
|
|
1159
|
+
>
|
|
1160
|
+
{group.normal.reconciled
|
|
1161
|
+
? 'Conciliado'
|
|
1162
|
+
: 'Pendente'}
|
|
1163
|
+
</span>
|
|
1034
1164
|
</TableCell>
|
|
1035
1165
|
<TableCell className="text-right">
|
|
1036
|
-
<
|
|
1037
|
-
|
|
1166
|
+
<div className="flex items-center justify-end gap-2">
|
|
1167
|
+
{group.normal.reconciled &&
|
|
1168
|
+
group.normal.reconciliationId ? (
|
|
1038
1169
|
<Button
|
|
1039
1170
|
variant="outline"
|
|
1040
1171
|
size="sm"
|
|
1041
1172
|
disabled={
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1173
|
+
unreconcilingId ===
|
|
1174
|
+
group.normal.reconciliationId
|
|
1175
|
+
}
|
|
1176
|
+
onClick={() =>
|
|
1177
|
+
void handleUnreconcileSettlement(
|
|
1178
|
+
String(group.normal.reconciliationId)
|
|
1179
|
+
)
|
|
1045
1180
|
}
|
|
1046
1181
|
>
|
|
1047
|
-
|
|
1048
|
-
|
|
1182
|
+
{unreconcilingId ===
|
|
1183
|
+
group.normal.reconciliationId
|
|
1184
|
+
? 'Desconciliando...'
|
|
1185
|
+
: 'Desconciliar'}
|
|
1049
1186
|
</Button>
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1187
|
+
) : null}
|
|
1188
|
+
|
|
1189
|
+
<Button
|
|
1190
|
+
variant="outline"
|
|
1191
|
+
size="sm"
|
|
1192
|
+
title={
|
|
1193
|
+
group.normal.reconciled
|
|
1194
|
+
? 'Desconciliar primeiro'
|
|
1195
|
+
: undefined
|
|
1196
|
+
}
|
|
1197
|
+
disabled={!canReverseNormal}
|
|
1198
|
+
onClick={() => {
|
|
1199
|
+
setSelectedSettlementIdToReverse(normalId);
|
|
1200
|
+
setReverseReason('');
|
|
1201
|
+
setIsReverseDialogOpen(true);
|
|
1202
|
+
}}
|
|
1203
|
+
>
|
|
1204
|
+
<Undo className="mr-2 h-4 w-4" />
|
|
1205
|
+
Estornar
|
|
1206
|
+
</Button>
|
|
1207
|
+
|
|
1208
|
+
<Button
|
|
1209
|
+
variant="ghost"
|
|
1210
|
+
size="sm"
|
|
1211
|
+
onClick={() =>
|
|
1212
|
+
toggleSettlementExpanded(normalId)
|
|
1213
|
+
}
|
|
1214
|
+
>
|
|
1215
|
+
{isExpanded ? (
|
|
1216
|
+
<ChevronUp className="h-4 w-4" />
|
|
1217
|
+
) : (
|
|
1218
|
+
<ChevronDown className="h-4 w-4" />
|
|
1219
|
+
)}
|
|
1220
|
+
</Button>
|
|
1221
|
+
</div>
|
|
1082
1222
|
</TableCell>
|
|
1083
1223
|
</TableRow>
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1224
|
+
|
|
1225
|
+
{group.reversal ? (
|
|
1226
|
+
<TableRow>
|
|
1227
|
+
<TableCell className="pl-8">
|
|
1228
|
+
{formatarData(group.reversal.paidAt)}
|
|
1229
|
+
</TableCell>
|
|
1230
|
+
<TableCell>
|
|
1231
|
+
<span className="rounded-md border px-2 py-1 text-xs font-medium">
|
|
1232
|
+
REVERSAL
|
|
1233
|
+
</span>
|
|
1234
|
+
</TableCell>
|
|
1235
|
+
<TableCell>
|
|
1236
|
+
<span className="rounded-md bg-muted px-2 py-1 text-xs font-medium text-muted-foreground">
|
|
1237
|
+
ESTORNO
|
|
1238
|
+
</span>
|
|
1239
|
+
</TableCell>
|
|
1240
|
+
<TableCell className="text-right font-medium text-destructive">
|
|
1241
|
+
-
|
|
1242
|
+
<Money
|
|
1243
|
+
value={
|
|
1244
|
+
Math.abs(group.reversal.amountCents || 0) /
|
|
1245
|
+
100
|
|
1246
|
+
}
|
|
1247
|
+
/>
|
|
1248
|
+
</TableCell>
|
|
1249
|
+
<TableCell>-</TableCell>
|
|
1250
|
+
<TableCell>-</TableCell>
|
|
1251
|
+
<TableCell>-</TableCell>
|
|
1252
|
+
<TableCell className="text-right text-xs text-muted-foreground">
|
|
1253
|
+
{group.reversal.memo || '-'}
|
|
1254
|
+
</TableCell>
|
|
1255
|
+
</TableRow>
|
|
1256
|
+
) : null}
|
|
1257
|
+
|
|
1258
|
+
{isExpanded ? (
|
|
1259
|
+
<TableRow>
|
|
1260
|
+
<TableCell colSpan={8}>
|
|
1261
|
+
<div className="rounded-md border bg-muted/20 p-3">
|
|
1262
|
+
<p className="mb-2 text-xs font-medium text-muted-foreground">
|
|
1263
|
+
Allocations
|
|
1264
|
+
</p>
|
|
1265
|
+
<div className="space-y-1">
|
|
1266
|
+
{group.allocations.map((allocation) => (
|
|
1267
|
+
<div
|
|
1268
|
+
key={`${normalId}-${allocation.installmentId}`}
|
|
1269
|
+
className="flex items-center justify-between text-sm"
|
|
1270
|
+
>
|
|
1271
|
+
<span>
|
|
1272
|
+
Parcela #{allocation.installmentSeq}
|
|
1273
|
+
</span>
|
|
1274
|
+
<span className="font-medium">
|
|
1275
|
+
+
|
|
1276
|
+
<Money
|
|
1277
|
+
value={
|
|
1278
|
+
Math.abs(
|
|
1279
|
+
Number(
|
|
1280
|
+
allocation.amountCents || 0
|
|
1281
|
+
)
|
|
1282
|
+
) / 100
|
|
1283
|
+
}
|
|
1284
|
+
/>
|
|
1285
|
+
</span>
|
|
1286
|
+
</div>
|
|
1287
|
+
))}
|
|
1288
|
+
</div>
|
|
1289
|
+
</div>
|
|
1290
|
+
</TableCell>
|
|
1291
|
+
</TableRow>
|
|
1292
|
+
) : null}
|
|
1293
|
+
</Fragment>
|
|
1294
|
+
);
|
|
1295
|
+
})}
|
|
1087
1296
|
</TableBody>
|
|
1088
1297
|
</Table>
|
|
1089
1298
|
) : (
|