@spaceinvoices/react-ui 0.4.4 → 0.4.5

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 (147) hide show
  1. package/cli/dist/index.js +1 -1
  2. package/package.json +1 -1
  3. package/src/components/advance-invoices/create/create-advance-invoice-form.tsx +61 -11
  4. package/src/components/advance-invoices/create/locales/de.ts +15 -0
  5. package/src/components/advance-invoices/create/locales/es.ts +15 -0
  6. package/src/components/advance-invoices/create/locales/fr.ts +15 -0
  7. package/src/components/advance-invoices/create/locales/hr.ts +15 -0
  8. package/src/components/advance-invoices/create/locales/it.ts +15 -0
  9. package/src/components/advance-invoices/create/locales/nl.ts +15 -0
  10. package/src/components/advance-invoices/create/locales/pl.ts +15 -0
  11. package/src/components/advance-invoices/create/locales/pt.ts +15 -0
  12. package/src/components/advance-invoices/create/locales/sl.ts +15 -0
  13. package/src/components/advance-invoices/list/list-row-actions.tsx +48 -1
  14. package/src/components/advance-invoices/list/list-table.tsx +21 -1
  15. package/src/components/advance-invoices/list/locales/de.ts +4 -0
  16. package/src/components/advance-invoices/list/locales/en.ts +3 -0
  17. package/src/components/advance-invoices/list/locales/es.ts +4 -0
  18. package/src/components/advance-invoices/list/locales/fr.ts +4 -0
  19. package/src/components/advance-invoices/list/locales/hr.ts +3 -0
  20. package/src/components/advance-invoices/list/locales/it.ts +4 -0
  21. package/src/components/advance-invoices/list/locales/nl.ts +4 -0
  22. package/src/components/advance-invoices/list/locales/pl.ts +3 -0
  23. package/src/components/advance-invoices/list/locales/pt.ts +4 -0
  24. package/src/components/advance-invoices/list/locales/sl.ts +3 -0
  25. package/src/components/credit-notes/create/create-credit-note-form.tsx +71 -8
  26. package/src/components/credit-notes/create/locales/de.ts +16 -0
  27. package/src/components/credit-notes/create/locales/es.ts +16 -0
  28. package/src/components/credit-notes/create/locales/fr.ts +16 -0
  29. package/src/components/credit-notes/create/locales/hr.ts +16 -0
  30. package/src/components/credit-notes/create/locales/it.ts +16 -0
  31. package/src/components/credit-notes/create/locales/nl.ts +16 -0
  32. package/src/components/credit-notes/create/locales/pl.ts +16 -0
  33. package/src/components/credit-notes/create/locales/pt.ts +16 -0
  34. package/src/components/credit-notes/create/locales/sl.ts +17 -1
  35. package/src/components/credit-notes/list/list-row-actions.tsx +44 -1
  36. package/src/components/credit-notes/list/list-table.tsx +16 -2
  37. package/src/components/credit-notes/list/locales/de.ts +2 -0
  38. package/src/components/credit-notes/list/locales/en.ts +2 -0
  39. package/src/components/credit-notes/list/locales/es.ts +2 -0
  40. package/src/components/credit-notes/list/locales/fr.ts +2 -0
  41. package/src/components/credit-notes/list/locales/hr.ts +2 -0
  42. package/src/components/credit-notes/list/locales/it.ts +2 -0
  43. package/src/components/credit-notes/list/locales/nl.ts +2 -0
  44. package/src/components/credit-notes/list/locales/pl.ts +2 -0
  45. package/src/components/credit-notes/list/locales/pt.ts +2 -0
  46. package/src/components/credit-notes/list/locales/sl.ts +2 -0
  47. package/src/components/dashboard/collection-rate-card/use-collection-rate.ts +48 -9
  48. package/src/components/dashboard/revenue-trend-chart/use-revenue-trend.ts +77 -48
  49. package/src/components/dashboard/shared/use-revenue-data.ts +77 -9
  50. package/src/components/delivery-notes/create/create-delivery-note-form.tsx +67 -7
  51. package/src/components/delivery-notes/create/locales/de.ts +16 -0
  52. package/src/components/delivery-notes/create/locales/es.ts +16 -0
  53. package/src/components/delivery-notes/create/locales/fr.ts +16 -0
  54. package/src/components/delivery-notes/create/locales/hr.ts +16 -0
  55. package/src/components/delivery-notes/create/locales/it.ts +16 -0
  56. package/src/components/delivery-notes/create/locales/nl.ts +16 -0
  57. package/src/components/delivery-notes/create/locales/pl.ts +16 -0
  58. package/src/components/delivery-notes/create/locales/pt.ts +16 -0
  59. package/src/components/delivery-notes/create/locales/sl.ts +17 -1
  60. package/src/components/delivery-notes/list/list-table.tsx +17 -8
  61. package/src/components/delivery-notes/list/locales/de.ts +32 -1
  62. package/src/components/delivery-notes/list/locales/en.ts +31 -0
  63. package/src/components/delivery-notes/list/locales/es.ts +32 -1
  64. package/src/components/delivery-notes/list/locales/fr.ts +32 -1
  65. package/src/components/delivery-notes/list/locales/hr.ts +32 -1
  66. package/src/components/delivery-notes/list/locales/it.ts +32 -1
  67. package/src/components/delivery-notes/list/locales/nl.ts +32 -1
  68. package/src/components/delivery-notes/list/locales/pl.ts +32 -1
  69. package/src/components/delivery-notes/list/locales/pt.ts +32 -1
  70. package/src/components/delivery-notes/list/locales/sl.ts +32 -1
  71. package/src/components/documents/create/document-add-item-form.tsx +70 -0
  72. package/src/components/documents/create/document-details-section.tsx +122 -2
  73. package/src/components/documents/create/document-items-section.tsx +21 -4
  74. package/src/components/documents/create/live-preview.tsx +24 -4
  75. package/src/components/documents/create/mark-as-paid-section.tsx +29 -20
  76. package/src/components/documents/create/prepare-document-submission.ts +19 -7
  77. package/src/components/documents/shared/document-preview-display.tsx +3 -4
  78. package/src/components/documents/view/document-actions-bar.tsx +7 -27
  79. package/src/components/documents/view/document-details-card.tsx +26 -9
  80. package/src/components/documents/view/locales/de.ts +2 -0
  81. package/src/components/documents/view/locales/es.ts +2 -0
  82. package/src/components/documents/view/locales/fr.ts +2 -0
  83. package/src/components/documents/view/locales/hr.ts +2 -0
  84. package/src/components/documents/view/locales/it.ts +2 -0
  85. package/src/components/documents/view/locales/nl.ts +2 -0
  86. package/src/components/documents/view/locales/pl.ts +2 -0
  87. package/src/components/documents/view/locales/pt.ts +2 -0
  88. package/src/components/documents/view/locales/sl.ts +3 -1
  89. package/src/components/documents/view/use-document-download.ts +6 -3
  90. package/src/components/entities/create-entity-form.tsx +2 -1
  91. package/src/components/entities/entity-settings-form/input-with-preview.tsx +30 -2
  92. package/src/components/entities/entity-settings-form/locales/de.ts +1 -0
  93. package/src/components/entities/entity-settings-form/locales/es.ts +1 -0
  94. package/src/components/entities/entity-settings-form/locales/fr.ts +1 -0
  95. package/src/components/entities/entity-settings-form/locales/hr.ts +1 -0
  96. package/src/components/entities/entity-settings-form/locales/it.ts +1 -0
  97. package/src/components/entities/entity-settings-form/locales/nl.ts +1 -0
  98. package/src/components/entities/entity-settings-form/locales/pl.ts +1 -0
  99. package/src/components/entities/entity-settings-form/locales/pt.ts +1 -0
  100. package/src/components/entities/entity-settings-form/locales/sl.ts +1 -0
  101. package/src/components/entities/settings/company-settings-form.tsx +173 -20
  102. package/src/components/estimates/create/create-estimate-form.tsx +64 -6
  103. package/src/components/estimates/create/locales/de.ts +16 -0
  104. package/src/components/estimates/create/locales/es.ts +16 -0
  105. package/src/components/estimates/create/locales/fr.ts +16 -0
  106. package/src/components/estimates/create/locales/hr.ts +16 -0
  107. package/src/components/estimates/create/locales/it.ts +16 -0
  108. package/src/components/estimates/create/locales/nl.ts +16 -0
  109. package/src/components/estimates/create/locales/pl.ts +16 -0
  110. package/src/components/estimates/create/locales/pt.ts +16 -0
  111. package/src/components/estimates/create/locales/sl.ts +17 -1
  112. package/src/components/estimates/list/list-table.tsx +11 -2
  113. package/src/components/estimates/list/locales/de.ts +1 -0
  114. package/src/components/estimates/list/locales/en.ts +1 -0
  115. package/src/components/estimates/list/locales/es.ts +1 -0
  116. package/src/components/estimates/list/locales/fr.ts +1 -0
  117. package/src/components/estimates/list/locales/hr.ts +1 -0
  118. package/src/components/estimates/list/locales/it.ts +1 -0
  119. package/src/components/estimates/list/locales/nl.ts +1 -0
  120. package/src/components/estimates/list/locales/pl.ts +1 -0
  121. package/src/components/estimates/list/locales/pt.ts +1 -0
  122. package/src/components/estimates/list/locales/sl.ts +1 -0
  123. package/src/components/export/document-export-form.tsx +46 -12
  124. package/src/components/invoices/create/create-invoice-form.tsx +58 -10
  125. package/src/components/invoices/create/locales/de.ts +15 -0
  126. package/src/components/invoices/create/locales/es.ts +15 -0
  127. package/src/components/invoices/create/locales/fr.ts +15 -0
  128. package/src/components/invoices/create/locales/hr.ts +15 -0
  129. package/src/components/invoices/create/locales/it.ts +15 -0
  130. package/src/components/invoices/create/locales/nl.ts +15 -0
  131. package/src/components/invoices/create/locales/pl.ts +15 -0
  132. package/src/components/invoices/create/locales/pt.ts +15 -0
  133. package/src/components/invoices/create/locales/sl.ts +16 -1
  134. package/src/components/invoices/view/fiscalization-status-card.tsx +10 -8
  135. package/src/components/table/search-input.tsx +17 -0
  136. package/src/generated/schemas/advanceinvoice.ts +4 -2
  137. package/src/generated/schemas/creditnote.ts +2 -1
  138. package/src/generated/schemas/deliverynote.ts +2 -1
  139. package/src/generated/schemas/estimate.ts +4 -2
  140. package/src/generated/schemas/invoice.ts +2 -1
  141. package/src/generated/schemas/renderadvanceinvoicepreview_body.ts +17 -23
  142. package/src/generated/schemas/rendercreditnotepreview_body.ts +17 -23
  143. package/src/generated/schemas/renderdeliverynotepreview_body.ts +17 -23
  144. package/src/generated/schemas/renderestimatepreview_body.ts +17 -23
  145. package/src/generated/schemas/renderinvoicepreview_body.ts +19 -23
  146. package/src/hooks/use-duplicate-document.ts +16 -9
  147. package/src/hooks/use-vies-check.ts +3 -0
