@spaceinvoices/react-ui 0.4.12 → 0.4.31

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 (334) hide show
  1. package/cli/dist/index.js +1 -1
  2. package/package.json +1 -1
  3. package/src/common/autocomplete.tsx +7 -1
  4. package/src/components/advance-invoices/advance-invoices.hooks.ts +35 -44
  5. package/src/components/advance-invoices/create/create-advance-invoice-form.tsx +189 -73
  6. package/src/components/advance-invoices/create/locales/bg.ts +17 -9
  7. package/src/components/advance-invoices/create/locales/cs.ts +17 -9
  8. package/src/components/advance-invoices/create/locales/de.ts +15 -7
  9. package/src/components/advance-invoices/create/locales/en.ts +15 -7
  10. package/src/components/advance-invoices/create/locales/es.ts +15 -7
  11. package/src/components/advance-invoices/create/locales/et.ts +17 -9
  12. package/src/components/advance-invoices/create/locales/fi.ts +18 -10
  13. package/src/components/advance-invoices/create/locales/fr.ts +16 -8
  14. package/src/components/advance-invoices/create/locales/hr.ts +15 -7
  15. package/src/components/advance-invoices/create/locales/is.ts +17 -9
  16. package/src/components/advance-invoices/create/locales/it.ts +15 -7
  17. package/src/components/advance-invoices/create/locales/nb.ts +17 -9
  18. package/src/components/advance-invoices/create/locales/nl.ts +15 -7
  19. package/src/components/advance-invoices/create/locales/pl.ts +17 -9
  20. package/src/components/advance-invoices/create/locales/pt.ts +16 -8
  21. package/src/components/advance-invoices/create/locales/sk.ts +17 -9
  22. package/src/components/advance-invoices/create/locales/sl.ts +14 -5
  23. package/src/components/advance-invoices/create/locales/sv.ts +17 -9
  24. package/src/components/advance-invoices/create/prepare-advance-invoice-submission.ts +47 -1
  25. package/src/components/advance-invoices/list/list-table.tsx +2 -1
  26. package/src/components/credit-notes/create/create-credit-note-form.tsx +253 -85
  27. package/src/components/credit-notes/create/locales/bg.ts +22 -8
  28. package/src/components/credit-notes/create/locales/cs.ts +22 -8
  29. package/src/components/credit-notes/create/locales/de.ts +20 -7
  30. package/src/components/credit-notes/create/locales/en.ts +19 -5
  31. package/src/components/credit-notes/create/locales/es.ts +20 -7
  32. package/src/components/credit-notes/create/locales/et.ts +22 -8
  33. package/src/components/credit-notes/create/locales/fi.ts +23 -9
  34. package/src/components/credit-notes/create/locales/fr.ts +21 -8
  35. package/src/components/credit-notes/create/locales/hr.ts +20 -7
  36. package/src/components/credit-notes/create/locales/is.ts +22 -8
  37. package/src/components/credit-notes/create/locales/it.ts +20 -7
  38. package/src/components/credit-notes/create/locales/nb.ts +22 -8
  39. package/src/components/credit-notes/create/locales/nl.ts +20 -7
  40. package/src/components/credit-notes/create/locales/pl.ts +22 -9
  41. package/src/components/credit-notes/create/locales/pt.ts +21 -8
  42. package/src/components/credit-notes/create/locales/sk.ts +22 -8
  43. package/src/components/credit-notes/create/locales/sl.ts +19 -5
  44. package/src/components/credit-notes/create/locales/sv.ts +22 -8
  45. package/src/components/credit-notes/create/prepare-credit-note-submission.ts +35 -1
  46. package/src/components/credit-notes/credit-notes.hooks.ts +21 -2
  47. package/src/components/credit-notes/list/list-table.tsx +2 -1
  48. package/src/components/delivery-notes/create/create-delivery-note-form.tsx +132 -30
  49. package/src/components/delivery-notes/create/locales/bg.ts +1 -0
  50. package/src/components/delivery-notes/create/locales/cs.ts +1 -0
  51. package/src/components/delivery-notes/create/locales/de.ts +1 -0
  52. package/src/components/delivery-notes/create/locales/en.ts +1 -0
  53. package/src/components/delivery-notes/create/locales/es.ts +1 -0
  54. package/src/components/delivery-notes/create/locales/et.ts +1 -0
  55. package/src/components/delivery-notes/create/locales/fi.ts +1 -0
  56. package/src/components/delivery-notes/create/locales/fr.ts +1 -0
  57. package/src/components/delivery-notes/create/locales/hr.ts +1 -0
  58. package/src/components/delivery-notes/create/locales/is.ts +1 -0
  59. package/src/components/delivery-notes/create/locales/it.ts +1 -0
  60. package/src/components/delivery-notes/create/locales/nb.ts +1 -0
  61. package/src/components/delivery-notes/create/locales/nl.ts +1 -0
  62. package/src/components/delivery-notes/create/locales/pl.ts +1 -0
  63. package/src/components/delivery-notes/create/locales/pt.ts +1 -0
  64. package/src/components/delivery-notes/create/locales/sk.ts +1 -0
  65. package/src/components/delivery-notes/create/locales/sl.ts +1 -0
  66. package/src/components/delivery-notes/create/locales/sv.ts +1 -0
  67. package/src/components/delivery-notes/create/prepare-delivery-note-submission.ts +34 -1
  68. package/src/components/delivery-notes/delivery-notes.hooks.ts +15 -1
  69. package/src/components/delivery-notes/list/list-table.tsx +2 -1
  70. package/src/components/documents/create/custom-create-template.ts +114 -0
  71. package/src/components/documents/create/document-add-item-form.tsx +12 -8
  72. package/src/components/documents/create/document-add-item-tax-rate-field.tsx +1 -2
  73. package/src/components/documents/create/document-date-validation.ts +111 -0
  74. package/src/components/documents/create/document-details-section.tsx +93 -48
  75. package/src/components/documents/create/document-form-item.ts +67 -0
  76. package/src/components/documents/create/document-item-validation.ts +6 -2
  77. package/src/components/documents/create/form-types.ts +2 -2
  78. package/src/components/documents/create/linked-documents-info.tsx +2 -11
  79. package/src/components/documents/create/live-preview.tsx +3 -3
  80. package/src/components/documents/create/mark-as-paid-section.tsx +14 -11
  81. package/src/components/documents/create/payment-rows.ts +30 -0
  82. package/src/components/documents/create/prepare-document-submission.ts +143 -103
  83. package/src/components/documents/create/prepare-preview-data.ts +12 -0
  84. package/src/components/documents/create/preserved-expected-total.ts +90 -0
  85. package/src/components/documents/public/public-document-summary.tsx +6 -13
  86. package/src/components/documents/view/document-actions-bar.tsx +10 -1
  87. package/src/components/documents/view/document-details-card.tsx +4 -12
  88. package/src/components/documents/view/document-relations-list.tsx +4 -4
  89. package/src/components/documents/view/locales/bg.ts +8 -8
  90. package/src/components/documents/view/locales/cs.ts +8 -8
  91. package/src/components/documents/view/locales/de.ts +1 -1
  92. package/src/components/documents/view/locales/en.ts +14 -14
  93. package/src/components/documents/view/locales/es.ts +1 -1
  94. package/src/components/documents/view/locales/et.ts +8 -8
  95. package/src/components/documents/view/locales/fi.ts +10 -10
  96. package/src/components/documents/view/locales/fr.ts +1 -1
  97. package/src/components/documents/view/locales/hr.ts +6 -6
  98. package/src/components/documents/view/locales/is.ts +8 -8
  99. package/src/components/documents/view/locales/it.ts +1 -1
  100. package/src/components/documents/view/locales/nb.ts +8 -8
  101. package/src/components/documents/view/locales/nl.ts +1 -1
  102. package/src/components/documents/view/locales/pl.ts +1 -1
  103. package/src/components/documents/view/locales/pt.ts +1 -1
  104. package/src/components/documents/view/locales/sk.ts +8 -8
  105. package/src/components/documents/view/locales/sl.ts +9 -9
  106. package/src/components/documents/view/locales/sv.ts +1 -1
  107. package/src/components/documents/view/use-document-download.ts +2 -2
  108. package/src/components/entities/entity-settings-form/locales/bg.ts +7 -0
  109. package/src/components/entities/entity-settings-form/locales/cs.ts +7 -0
  110. package/src/components/entities/entity-settings-form/locales/de.ts +9 -0
  111. package/src/components/entities/entity-settings-form/locales/en.ts +7 -0
  112. package/src/components/entities/entity-settings-form/locales/es.ts +7 -0
  113. package/src/components/entities/entity-settings-form/locales/et.ts +7 -0
  114. package/src/components/entities/entity-settings-form/locales/fi.ts +7 -0
  115. package/src/components/entities/entity-settings-form/locales/fr.ts +7 -0
  116. package/src/components/entities/entity-settings-form/locales/hr.ts +7 -0
  117. package/src/components/entities/entity-settings-form/locales/is.ts +7 -0
  118. package/src/components/entities/entity-settings-form/locales/it.ts +7 -0
  119. package/src/components/entities/entity-settings-form/locales/nb.ts +7 -0
  120. package/src/components/entities/entity-settings-form/locales/nl.ts +7 -0
  121. package/src/components/entities/entity-settings-form/locales/pl.ts +7 -0
  122. package/src/components/entities/entity-settings-form/locales/pt.ts +7 -0
  123. package/src/components/entities/entity-settings-form/locales/sk.ts +7 -0
  124. package/src/components/entities/entity-settings-form/locales/sl.ts +12 -4
  125. package/src/components/entities/entity-settings-form/locales/sv.ts +7 -0
  126. package/src/components/entities/settings/tax-rules-settings-form.tsx +36 -0
  127. package/src/components/estimates/create/create-estimate-form.tsx +195 -47
  128. package/src/components/estimates/create/locales/bg.ts +6 -5
  129. package/src/components/estimates/create/locales/cs.ts +6 -5
  130. package/src/components/estimates/create/locales/de.ts +4 -3
  131. package/src/components/estimates/create/locales/en.ts +4 -3
  132. package/src/components/estimates/create/locales/es.ts +4 -3
  133. package/src/components/estimates/create/locales/et.ts +6 -5
  134. package/src/components/estimates/create/locales/fi.ts +9 -8
  135. package/src/components/estimates/create/locales/fr.ts +4 -3
  136. package/src/components/estimates/create/locales/hr.ts +7 -6
  137. package/src/components/estimates/create/locales/is.ts +6 -5
  138. package/src/components/estimates/create/locales/it.ts +4 -3
  139. package/src/components/estimates/create/locales/nb.ts +6 -5
  140. package/src/components/estimates/create/locales/nl.ts +4 -3
  141. package/src/components/estimates/create/locales/pl.ts +4 -3
  142. package/src/components/estimates/create/locales/pt.ts +4 -3
  143. package/src/components/estimates/create/locales/sk.ts +6 -5
  144. package/src/components/estimates/create/locales/sl.ts +7 -6
  145. package/src/components/estimates/create/locales/sv.ts +6 -5
  146. package/src/components/estimates/create/prepare-estimate-submission.ts +37 -3
  147. package/src/components/estimates/estimates.hooks.ts +11 -2
  148. package/src/components/estimates/list/list-table.tsx +11 -1
  149. package/src/components/estimates/list/locales/bg.ts +2 -0
  150. package/src/components/estimates/list/locales/cs.ts +2 -0
  151. package/src/components/estimates/list/locales/de.ts +2 -0
  152. package/src/components/estimates/list/locales/en.ts +2 -0
  153. package/src/components/estimates/list/locales/es.ts +2 -0
  154. package/src/components/estimates/list/locales/et.ts +2 -0
  155. package/src/components/estimates/list/locales/fi.ts +2 -0
  156. package/src/components/estimates/list/locales/fr.ts +2 -0
  157. package/src/components/estimates/list/locales/hr.ts +7 -5
  158. package/src/components/estimates/list/locales/is.ts +2 -0
  159. package/src/components/estimates/list/locales/it.ts +2 -0
  160. package/src/components/estimates/list/locales/nb.ts +2 -0
  161. package/src/components/estimates/list/locales/nl.ts +2 -0
  162. package/src/components/estimates/list/locales/pl.ts +2 -0
  163. package/src/components/estimates/list/locales/pt.ts +2 -0
  164. package/src/components/estimates/list/locales/sk.ts +2 -0
  165. package/src/components/estimates/list/locales/sl.ts +9 -7
  166. package/src/components/estimates/list/locales/sv.ts +2 -0
  167. package/src/components/invoices/create/create-invoice-form.tsx +230 -60
  168. package/src/components/invoices/create/locales/bg.ts +23 -14
  169. package/src/components/invoices/create/locales/cs.ts +23 -14
  170. package/src/components/invoices/create/locales/de.ts +17 -9
  171. package/src/components/invoices/create/locales/en.ts +16 -7
  172. package/src/components/invoices/create/locales/es.ts +18 -9
  173. package/src/components/invoices/create/locales/et.ts +23 -14
  174. package/src/components/invoices/create/locales/fi.ts +24 -15
  175. package/src/components/invoices/create/locales/fr.ts +19 -11
  176. package/src/components/invoices/create/locales/hr.ts +18 -9
  177. package/src/components/invoices/create/locales/is.ts +23 -14
  178. package/src/components/invoices/create/locales/it.ts +19 -11
  179. package/src/components/invoices/create/locales/nb.ts +23 -14
  180. package/src/components/invoices/create/locales/nl.ts +19 -10
  181. package/src/components/invoices/create/locales/pl.ts +19 -11
  182. package/src/components/invoices/create/locales/pt.ts +19 -10
  183. package/src/components/invoices/create/locales/sk.ts +23 -14
  184. package/src/components/invoices/create/locales/sl.ts +17 -9
  185. package/src/components/invoices/create/locales/sv.ts +17 -8
  186. package/src/components/invoices/create/prepare-invoice-submission.ts +55 -1
  187. package/src/components/invoices/invoices.hooks.ts +11 -2
  188. package/src/components/invoices/list/list-table.tsx +2 -1
  189. package/src/components/invoices/send-email-dialog/locales/bg.ts +5 -0
  190. package/src/components/invoices/send-email-dialog/locales/cs.ts +5 -0
  191. package/src/components/invoices/send-email-dialog/locales/de.ts +5 -0
  192. package/src/components/invoices/send-email-dialog/locales/en.ts +5 -0
  193. package/src/components/invoices/send-email-dialog/locales/es.ts +5 -0
  194. package/src/components/invoices/send-email-dialog/locales/et.ts +5 -0
  195. package/src/components/invoices/send-email-dialog/locales/fi.ts +5 -0
  196. package/src/components/invoices/send-email-dialog/locales/fr.ts +5 -0
  197. package/src/components/invoices/send-email-dialog/locales/hr.ts +8 -3
  198. package/src/components/invoices/send-email-dialog/locales/is.ts +5 -0
  199. package/src/components/invoices/send-email-dialog/locales/it.ts +5 -0
  200. package/src/components/invoices/send-email-dialog/locales/nb.ts +5 -0
  201. package/src/components/invoices/send-email-dialog/locales/nl.ts +5 -0
  202. package/src/components/invoices/send-email-dialog/locales/pl.ts +5 -0
  203. package/src/components/invoices/send-email-dialog/locales/pt.ts +5 -0
  204. package/src/components/invoices/send-email-dialog/locales/sk.ts +5 -0
  205. package/src/components/invoices/send-email-dialog/locales/sl.ts +8 -3
  206. package/src/components/invoices/send-email-dialog/locales/sv.ts +5 -0
  207. package/src/components/invoices/send-email-dialog/send-email-dialog.tsx +2 -1
  208. package/src/components/items/item-combobox.tsx +4 -4
  209. package/src/components/payments/create-payment-form/create-payment-form.tsx +5 -2
  210. package/src/components/payments/edit-payment-form/edit-payment-form.tsx +5 -1
  211. package/src/components/recurring-invoices/create-recurring-invoice-form/create-recurring-invoice-form.tsx +98 -22
  212. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/bg.ts +26 -26
  213. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/cs.ts +25 -25
  214. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/et.ts +26 -26
  215. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/fi.ts +36 -36
  216. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/is.ts +26 -26
  217. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/nb.ts +26 -26
  218. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/sk.ts +25 -25
  219. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/sv.ts +26 -26
  220. package/src/components/recurring-invoices/list/list-row-actions.tsx +9 -1
  221. package/src/components/recurring-invoices/list/list-table.tsx +53 -5
  222. package/src/components/recurring-invoices/list/locales/bg.ts +4 -0
  223. package/src/components/recurring-invoices/list/locales/cs.ts +4 -0
  224. package/src/components/recurring-invoices/list/locales/de.ts +4 -0
  225. package/src/components/recurring-invoices/list/locales/en.ts +4 -0
  226. package/src/components/recurring-invoices/list/locales/es.ts +4 -0
  227. package/src/components/recurring-invoices/list/locales/et.ts +4 -0
  228. package/src/components/recurring-invoices/list/locales/fi.ts +4 -0
  229. package/src/components/recurring-invoices/list/locales/fr.ts +4 -0
  230. package/src/components/recurring-invoices/list/locales/hr.ts +4 -0
  231. package/src/components/recurring-invoices/list/locales/is.ts +4 -0
  232. package/src/components/recurring-invoices/list/locales/it.ts +4 -0
  233. package/src/components/recurring-invoices/list/locales/nb.ts +4 -0
  234. package/src/components/recurring-invoices/list/locales/nl.ts +4 -0
  235. package/src/components/recurring-invoices/list/locales/pl.ts +4 -0
  236. package/src/components/recurring-invoices/list/locales/pt.ts +4 -0
  237. package/src/components/recurring-invoices/list/locales/sk.ts +4 -0
  238. package/src/components/recurring-invoices/list/locales/sl.ts +4 -0
  239. package/src/components/recurring-invoices/list/locales/sv.ts +4 -0
  240. package/src/components/tax-reports/slovenia-tax-profile-step.tsx +4 -1
  241. package/src/components/tax-reports/slovenia-yearly-export-form.tsx +3 -0
  242. package/src/components/tax-reports/slovenia-yearly-review-step.tsx +2 -1
  243. package/src/components/ui/form.tsx +5 -13
  244. package/src/components/ui/select.tsx +0 -1
  245. package/src/components/ui/sidebar.tsx +2 -2
  246. package/src/generate-schemas.ts +132 -99
  247. package/src/generated/schemas/acceptentityinvitation_body.ts +4 -3
  248. package/src/generated/schemas/accountwebhook.ts +4 -8
  249. package/src/generated/schemas/addentityuser_body.ts +4 -3
  250. package/src/generated/schemas/advanceinvoice.ts +167 -168
  251. package/src/generated/schemas/authorizeshopify_body.ts +4 -3
  252. package/src/generated/schemas/calculatedocumentpreview.ts +120 -0
  253. package/src/generated/schemas/checktransactiontype.ts +35 -0
  254. package/src/generated/schemas/creditnote.ts +203 -76
  255. package/src/generated/schemas/customadvanceinvoice.ts +172 -165
  256. package/src/generated/schemas/customcreditnote.ts +183 -155
  257. package/src/generated/schemas/customdeliverynote.ts +166 -0
  258. package/src/generated/schemas/customer.ts +4 -8
  259. package/src/generated/schemas/customestimate.ts +123 -97
  260. package/src/generated/schemas/customincomingpurchasedocument.ts +142 -0
  261. package/src/generated/schemas/custominvoice.ts +183 -154
  262. package/src/generated/schemas/deliverynote.ts +124 -79
  263. package/src/generated/schemas/einvoice.ts +19 -0
  264. package/src/generated/schemas/einvoicingsettings.ts +21 -0
  265. package/src/generated/schemas/einvoicingsupplier.ts +45 -0
  266. package/src/generated/schemas/entity.ts +44 -40
  267. package/src/generated/schemas/entityapikey.ts +1 -3
  268. package/src/generated/schemas/entityuserrole.ts +1 -3
  269. package/src/generated/schemas/estimate.ts +120 -127
  270. package/src/generated/schemas/exportsloveniavodxml_body.ts +4 -3
  271. package/src/generated/schemas/exportsloveniayearlynormiranireport_body.ts +4 -3
  272. package/src/generated/schemas/finadevice.ts +15 -0
  273. package/src/generated/schemas/finalizedocument.ts +52 -0
  274. package/src/generated/schemas/finapremise.ts +15 -0
  275. package/src/generated/schemas/finasettings.ts +1 -3
  276. package/src/generated/schemas/furselectronicdevice.ts +15 -0
  277. package/src/generated/schemas/furssettings.ts +1 -3
  278. package/src/generated/schemas/image.ts +15 -0
  279. package/src/generated/schemas/incomingpurchasedocument.ts +7 -27
  280. package/src/generated/schemas/incomingpurchasedocumentattachment.ts +15 -0
  281. package/src/generated/schemas/incomingpurchasedocumentpayment.ts +1 -3
  282. package/src/generated/schemas/index.ts +20 -5
  283. package/src/generated/schemas/invoice.ts +182 -183
  284. package/src/generated/schemas/item.ts +6 -10
  285. package/src/generated/schemas/legacymigrationauth.ts +18 -0
  286. package/src/generated/schemas/me.ts +2 -24
  287. package/src/generated/schemas/migrationjob.ts +20 -0
  288. package/src/generated/schemas/order.ts +4 -8
  289. package/src/generated/schemas/orderintegration.ts +4 -8
  290. package/src/generated/schemas/payment.ts +4 -8
  291. package/src/generated/schemas/ptatcudseries.ts +1 -3
  292. package/src/generated/schemas/queryentitystats.ts +15 -0
  293. package/src/generated/schemas/recurringinvoice.ts +4 -8
  294. package/src/generated/schemas/registerfursmovablepremise_body.ts +1 -3
  295. package/src/generated/schemas/registerfursrealestatepremise_body.ts +1 -3
  296. package/src/generated/schemas/renderadvanceinvoicepreview_body.ts +10 -16
  297. package/src/generated/schemas/rendercreditnotepreview_body.ts +10 -16
  298. package/src/generated/schemas/renderdeliverynotepreview_body.ts +9 -5
  299. package/src/generated/schemas/renderestimatepreview_body.ts +11 -7
  300. package/src/generated/schemas/renderinvoicepreview_body.ts +10 -16
  301. package/src/generated/schemas/reviewsloveniayearlynormiranireport.ts +15 -0
  302. package/src/generated/schemas/searcheinvoicingcustomer.ts +18 -0
  303. package/src/generated/schemas/senddocument_body.ts +1 -3
  304. package/src/generated/schemas/sendemail_body.ts +2 -24
  305. package/src/generated/schemas/sloveniataxprofile.ts +8 -10
  306. package/src/generated/schemas/starteslogexport_body.ts +4 -3
  307. package/src/generated/schemas/startpdfexport_body.ts +8 -87
  308. package/src/generated/schemas/stripeappconnect_body.ts +4 -3
  309. package/src/generated/schemas/stripeappcreateinvoice_body.ts +4 -6
  310. package/src/generated/schemas/stripeappmarketplaceauthorize.ts +15 -0
  311. package/src/generated/schemas/stripeappupdatesettings_body.ts +6 -6
  312. package/src/generated/schemas/supplier.ts +4 -8
  313. package/src/generated/schemas/syncshopifyorders_body.ts +4 -3
  314. package/src/generated/schemas/tax.ts +6 -8
  315. package/src/generated/schemas/uploadfile_body.ts +1 -3
  316. package/src/generated/schemas/uploadfurscertificate_body.ts +6 -6
  317. package/src/generated/schemas/userfinasettings.ts +1 -3
  318. package/src/generated/schemas/userfurssettings.ts +1 -3
  319. package/src/generated/schemas/userptsettings.ts +1 -3
  320. package/src/generated/schemas/voidinvoice_body.ts +8 -3
  321. package/src/generated/schemas/webhook.ts +4 -8
  322. package/src/generated/schemas/wlsubscriptionbillingemail.ts +17 -0
  323. package/src/hooks/use-duplicate-document.ts +61 -30
  324. package/src/lib/date-only.ts +58 -0
  325. package/src/lib/document-display.ts +18 -0
  326. package/src/lib/payment-display.ts +5 -3
  327. package/src/lib/schemas/shared.ts +11 -0
  328. package/src/providers/wl-subscription-provider.tsx +5 -0
  329. package/src/generated/schemas/account_webhook.ts +0 -43
  330. package/src/generated/schemas/previewadvanceinvoice_body.ts +0 -354
  331. package/src/generated/schemas/previewestimate_body.ts +0 -309
  332. package/src/generated/schemas/registerfinamovablepremise_body.ts +0 -26
  333. package/src/generated/schemas/registerfinarealestatepremise_body.ts +0 -37
  334. package/src/generated/schemas/renderdocument_body.ts +0 -594
