shutro-erp 0.3.6 → 0.3.7

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 (623) hide show
  1. package/dist/account_asset/.kosh/bindings.js +1 -1
  2. package/dist/account_asset/.kosh/schema.d.ts +530 -8
  3. package/dist/account_asset/i18n/bn.d.ts +2 -0
  4. package/dist/account_asset/i18n/bn.js +97 -0
  5. package/dist/account_asset/index.js +2 -0
  6. package/dist/account_asset/module.d.ts +4899 -1445
  7. package/dist/account_budget/.kosh/bindings.js +1 -1
  8. package/dist/account_budget/.kosh/schema.d.ts +1130 -56
  9. package/dist/account_budget/i18n/bn.d.ts +2 -0
  10. package/dist/account_budget/i18n/bn.js +63 -0
  11. package/dist/account_budget/index.js +14 -0
  12. package/dist/account_budget/module.d.ts +17958 -4532
  13. package/dist/account_budget/module.js +15 -0
  14. package/dist/account_portal/.kosh/bindings.js +1 -1
  15. package/dist/account_portal/.kosh/schema.d.ts +530 -8
  16. package/dist/account_portal/i18n/bn.d.ts +2 -0
  17. package/dist/account_portal/i18n/bn.js +6 -0
  18. package/dist/account_portal/index.js +2 -0
  19. package/dist/account_portal/module.d.ts +5167 -1693
  20. package/dist/accounting/.kosh/bindings.js +1 -1
  21. package/dist/accounting/.kosh/schema.d.ts +530 -8
  22. package/dist/accounting/closing.js +1 -0
  23. package/dist/accounting/fiscal.d.ts +578 -0
  24. package/dist/accounting/fiscal.js +401 -0
  25. package/dist/accounting/followups.d.ts +618 -0
  26. package/dist/accounting/followups.js +420 -0
  27. package/dist/accounting/i18n/bn.d.ts +2 -0
  28. package/dist/accounting/i18n/bn.js +425 -0
  29. package/dist/accounting/index.d.ts +2 -0
  30. package/dist/accounting/index.js +649 -2
  31. package/dist/accounting/module.d.ts +4998 -1451
  32. package/dist/accounting/module.js +124 -18
  33. package/dist/accounting/statements.d.ts +878 -0
  34. package/dist/accounting/statements.js +728 -0
  35. package/dist/accounting/web/BankReconcilePage.d.ts +9 -0
  36. package/dist/accounting/web/BankReconcilePage.js +138 -0
  37. package/dist/accounting/web/FollowupsPage.d.ts +8 -0
  38. package/dist/accounting/web/FollowupsPage.js +54 -0
  39. package/dist/accounting/web/PostingPreview.d.ts +8 -0
  40. package/dist/accounting/web/PostingPreview.js +26 -0
  41. package/dist/accounting/web/index.d.ts +3 -0
  42. package/dist/accounting/web/index.js +9 -0
  43. package/dist/accounting/web/messages.js +140 -0
  44. package/dist/approvals/.kosh/bindings.js +1 -1
  45. package/dist/approvals/.kosh/schema.d.ts +272 -4
  46. package/dist/approvals/demo.d.ts +7 -0
  47. package/dist/approvals/demo.js +41 -0
  48. package/dist/approvals/i18n/bn.d.ts +2 -0
  49. package/dist/approvals/i18n/bn.js +133 -0
  50. package/dist/approvals/index.d.ts +19 -1
  51. package/dist/approvals/index.js +477 -7
  52. package/dist/approvals/mails.d.ts +7 -2
  53. package/dist/approvals/mails.js +8 -3
  54. package/dist/approvals/module.d.ts +2930 -1
  55. package/dist/approvals/module.js +468 -7
  56. package/dist/approvals/web/Config.d.ts +12 -0
  57. package/dist/approvals/web/Config.js +60 -0
  58. package/dist/approvals/web/Matrix.d.ts +9 -0
  59. package/dist/approvals/web/Matrix.js +26 -0
  60. package/dist/approvals/web/index.d.ts +3 -1
  61. package/dist/approvals/web/index.js +8 -1
  62. package/dist/approvals/web/messages.js +92 -0
  63. package/dist/approvals_purchase/.kosh/bindings.js +15 -0
  64. package/dist/approvals_purchase/.kosh/schema.d.ts +1997 -0
  65. package/dist/approvals_purchase/i18n/bn.d.ts +2 -0
  66. package/dist/approvals_purchase/i18n/bn.js +5 -0
  67. package/dist/approvals_purchase/index.d.ts +3 -0
  68. package/dist/approvals_purchase/index.js +47 -0
  69. package/dist/approvals_purchase/module.d.ts +12670 -0
  70. package/dist/approvals_purchase/module.js +84 -0
  71. package/dist/attendance/.kosh/bindings.js +1 -1
  72. package/dist/attendance/.kosh/schema.d.ts +59 -1
  73. package/dist/attendance/i18n/bn.d.ts +2 -0
  74. package/dist/attendance/i18n/bn.js +147 -0
  75. package/dist/attendance/index.js +3 -1
  76. package/dist/attendance/module.d.ts +452 -8
  77. package/dist/automation/engine.js +1 -1
  78. package/dist/calendar/.kosh/bindings.js +1 -1
  79. package/dist/calendar/.kosh/schema.d.ts +2 -1
  80. package/dist/calendar/i18n/bn.d.ts +2 -0
  81. package/dist/calendar/i18n/bn.js +80 -0
  82. package/dist/calendar/index.js +77 -0
  83. package/dist/calendar/module.d.ts +26 -0
  84. package/dist/calendar/module.js +14 -4
  85. package/dist/cli/apps.js +25 -5
  86. package/dist/cli/init.js +14 -4
  87. package/dist/cli/templates.d.ts +1 -1
  88. package/dist/cli/templates.js +34 -5
  89. package/dist/contacts/.kosh/bindings.js +1 -1
  90. package/dist/contacts/.kosh/schema.d.ts +2 -1
  91. package/dist/contacts/i18n/bn.d.ts +2 -0
  92. package/dist/contacts/i18n/bn.js +67 -0
  93. package/dist/contacts/index.js +3 -0
  94. package/dist/contacts/module.d.ts +42 -0
  95. package/dist/contacts/module.js +6 -1
  96. package/dist/crm/.kosh/bindings.js +1 -1
  97. package/dist/crm/.kosh/schema.d.ts +2 -1
  98. package/dist/crm/i18n/bn.d.ts +2 -0
  99. package/dist/crm/i18n/bn.js +80 -0
  100. package/dist/crm/index.js +22 -0
  101. package/dist/crm/module.d.ts +20 -0
  102. package/dist/crm/module.js +4 -2
  103. package/dist/documents/.kosh/bindings.js +1 -1
  104. package/dist/documents/.kosh/schema.d.ts +2 -1
  105. package/dist/documents/i18n/bn.d.ts +2 -0
  106. package/dist/documents/i18n/bn.js +83 -0
  107. package/dist/documents/index.js +128 -1
  108. package/dist/documents/module.d.ts +20 -0
  109. package/dist/documents/module.js +1 -0
  110. package/dist/event/.kosh/bindings.js +1 -1
  111. package/dist/event/.kosh/schema.d.ts +2 -1
  112. package/dist/event/i18n/bn.d.ts +2 -0
  113. package/dist/event/i18n/bn.js +101 -0
  114. package/dist/event/index.js +66 -0
  115. package/dist/event/module.d.ts +20 -0
  116. package/dist/event/module.js +8 -1
  117. package/dist/event_account/.kosh/bindings.js +1 -1
  118. package/dist/event_account/.kosh/schema.d.ts +530 -8
  119. package/dist/event_account/i18n/bn.d.ts +2 -0
  120. package/dist/event_account/i18n/bn.js +5 -0
  121. package/dist/event_account/index.js +2 -0
  122. package/dist/event_account/module.d.ts +4905 -1431
  123. package/dist/expense/.kosh/bindings.js +1 -1
  124. package/dist/expense/.kosh/schema.d.ts +323 -2
  125. package/dist/expense/i18n/bn.d.ts +2 -0
  126. package/dist/expense/i18n/bn.js +155 -0
  127. package/dist/expense/index.js +8 -1
  128. package/dist/expense/module.d.ts +2715 -694
  129. package/dist/expense/module.js +3 -1
  130. package/dist/expense_account/.kosh/bindings.js +1 -1
  131. package/dist/expense_account/.kosh/schema.d.ts +587 -8
  132. package/dist/expense_account/i18n/bn.d.ts +2 -0
  133. package/dist/expense_account/i18n/bn.js +15 -0
  134. package/dist/expense_account/index.js +2 -0
  135. package/dist/expense_account/module.d.ts +8094 -2619
  136. package/dist/helpdesk/.kosh/bindings.js +1 -1
  137. package/dist/helpdesk/.kosh/schema.d.ts +2 -1
  138. package/dist/helpdesk/i18n/bn.d.ts +2 -0
  139. package/dist/helpdesk/i18n/bn.js +127 -0
  140. package/dist/helpdesk/index.js +2 -0
  141. package/dist/helpdesk/module.d.ts +20 -0
  142. package/dist/hr/.kosh/bindings.js +1 -1
  143. package/dist/hr/.kosh/schema.d.ts +59 -1
  144. package/dist/hr/demo.js +11 -1
  145. package/dist/hr/i18n/bn.d.ts +2 -0
  146. package/dist/hr/i18n/bn.js +126 -0
  147. package/dist/hr/index.d.ts +1 -1
  148. package/dist/hr/index.js +158 -12
  149. package/dist/hr/module.d.ts +932 -59
  150. package/dist/hr/module.js +114 -17
  151. package/dist/{mrp → indent}/.kosh/bindings.js +2 -2
  152. package/dist/indent/.kosh/schema.d.ts +2084 -0
  153. package/dist/indent/demo.d.ts +7 -0
  154. package/dist/indent/demo.js +48 -0
  155. package/dist/indent/i18n/bn.d.ts +2 -0
  156. package/dist/indent/i18n/bn.js +143 -0
  157. package/dist/indent/index.d.ts +3 -0
  158. package/dist/indent/index.js +450 -0
  159. package/dist/{mrp → indent}/module.d.ts +7164 -3075
  160. package/dist/indent/module.js +792 -0
  161. package/dist/indent_purchase/.kosh/bindings.d.ts +22 -0
  162. package/dist/indent_purchase/.kosh/bindings.js +15 -0
  163. package/dist/indent_purchase/.kosh/schema.d.ts +2710 -0
  164. package/dist/indent_purchase/i18n/bn.d.ts +2 -0
  165. package/dist/indent_purchase/i18n/bn.js +13 -0
  166. package/dist/indent_purchase/index.d.ts +3 -0
  167. package/dist/indent_purchase/index.js +61 -0
  168. package/dist/indent_purchase/module.d.ts +27950 -0
  169. package/dist/indent_purchase/module.js +163 -0
  170. package/dist/l10n_bd/.kosh/bindings.js +1 -1
  171. package/dist/l10n_bd/.kosh/schema.d.ts +530 -8
  172. package/dist/l10n_bd/i18n/bn.d.ts +2 -0
  173. package/dist/l10n_bd/i18n/bn.js +69 -0
  174. package/dist/l10n_bd/index.js +2 -0
  175. package/dist/l10n_bd/module.d.ts +5167 -1693
  176. package/dist/l10n_bd_payroll/.kosh/bindings.js +1 -1
  177. package/dist/l10n_bd_payroll/.kosh/schema.d.ts +587 -8
  178. package/dist/l10n_bd_payroll/i18n/bn.d.ts +2 -0
  179. package/dist/l10n_bd_payroll/i18n/bn.js +4 -0
  180. package/dist/l10n_bd_payroll/index.js +2 -0
  181. package/dist/l10n_bd_payroll/module.d.ts +5910 -1548
  182. package/dist/l10n_bd_pos/.kosh/bindings.d.ts +22 -0
  183. package/dist/{mrp_account → l10n_bd_pos}/.kosh/bindings.js +2 -2
  184. package/dist/{mrp_account → l10n_bd_pos}/.kosh/schema.d.ts +693 -651
  185. package/dist/l10n_bd_pos/i18n/bn.d.ts +2 -0
  186. package/dist/l10n_bd_pos/i18n/bn.js +32 -0
  187. package/dist/l10n_bd_pos/index.d.ts +3 -0
  188. package/dist/l10n_bd_pos/index.js +111 -0
  189. package/dist/{mrp_account → l10n_bd_pos}/module.d.ts +7402 -7647
  190. package/dist/l10n_bd_pos/module.js +43 -0
  191. package/dist/l10n_in/.kosh/bindings.js +1 -1
  192. package/dist/l10n_in/.kosh/schema.d.ts +530 -8
  193. package/dist/l10n_in/i18n/bn.d.ts +2 -0
  194. package/dist/l10n_in/i18n/bn.js +95 -0
  195. package/dist/l10n_in/index.js +2 -0
  196. package/dist/l10n_in/module.d.ts +6703 -1652
  197. package/dist/l10n_in/module.js +25 -5
  198. package/dist/l10n_in/web/GstSettings.js +2 -2
  199. package/dist/mail/inbound/handle.js +2 -4
  200. package/dist/mail/inbound/models.js +5 -3
  201. package/dist/mail/index.d.ts +12 -1
  202. package/dist/mail/index.js +139 -2
  203. package/dist/mail/send.d.ts +56 -0
  204. package/dist/mail/send.js +394 -0
  205. package/dist/mail/web/SendButton.d.ts +9 -0
  206. package/dist/mail/web/SendButton.js +71 -0
  207. package/dist/mail/web/SendSelected.d.ts +8 -0
  208. package/dist/mail/web/SendSelected.js +33 -0
  209. package/dist/mail/web/index.d.ts +2 -0
  210. package/dist/mail/web/index.js +6 -0
  211. package/dist/mail/web/messages.js +36 -0
  212. package/dist/maintenance/.kosh/bindings.js +1 -1
  213. package/dist/maintenance/.kosh/schema.d.ts +2 -1
  214. package/dist/maintenance/i18n/bn.d.ts +2 -0
  215. package/dist/maintenance/i18n/bn.js +132 -0
  216. package/dist/maintenance/index.js +85 -0
  217. package/dist/maintenance/module.d.ts +25 -0
  218. package/dist/maintenance/module.js +27 -9
  219. package/dist/maintenance_stock/.kosh/bindings.js +1 -1
  220. package/dist/maintenance_stock/.kosh/schema.d.ts +298 -2
  221. package/dist/maintenance_stock/i18n/bn.d.ts +2 -0
  222. package/dist/maintenance_stock/i18n/bn.js +21 -0
  223. package/dist/maintenance_stock/index.js +2 -0
  224. package/dist/maintenance_stock/module.d.ts +5302 -1256
  225. package/dist/maintenance_stock/module.js +1 -0
  226. package/dist/modules-sdk/apps.d.ts +10 -0
  227. package/dist/modules-sdk/apps.js +32 -0
  228. package/dist/modules-sdk/index.d.ts +1 -1
  229. package/dist/modules-sdk/manifest.d.ts +68 -2
  230. package/dist/payment/.kosh/bindings.js +1 -1
  231. package/dist/payment/.kosh/schema.d.ts +530 -8
  232. package/dist/payment/i18n/bn.d.ts +2 -0
  233. package/dist/payment/i18n/bn.js +59 -0
  234. package/dist/payment/index.js +85 -0
  235. package/dist/payment/module.d.ts +5134 -1660
  236. package/dist/payment/module.js +17 -3
  237. package/dist/payment/settle.js +1 -0
  238. package/dist/payroll/.kosh/bindings.js +1 -1
  239. package/dist/payroll/.kosh/schema.d.ts +59 -1
  240. package/dist/payroll/i18n/bn.d.ts +2 -0
  241. package/dist/payroll/i18n/bn.js +206 -0
  242. package/dist/payroll/index.js +2 -0
  243. package/dist/payroll/module.d.ts +936 -48
  244. package/dist/payroll_account/.kosh/bindings.js +1 -1
  245. package/dist/payroll_account/.kosh/schema.d.ts +587 -8
  246. package/dist/payroll_account/i18n/bn.d.ts +2 -0
  247. package/dist/payroll_account/i18n/bn.js +10 -0
  248. package/dist/payroll_account/index.js +2 -0
  249. package/dist/payroll_account/module.d.ts +7534 -3192
  250. package/dist/permissions/approvals.d.ts +97 -4
  251. package/dist/permissions/approvals.js +780 -31
  252. package/dist/permissions/index.d.ts +1 -1
  253. package/dist/permissions/index.js +2 -2
  254. package/dist/permissions/models.js +177 -5
  255. package/dist/permissions/routes.d.ts +3 -0
  256. package/dist/permissions/routes.js +36 -2
  257. package/dist/permissions/web/ApprovalPanel.js +43 -5
  258. package/dist/permissions/web/messages.js +52 -0
  259. package/dist/portal/.kosh/bindings.js +1 -1
  260. package/dist/portal/.kosh/schema.d.ts +2 -1
  261. package/dist/portal/documents.d.ts +3 -0
  262. package/dist/portal/documents.js +21 -1
  263. package/dist/portal/i18n/bn.d.ts +2 -0
  264. package/dist/portal/i18n/bn.js +33 -0
  265. package/dist/portal/index.js +2 -0
  266. package/dist/portal/module.d.ts +20 -0
  267. package/dist/portal/routes-documents.js +76 -0
  268. package/dist/pos/.kosh/bindings.js +1 -1
  269. package/dist/pos/.kosh/schema.d.ts +531 -8
  270. package/dist/pos/i18n/bn.d.ts +2 -0
  271. package/dist/pos/i18n/bn.js +133 -0
  272. package/dist/pos/index.js +83 -1
  273. package/dist/pos/module.d.ts +6888 -1777
  274. package/dist/pos/module.js +49 -5
  275. package/dist/pos/routes.js +80 -7
  276. package/dist/pos/web/Register.js +2 -5
  277. package/dist/pos_stock/.kosh/bindings.js +1 -1
  278. package/dist/pos_stock/.kosh/schema.d.ts +626 -9
  279. package/dist/pos_stock/i18n/bn.d.ts +2 -0
  280. package/dist/pos_stock/i18n/bn.js +6 -0
  281. package/dist/pos_stock/index.js +2 -0
  282. package/dist/pos_stock/module.d.ts +10798 -3276
  283. package/dist/product/.kosh/bindings.js +1 -1
  284. package/dist/product/.kosh/schema.d.ts +202 -1
  285. package/dist/product/i18n/bn.d.ts +2 -0
  286. package/dist/product/i18n/bn.js +175 -0
  287. package/dist/product/index.d.ts +1 -0
  288. package/dist/product/index.js +288 -1
  289. package/dist/product/module.d.ts +1725 -0
  290. package/dist/product/module.js +66 -6
  291. package/dist/product/pricelist.d.ts +575 -0
  292. package/dist/product/pricelist.js +257 -0
  293. package/dist/product/variants.d.ts +908 -0
  294. package/dist/product/variants.js +251 -0
  295. package/dist/production/.kosh/bindings.d.ts +22 -0
  296. package/dist/production/.kosh/bindings.js +15 -0
  297. package/dist/production/.kosh/schema.d.ts +2345 -0
  298. package/dist/{mrp → production}/demo.d.ts +1 -1
  299. package/dist/{mrp → production}/demo.js +5 -5
  300. package/dist/production/depth.d.ts +790 -0
  301. package/dist/production/depth.js +262 -0
  302. package/dist/production/i18n/bn.d.ts +2 -0
  303. package/dist/production/i18n/bn.js +350 -0
  304. package/dist/production/index.d.ts +6 -0
  305. package/dist/production/index.js +1256 -0
  306. package/dist/production/module.d.ts +17327 -0
  307. package/dist/production/module.js +1333 -0
  308. package/dist/production/plan.d.ts +921 -0
  309. package/dist/production/plan.js +511 -0
  310. package/dist/production/schedule.d.ts +656 -0
  311. package/dist/production/schedule.js +309 -0
  312. package/dist/production_account/.kosh/bindings.d.ts +22 -0
  313. package/dist/production_account/.kosh/bindings.js +15 -0
  314. package/dist/production_account/.kosh/schema.d.ts +3496 -0
  315. package/dist/production_account/i18n/bn.d.ts +2 -0
  316. package/dist/production_account/i18n/bn.js +93 -0
  317. package/dist/production_account/index.d.ts +4 -0
  318. package/dist/production_account/index.js +246 -0
  319. package/dist/production_account/module.d.ts +1192 -0
  320. package/dist/{mrp_account → production_account}/module.js +72 -18
  321. package/dist/production_account/overhead.d.ts +1195 -0
  322. package/dist/production_account/overhead.js +554 -0
  323. package/dist/project/.kosh/bindings.js +1 -1
  324. package/dist/project/.kosh/schema.d.ts +65 -2
  325. package/dist/project/i18n/bn.d.ts +2 -0
  326. package/dist/project/i18n/bn.js +383 -0
  327. package/dist/project/index.js +123 -0
  328. package/dist/project/module.d.ts +20 -0
  329. package/dist/project/module.js +73 -14
  330. package/dist/project_account/.kosh/bindings.js +1 -1
  331. package/dist/project_account/.kosh/schema.d.ts +530 -8
  332. package/dist/project_account/i18n/bn.d.ts +2 -0
  333. package/dist/project_account/i18n/bn.js +6 -0
  334. package/dist/project_account/index.js +2 -0
  335. package/dist/project_account/module.d.ts +4926 -1452
  336. package/dist/project_portal/.kosh/bindings.js +1 -1
  337. package/dist/project_portal/.kosh/schema.d.ts +65 -2
  338. package/dist/project_portal/i18n/bn.d.ts +2 -0
  339. package/dist/project_portal/i18n/bn.js +6 -0
  340. package/dist/project_portal/index.js +2 -0
  341. package/dist/project_portal/module.d.ts +40 -0
  342. package/dist/project_purchase/.kosh/bindings.js +1 -1
  343. package/dist/project_purchase/.kosh/schema.d.ts +1126 -53
  344. package/dist/project_purchase/i18n/bn.d.ts +2 -0
  345. package/dist/project_purchase/i18n/bn.js +4 -0
  346. package/dist/project_purchase/index.js +2 -0
  347. package/dist/project_purchase/module.d.ts +17912 -4446
  348. package/dist/purchase/.kosh/bindings.js +1 -1
  349. package/dist/purchase/.kosh/schema.d.ts +813 -3
  350. package/dist/purchase/comparison.d.ts +993 -0
  351. package/dist/purchase/comparison.js +415 -0
  352. package/dist/purchase/extras.d.ts +1509 -0
  353. package/dist/purchase/extras.js +445 -0
  354. package/dist/purchase/i18n/bn.d.ts +2 -0
  355. package/dist/purchase/i18n/bn.js +413 -0
  356. package/dist/purchase/index.d.ts +5 -0
  357. package/dist/purchase/index.js +1280 -4
  358. package/dist/purchase/module.d.ts +7139 -398
  359. package/dist/purchase/module.js +295 -11
  360. package/dist/purchase/request.d.ts +696 -0
  361. package/dist/purchase/request.js +446 -0
  362. package/dist/purchase/tender.d.ts +1208 -0
  363. package/dist/purchase/tender.js +507 -0
  364. package/dist/purchase/vendorprice.d.ts +340 -0
  365. package/dist/purchase/vendorprice.js +153 -0
  366. package/dist/purchase_account/.kosh/bindings.js +1 -1
  367. package/dist/purchase_account/.kosh/schema.d.ts +1130 -57
  368. package/dist/purchase_account/i18n/bn.d.ts +2 -0
  369. package/dist/purchase_account/i18n/bn.js +22 -0
  370. package/dist/purchase_account/index.js +19 -0
  371. package/dist/purchase_account/module.d.ts +12276 -2247
  372. package/dist/purchase_account/module.js +241 -9
  373. package/dist/purchase_portal/.kosh/bindings.js +1 -1
  374. package/dist/purchase_portal/.kosh/schema.d.ts +813 -3
  375. package/dist/purchase_portal/i18n/bn.d.ts +2 -0
  376. package/dist/purchase_portal/i18n/bn.js +5 -0
  377. package/dist/purchase_portal/index.js +2 -0
  378. package/dist/purchase_portal/module.d.ts +6849 -353
  379. package/dist/purchase_stock/.kosh/bindings.js +1 -1
  380. package/dist/purchase_stock/.kosh/schema.d.ts +910 -4
  381. package/dist/purchase_stock/i18n/bn.d.ts +2 -0
  382. package/dist/purchase_stock/i18n/bn.js +19 -0
  383. package/dist/purchase_stock/index.d.ts +1 -1
  384. package/dist/purchase_stock/index.js +29 -0
  385. package/dist/purchase_stock/module.d.ts +12410 -1864
  386. package/dist/purchase_stock/module.js +81 -9
  387. package/dist/purchase_stock/scorecard.d.ts +22 -0
  388. package/dist/purchase_stock/scorecard.js +77 -0
  389. package/dist/purchase_stock/web/Scorecard.d.ts +7 -0
  390. package/dist/purchase_stock/web/Scorecard.js +22 -0
  391. package/dist/purchase_stock/web/index.d.ts +11 -0
  392. package/dist/purchase_stock/web/index.js +16 -0
  393. package/dist/purchase_stock/web/messages.d.ts +2 -0
  394. package/dist/purchase_stock/web/messages.js +27 -0
  395. package/dist/purchase_stock_account/.kosh/bindings.js +1 -1
  396. package/dist/purchase_stock_account/.kosh/schema.d.ts +1286 -58
  397. package/dist/purchase_stock_account/i18n/bn.d.ts +2 -0
  398. package/dist/purchase_stock_account/i18n/bn.js +8 -0
  399. package/dist/purchase_stock_account/index.js +18 -0
  400. package/dist/purchase_stock_account/module.d.ts +7 -37995
  401. package/dist/purchase_stock_account/module.js +24 -3
  402. package/dist/recruitment/.kosh/bindings.js +1 -1
  403. package/dist/recruitment/.kosh/schema.d.ts +59 -1
  404. package/dist/recruitment/i18n/bn.d.ts +2 -0
  405. package/dist/recruitment/i18n/bn.js +93 -0
  406. package/dist/recruitment/index.js +64 -0
  407. package/dist/recruitment/module.d.ts +458 -8
  408. package/dist/recruitment/module.js +11 -3
  409. package/dist/reporting/documents.d.ts +5 -0
  410. package/dist/reporting/documents.js +11 -1
  411. package/dist/reporting/index.d.ts +1 -1
  412. package/dist/reporting/index.js +1 -1
  413. package/dist/reporting/web/CalendarView.d.ts +18 -5
  414. package/dist/reporting/web/CalendarView.js +163 -29
  415. package/dist/reporting/web/messages.js +18 -0
  416. package/dist/sale_account/.kosh/bindings.js +1 -1
  417. package/dist/sale_account/.kosh/schema.d.ts +642 -16
  418. package/dist/sale_account/i18n/bn.d.ts +2 -0
  419. package/dist/sale_account/i18n/bn.js +48 -0
  420. package/dist/sale_account/index.d.ts +1 -1
  421. package/dist/sale_account/index.js +102 -4
  422. package/dist/sale_account/module.d.ts +8254 -2212
  423. package/dist/sale_account/module.js +535 -46
  424. package/dist/sale_crm/.kosh/bindings.d.ts +22 -0
  425. package/dist/sale_crm/.kosh/bindings.js +15 -0
  426. package/dist/{mrp → sale_crm}/.kosh/schema.d.ts +389 -567
  427. package/dist/sale_crm/i18n/bn.d.ts +2 -0
  428. package/dist/sale_crm/i18n/bn.js +9 -0
  429. package/dist/sale_crm/index.d.ts +7 -0
  430. package/dist/sale_crm/index.js +104 -0
  431. package/dist/sale_crm/module.d.ts +5609 -0
  432. package/dist/sale_crm/module.js +73 -0
  433. package/dist/sale_portal/.kosh/bindings.js +1 -1
  434. package/dist/sale_portal/.kosh/schema.d.ts +291 -4
  435. package/dist/sale_portal/i18n/bn.d.ts +2 -0
  436. package/dist/sale_portal/i18n/bn.js +7 -0
  437. package/dist/sale_portal/index.js +10 -0
  438. package/dist/sale_portal/module.d.ts +2564 -294
  439. package/dist/sale_project/.kosh/bindings.js +1 -1
  440. package/dist/sale_project/.kosh/schema.d.ts +354 -5
  441. package/dist/sale_project/i18n/bn.d.ts +2 -0
  442. package/dist/sale_project/i18n/bn.js +12 -0
  443. package/dist/sale_project/index.js +2 -0
  444. package/dist/sale_project/module.d.ts +6249 -2402
  445. package/dist/sale_stock/.kosh/bindings.js +1 -1
  446. package/dist/sale_stock/.kosh/schema.d.ts +387 -5
  447. package/dist/sale_stock/i18n/bn.d.ts +2 -0
  448. package/dist/sale_stock/i18n/bn.js +15 -0
  449. package/dist/sale_stock/index.js +2 -0
  450. package/dist/sale_stock/module.d.ts +8057 -1759
  451. package/dist/sale_stock/module.js +20 -3
  452. package/dist/sales/.kosh/bindings.js +1 -1
  453. package/dist/sales/.kosh/schema.d.ts +291 -4
  454. package/dist/sales/i18n/bn.d.ts +2 -0
  455. package/dist/sales/i18n/bn.js +128 -0
  456. package/dist/sales/index.js +120 -5
  457. package/dist/sales/module.d.ts +3567 -633
  458. package/dist/sales/module.js +306 -11
  459. package/dist/server/api/duplicate.d.ts +14 -0
  460. package/dist/server/api/duplicate.js +75 -0
  461. package/dist/server/api/explain.d.ts +70 -0
  462. package/dist/server/api/explain.js +111 -0
  463. package/dist/server/api/metadata.d.ts +2 -0
  464. package/dist/server/api/metadata.js +9 -0
  465. package/dist/server/api/openapi.js +15 -0
  466. package/dist/server/api/rest.d.ts +1 -0
  467. package/dist/server/api/rest.js +76 -12
  468. package/dist/server/api/views.js +1 -1
  469. package/dist/server/apps.d.ts +16 -1
  470. package/dist/server/apps.js +164 -2
  471. package/dist/server/auth/base.js +2 -0
  472. package/dist/server/auth/service.d.ts +8 -0
  473. package/dist/server/auth/service.js +19 -0
  474. package/dist/server/events.d.ts +13 -0
  475. package/dist/server/events.js +22 -0
  476. package/dist/server/i18n.d.ts +27 -0
  477. package/dist/server/i18n.js +143 -0
  478. package/dist/server/index.d.ts +2 -0
  479. package/dist/server/index.js +2 -0
  480. package/dist/server/server.js +6 -0
  481. package/dist/settings/company.d.ts +3 -1
  482. package/dist/settings/company.js +26 -5
  483. package/dist/settings/routes.d.ts +10 -0
  484. package/dist/settings/routes.js +19 -3
  485. package/dist/settings/web/AppsPage.d.ts +3 -2
  486. package/dist/settings/web/AppsPage.js +26 -8
  487. package/dist/settings/web/CompaniesPage.js +91 -6
  488. package/dist/settings/web/messages.js +64 -0
  489. package/dist/sign/.kosh/bindings.js +1 -1
  490. package/dist/sign/.kosh/schema.d.ts +2 -1
  491. package/dist/sign/i18n/bn.d.ts +2 -0
  492. package/dist/sign/i18n/bn.js +97 -0
  493. package/dist/sign/index.d.ts +15 -0
  494. package/dist/sign/index.js +129 -1
  495. package/dist/sign/module.d.ts +40 -0
  496. package/dist/sign/module.js +11 -2
  497. package/dist/stock/.kosh/bindings.js +1 -1
  498. package/dist/stock/.kosh/schema.d.ts +298 -2
  499. package/dist/stock/i18n/bn.d.ts +2 -0
  500. package/dist/stock/i18n/bn.js +311 -0
  501. package/dist/stock/index.d.ts +3 -1
  502. package/dist/stock/index.js +442 -3
  503. package/dist/stock/ledger.d.ts +78 -0
  504. package/dist/stock/ledger.js +582 -0
  505. package/dist/stock/module.d.ts +5280 -2044
  506. package/dist/stock/module.js +222 -23
  507. package/dist/stock/replenish.js +16 -1
  508. package/dist/stock/returns.d.ts +157 -0
  509. package/dist/stock/returns.js +163 -0
  510. package/dist/stock/web/Ledger.d.ts +9 -0
  511. package/dist/stock/web/Ledger.js +108 -0
  512. package/dist/stock/web/Operations.d.ts +8 -0
  513. package/dist/stock/web/Operations.js +33 -0
  514. package/dist/stock/web/ReturnButton.d.ts +7 -0
  515. package/dist/stock/web/ReturnButton.js +62 -0
  516. package/dist/stock/web/index.d.ts +3 -0
  517. package/dist/stock/web/index.js +9 -0
  518. package/dist/stock/web/messages.js +154 -0
  519. package/dist/stock_account/.kosh/bindings.js +1 -1
  520. package/dist/stock_account/.kosh/schema.d.ts +682 -9
  521. package/dist/stock_account/i18n/bn.d.ts +2 -0
  522. package/dist/stock_account/i18n/bn.js +73 -0
  523. package/dist/stock_account/index.d.ts +1 -0
  524. package/dist/stock_account/index.js +131 -3
  525. package/dist/stock_account/landed.d.ts +429 -0
  526. package/dist/stock_account/landed.js +335 -0
  527. package/dist/stock_account/module.d.ts +11247 -3363
  528. package/dist/stock_account/module.js +135 -6
  529. package/dist/stock_account/web/LandedPreview.d.ts +7 -0
  530. package/dist/stock_account/web/LandedPreview.js +23 -0
  531. package/dist/stock_account/web/index.d.ts +11 -0
  532. package/dist/stock_account/web/index.js +16 -0
  533. package/dist/stock_account/web/messages.d.ts +2 -0
  534. package/dist/stock_account/web/messages.js +27 -0
  535. package/dist/todo/i18n/bn.d.ts +2 -0
  536. package/dist/todo/i18n/bn.js +66 -0
  537. package/dist/todo/index.js +59 -0
  538. package/dist/todo/module.d.ts +5 -0
  539. package/dist/todo/module.js +5 -3
  540. package/dist/trade_finance/.kosh/bindings.js +1 -1
  541. package/dist/trade_finance/.kosh/schema.d.ts +2 -1
  542. package/dist/trade_finance/i18n/bn.d.ts +2 -0
  543. package/dist/trade_finance/i18n/bn.js +162 -0
  544. package/dist/trade_finance/index.js +93 -0
  545. package/dist/trade_finance/module.d.ts +26 -0
  546. package/dist/trade_finance/module.js +27 -8
  547. package/dist/trade_finance_account/.kosh/bindings.js +1 -1
  548. package/dist/trade_finance_account/.kosh/schema.d.ts +530 -8
  549. package/dist/trade_finance_account/i18n/bn.d.ts +2 -0
  550. package/dist/trade_finance_account/i18n/bn.js +27 -0
  551. package/dist/trade_finance_account/index.js +2 -0
  552. package/dist/trade_finance_account/module.d.ts +4906 -1432
  553. package/dist/trade_finance_account/module.js +1 -0
  554. package/dist/trade_finance_purchase/.kosh/bindings.js +1 -1
  555. package/dist/trade_finance_purchase/.kosh/schema.d.ts +813 -3
  556. package/dist/trade_finance_purchase/i18n/bn.d.ts +2 -0
  557. package/dist/trade_finance_purchase/i18n/bn.js +6 -0
  558. package/dist/trade_finance_purchase/index.js +2 -0
  559. package/dist/trade_finance_purchase/module.d.ts +6909 -413
  560. package/dist/trade_finance_sale/.kosh/bindings.js +1 -1
  561. package/dist/trade_finance_sale/.kosh/schema.d.ts +291 -4
  562. package/dist/trade_finance_sale/i18n/bn.d.ts +2 -0
  563. package/dist/trade_finance_sale/i18n/bn.js +6 -0
  564. package/dist/trade_finance_sale/index.js +2 -0
  565. package/dist/trade_finance_sale/module.d.ts +2601 -331
  566. package/dist/ui/api.d.ts +2 -0
  567. package/dist/ui/app.d.ts +9 -0
  568. package/dist/ui/app.js +24 -4
  569. package/dist/ui/components/AppIcon.js +2 -2
  570. package/dist/ui/components/Explain.d.ts +69 -0
  571. package/dist/ui/components/Explain.js +62 -0
  572. package/dist/ui/context.d.ts +8 -1
  573. package/dist/ui/context.js +34 -1
  574. package/dist/ui/i18n/messages.d.ts +36 -0
  575. package/dist/ui/i18n/messages.js +72 -0
  576. package/dist/ui/index.d.ts +2 -1
  577. package/dist/ui/index.js +1 -0
  578. package/dist/ui/registry.d.ts +14 -0
  579. package/dist/ui/registry.js +10 -0
  580. package/dist/ui/views/FormView.d.ts +6 -0
  581. package/dist/ui/views/FormView.js +47 -10
  582. package/dist/ui/views/ListView.d.ts +8 -0
  583. package/dist/ui/views/ListView.js +10 -3
  584. package/dist/ui/views/StatsRow.js +2 -1
  585. package/dist/views/extend.js +12 -0
  586. package/dist/views/types.d.ts +13 -2
  587. package/dist/views/validate.js +8 -1
  588. package/dist/website/.kosh/bindings.js +1 -1
  589. package/dist/website/.kosh/schema.d.ts +2 -1
  590. package/dist/website/i18n/bn.d.ts +2 -0
  591. package/dist/website/i18n/bn.js +113 -0
  592. package/dist/website/index.js +36 -0
  593. package/dist/website/module.d.ts +20 -0
  594. package/dist/website/module.js +29 -5
  595. package/dist/website_crm/.kosh/bindings.js +1 -1
  596. package/dist/website_crm/.kosh/schema.d.ts +2 -1
  597. package/dist/website_crm/i18n/bn.d.ts +2 -0
  598. package/dist/website_crm/i18n/bn.js +5 -0
  599. package/dist/website_crm/index.js +2 -0
  600. package/dist/website_crm/module.d.ts +40 -0
  601. package/dist/website_sale/.kosh/bindings.js +1 -1
  602. package/dist/website_sale/.kosh/schema.d.ts +642 -17
  603. package/dist/website_sale/i18n/bn.d.ts +2 -0
  604. package/dist/website_sale/i18n/bn.js +132 -0
  605. package/dist/website_sale/index.js +83 -1
  606. package/dist/website_sale/module.d.ts +18705 -5550
  607. package/dist/website_sale/module.js +32 -10
  608. package/dist/website_sale/shop.js +22 -9
  609. package/dist/website_sale_stock/.kosh/bindings.js +1 -1
  610. package/dist/website_sale_stock/.kosh/schema.d.ts +737 -18
  611. package/dist/website_sale_stock/i18n/bn.d.ts +2 -0
  612. package/dist/website_sale_stock/i18n/bn.js +4 -0
  613. package/dist/website_sale_stock/index.js +2 -0
  614. package/dist/website_sale_stock/module.d.ts +10 -24997
  615. package/dist/website_sale_stock/module.js +7 -3
  616. package/package.json +36 -8
  617. package/dist/mrp/index.d.ts +0 -3
  618. package/dist/mrp/index.js +0 -393
  619. package/dist/mrp/module.js +0 -757
  620. package/dist/mrp_account/index.d.ts +0 -3
  621. package/dist/mrp_account/index.js +0 -22
  622. /package/dist/{mrp → approvals_purchase}/.kosh/bindings.d.ts +0 -0
  623. /package/dist/{mrp_account → indent}/.kosh/bindings.d.ts +0 -0
