@spaceinvoices/react-ui 0.4.3 → 0.4.4

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 (218) hide show
  1. package/cli/dist/index.js +1 -1
  2. package/package.json +1 -1
  3. package/src/common/autocomplete.tsx +18 -2
  4. package/src/components/advance-invoices/create/create-advance-invoice-form.tsx +0 -1
  5. package/src/components/advance-invoices/create/locales/de.ts +2 -0
  6. package/src/components/advance-invoices/create/locales/es.ts +2 -0
  7. package/src/components/advance-invoices/create/locales/fr.ts +2 -0
  8. package/src/components/advance-invoices/create/locales/hr.ts +1 -0
  9. package/src/components/advance-invoices/create/locales/it.ts +2 -0
  10. package/src/components/advance-invoices/create/locales/nl.ts +2 -0
  11. package/src/components/advance-invoices/create/locales/pl.ts +1 -0
  12. package/src/components/advance-invoices/create/locales/pt.ts +1 -0
  13. package/src/components/advance-invoices/create/locales/sl.ts +1 -0
  14. package/src/components/advance-invoices/create/prepare-advance-invoice-submission.ts +0 -1
  15. package/src/components/advance-invoices/list/list-table.tsx +80 -50
  16. package/src/components/advance-invoices/list/locales/de.ts +5 -0
  17. package/src/components/advance-invoices/list/locales/en.ts +4 -0
  18. package/src/components/advance-invoices/list/locales/es.ts +5 -0
  19. package/src/components/advance-invoices/list/locales/fr.ts +5 -0
  20. package/src/components/advance-invoices/list/locales/hr.ts +5 -0
  21. package/src/components/advance-invoices/list/locales/it.ts +5 -0
  22. package/src/components/advance-invoices/list/locales/nl.ts +5 -0
  23. package/src/components/advance-invoices/list/locales/pl.ts +5 -0
  24. package/src/components/advance-invoices/list/locales/pt.ts +5 -0
  25. package/src/components/advance-invoices/list/locales/sl.ts +5 -0
  26. package/src/components/credit-notes/create/create-credit-note-form.tsx +114 -3
  27. package/src/components/credit-notes/create/locales/de.ts +2 -0
  28. package/src/components/credit-notes/create/locales/es.ts +2 -0
  29. package/src/components/credit-notes/create/locales/fr.ts +2 -0
  30. package/src/components/credit-notes/create/locales/hr.ts +1 -0
  31. package/src/components/credit-notes/create/locales/it.ts +2 -0
  32. package/src/components/credit-notes/create/locales/nl.ts +2 -0
  33. package/src/components/credit-notes/create/locales/pl.ts +1 -0
  34. package/src/components/credit-notes/create/locales/pt.ts +1 -0
  35. package/src/components/credit-notes/create/locales/sl.ts +1 -0
  36. package/src/components/credit-notes/credit-notes.hooks.ts +30 -0
  37. package/src/components/credit-notes/list/list-table.tsx +77 -30
  38. package/src/components/credit-notes/list/locales/de.ts +5 -0
  39. package/src/components/credit-notes/list/locales/en.ts +4 -0
  40. package/src/components/credit-notes/list/locales/es.ts +5 -0
  41. package/src/components/credit-notes/list/locales/fr.ts +5 -0
  42. package/src/components/credit-notes/list/locales/hr.ts +5 -0
  43. package/src/components/credit-notes/list/locales/it.ts +5 -0
  44. package/src/components/credit-notes/list/locales/nl.ts +5 -0
  45. package/src/components/credit-notes/list/locales/pl.ts +5 -0
  46. package/src/components/credit-notes/list/locales/pt.ts +5 -0
  47. package/src/components/credit-notes/list/locales/sl.ts +5 -0
  48. package/src/components/customers/customer-list-table/customer-list-table.tsx +0 -3
  49. package/src/components/customers/customer-list-table/locales/de.ts +1 -0
  50. package/src/components/customers/customer-list-table/locales/es.ts +1 -0
  51. package/src/components/customers/customer-list-table/locales/fr.ts +1 -0
  52. package/src/components/customers/customer-list-table/locales/hr.ts +1 -0
  53. package/src/components/customers/customer-list-table/locales/it.ts +1 -0
  54. package/src/components/customers/customer-list-table/locales/nl.ts +1 -0
  55. package/src/components/customers/customer-list-table/locales/pl.ts +1 -0
  56. package/src/components/customers/customer-list-table/locales/pt.ts +1 -0
  57. package/src/components/customers/customer-list-table/locales/sl.ts +1 -0
  58. package/src/components/delivery-notes/list/list-row-actions.tsx +20 -1
  59. package/src/components/delivery-notes/list/list-table.tsx +41 -8
  60. package/src/components/delivery-notes/list/locales/de.ts +4 -0
  61. package/src/components/delivery-notes/list/locales/en.ts +2 -0
  62. package/src/components/delivery-notes/list/locales/es.ts +4 -0
  63. package/src/components/delivery-notes/list/locales/fr.ts +4 -0
  64. package/src/components/delivery-notes/list/locales/hr.ts +4 -0
  65. package/src/components/delivery-notes/list/locales/it.ts +4 -0
  66. package/src/components/delivery-notes/list/locales/nl.ts +4 -0
  67. package/src/components/delivery-notes/list/locales/pl.ts +4 -0
  68. package/src/components/delivery-notes/list/locales/pt.ts +4 -0
  69. package/src/components/delivery-notes/list/locales/sl.ts +4 -0
  70. package/src/components/documents/create/document-details-section.tsx +41 -27
  71. package/src/components/documents/create/linked-documents-info.tsx +82 -0
  72. package/src/components/documents/create/live-preview.tsx +1 -1
  73. package/src/components/documents/types.ts +2 -2
  74. package/src/components/documents/view/document-activities-list.tsx +65 -47
  75. package/src/components/documents/view/document-details-card.tsx +99 -74
  76. package/src/components/documents/view/document-payments-list.tsx +99 -65
  77. package/src/components/documents/view/document-relations-list.tsx +43 -28
  78. package/src/components/documents/view/document-sidebar.tsx +151 -0
  79. package/src/components/documents/view/index.ts +2 -0
  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 +2 -0
  89. package/src/components/documents/view/use-document-download.ts +3 -2
  90. package/src/components/entities/create-entity-form.tsx +165 -13
  91. package/src/components/entities/entity-settings-form/entity-settings-form.tsx +101 -1
  92. package/src/components/entities/entity-settings-form/locales/de.ts +9 -0
  93. package/src/components/entities/entity-settings-form/locales/es.ts +9 -0
  94. package/src/components/entities/entity-settings-form/locales/fr.ts +9 -0
  95. package/src/components/entities/entity-settings-form/locales/hr.ts +9 -0
  96. package/src/components/entities/entity-settings-form/locales/it.ts +9 -0
  97. package/src/components/entities/entity-settings-form/locales/nl.ts +9 -0
  98. package/src/components/entities/entity-settings-form/locales/pl.ts +9 -0
  99. package/src/components/entities/entity-settings-form/locales/pt.ts +9 -0
  100. package/src/components/entities/entity-settings-form/locales/sl.ts +9 -0
  101. package/src/components/entities/fina-settings-form/fina-settings-form.tsx +6 -6
  102. package/src/components/entities/fina-settings-form/locales/de.ts +2 -2
  103. package/src/components/entities/fina-settings-form/locales/en.ts +2 -2
  104. package/src/components/entities/fina-settings-form/locales/es.ts +2 -2
  105. package/src/components/entities/fina-settings-form/locales/fr.ts +2 -2
  106. package/src/components/entities/fina-settings-form/locales/hr.ts +2 -2
  107. package/src/components/entities/fina-settings-form/locales/it.ts +2 -2
  108. package/src/components/entities/fina-settings-form/locales/nl.ts +2 -2
  109. package/src/components/entities/fina-settings-form/locales/pl.ts +2 -2
  110. package/src/components/entities/fina-settings-form/locales/pt.ts +2 -2
  111. package/src/components/entities/fina-settings-form/locales/sl.ts +2 -2
  112. package/src/components/entities/furs-settings-form/locales/en.ts +0 -1
  113. package/src/components/entities/settings/pdf-template-selector/locales/de.ts +3 -1
  114. package/src/components/entities/settings/pdf-template-selector/locales/es.ts +3 -1
  115. package/src/components/entities/settings/pdf-template-selector/locales/fr.ts +4 -1
  116. package/src/components/entities/settings/pdf-template-selector/locales/hr.ts +4 -1
  117. package/src/components/entities/settings/pdf-template-selector/locales/it.ts +3 -1
  118. package/src/components/entities/settings/pdf-template-selector/locales/nl.ts +3 -1
  119. package/src/components/entities/settings/pdf-template-selector/locales/pl.ts +3 -1
  120. package/src/components/entities/settings/pdf-template-selector/locales/pt.ts +3 -1
  121. package/src/components/entities/settings/pdf-template-selector/locales/sl.ts +3 -1
  122. package/src/components/entities/settings/pdf-template-selector/pdf-template-cards.tsx +1 -0
  123. package/src/components/estimates/create/create-estimate-form.tsx +29 -2
  124. package/src/components/estimates/list/list-table.tsx +3 -6
  125. package/src/components/estimates/list/locales/de.ts +1 -0
  126. package/src/components/estimates/list/locales/es.ts +1 -0
  127. package/src/components/estimates/list/locales/fr.ts +1 -0
  128. package/src/components/estimates/list/locales/hr.ts +1 -0
  129. package/src/components/estimates/list/locales/it.ts +1 -0
  130. package/src/components/estimates/list/locales/nl.ts +1 -0
  131. package/src/components/estimates/list/locales/pl.ts +1 -0
  132. package/src/components/estimates/list/locales/pt.ts +1 -0
  133. package/src/components/estimates/list/locales/sl.ts +1 -0
  134. package/src/components/export/document-export-form.tsx +9 -2
  135. package/src/components/export/index.ts +2 -0
  136. package/src/components/export/sales-per-item-export-form.tsx +223 -0
  137. package/src/components/invoices/create/create-invoice-form.tsx +48 -1
  138. package/src/components/invoices/create/locales/de.ts +11 -0
  139. package/src/components/invoices/create/locales/es.ts +11 -0
  140. package/src/components/invoices/create/locales/fr.ts +11 -0
  141. package/src/components/invoices/create/locales/hr.ts +10 -0
  142. package/src/components/invoices/create/locales/it.ts +11 -0
  143. package/src/components/invoices/create/locales/nl.ts +11 -0
  144. package/src/components/invoices/create/locales/pl.ts +10 -0
  145. package/src/components/invoices/create/locales/pt.ts +10 -0
  146. package/src/components/invoices/create/locales/sl.ts +10 -0
  147. package/src/components/invoices/invoices-furs.hooks.ts +4 -1
  148. package/src/components/invoices/list/list-table.tsx +77 -31
  149. package/src/components/invoices/list/locales/de.ts +5 -0
  150. package/src/components/invoices/list/locales/en.ts +4 -0
  151. package/src/components/invoices/list/locales/es.ts +5 -0
  152. package/src/components/invoices/list/locales/fr.ts +5 -0
  153. package/src/components/invoices/list/locales/hr.ts +5 -0
  154. package/src/components/invoices/list/locales/it.ts +5 -0
  155. package/src/components/invoices/list/locales/nl.ts +5 -0
  156. package/src/components/invoices/list/locales/pl.ts +5 -0
  157. package/src/components/invoices/list/locales/pt.ts +5 -0
  158. package/src/components/invoices/list/locales/sl.ts +5 -0
  159. package/src/components/invoices/view/fiscalization-status-card.tsx +42 -24
  160. package/src/components/items/item-combobox.tsx +5 -3
  161. package/src/components/items/item-list-table/item-list-header.tsx +4 -17
  162. package/src/components/items/item-list-table/item-list-table.tsx +3 -3
  163. package/src/components/items/item-list-table/locales/de.ts +1 -0
  164. package/src/components/items/item-list-table/locales/es.ts +1 -0
  165. package/src/components/items/item-list-table/locales/fr.ts +1 -0
  166. package/src/components/items/item-list-table/locales/hr.ts +1 -0
  167. package/src/components/items/item-list-table/locales/it.ts +1 -0
  168. package/src/components/items/item-list-table/locales/nl.ts +1 -0
  169. package/src/components/items/item-list-table/locales/pl.ts +1 -0
  170. package/src/components/items/item-list-table/locales/pt.ts +1 -0
  171. package/src/components/items/item-list-table/locales/sl.ts +1 -0
  172. package/src/components/payments/list/list-table.tsx +0 -4
  173. package/src/components/payments/list/locales/de.ts +1 -0
  174. package/src/components/payments/list/locales/es.ts +1 -0
  175. package/src/components/payments/list/locales/fr.ts +1 -0
  176. package/src/components/payments/list/locales/hr.ts +1 -0
  177. package/src/components/payments/list/locales/it.ts +1 -0
  178. package/src/components/payments/list/locales/nl.ts +1 -0
  179. package/src/components/payments/list/locales/pl.ts +1 -0
  180. package/src/components/payments/list/locales/pt.ts +1 -0
  181. package/src/components/payments/list/locales/sl.ts +1 -0
  182. package/src/components/recurring-invoices/list/list-table.tsx +0 -7
  183. package/src/components/recurring-invoices/list/locales/de.ts +1 -0
  184. package/src/components/recurring-invoices/list/locales/es.ts +1 -0
  185. package/src/components/recurring-invoices/list/locales/fr.ts +1 -0
  186. package/src/components/recurring-invoices/list/locales/hr.ts +1 -0
  187. package/src/components/recurring-invoices/list/locales/it.ts +1 -0
  188. package/src/components/recurring-invoices/list/locales/nl.ts +1 -0
  189. package/src/components/recurring-invoices/list/locales/pl.ts +1 -0
  190. package/src/components/recurring-invoices/list/locales/pt.ts +1 -0
  191. package/src/components/recurring-invoices/list/locales/sl.ts +1 -0
  192. package/src/components/request-logs/request-log-list-table.tsx +0 -3
  193. package/src/components/table/README.md +14 -121
  194. package/src/components/table/data-table.tsx +22 -37
  195. package/src/components/table/hooks/use-table-state.ts +3 -27
  196. package/src/components/table/index.ts +0 -2
  197. package/src/components/table/selection-toolbar.tsx +35 -1
  198. package/src/components/table/table-empty-state.tsx +6 -3
  199. package/src/components/table/table-no-results.tsx +10 -5
  200. package/src/components/table/types.ts +0 -5
  201. package/src/components/taxes/tax-list-table/locales/de.ts +1 -0
  202. package/src/components/taxes/tax-list-table/locales/es.ts +1 -0
  203. package/src/components/taxes/tax-list-table/locales/fr.ts +1 -0
  204. package/src/components/taxes/tax-list-table/locales/hr.ts +1 -0
  205. package/src/components/taxes/tax-list-table/locales/it.ts +1 -0
  206. package/src/components/taxes/tax-list-table/locales/nl.ts +1 -0
  207. package/src/components/taxes/tax-list-table/locales/pl.ts +1 -0
  208. package/src/components/taxes/tax-list-table/locales/pt.ts +1 -0
  209. package/src/components/taxes/tax-list-table/locales/sl.ts +1 -0
  210. package/src/components/taxes/tax-list-table/tax-list-header.tsx +3 -14
  211. package/src/components/taxes/tax-list-table/tax-list-table.tsx +3 -3
  212. package/src/components/ui/popover.tsx +3 -1
  213. package/src/components/ui/tooltip.tsx +3 -1
  214. package/src/generated/schemas/index.ts +1 -1
  215. package/src/hooks/use-duplicate-document.ts +40 -5
  216. package/src/lib/fiscalization.ts +12 -0
  217. package/src/lib/schemas/advance-invoice.ts +0 -1
  218. package/src/components/table/sortable-header.tsx +0 -56
