@spaceinvoices/react-ui 0.4.1 → 0.4.3

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 (245) hide show
  1. package/cli/dist/index.js +1 -1
  2. package/package.json +1 -1
  3. package/registry.json +25 -0
  4. package/src/components/advance-invoices/advance-invoices.hooks.ts +32 -2
  5. package/src/components/advance-invoices/create/create-advance-invoice-form.tsx +109 -4
  6. package/src/components/advance-invoices/create/locales/de.ts +2 -0
  7. package/src/components/advance-invoices/create/locales/es.ts +2 -0
  8. package/src/components/advance-invoices/create/locales/fr.ts +2 -0
  9. package/src/components/advance-invoices/create/locales/hr.ts +2 -0
  10. package/src/components/advance-invoices/create/locales/it.ts +2 -0
  11. package/src/components/advance-invoices/create/locales/nl.ts +2 -0
  12. package/src/components/advance-invoices/create/locales/pl.ts +2 -0
  13. package/src/components/advance-invoices/create/locales/pt.ts +2 -0
  14. package/src/components/advance-invoices/create/locales/sl.ts +2 -0
  15. package/src/components/advance-invoices/create/prepare-advance-invoice-submission.ts +17 -0
  16. package/src/components/advance-invoices/list/list-row-actions.tsx +3 -6
  17. package/src/components/advance-invoices/list/list-table.tsx +105 -2
  18. package/src/components/advance-invoices/list/locales/de.ts +4 -0
  19. package/src/components/advance-invoices/list/locales/en.ts +4 -0
  20. package/src/components/advance-invoices/list/locales/es.ts +4 -0
  21. package/src/components/advance-invoices/list/locales/fr.ts +4 -0
  22. package/src/components/advance-invoices/list/locales/hr.ts +4 -0
  23. package/src/components/advance-invoices/list/locales/it.ts +4 -0
  24. package/src/components/advance-invoices/list/locales/nl.ts +4 -0
  25. package/src/components/advance-invoices/list/locales/pl.ts +4 -0
  26. package/src/components/advance-invoices/list/locales/pt.ts +4 -0
  27. package/src/components/advance-invoices/list/locales/sl.ts +4 -0
  28. package/src/components/credit-notes/create/create-credit-note-form.tsx +177 -6
  29. package/src/components/credit-notes/create/locales/de.ts +8 -0
  30. package/src/components/credit-notes/create/locales/es.ts +8 -0
  31. package/src/components/credit-notes/create/locales/fr.ts +7 -0
  32. package/src/components/credit-notes/create/locales/hr.ts +7 -0
  33. package/src/components/credit-notes/create/locales/it.ts +9 -0
  34. package/src/components/credit-notes/create/locales/nl.ts +7 -0
  35. package/src/components/credit-notes/create/locales/pl.ts +7 -0
  36. package/src/components/credit-notes/create/locales/pt.ts +7 -0
  37. package/src/components/credit-notes/create/locales/sl.ts +7 -0
  38. package/src/components/credit-notes/credit-notes.hooks.ts +30 -0
  39. package/src/components/credit-notes/list/list-row-actions.tsx +3 -6
  40. package/src/components/credit-notes/list/list-table.tsx +79 -8
  41. package/src/components/credit-notes/list/locales/de.ts +4 -1
  42. package/src/components/credit-notes/list/locales/en.ts +5 -0
  43. package/src/components/credit-notes/list/locales/es.ts +4 -1
  44. package/src/components/credit-notes/list/locales/fr.ts +4 -1
  45. package/src/components/credit-notes/list/locales/hr.ts +4 -1
  46. package/src/components/credit-notes/list/locales/it.ts +4 -1
  47. package/src/components/credit-notes/list/locales/nl.ts +4 -1
  48. package/src/components/credit-notes/list/locales/pl.ts +4 -1
  49. package/src/components/credit-notes/list/locales/pt.ts +4 -1
  50. package/src/components/credit-notes/list/locales/sl.ts +4 -1
  51. package/src/components/customers/create-customer-form/create-customer-form.tsx +0 -1
  52. package/src/components/dashboard/collection-rate-card/use-collection-rate.ts +2 -2
  53. package/src/components/dashboard/invoice-status-chart/use-invoice-status.ts +3 -3
  54. package/src/components/dashboard/payment-methods-chart/use-payment-methods.ts +1 -1
  55. package/src/components/dashboard/payment-trend-chart/use-payment-trend.ts +1 -1
  56. package/src/components/dashboard/revenue-trend-chart/use-revenue-trend.ts +1 -1
  57. package/src/components/dashboard/shared/use-revenue-data.ts +4 -4
  58. package/src/components/dashboard/shared/use-stats-counts.ts +4 -4
  59. package/src/components/dashboard/shared/use-stats-query.ts +1 -1
  60. package/src/components/dashboard/tax-collected-card/use-tax-collected.ts +2 -2
  61. package/src/components/dashboard/top-customers-chart/use-top-customers.ts +1 -1
  62. package/src/components/delivery-notes/create/create-delivery-note-form.tsx +332 -0
  63. package/src/components/delivery-notes/create/locales/de.ts +50 -0
  64. package/src/components/delivery-notes/create/locales/es.ts +49 -0
  65. package/src/components/delivery-notes/create/locales/fr.ts +50 -0
  66. package/src/components/delivery-notes/create/locales/hr.ts +49 -0
  67. package/src/components/delivery-notes/create/locales/it.ts +49 -0
  68. package/src/components/delivery-notes/create/locales/nl.ts +50 -0
  69. package/src/components/delivery-notes/create/locales/pl.ts +49 -0
  70. package/src/components/delivery-notes/create/locales/pt.ts +50 -0
  71. package/src/components/delivery-notes/create/locales/sl.ts +49 -0
  72. package/src/components/delivery-notes/create/prepare-delivery-note-submission.ts +38 -0
  73. package/src/components/delivery-notes/create/use-delivery-note-customer-form.ts +1 -0
  74. package/src/components/delivery-notes/delivery-notes.hooks.ts +15 -0
  75. package/src/components/delivery-notes/list/index.ts +3 -0
  76. package/src/components/delivery-notes/list/list-row-actions.tsx +103 -0
  77. package/src/components/delivery-notes/list/list-table.tsx +214 -0
  78. package/src/components/delivery-notes/list/locales/de.ts +9 -0
  79. package/src/components/delivery-notes/list/locales/en.ts +11 -0
  80. package/src/components/delivery-notes/list/locales/es.ts +9 -0
  81. package/src/components/delivery-notes/list/locales/fr.ts +9 -0
  82. package/src/components/delivery-notes/list/locales/hr.ts +9 -0
  83. package/src/components/delivery-notes/list/locales/it.ts +9 -0
  84. package/src/components/delivery-notes/list/locales/nl.ts +9 -0
  85. package/src/components/delivery-notes/list/locales/pl.ts +9 -0
  86. package/src/components/delivery-notes/list/locales/pt.ts +9 -0
  87. package/src/components/delivery-notes/list/locales/sl.ts +9 -0
  88. package/src/components/delivery-notes/list/use-delivery-note-download.ts +63 -0
  89. package/src/components/documents/create/document-details-section.tsx +103 -33
  90. package/src/components/documents/create/live-preview.tsx +37 -10
  91. package/src/components/documents/create/mark-as-paid-section.tsx +11 -2
  92. package/src/components/documents/create/prepare-document-submission.ts +1 -1
  93. package/src/components/documents/documents.hooks.ts +2 -1
  94. package/src/components/documents/shared/document-preview-display.tsx +12 -5
  95. package/src/components/documents/types.ts +10 -1
  96. package/src/components/documents/view/document-actions-bar.tsx +30 -0
  97. package/src/components/documents/view/document-details-card.tsx +3 -3
  98. package/src/components/documents/view/document-payments-list.tsx +3 -3
  99. package/src/components/documents/view/document-relations-list.tsx +105 -0
  100. package/src/components/documents/view/locales/de.ts +26 -0
  101. package/src/components/documents/view/locales/es.ts +26 -0
  102. package/src/components/documents/view/locales/fr.ts +26 -0
  103. package/src/components/documents/view/locales/hr.ts +26 -0
  104. package/src/components/documents/view/locales/it.ts +26 -0
  105. package/src/components/documents/view/locales/nl.ts +26 -0
  106. package/src/components/documents/view/locales/pl.ts +26 -0
  107. package/src/components/documents/view/locales/pt.ts +26 -0
  108. package/src/components/documents/view/locales/sl.ts +26 -0
  109. package/src/components/documents/view/use-document-download.ts +5 -3
  110. package/src/components/entities/create-entity-form.tsx +1 -1
  111. package/src/components/entities/entity-settings-form/entity-settings-form.tsx +2 -3
  112. package/src/components/entities/entity-settings-form/locales/es.ts +2 -0
  113. package/src/components/entities/entity-settings-form/locales/fr.ts +2 -0
  114. package/src/components/entities/entity-settings-form/locales/hr.ts +2 -0
  115. package/src/components/entities/entity-settings-form/locales/it.ts +2 -0
  116. package/src/components/entities/entity-settings-form/locales/nl.ts +2 -0
  117. package/src/components/entities/entity-settings-form/locales/pl.ts +2 -0
  118. package/src/components/entities/entity-settings-form/locales/pt.ts +2 -0
  119. package/src/components/entities/fina-settings-form/fina-operator-required-dialog.tsx +109 -0
  120. package/src/components/entities/fina-settings-form/fina-settings-form.tsx +377 -35
  121. package/src/components/entities/fina-settings-form/fina-settings.hooks.ts +106 -20
  122. package/src/components/entities/fina-settings-form/index.ts +1 -0
  123. package/src/components/entities/fina-settings-form/locales/de.ts +54 -34
  124. package/src/components/entities/fina-settings-form/locales/en.ts +51 -34
  125. package/src/components/entities/fina-settings-form/locales/es.ts +50 -34
  126. package/src/components/entities/fina-settings-form/locales/fr.ts +50 -34
  127. package/src/components/entities/fina-settings-form/locales/hr.ts +50 -34
  128. package/src/components/entities/fina-settings-form/locales/it.ts +50 -34
  129. package/src/components/entities/fina-settings-form/locales/nl.ts +50 -34
  130. package/src/components/entities/fina-settings-form/locales/pl.ts +50 -34
  131. package/src/components/entities/fina-settings-form/locales/pt.ts +50 -34
  132. package/src/components/entities/fina-settings-form/locales/sl.ts +50 -34
  133. package/src/components/entities/fina-settings-form/sections/certificate-settings-section.tsx +18 -0
  134. package/src/components/entities/fina-settings-form/sections/premises-management-section.tsx +64 -89
  135. package/src/components/entities/fina-settings-form/sections/register-premise-dialog.tsx +51 -323
  136. package/src/components/entities/furs-settings-form/furs-operator-required-dialog.tsx +106 -0
  137. package/src/components/entities/furs-settings-form/furs-settings-form.tsx +33 -10
  138. package/src/components/entities/furs-settings-form/furs-settings.hooks.ts +12 -11
  139. package/src/components/entities/furs-settings-form/index.ts +1 -0
  140. package/src/components/entities/furs-settings-form/locales/de.ts +27 -3
  141. package/src/components/entities/furs-settings-form/locales/en.ts +17 -3
  142. package/src/components/entities/furs-settings-form/locales/es.ts +26 -3
  143. package/src/components/entities/furs-settings-form/locales/fr.ts +26 -3
  144. package/src/components/entities/furs-settings-form/locales/hr.ts +26 -3
  145. package/src/components/entities/furs-settings-form/locales/it.ts +26 -3
  146. package/src/components/entities/furs-settings-form/locales/nl.ts +26 -3
  147. package/src/components/entities/furs-settings-form/locales/pl.ts +26 -3
  148. package/src/components/entities/furs-settings-form/locales/pt.ts +26 -3
  149. package/src/components/entities/furs-settings-form/locales/sl.ts +16 -3
  150. package/src/components/entities/furs-settings-form/sections/certificate-settings-section.tsx +22 -0
  151. package/src/components/entities/furs-settings-form/sections/general-settings-section.tsx +26 -5
  152. package/src/components/entities/furs-settings-form/sections/register-premise-dialog.tsx +14 -2
  153. package/src/components/entities/settings/tax-rules-settings-form.tsx +4 -4
  154. package/src/components/estimates/list/list-row-actions.tsx +3 -7
  155. package/src/components/estimates/list/list-table.tsx +35 -2
  156. package/src/components/estimates/list/locales/de.ts +3 -0
  157. package/src/components/estimates/list/locales/en.ts +3 -0
  158. package/src/components/estimates/list/locales/es.ts +3 -0
  159. package/src/components/estimates/list/locales/fr.ts +3 -0
  160. package/src/components/estimates/list/locales/hr.ts +3 -0
  161. package/src/components/estimates/list/locales/it.ts +3 -0
  162. package/src/components/estimates/list/locales/nl.ts +3 -0
  163. package/src/components/estimates/list/locales/pl.ts +3 -0
  164. package/src/components/estimates/list/locales/pt.ts +3 -0
  165. package/src/components/estimates/list/locales/sl.ts +3 -0
  166. package/src/components/export/document-export-form.tsx +34 -34
  167. package/src/components/invoices/create/create-invoice-form.tsx +107 -5
  168. package/src/components/invoices/create/prepare-invoice-submission.ts +17 -0
  169. package/src/components/invoices/invoices-furs.hooks.ts +24 -9
  170. package/src/components/invoices/invoices.hooks.ts +32 -2
  171. package/src/components/invoices/list/list-row-actions.tsx +26 -11
  172. package/src/components/invoices/list/list-table.tsx +121 -5
  173. package/src/components/invoices/list/locales/de.ts +5 -0
  174. package/src/components/invoices/list/locales/en.ts +5 -0
  175. package/src/components/invoices/list/locales/es.ts +5 -0
  176. package/src/components/invoices/list/locales/fr.ts +5 -0
  177. package/src/components/invoices/list/locales/hr.ts +5 -0
  178. package/src/components/invoices/list/locales/it.ts +5 -0
  179. package/src/components/invoices/list/locales/nl.ts +5 -0
  180. package/src/components/invoices/list/locales/pl.ts +5 -0
  181. package/src/components/invoices/list/locales/pt.ts +5 -0
  182. package/src/components/invoices/list/locales/sl.ts +5 -0
  183. package/src/components/invoices/view/fiscalization-status-card.tsx +4 -1
  184. package/src/components/items/item-list-table/item-list-row-actions.tsx +5 -8
  185. package/src/components/items/item-list-table/item-list-row.tsx +5 -3
  186. package/src/components/items/item-list-table/item-list-table.tsx +5 -1
  187. package/src/components/recurring-invoices/create-recurring-invoice-form/create-recurring-invoice-form.tsx +418 -0
  188. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/de.ts +45 -0
  189. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/es.ts +44 -0
  190. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/fr.ts +44 -0
  191. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/hr.ts +44 -0
  192. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/it.ts +44 -0
  193. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/nl.ts +44 -0
  194. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/pl.ts +44 -0
  195. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/pt.ts +44 -0
  196. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/sl.ts +44 -0
  197. package/src/components/recurring-invoices/index.ts +3 -0
  198. package/src/components/recurring-invoices/list/index.ts +2 -0
  199. package/src/components/recurring-invoices/list/list-row-actions.tsx +139 -0
  200. package/src/components/recurring-invoices/list/list-table.tsx +179 -0
  201. package/src/components/recurring-invoices/list/locales/de.ts +27 -0
  202. package/src/components/recurring-invoices/list/locales/en.ts +5 -0
  203. package/src/components/recurring-invoices/list/locales/es.ts +27 -0
  204. package/src/components/recurring-invoices/list/locales/fr.ts +27 -0
  205. package/src/components/recurring-invoices/list/locales/hr.ts +27 -0
  206. package/src/components/recurring-invoices/list/locales/it.ts +27 -0
  207. package/src/components/recurring-invoices/list/locales/nl.ts +27 -0
  208. package/src/components/recurring-invoices/list/locales/pl.ts +27 -0
  209. package/src/components/recurring-invoices/list/locales/pt.ts +27 -0
  210. package/src/components/recurring-invoices/list/locales/sl.ts +27 -0
  211. package/src/components/recurring-invoices/recurring-invoices.hooks.ts +28 -0
  212. package/src/components/table/data-table.tsx +122 -5
  213. package/src/components/table/selection-toolbar.tsx +36 -0
  214. package/src/components/tax-reports/kir-export-form.tsx +75 -55
  215. package/src/components/taxes/tax-list-table/tax-list-row-actions.tsx +3 -6
  216. package/src/components/taxes/tax-list-table/tax-list-row.tsx +3 -2
  217. package/src/components/taxes/tax-list-table/tax-list-table.tsx +5 -1
  218. package/src/components/ui/checkbox.tsx +5 -5
  219. package/src/generate-schemas.ts +45 -18
  220. package/src/generated/schemas/authorizeshopify_body.ts +22 -0
  221. package/src/generated/schemas/creditnote.ts +0 -2
  222. package/src/generated/schemas/deliverynote.ts +134 -0
  223. package/src/generated/schemas/entity.ts +5 -1
  224. package/src/generated/schemas/index.ts +42 -28
  225. package/src/generated/schemas/order.ts +129 -0
  226. package/src/generated/schemas/orderintegration.ts +51 -0
  227. package/src/generated/schemas/payment.ts +24 -2
  228. package/src/generated/schemas/recurringinvoice.ts +61 -0
  229. package/src/generated/schemas/renderadvanceinvoicepreview_body.ts +108 -140
  230. package/src/generated/schemas/rendercreditnotepreview_body.ts +109 -141
  231. package/src/generated/schemas/renderdeliverynotepreview_body.ts +185 -0
  232. package/src/generated/schemas/renderestimatepreview_body.ts +79 -82
  233. package/src/generated/schemas/renderinvoicepreview_body.ts +109 -141
  234. package/src/generated/schemas/startpdfexport_body.ts +18 -2
  235. package/src/generated/schemas/userfinasettings.ts +19 -0
  236. package/src/generated/schemas/webhook.ts +54 -0
  237. package/src/hooks/use-duplicate-document.ts +11 -3
  238. package/src/hooks/use-next-document-number.ts +2 -2
  239. package/src/lib/furs-error-utils.ts +36 -0
  240. package/src/lib/schemas/advance-invoice.ts +3 -3
  241. package/src/lib/schemas/credit-note.ts +3 -3
  242. package/src/lib/schemas/estimate.ts +3 -3
  243. package/src/lib/schemas/invoice.ts +3 -3
  244. package/src/providers/sdk-provider.tsx +5 -7
  245. package/src/providers/white-label-provider.tsx +3 -0
