@spaceinvoices/react-ui 0.4.4 → 0.4.6

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 (178) hide show
  1. package/cli/dist/index.js +1 -1
  2. package/package.json +1 -1
  3. package/src/components/advance-invoices/advance-invoices.hooks.ts +2 -2
  4. package/src/components/advance-invoices/create/create-advance-invoice-form.tsx +151 -45
  5. package/src/components/advance-invoices/create/locales/de.ts +20 -0
  6. package/src/components/advance-invoices/create/locales/es.ts +20 -0
  7. package/src/components/advance-invoices/create/locales/fr.ts +20 -0
  8. package/src/components/advance-invoices/create/locales/hr.ts +20 -0
  9. package/src/components/advance-invoices/create/locales/it.ts +20 -0
  10. package/src/components/advance-invoices/create/locales/nl.ts +20 -0
  11. package/src/components/advance-invoices/create/locales/pl.ts +20 -0
  12. package/src/components/advance-invoices/create/locales/pt.ts +20 -0
  13. package/src/components/advance-invoices/create/locales/sl.ts +20 -0
  14. package/src/components/advance-invoices/create/prepare-advance-invoice-submission.ts +5 -5
  15. package/src/components/advance-invoices/list/list-row-actions.tsx +48 -1
  16. package/src/components/advance-invoices/list/list-table.tsx +21 -1
  17. package/src/components/advance-invoices/list/locales/de.ts +4 -0
  18. package/src/components/advance-invoices/list/locales/en.ts +3 -0
  19. package/src/components/advance-invoices/list/locales/es.ts +4 -0
  20. package/src/components/advance-invoices/list/locales/fr.ts +4 -0
  21. package/src/components/advance-invoices/list/locales/hr.ts +3 -0
  22. package/src/components/advance-invoices/list/locales/it.ts +4 -0
  23. package/src/components/advance-invoices/list/locales/nl.ts +4 -0
  24. package/src/components/advance-invoices/list/locales/pl.ts +3 -0
  25. package/src/components/advance-invoices/list/locales/pt.ts +4 -0
  26. package/src/components/advance-invoices/list/locales/sl.ts +3 -0
  27. package/src/components/credit-notes/create/create-credit-note-form.tsx +161 -42
  28. package/src/components/credit-notes/create/locales/de.ts +21 -0
  29. package/src/components/credit-notes/create/locales/es.ts +21 -0
  30. package/src/components/credit-notes/create/locales/fr.ts +21 -0
  31. package/src/components/credit-notes/create/locales/hr.ts +21 -0
  32. package/src/components/credit-notes/create/locales/it.ts +21 -0
  33. package/src/components/credit-notes/create/locales/nl.ts +21 -0
  34. package/src/components/credit-notes/create/locales/pl.ts +21 -0
  35. package/src/components/credit-notes/create/locales/pt.ts +21 -0
  36. package/src/components/credit-notes/create/locales/sl.ts +22 -1
  37. package/src/components/credit-notes/credit-notes.hooks.ts +2 -2
  38. package/src/components/credit-notes/list/list-row-actions.tsx +44 -1
  39. package/src/components/credit-notes/list/list-table.tsx +16 -2
  40. package/src/components/credit-notes/list/locales/de.ts +2 -0
  41. package/src/components/credit-notes/list/locales/en.ts +2 -0
  42. package/src/components/credit-notes/list/locales/es.ts +2 -0
  43. package/src/components/credit-notes/list/locales/fr.ts +2 -0
  44. package/src/components/credit-notes/list/locales/hr.ts +2 -0
  45. package/src/components/credit-notes/list/locales/it.ts +2 -0
  46. package/src/components/credit-notes/list/locales/nl.ts +2 -0
  47. package/src/components/credit-notes/list/locales/pl.ts +2 -0
  48. package/src/components/credit-notes/list/locales/pt.ts +2 -0
  49. package/src/components/credit-notes/list/locales/sl.ts +2 -0
  50. package/src/components/dashboard/collection-rate-card/use-collection-rate.ts +48 -9
  51. package/src/components/dashboard/revenue-trend-chart/use-revenue-trend.ts +77 -48
  52. package/src/components/dashboard/shared/use-revenue-data.ts +77 -9
  53. package/src/components/delivery-notes/create/create-delivery-note-form.tsx +114 -7
  54. package/src/components/delivery-notes/create/locales/de.ts +21 -0
  55. package/src/components/delivery-notes/create/locales/es.ts +21 -0
  56. package/src/components/delivery-notes/create/locales/fr.ts +21 -0
  57. package/src/components/delivery-notes/create/locales/hr.ts +21 -0
  58. package/src/components/delivery-notes/create/locales/it.ts +21 -0
  59. package/src/components/delivery-notes/create/locales/nl.ts +21 -0
  60. package/src/components/delivery-notes/create/locales/pl.ts +21 -0
  61. package/src/components/delivery-notes/create/locales/pt.ts +21 -0
  62. package/src/components/delivery-notes/create/locales/sl.ts +22 -1
  63. package/src/components/delivery-notes/list/list-table.tsx +17 -8
  64. package/src/components/delivery-notes/list/locales/de.ts +32 -1
  65. package/src/components/delivery-notes/list/locales/en.ts +31 -0
  66. package/src/components/delivery-notes/list/locales/es.ts +32 -1
  67. package/src/components/delivery-notes/list/locales/fr.ts +32 -1
  68. package/src/components/delivery-notes/list/locales/hr.ts +32 -1
  69. package/src/components/delivery-notes/list/locales/it.ts +32 -1
  70. package/src/components/delivery-notes/list/locales/nl.ts +32 -1
  71. package/src/components/delivery-notes/list/locales/pl.ts +32 -1
  72. package/src/components/delivery-notes/list/locales/pt.ts +32 -1
  73. package/src/components/delivery-notes/list/locales/sl.ts +32 -1
  74. package/src/components/documents/create/document-add-item-form.tsx +70 -0
  75. package/src/components/documents/create/document-details-section.tsx +590 -344
  76. package/src/components/documents/create/document-items-section.tsx +21 -4
  77. package/src/components/documents/create/live-preview.tsx +24 -4
  78. package/src/components/documents/create/mark-as-paid-section.tsx +29 -20
  79. package/src/components/documents/create/prepare-document-submission.ts +22 -8
  80. package/src/components/documents/create/smart-code-insert-button.tsx +6 -0
  81. package/src/components/documents/shared/document-preview-display.tsx +3 -4
  82. package/src/components/documents/view/document-actions-bar.tsx +7 -27
  83. package/src/components/documents/view/document-details-card.tsx +32 -9
  84. package/src/components/documents/view/locales/de.ts +3 -0
  85. package/src/components/documents/view/locales/es.ts +3 -0
  86. package/src/components/documents/view/locales/fr.ts +3 -0
  87. package/src/components/documents/view/locales/hr.ts +3 -0
  88. package/src/components/documents/view/locales/it.ts +3 -0
  89. package/src/components/documents/view/locales/nl.ts +3 -0
  90. package/src/components/documents/view/locales/pl.ts +3 -0
  91. package/src/components/documents/view/locales/pt.ts +3 -0
  92. package/src/components/documents/view/locales/sl.ts +4 -1
  93. package/src/components/documents/view/use-document-download.ts +6 -3
  94. package/src/components/entities/create-entity-form.tsx +2 -1
  95. package/src/components/entities/entity-settings-form/email-template-variables-info.tsx +6 -0
  96. package/src/components/entities/entity-settings-form/input-with-preview.tsx +2 -117
  97. package/src/components/entities/entity-settings-form/locales/de.ts +5 -0
  98. package/src/components/entities/entity-settings-form/locales/es.ts +5 -0
  99. package/src/components/entities/entity-settings-form/locales/fr.ts +5 -0
  100. package/src/components/entities/entity-settings-form/locales/hr.ts +5 -0
  101. package/src/components/entities/entity-settings-form/locales/it.ts +5 -0
  102. package/src/components/entities/entity-settings-form/locales/nl.ts +5 -0
  103. package/src/components/entities/entity-settings-form/locales/pl.ts +5 -0
  104. package/src/components/entities/entity-settings-form/locales/pt.ts +5 -0
  105. package/src/components/entities/entity-settings-form/locales/sl.ts +5 -0
  106. package/src/components/entities/fina-settings-form/fina-settings-form.tsx +15 -0
  107. package/src/components/entities/fina-settings-form/fina-settings.hooks.ts +5 -1
  108. package/src/components/entities/fina-settings-form/locales/de.ts +3 -0
  109. package/src/components/entities/fina-settings-form/locales/en.ts +3 -0
  110. package/src/components/entities/fina-settings-form/locales/es.ts +3 -0
  111. package/src/components/entities/fina-settings-form/locales/fr.ts +3 -0
  112. package/src/components/entities/fina-settings-form/locales/hr.ts +3 -0
  113. package/src/components/entities/fina-settings-form/locales/it.ts +3 -0
  114. package/src/components/entities/fina-settings-form/locales/nl.ts +3 -0
  115. package/src/components/entities/fina-settings-form/locales/pl.ts +3 -0
  116. package/src/components/entities/fina-settings-form/locales/pt.ts +3 -0
  117. package/src/components/entities/fina-settings-form/locales/sl.ts +3 -0
  118. package/src/components/entities/fina-settings-form/sections/premises-management-section.tsx +4 -4
  119. package/src/components/entities/fina-settings-form/sections/register-premise-dialog.tsx +3 -3
  120. package/src/components/entities/settings/company-settings-form.tsx +173 -20
  121. package/src/components/entities/settings/defaults-settings-form.tsx +38 -1
  122. package/src/components/entities/settings/tax-rules-settings-form.tsx +1 -2
  123. package/src/components/estimates/create/create-estimate-form.tsx +107 -8
  124. package/src/components/estimates/create/locales/de.ts +21 -0
  125. package/src/components/estimates/create/locales/es.ts +21 -0
  126. package/src/components/estimates/create/locales/fr.ts +21 -0
  127. package/src/components/estimates/create/locales/hr.ts +21 -0
  128. package/src/components/estimates/create/locales/it.ts +21 -0
  129. package/src/components/estimates/create/locales/nl.ts +21 -0
  130. package/src/components/estimates/create/locales/pl.ts +21 -0
  131. package/src/components/estimates/create/locales/pt.ts +21 -0
  132. package/src/components/estimates/create/locales/sl.ts +22 -1
  133. package/src/components/estimates/list/list-table.tsx +11 -2
  134. package/src/components/estimates/list/locales/de.ts +1 -0
  135. package/src/components/estimates/list/locales/en.ts +1 -0
  136. package/src/components/estimates/list/locales/es.ts +1 -0
  137. package/src/components/estimates/list/locales/fr.ts +1 -0
  138. package/src/components/estimates/list/locales/hr.ts +1 -0
  139. package/src/components/estimates/list/locales/it.ts +1 -0
  140. package/src/components/estimates/list/locales/nl.ts +1 -0
  141. package/src/components/estimates/list/locales/pl.ts +1 -0
  142. package/src/components/estimates/list/locales/pt.ts +1 -0
  143. package/src/components/estimates/list/locales/sl.ts +1 -0
  144. package/src/components/export/document-export-form.tsx +46 -12
  145. package/src/components/invoices/create/create-invoice-form.tsx +186 -48
  146. package/src/components/invoices/create/locales/de.ts +28 -0
  147. package/src/components/invoices/create/locales/es.ts +28 -0
  148. package/src/components/invoices/create/locales/fr.ts +28 -0
  149. package/src/components/invoices/create/locales/hr.ts +28 -0
  150. package/src/components/invoices/create/locales/it.ts +28 -0
  151. package/src/components/invoices/create/locales/nl.ts +28 -0
  152. package/src/components/invoices/create/locales/pl.ts +28 -0
  153. package/src/components/invoices/create/locales/pt.ts +28 -0
  154. package/src/components/invoices/create/locales/sl.ts +29 -1
  155. package/src/components/invoices/create/prepare-invoice-submission.ts +5 -5
  156. package/src/components/invoices/invoices.hooks.ts +2 -2
  157. package/src/components/invoices/view/fiscalization-status-card.tsx +10 -8
  158. package/src/components/table/search-input.tsx +17 -0
  159. package/src/components/table/table-pagination.tsx +1 -1
  160. package/src/generated/schemas/advanceinvoice.ts +6 -2
  161. package/src/generated/schemas/creditnote.ts +3 -1
  162. package/src/generated/schemas/deliverynote.ts +3 -1
  163. package/src/generated/schemas/entity.ts +4 -4
  164. package/src/generated/schemas/entityapikey.ts +19 -0
  165. package/src/generated/schemas/estimate.ts +6 -2
  166. package/src/generated/schemas/index.ts +1 -0
  167. package/src/generated/schemas/invoice.ts +4 -1
  168. package/src/generated/schemas/renderadvanceinvoicepreview_body.ts +17 -23
  169. package/src/generated/schemas/rendercreditnotepreview_body.ts +17 -23
  170. package/src/generated/schemas/renderdeliverynotepreview_body.ts +17 -23
  171. package/src/generated/schemas/renderestimatepreview_body.ts +17 -23
  172. package/src/generated/schemas/renderinvoicepreview_body.ts +19 -23
  173. package/src/generated/schemas/startpdfexport_body.ts +14 -2
  174. package/src/generated/schemas/webhook.ts +4 -0
  175. package/src/hooks/use-duplicate-document.ts +16 -9
  176. package/src/hooks/use-vies-check.ts +3 -0
  177. package/src/lib/template-variables.tsx +167 -0
  178. package/src/providers/entities-context.tsx +2 -2