@@ -5,12 +5,15 @@
5
5
  */
6
6
  import { contactsShutro } from '../contacts/index.js';
7
7
  import { messagingShutro } from '../messaging/index.js';
8
- import { computeTaxes, productShutro, taxRule } from '../product/index.js';
8
+ import { computeTaxes, priceFor, productShutro, taxRule } from '../product/index.js';
9
9
  import { orm } from '../server/orm.js';
10
- import { check, compute, defineModel, defineModule, extendModel, f, onchange, records, } from './.kosh/bindings.js';
10
+ import { check, compute, defineModel, defineModule, extendModel, f, method, onchange, records, } from './.kosh/bindings.js';
11
11
  /** A line's taxes through the engine (RFC 0016): its amount after discount, its taxes in order. */
12
12
  function taxesOf(l) {
13
- const amount = l.quantity.times(l.priceUnit).times(orm.toDecimal(100).minus(l.discount)).div(100);
13
+ const amount = l.quantity
14
+ .times(l.priceUnit ?? orm.toDecimal('0'))
15
+ .times(orm.toDecimal(100).minus(l.discount))
16
+ .div(100);
14
17
  return computeTaxes(amount, l.quantity, [...l.taxes].map(taxRule));
15
18
  }
16
19
  /** A monetary value's amount (a Money object or a plain Decimal), or null. */