@@ -1,17 +1,26 @@
1
- import { AlertCircle, CheckCircle2, Info } from "lucide-react";
1
+ import { AlertCircle, AlertTriangle, Building2, CheckCircle2, ChevronRight, Info, User } from "lucide-react";
2
2
  import { type FC, type ReactNode, useCallback, useEffect, useState } from "react";
3
+ import { useUpdateEntity } from "@/ui/components/entities/entities.hooks";
3
4
  import { Alert, AlertDescription, AlertTitle } from "@/ui/components/ui/alert";
4
5
  import { Button } from "@/ui/components/ui/button";
6
+ import { Input } from "@/ui/components/ui/input";
5
7
  import { Label } from "@/ui/components/ui/label";
6
8
  import { PageLoadingSpinner } from "@/ui/components/ui/loading-spinner";
7
9
  import { RadioGroup, RadioGroupItem } from "@/ui/components/ui/radio-group";
10
+ import { Separator } from "@/ui/components/ui/separator";
8
11
  import { Switch } from "@/ui/components/ui/switch";
9
12
  import { Tabs, TabsList, TabsTrigger } from "@/ui/components/ui/tabs";
10
13
  import { Tooltip, TooltipContent, TooltipTrigger } from "@/ui/components/ui/tooltip";
11
14
  import type { ComponentTranslationProps } from "@/ui/lib/translation";