@@ -190,6 +190,13 @@ export default {
190
190
  "tax-rules.require_gross_prices.label": "Exigir preços brutos",
191
191
  "tax-rules.require_gross_prices.description":
192
192
  "Exigir preços brutos quando a autoliquidação é aplicada. Previne variações inesperadas nos valores totais das faturas.",
193
+ "tax-rules.calculation_mode.label": "Calculation mode",
194
+ "tax-rules.calculation_mode.description": "Choose how discounts and VAT are ordered when document totals are calculated.",
195
+ "tax-rules.calculation_mode.b2b_standard.label": "B2B standard",
196
+ "tax-rules.calculation_mode.b2b_standard.description": "Discounts reduce the net line amount first, then VAT is calculated.",
197
+ "tax-rules.calculation_mode.b2c_gross_discount.label": "B2C gross discount",
198
+ "tax-rules.calculation_mode.b2c_gross_discount.description":
199
+ "Discounts reduce the final gross payable amount, then net and VAT are derived from that result.",
193
200
  // Tax clauses settings
194
201
  "Default Tax Clauses": "Cláusulas fiscais predefinidas",
195
202
  "Set default tax clauses that are automatically added to documents based on transaction type":
@@ -169,6 +169,13 @@ export default {
169
169
  "tax-rules.auto_remove_tax_export.description": "tax-rules.auto_remove_tax_export.description",
170
170
  "tax-rules.require_gross_prices.label": "tax-rules.require_gross_prices.label",
171
171
  "tax-rules.require_gross_prices.description": "tax-rules.require_gross_prices.description",
172
+ "tax-rules.calculation_mode.label": "Calculation mode",
173
+ "tax-rules.calculation_mode.description": "Choose how discounts and VAT are ordered when document totals are calculated.",
174
+ "tax-rules.calculation_mode.b2b_standard.label": "B2B standard",
175
+ "tax-rules.calculation_mode.b2b_standard.description": "Discounts reduce the net line amount first, then VAT is calculated.",
176
+ "tax-rules.calculation_mode.b2c_gross_discount.label": "B2C gross discount",
177
+ "tax-rules.calculation_mode.b2c_gross_discount.description":
178
+ "Discounts reduce the final gross payable amount, then net and VAT are derived from that result.",
172
179
  "Default Tax Clauses": "Default Tax Clauses",
173
180
  "Set default tax clauses that are automatically added to documents based on transaction type":
174
181
  "Set default tax clauses that are automatically added to documents based on transaction type",
@@ -64,19 +64,19 @@ export default {
64
64
  "This note will be pre-filled when creating new invoices":
65
65
  "Ta pripis bo vnaprej izpolnjen pri ustvarjanju novih računov",
66
66
  "This note will be pre-filled when creating new estimates":
67
- "Ta pripis bo vnaprej izpolnjen pri ustvarjanju novih predračunov",
67
+ "Ta pripis bo vnaprej izpolnjen pri ustvarjanju novih ponudb",
68
68
  "This note will be pre-filled when creating new credit notes":
69
69
  "Ta pripis bo vnaprej izpolnjen pri ustvarjanju novih dobropisov",
70
70
  "Payment terms pre-filled when creating new invoices":
71
71
  "Plačilni pogoji bodo vnaprej izpolnjeni pri ustvarjanju novih računov",
72
72
  "Payment terms pre-filled when creating new estimates":
73
- "Plačilni pogoji bodo vnaprej izpolnjeni pri ustvarjanju novih predračunov",
73
+ "Plačilni pogoji bodo vnaprej izpolnjeni pri ustvarjanju novih ponudb",
74
74
  "Payment terms pre-filled when creating new credit notes":
75
75
  "Plačilni pogoji bodo vnaprej izpolnjeni pri ustvarjanju novih dobropisov",
76
76
  "Optional note for the document.": "Neobvezna opomba za dokument.",
77
77
  "Please remit payment using the bank details shown on the document.":
78
78
  "Plačilo izvedite po bančnih podatkih, navedenih na dokumentu.",
79
- "This estimate is valid until {document_valid_until}.": "Ta predračun velja do {document_valid_until}.",
79
+ "This estimate is valid until {document_valid_until}.": "Ta ponudba velja do {document_valid_until}.",
80
80
  "Payment due upon acceptance.": "Plačilo ob sprejemu.",
81
81
  "Credit note for invoice {document_number}.": "Dobropis za račun {document_number}.",
82
82
  "Credit will be applied to your account.": "Dobropis bo upoštevan na vašem računu.",
@@ -167,7 +167,7 @@ export default {
167
167
  "UPN QR je slovenski standard za plačilne naloge. Ko je omogočen, bodo vaši računi vključevali QR kodo, ki jo stranke lahko skenirajo z mobilno bančno aplikacijo za takojšnje plačilo.",
168
168
  // Number format settings
169
169
  Invoice: "Račun",
170
- Estimate: "Predračun",
170
+ Estimate: "Ponudba",
171
171
  "Credit Note": "Dobropis",
172
172
  "Advance Invoice": "Avansni račun",
173
173
  "Number Format": "Format številke",
@@ -186,6 +186,14 @@ export default {
186
186
  "tax-rules.require_gross_prices.label": "Zahtevaj bruto cene",
187
187
  "tax-rules.require_gross_prices.description":
188
188
  "Zahtevaj bruto cene, ko se uporabi obrnjena davčna obveznost. Prepreči nepričakovane spremembe skupnih zneskov računov.",
189
+ "tax-rules.calculation_mode.label": "Način izračuna",
190
+ "tax-rules.calculation_mode.description": "Izberite vrstni red popustov in DDV pri izračunu zneskov dokumenta.",
191
+ "tax-rules.calculation_mode.b2b_standard.label": "Standard B2B",
192
+ "tax-rules.calculation_mode.b2b_standard.description":
193
+ "Popusti najprej zmanjšajo neto znesek postavke, nato se obračuna DDV.",
194
+ "tax-rules.calculation_mode.b2c_gross_discount.label": "B2C bruto popust",
195
+ "tax-rules.calculation_mode.b2c_gross_discount.description":
196
+ "Popusti zmanjšajo končni bruto znesek za plačilo, neto osnova in DDV pa se izračunata iz tega rezultata.",
189
197
  // Tax clauses settings
190
198
  "Default Tax Clauses": "Privzete davčne klavzule",
191
199
  "Set default tax clauses that are automatically added to documents based on transaction type":
@@ -175,6 +175,13 @@ export default {
175
175
  "tax-rules.auto_remove_tax_export.description": "tax-rules.auto_remove_tax_export.description",
176
176
  "tax-rules.require_gross_prices.label": "tax-rules.require_gross_prices.label",
177
177
  "tax-rules.require_gross_prices.description": "tax-rules.require_gross_prices.description",
178
+ "tax-rules.calculation_mode.label": "Calculation mode",
179
+ "tax-rules.calculation_mode.description": "Choose how discounts and VAT are ordered when document totals are calculated.",
180
+ "tax-rules.calculation_mode.b2b_standard.label": "B2B standard",
181
+ "tax-rules.calculation_mode.b2b_standard.description": "Discounts reduce the net line amount first, then VAT is calculated.",
182
+ "tax-rules.calculation_mode.b2c_gross_discount.label": "B2C gross discount",
183
+ "tax-rules.calculation_mode.b2c_gross_discount.description":
184
+ "Discounts reduce the final gross payable amount, then net and VAT are derived from that result.",
178
185
  "Default Tax Clauses": "Standardskatteklausuler",
179
186
  "Set default tax clauses that are automatically added to documents based on transaction type":
180
187
  "Ange standardskatteklausuler som automatiskt läggs till i dokument utifrån transaktionstyp",
@@ -17,6 +17,7 @@ import {
17
17
  } from "@/ui/components/ui/form";
18
18
  import { Switch } from "@/ui/components/ui/switch";
19
19
  import { Textarea } from "@/ui/components/ui/textarea";
20
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/ui/components/ui/select";
20
21
  import type { ComponentTranslationProps } from "@/ui/lib/translation";
21
22
  import { createTranslation } from "@/ui/lib/translation";
22
23
  import { cn } from "@/ui/lib/utils";
@@ -28,6 +29,7 @@ import sl from "../entity-settings-form/locales/sl";
28
29
  const translations = { sl, de } as const;
29
30
 
30
31
  const taxRulesSettingsSchema = z.object({
32
+ calculation_mode: z.enum(["b2b_standard", "b2c_gross_discount"]),
31
33
  vies_validate_vat: z.boolean(),
32
34
  auto_reverse_charge: z.boolean(),
33
35
  auto_remove_tax_export: z.boolean(),
@@ -83,6 +85,7 @@ export function TaxRulesSettingsForm({
83
85
 
84
86
  const defaultValues = useMemo(
85
87
  (): TaxRulesSettingsSchema => ({
88
+ calculation_mode: currentSettings.calculation?.default_mode ?? "b2b_standard",
86
89
  vies_validate_vat: currentTaxRules.vies_validate_vat ?? true,
87
90
  auto_reverse_charge: currentTaxRules.auto_reverse_charge ?? false,
88
91
  auto_remove_tax_export: currentTaxRules.auto_remove_tax_export ?? false,
@@ -129,6 +132,10 @@ export function TaxRulesSettingsForm({
129
132
  const onSubmit = (values: TaxRulesSettingsSchema) => {
130
133
  const updatedSettings: EntitySettings = {
131
134
  ...currentSettings,
135
+ calculation: {
136
+ ...currentSettings.calculation,
137
+ default_mode: values.calculation_mode,
138
+ },
132
139
  tax_rules: {
133
140
  eu: {
134
141
  vies_validate_vat: values.vies_validate_vat,
@@ -165,6 +172,35 @@ export function TaxRulesSettingsForm({
165
172
  // Tax rules section content (switches)
166
173
  const taxRulesContent = (
167
174
  <div className="space-y-4">
175
+ <FormField
176
+ control={form.control}
177
+ name="calculation_mode"
178
+ render={({ field }) => (
179
+ <FormItem className="rounded-lg border p-4">
180
+ <FormLabel className="text-base">{t("tax-rules.calculation_mode.label")}</FormLabel>
181
+ <FormDescription>{t("tax-rules.calculation_mode.description")}</FormDescription>
182
+ <FormControl>
183
+ <Select value={field.value} onValueChange={field.onChange}>
184
+ <SelectTrigger className="mt-3">
185
+ <SelectValue />
186
+ </SelectTrigger>
187
+ <SelectContent>
188
+ <SelectItem value="b2b_standard">{t("tax-rules.calculation_mode.b2b_standard.label")}</SelectItem>
189
+ <SelectItem value="b2c_gross_discount">
190
+ {t("tax-rules.calculation_mode.b2c_gross_discount.label")}
191
+ </SelectItem>
192
+ </SelectContent>
193
+ </Select>
194
+ </FormControl>
195
+ <div className="mt-3 space-y-1 text-muted-foreground text-sm">
196
+ <p>{t("tax-rules.calculation_mode.b2b_standard.description")}</p>
197
+ <p>{t("tax-rules.calculation_mode.b2c_gross_discount.description")}</p>
198
+ </div>
199
+ <FormMessage />
200
+ </FormItem>
201
+ )}
202
+ />
203
+
168
204
  <FormField
169
205
  control={form.control}
170
206
  name="vies_validate_vat"
@@ -1,7 +1,7 @@
1
1
  import { zodResolver } from "@hookform/resolvers/zod";
2
- import type { CreateEstimateRequest, Estimate } from "@spaceinvoices/js-sdk";
2
+ import type { CreateEstimateRequest, Estimate, UpdateEstimate } from "@spaceinvoices/js-sdk";
3
3
  import { useQueryClient } from "@tanstack/react-query";
4
- import { RefreshCw } from "lucide-react";
4
+ import { ArrowUpDown } from "lucide-react";
5
5
  import type { ReactNode } from "react";
6
6
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
7
7
  import type { Resolver } from "react-hook-form";
@@ -17,11 +17,13 @@ import {
17
17
  type PtDocumentInputForm,
18
18
  ptDocumentInputFormSchema,
19
19
  } from "@/ui/lib/pt-document-input";
20
+ import { normalizeLineItemDiscountsForForm } from "@/ui/lib/schemas/shared";
20
21
  import type { ComponentTranslationProps } from "@/ui/lib/translation";
21
22
  import { createTranslation } from "@/ui/lib/translation";
22
23
  import { useEntities } from "@/ui/providers/entities-context";
23
24
  import { useFormFooterRegistration } from "@/ui/providers/form-footer-context";
24
25
  import { CUSTOMERS_CACHE_KEY } from "../../customers/customers.hooks";
26
+ import { withEstimateIssueDateValidation } from "../../documents/create/document-date-validation";
25
27
  import {
26
28
  DocumentDetailsSection,
27
29
  DocumentFooterField,
@@ -33,8 +35,11 @@ import {
33
35
  import { withRequiredDocumentItemFields } from "../../documents/create/document-item-validation";
34
36
  import { DocumentItemsSection, type PriceModesMap } from "../../documents/create/document-items-section";
35
37
  import { DocumentRecipientSection } from "../../documents/create/document-recipient-section";
38
+ import { prepareDocumentItems } from "../../documents/create/prepare-document-submission";
39
+ import { applyCustomCreateTemplate } from "../../documents/create/custom-create-template";
40
+ import { financialInputsMatchInitial, resolvePreservedExpectedTotal } from "../../documents/create/preserved-expected-total";
36
41
  import type { DocumentTypes } from "../../documents/types";
37
- import { useCreateEstimate } from "../estimates.hooks";
42
+ import { useCreateCustomEstimate, useCreateEstimate, useUpdateEstimate } from "../estimates.hooks";
38
43
  import de from "./locales/de";
39
44
  import es from "./locales/es";
40
45
  import fr from "./locales/fr";
@@ -44,7 +49,7 @@ import nl from "./locales/nl";
44
49
  import pl from "./locales/pl";
45
50
  import pt from "./locales/pt";
46
51
  import sl from "./locales/sl";
47
- import { prepareEstimateSubmission } from "./prepare-estimate-submission";
52
+ import { prepareEstimateSubmission, prepareEstimateUpdateSubmission } from "./prepare-estimate-submission";
48
53
  import { useEstimateCustomerForm } from "./use-estimate-customer-form";
49
54
 
50
55
  function calculateDueDate(dateIso: string, days: number): string {
@@ -64,10 +69,12 @@ const translations = {
64
69
  pl,
65
70
  hr,
66
71
  } as const;
67
- const createEstimateFormSchema = withRequiredDocumentItemFields(
68
- createEstimateSchema.extend({
69
- pt: ptDocumentInputFormSchema.optional(),
70
- }),
72
+ const createEstimateFormSchema = withEstimateIssueDateValidation(
73
+ withRequiredDocumentItemFields(
74
+ createEstimateSchema.extend({
75
+ pt: ptDocumentInputFormSchema.optional(),
76
+ }),
77
+ ),
71
78
  );
72
79
 
73
80
  // Form values: extend schema with local-only fields (number is for display, not sent to API)
@@ -88,7 +95,12 @@ type CreateEstimateFormProps = {
88
95
  /** Callback to update header action (title toggle) */
89
96
  onHeaderActionChange?: (action: ReactNode) => void;
90
97
  /** Initial values for form fields (used for document duplication) */
91
- initialValues?: Partial<CreateEstimateRequest>;
98
+ initialValues?: Partial<CreateEstimateRequest> & {
99
+ number?: string;
100
+ title_type?: "estimate" | "proforma_invoice" | null;
101
+ };
102
+ mode?: "create" | "edit";
103
+ documentId?: string;
92
104
  /** Whether draft actions should be available in the UI */
93
105
  allowDrafts?: boolean;
94
106
  /** Optional app-level content rendered inside the details section. */
@@ -105,6 +117,8 @@ export default function CreateEstimateForm({
105
117
  onAddNewTax,
106
118
  onHeaderActionChange,
107
119
  initialValues,
120
+ mode = "create",
121
+ documentId,
108
122
  allowDrafts = true,
109
123
  detailsExtras,
110
124
  translationLocale,
@@ -122,9 +136,12 @@ export default function CreateEstimateForm({
122
136
 
123
137
  const { activeEntity } = useEntities();
124
138
  const queryClient = useQueryClient();
139
+ const isEditMode = mode === "edit";
125
140
 
126
- // Title type state: "estimate" (default) or "quote"
127
- const [titleType, setTitleType] = useState<"estimate" | "quote">((initialValues as any)?.title_type || "estimate");
141
+ // Title type state: "estimate" (default) or "proforma_invoice"
142
+ const [titleType, setTitleType] = useState<"estimate" | "proforma_invoice">(
143
+ (initialValues as any)?.title_type || "estimate",
144
+ );
128
145
 
129
146
  // Draft submission state
130
147
  const [isDraftPending, setIsDraftPending] = useState(false);
@@ -135,7 +152,7 @@ export default function CreateEstimateForm({
135
152
 
136
153
  // Fetch next estimate number
137
154
  const { data: nextNumberData } = useNextDocumentNumber(entityId, "estimate", {
138
- enabled: !!entityId,
155
+ enabled: !!entityId && !isEditMode,
139
156
  });
140
157
 
141
158
  // Get default payment terms and footer from entity settings
@@ -145,22 +162,28 @@ export default function CreateEstimateForm({
145
162
  const form = useForm<CreateEstimateFormValues>({
146
163
  resolver: zodResolver(createEstimateFormSchema) as Resolver<CreateEstimateFormValues>,
147
164
  defaultValues: {
148
- number: "",
165
+ number: initialValues?.number ?? "",
166
+ calculation_mode: (initialValues as any)?.calculation_mode ?? undefined,
149
167
  date: initialValues?.date || new Date().toISOString(),
150
168
  customer_id: initialValues?.customer_id ?? undefined,
151
169
  // Cast customer to form schema type (API type may have additional fields)
152
170
  customer: (initialValues?.customer as CreateEstimateFormValues["customer"]) ?? undefined,
153
171
  items: initialValues?.items?.length
154
172
  ? initialValues.items.map((item: any) => ({
155
- type: item.type,
173
+ type: item.type ?? undefined,
156
174
  name: item.name || "",
157
175
  description: item.description || "",
158
176
  ...(item.type !== "separator"
159
177
  ? {
178
+ item_id: item.item_id ?? undefined,
179
+ classification: item.classification ?? undefined,
180
+ unit: item.unit ?? undefined,
160
181
  quantity: item.quantity ?? 1,
161
182
  // Use gross_price if set, otherwise use price
162
183
  price: item.gross_price ?? item.price,
184
+ gross_price: item.gross_price ?? undefined,
163
185
  taxes: item.taxes || [],
186
+ discounts: normalizeLineItemDiscountsForForm(item.discounts),
164
187
  }
165
188
  : {}),
166
189
  }))
@@ -175,13 +198,16 @@ export default function CreateEstimateForm({
175
198
  ],
176
199
  currency_code: initialValues?.currency_code || activeEntity?.currency_code || "EUR",
177
200
  reference: (initialValues as any)?.reference ?? "",
178
- note: initialValues?.note ?? defaultEstimateNote,
201
+ note: initialValues?.note ?? (isEditMode ? "" : defaultEstimateNote),
179
202
  tax_clause: (initialValues as any)?.tax_clause ?? "",
180
- payment_terms: initialValues?.payment_terms ?? defaultPaymentTerms,
181
- footer: (initialValues as any)?.footer ?? defaultFooter,
203
+ payment_terms: initialValues?.payment_terms ?? (isEditMode ? "" : defaultPaymentTerms),
204
+ signature: (initialValues as any)?.signature ?? "",
205
+ footer: (initialValues as any)?.footer ?? (isEditMode ? "" : defaultFooter),
182
206
  date_valid_till:
183
207
  initialValues?.date_valid_till ||
184
- calculateDueDate(initialValues?.date || new Date().toISOString(), defaultEstimateValidDays),
208
+ (isEditMode
209
+ ? undefined
210
+ : calculateDueDate(initialValues?.date || new Date().toISOString(), defaultEstimateValidDays)),
185
211
  pt: ((initialValues as any)?.pt as PtDocumentInputForm | undefined) ?? undefined,
186
212
  },
187
213
  });
@@ -189,6 +215,7 @@ export default function CreateEstimateForm({
189
215
  // Price modes per item (gross vs net) - collected from component state at submit
190
216
  const onHeaderActionChangeRef = useRef(onHeaderActionChange);
191
217
  onHeaderActionChangeRef.current = onHeaderActionChange;
218
+ const headerActionSignatureRef = useRef<string | null>(null);
192
219
 
193
220
  const onChangeRef = useRef(onChange);
194
221
  onChangeRef.current = onChange;
@@ -201,16 +228,48 @@ export default function CreateEstimateForm({
201
228
  }, {} as PriceModesMap);
202
229
  }, [initialValues?.items]);
203
230
  const priceModesRef = useRef<PriceModesMap>(initialPriceModes);
231
+ const customCreateTemplate = (initialValues as any)?._custom_create_template;
232
+ const financialInputsMatchSource = useCallback(
233
+ (values: { items?: any[]; currency_code?: string; calculation_mode?: string | null }) =>
234
+ financialInputsMatchInitial({
235
+ initialItems: initialValues?.items,
236
+ currentItems: values.items,
237
+ initialCurrencyCode: initialValues?.currency_code,
238
+ currentCurrencyCode: values.currency_code,
239
+ initialCalculationMode: (initialValues as any)?.calculation_mode ?? null,
240
+ currentCalculationMode: values.calculation_mode ?? null,
241
+ initialPriceModes,
242
+ currentPriceModes: priceModesRef.current,
243
+ }),
244
+ [initialPriceModes, initialValues],
245
+ );
246
+ const getPreservedExpectedTotalWithTax = useCallback(
247
+ (values: { items?: any[]; currency_code?: string; calculation_mode?: string | null }) =>
248
+ resolvePreservedExpectedTotal({
249
+ initialExpectedTotalWithTax: (initialValues as any)?._preserved_expected_total_with_tax,
250
+ initialItems: initialValues?.items,
251
+ currentItems: values.items,
252
+ initialCurrencyCode: initialValues?.currency_code,
253
+ currentCurrencyCode: values.currency_code,
254
+ initialCalculationMode: (initialValues as any)?.calculation_mode ?? null,
255
+ currentCalculationMode: values.calculation_mode ?? null,
256
+ initialPriceModes,
257
+ currentPriceModes: priceModesRef.current,
258
+ }),
259
+ [initialPriceModes, initialValues],
260
+ );
204
261
 
205
262
  // Update number when fetched
206
263
  useEffect(() => {
264
+ if (isEditMode) return;
207
265
  if (nextNumberData?.number) {
208
266
  form.setValue("number", nextNumberData.number);
209
267
  }
210
- }, [nextNumberData?.number, form]);
268
+ }, [form, isEditMode, nextNumberData?.number]);
211
269
 
212
270
  // Update default note and valid-till date when entity loads
213
271
  useEffect(() => {
272
+ if (isEditMode) return;
214
273
  const entityDefaultNote = (activeEntity?.settings as any)?.default_estimate_note;
215
274
  if (entityDefaultNote && !form.getValues("note")) {
216
275
  form.setValue("note", entityDefaultNote);
@@ -226,7 +285,7 @@ export default function CreateEstimateForm({
226
285
  form.setValue("date_valid_till", calculateDueDate(currentDate, validDays));
227
286
  }
228
287
  }
229
- }, [activeEntity, form, initialValues?.date_valid_till]);
288
+ }, [activeEntity, form, initialValues?.date_valid_till, isEditMode]);
230
289
 
231
290
  // Auto-add tax field for tax subject entities
232
291
  useEffect(() => {
@@ -241,12 +300,39 @@ export default function CreateEstimateForm({
241
300
  // Update header with clickable title toggle
242
301
  useEffect(() => {
243
302
  const callback = onHeaderActionChangeRef.current;
244
- if (!callback) return;
303
+ if (!callback) {
304
+ headerActionSignatureRef.current = null;
305
+ return;
306
+ }
245
307
 
246
308
  const toggleTitle = () => {
247
- setTitleType((prev) => (prev === "estimate" ? "quote" : "estimate"));
309
+ setTitleType((prev) => (prev === "estimate" ? "proforma_invoice" : "estimate"));
248
310
  };
249
311
 
312
+ const titleLabel = isEditMode
313
+ ? titleType === "estimate"
314
+ ? t("Estimate")
315
+ : t("Proforma invoice")
316
+ : titleType === "estimate"
317
+ ? t("Create Estimate")
318
+ : t("Create Proforma invoice");
319
+ const tooltipLabel = isEditMode
320
+ ? titleType === "estimate"
321
+ ? t("Click to switch to Proforma invoice")
322
+ : t("Click to switch to Estimate")
323
+ : titleType === "estimate"
324
+ ? t("Click to switch to Proforma invoice")
325
+ : t("Click to switch to Estimate");
326
+ const headerActionSignature = JSON.stringify({
327
+ titleLabel,
328
+ tooltipLabel,
329
+ isEditMode,
330
+ titleType,
331
+ });
332
+
333
+ if (headerActionSignatureRef.current === headerActionSignature) return;
334
+ headerActionSignatureRef.current = headerActionSignature;
335
+
250
336
  callback(
251
337
  <TooltipProvider>
252
338
  <Tooltip>
@@ -256,17 +342,24 @@ export default function CreateEstimateForm({
256
342
  onClick={toggleTitle}
257
343
  className="flex cursor-pointer items-center gap-2 font-bold text-2xl hover:text-primary"
258
344
  >
259
- {titleType === "estimate" ? t("Create Estimate") : t("Create Quote")}
260
- <RefreshCw className="size-4 text-muted-foreground" />
345
+ {titleLabel}
346
+ <ArrowUpDown className="size-4 text-muted-foreground" />
261
347
  </button>
262
348
  </TooltipTrigger>
263
- <TooltipContent side="bottom">
264
- {titleType === "estimate" ? t("Click to switch to Quote") : t("Click to switch to Estimate")}
265
- </TooltipContent>
349
+ <TooltipContent side="bottom">{tooltipLabel}</TooltipContent>
266
350
  </Tooltip>
267
351
  </TooltipProvider>,
268
352
  );
269
- }, [titleType, t]);
353
+ }, [isEditMode, t, titleType]);
354
+
355
+ useEffect(() => {
356
+ const callback = onHeaderActionChangeRef.current;
357
+ return () => {
358
+ if (!callback || headerActionSignatureRef.current === null) return;
359
+ headerActionSignatureRef.current = null;
360
+ callback(null);
361
+ };
362
+ }, []);
270
363
 
271
364
  const formValues = useWatch({
272
365
  control: form.control,
@@ -297,13 +390,14 @@ export default function CreateEstimateForm({
297
390
  useEffect(() => {
298
391
  if (effectiveTransactionType === prevTransactionTypeRef.current) return;
299
392
  prevTransactionTypeRef.current = effectiveTransactionType;
393
+ if (isEditMode) return;
300
394
 
301
395
  const taxClauseDefaults = (activeEntity?.settings as any)?.tax_clause_defaults;
302
396
  if (!taxClauseDefaults) return;
303
397
 
304
398
  const clause = taxClauseDefaults[effectiveTransactionType] ?? "";
305
399
  form.setValue("tax_clause", clause);
306
- }, [effectiveTransactionType, activeEntity, form]);
400
+ }, [effectiveTransactionType, activeEntity, form, isEditMode]);
307
401
 
308
402
  // Extract customer management logic into a custom hook
309
403
  const {
@@ -327,18 +421,59 @@ export default function CreateEstimateForm({
327
421
  },
328
422
  onError,
329
423
  });
424
+ const { mutate: createCustomEstimate, isPending: isCreateCustomPending } = useCreateCustomEstimate({
425
+ entityId,
426
+ onSuccess: (data) => {
427
+ if (data.customer_id) {
428
+ queryClient.invalidateQueries({ queryKey: [CUSTOMERS_CACHE_KEY] });
429
+ }
430
+ onSuccess?.(data);
431
+ },
432
+ onError,
433
+ });
434
+ const { mutate: updateEstimate, isPending: isUpdatePending } = useUpdateEstimate({
435
+ entityId,
436
+ onSuccess,
437
+ onError,
438
+ });
330
439
 
331
440
  // Shared submit logic for both regular save and save as draft
332
441
  const submitEstimate = useCallback(
333
442
  (values: CreateEstimateFormValues, isDraft: boolean) => {
334
443
  try {
444
+ if (isEditMode) {
445
+ if (!documentId) {
446
+ throw new Error("Estimate edit mode requires a documentId");
447
+ }
448
+
449
+ const submission = prepareEstimateUpdateSubmission(values as any, {
450
+ originalCustomer,
451
+ priceModes: priceModesRef.current,
452
+ titleType,
453
+ }) as UpdateEstimate;
454
+
455
+ updateEstimate({ id: documentId, data: submission });
456
+ return;
457
+ }
458
+
335
459
  const submission = prepareEstimateSubmission(values, {
336
460
  originalCustomer,
337
461
  priceModes: priceModesRef.current,
338
462
  titleType,
339
463
  isDraft,
340
464
  });
341
- createEstimate(submission);
465
+ const preservedExpectedTotalWithTax = getPreservedExpectedTotalWithTax(values);
466
+ if (preservedExpectedTotalWithTax !== undefined) {
467
+ (submission as any).expected_total_with_tax = preservedExpectedTotalWithTax;
468
+ } else {
469
+ delete (submission as any).expected_total_with_tax;
470
+ }
471
+ if (customCreateTemplate && financialInputsMatchSource(values)) {
472
+ delete (submission as any).expected_total_with_tax;
473
+ createCustomEstimate(applyCustomCreateTemplate(submission as any, customCreateTemplate));
474
+ } else {
475
+ createEstimate(submission);
476
+ }
342
477
  } catch (error) {
343
478
  console.error("Estimate submission error:", error);
344
479
  if (onError) {
@@ -346,7 +481,19 @@ export default function CreateEstimateForm({
346
481
  }
347
482
  }
348
483
  },
349
- [createEstimate, onError, originalCustomer, titleType],
484
+ [
485
+ createEstimate,
486
+ createCustomEstimate,
487
+ customCreateTemplate,
488
+ documentId,
489
+ financialInputsMatchSource,
490
+ getPreservedExpectedTotalWithTax,
491
+ isEditMode,
492
+ onError,
493
+ originalCustomer,
494
+ titleType,
495
+ updateEstimate,
496
+ ],
350
497
  );
351
498
 
352
499
  // Handle save as draft
@@ -365,26 +512,27 @@ export default function CreateEstimateForm({
365
512
 
366
513
  const secondaryAction = useMemo(
367
514
  () =>
368
- allowDrafts
515
+ allowDrafts && !isEditMode
369
516
  ? {
370
517
  label: t("Save as Draft"),
371
518
  onClick: handleSaveAsDraft,
372
519
  isPending: isDraftPending,
373
520
  }
374
521
  : undefined,
375
- [allowDrafts, t, handleSaveAsDraft, isDraftPending],
522
+ [allowDrafts, t, handleSaveAsDraft, isDraftPending, isEditMode],
376
523
  );
377
524
 
378
525
  useFormFooterRegistration({
379
526
  formId: "create-estimate-form",
380
- isPending,
527
+ isPending: isPending || isCreateCustomPending || isUpdatePending,
381
528
  isDirty: form.formState.isDirty || !!initialValues,
382
- label: titleType === "estimate" ? t("Create Estimate") : t("Create Quote"),
529
+ label: isEditMode ? t("Update") : titleType === "estimate" ? t("Create Estimate") : t("Create Proforma invoice"),
383
530
  secondaryAction,
384
531
  });
385
532
 
386
533
  // Set default payment terms and footer from entity settings when entity data is available
387
534
  useEffect(() => {
535
+ if (isEditMode) return;
388
536
  const entityDefaultPaymentTerms = (activeEntity?.settings as any)?.default_estimate_payment_terms;
389
537
  if (entityDefaultPaymentTerms && !form.getValues("payment_terms")) {
390
538
  form.setValue("payment_terms", entityDefaultPaymentTerms);
@@ -393,44 +541,44 @@ export default function CreateEstimateForm({
393
541
  if (entityDefaultFooter && !form.getValues("footer")) {
394
542
  form.setValue("footer", entityDefaultFooter);
395
543
  }
396
- }, [activeEntity, form]);
544
+ }, [activeEntity, form, isEditMode]);
397
545
 
398
546
  // Recalculate valid-till date when document date changes
399
547
  const prevDateRef = useRef(form.getValues("date"));
400
548
  useEffect(() => {
549
+ if (isEditMode) return;
401
550
  const currentDate = formValues.date;
402
551
  if (!currentDate || currentDate === prevDateRef.current) return;
403
552
  prevDateRef.current = currentDate;
404
553
  const validDays = (activeEntity?.settings as any)?.default_estimate_valid_days ?? 30;
405
554
  form.setValue("date_valid_till", calculateDueDate(currentDate, validDays));
406
- }, [formValues.date, activeEntity, form]);
555
+ }, [formValues.date, activeEntity, form, isEditMode]);
407
556
 
408
557
  const buildPreviewPayload = useCallback(
409
558
  (values: CreateEstimateFormValues): EstimatePreviewPayload => {
410
- const currentItems = values.items || [];
411
-
412
- const transformedItems = currentItems.map((item: any, index: number) => {
413
- const { price, ...rest } = item;
414
- const isGross = priceModesRef.current[index] ?? false;
415
- return isGross ? { ...rest, gross_price: price } : { ...rest, price };
416
- });
417
-
559
+ const preservedExpectedTotalWithTax = getPreservedExpectedTotalWithTax(values);
418
560
  return {
419
561
  number: values.number,
420
562
  date: values.date,
421
563
  customer_id: values.customer_id,
422
564
  customer: values.customer,
423
- items: transformedItems,
565
+ items: prepareDocumentItems(values.items, priceModesRef.current),
424
566
  currency_code: values.currency_code,
425
567
  reference: values.reference,
426
568
  note: values.note,
569
+ tax_clause: values.tax_clause,
427
570
  payment_terms: values.payment_terms,
428
571
  signature: values.signature,
572
+ footer: values.footer,
573
+ date_valid_till: values.date_valid_till,
429
574
  title_type: titleType,
575
+ ...(preservedExpectedTotalWithTax !== undefined
576
+ ? { expected_total_with_tax: preservedExpectedTotalWithTax }
577
+ : {}),
430
578
  ...(normalizePtDocumentInput(values.pt) ? { pt: normalizePtDocumentInput(values.pt) } : {}),
431
579
  };
432
580
  },
433
- [titleType],
581
+ [getPreservedExpectedTotalWithTax, titleType],
434
582
  );
435
583
 
436
584
  const emitPreviewPayload = useCallback((payload: EstimatePreviewPayload) => {