@@ -63,20 +66,64 @@ export const SaleOrder = defineModel('sale.order', {
63
66
  label: 'Salesperson',
64
67
  }),
65
68
  partner: f.many2one('res.partner', { required: true, checkCompany: true, label: 'Customer' }),
69
+ /** Where the invoice goes and where the goods go (RFC 0028 §3.2); empty: the customer's own address. */
70
+ partnerInvoice: f.many2one('res.partner', {
71
+ checkCompany: true,
72
+ label: 'Invoice to',
73
+ help: 'The contact the invoice is addressed to; empty: the customer.',
74
+ }),
75
+ partnerShipping: f.many2one('res.partner', {
76
+ checkCompany: true,
77
+ label: 'Deliver to',
78
+ help: 'Where the goods go; empty: the customer’s address.',
79
+ }),
80
+ /** The price list its lines are priced by (RFC 0028 §3.1); from the customer, else none (list prices). */
81
+ pricelist: f.many2one('product.pricelist', {
82
+ ondelete: 'restrict',
83
+ label: 'Price list',
84
+ help: 'Lines without a price typed in are priced by this list; each line says why.',
85
+ }),
66
86
  currency: f.many2one('res.currency', { required: true }),
67
87
  dateOrder: f.date({ required: true, default: (env) => env.today(), label: 'Order date' }),