12
15
  import { createTranslation } from "@/ui/lib/translation";
13
16
  import { cn } from "@/ui/lib/utils";
14
- import { useFinaPremises, useFinaSettings, useUpdateFinaSettings } from "./fina-settings.hooks";
17
+ import {
18
+ useFinaPremises,
19
+ useFinaSettings,
20
+ useUpdateFinaSettings,
21
+ useUpdateUserFinaSettings,
22
+ useUserFinaSettings,
23
+ } from "./fina-settings.hooks";
15
24
  import de from "./locales/de";
16
25
  import en from "./locales/en";
17
26
  import es from "./locales/es";
@@ -28,7 +37,15 @@ import { PremisesManagementSection } from "./sections/premises-management-sectio
28
37
  const translations = { sl, de, en, it, fr, es, pt, nl, pl, hr } as const;
29
38
 
30
39
  export type FinaStepType = "settings" | "certificate" | "premises" | "enable";
31
- export type FinaSectionType = "operator" | "numbering" | "certificate-upload" | "premises-list" | "enable-toggle";
40
+ export type FinaSectionType =
41
+ | "entity-info"
42
+ | "operator"
43
+ | "numbering"
44
+ | "certificate-upload"
45
+ | "premises-list"
46
+ | "enable-toggle"
47
+ | "user-operator"
48
+ | "advanced";
32
49
 