@@ -26,7 +26,14 @@ import { prepareDocumentSubmission } from "../../documents/create/prepare-docume
26
26
  import { useDocumentCustomerForm } from "../../documents/create/use-document-customer-form";
27
27
  import type { DocumentTypes } from "../../documents/types";
28
28
  import { useFinaPremises, useFinaSettings } from "../../entities/fina-settings-form/fina-settings.hooks";
29
- import { getLastUsedFinaCombo, setLastUsedFinaCombo, useCreateCreditNote } from "../credit-notes.hooks";
29
+ import { useFursPremises, useFursSettings } from "../../entities/furs-settings-form/furs-settings.hooks";
30
+ import {
31
+ getLastUsedFinaCombo,
32
+ getLastUsedFursCombo,
33
+ setLastUsedFinaCombo,
34
+ setLastUsedFursCombo,
35
+ useCreateCreditNote,
36
+ } from "../credit-notes.hooks";
30
37
  import de from "./locales/de";
31
38
  import es from "./locales/es";
32
39
  import fr from "./locales/fr";
@@ -90,6 +97,23 @@ export default function CreateCreditNoteForm({
90
97
  const { activeEntity } = useEntities();
91
98
  const queryClient = useQueryClient();
92
99
 
100
+ // ============================================================================
101
+ // FURS Settings & Premises
102
+ // ============================================================================
103
+ const { data: fursSettings, isLoading: isFursSettingsLoading } = useFursSettings(entityId);
104
+ const { data: fursPremises, isLoading: isFursPremisesLoading } = useFursPremises(entityId, {
105
+ enabled: fursSettings?.enabled === true,
106
+ });
107
+
108
+ const isFursLoading = isFursSettingsLoading || (fursSettings?.enabled && isFursPremisesLoading);
109
+ const isFursEnabled = fursSettings?.enabled === true;
110
+ const activePremises = useMemo(() => fursPremises?.filter((p) => p.is_active) || [], [fursPremises]);
111
+ const hasFursPremises = activePremises.length > 0;
112
+
113
+ // FURS premise/device selection state
114
+ const [selectedPremiseName, setSelectedPremiseName] = useState<string | undefined>();
115
+ const [selectedDeviceName, setSelectedDeviceName] = useState<string | undefined>();
116
+
93
117
  // ============================================================================
94
118
  // FINA Settings & Premises
95
119
  // ============================================================================
@@ -122,6 +146,57 @@ export default function CreateCreditNoteForm({
122
146
  }, [initialValues?.items]);
123
147
  const priceModesRef = useRef<PriceModesMap>(initialPriceModes);
124
148
 
149
+ // Get active FURS devices for selected premise
150
+ const activeDevices = useMemo(() => {
151
+ if (!selectedPremiseName) return [];
152
+ const premise = activePremises.find((p) => p.business_premise_name === selectedPremiseName);
153
+ return premise?.Devices?.filter((d) => d.is_active) || [];
154
+ }, [activePremises, selectedPremiseName]);
155
+
156
+ // Initialize FURS selection from localStorage or first active combo
157
+ useEffect(() => {
158
+ if (!isFursEnabled || !hasFursPremises || selectedPremiseName) return;
159
+
160
+ const lastUsed = getLastUsedFursCombo(entityId);
161
+ if (lastUsed) {
162
+ const premise = activePremises.find((p) => p.business_premise_name === lastUsed.business_premise_name);
163
+ const device = premise?.Devices?.find(
164
+ (d) => d.electronic_device_name === lastUsed.electronic_device_name && d.is_active,
165
+ );
166
+ if (premise && device) {
167
+ setSelectedPremiseName(lastUsed.business_premise_name);
168
+ setSelectedDeviceName(lastUsed.electronic_device_name);
169
+ return;
170
+ }
171
+ }
172
+
173
+ const firstPremise = activePremises[0];
174
+ const firstDevice = firstPremise?.Devices?.find((d) => d.is_active);
175
+ if (firstPremise && firstDevice) {
176
+ setSelectedPremiseName(firstPremise.business_premise_name);
177
+ setSelectedDeviceName(firstDevice.electronic_device_name);
178
+ }
179
+ }, [isFursEnabled, hasFursPremises, activePremises, entityId, selectedPremiseName]);
180
+
181
+ // When FURS premise changes, select first active device
182
+ useEffect(() => {
183
+ if (!selectedPremiseName) return;
184
+ const premise = activePremises.find((p) => p.business_premise_name === selectedPremiseName);
185
+ const firstDevice = premise?.Devices?.find((d) => d.is_active);
186
+ if (firstDevice && selectedDeviceName !== firstDevice.electronic_device_name) {
187
+ const currentDeviceInPremise = premise?.Devices?.find(
188
+ (d) => d.electronic_device_name === selectedDeviceName && d.is_active,
189
+ );
190
+ if (!currentDeviceInPremise) {
191
+ setSelectedDeviceName(firstDevice.electronic_device_name);
192
+ }
193
+ }
194
+ }, [selectedPremiseName, activePremises, selectedDeviceName]);
195
+
196
+ // FURS selection ready and active checks
197
+ const isFursSelectionReady = !isFursEnabled || !hasFursPremises || (!!selectedPremiseName && !!selectedDeviceName);
198
+ const isFursActive = isFursEnabled && hasFursPremises && selectedPremiseName && selectedDeviceName;
199
+
125
200
  // Get active FINA devices for selected premise
126
201
  const activeFinaDevices = useMemo(() => {
127
202
  if (!selectedFinaPremiseId) return [];
@@ -176,11 +251,14 @@ export default function CreateCreditNoteForm({
176
251
  // Next Credit Note Number Preview
177
252
  // ============================================================================
178
253
  const { data: nextNumberData, isLoading: isNextNumberLoading } = useNextDocumentNumber(entityId, "credit_note", {
179
- enabled: !!entityId && !isFinaLoading && isFinaSelectionReady,
254
+ businessPremiseName: isFursActive ? selectedPremiseName : undefined,
255
+ electronicDeviceName: isFursActive ? selectedDeviceName : undefined,
256
+ enabled: !!entityId && !isFursLoading && isFursSelectionReady && !isFinaLoading && isFinaSelectionReady,
180
257
  });
181
258
 
182
259
  // Overall loading state
183
- const isFormDataLoading = isFinaLoading || !isFinaSelectionReady || isNextNumberLoading;
260
+ const isFormDataLoading =
261
+ isFursLoading || !isFursSelectionReady || isFinaLoading || !isFinaSelectionReady || isNextNumberLoading;
184
262
 
185
263
  // No header action for credit notes - FINA can't be skipped
186
264
 
@@ -245,6 +323,13 @@ export default function CreateCreditNoteForm({
245
323
  const { mutate: createCreditNote, isPending } = useCreateCreditNote({
246
324
  entityId,
247
325
  onSuccess: (data) => {
326
+ // Save FURS combo to localStorage on successful creation
327
+ if (isFursActive && selectedPremiseName && selectedDeviceName) {
328
+ setLastUsedFursCombo(entityId, {
329
+ business_premise_name: selectedPremiseName,
330
+ electronic_device_name: selectedDeviceName,
331
+ });
332
+ }
248
333
  // Save FINA combo to localStorage on successful creation
249
334
  if (isFinaActive && selectedFinaPremiseId && selectedFinaDeviceId) {
250
335
  setLastUsedFinaCombo(entityId, {
@@ -264,6 +349,12 @@ export default function CreateCreditNoteForm({
264
349
  // Shared submit logic for both regular save and save as draft
265
350
  const submitCreditNote = useCallback(
266
351
  (values: CreateCreditNoteFormValues, isDraft: boolean) => {
352
+ // Build FURS options (skip for drafts; no skip toggle for credit notes)
353
+ const fursOptions =
354
+ !isDraft && isFursEnabled && selectedPremiseName && selectedDeviceName
355
+ ? { business_premise_name: selectedPremiseName, electronic_device_name: selectedDeviceName }
356
+ : undefined;
357
+
267
358
  // Build FINA options (skip for drafts; FINA can't be skipped)
268
359
  const finaOptions =
269
360
  !isDraft && isFinaEnabled && selectedFinaPremiseId && selectedFinaDeviceId
@@ -280,6 +371,11 @@ export default function CreateCreditNoteForm({
280
371
  isDraft,
281
372
  });
282
373
 
374
+ // Add FURS data to payload
375
+ if (fursOptions) {
376
+ (payload as any).furs = fursOptions;
377
+ }
378
+
283
379
  // Add FINA data to payload
284
380
  if (finaOptions) {
285
381
  (payload as any).fina = finaOptions;
@@ -289,12 +385,15 @@ export default function CreateCreditNoteForm({
289
385
  },
290
386
  [
291
387
  createCreditNote,
388
+ isFursEnabled,
292
389
  isFinaEnabled,
293
390
  markAsPaid,
294
391
  originalCustomer,
295
392
  paymentTypes,
393
+ selectedDeviceName,
296
394
  selectedFinaDeviceId,
297
395
  selectedFinaPremiseId,
396
+ selectedPremiseName,
298
397
  showCustomerForm,
299
398
  ],
300
399
  );
@@ -449,6 +548,18 @@ export default function CreateCreditNoteForm({
449
548
  control={form.control}
450
549
  documentType={_type}
451
550
  t={t}
551
+ fursInline={
552
+ isFursEnabled && hasFursPremises
553
+ ? {
554
+ premises: activePremises.map((p) => ({ id: p.id, business_premise_name: p.business_premise_name })),
555
+ devices: activeDevices.map((d) => ({ id: d.id, electronic_device_name: d.electronic_device_name })),
556
+ selectedPremise: selectedPremiseName,
557
+ selectedDevice: selectedDeviceName,
558
+ onPremiseChange: setSelectedPremiseName,
559
+ onDeviceChange: setSelectedDeviceName,
560
+ }
561
+ : undefined
562
+ }
452
563
  finaInline={
453
564
  isFinaEnabled && hasFinaPremises
454
565
  ? {
@@ -74,4 +74,6 @@ export default {
74
74
  "Cannot skip fiscalization for cash payments": "Fiskalisierung kann für Barzahlungen nicht übersprungen werden",
75
75
  Premise: "Geschäftsräume",
76
76
  Device: "Gerät",
77
+ "FINA fiscalized invoices always use the current date":
78
+ "FINA-fiskalisierte Dokumente verwenden immer das aktuelle Datum",
77
79
  } as const;
@@ -73,4 +73,6 @@ export default {
73
73
  "Cannot skip fiscalization for cash payments": "No se puede omitir la fiscalizacion para pagos en efectivo",
74
74
  Premise: "Local",
75
75
  Device: "Dispositivo",
76
+ "FINA fiscalized invoices always use the current date":
77
+ "Los documentos fiscalizados con FINA siempre usan la fecha actual",
76
78
  } as const;
@@ -73,4 +73,6 @@ export default {
73
73
  "Cannot skip fiscalization for cash payments": "Impossible d'ignorer la fiscalisation pour les paiements en especes",
74
74
  Premise: "Local",
75
75
  Device: "Appareil",
76
+ "FINA fiscalized invoices always use the current date":
77
+ "Les documents fiscalisés FINA utilisent toujours la date actuelle",
76
78
  } as const;
@@ -72,4 +72,5 @@ export default {
72
72
  "Cannot skip fiscalization for cash payments": "Za gotovinska placanja nije moguce preskociti fiskalizaciju",
73
73
  Premise: "Prostor",
74
74
  Device: "Uredaj",
75
+ "FINA fiscalized invoices always use the current date": "FINA fiskalizirani dokumenti uvijek koriste trenutni datum",
75
76
  } as const;
@@ -74,4 +74,6 @@ export default {
74
74
  "Non e possibile saltare la fiscalizzazione per i pagamenti in contanti",
75
75
  Premise: "Locale",
76
76
  Device: "Dispositivo",
77
+ "FINA fiscalized invoices always use the current date":
78
+ "I documenti fiscalizzati FINA utilizzano sempre la data corrente",
77
79
  } as const;
@@ -73,4 +73,6 @@ export default {
73
73
  "Cannot skip fiscalization for cash payments": "Fiscalisatie kan niet worden overgeslagen voor contante betalingen",
74
74
  Premise: "Bedrijfsruimte",
75
75
  Device: "Apparaat",
76
+ "FINA fiscalized invoices always use the current date":
77
+ "FINA-gefiscaliseerde documenten gebruiken altijd de huidige datum",
76
78
  } as const;
@@ -72,4 +72,5 @@ export default {
72
72
  "Cannot skip fiscalization for cash payments": "Nie mozna pominac fiskalizacji dla platnosci gotowkowych",
73
73
  Premise: "Lokal",
74
74
  Device: "Urządzenie",
75
+ "FINA fiscalized invoices always use the current date": "Dokumenty fiskalizowane FINA zawsze używają bieżącej daty",
75
76
  } as const;
@@ -72,4 +72,5 @@ export default {
72
72
  "Cannot skip fiscalization for cash payments": "Nao e possivel ignorar a fiscalizacao para pagamentos em dinheiro",
73
73
  Premise: "Estabelecimento",
74
74
  Device: "Dispositivo",
75
+ "FINA fiscalized invoices always use the current date": "Os documentos fiscalizados FINA usam sempre a data atual",
75
76
  } as const;
@@ -71,4 +71,5 @@ export default {
71
71
  "Cannot skip fiscalization for cash payments": "Za gotovinska plačila ni mogoče preskočiti davčnega potrjevanja",
72
72
  Premise: "Poslovni prostor",
73
73
  Device: "Naprava",
74
+ "FINA fiscalized invoices always use the current date": "FINA fiskalizirani dokumenti vedno uporabijo trenutni datum",
74
75
  } as const;
@@ -21,6 +21,36 @@ const {
21
21
 
22
22
  export { useCreateCreditNote, useUpdateCreditNote, useDeleteCreditNote };
23
23
 
24
+ // ============================================================================
25
+ // FURS Last-Used Combo (localStorage) for credit notes
26
+ // ============================================================================
27
+
28
+ const FURS_CN_LAST_USED_KEY = "si:furs:cn:last-used";
29
+
30
+ export type FursCombo = {
31
+ business_premise_name: string;
32
+ electronic_device_name: string;
33
+ };
34
+
35
+ export function getLastUsedFursCombo(entityId: string): FursCombo | null {
36
+ if (typeof window === "undefined") return null;
37
+ try {
38
+ const stored = localStorage.getItem(`${FURS_CN_LAST_USED_KEY}:${entityId}`);
39
+ return stored ? JSON.parse(stored) : null;
40
+ } catch {
41
+ return null;
42
+ }
43
+ }
44
+
45
+ export function setLastUsedFursCombo(entityId: string, combo: FursCombo): void {
46
+ if (typeof window === "undefined") return;
47
+ try {
48
+ localStorage.setItem(`${FURS_CN_LAST_USED_KEY}:${entityId}`, JSON.stringify(combo));
49
+ } catch {
50
+ // Ignore localStorage errors
51
+ }
52
+ }
53
+
24
54
  // ============================================================================
25
55
  // FINA Last-Used Combo (localStorage) for credit notes
26
56
  // ============================================================================
@@ -1,4 +1,5 @@
1
1
  import type { CreditNote } from "@spaceinvoices/js-sdk";
2
+ import { AlertTriangle } from "lucide-react";
2
3
  import { useCallback, useMemo, useState } from "react";
3
4
  import { DataTable } from "@/ui/components/table/data-table";
4
5
  import { FormattedDate } from "@/ui/components/table/date-cell";
@@ -13,6 +14,8 @@ import type {
13
14
  } from "@/ui/components/table/types";
14
15
  import { Badge } from "@/ui/components/ui/badge";
15
16
  import { Button } from "@/ui/components/ui/button";
17
+ import { Tooltip, TooltipContent, TooltipTrigger } from "@/ui/components/ui/tooltip";
18
+ import { getFiscalizationFailureType } from "@/ui/lib/fiscalization";
16
19
  import { createTranslation } from "@/ui/lib/translation";
17
20
  import { useSDK } from "@/ui/providers/sdk-provider";
18
21
 
@@ -53,6 +56,9 @@ type CreditNoteListTableProps = {
53
56
  onDownloadSuccess?: (fileName: string) => void;
54
57
  onDownloadError?: (error: string) => void;
55
58
  onExportSelected?: (documentIds: string[]) => void;
59
+ onRetryFiscalization?: (documentIds: string[]) => void;
60
+ fiscalizationFeatures?: ("furs" | "fina")[];
61
+ onCreateNew?: () => void;
56
62
  } & ListTableProps<CreditNote>;
57
63
 
58
64
  export default function CreditNoteListTable({
@@ -67,6 +73,9 @@ export default function CreditNoteListTable({
67
73
  onDownloadSuccess,
68
74
  onDownloadError,
69
75
  onExportSelected,
76
+ onRetryFiscalization,
77
+ fiscalizationFeatures,
78
+ onCreateNew,
70
79
  ...i18nProps
71
80
  }: CreditNoteListTableProps) {
72
81
  const t = createTranslation({
@@ -86,7 +95,6 @@ export default function CreditNoteListTable({
86
95
  limit: params.limit,
87
96
  next_cursor: params.next_cursor,
88
97
  prev_cursor: params.prev_cursor,
89
- order_by: params.order_by,
90
98
  search: params.search,
91
99
  query: params.query,
92
100
  });
@@ -115,15 +123,42 @@ export default function CreditNoteListTable({
115
123
  }, []);
116
124
 
117
125
  const selectionToolbar = useCallback(
118
- (count: number) => (
119
- <SelectionToolbar
120
- selectedCount={count}
121
- onExportPdfs={onExportSelected ? handleExportPdfs : undefined}
122
- onDeselectAll={handleDeselectAll}
123
- t={t}
124
- />
125
- ),
126
- [handleExportPdfs, handleDeselectAll, onExportSelected, t],
126
+ (count: number, data: CreditNote[]) => {
127
+ const selectedDocs = data.filter((d) => selectedIds.has(d.id));
128
+ const failedDocs = selectedDocs.filter((d) => {
129
+ const failureType = getFiscalizationFailureType(d as any);
130
+ return failureType && fiscalizationFeatures?.includes(failureType);
131
+ });
132
+
133
+ const hasRetry = onRetryFiscalization && fiscalizationFeatures?.length;
134
+ const failedCount = failedDocs.length;
135
+ const allFailed = failedCount > 0 && failedCount === selectedDocs.length;
136
+ const someFailed = failedCount > 0 && failedCount < selectedDocs.length;
137
+ const showRetry = hasRetry && failedCount > 0;
138
+
139
+ return (
140
+ <SelectionToolbar
141
+ selectedCount={count}
142
+ onExportPdfs={onExportSelected ? handleExportPdfs : undefined}
143
+ onRetryFiscalization={showRetry ? () => onRetryFiscalization(failedDocs.map((d) => d.id)) : undefined}
144
+ retryFiscalizationDisabled={someFailed && !allFailed}
145
+ retryFiscalizationTooltip={
146
+ someFailed ? t("Some selected documents don't have failed fiscalization") : undefined
147
+ }
148
+ onDeselectAll={handleDeselectAll}
149
+ t={t}
150
+ />
151
+ );
152
+ },
153
+ [
154
+ handleExportPdfs,
155
+ handleDeselectAll,
156
+ onExportSelected,
157
+ onRetryFiscalization,
158
+ fiscalizationFeatures,
159
+ selectedIds,
160
+ t,
161
+ ],
127
162
  );
128
163
 
129
164
  const columns: Column<CreditNote>[] = useMemo(
@@ -131,22 +166,35 @@ export default function CreditNoteListTable({
131
166
  {
132
167
  id: "number",
133
168
  header: t("Number"),
134
- sortable: true,
135
- cell: (creditNote) => (
136
- <div className="flex items-center gap-2">
137
- <Button variant="link" className="cursor-pointer py-0 underline" onClick={() => onRowClick?.(creditNote)}>
138
- {creditNote.number}
139
- </Button>
140
- {(creditNote as any).is_draft && (
141
- <Badge
142
- variant="outline"
143
- className="border-amber-500 bg-amber-50 text-amber-700 dark:bg-amber-950 dark:text-amber-400"
144
- >
145
- {t("Draft")}
146
- </Badge>
147
- )}
148
- </div>
149
- ),
169
+ cell: (creditNote) => {
170
+ const failureType = getFiscalizationFailureType(creditNote as any);
171
+ const showWarning = failureType && fiscalizationFeatures?.includes(failureType);
172
+ return (
173
+ <div className="flex items-center gap-2">
174
+ <Button variant="link" className="cursor-pointer py-0 underline" onClick={() => onRowClick?.(creditNote)}>
175
+ {creditNote.number}
176
+ </Button>
177
+ {(creditNote as any).is_draft && (
178
+ <Badge
179
+ variant="outline"
180
+ className="border-amber-500 bg-amber-50 text-amber-700 dark:bg-amber-950 dark:text-amber-400"
181
+ >
182
+ {t("Draft")}
183
+ </Badge>
184
+ )}
185
+ {showWarning && (
186
+ <Tooltip>
187
+ <TooltipTrigger>
188
+ <AlertTriangle className="size-4 text-orange-500" />
189
+ </TooltipTrigger>
190
+ <TooltipContent>
191
+ {t(failureType === "furs" ? "FURS fiscalization failed" : "FINA fiscalization failed")}
192
+ </TooltipContent>
193
+ </Tooltip>
194
+ )}
195
+ </div>
196
+ );
197
+ },
150
198
  },
151
199
  {
152
200
  id: "customer",
@@ -156,20 +204,17 @@ export default function CreditNoteListTable({
156
204
  {
157
205
  id: "date",
158
206
  header: t("Date"),
159
- sortable: true,
160
207
  cell: (creditNote) => <FormattedDate date={creditNote.date} />,
161
208
  },
162
209
  {
163
210
  id: "total",
164
211
  header: t("Total"),
165
- sortable: true,
166
212
  align: "right",
167
213
  cell: (creditNote) => creditNote.total,
168
214
  },
169
215
  {
170
216
  id: "total_with_tax",
171
217
  header: t("Total with Tax"),
172
- sortable: true,
173
218
  align: "right",
174
219
  cell: (creditNote) => creditNote.total_with_tax,
175
220
  },
@@ -207,6 +252,7 @@ export default function CreditNoteListTable({
207
252
  onDownloadSuccess,
208
253
  onDownloadError,
209
254
  i18nProps.locale,
255
+ fiscalizationFeatures,
210
256
  ],
211
257
  );
212
258
 
@@ -217,13 +263,14 @@ export default function CreditNoteListTable({
217
263
  resourceName="credit_note"
218
264
  cacheKey="credit-notes"
219
265
  createNewLink={entityId ? `/app/${entityId}/documents/add/credit_note` : undefined}
266
+ onCreateNew={onCreateNew}
220
267
  onFetch={handleFetch}
221
268
  onChangeParams={onChangeParams}
222
269
  entityId={entityId}
223
270
  filterConfig={filterConfig}
224
271
  t={t}
225
272
  locale={i18nProps.locale}
226
- selectable={!!onExportSelected}
273
+ selectable={!!(onExportSelected || onRetryFiscalization)}
227
274
  selectedIds={selectedIds}
228
275
  onSelectionChange={setSelectedIds}
229
276
  selectionToolbar={selectionToolbar}
@@ -38,7 +38,12 @@ export default {
38
38
  "No results found": "Keine Gutschriften gefunden",
39
39
  "Try adjusting your search criteria": "Versuchen Sie, Ihre Suchkriterien anzupassen",
40
40
  "Clear search": "Suche zurücksetzen",
41
+ "Clear all": "Alles zurücksetzen",
41
42
  selected: "ausgewählt",
42
43
  "Export PDFs": "PDFs exportieren",
43
44
  "Deselect all": "Auswahl aufheben",
45
+ "FURS fiscalization failed": "FURS fiscalization failed",
46
+ "FINA fiscalization failed": "FINA fiscalization failed",
47
+ "Retry Fiscalization": "Retry Fiscalization",
48
+ "Some selected documents don't have failed fiscalization": "Some selected documents don't have failed fiscalization",
44
49
  } as const;
@@ -10,4 +10,8 @@ export default {
10
10
  "Deselect all": "Deselect all",
11
11
  "Partially Paid": "Partially Paid",
12
12
  Voided: "Voided",
13
+ "FURS fiscalization failed": "FURS fiscalization failed",
14
+ "FINA fiscalization failed": "FINA fiscalization failed",
15
+ "Retry Fiscalization": "Retry Fiscalization",
16
+ "Some selected documents don't have failed fiscalization": "Some selected documents don't have failed fiscalization",
13
17
  } as const;
@@ -38,7 +38,12 @@ export default {
38
38
  "No results found": "No se encontraron notas de credito",
39
39
  "Try adjusting your search criteria": "Intente ajustar sus criterios de busqueda",
40
40
  "Clear search": "Limpiar busqueda",
41
+ "Clear all": "Borrar todo",
41
42
  selected: "seleccionados",
42
43
  "Export PDFs": "Exportar PDFs",
43
44
  "Deselect all": "Deseleccionar todo",
45
+ "FURS fiscalization failed": "FURS fiscalization failed",
46
+ "FINA fiscalization failed": "FINA fiscalization failed",
47
+ "Retry Fiscalization": "Retry Fiscalization",
48
+ "Some selected documents don't have failed fiscalization": "Some selected documents don't have failed fiscalization",
44
49
  } as const;
@@ -38,7 +38,12 @@ export default {
38
38
  "No results found": "Aucun avoir trouve",
39
39
  "Try adjusting your search criteria": "Essayez de modifier vos criteres de recherche",
40
40
  "Clear search": "Effacer la recherche",
41
+ "Clear all": "Tout effacer",
41
42
  selected: "sélectionnés",
42
43
  "Export PDFs": "Exporter les PDF",
43
44
  "Deselect all": "Tout désélectionner",
45
+ "FURS fiscalization failed": "FURS fiscalization failed",
46
+ "FINA fiscalization failed": "FINA fiscalization failed",
47
+ "Retry Fiscalization": "Retry Fiscalization",
48
+ "Some selected documents don't have failed fiscalization": "Some selected documents don't have failed fiscalization",
44
49
  } as const;
@@ -38,7 +38,12 @@ export default {
38
38
  "No results found": "Nije pronadjeno nijedno odobrenje",
39
39
  "Try adjusting your search criteria": "Pokusajte prilagoditi kriterije pretrazivanja",
40
40
  "Clear search": "Ocisti pretragu",
41
+ "Clear all": "Očisti sve",
41
42
  selected: "odabranih",
42
43
  "Export PDFs": "Izvezi PDF-ove",
43
44
  "Deselect all": "Poništi odabir",
45
+ "FURS fiscalization failed": "FURS fiskalizacija nije uspjela",
46
+ "FINA fiscalization failed": "FINA fiskalizacija nije uspjela",
47
+ "Retry Fiscalization": "Ponovi fiskalizaciju",
48
+ "Some selected documents don't have failed fiscalization": "Neki odabrani dokumenti nemaju neuspjelu fiskalizaciju",
44
49
  } as const;
@@ -38,7 +38,12 @@ export default {
38
38
  "No results found": "Nessuna nota di credito trovata",
39
39
  "Try adjusting your search criteria": "Prova a modificare i criteri di ricerca",
40
40
  "Clear search": "Cancella ricerca",
41
+ "Clear all": "Cancella tutto",
41
42
  selected: "selezionati",
42
43
  "Export PDFs": "Esporta PDF",
43
44
  "Deselect all": "Deseleziona tutto",
45
+ "FURS fiscalization failed": "FURS fiscalization failed",
46
+ "FINA fiscalization failed": "FINA fiscalization failed",
47
+ "Retry Fiscalization": "Retry Fiscalization",
48
+ "Some selected documents don't have failed fiscalization": "Some selected documents don't have failed fiscalization",
44
49
  } as const;
@@ -38,7 +38,12 @@ export default {
38
38
  "No results found": "Geen creditnota's gevonden",
39
39
  "Try adjusting your search criteria": "Probeer uw zoekcriteria aan te passen",
40
40
  "Clear search": "Zoekopdracht wissen",
41
+ "Clear all": "Alles wissen",
41
42
  selected: "geselecteerd",
42
43
  "Export PDFs": "PDFs exporteren",
43
44
  "Deselect all": "Alles deselecteren",
45
+ "FURS fiscalization failed": "FURS fiscalization failed",
46
+ "FINA fiscalization failed": "FINA fiscalization failed",
47
+ "Retry Fiscalization": "Retry Fiscalization",
48
+ "Some selected documents don't have failed fiscalization": "Some selected documents don't have failed fiscalization",
44
49
  } as const;
@@ -38,7 +38,12 @@ export default {
38
38
  "No results found": "Nie znaleziono not kredytowych",
39
39
  "Try adjusting your search criteria": "Sprobuj dostosowac kryteria wyszukiwania",
40
40
  "Clear search": "Wyczysc wyszukiwanie",
41
+ "Clear all": "Wyczyść wszystko",
41
42
  selected: "wybranych",
42
43
  "Export PDFs": "Eksportuj PDF-y",
43
44
  "Deselect all": "Odznacz wszystko",
45
+ "FURS fiscalization failed": "FURS fiscalization failed",
46
+ "FINA fiscalization failed": "FINA fiscalization failed",
47
+ "Retry Fiscalization": "Retry Fiscalization",
48
+ "Some selected documents don't have failed fiscalization": "Some selected documents don't have failed fiscalization",
44
49
  } as const;
@@ -38,7 +38,12 @@ export default {
38
38
  "No results found": "Nenhuma nota de credito encontrada",
39
39
  "Try adjusting your search criteria": "Tente ajustar os seus criterios de pesquisa",
40
40
  "Clear search": "Limpar pesquisa",
41
+ "Clear all": "Limpar tudo",
41
42
  selected: "selecionados",
42
43
  "Export PDFs": "Exportar PDFs",
43
44
  "Deselect all": "Desselecionar tudo",
45
+ "FURS fiscalization failed": "FURS fiscalization failed",
46
+ "FINA fiscalization failed": "FINA fiscalization failed",
47
+ "Retry Fiscalization": "Retry Fiscalization",
48
+ "Some selected documents don't have failed fiscalization": "Some selected documents don't have failed fiscalization",
44
49
  } as const;
@@ -38,7 +38,12 @@ export default {
38
38
  "No results found": "Ni najdenih dobropisov",
39
39
  "Try adjusting your search criteria": "Poskusite prilagoditi iskalne kriterije",
40
40
  "Clear search": "Počisti iskanje",
41
+ "Clear all": "Počisti vse",
41
42
  selected: "izbranih",
42
43
  "Export PDFs": "Izvozi PDF-je",
43
44
  "Deselect all": "Počisti izbiro",
45
+ "FURS fiscalization failed": "FURS davčno potrjevanje ni uspelo",
46
+ "FINA fiscalization failed": "FINA fiskalizacija ni uspela",
47
+ "Retry Fiscalization": "Ponovi fiskalizacijo",
48
+ "Some selected documents don't have failed fiscalization": "Nekateri izbrani dokumenti nimajo neuspele fiskalizacije",
44
49
  } as const;
@@ -69,7 +69,6 @@ export default function CustomerListTable({
69
69
  limit: params.limit,
70
70
  next_cursor: params.next_cursor,
71
71
  prev_cursor: params.prev_cursor,
72
- order_by: params.order_by,
73
72
  search: params.search,
74
73
  query: params.query,
75
74
  });
@@ -81,7 +80,6 @@ export default function CustomerListTable({
81
80
  {
82
81
  id: "name",
83
82
  header: t("Name"),
84
- sortable: true,
85
83
  cell: (customer) => (
86
84
  <Button variant="link" className="cursor-pointer py-0 underline" onClick={() => onRowClick?.(customer)}>
87
85
  <User className="h-4 w-4 flex-shrink-0" />
@@ -92,7 +90,6 @@ export default function CustomerListTable({
92
90
  {
93
91
  id: "address",
94
92
  header: t("Address"),
95
- sortable: true,
96
93
  cell: (customer) => customer.address,
97
94
  },
98
95
  {
@@ -22,4 +22,5 @@ export default {
22
22
  "No results found": "Keine Kunden gefunden",
23
23
  "Try adjusting your search criteria": "Versuchen Sie, Ihre Suchkriterien anzupassen",
24
24
  "Clear search": "Suche zurücksetzen",
25
+ "Clear all": "Alles zurücksetzen",
25
26
  } as const;