68
88
  validityDate: f.date({ label: 'Valid until' }),
69
89
  clientReference: f.char({ label: 'Customer reference' }),
70
90
  note: f.text({ label: 'Terms and conditions' }),
71
91
  lines: f.one2many('sale.order.line', 'order'),
72
- amountUntaxed: f.monetary({ currency: 'currency', store: true, label: 'Untaxed', ...amounts }),
73
- amountTax: f.monetary({ currency: 'currency', store: true, label: 'Taxes', ...amounts }),
74
- amountTotal: f.monetary({ currency: 'currency', store: true, label: 'Total', ...amounts }),
92
+ /** The quotation template it started from (RFC 0028 §3.5). */
93
+ template: f.many2one('sale.order.template', {
94
+ ondelete: 'set null',
95
+ label: 'Quotation template',
96
+ help: '“Fill from template” fills the quotation’s lines, options, validity and terms from it.',
97
+ }),
98
+ /** Optional products offered with the quotation; added as lines when the customer wants them. */
99
+ options: f.one2many('sale.order.option', 'order', { label: 'Optional products' }),
100
+ amountUntaxed: f.monetary({
101
+ currency: 'currency',
102
+ store: true,
103
+ label: 'Untaxed',
104
+ help: 'The sum of the lines’ amounts before taxes.',
105
+ ...amounts,
106
+ }),
107
+ amountTax: f.monetary({
108
+ currency: 'currency',
109
+ store: true,
110
+ label: 'Taxes',
111
+ help: 'The sum of the taxes on the lines.',
112
+ ...amounts,
113
+ }),
114
+ amountTotal: f.monetary({
115
+ currency: 'currency',
116
+ store: true,
117
+ label: 'Total',
118
+ help: 'What the customer pays: the untaxed amount plus the taxes.',
119
+ ...amounts,
120
+ }),
75
121
  /** RFC 0022 step 2: what the order earns — the lines' untaxed amounts less their products' cost. */