@@ -22,8 +22,11 @@ import { useFormFooterRegistration } from "@/ui/providers/form-footer-context";
22
22
  import { CUSTOMERS_CACHE_KEY } from "../../customers/customers.hooks";
23
23
  import {
24
24
  DocumentDetailsSection,
25
+ DocumentFooterField,
25
26
  DocumentNoteField,
26
27
  DocumentPaymentTermsField,
28
+ DocumentSignatureField,
29
+ DocumentTaxClauseField,
27
30
  } from "../../documents/create/document-details-section";
28
31
  import { DocumentItemsSection, type PriceModesMap } from "../../documents/create/document-items-section";
29
32
  import { DocumentRecipientSection } from "../../documents/create/document-recipient-section";
@@ -60,6 +63,8 @@ function calculateDueDate(dateIso: string, days: number): string {
60
63
  return date.toISOString();
61
64
  }
62
65
 
66
+ const DUE_DAYS_PRESETS = [0, 7, 14, 30, 60, 90] as const;
67
+
63
68
  const translations = {
64
69
  sl,
65
70
  de,
@@ -131,6 +136,7 @@ export default function CreateInvoiceForm({
131
136
  // Get default invoice note and payment terms from entity settings
132
137
  const defaultInvoiceNote = (activeEntity?.settings as any)?.default_invoice_note || "";
133
138
  const defaultPaymentTerms = (activeEntity?.settings as any)?.default_invoice_payment_terms || "";
139
+ const defaultFooter = (activeEntity?.settings as any)?.document_footer || "";
134
140
  const defaultInvoiceDueDays = (activeEntity?.settings as any)?.default_invoice_due_days ?? 30;
135
141
 
136
142
  // ============================================================================
@@ -168,8 +174,8 @@ export default function CreateInvoiceForm({
168
174
  const hasFinaPremises = activeFinaPremises.length > 0;
169
175
 
170
176
  // FINA premise/device selection state (no skip - all FINA invoices must be fiscalized)
171
- const [selectedFinaPremiseId, setSelectedFinaPremiseId] = useState<string | undefined>();
172
- const [selectedFinaDeviceId, setSelectedFinaDeviceId] = useState<string | undefined>();
177
+ const [selectedFinaBusinessPremiseName, setSelectedFinaBusinessPremiseName] = useState<string | undefined>();
178
+ const [selectedFinaElectronicDeviceName, setSelectedFinaElectronicDeviceName] = useState<string | undefined>();
173
179
 
174
180
  // UI-only state (not part of API schema)
175
181
  const [markAsPaid, setMarkAsPaid] = useState(false);
@@ -179,6 +185,12 @@ export default function CreateInvoiceForm({
179
185
  // Service date type state (single date or range)
180
186
  const [serviceDateType, setServiceDateType] = useState<"single" | "range">("single");
181
187
 
188
+ // Due days type state for invoice due date selector
189
+ const [dueDaysType, setDueDaysType] = useState<number | "custom">(() => {
190
+ if (mode === "edit" || initialValues?.date_due) return "custom";
191
+ return (DUE_DAYS_PRESETS as readonly number[]).includes(defaultInvoiceDueDays) ? defaultInvoiceDueDays : "custom";
192
+ });
193
+
182
194
  // Price modes per item (gross vs net) - collected from component state at submit
183
195
  // Initialize from initialValues for duplicated documents
184
196
  const initialPriceModes = useMemo(() => {
@@ -268,22 +280,24 @@ export default function CreateInvoiceForm({
268
280
 
269
281
  // Get active FINA devices for selected premise
270
282
  const activeFinaDevices = useMemo(() => {
271
- if (!selectedFinaPremiseId) return [];
272
- const premise = activeFinaPremises.find((p: any) => p.premise_id === selectedFinaPremiseId);
283
+ if (!selectedFinaBusinessPremiseName) return [];
284
+ const premise = activeFinaPremises.find((p: any) => p.business_premise_name === selectedFinaBusinessPremiseName);
273
285
  return premise?.Devices?.filter((d: any) => d.is_active) || [];
274
- }, [activeFinaPremises, selectedFinaPremiseId]);
286
+ }, [activeFinaPremises, selectedFinaBusinessPremiseName]);
275
287
 
276
288
  // Initialize FINA selection from localStorage or first active combo
277
289
  useEffect(() => {
278
- if (!isFinaEnabled || !hasFinaPremises || selectedFinaPremiseId) return;
290
+ if (!isFinaEnabled || !hasFinaPremises || selectedFinaBusinessPremiseName) return;
279
291
 
280
292
  const lastUsed = getLastUsedFinaCombo(entityId);
281
293
  if (lastUsed) {
282
- const premise = activeFinaPremises.find((p: any) => p.premise_id === lastUsed.premise_id);
283
- const device = premise?.Devices?.find((d: any) => d.device_id === lastUsed.device_id && d.is_active);
294
+ const premise = activeFinaPremises.find((p: any) => p.business_premise_name === lastUsed.business_premise_name);
295
+ const device = premise?.Devices?.find(
296
+ (d: any) => d.electronic_device_name === lastUsed.electronic_device_name && d.is_active,
297
+ );
284
298
  if (premise && device) {
285
- setSelectedFinaPremiseId(lastUsed.premise_id);
286
- setSelectedFinaDeviceId(lastUsed.device_id);
299
+ setSelectedFinaBusinessPremiseName(lastUsed.business_premise_name);
300
+ setSelectedFinaElectronicDeviceName(lastUsed.electronic_device_name);
287
301
  return;
288
302
  }
289
303
  }
@@ -291,25 +305,25 @@ export default function CreateInvoiceForm({
291
305
  const firstPremise = activeFinaPremises[0];
292
306
  const firstDevice = firstPremise?.Devices?.find((d: any) => d.is_active);
293
307
  if (firstPremise && firstDevice) {
294
- setSelectedFinaPremiseId(firstPremise.premise_id);
295
- setSelectedFinaDeviceId(firstDevice.device_id);
308
+ setSelectedFinaBusinessPremiseName(firstPremise.business_premise_name);
309
+ setSelectedFinaElectronicDeviceName(firstDevice.electronic_device_name);
296
310
  }
297
- }, [isFinaEnabled, hasFinaPremises, activeFinaPremises, entityId, selectedFinaPremiseId]);
311
+ }, [isFinaEnabled, hasFinaPremises, activeFinaPremises, entityId, selectedFinaBusinessPremiseName]);
298
312
 
299
313
  // When FINA premise changes, select first active device
300
314
  useEffect(() => {
301
- if (!selectedFinaPremiseId) return;
302
- const premise = activeFinaPremises.find((p: any) => p.premise_id === selectedFinaPremiseId);
315
+ if (!selectedFinaBusinessPremiseName) return;
316
+ const premise = activeFinaPremises.find((p: any) => p.business_premise_name === selectedFinaBusinessPremiseName);
303
317
  const firstDevice = premise?.Devices?.find((d: any) => d.is_active);
304
- if (firstDevice && selectedFinaDeviceId !== firstDevice.device_id) {
318
+ if (firstDevice && selectedFinaElectronicDeviceName !== firstDevice.electronic_device_name) {
305
319
  const currentDeviceInPremise = premise?.Devices?.find(
306
- (d: any) => d.device_id === selectedFinaDeviceId && d.is_active,
320
+ (d: any) => d.electronic_device_name === selectedFinaElectronicDeviceName && d.is_active,
307
321
  );
308
322
  if (!currentDeviceInPremise) {
309
- setSelectedFinaDeviceId(firstDevice.device_id);
323
+ setSelectedFinaElectronicDeviceName(firstDevice.electronic_device_name);
310
324
  }
311
325
  }
312
- }, [selectedFinaPremiseId, activeFinaPremises, selectedFinaDeviceId]);
326
+ }, [selectedFinaBusinessPremiseName, activeFinaPremises, selectedFinaElectronicDeviceName]);
313
327
 
314
328
  const form = useForm<CreateInvoiceFormValues>({
315
329
  // Cast resolver to accept extended form type (includes UI-only fields)
@@ -321,13 +335,18 @@ export default function CreateInvoiceForm({
321
335
  // Cast customer to form schema type (API type may have additional fields)
322
336
  customer: (initialValues?.customer as CreateInvoiceFormValues["customer"]) ?? undefined,
323
337
  items: initialValues?.items?.length
324
- ? initialValues.items.map((item) => ({
338
+ ? initialValues.items.map((item: any) => ({
339
+ type: item.type,
325
340
  name: item.name || "",
326
341
  description: item.description || "",
327
- quantity: item.quantity ?? 1,
328
- // Use gross_price if set, otherwise use price
329
- price: item.gross_price ?? item.price,
330
- taxes: item.taxes || [],
342
+ ...(item.type !== "separator"
343
+ ? {
344
+ quantity: item.quantity ?? 1,
345
+ // Use gross_price if set, otherwise use price
346
+ price: item.gross_price ?? item.price,
347
+ taxes: item.taxes || [],
348
+ }
349
+ : {}),
331
350
  }))
332
351
  : [
333
352
  {
@@ -339,8 +358,11 @@ export default function CreateInvoiceForm({
339
358
  },
340
359
  ],
341
360
  currency_code: initialValues?.currency_code || activeEntity?.currency_code || "EUR",
361
+ reference: (initialValues as any)?.reference ?? "",
342
362
  note: initialValues?.note ?? defaultInvoiceNote,
363
+ tax_clause: (initialValues as any)?.tax_clause ?? "",
343
364
  payment_terms: initialValues?.payment_terms ?? defaultPaymentTerms,
365
+ footer: (initialValues as any)?.footer ?? defaultFooter,
344
366
  date_due:
345
367
  initialValues?.date_due ||
346
368
  calculateDueDate(initialValues?.date || new Date().toISOString(), defaultInvoiceDueDays),
@@ -366,6 +388,20 @@ export default function CreateInvoiceForm({
366
388
  }
367
389
  }, [serviceDateType, form]);
368
390
 
391
+ // Handle due days type change - recalculate due date for presets
392
+ const handleDueDaysTypeChange = useCallback(
393
+ (type: number | "custom") => {
394
+ setDueDaysType(type);
395
+ if (type !== "custom") {
396
+ const currentDate = form.getValues("date");
397
+ if (currentDate) {
398
+ form.setValue("date_due", calculateDueDate(currentDate, type));
399
+ }
400
+ }
401
+ },
402
+ [form],
403
+ );
404
+
369
405
  // Check if FURS selection is ready (needed to prevent number flashing)
370
406
  // Selection is ready when: FURS not enabled, OR no premises, OR we have a valid selection
371
407
  const isFursSelectionReady = !isFursEnabled || !hasFursPremises || (!!selectedPremiseName && !!selectedDeviceName);
@@ -376,8 +412,9 @@ export default function CreateInvoiceForm({
376
412
 
377
413
  // FINA selection ready and active checks
378
414
  const isFinaSelectionReady =
379
- !isFinaEnabled || !hasFinaPremises || (!!selectedFinaPremiseId && !!selectedFinaDeviceId);
380
- const isFinaActive = isFinaEnabled && hasFinaPremises && selectedFinaPremiseId && selectedFinaDeviceId;
415
+ !isFinaEnabled || !hasFinaPremises || (!!selectedFinaBusinessPremiseName && !!selectedFinaElectronicDeviceName);
416
+ const isFinaActive =
417
+ isFinaEnabled && hasFinaPremises && selectedFinaBusinessPremiseName && selectedFinaElectronicDeviceName;
381
418
 
382
419
  // ============================================================================
383
420
  // Next Invoice Number Preview
@@ -529,7 +566,13 @@ export default function CreateInvoiceForm({
529
566
  // ============================================================================
530
567
  // VIES Check - determine if reverse charge applies
531
568
  // ============================================================================
532
- const { reverseChargeApplies, warning: viesWarning } = useViesCheck({
569
+ const {
570
+ reverseChargeApplies,
571
+ transactionType,
572
+ customerCountryCode: viesCustomerCountryCode,
573
+ isFetching: isViesFetching,
574
+ warning: viesWarning,
575
+ } = useViesCheck({
533
576
  issuerCountryCode: activeEntity?.country_code,
534
577
  isTaxSubject: activeEntity?.is_tax_subject ?? true,
535
578
  customerCountry,
@@ -538,6 +581,26 @@ export default function CreateInvoiceForm({
538
581
  enabled: !!activeEntity,
539
582
  });
540
583
 
584
+ // FINA non-domestic guard: hide FINA selectors for non-domestic transactions
585
+ // When unified_numbering is enabled (default: true), show FINA selectors for all transactions
586
+ const finaUnifiedNumbering = finaSettings?.unified_numbering !== false;
587
+ const isFinaNonDomestic =
588
+ isFinaEnabled && !finaUnifiedNumbering && viesCustomerCountryCode != null && viesCustomerCountryCode !== "HR";
589
+
590
+ // Auto-populate tax_clause from entity settings when transaction type changes
591
+ const effectiveTransactionType = transactionType ?? "domestic";
592
+ const prevTransactionTypeRef = useRef<string | undefined>(undefined);
593
+ useEffect(() => {
594
+ if (effectiveTransactionType === prevTransactionTypeRef.current) return;
595
+ prevTransactionTypeRef.current = effectiveTransactionType;
596
+
597
+ const taxClauseDefaults = (activeEntity?.settings as any)?.tax_clause_defaults;
598
+ if (!taxClauseDefaults) return;
599
+
600
+ const clause = taxClauseDefaults[effectiveTransactionType] ?? "";
601
+ form.setValue("tax_clause", clause);
602
+ }, [effectiveTransactionType, activeEntity, form]);
603
+
541
604
  // Extract customer management logic into a custom hook
542
605
  const {
543
606
  originalCustomer,
@@ -560,10 +623,10 @@ export default function CreateInvoiceForm({
560
623
  });
561
624
  }
562
625
  // Save FINA combo to localStorage on successful creation
563
- if (isFinaActive && selectedFinaPremiseId && selectedFinaDeviceId) {
626
+ if (isFinaActive && selectedFinaBusinessPremiseName && selectedFinaElectronicDeviceName) {
564
627
  setLastUsedFinaCombo(entityId, {
565
- premise_id: selectedFinaPremiseId,
566
- device_id: selectedFinaDeviceId,
628
+ business_premise_name: selectedFinaBusinessPremiseName,
629
+ electronic_device_name: selectedFinaElectronicDeviceName,
567
630
  });
568
631
  }
569
632
  // Invalidate customers cache when a customer was created/linked
@@ -624,10 +687,19 @@ export default function CreateInvoiceForm({
624
687
  : undefined
625
688
  : undefined;
626
689
 
627
- // Build FINA options (skip for drafts and edit mode; FINA can't be skipped)
690
+ // Build FINA options (skip for drafts, edit mode, and non-domestic transactions)
628
691
  const finaOptions =
629
- !isDraft && !isEditMode && isFinaEnabled && selectedFinaPremiseId && selectedFinaDeviceId
630
- ? { premise_id: selectedFinaPremiseId, device_id: selectedFinaDeviceId, payment_type: paymentTypes[0] }
692
+ !isDraft &&
693
+ !isEditMode &&
694
+ isFinaEnabled &&
695
+ !isFinaNonDomestic &&
696
+ selectedFinaBusinessPremiseName &&
697
+ selectedFinaElectronicDeviceName
698
+ ? {
699
+ business_premise_name: selectedFinaBusinessPremiseName,
700
+ electronic_device_name: selectedFinaElectronicDeviceName,
701
+ payment_type: paymentTypes[0],
702
+ }
631
703
  : undefined;
632
704
 
633
705
  // Build e-SLOG options (skip for drafts and edit mode)
@@ -674,13 +746,14 @@ export default function CreateInvoiceForm({
674
746
  isEslogAvailable,
675
747
  isFursEnabled,
676
748
  isFinaEnabled,
749
+ isFinaNonDomestic,
677
750
  markAsPaid,
678
751
  originalCustomer,
679
752
  paymentTypes,
680
753
  selectedDeviceName,
681
754
  selectedPremiseName,
682
- selectedFinaPremiseId,
683
- selectedFinaDeviceId,
755
+ selectedFinaBusinessPremiseName,
756
+ selectedFinaElectronicDeviceName,
684
757
  showCustomerForm,
685
758
  skipFiscalization,
686
759
  ],
@@ -717,7 +790,8 @@ export default function CreateInvoiceForm({
717
790
  );
718
791
 
719
792
  // Watch isDirty to get stable reference
720
- const isDirty = form.formState.isDirty;
793
+ // When form is pre-populated via initialValues (duplicate/merge), treat as dirty immediately
794
+ const isDirty = form.formState.isDirty || !!initialValues;
721
795
 
722
796
  useFormFooterRegistration({
723
797
  formId: "create-invoice-form",
@@ -744,14 +818,23 @@ export default function CreateInvoiceForm({
744
818
  if (entityDefaultPaymentTerms && !form.getValues("payment_terms")) {
745
819
  form.setValue("payment_terms", entityDefaultPaymentTerms);
746
820
  }
821
+ const entityDefaultFooter = (activeEntity.settings as any)?.document_footer;
822
+ if (entityDefaultFooter && !form.getValues("footer")) {
823
+ form.setValue("footer", entityDefaultFooter);
824
+ }
825
+ const entityDefaultSignature = (activeEntity.settings as any)?.default_document_signature;
826
+ if (entityDefaultSignature && !form.getValues("signature")) {
827
+ form.setValue("signature", entityDefaultSignature);
828
+ }
747
829
 
748
- // Auto-populate due date from entity settings when entity loads async
830
+ // Auto-populate due date and due days type from entity settings when entity loads async
749
831
  if (!isEditMode && !initialValues?.date_due) {
750
832
  const dueDays = (activeEntity.settings as any)?.default_invoice_due_days ?? 30;
751
833
  const currentDate = form.getValues("date");
752
834
  if (currentDate) {
753
835
  form.setValue("date_due", calculateDueDate(currentDate, dueDays));
754
836
  }
837
+ setDueDaysType((DUE_DAYS_PRESETS as readonly number[]).includes(dueDays) ? dueDays : "custom");
755
838
  }
756
839
 
757
840
  // Auto-add tax field for tax subject entities
@@ -765,15 +848,16 @@ export default function CreateInvoiceForm({
765
848
  initialSetupDoneRef.current = true;
766
849
  }, [activeEntity, form, isEditMode, initialValues?.date_due]);
767
850
 
768
- // Recalculate due date when document date changes (skip in edit mode)
851
+ // Recalculate due date when document date changes (skip in edit mode and custom due days)
769
852
  const prevDateRef = useRef(form.getValues("date"));
770
853
  useEffect(() => {
771
854
  if (isEditMode) return;
772
855
  if (!watchedDate || watchedDate === prevDateRef.current) return;
773
856
  prevDateRef.current = watchedDate;
774
- const dueDays = (activeEntity?.settings as any)?.default_invoice_due_days ?? 30;
775
- form.setValue("date_due", calculateDueDate(watchedDate, dueDays));
776
- }, [watchedDate, activeEntity, isEditMode, form]);
857
+ if (dueDaysType !== "custom") {
858
+ form.setValue("date_due", calculateDueDate(watchedDate, dueDaysType));
859
+ }
860
+ }, [watchedDate, isEditMode, form, dueDaysType]);
777
861
 
778
862
  // Use form.watch subscription for onChange callback (avoids re-render loops)
779
863
  const prevPayloadRef = useRef<string>("");
@@ -795,8 +879,10 @@ export default function CreateInvoiceForm({
795
879
  customer: formValues.customer,
796
880
  items: transformedItems,
797
881
  currency_code: formValues.currency_code,
882
+ reference: formValues.reference,
798
883
  note: formValues.note,
799
884
  payment_terms: formValues.payment_terms,
885
+ signature: formValues.signature,
800
886
  };
801
887
  };
802
888
 
@@ -931,14 +1017,20 @@ export default function CreateInvoiceForm({
931
1017
  : undefined
932
1018
  }
933
1019
  finaInline={
934
- !isEditMode && isFinaEnabled && hasFinaPremises
1020
+ !isEditMode && isFinaEnabled && hasFinaPremises && !isFinaNonDomestic
935
1021
  ? {
936
- premises: activeFinaPremises.map((p: any) => ({ id: p.id, premise_id: p.premise_id })),
937
- devices: activeFinaDevices.map((d: any) => ({ id: d.id, device_id: d.device_id })),
938
- selectedPremise: selectedFinaPremiseId,
939
- selectedDevice: selectedFinaDeviceId,
940
- onPremiseChange: setSelectedFinaPremiseId,
941
- onDeviceChange: setSelectedFinaDeviceId,
1022
+ premises: activeFinaPremises.map((p: any) => ({
1023
+ id: p.id,
1024
+ business_premise_name: p.business_premise_name,
1025
+ })),
1026
+ devices: activeFinaDevices.map((d: any) => ({
1027
+ id: d.id,
1028
+ electronic_device_name: d.electronic_device_name,
1029
+ })),
1030
+ selectedPremise: selectedFinaBusinessPremiseName,
1031
+ selectedDevice: selectedFinaElectronicDeviceName,
1032
+ onPremiseChange: setSelectedFinaBusinessPremiseName,
1033
+ onDeviceChange: setSelectedFinaElectronicDeviceName,
942
1034
  }
943
1035
  : undefined
944
1036
  }
@@ -946,6 +1038,10 @@ export default function CreateInvoiceForm({
946
1038
  dateType: serviceDateType,
947
1039
  onDateTypeChange: setServiceDateType,
948
1040
  }}
1041
+ dueDays={{
1042
+ dueDaysType,
1043
+ onDueDaysTypeChange: handleDueDaysTypeChange,
1044
+ }}
949
1045
  >
950
1046
  {/* Invoice-specific: Mark as paid section (UI-only state, not in form schema) */}
951
1047
  {/* Hide in edit mode - payments are managed separately */}
@@ -993,6 +1089,22 @@ export default function CreateInvoiceForm({
993
1089
  }}
994
1090
  />
995
1091
 
1092
+ <DocumentTaxClauseField
1093
+ control={form.control}
1094
+ t={t}
1095
+ entity={activeEntity}
1096
+ document={{
1097
+ number: watchedNumber,
1098
+ date: watchedDate,
1099
+ date_due: watchedDateDue,
1100
+ currency_code: watchedCurrencyCode,
1101
+ customer: watchedCustomer as any,
1102
+ }}
1103
+ transactionType={transactionType}
1104
+ isTransactionTypeFetching={isViesFetching}
1105
+ isFinaNonDomestic={isFinaNonDomestic}
1106
+ />
1107
+
996
1108
  <DocumentPaymentTermsField
997
1109
  control={form.control}
998
1110
  t={t}
@@ -1006,6 +1118,32 @@ export default function CreateInvoiceForm({
1006
1118
  }}
1007
1119
  />
1008
1120
 
1121
+ <DocumentSignatureField
1122
+ control={form.control}
1123
+ t={t}
1124
+ entity={activeEntity}
1125
+ document={{
1126
+ number: watchedNumber,
1127
+ date: watchedDate,
1128
+ date_due: watchedDateDue,
1129
+ currency_code: watchedCurrencyCode,
1130
+ customer: watchedCustomer as any,
1131
+ }}
1132
+ />
1133
+
1134
+ <DocumentFooterField
1135
+ control={form.control}
1136
+ t={t}
1137
+ entity={activeEntity}
1138
+ document={{
1139
+ number: watchedNumber,
1140
+ date: watchedDate,
1141
+ date_due: watchedDateDue,
1142
+ currency_code: watchedCurrencyCode,
1143
+ customer: watchedCustomer as any,
1144
+ }}
1145
+ />
1146
+
1009
1147
  {sourceDocuments && sourceDocuments.length > 0 && (
1010
1148
  <LinkedDocumentsInfo documents={sourceDocuments} locale={locale || "en"} t={t} />
1011
1149
  )}
@@ -40,6 +40,9 @@ export default {
40
40
  "Insert variable": "Variable einfügen",
41
41
  "Add payment instructions, terms, or other notes...":
42
42
  "Zahlungsanweisungen, Bedingungen oder andere Notizen hinzufügen...",
43
+ // Signature field
44
+ Signature: "Unterschrift",
45
+ "Add signature text...": "Unterschriftstext hinzufügen...",
43
46
  // Payment terms field
44
47
  "Payment Terms": "Zahlungsbedingungen",
45
48
  "Add payment terms...": "Zahlungsbedingungen hinzufügen...",
@@ -120,10 +123,35 @@ export default {
120
123
  "Advance invoice": "Vorausrechnung",
121
124
  "FINA fiscalized invoices always use the current date":
122
125
  "FINA-fiskalisierte Rechnungen verwenden immer das aktuelle Datum",
126
+ // Due days selector
127
+ "On receipt": "Bei Erhalt",
128
+ "7 days": "7 Tage",
129
+ "14 days": "14 Tage",
130
+ "30 days": "30 Tage",
131
+ "60 days": "60 Tage",
132
+ "90 days": "90 Tage",
133
+ Custom: "Benutzerdefiniert",
123
134
  // Service date
124
135
  "Service Date": "Leistungsdatum",
125
136
  "Single Date": "Datum",
126
137
  "Date Range": "Zeitraum",
127
138
  From: "Von",
128
139
  To: "Bis",
140
+ // Separator items
141
+ "Add separator": "Trennzeile hinzufügen",
142
+ "Section header": "Abschnittsüberschrift",
143
+ "Section title...": "Abschnittstitel...",
144
+ // Transaction type
145
+ "Transaction type": "Transaktionstyp",
146
+ Domestic: "Inland",
147
+ "EU B2B": "EU B2B",
148
+ "EU B2C": "EU B2C",
149
+ Export: "Export",
150
+ "Determining transaction type...": "Transaktionstyp wird ermittelt...",
151
+ "This invoice will not be fiscalized (non-domestic transaction)":
152
+ "Diese Rechnung wird nicht fiskalisiert (nicht-inländische Transaktion)",
153
+ "Tax Clause": "Steuerklausel",
154
+ "Add tax clause...": "Steuerklausel hinzufügen...",
155
+ Footer: "Fußzeile",
156
+ "Add document footer...": "Dokumentfußzeile hinzufügen...",
129
157
  } as const;
@@ -38,6 +38,9 @@ export default {
38
38
  Note: "Nota",
39
39
  "Insert variable": "Insertar variable",
40
40
  "Add payment instructions, terms, or other notes...": "Añada instrucciones de pago, condiciones u otras notas...",
41
+ // Signature field
42
+ Signature: "Firma",
43
+ "Add signature text...": "Añadir texto de firma...",
41
44
  "Payment Terms": "Condiciones de pago",
42
45
  "Add payment terms...": "Añada condiciones de pago...",
43
46
  Entity: "Empresa",
@@ -106,9 +109,34 @@ export default {
106
109
  "Advance invoice": "Factura anticipada",
107
110
  "FINA fiscalized invoices always use the current date":
108
111
  "Las facturas fiscalizadas con FINA siempre usan la fecha actual",
112
+ // Due days selector
113
+ "On receipt": "Al recibir",
114
+ "7 days": "7 días",
115
+ "14 days": "14 días",
116
+ "30 days": "30 días",
117
+ "60 days": "60 días",
118
+ "90 days": "90 días",
119
+ Custom: "Personalizado",
109
120
  "Service Date": "Fecha de servicio",
110
121
  "Single Date": "Fecha única",
111
122
  "Date Range": "Rango de fechas",
112
123
  From: "Desde",
113
124
  To: "Hasta",
125
+ // Separator items
126
+ "Add separator": "Añadir separador",
127
+ "Section header": "Encabezado de sección",
128
+ "Section title...": "Título de sección...",
129
+ // Transaction type
130
+ "Transaction type": "Tipo de transacción",
131
+ Domestic: "Nacional",
132
+ "EU B2B": "EU B2B",
133
+ "EU B2C": "EU B2C",
134
+ Export: "Exportación",
135
+ "Determining transaction type...": "Determinando tipo de transacción...",
136
+ "This invoice will not be fiscalized (non-domestic transaction)":
137
+ "Esta factura no será fiscalizada (transacción no nacional)",
138
+ "Tax Clause": "Cláusula fiscal",
139
+ "Add tax clause...": "Agregar cláusula fiscal...",
140
+ Footer: "Pie de página",
141
+ "Add document footer...": "Añadir pie de página del documento...",
114
142
  } as const;
@@ -40,6 +40,9 @@ export default {
40
40
  "Insert variable": "Insérer une variable",
41
41
  "Add payment instructions, terms, or other notes...":
42
42
  "Ajoutez des instructions de paiement, des conditions ou d'autres notes...",
43
+ // Signature field
44
+ Signature: "Signature",
45
+ "Add signature text...": "Ajouter un texte de signature...",
43
46
  "Payment Terms": "Conditions de paiement",
44
47
  "Add payment terms...": "Ajoutez des conditions de paiement...",
45
48
  Entity: "Entreprise",
@@ -108,9 +111,34 @@ export default {
108
111
  "Advance invoice": "Facture d'acompte",
109
112
  "FINA fiscalized invoices always use the current date":
110
113
  "Les factures fiscalisées FINA utilisent toujours la date actuelle",
114
+ // Due days selector
115
+ "On receipt": "À réception",
116
+ "7 days": "7 jours",
117
+ "14 days": "14 jours",
118
+ "30 days": "30 jours",
119
+ "60 days": "60 jours",
120
+ "90 days": "90 jours",
121
+ Custom: "Personnalisé",
111
122
  "Service Date": "Date de service",
112
123
  "Single Date": "Date unique",
113
124
  "Date Range": "Plage de dates",
114
125
  From: "Du",
115
126
  To: "Au",
127
+ // Separator items
128
+ "Add separator": "Ajouter un séparateur",
129
+ "Section header": "En-tête de section",
130
+ "Section title...": "Titre de section...",
131
+ // Transaction type
132
+ "Transaction type": "Type de transaction",
133
+ Domestic: "Nationale",
134
+ "EU B2B": "EU B2B",
135
+ "EU B2C": "EU B2C",
136
+ Export: "Exportation",
137
+ "Determining transaction type...": "Détermination du type de transaction...",
138
+ "This invoice will not be fiscalized (non-domestic transaction)":
139
+ "Cette facture ne sera pas fiscalisée (transaction non nationale)",
140
+ "Tax Clause": "Clause fiscale",
141
+ "Add tax clause...": "Ajouter une clause fiscale...",
142
+ Footer: "Pied de page",
143
+ "Add document footer...": "Ajouter un pied de page...",
116
144
  } as const;
@@ -38,6 +38,9 @@ export default {
38
38
  Note: "Napomena",
39
39
  "Insert variable": "Umetni varijablu",
40
40
  "Add payment instructions, terms, or other notes...": "Dodajte upute za plaćanje, uvjete ili druge napomene...",
41
+ // Signature field
42
+ Signature: "Potpis",
43
+ "Add signature text...": "Dodaj tekst potpisa...",
41
44
  "Payment Terms": "Uvjeti plaćanja",
42
45
  "Add payment terms...": "Dodajte uvjete plaćanja...",
43
46
  Entity: "Tvrtka",
@@ -105,9 +108,34 @@ export default {
105
108
  "Credit note": "Odobrenje",
106
109
  "Advance invoice": "Avansni račun",
107
110
  "FINA fiscalized invoices always use the current date": "FINA fiskalizirani računi uvijek koriste trenutni datum",
111
+ // Due days selector
112
+ "On receipt": "Po primitku",
113
+ "7 days": "7 dana",
114
+ "14 days": "14 dana",
115
+ "30 days": "30 dana",
116
+ "60 days": "60 dana",
117
+ "90 days": "90 dana",
118
+ Custom: "Prilagođeno",
108
119
  "Service Date": "Datum usluge",
109
120
  "Single Date": "Datum",
110
121
  "Date Range": "Raspon datuma",
111
122
  From: "Od",
112
123
  To: "Do",
124
+ // Separator items
125
+ "Add separator": "Dodaj separator",
126
+ "Section header": "Naslov odjeljka",
127
+ "Section title...": "Naslov odjeljka...",
128
+ // Transaction type
129
+ "Transaction type": "Vrsta transakcije",
130
+ Domestic: "Domaća",
131
+ "EU B2B": "EU B2B",
132
+ "EU B2C": "EU B2C",
133
+ Export: "Izvoz",
134
+ "Determining transaction type...": "Određivanje vrste transakcije...",
135
+ "This invoice will not be fiscalized (non-domestic transaction)":
136
+ "Ovaj račun neće biti fiskaliziran (nedomaća transakcija)",
137
+ "Tax Clause": "Porezna klauzula",
138
+ "Add tax clause...": "Dodajte poreznu klauzulu...",
139
+ Footer: "Podnožje",
140
+ "Add document footer...": "Dodajte podnožje dokumenta...",
113
141
  } as const;
@@ -39,6 +39,9 @@ export default {
39
39
  Note: "Nota",
40
40
  "Insert variable": "Inserisci variabile",
41
41
  "Add payment instructions, terms, or other notes...": "Aggiungi istruzioni di pagamento, condizioni o altre note...",
42
+ // Signature field
43
+ Signature: "Firma",
44
+ "Add signature text...": "Aggiungi testo della firma...",
42
45
  "Payment Terms": "Condizioni di pagamento",
43
46
  "Add payment terms...": "Aggiungi condizioni di pagamento...",
44
47
  Entity: "Azienda",
@@ -108,9 +111,34 @@ export default {
108
111
  "Advance invoice": "Fattura di acconto",
109
112
  "FINA fiscalized invoices always use the current date":
110
113
  "Le fatture fiscalizzate FINA utilizzano sempre la data corrente",
114
+ // Due days selector
115
+ "On receipt": "Alla ricezione",
116
+ "7 days": "7 giorni",
117
+ "14 days": "14 giorni",
118
+ "30 days": "30 giorni",
119
+ "60 days": "60 giorni",
120
+ "90 days": "90 giorni",
121
+ Custom: "Personalizzato",
111
122
  "Service Date": "Data del servizio",
112
123
  "Single Date": "Data singola",
113
124
  "Date Range": "Intervallo di date",
114
125
  From: "Da",
115
126
  To: "A",
127
+ // Separator items
128
+ "Add separator": "Aggiungi separatore",
129
+ "Section header": "Intestazione sezione",
130
+ "Section title...": "Titolo sezione...",
131
+ // Transaction type
132
+ "Transaction type": "Tipo di transazione",
133
+ Domestic: "Nazionale",
134
+ "EU B2B": "EU B2B",
135
+ "EU B2C": "EU B2C",
136
+ Export: "Esportazione",
137
+ "Determining transaction type...": "Determinazione tipo di transazione...",
138
+ "This invoice will not be fiscalized (non-domestic transaction)":
139
+ "Questa fattura non sarà fiscalizzata (transazione non nazionale)",
140
+ "Tax Clause": "Clausola fiscale",
141
+ "Add tax clause...": "Aggiungi clausola fiscale...",
142
+ Footer: "Piè di pagina",
143
+ "Add document footer...": "Aggiungi piè di pagina del documento...",
116
144
  } as const;