@spaceinvoices/react-ui 0.4.4 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/cli/dist/index.js +1 -1
  2. package/package.json +1 -1
  3. package/src/components/advance-invoices/create/create-advance-invoice-form.tsx +61 -11
  4. package/src/components/advance-invoices/create/locales/de.ts +15 -0
  5. package/src/components/advance-invoices/create/locales/es.ts +15 -0
  6. package/src/components/advance-invoices/create/locales/fr.ts +15 -0
  7. package/src/components/advance-invoices/create/locales/hr.ts +15 -0
  8. package/src/components/advance-invoices/create/locales/it.ts +15 -0
  9. package/src/components/advance-invoices/create/locales/nl.ts +15 -0
  10. package/src/components/advance-invoices/create/locales/pl.ts +15 -0
  11. package/src/components/advance-invoices/create/locales/pt.ts +15 -0
  12. package/src/components/advance-invoices/create/locales/sl.ts +15 -0
  13. package/src/components/advance-invoices/list/list-row-actions.tsx +48 -1
  14. package/src/components/advance-invoices/list/list-table.tsx +21 -1
  15. package/src/components/advance-invoices/list/locales/de.ts +4 -0
  16. package/src/components/advance-invoices/list/locales/en.ts +3 -0
  17. package/src/components/advance-invoices/list/locales/es.ts +4 -0
  18. package/src/components/advance-invoices/list/locales/fr.ts +4 -0
  19. package/src/components/advance-invoices/list/locales/hr.ts +3 -0
  20. package/src/components/advance-invoices/list/locales/it.ts +4 -0
  21. package/src/components/advance-invoices/list/locales/nl.ts +4 -0
  22. package/src/components/advance-invoices/list/locales/pl.ts +3 -0
  23. package/src/components/advance-invoices/list/locales/pt.ts +4 -0
  24. package/src/components/advance-invoices/list/locales/sl.ts +3 -0
  25. package/src/components/credit-notes/create/create-credit-note-form.tsx +71 -8
  26. package/src/components/credit-notes/create/locales/de.ts +16 -0
  27. package/src/components/credit-notes/create/locales/es.ts +16 -0
  28. package/src/components/credit-notes/create/locales/fr.ts +16 -0
  29. package/src/components/credit-notes/create/locales/hr.ts +16 -0
  30. package/src/components/credit-notes/create/locales/it.ts +16 -0
  31. package/src/components/credit-notes/create/locales/nl.ts +16 -0
  32. package/src/components/credit-notes/create/locales/pl.ts +16 -0
  33. package/src/components/credit-notes/create/locales/pt.ts +16 -0
  34. package/src/components/credit-notes/create/locales/sl.ts +17 -1
  35. package/src/components/credit-notes/list/list-row-actions.tsx +44 -1
  36. package/src/components/credit-notes/list/list-table.tsx +16 -2
  37. package/src/components/credit-notes/list/locales/de.ts +2 -0
  38. package/src/components/credit-notes/list/locales/en.ts +2 -0
  39. package/src/components/credit-notes/list/locales/es.ts +2 -0
  40. package/src/components/credit-notes/list/locales/fr.ts +2 -0
  41. package/src/components/credit-notes/list/locales/hr.ts +2 -0
  42. package/src/components/credit-notes/list/locales/it.ts +2 -0
  43. package/src/components/credit-notes/list/locales/nl.ts +2 -0
  44. package/src/components/credit-notes/list/locales/pl.ts +2 -0
  45. package/src/components/credit-notes/list/locales/pt.ts +2 -0
  46. package/src/components/credit-notes/list/locales/sl.ts +2 -0
  47. package/src/components/dashboard/collection-rate-card/use-collection-rate.ts +48 -9
  48. package/src/components/dashboard/revenue-trend-chart/use-revenue-trend.ts +77 -48
  49. package/src/components/dashboard/shared/use-revenue-data.ts +77 -9
  50. package/src/components/delivery-notes/create/create-delivery-note-form.tsx +67 -7
  51. package/src/components/delivery-notes/create/locales/de.ts +16 -0
  52. package/src/components/delivery-notes/create/locales/es.ts +16 -0
  53. package/src/components/delivery-notes/create/locales/fr.ts +16 -0
  54. package/src/components/delivery-notes/create/locales/hr.ts +16 -0
  55. package/src/components/delivery-notes/create/locales/it.ts +16 -0
  56. package/src/components/delivery-notes/create/locales/nl.ts +16 -0
  57. package/src/components/delivery-notes/create/locales/pl.ts +16 -0
  58. package/src/components/delivery-notes/create/locales/pt.ts +16 -0
  59. package/src/components/delivery-notes/create/locales/sl.ts +17 -1
  60. package/src/components/delivery-notes/list/list-table.tsx +17 -8
  61. package/src/components/delivery-notes/list/locales/de.ts +32 -1
  62. package/src/components/delivery-notes/list/locales/en.ts +31 -0
  63. package/src/components/delivery-notes/list/locales/es.ts +32 -1
  64. package/src/components/delivery-notes/list/locales/fr.ts +32 -1
  65. package/src/components/delivery-notes/list/locales/hr.ts +32 -1
  66. package/src/components/delivery-notes/list/locales/it.ts +32 -1
  67. package/src/components/delivery-notes/list/locales/nl.ts +32 -1
  68. package/src/components/delivery-notes/list/locales/pl.ts +32 -1
  69. package/src/components/delivery-notes/list/locales/pt.ts +32 -1
  70. package/src/components/delivery-notes/list/locales/sl.ts +32 -1
  71. package/src/components/documents/create/document-add-item-form.tsx +70 -0
  72. package/src/components/documents/create/document-details-section.tsx +122 -2
  73. package/src/components/documents/create/document-items-section.tsx +21 -4
  74. package/src/components/documents/create/live-preview.tsx +24 -4
  75. package/src/components/documents/create/mark-as-paid-section.tsx +29 -20
  76. package/src/components/documents/create/prepare-document-submission.ts +19 -7
  77. package/src/components/documents/shared/document-preview-display.tsx +3 -4
  78. package/src/components/documents/view/document-actions-bar.tsx +7 -27
  79. package/src/components/documents/view/document-details-card.tsx +26 -9
  80. package/src/components/documents/view/locales/de.ts +2 -0
  81. package/src/components/documents/view/locales/es.ts +2 -0
  82. package/src/components/documents/view/locales/fr.ts +2 -0
  83. package/src/components/documents/view/locales/hr.ts +2 -0
  84. package/src/components/documents/view/locales/it.ts +2 -0
  85. package/src/components/documents/view/locales/nl.ts +2 -0
  86. package/src/components/documents/view/locales/pl.ts +2 -0
  87. package/src/components/documents/view/locales/pt.ts +2 -0
  88. package/src/components/documents/view/locales/sl.ts +3 -1
  89. package/src/components/documents/view/use-document-download.ts +6 -3
  90. package/src/components/entities/create-entity-form.tsx +2 -1
  91. package/src/components/entities/entity-settings-form/input-with-preview.tsx +30 -2
  92. package/src/components/entities/entity-settings-form/locales/de.ts +1 -0
  93. package/src/components/entities/entity-settings-form/locales/es.ts +1 -0
  94. package/src/components/entities/entity-settings-form/locales/fr.ts +1 -0
  95. package/src/components/entities/entity-settings-form/locales/hr.ts +1 -0
  96. package/src/components/entities/entity-settings-form/locales/it.ts +1 -0
  97. package/src/components/entities/entity-settings-form/locales/nl.ts +1 -0
  98. package/src/components/entities/entity-settings-form/locales/pl.ts +1 -0
  99. package/src/components/entities/entity-settings-form/locales/pt.ts +1 -0
  100. package/src/components/entities/entity-settings-form/locales/sl.ts +1 -0
  101. package/src/components/entities/settings/company-settings-form.tsx +173 -20
  102. package/src/components/estimates/create/create-estimate-form.tsx +64 -6
  103. package/src/components/estimates/create/locales/de.ts +16 -0
  104. package/src/components/estimates/create/locales/es.ts +16 -0
  105. package/src/components/estimates/create/locales/fr.ts +16 -0
  106. package/src/components/estimates/create/locales/hr.ts +16 -0
  107. package/src/components/estimates/create/locales/it.ts +16 -0
  108. package/src/components/estimates/create/locales/nl.ts +16 -0
  109. package/src/components/estimates/create/locales/pl.ts +16 -0
  110. package/src/components/estimates/create/locales/pt.ts +16 -0
  111. package/src/components/estimates/create/locales/sl.ts +17 -1
  112. package/src/components/estimates/list/list-table.tsx +11 -2
  113. package/src/components/estimates/list/locales/de.ts +1 -0
  114. package/src/components/estimates/list/locales/en.ts +1 -0
  115. package/src/components/estimates/list/locales/es.ts +1 -0
  116. package/src/components/estimates/list/locales/fr.ts +1 -0
  117. package/src/components/estimates/list/locales/hr.ts +1 -0
  118. package/src/components/estimates/list/locales/it.ts +1 -0
  119. package/src/components/estimates/list/locales/nl.ts +1 -0
  120. package/src/components/estimates/list/locales/pl.ts +1 -0
  121. package/src/components/estimates/list/locales/pt.ts +1 -0
  122. package/src/components/estimates/list/locales/sl.ts +1 -0
  123. package/src/components/export/document-export-form.tsx +46 -12
  124. package/src/components/invoices/create/create-invoice-form.tsx +58 -10
  125. package/src/components/invoices/create/locales/de.ts +15 -0
  126. package/src/components/invoices/create/locales/es.ts +15 -0
  127. package/src/components/invoices/create/locales/fr.ts +15 -0
  128. package/src/components/invoices/create/locales/hr.ts +15 -0
  129. package/src/components/invoices/create/locales/it.ts +15 -0
  130. package/src/components/invoices/create/locales/nl.ts +15 -0
  131. package/src/components/invoices/create/locales/pl.ts +15 -0
  132. package/src/components/invoices/create/locales/pt.ts +15 -0
  133. package/src/components/invoices/create/locales/sl.ts +16 -1
  134. package/src/components/invoices/view/fiscalization-status-card.tsx +10 -8
  135. package/src/components/table/search-input.tsx +17 -0
  136. package/src/generated/schemas/advanceinvoice.ts +4 -2
  137. package/src/generated/schemas/creditnote.ts +2 -1
  138. package/src/generated/schemas/deliverynote.ts +2 -1
  139. package/src/generated/schemas/estimate.ts +4 -2
  140. package/src/generated/schemas/invoice.ts +2 -1
  141. package/src/generated/schemas/renderadvanceinvoicepreview_body.ts +17 -23
  142. package/src/generated/schemas/rendercreditnotepreview_body.ts +17 -23
  143. package/src/generated/schemas/renderdeliverynotepreview_body.ts +17 -23
  144. package/src/generated/schemas/renderestimatepreview_body.ts +17 -23
  145. package/src/generated/schemas/renderinvoicepreview_body.ts +19 -23
  146. package/src/hooks/use-duplicate-document.ts +16 -9
  147. package/src/hooks/use-vies-check.ts +3 -0
