@spaceinvoices/react-ui 0.4.12 → 0.4.32

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 +190 -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 +254 -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 +133 -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 +151 -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 +196 -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 +231 -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 +74 -32
  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,29 @@ 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),
187
+ metadata: item.metadata ?? undefined,
164
188
  }
165
189
  : {}),
166
190
  }))
@@ -175,13 +199,16 @@ export default function CreateEstimateForm({
175
199
  ],
176
200
  currency_code: initialValues?.currency_code || activeEntity?.currency_code || "EUR",
177
201
  reference: (initialValues as any)?.reference ?? "",
178
- note: initialValues?.note ?? defaultEstimateNote,
202
+ note: initialValues?.note ?? (isEditMode ? "" : defaultEstimateNote),
179
203
  tax_clause: (initialValues as any)?.tax_clause ?? "",
180
- payment_terms: initialValues?.payment_terms ?? defaultPaymentTerms,
181
- footer: (initialValues as any)?.footer ?? defaultFooter,
204
+ payment_terms: initialValues?.payment_terms ?? (isEditMode ? "" : defaultPaymentTerms),
205
+ signature: (initialValues as any)?.signature ?? "",
206
+ footer: (initialValues as any)?.footer ?? (isEditMode ? "" : defaultFooter),
182
207
  date_valid_till:
183
208
  initialValues?.date_valid_till ||
184
- calculateDueDate(initialValues?.date || new Date().toISOString(), defaultEstimateValidDays),
209
+ (isEditMode
210
+ ? undefined
211
+ : calculateDueDate(initialValues?.date || new Date().toISOString(), defaultEstimateValidDays)),
185
212
  pt: ((initialValues as any)?.pt as PtDocumentInputForm | undefined) ?? undefined,
186
213
  },
187
214
  });
@@ -189,6 +216,7 @@ export default function CreateEstimateForm({
189
216
  // Price modes per item (gross vs net) - collected from component state at submit
190
217
  const onHeaderActionChangeRef = useRef(onHeaderActionChange);
191
218
  onHeaderActionChangeRef.current = onHeaderActionChange;
219
+ const headerActionSignatureRef = useRef<string | null>(null);
192
220
 
193
221
  const onChangeRef = useRef(onChange);
194
222
  onChangeRef.current = onChange;
@@ -201,16 +229,48 @@ export default function CreateEstimateForm({
201
229
  }, {} as PriceModesMap);
202
230
  }, [initialValues?.items]);
203
231
  const priceModesRef = useRef<PriceModesMap>(initialPriceModes);
232
+ const customCreateTemplate = (initialValues as any)?._custom_create_template;
233
+ const financialInputsMatchSource = useCallback(
234
+ (values: { items?: any[]; currency_code?: string; calculation_mode?: string | null }) =>
235
+ financialInputsMatchInitial({
236
+ initialItems: initialValues?.items,
237
+ currentItems: values.items,
238
+ initialCurrencyCode: initialValues?.currency_code,
239
+ currentCurrencyCode: values.currency_code,
240
+ initialCalculationMode: (initialValues as any)?.calculation_mode ?? null,
241
+ currentCalculationMode: values.calculation_mode ?? null,
242
+ initialPriceModes,
243
+ currentPriceModes: priceModesRef.current,
244
+ }),
245
+ [initialPriceModes, initialValues],
246
+ );
247
+ const getPreservedExpectedTotalWithTax = useCallback(
248
+ (values: { items?: any[]; currency_code?: string; calculation_mode?: string | null }) =>
249
+ resolvePreservedExpectedTotal({
250
+ initialExpectedTotalWithTax: (initialValues as any)?._preserved_expected_total_with_tax,
251
+ initialItems: initialValues?.items,
252
+ currentItems: values.items,
253
+ initialCurrencyCode: initialValues?.currency_code,
254
+ currentCurrencyCode: values.currency_code,
255
+ initialCalculationMode: (initialValues as any)?.calculation_mode ?? null,
256
+ currentCalculationMode: values.calculation_mode ?? null,
257
+ initialPriceModes,
258
+ currentPriceModes: priceModesRef.current,
259
+ }),
260
+ [initialPriceModes, initialValues],
261
+ );
204
262
 