33
50
  interface FinaSettingsFormProps extends ComponentTranslationProps {
34
51
  entity: any;
@@ -37,6 +54,11 @@ interface FinaSettingsFormProps extends ComponentTranslationProps {
37
54
  initialStep?: FinaStepType;
38
55
  onStepChange?: (step: FinaStepType) => void;
39
56
  renderSection?: (section: FinaSectionType, content: ReactNode) => ReactNode;
57
+ /**
58
+ * Hide user-specific operator section (for embed/API key contexts without user session).
59
+ * When true, the "Advanced Settings" entity-level operator fields are auto-expanded instead.
60
+ */
61
+ hideUserOperatorSection?: boolean;
40
62
  }
41
63
 
42
64
  /**
@@ -58,6 +80,7 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
58
80
  initialStep = "settings",
59
81
  onStepChange,
60
82
  renderSection,
83
+ hideUserOperatorSection,
61
84
  }) => {
62
85
  const [activeStep, setActiveStep] = useState<FinaStepType>(initialStep);
63
86
  const [hasInitializedStep, setHasInitializedStep] = useState(false);
@@ -77,6 +100,36 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
77
100
  [onStepChange],
78
101
  );
79
102
 
103
+ // Entity info state
104
+ const [entityTaxNumber, setEntityTaxNumber] = useState("");
105
+ const [entityAddress, setEntityAddress] = useState("");
106
+ const [entityCity, setEntityCity] = useState("");
107
+ const [entityPostCode, setEntityPostCode] = useState("");
108
+
109
+ useEffect(() => {
110
+ setEntityTaxNumber(entity.tax_number || "");
111
+ setEntityAddress(entity.address || "");
112
+ setEntityCity(entity.city || "");
113
+ setEntityPostCode(entity.post_code || "");
114
+ }, [entity.tax_number, entity.address, entity.city, entity.post_code]);
115
+
116
+ const { mutate: updateEntity, isPending: isEntityUpdatePending } = useUpdateEntity({
117
+ onSuccess: () => onSuccess?.(),
118
+ onError: (error) => onError?.(error),
119
+ });
120
+
121
+ const handleSaveEntityInfo = () => {
122
+ updateEntity({
123
+ id: entity.id,
124
+ data: {
125
+ tax_number: entityTaxNumber || null,
126
+ address: entityAddress || null,
127
+ city: entityCity || null,
128
+ post_code: entityPostCode || null,
129
+ },
130
+ });
131
+ };
132
+
80
133
  // Fetch FINA settings and premises
81
134
  const { data: finaSettings, isLoading: settingsLoading } = useFinaSettings(entity.id);
82
135
  const { data: premises, isLoading: premisesLoading } = useFinaPremises(entity.id);
@@ -90,7 +143,38 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
90
143
  },
91
144
  });
92
145
 
93
- // Form state for settings
146
+ // User FINA operator settings (per-user, stored in user.settings)
147
+ const { data: userFinaSettings, isLoading: userSettingsLoading } = useUserFinaSettings(entity.id, {
148
+ enabled: !hideUserOperatorSection,
149
+ });
150
+ const [userOperatorOib, setUserOperatorOib] = useState("");
151
+ const [userOperatorLabel, setUserOperatorLabel] = useState("");
152
+
153
+ useEffect(() => {
154
+ if (userFinaSettings) {
155
+ setUserOperatorOib(userFinaSettings.operator_oib || "");
156
+ setUserOperatorLabel(userFinaSettings.operator_label || "");
157
+ }
158
+ }, [userFinaSettings]);
159
+
160
+ const { mutate: updateUserSettings, isPending: isUserSettingsPending } = useUpdateUserFinaSettings({
161
+ onSuccess: () => onSuccess?.(),
162
+ onError: (error) => onError?.(error),
163
+ });
164
+
165
+ const handleSaveUserSettings = () => {
166
+ if (userOperatorOibError) return;
167
+ updateUserSettings({
168
+ entityId: entity.id,
169
+ data: {
170
+ operator_oib: userOperatorOib || undefined,
171
+ operator_label: userOperatorLabel || undefined,
172
+ },
173
+ });
174
+ };
175
+
176
+ // Form state for entity-level settings (API default)
177
+ const [isAdvancedOpen, setIsAdvancedOpen] = useState(!!hideUserOperatorSection);
94
178
  const [formData, setFormData] = useState({
95
179
  enabled: false,
96
180
  numbering_sequence: "N" as "N" | "P",
@@ -113,6 +197,12 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
113
197
  }, [finaSettings]);
114
198
 
115
199
  // Determine completion status
200
+ const hasEntityTaxNumber = !!entity.tax_number;
201
+ // Operator OIB is required by CIS protocol (minOccurs="1" in FiskalizacijaSchema.xsd)
202
+ // Can come from user settings or entity-level FINA settings
203
+ const hasOperatorSettings =
204
+ (!!userFinaSettings?.operator_oib && !!userFinaSettings?.operator_label) ||
205
+ (!!finaSettings?.operator_oib && !!finaSettings?.operator_label);
116
206
  const hasCertificate = finaSettings?.has_certificate || false;
117
207
  const certificateValid = finaSettings?.certificate_status === "valid";
118
208
  const hasPremises = (premises?.length || 0) > 0;
@@ -120,16 +210,23 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
120
210
  hasPremises && premises?.some((premise: any) => premise.Devices && premise.Devices.length > 0);
121
211
 
122
212
  const finaEnabled = finaSettings?.enabled || false;
123
- const canAccessPremises = hasCertificate && certificateValid;
124
- const canAccessEnable = certificateValid && hasPremises && hasPremiseWithDevice;
213
+ const canAccessCertificate = hasEntityTaxNumber && hasOperatorSettings;
214
+ const canAccessPremises = hasEntityTaxNumber && hasOperatorSettings && hasCertificate && certificateValid;
215
+ const canAccessEnable =
216
+ hasEntityTaxNumber && hasOperatorSettings && certificateValid && hasPremises && hasPremiseWithDevice;
125
217
 
126
218
  const steps = [
127
- { id: "settings" as const, title: translate("General Settings"), complete: true, unlocked: true },
219
+ {
220
+ id: "settings" as const,
221
+ title: translate("General Settings"),
222
+ complete: hasEntityTaxNumber && hasOperatorSettings,
223
+ unlocked: true,
224
+ },
128
225
  {
129
226
  id: "certificate" as const,
130
227
  title: translate("Certificate"),
131
228
  complete: hasCertificate && certificateValid,
132
- unlocked: true,
229
+ unlocked: canAccessCertificate,
133
230
  },
134
231
  {
135
232
  id: "premises" as const,
@@ -196,10 +293,23 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
196
293
 
197
294
  const isSandboxMode = entity.environment === "sandbox";
198
295
 
296
+ const userOperatorOibError =
297
+ userOperatorOib !== "" && !/^\d{11}$/.test(userOperatorOib) ? translate("OIB must be exactly 11 digits") : "";
298
+
299
+ const operatorOibError =
300
+ formData.operator_oib !== "" && !/^\d{11}$/.test(formData.operator_oib)
301
+ ? translate("OIB must be exactly 11 digits")
302
+ : "";
303
+
199
304
  const handleSaveSettings = () => {
305
+ if (operatorOibError) return;
200
306
  updateSettings({
201
307
  entityId: entity.id,
202
- data: formData,
308
+ data: {
309
+ ...formData,
310
+ operator_oib: formData.operator_oib || undefined,
311
+ operator_label: formData.operator_label || undefined,
312
+ },
203
313
  });
204
314
  };
205
315
 
@@ -218,10 +328,24 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
218
328
  const isLocked = !step.unlocked;
219
329
  let tooltipText = "";
220
330
  if (isLocked) {
221
- if (step.id === "premises") {
222
- tooltipText = translate("Upload and validate digital certificate first");
331
+ if (step.id === "certificate") {
332
+ if (!hasEntityTaxNumber) {
333
+ tooltipText = translate("Set entity OIB in General Settings first");
334
+ } else {
335
+ tooltipText = translate("Set operator OIB and label in General Settings first");
336
+ }
337
+ } else if (step.id === "premises") {
338
+ if (!hasEntityTaxNumber) {
339
+ tooltipText = translate("Set entity OIB in General Settings first");
340
+ } else if (!hasOperatorSettings) {
341
+ tooltipText = translate("Set operator OIB and label in General Settings first");
342
+ } else {
343
+ tooltipText = translate("Upload and validate digital certificate first");
344
+ }
223
345
  } else if (step.id === "enable") {
224
- if (!certificateValid) {
346
+ if (!hasEntityTaxNumber || !hasOperatorSettings) {
347
+ tooltipText = translate("Complete General Settings first");
348
+ } else if (!certificateValid) {
225
349
  tooltipText = translate("Upload and validate digital certificate first");
226
350
  } else if (!hasPremises) {
227
351
  tooltipText = translate("Register at least one business premise first");
@@ -295,6 +419,97 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
295
419
  {/* Settings step */}
