@hed-hog/finance 0.0.304 → 0.0.306
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/hedhog/frontend/app/_components/finance-entity-field-with-create.tsx.ejs +130 -465
- package/hedhog/frontend/app/_components/finance-layout.tsx.ejs +135 -131
- package/hedhog/frontend/app/accounts-payable/installments/page.tsx.ejs +270 -14
- package/hedhog/frontend/app/accounts-receivable/collections-default/page.tsx.ejs +175 -4
- package/hedhog/frontend/app/accounts-receivable/installments/page.tsx.ejs +271 -19
- package/hedhog/frontend/app/administration/categories/page.tsx.ejs +97 -11
- package/hedhog/frontend/app/administration/cost-centers/page.tsx.ejs +88 -8
- package/hedhog/frontend/app/administration/period-close/page.tsx.ejs +94 -8
- package/hedhog/frontend/app/cash-and-banks/bank-accounts/page.tsx.ejs +163 -42
- package/hedhog/frontend/app/cash-and-banks/bank-reconciliation/page.tsx.ejs +135 -57
- package/hedhog/frontend/app/cash-and-banks/statements/page.tsx.ejs +202 -49
- package/hedhog/frontend/app/cash-and-banks/transfers/page.tsx.ejs +107 -22
- package/hedhog/frontend/messages/en.json +174 -221
- package/hedhog/frontend/messages/pt.json +174 -221
- package/package.json +4 -4
- package/hedhog/frontend/app/_components/person-field-with-create.tsx.ejs +0 -734
|
@@ -46,8 +46,12 @@ import {
|
|
|
46
46
|
SheetHeader,
|
|
47
47
|
SheetTitle,
|
|
48
48
|
} from '@/components/ui/sheet';
|
|
49
|
+
import { useFormDraft } from '@/hooks/use-form-draft';
|
|
50
|
+
import { formatDateTime } from '@/lib/format-date';
|
|
49
51
|
import { useApp, useQuery } from '@hed-hog/next-app-provider';
|
|
50
52
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
53
|
+
import { formatDistanceToNow } from 'date-fns';
|
|
54
|
+
import { enUS, ptBR } from 'date-fns/locale';
|
|
51
55
|
import {
|
|
52
56
|
Building2,
|
|
53
57
|
Eye,
|
|
@@ -64,8 +68,8 @@ import {
|
|
|
64
68
|
} from 'lucide-react';
|
|
65
69
|
import { useTranslations } from 'next-intl';
|
|
66
70
|
import Link from 'next/link';
|
|
67
|
-
import { useEffect, useRef, useState, type ChangeEvent } from 'react';
|
|
68
|
-
import { useForm } from 'react-hook-form';
|
|
71
|
+
import { useEffect, useMemo, useRef, useState, type ChangeEvent } from 'react';
|
|
72
|
+
import { useForm, useWatch } from 'react-hook-form';
|
|
69
73
|
import { z } from 'zod';
|
|
70
74
|
import {
|
|
71
75
|
FinancePageSection,
|
|
@@ -103,6 +107,16 @@ type UploadedFilePayload = {
|
|
|
103
107
|
id?: number | string | null;
|
|
104
108
|
};
|
|
105
109
|
|
|
110
|
+
type BankAccountDraftPayload = {
|
|
111
|
+
mode: 'create' | 'edit';
|
|
112
|
+
accountId: string | null;
|
|
113
|
+
values: BankAccountFormValues;
|
|
114
|
+
logoFileId: number | null;
|
|
115
|
+
logoPreviewUrl: string | null;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const BANK_ACCOUNT_FORM_DRAFT_STORAGE_KEY = 'finance-bank-account-form-draft';
|
|
119
|
+
|
|
106
120
|
function BankAccountLogo({
|
|
107
121
|
account,
|
|
108
122
|
icon: Icon,
|
|
@@ -144,13 +158,14 @@ function NovaContaSheet({
|
|
|
144
158
|
onEditingAccountChange,
|
|
145
159
|
}: {
|
|
146
160
|
t: ReturnType<typeof useTranslations>;
|
|
147
|
-
onCreated: () => Promise<
|
|
161
|
+
onCreated: () => Promise<unknown> | void;
|
|
148
162
|
open: boolean;
|
|
149
163
|
onOpenChange: (open: boolean) => void;
|
|
150
164
|
editingAccount: BankAccount | null;
|
|
151
165
|
onEditingAccountChange: (account: BankAccount | null) => void;
|
|
152
166
|
}) {
|
|
153
|
-
const { request, showToastHandler } =
|
|
167
|
+
const { request, showToastHandler, currentLocaleCode, getSettingValue } =
|
|
168
|
+
useApp();
|
|
154
169
|
|
|
155
170
|
const createSuccessMessage = t.has('messages.createSuccess')
|
|
156
171
|
? t('messages.createSuccess')
|
|
@@ -201,6 +216,80 @@ function NovaContaSheet({
|
|
|
201
216
|
const [isUploadingLogo, setIsUploadingLogo] = useState(false);
|
|
202
217
|
const [logoUploadProgress, setLogoUploadProgress] = useState(0);
|
|
203
218
|
const logoInputRef = useRef<HTMLInputElement | null>(null);
|
|
219
|
+
const watchedFormValues = useWatch({
|
|
220
|
+
control: form.control,
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
const hasDraftContent = useMemo(
|
|
224
|
+
() =>
|
|
225
|
+
Boolean(
|
|
226
|
+
(watchedFormValues.banco ?? '').trim() ||
|
|
227
|
+
(watchedFormValues.agencia ?? '').trim() ||
|
|
228
|
+
(watchedFormValues.conta ?? '').trim() ||
|
|
229
|
+
(watchedFormValues.tipo ?? '').trim() ||
|
|
230
|
+
(watchedFormValues.descricao ?? '').trim() ||
|
|
231
|
+
(watchedFormValues.saldoInicial ?? 0) > 0 ||
|
|
232
|
+
logoFileId != null
|
|
233
|
+
),
|
|
234
|
+
[watchedFormValues, logoFileId]
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
const draftValue = useMemo<BankAccountDraftPayload>(
|
|
238
|
+
() => ({
|
|
239
|
+
mode: editingAccount ? 'edit' : 'create',
|
|
240
|
+
accountId: editingAccount?.id ?? null,
|
|
241
|
+
values: {
|
|
242
|
+
banco: watchedFormValues.banco ?? '',
|
|
243
|
+
agencia: watchedFormValues.agencia ?? '',
|
|
244
|
+
conta: watchedFormValues.conta ?? '',
|
|
245
|
+
tipo: watchedFormValues.tipo ?? '',
|
|
246
|
+
descricao: watchedFormValues.descricao ?? '',
|
|
247
|
+
logoFileId: logoFileId ?? null,
|
|
248
|
+
saldoInicial: watchedFormValues.saldoInicial ?? 0,
|
|
249
|
+
},
|
|
250
|
+
logoFileId: logoFileId ?? null,
|
|
251
|
+
logoPreviewUrl,
|
|
252
|
+
}),
|
|
253
|
+
[editingAccount, logoFileId, logoPreviewUrl, watchedFormValues]
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
const {
|
|
257
|
+
clearDraft,
|
|
258
|
+
loadDraft,
|
|
259
|
+
hasDraft,
|
|
260
|
+
savedAt: draftSavedAt,
|
|
261
|
+
} = useFormDraft<BankAccountDraftPayload>({
|
|
262
|
+
storageKey: BANK_ACCOUNT_FORM_DRAFT_STORAGE_KEY,
|
|
263
|
+
value: draftValue,
|
|
264
|
+
hasData: hasDraftContent,
|
|
265
|
+
enabled: open,
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
const draftStatusContent = useMemo(() => {
|
|
269
|
+
if (!hasDraft || !draftSavedAt) {
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const savedDate = new Date(draftSavedAt);
|
|
274
|
+
if (Number.isNaN(savedDate.getTime())) {
|
|
275
|
+
return null;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const locale = currentLocaleCode.startsWith('pt') ? ptBR : enUS;
|
|
279
|
+
const relativeLabel = formatDistanceToNow(savedDate, {
|
|
280
|
+
addSuffix: true,
|
|
281
|
+
locale,
|
|
282
|
+
});
|
|
283
|
+
const absoluteLabel = formatDateTime(
|
|
284
|
+
savedDate,
|
|
285
|
+
getSettingValue,
|
|
286
|
+
currentLocaleCode
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
return currentLocaleCode.startsWith('pt')
|
|
290
|
+
? `Rascunho salvo ${relativeLabel} • Último salvamento: ${absoluteLabel}`
|
|
291
|
+
: `Draft saved ${relativeLabel} • Last saved: ${absoluteLabel}`;
|
|
292
|
+
}, [draftSavedAt, currentLocaleCode, getSettingValue, hasDraft]);
|
|
204
293
|
|
|
205
294
|
const getLogoUrl = (fileId?: number | null) => {
|
|
206
295
|
if (typeof fileId !== 'number' || fileId <= 0) {
|
|
@@ -342,45 +431,67 @@ function NovaContaSheet({
|
|
|
342
431
|
return;
|
|
343
432
|
}
|
|
344
433
|
|
|
434
|
+
const storedDraft = loadDraft();
|
|
435
|
+
|
|
345
436
|
if (editingAccount) {
|
|
346
|
-
const
|
|
437
|
+
const shouldRestoreDraft =
|
|
438
|
+
storedDraft?.payload.mode === 'edit' &&
|
|
439
|
+
storedDraft.payload.accountId === editingAccount.id;
|
|
440
|
+
const currentLogoFileId = shouldRestoreDraft
|
|
441
|
+
? storedDraft.payload.logoFileId
|
|
442
|
+
: (editingAccount.logoFileId ?? null);
|
|
347
443
|
|
|
348
444
|
setLogoFileId(currentLogoFileId);
|
|
349
|
-
setPersistedLogoFileId(
|
|
445
|
+
setPersistedLogoFileId(editingAccount.logoFileId ?? null);
|
|
350
446
|
setLogoPreviewUrl(
|
|
351
|
-
|
|
352
|
-
?
|
|
353
|
-
:
|
|
447
|
+
shouldRestoreDraft
|
|
448
|
+
? storedDraft.payload.logoPreviewUrl
|
|
449
|
+
: currentLogoFileId
|
|
450
|
+
? `${getLogoUrl(currentLogoFileId)}?ts=${Date.now()}`
|
|
451
|
+
: null
|
|
354
452
|
);
|
|
355
453
|
setLogoUploadProgress(0);
|
|
356
454
|
|
|
357
|
-
form.reset(
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
455
|
+
form.reset(
|
|
456
|
+
shouldRestoreDraft
|
|
457
|
+
? storedDraft.payload.values
|
|
458
|
+
: {
|
|
459
|
+
banco: editingAccount.banco,
|
|
460
|
+
agencia:
|
|
461
|
+
editingAccount.agencia === '-' ? '' : editingAccount.agencia,
|
|
462
|
+
conta: editingAccount.conta === '-' ? '' : editingAccount.conta,
|
|
463
|
+
tipo: editingAccount.tipo,
|
|
464
|
+
descricao: editingAccount.descricao,
|
|
465
|
+
logoFileId: currentLogoFileId,
|
|
466
|
+
saldoInicial: editingAccount.saldoAtual,
|
|
467
|
+
}
|
|
468
|
+
);
|
|
366
469
|
return;
|
|
367
470
|
}
|
|
368
471
|
|
|
369
|
-
|
|
472
|
+
const shouldRestoreDraft = storedDraft?.payload.mode === 'create';
|
|
473
|
+
|
|
474
|
+
setLogoFileId(shouldRestoreDraft ? storedDraft.payload.logoFileId : null);
|
|
370
475
|
setPersistedLogoFileId(null);
|
|
371
|
-
setLogoPreviewUrl(
|
|
476
|
+
setLogoPreviewUrl(
|
|
477
|
+
shouldRestoreDraft ? storedDraft.payload.logoPreviewUrl : null
|
|
478
|
+
);
|
|
372
479
|
setLogoUploadProgress(0);
|
|
373
480
|
|
|
374
|
-
form.reset(
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
481
|
+
form.reset(
|
|
482
|
+
shouldRestoreDraft
|
|
483
|
+
? storedDraft.payload.values
|
|
484
|
+
: {
|
|
485
|
+
banco: '',
|
|
486
|
+
agencia: '',
|
|
487
|
+
conta: '',
|
|
488
|
+
tipo: '',
|
|
489
|
+
descricao: '',
|
|
490
|
+
logoFileId: null,
|
|
491
|
+
saldoInicial: 0,
|
|
492
|
+
}
|
|
493
|
+
);
|
|
494
|
+
}, [editingAccount, form, loadDraft, open]);
|
|
384
495
|
|
|
385
496
|
const handleSubmit = async (values: BankAccountFormValues) => {
|
|
386
497
|
const nextLogoFileId = values.logoFileId ?? null;
|
|
@@ -425,6 +536,7 @@ function NovaContaSheet({
|
|
|
425
536
|
await deleteFileById(previousPersistedLogoId);
|
|
426
537
|
}
|
|
427
538
|
|
|
539
|
+
clearDraft();
|
|
428
540
|
setPersistedLogoFileId(nextLogoFileId);
|
|
429
541
|
setLogoFileId(nextLogoFileId);
|
|
430
542
|
setLogoPreviewUrl(
|
|
@@ -455,7 +567,9 @@ function NovaContaSheet({
|
|
|
455
567
|
};
|
|
456
568
|
|
|
457
569
|
const handleCancel = () => {
|
|
458
|
-
|
|
570
|
+
if (!hasDraftContent) {
|
|
571
|
+
void cleanupUnsavedLogo();
|
|
572
|
+
}
|
|
459
573
|
form.reset();
|
|
460
574
|
onEditingAccountChange(null);
|
|
461
575
|
onOpenChange(false);
|
|
@@ -465,7 +579,7 @@ function NovaContaSheet({
|
|
|
465
579
|
<Sheet
|
|
466
580
|
open={open}
|
|
467
581
|
onOpenChange={(nextOpen) => {
|
|
468
|
-
if (!nextOpen) {
|
|
582
|
+
if (!nextOpen && !hasDraftContent) {
|
|
469
583
|
void cleanupUnsavedLogo();
|
|
470
584
|
}
|
|
471
585
|
|
|
@@ -696,16 +810,23 @@ function NovaContaSheet({
|
|
|
696
810
|
</FinanceSheetSection>
|
|
697
811
|
</FinanceSheetBody>
|
|
698
812
|
|
|
699
|
-
<div className="
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
813
|
+
<div className="border-t px-4 py-4 sm:px-6">
|
|
814
|
+
{draftStatusContent ? (
|
|
815
|
+
<p className="mb-3 text-xs text-muted-foreground">
|
|
816
|
+
{draftStatusContent}
|
|
817
|
+
</p>
|
|
818
|
+
) : null}
|
|
819
|
+
<div className="flex justify-end gap-2">
|
|
820
|
+
<Button type="button" variant="outline" onClick={handleCancel}>
|
|
821
|
+
{t('common.cancel')}
|
|
822
|
+
</Button>
|
|
823
|
+
<Button
|
|
824
|
+
type="submit"
|
|
825
|
+
disabled={form.formState.isSubmitting || isUploadingLogo}
|
|
826
|
+
>
|
|
827
|
+
{t('common.save')}
|
|
828
|
+
</Button>
|
|
829
|
+
</div>
|
|
709
830
|
</div>
|
|
710
831
|
</form>
|
|
711
832
|
</Form>
|
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
import { Badge } from '@/components/ui/badge';
|
|
16
16
|
import { Button } from '@/components/ui/button';
|
|
17
17
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
18
|
-
import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
|
|
19
18
|
import { Checkbox } from '@/components/ui/checkbox';
|
|
20
19
|
import {
|
|
21
20
|
Form,
|
|
@@ -27,6 +26,7 @@ import {
|
|
|
27
26
|
} from '@/components/ui/form';
|
|
28
27
|
import { Input } from '@/components/ui/input';
|
|
29
28
|
import { InputMoney } from '@/components/ui/input-money';
|
|
29
|
+
import { KpiCardsGrid } from '@/components/ui/kpi-cards-grid';
|
|
30
30
|
import { Money } from '@/components/ui/money';
|
|
31
31
|
import {
|
|
32
32
|
Select,
|
|
@@ -43,13 +43,17 @@ import {
|
|
|
43
43
|
SheetTitle,
|
|
44
44
|
} from '@/components/ui/sheet';
|
|
45
45
|
import { StatusBadge } from '@/components/ui/status-badge';
|
|
46
|
+
import { useFormDraft } from '@/hooks/use-form-draft';
|
|
47
|
+
import { formatDateTime } from '@/lib/format-date';
|
|
46
48
|
import { useApp, useQuery } from '@hed-hog/next-app-provider';
|
|
47
49
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
50
|
+
import { formatDistanceToNow } from 'date-fns';
|
|
51
|
+
import { enUS, ptBR } from 'date-fns/locale';
|
|
48
52
|
import { Check, DollarSign, Link2, RefreshCw, Trash2 } from 'lucide-react';
|
|
49
53
|
import { useTranslations } from 'next-intl';
|
|
50
54
|
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
|
|
51
55
|
import { useEffect, useMemo, useState } from 'react';
|
|
52
|
-
import { useForm } from 'react-hook-form';
|
|
56
|
+
import { useForm, useWatch } from 'react-hook-form';
|
|
53
57
|
import { z } from 'zod';
|
|
54
58
|
import { formatarData, formatarMoeda } from '../../_lib/formatters';
|
|
55
59
|
|
|
@@ -119,6 +123,14 @@ const ajusteSchema = z.object({
|
|
|
119
123
|
|
|
120
124
|
type AjusteFormValues = z.infer<typeof ajusteSchema>;
|
|
121
125
|
|
|
126
|
+
type ReconciliationAdjustmentDraftPayload = {
|
|
127
|
+
bankAccountId: string;
|
|
128
|
+
values: AjusteFormValues;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const RECONCILIATION_ADJUSTMENT_DRAFT_STORAGE_KEY =
|
|
132
|
+
'finance-bank-reconciliation-adjustment-draft';
|
|
133
|
+
|
|
122
134
|
function CriarAjusteSheet({
|
|
123
135
|
t,
|
|
124
136
|
contaFilter,
|
|
@@ -128,7 +140,8 @@ function CriarAjusteSheet({
|
|
|
128
140
|
contaFilter: string;
|
|
129
141
|
onCreated: () => Promise<void> | void;
|
|
130
142
|
}) {
|
|
131
|
-
const { request, showToastHandler } =
|
|
143
|
+
const { request, showToastHandler, currentLocaleCode, getSettingValue } =
|
|
144
|
+
useApp();
|
|
132
145
|
const [open, setOpen] = useState(false);
|
|
133
146
|
|
|
134
147
|
const form = useForm<AjusteFormValues>({
|
|
@@ -140,17 +153,76 @@ function CriarAjusteSheet({
|
|
|
140
153
|
},
|
|
141
154
|
});
|
|
142
155
|
|
|
156
|
+
const watchedValues = useWatch({
|
|
157
|
+
control: form.control,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
const {
|
|
161
|
+
clearDraft,
|
|
162
|
+
loadDraft,
|
|
163
|
+
hasDraft,
|
|
164
|
+
savedAt: draftSavedAt,
|
|
165
|
+
} = useFormDraft<ReconciliationAdjustmentDraftPayload>({
|
|
166
|
+
storageKey: RECONCILIATION_ADJUSTMENT_DRAFT_STORAGE_KEY,
|
|
167
|
+
value: {
|
|
168
|
+
bankAccountId: contaFilter,
|
|
169
|
+
values: {
|
|
170
|
+
type: watchedValues.type ?? '',
|
|
171
|
+
value: watchedValues.value ?? 0,
|
|
172
|
+
description: watchedValues.description ?? '',
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
hasData: Boolean(
|
|
176
|
+
(watchedValues.type ?? '').trim() ||
|
|
177
|
+
(watchedValues.description ?? '').trim() ||
|
|
178
|
+
(watchedValues.value ?? 0) > 0
|
|
179
|
+
),
|
|
180
|
+
enabled: open,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const draftStatusContent = useMemo(() => {
|
|
184
|
+
if (!hasDraft || !draftSavedAt) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const savedDate = new Date(draftSavedAt);
|
|
189
|
+
if (Number.isNaN(savedDate.getTime())) {
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const locale = currentLocaleCode.startsWith('pt') ? ptBR : enUS;
|
|
194
|
+
const relativeLabel = formatDistanceToNow(savedDate, {
|
|
195
|
+
addSuffix: true,
|
|
196
|
+
locale,
|
|
197
|
+
});
|
|
198
|
+
const absoluteLabel = formatDateTime(
|
|
199
|
+
savedDate,
|
|
200
|
+
getSettingValue,
|
|
201
|
+
currentLocaleCode
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
return currentLocaleCode.startsWith('pt')
|
|
205
|
+
? `Rascunho salvo ${relativeLabel} • Último salvamento: ${absoluteLabel}`
|
|
206
|
+
: `Draft saved ${relativeLabel} • Last saved: ${absoluteLabel}`;
|
|
207
|
+
}, [draftSavedAt, currentLocaleCode, getSettingValue, hasDraft]);
|
|
208
|
+
|
|
143
209
|
useEffect(() => {
|
|
144
210
|
if (!open) {
|
|
145
211
|
return;
|
|
146
212
|
}
|
|
147
213
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
214
|
+
const storedDraft = loadDraft();
|
|
215
|
+
|
|
216
|
+
form.reset(
|
|
217
|
+
storedDraft?.payload.bankAccountId === contaFilter
|
|
218
|
+
? storedDraft.payload.values
|
|
219
|
+
: {
|
|
220
|
+
type: '',
|
|
221
|
+
value: 0,
|
|
222
|
+
description: '',
|
|
223
|
+
}
|
|
224
|
+
);
|
|
225
|
+
}, [contaFilter, form, loadDraft, open]);
|
|
154
226
|
|
|
155
227
|
const handleSubmit = async (values: AjusteFormValues) => {
|
|
156
228
|
if (!contaFilter) {
|
|
@@ -170,6 +242,7 @@ function CriarAjusteSheet({
|
|
|
170
242
|
},
|
|
171
243
|
});
|
|
172
244
|
|
|
245
|
+
clearDraft();
|
|
173
246
|
await onCreated();
|
|
174
247
|
showToastHandler?.('success', 'Ajuste criado com sucesso');
|
|
175
248
|
setOpen(false);
|
|
@@ -267,6 +340,12 @@ function CriarAjusteSheet({
|
|
|
267
340
|
)}
|
|
268
341
|
/>
|
|
269
342
|
|
|
343
|
+
{draftStatusContent ? (
|
|
344
|
+
<p className="text-xs text-muted-foreground">
|
|
345
|
+
{draftStatusContent}
|
|
346
|
+
</p>
|
|
347
|
+
) : null}
|
|
348
|
+
|
|
270
349
|
<div className="flex justify-end gap-2 pt-4">
|
|
271
350
|
<Button
|
|
272
351
|
type="button"
|
|
@@ -294,7 +373,9 @@ export default function ConciliacaoPage() {
|
|
|
294
373
|
const searchParams = useSearchParams();
|
|
295
374
|
const bankAccountIdFromUrl = searchParams.get('bank_account_id');
|
|
296
375
|
|
|
297
|
-
const [contaFilter, setContaFilter] = useState<string>(
|
|
376
|
+
const [contaFilter, setContaFilter] = useState<string>(
|
|
377
|
+
() => bankAccountIdFromUrl || ''
|
|
378
|
+
);
|
|
298
379
|
const [selectedExtrato, setSelectedExtrato] = useState<string | null>(null);
|
|
299
380
|
const [selectedTitulo, setSelectedTitulo] = useState<string | null>(null);
|
|
300
381
|
const [reconciliationToUndo, setReconciliationToUndo] = useState<
|
|
@@ -313,50 +394,50 @@ export default function ConciliacaoPage() {
|
|
|
313
394
|
},
|
|
314
395
|
});
|
|
315
396
|
|
|
316
|
-
|
|
397
|
+
const activeContaFilter = useMemo(() => {
|
|
317
398
|
const firstAccount = contasBancarias[0];
|
|
318
399
|
|
|
319
400
|
if (!firstAccount) {
|
|
320
|
-
return;
|
|
401
|
+
return '';
|
|
321
402
|
}
|
|
322
403
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
contasBancarias.some((account) => account.id ===
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
: firstAccount.id;
|
|
404
|
+
if (
|
|
405
|
+
contaFilter &&
|
|
406
|
+
contasBancarias.some((account) => account.id === contaFilter)
|
|
407
|
+
) {
|
|
408
|
+
return contaFilter;
|
|
409
|
+
}
|
|
330
410
|
|
|
331
|
-
if (
|
|
332
|
-
|
|
411
|
+
if (
|
|
412
|
+
bankAccountIdFromUrl &&
|
|
413
|
+
contasBancarias.some((account) => account.id === bankAccountIdFromUrl)
|
|
414
|
+
) {
|
|
415
|
+
return bankAccountIdFromUrl;
|
|
333
416
|
}
|
|
334
417
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
418
|
+
return firstAccount.id;
|
|
419
|
+
}, [bankAccountIdFromUrl, contaFilter, contasBancarias]);
|
|
420
|
+
|
|
421
|
+
useEffect(() => {
|
|
422
|
+
if (!activeContaFilter || bankAccountIdFromUrl === activeContaFilter) {
|
|
423
|
+
return;
|
|
339
424
|
}
|
|
340
|
-
}, [
|
|
341
|
-
bankAccountIdFromUrl,
|
|
342
|
-
contaFilter,
|
|
343
|
-
contasBancarias,
|
|
344
|
-
pathname,
|
|
345
|
-
router,
|
|
346
|
-
searchParams,
|
|
347
|
-
]);
|
|
348
425
|
|
|
426
|
+
const params = new URLSearchParams(searchParams.toString());
|
|
427
|
+
params.set('bank_account_id', activeContaFilter);
|
|
428
|
+
router.replace(`${pathname}?${params.toString()}`);
|
|
429
|
+
}, [activeContaFilter, bankAccountIdFromUrl, pathname, router, searchParams]);
|
|
349
430
|
const { data: extratos = [], refetch: refetchExtratos } = useQuery<
|
|
350
431
|
Statement[]
|
|
351
432
|
>({
|
|
352
|
-
queryKey: ['finance-statements',
|
|
433
|
+
queryKey: ['finance-statements', activeContaFilter],
|
|
353
434
|
queryFn: async () => {
|
|
354
|
-
if (!
|
|
435
|
+
if (!activeContaFilter) {
|
|
355
436
|
return [];
|
|
356
437
|
}
|
|
357
438
|
|
|
358
439
|
const response = await request({
|
|
359
|
-
url: `/finance/statements?bank_account_id=${
|
|
440
|
+
url: `/finance/statements?bank_account_id=${activeContaFilter}`,
|
|
360
441
|
method: 'GET',
|
|
361
442
|
});
|
|
362
443
|
|
|
@@ -366,9 +447,9 @@ export default function ConciliacaoPage() {
|
|
|
366
447
|
|
|
367
448
|
const { data: reconciliationSummary, refetch: refetchReconciliationSummary } =
|
|
368
449
|
useQuery<BankReconciliationSummary>({
|
|
369
|
-
queryKey: ['finance-bank-reconciliation-summary',
|
|
450
|
+
queryKey: ['finance-bank-reconciliation-summary', activeContaFilter],
|
|
370
451
|
queryFn: async () => {
|
|
371
|
-
if (!
|
|
452
|
+
if (!activeContaFilter) {
|
|
372
453
|
return {
|
|
373
454
|
discrepancies: 0,
|
|
374
455
|
difference: 0,
|
|
@@ -376,7 +457,7 @@ export default function ConciliacaoPage() {
|
|
|
376
457
|
}
|
|
377
458
|
|
|
378
459
|
const response = await request<BankReconciliationSummary>({
|
|
379
|
-
url: `/finance/bank-reconciliation/summary?bank_account_id=${
|
|
460
|
+
url: `/finance/bank-reconciliation/summary?bank_account_id=${activeContaFilter}`,
|
|
380
461
|
method: 'GET',
|
|
381
462
|
});
|
|
382
463
|
|
|
@@ -427,10 +508,10 @@ export default function ConciliacaoPage() {
|
|
|
427
508
|
);
|
|
428
509
|
|
|
429
510
|
const extratosFiltered = extratosPendentes.filter(
|
|
430
|
-
(e) => e.contaBancariaId ===
|
|
511
|
+
(e) => e.contaBancariaId === activeContaFilter
|
|
431
512
|
);
|
|
432
513
|
const extratosConciliadosFiltered = extratosConciliados.filter(
|
|
433
|
-
(e) => e.contaBancariaId ===
|
|
514
|
+
(e) => e.contaBancariaId === activeContaFilter
|
|
434
515
|
);
|
|
435
516
|
|
|
436
517
|
const titulosAbertos = useMemo<OpenTitleItem[]>(() => {
|
|
@@ -480,24 +561,21 @@ export default function ConciliacaoPage() {
|
|
|
480
561
|
(titulo) => titulo.id === selectedTitulo
|
|
481
562
|
);
|
|
482
563
|
|
|
483
|
-
const titulosCompativeis =
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
? titulo.tipo === 'pagar'
|
|
491
|
-
: titulo.tipo === 'receber'
|
|
492
|
-
);
|
|
493
|
-
}, [selectedExtratoItem, titulosAbertos]);
|
|
564
|
+
const titulosCompativeis = !selectedExtratoItem
|
|
565
|
+
? titulosAbertos
|
|
566
|
+
: titulosAbertos.filter((titulo) =>
|
|
567
|
+
selectedExtratoItem.tipo === 'saida'
|
|
568
|
+
? titulo.tipo === 'pagar'
|
|
569
|
+
: titulo.tipo === 'receber'
|
|
570
|
+
);
|
|
494
571
|
|
|
495
572
|
const totalConciliado = extratos.filter(
|
|
496
573
|
(e) =>
|
|
497
|
-
e.contaBancariaId ===
|
|
574
|
+
e.contaBancariaId === activeContaFilter &&
|
|
575
|
+
e.statusConciliacao === 'conciliado'
|
|
498
576
|
).length;
|
|
499
577
|
const totalExtratoConta = extratos.filter(
|
|
500
|
-
(e) => e.contaBancariaId ===
|
|
578
|
+
(e) => e.contaBancariaId === activeContaFilter
|
|
501
579
|
).length;
|
|
502
580
|
const percentualConciliado =
|
|
503
581
|
totalExtratoConta > 0
|
|
@@ -557,7 +635,7 @@ export default function ConciliacaoPage() {
|
|
|
557
635
|
};
|
|
558
636
|
|
|
559
637
|
const handleReconcile = async () => {
|
|
560
|
-
if (!selectedExtratoItem || !selectedTituloItem || !
|
|
638
|
+
if (!selectedExtratoItem || !selectedTituloItem || !activeContaFilter) {
|
|
561
639
|
return;
|
|
562
640
|
}
|
|
563
641
|
|
|
@@ -618,7 +696,7 @@ export default function ConciliacaoPage() {
|
|
|
618
696
|
|
|
619
697
|
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
|
620
698
|
<Select
|
|
621
|
-
value={
|
|
699
|
+
value={activeContaFilter}
|
|
622
700
|
onValueChange={(value) => {
|
|
623
701
|
setContaFilter(value);
|
|
624
702
|
setSelectedExtrato(null);
|
|
@@ -644,7 +722,7 @@ export default function ConciliacaoPage() {
|
|
|
644
722
|
<div className="flex gap-2">
|
|
645
723
|
<CriarAjusteSheet
|
|
646
724
|
t={t}
|
|
647
|
-
contaFilter={
|
|
725
|
+
contaFilter={activeContaFilter}
|
|
648
726
|
onCreated={handleRefreshData}
|
|
649
727
|
/>
|
|
650
728
|
<Button
|