205
263
  // Update number when fetched
206
264
  useEffect(() => {
265
+ if (isEditMode) return;
207
266
  if (nextNumberData?.number) {
208
267
  form.setValue("number", nextNumberData.number);
209
268
  }
210
- }, [nextNumberData?.number, form]);
269
+ }, [form, isEditMode, nextNumberData?.number]);
211
270
 
212
271
  // Update default note and valid-till date when entity loads
213
272
  useEffect(() => {
273
+ if (isEditMode) return;
214
274
  const entityDefaultNote = (activeEntity?.settings as any)?.default_estimate_note;
215
275
  if (entityDefaultNote && !form.getValues("note")) {
216
276
  form.setValue("note", entityDefaultNote);
@@ -226,7 +286,7 @@ export default function CreateEstimateForm({
226
286
  form.setValue("date_valid_till", calculateDueDate(currentDate, validDays));
227
287
  }
228
288
  }
229
- }, [activeEntity, form, initialValues?.date_valid_till]);
289
+ }, [activeEntity, form, initialValues?.date_valid_till, isEditMode]);
230
290
 
231
291
  // Auto-add tax field for tax subject entities
232
292
  useEffect(() => {
@@ -241,12 +301,39 @@ export default function CreateEstimateForm({
241
301
  // Update header with clickable title toggle
242
302
  useEffect(() => {
243
303
  const callback = onHeaderActionChangeRef.current;
244
- if (!callback) return;
304
+ if (!callback) {
305
+ headerActionSignatureRef.current = null;
306
+ return;
307
+ }
245
308
 
246
309
  const toggleTitle = () => {
247
- setTitleType((prev) => (prev === "estimate" ? "quote" : "estimate"));
310
+ setTitleType((prev) => (prev === "estimate" ? "proforma_invoice" : "estimate"));
248
311
  };
249
312
 
313
+ const titleLabel = isEditMode
314
+ ? titleType === "estimate"
315
+ ? t("Estimate")
316
+ : t("Proforma invoice")
317
+ : titleType === "estimate"
318
+ ? t("Create Estimate")
319
+ : t("Create Proforma invoice");
320
+ const tooltipLabel = isEditMode
321
+ ? titleType === "estimate"
322
+ ? t("Click to switch to Proforma invoice")
323
+ : t("Click to switch to Estimate")
324
+ : titleType === "estimate"
325
+ ? t("Click to switch to Proforma invoice")
326
+ : t("Click to switch to Estimate");
327
+ const headerActionSignature = JSON.stringify({
328
+ titleLabel,
329
+ tooltipLabel,
330
+ isEditMode,
331
+ titleType,
332
+ });
333
+
334
+ if (headerActionSignatureRef.current === headerActionSignature) return;
335
+ headerActionSignatureRef.current = headerActionSignature;
336
+
250
337
  callback(
251
338
  <TooltipProvider>
252
339
  <Tooltip>
@@ -256,17 +343,24 @@ export default function CreateEstimateForm({
256
343
  onClick={toggleTitle}
257
344
  className="flex cursor-pointer items-center gap-2 font-bold text-2xl hover:text-primary"
258
345
  >
259
- {titleType === "estimate" ? t("Create Estimate") : t("Create Quote")}
260
- <RefreshCw className="size-4 text-muted-foreground" />
346
+ {titleLabel}
347
+ <ArrowUpDown className="size-4 text-muted-foreground" />
261
348
  </button>
262
349
  </TooltipTrigger>
263
- <TooltipContent side="bottom">
264
- {titleType === "estimate" ? t("Click to switch to Quote") : t("Click to switch to Estimate")}
265
- </TooltipContent>
350
+ <TooltipContent side="bottom">{tooltipLabel}</TooltipContent>
266
351
  </Tooltip>
267
352
  </TooltipProvider>,
268
353
  );
269
- }, [titleType, t]);
354
+ }, [isEditMode, t, titleType]);
355
+
356
+ useEffect(() => {
357
+ const callback = onHeaderActionChangeRef.current;
358
+ return () => {
359
+ if (!callback || headerActionSignatureRef.current === null) return;
360
+ headerActionSignatureRef.current = null;
361
+ callback(null);
362
+ };
363
+ }, []);
270
364
 
271
365
  const formValues = useWatch({
272
366
  control: form.control,
@@ -297,13 +391,14 @@ export default function CreateEstimateForm({
297
391
  useEffect(() => {
298
392
  if (effectiveTransactionType === prevTransactionTypeRef.current) return;
299
393
  prevTransactionTypeRef.current = effectiveTransactionType;
394
+ if (isEditMode) return;
300
395
 
301
396
  const taxClauseDefaults = (activeEntity?.settings as any)?.tax_clause_defaults;
302
397
  if (!taxClauseDefaults) return;
303
398
 
304
399
  const clause = taxClauseDefaults[effectiveTransactionType] ?? "";
305
400
  form.setValue("tax_clause", clause);
306
- }, [effectiveTransactionType, activeEntity, form]);
401
+ }, [effectiveTransactionType, activeEntity, form, isEditMode]);
307
402
 
308
403
  // Extract customer management logic into a custom hook
309
404
  const {
@@ -327,18 +422,59 @@ export default function CreateEstimateForm({
327
422
  },
328
423
  onError,
329
424
  });
425
+ const { mutate: createCustomEstimate, isPending: isCreateCustomPending } = useCreateCustomEstimate({
426
+ entityId,
427
+ onSuccess: (data) => {
428
+ if (data.customer_id) {
429
+ queryClient.invalidateQueries({ queryKey: [CUSTOMERS_CACHE_KEY] });
430
+ }
431
+ onSuccess?.(data);
432
+ },
433
+ onError,
434
+ });
435
+ const { mutate: updateEstimate, isPending: isUpdatePending } = useUpdateEstimate({
436
+ entityId,
437
+ onSuccess,
438
+ onError,
439
+ });
330
440
 
331
441
  // Shared submit logic for both regular save and save as draft
332
442
  const submitEstimate = useCallback(
333
443
  (values: CreateEstimateFormValues, isDraft: boolean) => {
334
444
  try {
445
+ if (isEditMode) {
446
+ if (!documentId) {
447
+ throw new Error("Estimate edit mode requires a documentId");
448
+ }
449
+
450
+ const submission = prepareEstimateUpdateSubmission(values as any, {
451
+ originalCustomer,
452
+ priceModes: priceModesRef.current,
453
+ titleType,
454
+ }) as UpdateEstimate;
455
+
456
+ updateEstimate({ id: documentId, data: submission });
457
+ return;
458
+ }
459
+
335
460
  const submission = prepareEstimateSubmission(values, {
336
461
  originalCustomer,
337
462
  priceModes: priceModesRef.current,
338
463
  titleType,
339
464
  isDraft,
340
465
  });
341
- createEstimate(submission);
466
+ const preservedExpectedTotalWithTax = getPreservedExpectedTotalWithTax(values);
467
+ if (preservedExpectedTotalWithTax !== undefined) {
468
+ (submission as any).expected_total_with_tax = preservedExpectedTotalWithTax;
469
+ } else {
470
+ delete (submission as any).expected_total_with_tax;
471
+ }
472
+ if (customCreateTemplate && financialInputsMatchSource(values)) {
473
+ delete (submission as any).expected_total_with_tax;
474
+ createCustomEstimate(applyCustomCreateTemplate(submission as any, customCreateTemplate));
475
+ } else {
476
+ createEstimate(submission);
477
+ }
342
478
  } catch (error) {
343
479
  console.error("Estimate submission error:", error);
344
480
  if (onError) {
@@ -346,7 +482,19 @@ export default function CreateEstimateForm({
346
482
  }
347
483
  }
348
484
  },
349
- [createEstimate, onError, originalCustomer, titleType],
485
+ [
486
+ createEstimate,
487
+ createCustomEstimate,
488
+ customCreateTemplate,
489
+ documentId,
490
+ financialInputsMatchSource,
491
+ getPreservedExpectedTotalWithTax,
492
+ isEditMode,
493
+ onError,
494
+ originalCustomer,
495
+ titleType,
496
+ updateEstimate,
497
+ ],
350
498
  );
351
499
 
352
500
  // Handle save as draft
@@ -365,26 +513,27 @@ export default function CreateEstimateForm({
365
513
 
366
514
  const secondaryAction = useMemo(
367
515
  () =>
368
- allowDrafts
516
+ allowDrafts && !isEditMode
369
517
  ? {
370
518
  label: t("Save as Draft"),
371
519
  onClick: handleSaveAsDraft,
372
520
  isPending: isDraftPending,
373
521
  }
374
522
  : undefined,
375
- [allowDrafts, t, handleSaveAsDraft, isDraftPending],
523
+ [allowDrafts, t, handleSaveAsDraft, isDraftPending, isEditMode],
376
524
  );
377
525
 
378
526
  useFormFooterRegistration({
379
527
  formId: "create-estimate-form",
380
- isPending,
528
+ isPending: isPending || isCreateCustomPending || isUpdatePending,
381
529
  isDirty: form.formState.isDirty || !!initialValues,
382
- label: titleType === "estimate" ? t("Create Estimate") : t("Create Quote"),
530
+ label: isEditMode ? t("Update") : titleType === "estimate" ? t("Create Estimate") : t("Create Proforma invoice"),
383
531
  secondaryAction,
384
532
  });
385
533
 
386
534
  // Set default payment terms and footer from entity settings when entity data is available
387
535
  useEffect(() => {
536
+ if (isEditMode) return;
388
537
  const entityDefaultPaymentTerms = (activeEntity?.settings as any)?.default_estimate_payment_terms;
389
538
  if (entityDefaultPaymentTerms && !form.getValues("payment_terms")) {
390
539
  form.setValue("payment_terms", entityDefaultPaymentTerms);
@@ -393,44 +542,44 @@ export default function CreateEstimateForm({
393
542
  if (entityDefaultFooter && !form.getValues("footer")) {
394
543
  form.setValue("footer", entityDefaultFooter);
395
544
  }
396
- }, [activeEntity, form]);
545
+ }, [activeEntity, form, isEditMode]);
397
546
 
398
547
  // Recalculate valid-till date when document date changes
399
548
  const prevDateRef = useRef(form.getValues("date"));
400
549
  useEffect(() => {
550
+ if (isEditMode) return;
401
551
  const currentDate = formValues.date;
402
552
  if (!currentDate || currentDate === prevDateRef.current) return;
403
553
  prevDateRef.current = currentDate;
404
554
  const validDays = (activeEntity?.settings as any)?.default_estimate_valid_days ?? 30;
405
555
  form.setValue("date_valid_till", calculateDueDate(currentDate, validDays));
406
- }, [formValues.date, activeEntity, form]);
556
+ }, [formValues.date, activeEntity, form, isEditMode]);
407
557
 
408
558
  const buildPreviewPayload = useCallback(
409
559
  (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
-
560
+ const preservedExpectedTotalWithTax = getPreservedExpectedTotalWithTax(values);
418
561
  return {
419
562
  number: values.number,
420
563
  date: values.date,
421
564
  customer_id: values.customer_id,
422
565
  customer: values.customer,
423
- items: transformedItems,
566
+ items: prepareDocumentItems(values.items, priceModesRef.current),
424
567
  currency_code: values.currency_code,
425
568
  reference: values.reference,
426
569
  note: values.note,
570
+ tax_clause: values.tax_clause,
427
571
  payment_terms: values.payment_terms,
428
572
  signature: values.signature,
573
+ footer: values.footer,
574
+ date_valid_till: values.date_valid_till,
429
575
  title_type: titleType,
576
+ ...(preservedExpectedTotalWithTax !== undefined
577
+ ? { expected_total_with_tax: preservedExpectedTotalWithTax }
578
+ : {}),
430
579
  ...(normalizePtDocumentInput(values.pt) ? { pt: normalizePtDocumentInput(values.pt) } : {}),
431
580
  };
432
581
  },
433
- [titleType],
582
+ [getPreservedExpectedTotalWithTax, titleType],
434
583
  );
435
584
 
436
585
  const emitPreviewPayload = useCallback((payload: EstimatePreviewPayload) => {