@@ -17,7 +17,7 @@ export default {
17
17
  Price: "Cena",
18
18
  Unit: "Enota",
19
19
  Discount: "Popust",
20
- Tax: "Davek",
20
+ Tax: "DDV",
21
21
  "Tax rate": "Davčna stopnja",
22
22
  "Add tax": "Dodaj davek",
23
23
  "Select tax...": "Izberi davek...",
@@ -121,4 +121,19 @@ export default {
121
121
  "Date Range": "Obdobje",
122
122
  From: "Od",
123
123
  To: "Do",
124
+ // Separator items
125
+ "Add separator": "Dodaj ločilnik",
126
+ "Section header": "Naslov razdelka",
127
+ "Section title...": "Naslov razdelka...",
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...": "Določanje vrste transakcije...",
135
+ "This invoice will not be fiscalized (non-domestic transaction)":
136
+ "Ta račun ne bo fiskaliziran (nedomača transakcija)",
137
+ "Tax Clause": "Davčna klavzula",
138
+ "Add tax clause...": "Dodajte davčno klavzulo...",
124
139
  } as const;
@@ -91,10 +91,16 @@ export function FiscalizationStatusCard({
91
91
 
92
92
  const bodyContent = (
93
93
  <>
94
- <div className="text-muted-foreground text-sm">
95
- {label} &middot;{" "}
96
- {fiscalizationData.fiscalized_at && new Date(fiscalizationData.fiscalized_at).toLocaleString(locale)}
97
- </div>
94
+ {fiscalizationData.status === "skipped" ? (
95
+ <div className="text-muted-foreground text-sm">
96
+ {label} &middot; {t("Skipped by user")}
97
+ </div>
98
+ ) : (
99
+ <div className="text-muted-foreground text-sm">
100
+ {label} &middot;{" "}
101
+ {fiscalizationData.fiscalized_at && new Date(fiscalizationData.fiscalized_at).toLocaleString(locale)}
102
+ </div>
103
+ )}
98
104
 
99
105
  {fiscalizationData.status === "failed" && fiscalizationData.error && (
100
106
  <Alert variant="destructive">
@@ -103,10 +109,6 @@ export function FiscalizationStatusCard({
103
109
  </Alert>
104
110
  )}
105
111
 
106
- {fiscalizationData.status === "skipped" && (fiscalizationData as any).data?.reason && (
107
- <div className="text-muted-foreground text-sm">{(fiscalizationData as any).data.reason}</div>
108
- )}
109
-
110
112
  {fiscalizationData.status === "failed" && onRetry && (
111
113
  <Button variant="outline" size="sm" onClick={onRetry} disabled={isRetrying}>
112
114
  {isRetrying ? <Loader2 className="mr-2 h-4 w-4 animate-spin" /> : <RefreshCw className="mr-2 h-4 w-4" />}
@@ -16,6 +16,7 @@ type SearchInputProps = {
16
16
  */
17
17
  export function SearchInput({ initialValue = "", onSearch, placeholder = "Search...", debounceMs }: SearchInputProps) {
18
18
  const [value, setValue] = useState(initialValue);
19
+ const [isFocused, setIsFocused] = useState(false);
19
20
 
20
21
  // Use ref to keep onSearch stable in useEffect
21
22
  const onSearchRef = useRef(onSearch);
@@ -56,6 +57,9 @@ export function SearchInput({ initialValue = "", onSearch, placeholder = "Search
56
57
  onSearchRef.current(null);
57
58
  }, []);
58
59
 
60
+ // Show "Enter ↵" hint when input requires Enter to search (no debounce) and user is typing
61
+ const showEnterHint = debounceMs === undefined && value && isFocused;
62
+
59
63
  return (
60
64
  <form onSubmit={handleSubmit} className="relative inline-block" data-testid="search-form">
61
65
  <Search className="pointer-events-none absolute top-1/2 left-2.5 z-10 h-3 w-3 -translate-y-1/2 text-muted-foreground" />
@@ -66,8 +70,21 @@ export function SearchInput({ initialValue = "", onSearch, placeholder = "Search
66
70
  placeholder={placeholder}
67
71
  value={value}
68
72
  onChange={handleChange}
73
+ onFocus={() => setIsFocused(true)}
74
+ onBlur={() => setIsFocused(false)}
69
75
  className="h-8 w-[150px] pr-8 pl-8 lg:w-[250px] [&::-webkit-search-cancel-button]:hidden [&::-webkit-search-decoration]:hidden"
70
76
  />
77
+ {/* Overlay that mirrors input padding to position hint right after typed text */}
78
+ {showEnterHint && (
79
+ <span
80
+ aria-hidden="true"
81
+ className="pointer-events-none absolute inset-0 flex items-center overflow-hidden pl-8 text-sm"
82
+ >
83
+ {/* Invisible text matching input value to push hint to the right */}
84
+ <span className="invisible whitespace-pre">{value}</span>
85
+ <span className="ml-1.5 shrink-0 text-muted-foreground/50 text-xs">Enter &crarr;</span>
86
+ </span>
87
+ )}
71
88
  {value && (
72
89
  <Button
73
90
  type="button"
@@ -104,11 +104,12 @@ const createAdvanceInvoiceSchemaDefinition = z.object({
104
104
  items: z
105
105
  .array(
106
106
  z.object({
107
+ type: z.enum(["separator"]).optional(),
107
108
  name: z.string().min(1).optional(),
108
109
  description: z.union([z.string().max(4000, "Description must not exceed 4000 characters"), z.null()]).optional(),
109
110
  price: z.number().optional(),
110
111
  gross_price: z.number().optional(),
111
- quantity: z.number().gte(-140737488355328).lte(140737488355327),
112
+ quantity: z.number().gte(-140737488355328).lte(140737488355327).optional(),
112
113
  unit: z.union([z.string(), z.null()]).optional(),
113
114
  taxes: z.array(DocumentItemTax).optional(),
114
115
  discounts: z.array(LineDiscount).max(5).optional(),
@@ -202,11 +203,12 @@ const updateAdvanceInvoiceSchemaDefinition = z
202
203
  items: z
203
204
  .array(
204
205
  z.object({
206
+ type: z.enum(["separator"]).optional(),
205
207
  name: z.string().min(1).optional(),
206
208
  description: z.union([z.string().max(4000, "Description must not exceed 4000 characters"), z.null()]).optional(),
207
209
  price: z.number().optional(),
208
210
  gross_price: z.number().optional(),
209
- quantity: z.number().gte(-140737488355328).lte(140737488355327),
211
+ quantity: z.number().gte(-140737488355328).lte(140737488355327).optional(),
210
212
  unit: z.union([z.string(), z.null()]).optional(),
211
213
  taxes: z.array(DocumentItemTax).optional(),
212
214
  discounts: z.array(LineDiscount).max(5).optional(),
@@ -85,11 +85,12 @@ const updateCreditNoteSchemaDefinition = z
85
85
  items: z
86
86
  .array(
87
87
  z.object({
88
+ type: z.enum(["separator"]).optional(),
88
89
  name: z.string().min(1).optional(),
89
90
  description: z.union([z.string().max(4000, "Description must not exceed 4000 characters"), z.null()]).optional(),
90
91
  price: z.number().optional(),
91
92
  gross_price: z.number().optional(),
92
- quantity: z.number().gte(-140737488355328).lte(140737488355327),
93
+ quantity: z.number().gte(-140737488355328).lte(140737488355327).optional(),
93
94
  unit: z.union([z.string(), z.null()]).optional(),
94
95
  taxes: z.array(DocumentItemTax).optional(),
95
96
  discounts: z.array(LineDiscount).max(5).optional(),
@@ -93,11 +93,12 @@ const createDeliveryNoteSchemaDefinition = z.object({
93
93
  items: z
94
94
  .array(
95
95
  z.object({
96
+ type: z.enum(["separator"]).optional(),
96
97
  name: z.string().min(1).optional(),
97
98
  description: z.union([z.string().max(4000, "Description must not exceed 4000 characters"), z.null()]).optional(),
98
99
  price: z.number().optional(),
99
100
  gross_price: z.number().optional(),
100
- quantity: z.number().gte(-140737488355328).lte(140737488355327),
101
+ quantity: z.number().gte(-140737488355328).lte(140737488355327).optional(),
101
102
  unit: z.union([z.string(), z.null()]).optional(),
102
103
  taxes: z.array(DocumentItemTax).optional(),
103
104
  discounts: z.array(LineDiscount).max(5).optional(),
@@ -96,11 +96,12 @@ const createEstimateSchemaDefinition = z.object({
96
96
  items: z
97
97
  .array(
98
98
  z.object({
99
+ type: z.enum(["separator"]).optional(),
99
100
  name: z.string().min(1).optional(),
100
101
  description: z.union([z.string().max(4000, "Description must not exceed 4000 characters"), z.null()]).optional(),
101
102
  price: z.number().optional(),
102
103
  gross_price: z.number().optional(),
103
- quantity: z.number().gte(-140737488355328).lte(140737488355327),
104
+ quantity: z.number().gte(-140737488355328).lte(140737488355327).optional(),
104
105
  unit: z.union([z.string(), z.null()]).optional(),
105
106
  taxes: z.array(DocumentItemTax).optional(),
106
107
  discounts: z.array(LineDiscount).max(5).optional(),
@@ -155,11 +156,12 @@ const updateEstimateSchemaDefinition = z
155
156
  items: z
156
157
  .array(
157
158
  z.object({
159
+ type: z.enum(["separator"]).optional(),
158
160
  name: z.string().min(1).optional(),
159
161
  description: z.union([z.string().max(4000, "Description must not exceed 4000 characters"), z.null()]).optional(),
160
162
  price: z.number().optional(),
161
163
  gross_price: z.number().optional(),
162
- quantity: z.number().gte(-140737488355328).lte(140737488355327),
164
+ quantity: z.number().gte(-140737488355328).lte(140737488355327).optional(),
163
165
  unit: z.union([z.string(), z.null()]).optional(),
164
166
  taxes: z.array(DocumentItemTax).optional(),
165
167
  discounts: z.array(LineDiscount).max(5).optional(),
@@ -105,11 +105,12 @@ const createInvoiceSchemaDefinition = z.object({
105
105
  items: z
106
106
  .array(
107
107
  z.object({
108
+ type: z.enum(["separator"]).optional(),
108
109
  name: z.string().min(1).optional(),
109
110
  description: z.union([z.string().max(4000, "Description must not exceed 4000 characters"), z.null()]).optional(),
110
111
  price: z.number().optional(),
111
112
  gross_price: z.number().optional(),
112
- quantity: z.number().gte(-140737488355328).lte(140737488355327),
113
+ quantity: z.number().gte(-140737488355328).lte(140737488355327).optional(),
113
114
  unit: z.union([z.string(), z.null()]).optional(),
114
115
  taxes: z.array(DocumentItemTax).optional(),
115
116
  discounts: z.array(LineDiscount).max(5).optional(),
@@ -112,6 +112,7 @@ const PartialAdvanceInvoicePreview = z.object({
112
112
  .array(
113
113
  z
114
114
  .object({
115
+ type: z.literal("separator"),
115
116
  name: z.string(),
116
117
  quantity: z.number(),
117
118
  price: z.number(),
@@ -154,29 +155,22 @@ const LineDiscount = z.object({
154
155
 
155
156
 
156
157
  // Dependency schema for renderadvanceinvoicepreview_body
157
- const CreateDocumentItem = z.object({
158
- name: z.string().min(1).optional(),
159
- description: z.union([z.string(), z.null()]).optional(),
160
- price: z.number().optional(),
161
- gross_price: z.number().optional(),
162
- quantity: z.number().gte(-140737488355328).lte(140737488355327),
163
- unit: z.union([z.string(), z.null()]).optional(),
164
- taxes: z.array(DocumentItemTax).optional(),
165
- discounts: z.array(LineDiscount).max(5).optional(),
166
- delivery_note_id: z.union([z.string(), z.null()]).optional(),
167
- metadata: z
168
- .union([
169
- z.string(),
170
- z.number(),
171
- z.boolean(),
172
- z.null(),
173
- z.object({}).partial().passthrough(),
174
- z.array(z.unknown()),
175
- z.null(),
176
- ])
177
- .optional(),
178
- item_id: z.string().optional(),
179
- });
158
+ const CreateDocumentItem = z
159
+ .object({
160
+ type: z.literal("separator"),
161
+ name: z.string().min(1),
162
+ description: z.union([z.string(), z.null()]),
163
+ price: z.number(),
164
+ gross_price: z.number(),
165
+ quantity: z.union([z.number(), z.null()]),
166
+ unit: z.union([z.string(), z.null()]),
167
+ taxes: z.array(DocumentItemTax),
168
+ discounts: z.array(LineDiscount).max(5),
169
+ item_id: z.string(),
170
+ metadata: z.union([z.record(z.string(), z.any()), z.null()]),
171
+ save_item: z.boolean().default(true),
172
+ })
173
+ .partial();
180
174
 
181
175
 
182
176
  // Dependency schema for renderadvanceinvoicepreview_body
@@ -113,6 +113,7 @@ const PartialCreditNotePreview = z.object({
113
113
  .array(
114
114
  z
115
115
  .object({
116
+ type: z.literal("separator"),
116
117
  name: z.string(),
117
118
  quantity: z.number(),
118
119
  price: z.number(),
@@ -155,29 +156,22 @@ const LineDiscount = z.object({
155
156
 
156
157
 
157
158
  // Dependency schema for rendercreditnotepreview_body
158
- const CreateDocumentItem = z.object({
159
- name: z.string().min(1).optional(),
160
- description: z.union([z.string(), z.null()]).optional(),
161
- price: z.number().optional(),
162
- gross_price: z.number().optional(),
163
- quantity: z.number().gte(-140737488355328).lte(140737488355327),
164
- unit: z.union([z.string(), z.null()]).optional(),
165
- taxes: z.array(DocumentItemTax).optional(),
166
- discounts: z.array(LineDiscount).max(5).optional(),
167
- delivery_note_id: z.union([z.string(), z.null()]).optional(),
168
- metadata: z
169
- .union([
170
- z.string(),
171
- z.number(),
172
- z.boolean(),
173
- z.null(),
174
- z.object({}).partial().passthrough(),
175
- z.array(z.unknown()),
176
- z.null(),
177
- ])
178
- .optional(),
179
- item_id: z.string().optional(),
180
- });
159
+ const CreateDocumentItem = z
160
+ .object({
161
+ type: z.literal("separator"),
162
+ name: z.string().min(1),
163
+ description: z.union([z.string(), z.null()]),
164
+ price: z.number(),
165
+ gross_price: z.number(),
166
+ quantity: z.union([z.number(), z.null()]),
167
+ unit: z.union([z.string(), z.null()]),
168
+ taxes: z.array(DocumentItemTax),
169
+ discounts: z.array(LineDiscount).max(5),
170
+ item_id: z.string(),
171
+ metadata: z.union([z.record(z.string(), z.any()), z.null()]),
172
+ save_item: z.boolean().default(true),
173
+ })
174
+ .partial();
181
175
 
182
176
 
183
177
  // Dependency schema for rendercreditnotepreview_body
@@ -81,6 +81,7 @@ const PartialDeliveryNotePreview = z.object({
81
81
  .array(
82
82
  z
83
83
  .object({
84
+ type: z.literal("separator"),
84
85
  name: z.string(),
85
86
  quantity: z.number(),
86
87
  price: z.number(),
@@ -123,29 +124,22 @@ const LineDiscount = z.object({
123
124
 
124
125
 
125
126
  // Dependency schema for renderdeliverynotepreview_body
126
- const CreateDocumentItem = z.object({
127
- name: z.string().min(1).optional(),
128
- description: z.union([z.string(), z.null()]).optional(),
129
- price: z.number().optional(),
130
- gross_price: z.number().optional(),
131
- quantity: z.number().gte(-140737488355328).lte(140737488355327),
132
- unit: z.union([z.string(), z.null()]).optional(),
133
- taxes: z.array(DocumentItemTax).optional(),
134
- discounts: z.array(LineDiscount).max(5).optional(),
135
- delivery_note_id: z.union([z.string(), z.null()]).optional(),
136
- metadata: z
137
- .union([
138
- z.string(),
139
- z.number(),
140
- z.boolean(),
141
- z.null(),
142
- z.object({}).partial().passthrough(),
143
- z.array(z.unknown()),
144
- z.null(),
145
- ])
146
- .optional(),
147
- item_id: z.string().optional(),
148
- });
127
+ const CreateDocumentItem = z
128
+ .object({
129
+ type: z.literal("separator"),
130
+ name: z.string().min(1),
131
+ description: z.union([z.string(), z.null()]),
132
+ price: z.number(),
133
+ gross_price: z.number(),
134
+ quantity: z.union([z.number(), z.null()]),
135
+ unit: z.union([z.string(), z.null()]),
136
+ taxes: z.array(DocumentItemTax),
137
+ discounts: z.array(LineDiscount).max(5),
138
+ item_id: z.string(),
139
+ metadata: z.union([z.record(z.string(), z.any()), z.null()]),
140
+ save_item: z.boolean().default(true),
141
+ })
142
+ .partial();
149
143
 
150
144
 
151
145
  // Dependency schema for renderdeliverynotepreview_body
@@ -82,6 +82,7 @@ const PartialEstimatePreview = z.object({
82
82
  .array(
83
83
  z
84
84
  .object({
85
+ type: z.literal("separator"),
85
86
  name: z.string(),
86
87
  quantity: z.number(),
87
88
  price: z.number(),
@@ -123,29 +124,22 @@ const LineDiscount = z.object({
123
124
 
124
125
 
125
126
  // Dependency schema for renderestimatepreview_body
126
- const CreateDocumentItem = z.object({
127
- name: z.string().min(1).optional(),
128
- description: z.union([z.string(), z.null()]).optional(),
129
- price: z.number().optional(),
130
- gross_price: z.number().optional(),
131
- quantity: z.number().gte(-140737488355328).lte(140737488355327),
132
- unit: z.union([z.string(), z.null()]).optional(),
133
- taxes: z.array(DocumentItemTax).optional(),
134
- discounts: z.array(LineDiscount).max(5).optional(),
135
- delivery_note_id: z.union([z.string(), z.null()]).optional(),
136
- metadata: z
137
- .union([
138
- z.string(),
139
- z.number(),
140
- z.boolean(),
141
- z.null(),
142
- z.object({}).partial().passthrough(),
143
- z.array(z.unknown()),
144
- z.null(),
145
- ])
146
- .optional(),
147
- item_id: z.string().optional(),
148
- });
127
+ const CreateDocumentItem = z
128
+ .object({
129
+ type: z.literal("separator"),
130
+ name: z.string().min(1),
131
+ description: z.union([z.string(), z.null()]),
132
+ price: z.number(),
133
+ gross_price: z.number(),
134
+ quantity: z.union([z.number(), z.null()]),
135
+ unit: z.union([z.string(), z.null()]),
136
+ taxes: z.array(DocumentItemTax),
137
+ discounts: z.array(LineDiscount).max(5),
138
+ item_id: z.string(),
139
+ metadata: z.union([z.record(z.string(), z.any()), z.null()]),
140
+ save_item: z.boolean().default(true),
141
+ })
142
+ .partial();
149
143
 
150
144
 
151
145
  // Dependency schema for renderestimatepreview_body
@@ -113,6 +113,7 @@ const PartialInvoicePreview = z.object({
113
113
  .array(
114
114
  z
115
115
  .object({
116
+ type: z.literal("separator"),
116
117
  name: z.string(),
117
118
  quantity: z.number(),
118
119
  price: z.number(),
@@ -132,6 +133,7 @@ const PartialInvoicePreview = z.object({
132
133
  .min(1),
133
134
  fina: CreateFinaInvoiceData.optional(),
134
135
  expected_total_with_tax: z.number().gt(0).optional(),
136
+ force_linked_documents: z.boolean().optional(),
135
137
  });
136
138
 
137
139
 
@@ -155,29 +157,22 @@ const LineDiscount = z.object({
155
157
 
156
158
 
157
159
  // Dependency schema for renderinvoicepreview_body
158
- const CreateDocumentItem = z.object({
159
- name: z.string().min(1).optional(),
160
- description: z.union([z.string(), z.null()]).optional(),
161
- price: z.number().optional(),
162
- gross_price: z.number().optional(),
163
- quantity: z.number().gte(-140737488355328).lte(140737488355327),
164
- unit: z.union([z.string(), z.null()]).optional(),
165
- taxes: z.array(DocumentItemTax).optional(),
166
- discounts: z.array(LineDiscount).max(5).optional(),
167
- delivery_note_id: z.union([z.string(), z.null()]).optional(),
168
- metadata: z
169
- .union([
170
- z.string(),
171
- z.number(),
172
- z.boolean(),
173
- z.null(),
174
- z.object({}).partial().passthrough(),
175
- z.array(z.unknown()),
176
- z.null(),
177
- ])
178
- .optional(),
179
- item_id: z.string().optional(),
180
- });
160
+ const CreateDocumentItem = z
161
+ .object({
162
+ type: z.literal("separator"),
163
+ name: z.string().min(1),
164
+ description: z.union([z.string(), z.null()]),
165
+ price: z.number(),
166
+ gross_price: z.number(),
167
+ quantity: z.union([z.number(), z.null()]),
168
+ unit: z.union([z.string(), z.null()]),
169
+ taxes: z.array(DocumentItemTax),
170
+ discounts: z.array(LineDiscount).max(5),
171
+ item_id: z.string(),
172
+ metadata: z.union([z.record(z.string(), z.any()), z.null()]),
173
+ save_item: z.boolean().default(true),
174
+ })
175
+ .partial();
181
176
 
182
177
 
183
178
  // Dependency schema for renderinvoicepreview_body
@@ -201,6 +196,7 @@ const CompleteInvoicePreview = z.object({
201
196
  items: z.array(CreateDocumentItem).min(1),
202
197
  fina: CreateFinaInvoiceData.optional(),
203
198
  expected_total_with_tax: z.number().gt(0).optional(),
199
+ force_linked_documents: z.boolean().optional(),
204
200
  });
205
201
 
206
202
 
@@ -64,6 +64,7 @@ function transformDocumentForDuplication(source: Document, targetType: DocumentT
64
64
  // Transform items - copy only the fields needed for creation
65
65
  // Use type assertion for items since all document item types share the same shape
66
66
  const sourceItems = source.items as Array<{
67
+ type?: string | null;
67
68
  name: string;
68
69
  description: string | null;
69
70
  quantity: number;
@@ -72,15 +73,21 @@ function transformDocumentForDuplication(source: Document, targetType: DocumentT
72
73
  taxes: Array<{ tax_id?: string }>;
73
74
  }>;
74
75
  const items = sourceItems?.map((item) => ({
76
+ type: item.type ?? undefined,
75
77
  name: item.name,
76
78
  description: item.description,
77
- quantity: item.quantity,
78
- // Use gross_price if set, otherwise use price. The form uses is_gross_price as a UI toggle.
79
- price: item.gross_price ?? item.price,
80
- // Copy tax references (tax_id), not computed tax data
81
- taxes: item.taxes?.map((tax) => ({ tax_id: tax.tax_id })),
82
- // Derive is_gross_price from whether gross_price is set
83
- gross_price: item.gross_price ?? undefined,
79
+ // Separator items skip financial fields
80
+ ...(item.type !== "separator"
81
+ ? {
82
+ quantity: item.quantity,
83
+ // Use gross_price if set, otherwise use price. The form uses is_gross_price as a UI toggle.
84
+ price: item.gross_price ?? item.price,
85
+ // Copy tax references (tax_id), not computed tax data
86
+ taxes: item.taxes?.map((tax) => ({ tax_id: tax.tax_id })),
87
+ // Derive is_gross_price from whether gross_price is set
88
+ gross_price: item.gross_price ?? undefined,
89
+ }
90
+ : {}),
84
91
  }));
85
92
 
86
93
  // Build customer data - always copy if available (form needs this for display)
@@ -108,8 +115,8 @@ function transformDocumentForDuplication(source: Document, targetType: DocumentT
108
115
  // The form needs customer data for display, even when customer_id is set
109
116
  ...(source.customer_id ? { customer_id: source.customer_id } : {}),
110
117
  ...(customerData ? { customer: customerData } : {}),
111
- // Items
112
- items,
118
+ // Items (cast needed: separator items omit financial fields like quantity)
119
+ items: items as any,
113
120
  // Currency
114
121
  currency_code: source.currency_code,
115
122
  // Notes
@@ -42,6 +42,8 @@ export interface UseViesCheckResult {
42
42
  reverseChargeApplies: boolean;
43
43
  /** Transaction type determined by VIES check */
44
44
  transactionType: ViesCheckResponse["transaction_type"] | undefined;
45
+ /** Customer country code returned by VIES check */
46
+ customerCountryCode: string | null;
45
47
  /** Warning message from VIES validation */
46
48
  warning: string | null;
47
49
  /** Whether VIES validation was successful */
@@ -124,6 +126,7 @@ export function useViesCheck({
124
126
  error: query.error,
125
127
  reverseChargeApplies: query.data?.reverse_charge_applies ?? false,
126
128
  transactionType: query.data?.transaction_type,
129
+ customerCountryCode: query.data?.customer_country_code ?? null,
127
130
  warning: query.data?.warning ?? null,
128
131
  viesValid: query.data?.vies_valid ?? null,
129
132
  };