296
420
  {activeStep === "settings" && (
297
421
  <div className="space-y-6">
422
+ {wrapSection(
423
+ "entity-info",
424
+ <div className="space-y-4">
425
+ <div className="flex items-center gap-3">
426
+ <div className="flex h-10 w-10 items-center justify-center rounded-lg bg-orange-500/10">
427
+ <Building2 className="h-5 w-5 text-orange-600 dark:text-orange-400" />
428
+ </div>
429
+ <div>
430
+ <h3 className="font-semibold text-lg">{translate("Entity Information")}</h3>
431
+ <p className="text-muted-foreground text-sm">
432
+ {translate("Required company details for FINA fiscalization")}
433
+ </p>
434
+ </div>
435
+ </div>
436
+
437
+ {!entity.tax_number && (
438
+ <Alert variant="destructive">
439
+ <AlertTriangle className="h-4 w-4" />
440
+ <AlertDescription>{translate("Entity OIB is required for FINA fiscalization")}</AlertDescription>
441
+ </Alert>
442
+ )}
443
+
444
+ <div className="space-y-4">
445
+ <div>
446
+ <label htmlFor="entity-tax-number" className="font-medium text-sm">
447
+ {translate("Entity OIB")}
448
+ </label>
449
+ <Input
450
+ id="entity-tax-number"
451
+ placeholder="12345678901"
452
+ value={entityTaxNumber}
453
+ onChange={(e) => setEntityTaxNumber(e.target.value)}
454
+ className={cn("mt-2 h-10", !entity.tax_number && "border-destructive")}
455
+ maxLength={11}
456
+ />
457
+ <p className="mt-1 text-muted-foreground text-xs">
458
+ {translate("Your company's OIB (must match FINA certificate)")}
459
+ </p>
460
+ </div>
461
+
462
+ <div>
463
+ <label htmlFor="entity-address" className="font-medium text-sm">
464
+ {translate("Address")}
465
+ </label>
466
+ <Input
467
+ id="entity-address"
468
+ value={entityAddress}
469
+ onChange={(e) => setEntityAddress(e.target.value)}
470
+ className="mt-2 h-10"
471
+ />
472
+ </div>
473
+
474
+ <div className="grid grid-cols-2 gap-4">
475
+ <div>
476
+ <label htmlFor="entity-post-code" className="font-medium text-sm">
477
+ {translate("Post Code")}
478
+ </label>
479
+ <Input
480
+ id="entity-post-code"
481
+ value={entityPostCode}
482
+ onChange={(e) => setEntityPostCode(e.target.value)}
483
+ className="mt-2 h-10"
484
+ />
485
+ </div>
486
+ <div>
487
+ <label htmlFor="entity-city" className="font-medium text-sm">
488
+ {translate("City")}
489
+ </label>
490
+ <Input
491
+ id="entity-city"
492
+ value={entityCity}
493
+ onChange={(e) => setEntityCity(e.target.value)}
494
+ className="mt-2 h-10"
495
+ />
496
+ </div>
497
+ </div>
498
+
499
+ <Button
500
+ type="button"
501
+ onClick={handleSaveEntityInfo}
502
+ disabled={isEntityUpdatePending}
503
+ className="cursor-pointer"
504
+ >
505
+ {isEntityUpdatePending ? translate("Saving...") : translate("Save Entity Info")}
506
+ </Button>
507
+ </div>
508
+ </div>,
509
+ )}
510
+
511
+ <Separator />
512
+
298
513
  {wrapSection(
299
514
  "numbering",
300
515
  <div className="space-y-4">
@@ -319,6 +534,8 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
319
534
  </div>,
320
535
  )}
321
536
 
537
+ <Separator />
538
+
322
539
  {wrapSection(
323
540
  "operator",
324
541
  <div className="space-y-4">
@@ -332,36 +549,154 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
332
549
  <Label>{translate("Entity is registered in the Croatian PDV (VAT) system")}</Label>
333
550
  </div>
334
551
  </div>
335
- <div>
336
- <Label className="font-medium text-sm">{translate("Operator OIB")}</Label>
337
- <input
338
- type="text"
339
- value={formData.operator_oib}
340
- onChange={(e) => setFormData((prev) => ({ ...prev, operator_oib: e.target.value }))}
341
- placeholder={translate("OIB of the operator (11 digits, optional)")}
342
- className="mt-1 block w-full rounded-md border border-input bg-background px-3 py-2 text-sm"
343
- maxLength={11}
344
- />
345
- </div>
346
- <div>
347
- <Label className="font-medium text-sm">{translate("Operator Label")}</Label>
348
- <input
349
- type="text"
350
- value={formData.operator_label}
351
- onChange={(e) => setFormData((prev) => ({ ...prev, operator_label: e.target.value }))}
352
- placeholder={translate("Descriptive label for the operator (optional)")}
353
- className="mt-1 block w-full rounded-md border border-input bg-background px-3 py-2 text-sm"
354
- />
355
- </div>
356
552
  </div>,
357
553
  )}
358
554
 
359
555
  <div className="grid items-start gap-6 lg:grid-cols-[1fr_280px]">
360
- <Button onClick={handleSaveSettings} disabled={isPending}>
556
+ <Button onClick={handleSaveSettings} disabled={isPending || !!operatorOibError}>
361
557
  {isPending ? translate("Saving...") : translate("Save Settings")}
362
558
  </Button>
363
559
  <div className="hidden lg:block" />
364
560
  </div>
561
+
562
+ <Separator />
563
+
564
+ {/* Per-user operator settings (hidden in embed/API key mode) */}
565
+ {!hideUserOperatorSection && (
566
+ <>
567
+ {wrapSection(
568
+ "user-operator",
569
+ <div className="space-y-4">
570
+ <div className="flex items-center gap-3">
571
+ <div className="flex h-10 w-10 items-center justify-center rounded-lg bg-blue-500/10">
572
+ <User className="h-5 w-5 text-blue-600 dark:text-blue-400" />
573
+ </div>
574
+ <div>
575
+ <h3 className="font-semibold text-lg">{translate("Your Operator Settings")}</h3>
576
+ <p className="text-muted-foreground text-sm">
577
+ {translate("Your personal operator info for FINA invoices")}
578
+ </p>
579
+ </div>
580
+ </div>
581
+
582
+ {(!userFinaSettings?.operator_oib || !userFinaSettings?.operator_label) && (
583
+ <Alert variant="destructive">
584
+ <AlertTriangle className="h-4 w-4" />
585
+ <AlertDescription>
586
+ {translate("Operator OIB and label are required for FINA fiscalization")}
587
+ </AlertDescription>
588
+ </Alert>
589
+ )}
590
+
591
+ <div className="space-y-4">
592
+ <div>
593
+ <Label className="font-medium text-sm">{translate("Operator OIB")}</Label>
594
+ <Input
595
+ type="text"
596
+ value={userOperatorOib}
597
+ onChange={(e) => {
598
+ const val = e.target.value.replace(/[^0-9]/g, "");
599
+ setUserOperatorOib(val);
600
+ }}
601
+ placeholder={translate("OIB of the operator (11 digits)")}
602
+ className={cn("mt-1", userOperatorOibError && "border-destructive")}
603
+ maxLength={11}
604
+ disabled={userSettingsLoading}
605
+ />
606
+ {userOperatorOibError && <p className="mt-1 text-destructive text-xs">{userOperatorOibError}</p>}
607
+ </div>
608
+ <div>
609
+ <Label className="font-medium text-sm">{translate("Operator Label")}</Label>
610
+ <Input
611
+ type="text"
612
+ value={userOperatorLabel}
613
+ onChange={(e) => setUserOperatorLabel(e.target.value)}
614
+ placeholder={translate("e.g. Cashier 1")}
615
+ className="mt-1"
616
+ disabled={userSettingsLoading}
617
+ />
618
+ </div>
619
+
620
+ <Button
621
+ type="button"
622
+ onClick={handleSaveUserSettings}
623
+ disabled={isUserSettingsPending || userSettingsLoading || !!userOperatorOibError}
624
+ className="cursor-pointer"
625
+ >
626
+ {isUserSettingsPending ? translate("Saving...") : translate("Save Operator Settings")}
627
+ </Button>
628
+ </div>
629
+ </div>,
630
+ )}
631
+
632
+ <Separator />
633
+ </>
634
+ )}
635
+
636
+ {/* API Default Operator (advanced/entity-level) */}
637
+ {wrapSection(
638
+ "advanced",
639
+ <div>
640
+ <button
641
+ type="button"
642
+ onClick={() => setIsAdvancedOpen(!isAdvancedOpen)}
643
+ className="flex w-full items-center gap-2 py-2 text-muted-foreground hover:text-foreground"
644
+ >
645
+ <ChevronRight className={cn("h-4 w-4 transition-transform", isAdvancedOpen && "rotate-90")} />
646
+ <span className="font-medium text-sm">{translate("Advanced Settings")}</span>
647
+ </button>
648
+ {isAdvancedOpen && (
649
+ <div className="pt-4">
650
+ <div className="space-y-4 rounded-lg border p-4">
651
+ <div>
652
+ <h4 className="font-medium text-sm">{translate("API Default Operator")}</h4>
653
+ <p className="text-muted-foreground text-xs">
654
+ {translate("Default operator settings for API key usage (when no user context)")}
655
+ </p>
656
+ </div>
657
+
658
+ <div className="space-y-4">
659
+ <div>
660
+ <Label className="text-sm">{translate("Operator OIB")}</Label>
661
+ <Input
662
+ type="text"
663
+ value={formData.operator_oib}
664
+ onChange={(e) => {
665
+ const val = e.target.value.replace(/[^0-9]/g, "");
666
+ setFormData((prev) => ({ ...prev, operator_oib: val }));
667
+ }}
668
+ placeholder={translate("OIB of the operator (11 digits)")}
669
+ className={cn("mt-1", operatorOibError && "border-destructive")}
670
+ maxLength={11}
671
+ />
672
+ {operatorOibError && <p className="mt-1 text-destructive text-xs">{operatorOibError}</p>}
673
+ <p className="mt-1 text-muted-foreground text-xs">
674
+ {translate("OIB for API key usage (optional)")}
675
+ </p>
676
+ </div>
677
+ <div>
678
+ <Label className="text-sm">{translate("Operator Label")}</Label>
679
+ <Input
680
+ type="text"
681
+ value={formData.operator_label}
682
+ onChange={(e) => setFormData((prev) => ({ ...prev, operator_label: e.target.value }))}
683
+ placeholder="API Default"
684
+ className="mt-1"
685
+ />
686
+ <p className="mt-1 text-muted-foreground text-xs">
687
+ {translate("Operator label for API key usage (optional)")}
688
+ </p>
689
+ </div>
690
+ </div>
691
+
692
+ <Button onClick={handleSaveSettings} disabled={isPending || !!operatorOibError} size="sm">
693
+ {isPending ? translate("Saving...") : translate("Save Settings")}
694
+ </Button>
695
+ </div>
696
+ </div>
697
+ )}
698
+ </div>,
699
+ )}
365
700
  </div>
366
701
  )}
367
702
 
@@ -431,7 +766,14 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
431
766
  setFormData((prev) => ({ ...prev, enabled: checked }));
432
767
  updateSettings({
433
768
  entityId: entity.id,
434
- data: { ...formData, enabled: checked },
769
+ data: checked
770
+ ? {
771
+ ...formData,
772
+ enabled: true,
773
+ operator_oib: formData.operator_oib || undefined,
774
+ operator_label: formData.operator_label || undefined,
775
+ }
776
+ : { enabled: false },
435
777
  });
436
778
  }}
437
779
  />