76
122
  margin: f.monetary({
77
123
  currency: 'currency',
78
124
  store: true,
79
125
  label: 'Margin',
126
+ help: 'What the order earns: its lines’ untaxed amounts less their products’ cost.',
80
127
  ...compute('sale.order', 'margin', ['lines.margin', 'currency'], (orders) => {
81
128
  for (const o of orders)
82
129
  o.margin = o.currency === null ? null : o.lines.sum('margin', o.currency);
@@ -86,6 +133,7 @@ export const SaleOrder = defineModel('sale.order', {
86
133
  scale: 1,
87
134
  store: true,
88
135
  label: 'Margin (%)',
136
+ help: 'The margin as a percentage of the untaxed amount.',
89
137
  ...compute('sale.order', 'marginPercent', ['margin', 'amountUntaxed'], (orders) => {
90
138
  for (const o of orders) {
91
139
  const untaxed = amountOf(o.amountUntaxed);
@@ -98,6 +146,7 @@ export const SaleOrder = defineModel('sale.order', {
98
146
  }),
99
147
  }),
100
148
  state: f.state({
149
+ help: 'A quotation until it is confirmed as a sales order, which can then be locked or cancelled.',
101
150
  states: {
102
151
  draft: 'Quotation',
103
152
  sent: 'Quotation sent',
@@ -108,6 +157,54 @@ export const SaleOrder = defineModel('sale.order', {
108
157
  initial: 'draft',
109
158
  transitions: {
110
159
  send: { from: ['draft'], to: 'sent' },
160
+ // A quotation filled from its template (RFC 0028 §3.5): lines, options, validity, terms.
161
+ fill: {
162
+ from: ['draft'],
163
+ to: 'draft',
164
+ guard: records('sale.order', async (orders) => (await orders.load({ template: true })).filter((o) => o.template === null)),
165
+ message: 'Choose a quotation template first.',
166
+ after: records('sale.order', async (orders) => {
167
+ const env = orders.env;
168
+ for (const o of await orders.load({ template: { lines: { product: true } } })) {
169
+ const t = o.template;
170
+ if (t === null)
171
+ continue;
172
+ const rows = [...t.lines].sort((a, b) => (a.sequence ?? 10) - (b.sequence ?? 10));
173
+ const lines = rows.filter((r) => r.optional !== true);
174
+ const options = rows.filter((r) => r.optional === true);
175
+ if (lines.length > 0)
176
+ await env.model('sale.order.line').create(lines.map((r) => ({
177
+ order: o.id,
178
+ product: r.product.id,
179
+ name: r.name,
180
+ quantity: r.quantity,
181
+ })));
182
+ if (options.length > 0)
183
+ await env.model('sale.order.option').create(options.map((r) => ({
184
+ order: o.id,
185
+ product: r.product.id,
186
+ name: r.name,
187
+ quantity: r.quantity,
188
+ })));
189
+ const days = t.validityDays ?? 0;
190
+ const date = String(o.dateOrder).slice(0, 10);
191
+ const [y, m, day] = date.split('-').map(Number);
192
+ await env
193
+ .model('sale.order')
194
+ .browse([o.id])
195
+ .write({
196
+ ...(days > 0
197
+ ? {
198
+ validityDate: new Date(Date.UTC(y, m - 1, day + days))
199
+ .toISOString()
200
+ .slice(0, 10),
201
+ }
202
+ : {}),
203
+ ...(t.note !== null && t.note !== '' ? { note: t.note } : {}),
204
+ });
205
+ }
206
+ }),
207
+ },
111
208
  confirm: {
112
209
  from: ['draft', 'sent'],
113
210
  to: 'sale',
@@ -116,6 +213,11 @@ export const SaleOrder = defineModel('sale.order', {
116
213
  return loaded.filter((o) => o.lines.length === 0);
117
214
  }),
118
215
  message: 'Add at least one line before confirming the order.',
216
+ // Other apps check the order first (sale_account: the customer's credit).
217
+ before: records('sale.order', async (orders) => {
218
+ const env = orders.env;
219
+ await env.model('sale.order').browse(orders.ids).confirming();
220
+ }),
119
221
  // Other apps act on a confirmation through the outbox (sale_project creates the tasks).
120
222
  after: records('sale.order', async (orders) => {
121
223
  for (const o of await orders.load({}))
@@ -124,17 +226,40 @@ export const SaleOrder = defineModel('sale.order', {
124
226
  },
125
227
  lock: { from: ['sale'], to: 'done' },
126
228
  unlock: { from: ['done'], to: 'sale' },
127
- cancel: { from: ['draft', 'sent', 'sale'], to: 'cancel' },
229
+ cancel: {
230
+ from: ['draft', 'sent', 'sale'],
231
+ to: 'cancel',
232
+ // Other apps follow a cancellation through the outbox (sale_crm: a deal with every quotation cancelled).
233
+ after: records('sale.order', async (orders) => {
234
+ for (const o of await orders.load({}))
235
+ await orders.env.emit('sale.order.cancelled', { id: o.id });
236
+ }),
237
+ },
128
238
  redraft: { from: ['cancel'], to: 'draft' },
129
239
  },
130
240
  extensible: true, // Accounting adds invoicing states through its bridge
131
241
  }),
132
242
  },
243
+ methods: {
244
+ /** Before a confirmation: nothing here; sale_account checks the customer's credit (RFC 0028 §3.2). */
245
+ confirming: method('sale.order', async () => undefined),
246
+ },
133
247
  onchange: {
134
248
  // The customer's currency, else the company's; an empty validity and terms from the company's settings.
135
249
  partner: onchange('sale.order', async (d, env) => {
136
250
  await quotationDefaults(d, env);
137
251
  const p = await d.record('partner');
252
+ const [priced] = p === null
253
+ ? []
254
+ : await env
255
+ .model('res.partner')
256
+ .browse([p.id])
257
+ .load({ pricelist: { currency: true } });
258
+ d.set('pricelist', priced?.pricelist?.id ?? null);
259
+ if (priced?.pricelist?.currency) {
260
+ d.set('currency', priced.pricelist.currency.id);
261
+ return;
262
+ }
138
263
  if (p?.currency) {
139
264
  d.set('currency', p.currency.id);
140
265
  return;
@@ -146,6 +271,12 @@ export const SaleOrder = defineModel('sale.order', {
146
271
  if (company !== undefined)
147
272
  d.set('currency', company.currency.id);
148
273
  }),
274
+ // A price list in another currency puts the order in it.
275
+ pricelist: onchange('sale.order', async (d) => {
276
+ const list = await d.record('pricelist');
277
+ if (list?.currency)
278
+ d.set('currency', list.currency.id);
279
+ }),
149
280
  // A new order date moves the validity with it.
150
281
  dateOrder: onchange('sale.order', async (d, env) => {
151
282
  d.set('validityDate', null);
@@ -173,6 +304,16 @@ async function quotationDefaults(d, env) {
173
304
  if ((d.get('note') ?? '') === '' && typeof terms === 'string' && terms !== '')
174
305
  d.set('note', terms);
175
306
  }
307
+ /** A line's price and why (RFC 0028 §3.1): typed in, else its order's price list, else the list price. */
308
+ async function linePrice(l) {
309
+ if (l.manualPrice !== null)
310
+ return { price: l.manualPrice, reason: 'Typed in.' };
311
+ if (l.product === null)
312
+ return { price: orm.toDecimal('0'), reason: null };
313
+ const env = l.env;
314
+ const found = await priceFor(l.env, l.order?.pricelist?.id ?? null, l.product.id, l.quantity, String(l.order?.dateOrder ?? env.today()).slice(0, 10));
315
+ return { price: found.price, reason: found.explanation };
316
+ }
176
317
  export const SaleOrderLine = defineModel('sale.order.line', {
177
318
  label: 'Order line',
178
319
  access: {
@@ -185,7 +326,43 @@ export const SaleOrderLine = defineModel('sale.order.line', {
185
326
  name: f.char({ required: true, label: 'Description' }),
186
327
  quantity: f.decimal({ scale: 3, required: true, default: '1' }),
187
328
  uom: f.many2one('uom.uom', { label: 'Unit' }),
188
- priceUnit: f.decimal({ scale: 2, required: true, default: '0', label: 'Unit price' }),
329
+ /**
330
+ * The unit price: the one typed in, else the order's price list's (RFC 0028 §3.1). Typing a price keeps it
331
+ * (`manualPrice`); changing the product, the quantity or the list reprices the lines without one.
332
+ */
333
+ priceUnit: f.decimal({
334
+ scale: 2,
335
+ store: true,
336
+ label: 'Unit price',
337
+ help: 'The price typed in, else the order’s price list’s (see why on the line), else the product’s list price.',
338
+ ...compute('sale.order.line', 'priceUnit', ['product', 'quantity', 'manualPrice', 'order.pricelist', 'order.dateOrder'], async (lines) => {
339
+ for (const l of lines)
340
+ l.priceUnit = (await linePrice(l)).price;
341
+ }),
342
+ inverse: async (records) => {
343
+ const lines = records;
344
+ const env = records.env;
345
+ // Who may set prices by hand (RFC 0028 §3.1): the server decides.
346
+ if (!env.su && !env.access.has('sales.price_override'))
347
+ throw new orm.ValidationError('sale.order.line', ['priceUnit'], 'You may not change prices.', 'Prices come from the price list; ask a Sales manager.');
348
+ for (const l of lines)
349
+ await env
350
+ .model('sale.order.line')
351
+ .browse([l.id])
352
+ .write({ manualPrice: l.priceUnit });
353
+ },
354
+ }),
355
+ /** The price typed in, kept when the product, the quantity or the list changes (empty: the list's price). */
356
+ manualPrice: f.decimal({ scale: 2, label: 'Price typed in' }),
357
+ /** Why the line has its price: the list and rule, or "typed in". */
358
+ priceReason: f.char({
359
+ store: true,
360
+ label: 'Why this price',
361
+ ...compute('sale.order.line', 'priceReason', ['product', 'quantity', 'manualPrice', 'order.pricelist', 'order.dateOrder'], async (lines) => {
362
+ for (const l of lines)
363
+ l.priceReason = (await linePrice(l)).reason;
364
+ }),
365
+ }),
189
366
  /** Percent off the unit price (0–100). */
190
367
  discount: f.decimal({ scale: 2, required: true, default: '0', label: 'Discount %' }),
191
368
  /** The line's taxes, applied in order (RFC 0016). */
@@ -203,6 +380,7 @@ export const SaleOrderLine = defineModel('sale.order.line', {
203
380
  subtotal: f.monetary({
204
381
  currency: 'currency',
205
382
  store: true,
383
+ help: 'The line’s amount before taxes: the quantity times the unit price, less the discount and any tax included in the price.',
206
384
  ...compute('sale.order.line', 'subtotal', [
207
385
  'quantity',
208
386
  'priceUnit',
@@ -224,6 +402,7 @@ export const SaleOrderLine = defineModel('sale.order.line', {
224
402
  currency: 'currency',
225
403
  store: true,
226
404
  label: 'Margin',
405
+ help: 'What the line earns: its untaxed amount less its product’s cost for the quantity.',
227
406
  ...compute('sale.order.line', 'margin', ['subtotal', 'quantity', 'product.standardPrice'], (lines) => {
228
407
  for (const l of lines) {
229
408
  const untaxed = amountOf(l.subtotal);
@@ -238,6 +417,7 @@ export const SaleOrderLine = defineModel('sale.order.line', {
238
417
  currency: 'currency',
239
418
  store: true,
240
419
  label: 'Tax',
420
+ help: 'The taxes on this line, computed from its amount and its taxes.',
241
421
  ...compute('sale.order.line', 'taxAmount', [
242
422
  'quantity',
243
423
  'priceUnit',
@@ -279,10 +459,118 @@ export const SaleOrderLine = defineModel('sale.order.line', {
279
459
  },
280
460
  },
281
461
  });
462
+ /** A quotation template (RFC 0028 §3.5): lines and optional products, validity and terms. */
463
+ export const SaleOrderTemplate = defineModel('sale.order.template', {
464
+ label: 'Quotation template',
465
+ archivable: true,
466
+ order: ['name asc'],
467
+ access: {
468
+ 'sales.user': ['read'],
469
+ 'sales.manager': ['read', 'write', 'create', 'unlink', 'export', 'import'],
470
+ },
471
+ fields: {
472
+ name: f.char({ required: true, translate: true }),
473
+ validityDays: f.integer({
474
+ default: 0,
475
+ label: 'Valid for (days)',
476
+ help: 'The quotation is valid until its date plus these days; 0 keeps the quotation’s own.',
477
+ }),
478
+ note: f.text({ label: 'Terms and conditions' }),
479
+ lines: f.one2many('sale.order.template.line', 'template', { label: 'Lines' }),
480
+ },
481
+ });
482
+ export const SaleOrderTemplateLine = defineModel('sale.order.template.line', {
483
+ label: 'Template line',
484
+ order: ['template asc', 'sequence asc', 'id asc'],
485
+ access: {
486
+ 'sales.user': ['read'],
487
+ 'sales.manager': ['read', 'write', 'create', 'unlink'],
488
+ },
489
+ fields: {
490
+ template: f.many2one('sale.order.template', { required: true, ondelete: 'cascade' }),
491
+ sequence: f.integer({ default: 10 }),
492
+ product: f.many2one('product.product', { required: true }),
493
+ name: f.char({ required: true, label: 'Description' }),
494
+ quantity: f.decimal({ scale: 3, required: true, default: '1' }),
495
+ optional: f.boolean({
496
+ default: false,
497
+ label: 'Optional',
498
+ help: 'Offered with the quotation; the customer adds it, or not.',
499
+ }),
500
+ },
501
+ });
502
+ /** An optional product offered with a quotation (RFC 0028 §3.5); added, it becomes a line, once. */
503
+ export const SaleOrderOption = defineModel('sale.order.option', {
504
+ label: 'Optional product',
505
+ order: ['order asc', 'id asc'],
506
+ access: {
507
+ 'sales.user': ['read', 'write', 'create', 'unlink'],
508
+ 'sales.manager': ['read', 'write', 'create', 'unlink'],
509
+ },
510
+ fields: {
511
+ order: f.many2one('sale.order', { required: true, ondelete: 'cascade' }),
512
+ product: f.many2one('product.product', { required: true }),
513
+ name: f.char({ required: true, label: 'Description' }),
514
+ quantity: f.decimal({ scale: 3, required: true, default: '1' }),
515
+ /** Empty: the order's price list prices the line. */
516
+ priceUnit: f.decimal({ scale: 2, label: 'Unit price' }),
517
+ line: f.many2one('sale.order.line', { ondelete: 'set null', label: 'Added as' }),
518
+ state: f.state({
519
+ help: 'Offered until it is added to the quotation as a line.',
520
+ states: { offered: 'Offered', added: 'Added' },
521
+ initial: 'offered',
522
+ transitions: {
523
+ // Added while the quotation is open: a line, priced by the list unless the option has a price.
524
+ add: {
525
+ from: ['offered'],
526
+ to: 'added',
527
+ guard: records('sale.order.option', async (options) => (await options.load({ order: true })).filter((o) => o.order.state !== 'draft' && o.order.state !== 'sent')),
528
+ message: 'Options are added while the quotation is open.',
529
+ after: records('sale.order.option', async (options) => {
530
+ const env = options.env;
531
+ for (const o of await options.load({})) {
532
+ const made = await env.asSuperuser({ reason: 'option added' }, (su) => su.model('sale.order.line').create([
533
+ {
534
+ order: o.order.id,
535
+ product: o.product.id,
536
+ name: o.name,
537
+ quantity: o.quantity,
538
+ ...(o.priceUnit === null ? {} : { priceUnit: o.priceUnit }),
539
+ },
540
+ ]));
541
+ await env
542
+ .model('sale.order.option')
543
+ .browse([o.id])
544
+ .write({ line: made.ids[0] });
545
+ }
546
+ }),
547
+ },
548
+ },
549
+ }),
550
+ },
551
+ });
552
+ /** The customer's price list (RFC 0028 §3.1): their orders start on it. */
553
+ export const PartnerPricelist = extendModel('res.partner', {
554
+ fields: {
555
+ pricelist: f.many2one('product.pricelist', {
556
+ ondelete: 'set null',
557
+ label: 'Price list',
558
+ help: 'Orders for this customer start on this price list.',
559
+ }),
560
+ },
561
+ });
282
562
  export const salesShutro = defineModule({
283
563
  name: 'sales',
284
- version: '0.3.0',
564
+ version: '0.5.0',
285
565
  migrations: [
566
+ {
567
+ version: '0.4.0',
568
+ description: 'Price lists: existing lines keep the price they have, as typed in (no order is repriced)',
569
+ up: async (ctx) => {
570
+ await ctx.sql `UPDATE sale_order_line SET manual_price = price_unit WHERE manual_price IS NULL`;
571
+ await ctx.sql `UPDATE sale_order_line SET price_reason = 'Typed in.' WHERE price_reason IS NULL`;
572
+ },
573
+ },
286
574
  {
287
575
  version: '0.2.0',
288
576
  description: 'Several taxes per line: the single tax of each line becomes its first',
@@ -301,9 +589,16 @@ export const salesShutro = defineModule({
301
589
  }),
302
590
  orm.defineGroup({ code: 'sales.manager', label: 'Sales manager', implies: ['sales.user'] }),
303
591
  ],
592
+ permissions: [
593
+ orm.definePermission({
594
+ code: 'sales.price_override',
595
+ label: 'Type in prices on order lines (instead of the price list)',
596
+ groups: ['sales.user'],
597
+ }),
598
+ ],
304
599
  sequences: [
305
600
  orm.defineSequence({ code: 'sale.order', prefix: 'SO/{year}/', padding: 5, reset: 'yearly' }),
306
601
  ],
307
- models: [SaleOrder, SaleOrderLine],
308
- extensions: [CompanySales],
602
+ models: [SaleOrder, SaleOrderLine, SaleOrderTemplate, SaleOrderTemplateLine, SaleOrderOption],
603
+ extensions: [CompanySales, PartnerPricelist],
309
604
  });
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Duplicate (RFC 0023 R1, §3.2): a copy of a record made **as the user** (ACL, record rules and field groups decide)
3
+ * from the model's metadata — Shutro has no `copy()` yet (docs/shutro-requests.md #32):
4
+ * - stored, writable fields are copied; many2one kept, many2many as the same set;
5
+ * - states, sequences and computed fields start again (they are read-only, so not copied);
6
+ * - a field in a unique constraint (beside the company) is left out, or for a required text gets " (copy)";
7
+ * - one2many lines are copied with the record, each line by the same rules, without the link back.
8
+ */
9
+ import type { Env } from '../orm.js';
10
+ import type { ApiModel } from './metadata.js';
11
+ type Row = Record<string, unknown>;
12
+ /** The record's copy (as the API takes values), with its lines. */
13
+ export declare function duplicateValues(env: Env, models: ReadonlyMap<string, ApiModel>, model: ApiModel, id: number): Promise<Row>;
14
+ export {};
@@ -0,0 +1,75 @@
1
+ const ref = (env, name) => env.model(name);
2
+ /** Whether a field's value is copied as such. */
3
+ const copied = (env, model, f) => f.stored &&
4
+ !f.readonly &&
5
+ f.kind !== 'one2many' &&
6
+ f.kind !== 'binary' &&
7
+ env.access.canField(model.name, f.key, 'read') &&
8
+ env.access.canField(model.name, f.key, 'write');
9
+ /** The fields of the model's unique constraints, the company aside. */
10
+ const uniqueKeys = (model) => new Set(model.unique.flat().filter((k) => k !== 'company'));
11
+ async function valuesOf(env, model, id, skip, rename) {
12
+ const fields = model.fields.filter((f) => copied(env, model, f) && f.key !== skip);
13
+ const scalar = fields.filter((f) => f.kind !== 'many2many').map((f) => f.key);
14
+ const sets = fields.filter((f) => f.kind === 'many2many').map((f) => f.key);
15
+ let loaded = await ref(env, model.name)
16
+ .browse([id])
17
+ .load(['id', ...scalar]);
18
+ if (sets.length > 0)
19
+ loaded = await loaded.load(Object.fromEntries(sets.map((k) => [k, true])));
20
+ const [row] = loaded.read(['id', ...fields.map((f) => f.key)]);
21
+ if (row === undefined)
22
+ return {};
23
+ const unique = uniqueKeys(model);
24
+ const out = {};
25
+ for (const f of fields) {
26
+ const value = row[f.key];
27
+ if (value === null || value === undefined)
28
+ continue;
29
+ if (unique.has(f.key)) {
30
+ if (rename &&
31
+ f.required &&
32
+ (f.kind === 'char' || f.kind === 'text') &&
33
+ typeof value === 'string')
34
+ out[f.key] = `${value} (copy)`;
35
+ continue;
36
+ }
37
+ if (f.kind === 'many2one')
38
+ out[f.key] = typeof value === 'object' ? value.id : value;
39
+ else if (f.kind === 'many2many')
40
+ out[f.key] = {
41
+ set: value.map((v) => typeof v === 'object' && v !== null ? v.id : v),
42
+ };
43
+ else
44
+ out[f.key] = value;
45
+ }
46
+ return out;
47
+ }
48
+ /** The record's copy (as the API takes values), with its lines. */
49
+ export async function duplicateValues(env, models, model, id) {
50
+ const values = await valuesOf(env, model, id, null, true);
51
+ for (const f of model.fields) {
52
+ if (f.kind !== 'one2many' || f.readonly || f.target === null)
53
+ continue;
54
+ if (!env.access.canField(model.name, f.key, 'write'))
55
+ continue;
56
+ const lines = models.get(f.target);
57
+ if (lines === undefined || !env.access.can(f.target, 'create'))
58
+ continue;
59
+ // The lines' link back: their many2one to this model that is required.
60
+ const back = lines.fields.find((x) => x.kind === 'many2one' && x.target === model.name && x.required);
61
+ if (back === undefined)
62
+ continue;
63
+ const [parent] = (await ref(env, model.name)
64
+ .browse([id])
65
+ .load({ [f.key]: true })).read([f.key]);
66
+ const lineIds = (parent?.[f.key] ?? []).map((v) => typeof v === 'object' && v !== null ? Number(v.id) : Number(v));
67
+ if (lineIds.length === 0)
68
+ continue;
69
+ const create = [];
70
+ for (const lineId of lineIds)
71
+ create.push(await valuesOf(env, lines, lineId, back.key, false));
72
+ values[f.key] = { create };
73
+ }
74
+ return values;
75
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Explain (RFC 0031 §3.1): what a model, its fields and its buttons are, for developers and administrators — the
3
+ * facts behind the dark popovers of Developer mode. Where each field comes from (the module that defined the model,
4
+ * or the one that extended it), what it points to (and, for a one-to-many, through which field), whether it is
5
+ * stored or computed and from what, its default, its rules; each transition's states and guard; and every relation
6
+ * into the model from the other served models.
7
+ *
8
+ * - `GET /api/v1/meta/explain/:model` administrators and `base.developer` only
9
+ */
10
+ import type { FastifyInstance } from 'fastify';
11
+ import type { KoshRegistry } from '../registry.js';
12
+ import type { ApiModel } from './metadata.js';
13
+ /** One field, explained. */
14
+ export interface ExplainedField {
15
+ readonly key: string;
16
+ readonly label: string;
17
+ readonly kind: string;
18
+ readonly help: string | null;
19
+ readonly target: string | null;
20
+ /** For a one-to-many: the field of the target that points back. */
21
+ readonly inverse: string | null;
22
+ readonly required: boolean;
23
+ readonly readonly: boolean;
24
+ readonly stored: boolean;
25
+ readonly computed: boolean;
26
+ /** What a computed field is computed from. */
27
+ readonly depends: readonly string[];
28
+ readonly hasDefault: boolean;
29
+ readonly default: string | null;
30
+ readonly ondelete: string | null;
31
+ readonly translate: boolean;
32
+ readonly index: boolean;
33
+ readonly options: readonly (readonly [string, string])[] | null;
34
+ /** The module whose model or extension declares it. */
35
+ readonly module: string | null;
36
+ }
37
+ /** One transition, explained. */
38
+ export interface ExplainedTransition {
39
+ readonly name: string;
40
+ readonly field: string;
41
+ readonly from: readonly string[];
42
+ readonly to: string;
43
+ readonly guarded: boolean;
44
+ readonly message: string | null;
45
+ readonly requires: string | null;
46
+ }
47
+ /** A model, explained. */
48
+ export interface Explained {
49
+ readonly model: string;
50
+ readonly label: string;
51
+ readonly module: string | null;
52
+ readonly extendedBy: readonly string[];
53
+ readonly fields: readonly ExplainedField[];
54
+ readonly transitions: readonly ExplainedTransition[];
55
+ /** The relations of other models into this one. */
56
+ readonly incoming: readonly {
57
+ readonly model: string;
58
+ readonly field: string;
59
+ readonly label: string;
60
+ readonly kind: string;
61
+ }[];
62
+ }
63
+ /** A model explained, from the registry and the API metadata. */
64
+ export declare function explainModel(registry: KoshRegistry, models: ReadonlyMap<string, ApiModel>, name: string): Explained | null;
65
+ /** The group that may read explanations besides administrators. */
66
+ export declare const DEVELOPER_GROUP = "base.developer";
67
+ export declare function registerExplain(app: FastifyInstance, options: {
68
+ readonly registry: KoshRegistry;
69
+ readonly models: ReadonlyMap<string, ApiModel>;
70
+ }): void;