@hed-hog/finance 0.0.274 → 0.0.276

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 (40) hide show
  1. package/README.md +228 -126
  2. package/dist/dto/create-bank-reconciliation.dto.d.ts +8 -0
  3. package/dist/dto/create-bank-reconciliation.dto.d.ts.map +1 -0
  4. package/dist/dto/create-bank-reconciliation.dto.js +43 -0
  5. package/dist/dto/create-bank-reconciliation.dto.js.map +1 -0
  6. package/dist/finance-data.controller.d.ts +2 -0
  7. package/dist/finance-data.controller.d.ts.map +1 -1
  8. package/dist/finance-statements.controller.d.ts +42 -0
  9. package/dist/finance-statements.controller.d.ts.map +1 -1
  10. package/dist/finance-statements.controller.js +13 -0
  11. package/dist/finance-statements.controller.js.map +1 -1
  12. package/dist/finance.service.d.ts +44 -0
  13. package/dist/finance.service.d.ts.map +1 -1
  14. package/dist/finance.service.js +98 -9
  15. package/dist/finance.service.js.map +1 -1
  16. package/hedhog/data/route.yaml +9 -0
  17. package/hedhog/frontend/app/_components/person-field-with-create.tsx.ejs +126 -126
  18. package/hedhog/frontend/app/accounts-payable/approvals/page.tsx.ejs +373 -373
  19. package/hedhog/frontend/app/accounts-payable/installments/[id]/page.tsx.ejs +1270 -1270
  20. package/hedhog/frontend/app/accounts-receivable/installments/[id]/page.tsx.ejs +982 -982
  21. package/hedhog/frontend/app/cash-and-banks/bank-accounts/page.tsx.ejs +686 -686
  22. package/hedhog/frontend/app/cash-and-banks/bank-reconciliation/page.tsx.ejs +152 -32
  23. package/hedhog/frontend/app/cash-and-banks/statements/page.tsx.ejs +986 -986
  24. package/hedhog/frontend/app/cash-and-banks/transfers/page.tsx.ejs +492 -492
  25. package/hedhog/frontend/app/page.tsx.ejs +372 -372
  26. package/hedhog/frontend/app/planning/cash-flow-forecast/page.tsx.ejs +329 -329
  27. package/hedhog/frontend/app/planning/receivables-calendar/page.tsx.ejs +227 -227
  28. package/hedhog/frontend/app/planning/scenarios/page.tsx.ejs +408 -408
  29. package/hedhog/frontend/messages/en.json +15 -5
  30. package/hedhog/frontend/messages/pt.json +15 -5
  31. package/package.json +7 -7
  32. package/src/dto/create-bank-reconciliation.dto.ts +24 -0
  33. package/src/finance-statements.controller.ts +14 -0
  34. package/src/finance.module.ts +43 -43
  35. package/src/finance.service.ts +118 -0
  36. package/src/index.ts +14 -14
  37. package/dist/finance.controller.d.ts +0 -276
  38. package/dist/finance.controller.d.ts.map +0 -1
  39. package/dist/finance.controller.js +0 -110
  40. package/dist/finance.controller.js.map +0 -1
@@ -1,6 +1,16 @@
1
1
  'use client';
2
2
 
3
3
  import { Page, PageHeader } from '@/components/entity-list';
4
+ import {
5
+ AlertDialog,
6
+ AlertDialogAction,
7
+ AlertDialogCancel,
8
+ AlertDialogContent,
9
+ AlertDialogDescription,
10
+ AlertDialogFooter,
11
+ AlertDialogHeader,
12
+ AlertDialogTitle,
13
+ } from '@/components/ui/alert-dialog';
4
14
  import { Badge } from '@/components/ui/badge';
5
15
  import { Button } from '@/components/ui/button';