@@ -9,6 +9,7 @@ import { Form } from "@/ui/components/ui/form";
9
9
  import { Skeleton } from "@/ui/components/ui/skeleton";
10
10
  import { createCreditNoteSchema } from "@/ui/generated/schemas";
11
11
  import { useNextDocumentNumber } from "@/ui/hooks/use-next-document-number";
12
+ import { useViesCheck } from "@/ui/hooks/use-vies-check";
12
13
  import type { ComponentTranslationProps } from "@/ui/lib/translation";
13
14
  import { createTranslation } from "@/ui/lib/translation";
14
15
  import { useEntities } from "@/ui/providers/entities-context";
@@ -18,6 +19,7 @@ import {
18
19
  DocumentDetailsSection,
19
20
  DocumentNoteField,
20
21
  DocumentPaymentTermsField,
22
+ DocumentTaxClauseField,
21
23
  } from "../../documents/create/document-details-section";
22
24
  import { DocumentItemsSection, type PriceModesMap } from "../../documents/create/document-items-section";
23
25
  import { DocumentRecipientSection } from "../../documents/create/document-recipient-section";
@@ -275,13 +277,18 @@ export default function CreateCreditNoteForm({
275
277
  // Cast customer to form schema type (API type may have additional fields)
276
278
  customer: (initialValues?.customer as CreateCreditNoteFormValues["customer"]) ?? undefined,
277
279
  items: initialValues?.items?.length
278
- ? initialValues.items.map((item) => ({
280
+ ? initialValues.items.map((item: any) => ({
281
+ type: item.type,
279
282
  name: item.name || "",
280
283
  description: item.description || "",
281
- quantity: item.quantity ?? 1,
282
- // Use gross_price if set, otherwise use price
283
- price: item.gross_price ?? item.price,
284
- taxes: item.taxes || [],
284
+ ...(item.type !== "separator"
285
+ ? {
286
+ quantity: item.quantity ?? 1,
287
+ // Use gross_price if set, otherwise use price
288
+ price: item.gross_price ?? item.price,
289
+ taxes: item.taxes || [],
290
+ }
291
+ : {}),
285
292
  }))
286
293
  : [
287
294
  {
@@ -294,6 +301,7 @@ export default function CreateCreditNoteForm({
294
301
  ],
295
302
  currency_code: initialValues?.currency_code || activeEntity?.currency_code || "EUR",
296
303
  note: initialValues?.note ?? "",
304
+ tax_clause: (initialValues as any)?.tax_clause ?? "",
297
305
  payment_terms: initialValues?.payment_terms ?? defaultPaymentTerms,
298
306
  },
299
307
  });
@@ -302,6 +310,41 @@ export default function CreateCreditNoteForm({
302
310
  control: form.control,
303
311
  });
304
312
 
313
+ // ============================================================================
314
+ // VIES Check - determine if reverse charge applies
315
+ // ============================================================================
316
+ const {
317
+ reverseChargeApplies,
318
+ transactionType,
319
+ customerCountryCode: viesCustomerCountryCode,
320
+ isFetching: isViesFetching,
321
+ warning: viesWarning,
322
+ } = useViesCheck({
323
+ issuerCountryCode: activeEntity?.country_code,
324
+ isTaxSubject: activeEntity?.is_tax_subject ?? true,
325
+ customerCountry: formValues.customer?.country,
326
+ customerCountryCode: formValues.customer?.country_code,
327
+ customerTaxNumber: formValues.customer?.tax_number,
328
+ enabled: !!activeEntity,
329
+ });
330
+
331
+ // FINA non-domestic guard: hide FINA selectors for non-domestic transactions
332
+ const isFinaNonDomestic = isFinaEnabled && viesCustomerCountryCode != null && viesCustomerCountryCode !== "HR";
333
+
334
+ // Auto-populate tax_clause from entity settings when transaction type changes
335
+ const effectiveTransactionType = transactionType ?? "domestic";
336
+ const prevTransactionTypeRef = useRef<string | undefined>(undefined);
337
+ useEffect(() => {
338
+ if (effectiveTransactionType === prevTransactionTypeRef.current) return;
339
+ prevTransactionTypeRef.current = effectiveTransactionType;
340
+
341
+ const taxClauseDefaults = (activeEntity?.settings as any)?.tax_clause_defaults;
342
+ if (!taxClauseDefaults) return;
343
+
344
+ const clause = taxClauseDefaults[effectiveTransactionType] ?? "";
345
+ form.setValue("tax_clause", clause);
346
+ }, [effectiveTransactionType, activeEntity, form]);
347
+
305
348
  // Extract customer management logic into a shared hook
306
349
  const {
307
350
  originalCustomer,
@@ -357,7 +400,7 @@ export default function CreateCreditNoteForm({
357
400
 
358
401
  // Build FINA options (skip for drafts; FINA can't be skipped)
359
402
  const finaOptions =
360
- !isDraft && isFinaEnabled && selectedFinaPremiseId && selectedFinaDeviceId
403
+ !isDraft && isFinaEnabled && !isFinaNonDomestic && selectedFinaPremiseId && selectedFinaDeviceId
361
404
  ? { premise_id: selectedFinaPremiseId, device_id: selectedFinaDeviceId, payment_type: paymentTypes[0] }
362
405
  : undefined;
363
406
 
@@ -387,6 +430,7 @@ export default function CreateCreditNoteForm({
387
430
  createCreditNote,
388
431
  isFursEnabled,
389
432
  isFinaEnabled,
433
+ isFinaNonDomestic,
390
434
  markAsPaid,
391
435
  originalCustomer,
392
436
  paymentTypes,
@@ -415,7 +459,7 @@ export default function CreateCreditNoteForm({
415
459
  useFormFooterRegistration({
416
460
  formId: "create-credit-note-form",
417
461
  isPending,
418
- isDirty: form.formState.isDirty,
462
+ isDirty: form.formState.isDirty || !!initialValues,
419
463
  label: t("Save"),
420
464
  secondaryAction: {
421
465
  label: t("Save as Draft"),
@@ -561,7 +605,7 @@ export default function CreateCreditNoteForm({
561
605
  : undefined
562
606
  }
563
607
  finaInline={
564
- isFinaEnabled && hasFinaPremises
608
+ isFinaEnabled && hasFinaPremises && !isFinaNonDomestic
565
609
  ? {
566
610
  premises: activeFinaPremises.map((p: any) => ({ id: p.id, premise_id: p.premise_id })),
567
611
  devices: activeFinaDevices.map((d: any) => ({ id: d.id, device_id: d.device_id })),
@@ -597,6 +641,10 @@ export default function CreateCreditNoteForm({
597
641
  maxTaxesPerItem={activeEntity?.country_rules?.max_taxes_per_item}
598
642
  priceModesRef={priceModesRef}
599
643
  initialPriceModes={initialPriceModes}
644
+ taxesDisabled={reverseChargeApplies}
645
+ taxesDisabledMessage={
646
+ reverseChargeApplies ? t("Reverse charge - tax exempt EU B2B sale") : viesWarning ? viesWarning : undefined
647
+ }
600
648
  />
601
649
 
602
650
  <DocumentNoteField
@@ -611,6 +659,21 @@ export default function CreateCreditNoteForm({
611
659
  }}
612
660
  />
613
661
 
662
+ <DocumentTaxClauseField
663
+ control={form.control}
664
+ t={t}
665
+ entity={activeEntity}
666
+ document={{
667
+ number: formValues.number,
668
+ date: formValues.date,
669
+ currency_code: formValues.currency_code,
670
+ customer: formValues.customer as any,
671
+ }}
672
+ transactionType={transactionType}
673
+ isTransactionTypeFetching={isViesFetching}
674
+ isFinaNonDomestic={isFinaNonDomestic}
675
+ />
676
+
614
677
  <DocumentPaymentTermsField
615
678
  control={form.control}
616
679
  t={t}
@@ -76,4 +76,20 @@ export default {
76
76
  Device: "Gerät",
77
77
  "FINA fiscalized invoices always use the current date":
78
78
  "FINA-fiskalisierte Dokumente verwenden immer das aktuelle Datum",
79
+ // Separator items
80
+ "Add separator": "Trennzeile hinzufügen",
81
+ "Section header": "Abschnittsüberschrift",
82
+ "Section title...": "Abschnittstitel...",
83
+ // Transaction type
84
+ "Transaction type": "Transaktionstyp",
85
+ Domestic: "Inland",
86
+ "EU B2B": "EU B2B",
87
+ "EU B2C": "EU B2C",
88
+ Export: "Export",
89
+ "Determining transaction type...": "Transaktionstyp wird ermittelt...",
90
+ "This invoice will not be fiscalized (non-domestic transaction)":
91
+ "Diese Rechnung wird nicht fiskalisiert (nicht-inländische Transaktion)",
92
+ "Tax Clause": "Steuerklausel",
93
+ "Add tax clause...": "Steuerklausel hinzufügen...",
94
+ "Reverse charge - tax exempt EU B2B sale": "Umkehrung der Steuerschuldnerschaft - steuerbefreiter EU B2B Verkauf",
79
95
  } as const;
@@ -75,4 +75,20 @@ export default {
75
75
  Device: "Dispositivo",
76
76
  "FINA fiscalized invoices always use the current date":
77
77
  "Los documentos fiscalizados con FINA siempre usan la fecha actual",
78
+ // Separator items
79
+ "Add separator": "Añadir separador",
80
+ "Section header": "Encabezado de sección",
81
+ "Section title...": "Título de sección...",
82
+ // Transaction type
83
+ "Transaction type": "Tipo de transacción",
84
+ Domestic: "Nacional",
85
+ "EU B2B": "EU B2B",
86
+ "EU B2C": "EU B2C",
87
+ Export: "Exportación",
88
+ "Determining transaction type...": "Determinando tipo de transacción...",
89
+ "This invoice will not be fiscalized (non-domestic transaction)":
90
+ "Esta factura no será fiscalizada (transacción no nacional)",
91
+ "Tax Clause": "Cláusula fiscal",
92
+ "Add tax clause...": "Agregar cláusula fiscal...",
93
+ "Reverse charge - tax exempt EU B2B sale": "Inversión del sujeto pasivo - venta EU B2B exenta de impuestos",
78
94
  } as const;
@@ -75,4 +75,20 @@ export default {
75
75
  Device: "Appareil",
76
76
  "FINA fiscalized invoices always use the current date":
77
77
  "Les documents fiscalisés FINA utilisent toujours la date actuelle",
78
+ // Separator items
79
+ "Add separator": "Ajouter un séparateur",
80
+ "Section header": "En-tête de section",
81
+ "Section title...": "Titre de section...",
82
+ // Transaction type
83
+ "Transaction type": "Type de transaction",
84
+ Domestic: "Nationale",
85
+ "EU B2B": "EU B2B",
86
+ "EU B2C": "EU B2C",
87
+ Export: "Exportation",
88
+ "Determining transaction type...": "Détermination du type de transaction...",
89
+ "This invoice will not be fiscalized (non-domestic transaction)":
90
+ "Cette facture ne sera pas fiscalisée (transaction non nationale)",
91
+ "Tax Clause": "Clause fiscale",
92
+ "Add tax clause...": "Ajouter une clause fiscale...",
93
+ "Reverse charge - tax exempt EU B2B sale": "Autoliquidation - vente B2B UE exonérée de taxe",
78
94
  } as const;
@@ -73,4 +73,20 @@ export default {
73
73
  Premise: "Prostor",
74
74
  Device: "Uredaj",
75
75
  "FINA fiscalized invoices always use the current date": "FINA fiskalizirani dokumenti uvijek koriste trenutni datum",
76
+ // Separator items
77
+ "Add separator": "Dodaj separator",
78
+ "Section header": "Naslov odjeljka",
79
+ "Section title...": "Naslov odjeljka...",
80
+ // Transaction type
81
+ "Transaction type": "Vrsta transakcije",
82
+ Domestic: "Domaća",
83
+ "EU B2B": "EU B2B",
84
+ "EU B2C": "EU B2C",
85
+ Export: "Izvoz",
86
+ "Determining transaction type...": "Određivanje vrste transakcije...",
87
+ "This invoice will not be fiscalized (non-domestic transaction)":
88
+ "Ovaj račun neće biti fiskaliziran (nedomaća transakcija)",
89
+ "Tax Clause": "Porezna klauzula",
90
+ "Add tax clause...": "Dodajte poreznu klauzulu...",
91
+ "Reverse charge - tax exempt EU B2B sale": "Prijenos porezne obveze - porezno oslobođena EU B2B prodaja",
76
92
  } as const;
@@ -76,4 +76,20 @@ export default {
76
76
  Device: "Dispositivo",
77
77
  "FINA fiscalized invoices always use the current date":
78
78
  "I documenti fiscalizzati FINA utilizzano sempre la data corrente",
79
+ // Separator items
80
+ "Add separator": "Aggiungi separatore",
81
+ "Section header": "Intestazione sezione",
82
+ "Section title...": "Titolo sezione...",
83
+ // Transaction type
84
+ "Transaction type": "Tipo di transazione",
85
+ Domestic: "Nazionale",
86
+ "EU B2B": "EU B2B",
87
+ "EU B2C": "EU B2C",
88
+ Export: "Esportazione",
89
+ "Determining transaction type...": "Determinazione tipo di transazione...",
90
+ "This invoice will not be fiscalized (non-domestic transaction)":
91
+ "Questa fattura non sarà fiscalizzata (transazione non nazionale)",
92
+ "Tax Clause": "Clausola fiscale",
93
+ "Add tax clause...": "Aggiungi clausola fiscale...",
94
+ "Reverse charge - tax exempt EU B2B sale": "Inversione contabile - vendita B2B UE esente da imposta",
79
95
  } as const;
@@ -75,4 +75,20 @@ export default {
75
75
  Device: "Apparaat",
76
76
  "FINA fiscalized invoices always use the current date":
77
77
  "FINA-gefiscaliseerde documenten gebruiken altijd de huidige datum",
78
+ // Separator items
79
+ "Add separator": "Scheidingslijn toevoegen",
80
+ "Section header": "Sectiekop",
81
+ "Section title...": "Sectietitel...",
82
+ // Transaction type
83
+ "Transaction type": "Transactietype",
84
+ Domestic: "Binnenland",
85
+ "EU B2B": "EU B2B",
86
+ "EU B2C": "EU B2C",
87
+ Export: "Export",
88
+ "Determining transaction type...": "Transactietype bepalen...",
89
+ "This invoice will not be fiscalized (non-domestic transaction)":
90
+ "Deze factuur wordt niet gefiscaliseerd (niet-binnenlandse transactie)",
91
+ "Tax Clause": "Belastingclausule",
92
+ "Add tax clause...": "Belastingclausule toevoegen...",
93
+ "Reverse charge - tax exempt EU B2B sale": "Verlegging - belastingvrijgestelde EU B2B verkoop",
78
94
  } as const;
@@ -73,4 +73,20 @@ export default {
73
73
  Premise: "Lokal",
74
74
  Device: "Urządzenie",
75
75
  "FINA fiscalized invoices always use the current date": "Dokumenty fiskalizowane FINA zawsze używają bieżącej daty",
76
+ // Separator items
77
+ "Add separator": "Dodaj separator",
78
+ "Section header": "Nagłówek sekcji",
79
+ "Section title...": "Tytuł sekcji...",
80
+ // Transaction type
81
+ "Transaction type": "Typ transakcji",
82
+ Domestic: "Krajowa",
83
+ "EU B2B": "EU B2B",
84
+ "EU B2C": "EU B2C",
85
+ Export: "Eksport",
86
+ "Determining transaction type...": "Określanie typu transakcji...",
87
+ "This invoice will not be fiscalized (non-domestic transaction)":
88
+ "Ta faktura nie będzie fiskalizowana (transakcja niekrajowa)",
89
+ "Tax Clause": "Klauzula podatkowa",
90
+ "Add tax clause...": "Dodaj klauzulę podatkową...",
91
+ "Reverse charge - tax exempt EU B2B sale": "Odwrotne obciążenie - zwolniona z podatku sprzedaż EU B2B",
76
92
  } as const;
@@ -73,4 +73,20 @@ export default {
73
73
  Premise: "Estabelecimento",
74
74
  Device: "Dispositivo",
75
75
  "FINA fiscalized invoices always use the current date": "Os documentos fiscalizados FINA usam sempre a data atual",
76
+ // Separator items
77
+ "Add separator": "Adicionar separador",
78
+ "Section header": "Cabeçalho da secção",
79
+ "Section title...": "Título da secção...",
80
+ // Transaction type
81
+ "Transaction type": "Tipo de transação",
82
+ Domestic: "Nacional",
83
+ "EU B2B": "EU B2B",
84
+ "EU B2C": "EU B2C",
85
+ Export: "Exportação",
86
+ "Determining transaction type...": "Determinando tipo de transação...",
87
+ "This invoice will not be fiscalized (non-domestic transaction)":
88
+ "Esta fatura não será fiscalizada (transação não nacional)",
89
+ "Tax Clause": "Cláusula fiscal",
90
+ "Add tax clause...": "Adicionar cláusula fiscal...",
91
+ "Reverse charge - tax exempt EU B2B sale": "Autoliquidação - venda B2B UE isenta de imposto",
76
92
  } as const;
@@ -15,7 +15,7 @@ export default {
15
15
  Price: "Cena",
16
16
  Unit: "Enota",
17
17
  Discount: "Popust",
18
- Tax: "Davek",
18
+ Tax: "DDV",
19
19
  "Tax rate": "Davčna stopnja",
20
20
  "Add tax": "Dodaj davek",
21
21
  "Select tax...": "Izberi davek...",
@@ -72,4 +72,20 @@ export default {
72
72
  Premise: "Poslovni prostor",
73
73
  Device: "Naprava",
74
74
  "FINA fiscalized invoices always use the current date": "FINA fiskalizirani dokumenti vedno uporabijo trenutni datum",
75
+ // Separator items
76
+ "Add separator": "Dodaj ločilnik",
77
+ "Section header": "Naslov razdelka",
78
+ "Section title...": "Naslov razdelka...",
79
+ // Transaction type
80
+ "Transaction type": "Vrsta transakcije",
81
+ Domestic: "Domača",
82
+ "EU B2B": "EU B2B",
83
+ "EU B2C": "EU B2C",
84
+ Export: "Izvoz",
85
+ "Determining transaction type...": "Določanje vrste transakcije...",
86
+ "This invoice will not be fiscalized (non-domestic transaction)":
87
+ "Ta račun ne bo fiskaliziran (nedomača transakcija)",
88
+ "Tax Clause": "Davčna klavzula",
89
+ "Add tax clause...": "Dodajte davčno klavzulo...",
90
+ "Reverse charge - tax exempt EU B2B sale": "Obrnjena davčna obveznost - davka oproščena EU B2B prodaja",
75
91
  } as const;
@@ -1,4 +1,4 @@
1
- import { Copy, Download, Eye, Link2Off, Loader2, MoreHorizontal, Plus } from "lucide-react";
1
+ import { Ban, Copy, Download, Eye, Link2Off, Loader2, MoreHorizontal, Plus } from "lucide-react";
2
2
  import { Button } from "@/ui/components/ui/button";
3
3
  import {
4
4
  DropdownMenu,
@@ -9,6 +9,7 @@ import {
9
9
  DropdownMenuSeparator,
10
10
  DropdownMenuTrigger,
11
11
  } from "@/ui/components/ui/dropdown-menu";
12
+ import { Tooltip, TooltipContent, TooltipTrigger } from "@/ui/components/ui/tooltip";
12
13
  import type { ComponentTranslationProps } from "@/ui/lib/translation";
13
14
  import { createTranslation } from "@/ui/lib/translation";
14
15
  import { useCreditNoteDownload } from "./use-credit-note-download";
@@ -26,6 +27,8 @@ type CreditNoteListRowActionsProps = {
26
27
  onDownloadError?: (error: string) => void;
27
28
  onUnshare?: (creditNote: CreditNote) => Promise<void>;
28
29
  isUnsharing?: boolean;
30
+ onVoid?: (creditNote: CreditNote) => void;
31
+ isVoiding?: boolean;
29
32
  } & ComponentTranslationProps;
30
33
 
31
34
  export default function CreditNoteListRowActions({
@@ -38,6 +41,8 @@ export default function CreditNoteListRowActions({
38
41
  onDownloadError,
39
42
  onUnshare,
40
43
  isUnsharing,
44
+ onVoid,
45
+ isVoiding,
41
46
  ...i18nProps
42
47
  }: CreditNoteListRowActionsProps) {
43
48
  const t = createTranslation(i18nProps);
@@ -107,6 +112,44 @@ export default function CreditNoteListRowActions({
107
112
  </DropdownMenuGroup>
108
113
  </>
109
114
  )}
115
+ {onVoid &&
116
+ !creditNote.voided_at &&
117
+ !creditNote.is_draft &&
118
+ (() => {
119
+ const isFiscalized = !!(creditNote.furs || creditNote.fina);
120
+ const voidDisabled = isVoiding || isFiscalized;
121
+ const voidItem = (
122
+ <DropdownMenuItem
123
+ className={
124
+ voidDisabled
125
+ ? "text-destructive opacity-50"
126
+ : "cursor-pointer text-destructive focus:text-destructive"
127
+ }
128
+ onClick={() => !voidDisabled && onVoid(creditNote)}
129
+ disabled={voidDisabled}
130
+ >
131
+ {isVoiding ? <Loader2 className="h-4 w-4 animate-spin" /> : <Ban className="h-4 w-4" />}
132
+ {t("Void")}
133
+ </DropdownMenuItem>
134
+ );
135
+ return (
136
+ <>
137
+ <DropdownMenuSeparator />
138
+ <DropdownMenuGroup>
139
+ {isFiscalized ? (
140
+ <Tooltip>
141
+ <TooltipTrigger asChild>
142
+ <div>{voidItem}</div>
143
+ </TooltipTrigger>
144
+ <TooltipContent side="left">{t("Cannot void a fiscalized credit note")}</TooltipContent>
145
+ </Tooltip>
146
+ ) : (
147
+ voidItem
148
+ )}
149
+ </DropdownMenuGroup>
150
+ </>
151
+ );
152
+ })()}
110
153
  </DropdownMenuContent>
111
154
  </DropdownMenu>
112
155
  );
@@ -59,6 +59,8 @@ type CreditNoteListTableProps = {
59
59
  onRetryFiscalization?: (documentIds: string[]) => void;
60
60
  fiscalizationFeatures?: ("furs" | "fina")[];
61
61
  onCreateNew?: () => void;
62
+ onVoid?: (creditNote: CreditNote) => void;
63
+ isVoiding?: boolean;
62
64
  } & ListTableProps<CreditNote>;
63
65
 
64
66
  export default function CreditNoteListTable({
@@ -76,6 +78,8 @@ export default function CreditNoteListTable({
76
78
  onRetryFiscalization,
77
79
  fiscalizationFeatures,
78
80
  onCreateNew,
81
+ onVoid,
82
+ isVoiding,
79
83
  ...i18nProps
80
84
  }: CreditNoteListTableProps) {
81
85
  const t = createTranslation({
@@ -97,6 +101,7 @@ export default function CreditNoteListTable({
97
101
  prev_cursor: params.prev_cursor,
98
102
  search: params.search,
99
103
  query: params.query,
104
+ include: "document_relations",
100
105
  });
101
106
  return response as unknown as TableQueryResponse<CreditNote>;
102
107
  }, entityId);
@@ -210,13 +215,13 @@ export default function CreditNoteListTable({
210
215
  id: "total",
211
216
  header: t("Total"),
212
217
  align: "right",
213
- cell: (creditNote) => creditNote.total,
218
+ cell: (creditNote) => -creditNote.total,
214
219
  },
215
220
  {
216
221
  id: "total_with_tax",
217
222
  header: t("Total with Tax"),
218
223
  align: "right",
219
- cell: (creditNote) => creditNote.total_with_tax,
224
+ cell: (creditNote) => -creditNote.total_with_tax,
220
225
  },
221
226
  {
222
227
  id: "status",
@@ -236,6 +241,8 @@ export default function CreditNoteListTable({
236
241
  onDownloadStart={onDownloadStart}
237
242
  onDownloadSuccess={onDownloadSuccess}
238
243
  onDownloadError={onDownloadError}
244
+ onVoid={onVoid}
245
+ isVoiding={isVoiding}
239
246
  t={t}
240
247
  locale={i18nProps.locale}
241
248
  />
@@ -251,6 +258,8 @@ export default function CreditNoteListTable({
251
258
  onDownloadStart,
252
259
  onDownloadSuccess,
253
260
  onDownloadError,
261
+ onVoid,
262
+ isVoiding,
254
263
  i18nProps.locale,
255
264
  fiscalizationFeatures,
256
265
  ],
@@ -290,6 +299,11 @@ function CreditNoteStatusBadge({ creditNote, t }: { creditNote: CreditNote; t: (
290
299
  if ((creditNote as any).is_draft) {
291
300
  return null;
292
301
  }
302
+ // Hide payment badges for void-created credit notes (has "credit_for" relation)
303
+ const isVoidCreated = (creditNote as any).document_relations?.some((rel: any) => rel.relation_type === "credit_for");
304
+ if (isVoidCreated) {
305
+ return null;
306
+ }
293
307
  if (creditNote.paid_in_full) {
294
308
  return (
295
309
  <Badge
@@ -46,4 +46,6 @@ export default {
46
46
  "FINA fiscalization failed": "FINA fiscalization failed",
47
47
  "Retry Fiscalization": "Retry Fiscalization",
48
48
  "Some selected documents don't have failed fiscalization": "Some selected documents don't have failed fiscalization",
49
+ Void: "Stornieren",
50
+ "Cannot void a fiscalized credit note": "Stornierung einer fiskalisierten Gutschrift nicht möglich",
49
51
  } as const;
@@ -14,4 +14,6 @@ export default {
14
14
  "FINA fiscalization failed": "FINA fiscalization failed",
15
15
  "Retry Fiscalization": "Retry Fiscalization",
16
16
  "Some selected documents don't have failed fiscalization": "Some selected documents don't have failed fiscalization",
17
+ Void: "Void",
18
+ "Cannot void a fiscalized credit note": "Cannot void a fiscalized credit note",
17
19
  } as const;
@@ -46,4 +46,6 @@ export default {
46
46
  "FINA fiscalization failed": "FINA fiscalization failed",
47
47
  "Retry Fiscalization": "Retry Fiscalization",
48
48
  "Some selected documents don't have failed fiscalization": "Some selected documents don't have failed fiscalization",
49
+ Void: "Anular",
50
+ "Cannot void a fiscalized credit note": "No se puede anular una nota de crédito fiscalizada",
49
51
  } as const;
@@ -46,4 +46,6 @@ export default {
46
46
  "FINA fiscalization failed": "FINA fiscalization failed",
47
47
  "Retry Fiscalization": "Retry Fiscalization",
48
48
  "Some selected documents don't have failed fiscalization": "Some selected documents don't have failed fiscalization",
49
+ Void: "Annuler",
50
+ "Cannot void a fiscalized credit note": "Impossible d'annuler un avoir fiscalisé",
49
51
  } as const;
@@ -46,4 +46,6 @@ export default {
46
46
  "FINA fiscalization failed": "FINA fiskalizacija nije uspjela",
47
47
  "Retry Fiscalization": "Ponovi fiskalizaciju",
48
48
  "Some selected documents don't have failed fiscalization": "Neki odabrani dokumenti nemaju neuspjelu fiskalizaciju",
49
+ Void: "Storniraj",
50
+ "Cannot void a fiscalized credit note": "Nije moguće poništiti fiskalizirani dobropis",
49
51
  } as const;
@@ -46,4 +46,6 @@ export default {
46
46
  "FINA fiscalization failed": "FINA fiscalization failed",
47
47
  "Retry Fiscalization": "Retry Fiscalization",
48
48
  "Some selected documents don't have failed fiscalization": "Some selected documents don't have failed fiscalization",
49
+ Void: "Annulla",
50
+ "Cannot void a fiscalized credit note": "Impossibile annullare una nota di credito fiscalizzata",
49
51
  } as const;
@@ -46,4 +46,6 @@ export default {
46
46
  "FINA fiscalization failed": "FINA fiscalization failed",
47
47
  "Retry Fiscalization": "Retry Fiscalization",
48
48
  "Some selected documents don't have failed fiscalization": "Some selected documents don't have failed fiscalization",
49
+ Void: "Nietig verklaren",
50
+ "Cannot void a fiscalized credit note": "Kan een gefiscaliseerde creditnota niet ongeldig maken",
49
51
  } as const;
@@ -46,4 +46,6 @@ export default {
46
46
  "FINA fiscalization failed": "FINA fiscalization failed",
47
47
  "Retry Fiscalization": "Retry Fiscalization",
48
48
  "Some selected documents don't have failed fiscalization": "Some selected documents don't have failed fiscalization",
49
+ Void: "Anuluj",
50
+ "Cannot void a fiscalized credit note": "Nie można anulować zafiskalizowanej noty kredytowej",
49
51
  } as const;
@@ -46,4 +46,6 @@ export default {
46
46
  "FINA fiscalization failed": "FINA fiscalization failed",
47
47
  "Retry Fiscalization": "Retry Fiscalization",
48
48
  "Some selected documents don't have failed fiscalization": "Some selected documents don't have failed fiscalization",
49
+ Void: "Anular",
50
+ "Cannot void a fiscalized credit note": "Não é possível anular uma nota de crédito fiscalizada",
49
51
  } as const;
@@ -46,4 +46,6 @@ export default {
46
46
  "FINA fiscalization failed": "FINA fiskalizacija ni uspela",
47
47
  "Retry Fiscalization": "Ponovi fiskalizacijo",
48
48
  "Some selected documents don't have failed fiscalization": "Nekateri izbrani dokumenti nimajo neuspele fiskalizacije",
49
+ Void: "Storniraj",
50
+ "Cannot void a fiscalized credit note": "Ni mogoče razveljaviti fiskalizirane dobropisa",
49
51
  } as const;