6
16
  import {
@@ -40,7 +50,7 @@ import {
40
50
  import { StatusBadge } from '@/components/ui/status-badge';
41
51
  import { useApp, useQuery } from '@hed-hog/next-app-provider';
42
52
  import { zodResolver } from '@hookform/resolvers/zod';
43
- import { Check, DollarSign, Link2, RefreshCw } from 'lucide-react';
53
+ import { Check, DollarSign, Link2, RefreshCw, Trash2 } from 'lucide-react';
44
54
  import { useTranslations } from 'next-intl';
45
55
  import { usePathname, useRouter, useSearchParams } from 'next/navigation';
46
56
  import { useEffect, useMemo, useState } from 'react';
@@ -60,6 +70,8 @@ type Statement = {
60
70
  data: string;
61
71
  descricao: string;
62
72
  valor: number;
73
+ reconciliationId?: string | null;
74
+ settlementId?: string | null;
63
75
  tipo: 'entrada' | 'saida';
64
76
  statusConciliacao:
65
77
  | 'importado'
@@ -290,6 +302,9 @@ export default function ConciliacaoPage() {
290
302
  const [contaFilter, setContaFilter] = useState<string>('');
291
303
  const [selectedExtrato, setSelectedExtrato] = useState<string | null>(null);
292
304
  const [selectedTitulo, setSelectedTitulo] = useState<string | null>(null);
305
+ const [reconciliationToUndo, setReconciliationToUndo] = useState<
306
+ string | null
307
+ >(null);
293
308
 
294
309
  const { data: contasBancarias = [] } = useQuery<BankAccount[]>({
295
310
  queryKey: ['finance-bank-accounts'],
@@ -354,29 +369,30 @@ export default function ConciliacaoPage() {
354
369
  },
355
370
  });
356
371
 
357
- const { data: reconciliationSummary } = useQuery<BankReconciliationSummary>({
358
- queryKey: ['finance-bank-reconciliation-summary', contaFilter],
359
- queryFn: async () => {
360
- if (!contaFilter) {
361
- return {
362
- discrepancies: 0,
363
- difference: 0,
364
- };
365
- }
372
+ const { data: reconciliationSummary, refetch: refetchReconciliationSummary } =
373
+ useQuery<BankReconciliationSummary>({
374
+ queryKey: ['finance-bank-reconciliation-summary', contaFilter],
375
+ queryFn: async () => {
376
+ if (!contaFilter) {
377
+ return {
378
+ discrepancies: 0,
379
+ difference: 0,
380
+ };
381
+ }
366
382
 
367
- const response = await request<BankReconciliationSummary>({
368
- url: `/finance/bank-reconciliation/summary?bank_account_id=${contaFilter}`,
369
- method: 'GET',
370
- });
383
+ const response = await request<BankReconciliationSummary>({
384
+ url: `/finance/bank-reconciliation/summary?bank_account_id=${contaFilter}`,
385
+ method: 'GET',
386
+ });
371
387
 
372
- return (
373
- (response?.data as BankReconciliationSummary) || {
374
- discrepancies: 0,
375
- difference: 0,
376
- }
377
- );
378
- },
379
- });
388
+ return (
389
+ (response?.data as BankReconciliationSummary) || {
390
+ discrepancies: 0,
391
+ difference: 0,
392
+ }
393
+ );
394
+ },
395
+ });
380
396
 
381
397
  const { data: titulosPagar = [], refetch: refetchTitulosPagar } = useQuery<
382
398
  FinancialTitle[]
@@ -411,10 +427,16 @@ export default function ConciliacaoPage() {
411
427
  (e) =>
412
428
  e.statusConciliacao === 'pendente' || e.statusConciliacao === 'importado'
413
429
  );
430
+ const extratosConciliados = extratos.filter(
431
+ (e) => e.statusConciliacao === 'conciliado' && !!e.reconciliationId
432
+ );
414
433
 
415
434
  const extratosFiltered = extratosPendentes.filter(
416
435
  (e) => e.contaBancariaId === contaFilter
417
436
  );
437
+ const extratosConciliadosFiltered = extratosConciliados.filter(
438
+ (e) => e.contaBancariaId === contaFilter
439
+ );
418
440
 
419
441
  const titulosAbertos = useMemo<OpenTitleItem[]>(() => {
420
442
  const payables: OpenTitleItem[] = titulosPagar.flatMap((titulo) =>
@@ -492,6 +514,7 @@ export default function ConciliacaoPage() {
492
514
  refetchExtratos(),
493
515
  refetchTitulosPagar(),
494
516
  refetchTitulosReceber(),
517
+ refetchReconciliationSummary(),
495
518
  ]);
496
519
  };
497
520
 
@@ -500,23 +523,16 @@ export default function ConciliacaoPage() {
500
523
  return;
501
524
  }
502
525
 
503
- const endpointBase =
504
- selectedTituloItem.tipo === 'pagar'
505
- ? '/finance/accounts-payable/installments'
506
- : '/finance/accounts-receivable/installments';
507
-
508
526
  try {
509
527
  await request({
510
- url: `${endpointBase}/${selectedTituloItem.titleId}/settlements`,
528
+ url: '/finance/bank-reconciliations',
511
529
  method: 'POST',
512
530
  data: {
531
+ title_id: Number(selectedTituloItem.titleId),
513
532
  installment_id: Number(selectedTituloItem.installmentId),
514
- amount: Math.abs(selectedExtratoItem.valor),
515
- settled_at: selectedExtratoItem.data,
516
- bank_account_id: Number(contaFilter),
533
+ bank_statement_line_id: Number(selectedExtratoItem.id),
517
534
  payment_channel: 'transferencia',
518
535
  description: selectedExtratoItem.descricao,
519
- bank_statement_line_id: Number(selectedExtratoItem.id),
520
536
  },
521
537
  });
522
538
 
@@ -529,6 +545,27 @@ export default function ConciliacaoPage() {
529
545
  }
530
546
  };
531
547
 
548
+ const handleUnreconcile = async () => {
549
+ if (!reconciliationToUndo) {
550
+ return;
551
+ }
552
+
553
+ try {
554
+ await request({
555
+ url: `/finance/bank-reconciliations/${reconciliationToUndo}`,
556
+ method: 'DELETE',
557
+ });
558
+
559
+ setReconciliationToUndo(null);
560
+ setSelectedExtrato(null);
561
+ setSelectedTitulo(null);
562
+ await handleRefreshData();
563
+ showToastHandler?.('success', t('unreconcile.success'));
564
+ } catch {
565
+ showToastHandler?.('error', t('unreconcile.error'));
566
+ }
567
+ };
568
+
532
569
  return (
533
570
  <Page>
534
571
  <PageHeader
@@ -713,6 +750,65 @@ export default function ConciliacaoPage() {
713
750
  </p>
714
751
  </div>
715
752
  )}
753
+
754
+ {extratosConciliadosFiltered.length > 0 ? (
755
+ <>
756
+ <div className="mt-6 border-t pt-4">
757
+ <p className="text-sm font-medium">
758
+ {t('statement.reconciledTitle')}
759
+ </p>
760
+ <p className="text-xs text-muted-foreground">
761
+ {t('statement.reconciledDescription')}
762
+ </p>
763
+ </div>
764
+
765
+ {extratosConciliadosFiltered.map((extrato) => (
766
+ <div
767
+ key={`reconciled-${extrato.id}`}
768
+ className="flex items-center gap-3 rounded-lg border p-3"
769
+ >
770
+ <div className="flex-1">
771
+ <div className="flex items-center justify-between">
772
+ <span className="text-sm font-medium">
773
+ {extrato.descricao}
774
+ </span>
775
+ <span
776
+ className={`font-semibold ${
777
+ extrato.tipo === 'entrada'
778
+ ? 'text-green-600'
779
+ : 'text-red-600'
780
+ }`}
781
+ >
782
+ {extrato.tipo === 'saida' && '-'}
783
+ {formatarMoeda(Math.abs(extrato.valor))}
784
+ </span>
785
+ </div>
786
+ <div className="flex items-center gap-2 text-xs text-muted-foreground">
787
+ <span>{formatarData(extrato.data)}</span>
788
+ <StatusBadge
789
+ status={extrato.statusConciliacao}
790
+ type="conciliacao"
791
+ />
792
+ </div>
793
+ </div>
794
+ <Button
795
+ type="button"
796
+ variant="outline"
797
+ size="sm"
798
+ onClick={() =>
799
+ setReconciliationToUndo(
800
+ extrato.reconciliationId || null
801
+ )
802
+ }
803
+ disabled={!extrato.reconciliationId}
804
+ >
805
+ <Trash2 className="mr-2 h-4 w-4" />
806
+ {t('unreconcile.action')}
807
+ </Button>
808
+ </div>
809
+ ))}
810
+ </>
811
+ ) : null}
716
812
  </div>
717
813
  </CardContent>
718
814
  </Card>
@@ -820,6 +916,30 @@ export default function ConciliacaoPage() {
820
916
  </CardContent>
821
917
  </Card>
822
918
  )}
919
+
920
+ <AlertDialog
921
+ open={!!reconciliationToUndo}
922
+ onOpenChange={(open) => {
923
+ if (!open) {
924
+ setReconciliationToUndo(null);
925
+ }
926
+ }}
927
+ >
928
+ <AlertDialogContent>
929
+ <AlertDialogHeader>
930
+ <AlertDialogTitle>{t('unreconcile.title')}</AlertDialogTitle>
931
+ <AlertDialogDescription>
932
+ {t('unreconcile.description')}
933
+ </AlertDialogDescription>
934
+ </AlertDialogHeader>
935
+ <AlertDialogFooter>
936
+ <AlertDialogCancel>{t('common.cancel')}</AlertDialogCancel>
937
+ <AlertDialogAction onClick={() => void handleUnreconcile()}>
938
+ {t('unreconcile.confirm')}
939
+ </AlertDialogAction>
940
+ </AlertDialogFooter>
941
+ </AlertDialogContent>
942
+ </AlertDialog>
823
943
  </Page>
824
944
  );
825
945
  }