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
@@ -10,17 +10,25 @@
10
10
  * - `GET /api/v1/public/approvals/:token` the confirmation page of an email link
11
11
  * - `POST /api/v1/public/approvals/:token` `{ decision: approve | reject | send_back, comment? }`, once
12
12
  * - `POST /api/v1/approvals/deadlines/run` reminders and escalations now (Approvals managers; hourly too)
13
+ * - `POST /api/v1/approvals/categories/:id/policy` a request category's policy, made when missing (Approvals managers)
14
+ * - `GET /api/v1/approvals/policies/:id/preview` which of the last 50 records each level would have asked about
15
+ *
16
+ * **Generic requests** (step 4): categories say what a request asks for and what it leads to; a request is decided
17
+ * through its category's policy, and its outcome runs when approved.
13
18
  */
14
19
  import { randomBytes } from 'node:crypto';
20
+ import { contacts } from '../contacts/index.js';
15
21
  import { mailerFromEnv } from '../mail/index.js';
16
22
  import { defineModule } from '../modules-sdk/index.js';
17
- import { decide, groupsOf, linkOf, permissions, sweepDeadlines, useLink, } from '../permissions/index.js';
23
+ import { APPROVER_KEYS, decide, groupsOf, linkOf, permissions, previewPolicy, sweepDeadlines, syncLevels, turnOf, useLink, } from '../permissions/index.js';
24
+ import { reporting } from '../reporting/index.js';
18
25
  import { digest, HttpProblem } from '../server/index.js';
19
- import { form, list, search } from '../views/index.js';
26
+ import { action, form, kanban, list, search } from '../views/index.js';
27
+ import { approvalsDemo } from './demo.js';
20
28
  import { configureMails, mailDeciders, mailTurn } from './mails.js';
21
- import { approvalsShutro } from './module.js';
29
+ import { ApprovalAsk, ApprovalCategory, approvalsShutro, ensureCategoryPolicy } from './module.js';
22
30
  export { mailDeciders, mailTurn } from './mails.js';
23
- export { approvalsShutro } from './module.js';
31
+ export { ApprovalAsk, ApprovalAskLine, ApprovalCategory, approvalsShutro, ensureCategoryPolicy, missingFields, outcomesOffered, } from './module.js';
24
32
  const escapeHtml = (s) => s.replace(/[&<>"']/g, (c) => `&#${c.charCodeAt(0)};`);
25
33
  const DECISIONS = new Set(['approve', 'reject', 'send_back']);
26
34
  /** The subscribers that email a record's approvers when its approvals are asked and when a level is approved. */
@@ -35,11 +43,52 @@ export function approvalMailWorkers(context) {
35
43
  return;
36
44
  await env.asSuperuser({ reason: 'approval emails' }, (su) => mailTurn(su, model, id));
37
45
  }, { pollMs: 5000 });
46
+ // The people added to a waiting request (reassigned) and a request's backups (told): their own links.
47
+ const only = (name, topic, why) => context.shutro.subscribe(name, topic, async (event, env) => {
48
+ const p = (event.payload ?? {});
49
+ const id = Number(p['request']);
50
+ const users = Array.isArray(p['users']) ? p['users'] : [];
51
+ if (!Number.isSafeInteger(id) || users.length === 0)
52
+ return;
53
+ await env.asSuperuser({ reason: 'approval emails' }, async (su) => {
54
+ const [request] = (await turnOfRequest(su, id)) ?? [];
55
+ if (request !== undefined)
56
+ await mailDeciders(su, [request], why, users);
57
+ });
58
+ }, { pollMs: 5000 });
59
+ // Waiting requests follow their level's approvers (RFC 0027 §2.6): Shutro's change events of approval levels.
60
+ const sync = context.shutro.subscribe('approvals.sync', 'record.changed', async (event, env) => {
61
+ const p = (event.payload ?? {});
62
+ if (p['model'] !== 'approval.level' || p['action'] !== 'write')
63
+ return;
64
+ const keys = Array.isArray(p['keys']) ? p['keys'] : [];
65
+ if (!keys.some((k) => APPROVER_KEYS.includes(k)))
66
+ return;
67
+ const ids = (Array.isArray(p['ids']) ? p['ids'] : []).filter((i) => Number.isSafeInteger(i));
68
+ await env.asSuperuser({ reason: 'approval sync' }, async (su) => {
69
+ for (const done of await syncLevels(su, ids))
70
+ if (done.notify && done.added.length > 0)
71
+ await mailDeciders(su, [done.request], 'added', done.added);
72
+ });
73
+ }, { pollMs: 5000 });
38
74
  return [
39
75
  turn('approvals.asked', 'approval.requested'),
40
76
  turn('approvals.next', 'approval.decided'),
77
+ only('approvals.reassigned', 'approval.reassigned', 'added'),
78
+ only('approvals.backups', 'approval.backups', 'backup'),
79
+ sync,
41
80
  ];
42
81
  }
82
+ /** One request by id, while it waits (for the emails). */
83
+ async function turnOfRequest(su, id) {
84
+ const found = await su.model('approval.request').search({ where: { id, state: 'pending' }, limit: 1 });
85
+ if (found.length === 0)
86
+ return undefined;
87
+ const [row] = (await found.load(['targetModel', 'targetId'])).read(['targetModel', 'targetId']);
88
+ if (row === undefined)
89
+ return undefined;
90
+ return (await turnOf(su, String(row['targetModel']), Number(row['targetId']))).filter((r) => r.id === id);
91
+ }
43
92
  /** Reminders and escalations, then their emails (as the system). */
44
93
  async function runDeadlines(su) {
45
94
  const done = await sweepDeadlines(su);
@@ -51,6 +100,61 @@ async function runDeadlines(su) {
51
100
  }
52
101
  function registerApprovalAppRoutes(context) {
53
102
  const { app, shutro } = context;
103
+ const managersOnly = (env) => {
104
+ if (!env.administrator && !env.groups.has('approvals.manager'))
105
+ throw new HttpProblem(403, 'access', 'Approvals managers', 'This needs the Approvals manager role.');
106
+ };
107
+ const idParam = (params) => {
108
+ const id = Number(params['id']);
109
+ if (!Number.isSafeInteger(id) || id <= 0)
110
+ throw new HttpProblem(404, 'missing-record', 'Not found', 'No such record.');
111
+ return id;
112
+ };
113
+ app.post('/api/v1/approvals/categories/:id/policy', async (request) => {
114
+ const id = idParam(request.params);
115
+ return request.env(async (raw) => {
116
+ const env = raw;
117
+ managersOnly(env);
118
+ return env.asSuperuser({ reason: 'request category policy' }, async (su) => ({
119
+ policy: await ensureCategoryPolicy(su, id),
120
+ }));
121
+ }, { write: true });
122
+ });
123
+ app.get('/api/v1/approvals/policies/:id/preview', async (request) => {
124
+ const id = idParam(request.params);
125
+ return request.env(async (raw) => {
126
+ const env = raw;
127
+ managersOnly(env);
128
+ return env.asSuperuser({ reason: 'approval policy preview' }, (su) => previewPolicy(su, id));
129
+ }, { write: true });
130
+ });
131
+ // `POST /api/v1/approvals/policies/:id/sync` `{ mode? }`: "Sync now" — the policy's waiting requests get their
132
+ // approvers found again (RFC 0027 §2.6), adding unless the body or the policy says replace.
133
+ app.post('/api/v1/approvals/policies/:id/sync', async (request) => {
134
+ const id = idParam(request.params);
135
+ const mode = request.body?.mode;
136
+ if (mode !== undefined && mode !== 'add' && mode !== 'replace')
137
+ throw new HttpProblem(400, 'invalid-body', 'Invalid body', "mode is 'add' or 'replace'.");
138
+ return request.env(async (raw) => {
139
+ const env = raw;
140
+ managersOnly(env);
141
+ return env.asSuperuser({ reason: 'approval sync' }, async (su) => {
142
+ const levels = await (await su.model('approval.level').search({ where: { policy: id } })).ids;
143
+ const [policy] = await (await su.model('approval.policy').search({ where: { id }, limit: 1 }))
144
+ .load(['syncPending'])
145
+ .then((r) => r.read(['syncPending']));
146
+ if (policy === undefined)
147
+ throw new HttpProblem(404, 'missing-record', 'Not found', 'No such policy.');
148
+ const how = mode ??
149
+ (policy['syncPending'] === 'replace' ? 'replace' : 'add');
150
+ const done = await syncLevels(su, levels, how);
151
+ for (const d of done)
152
+ if (d.notify && d.added.length > 0)
153
+ await mailDeciders(su, [d.request], 'added', d.added);
154
+ return { synced: done.length };
155
+ });
156
+ });
157
+ });
54
158
  const tokenOf = (params) => String(params['token'] ?? '');
55
159
  const linkFor = (token) => shutro.bootstrap({ reason: 'approval link' }, (raw) => raw.asSuperuser({ reason: 'approval link' }, async (su) => {
56
160
  const link = await linkOf(su.withFlags({ checkCompany: false }), digest(token));
@@ -154,7 +258,8 @@ export function approvalsModule(options = {}) {
154
258
  return defineModule({
155
259
  shutro: approvalsShutro,
156
260
  kosh: '^0.1.0',
157
- depends: [permissions],
261
+ hooks: { demo: approvalsDemo },
262
+ depends: [permissions, contacts, reporting],
158
263
  app: {
159
264
  code: 'approvals',
160
265
  label: 'Approvals',
@@ -163,6 +268,92 @@ export function approvalsModule(options = {}) {
163
268
  category: 'Productivity',
164
269
  summary: 'Everything waiting for your decision, in one place — and what you asked for',
165
270
  },
271
+ importTemplates: [
272
+ {
273
+ key: 'approval_ask',
274
+ model: 'approval.ask',
275
+ label: 'Request',
276
+ columns: [
277
+ { header: 'Category', field: 'category' },
278
+ { header: 'What for', field: 'title' },
279
+ { header: 'Asked by', field: 'requester' },
280
+ { header: 'Description', field: 'description' },
281
+ { header: 'Amount', field: 'amount' },
282
+ { header: 'From', field: 'dateFrom' },
283
+ { header: 'Until', field: 'dateTo' },
284
+ { header: 'Contact', field: 'partner' },
285
+ { header: 'Location', field: 'location' },
286
+ { header: 'Quantity', field: 'quantity' },
287
+ { header: 'Lines › Description', field: 'lines.name' },
288
+ { header: 'Lines › Quantity', field: 'lines.quantity' },
289
+ { header: 'Lines › Unit price', field: 'lines.priceUnit' },
290
+ ],
291
+ },
292
+ ],
293
+ events: [{ topic: 'approval.ask.approved', model: 'approval.ask', label: 'Request approved' }],
294
+ // Bangla for the labels it serves (RFC 0023 §3.1; `pnpm i18n:extract`).
295
+ i18n: { bn: () => import('./i18n/bn.js') },
296
+ overview: {
297
+ cards: [
298
+ {
299
+ id: 'waiting',
300
+ title: 'Requests waiting',
301
+ kind: 'kpi',
302
+ model: 'approval.ask',
303
+ measure: 'count',
304
+ filter: { state: 'submitted' },
305
+ w: 3,
306
+ },
307
+ {
308
+ id: 'approved',
309
+ title: 'Approved this month',
310
+ kind: 'kpi',
311
+ model: 'approval.ask',
312
+ measure: 'count',
313
+ filter: { state: 'approved' },
314
+ comparison: { field: 'approvedAt', mode: 'previous' },
315
+ w: 3,
316
+ },
317
+ {
318
+ id: 'refused',
319
+ title: 'Refused',
320
+ kind: 'kpi',
321
+ model: 'approval.ask',
322
+ measure: 'count',
323
+ filter: { state: 'refused' },
324
+ w: 3,
325
+ },
326
+ {
327
+ id: 'amount',
328
+ title: 'Amount waiting',
329
+ kind: 'kpi',
330
+ model: 'approval.ask',
331
+ measure: 'sum:amount',
332
+ filter: { state: 'submitted' },
333
+ w: 3,
334
+ },
335
+ {
336
+ id: 'by_category',
337
+ title: 'Requests by category',
338
+ kind: 'chart',
339
+ model: 'approval.ask',
340
+ measure: 'count',
341
+ groupBy: 'category',
342
+ chart: 'bar',
343
+ w: 6,
344
+ },
345
+ {
346
+ id: 'by_state',
347
+ title: 'Requests by state',
348
+ kind: 'chart',
349
+ model: 'approval.ask',
350
+ measure: 'count',
351
+ groupBy: 'state',
352
+ chart: 'pie',
353
+ w: 6,
354
+ },
355
+ ],
356
+ },
166
357
  accessLevels: {
167
358
  user: { label: 'Everyone (decide and ask)', groups: ['base.user'] },
168
359
  manager: {
@@ -175,6 +366,58 @@ export function approvalsModule(options = {}) {
175
366
  configureMails({ log: (message, error) => context.app.log.warn({ err: error }, message) });
176
367
  registerApprovalAppRoutes(context);
177
368
  },
369
+ documents: [
370
+ {
371
+ key: 'approval_request',
372
+ name: 'Request',
373
+ model: 'approval.ask',
374
+ layout: {
375
+ paper: 'A4',
376
+ header: '{{company.name}}',
377
+ footer: 'Page {{page}} of {{pages}}',
378
+ blocks: [
379
+ { kind: 'heading', id: 'title', text: 'Request {{name}}: {{title}}', level: 1 },
380
+ {
381
+ kind: 'fields',
382
+ id: 'ask',
383
+ items: [
384
+ { label: 'Category', bind: 'category.name' },
385
+ { label: 'Asked by', bind: 'requester.name' },
386
+ { label: 'Amount', bind: 'amount' },
387
+ { label: 'From', bind: 'dateFrom' },
388
+ { label: 'Until', bind: 'dateTo' },
389
+ { label: 'Contact', bind: 'partner.name' },
390
+ { label: 'Location', bind: 'location' },
391
+ { label: 'Quantity', bind: 'quantity' },
392
+ { label: 'Status', bind: 'state' },
393
+ { label: 'Approved on', bind: 'approvedAt' },
394
+ ],
395
+ },
396
+ { kind: 'text', id: 'about', text: '{{description}}' },
397
+ {
398
+ kind: 'table',
399
+ id: 'lines',
400
+ bind: 'lines',
401
+ columns: [
402
+ { label: 'Description', bind: 'name' },
403
+ { label: 'Quantity', bind: 'quantity' },
404
+ { label: 'Unit price', bind: 'priceUnit' },
405
+ { label: 'Amount', bind: 'subtotal' },
406
+ ],
407
+ },
408
+ {
409
+ kind: 'fields',
410
+ id: 'total',
411
+ items: [
412
+ { label: 'Lines total', bind: 'linesTotal' },
413
+ { label: 'Made', bind: 'resultName' },
414
+ ],
415
+ },
416
+ { kind: 'signature', id: 'sign', labels: ['Asked by', 'Approved by'] },
417
+ ],
418
+ },
419
+ },
420
+ ],
178
421
  actions: {
179
422
  'approvals.action_inbox': { type: 'client', page: 'approvals.Inbox', label: 'To approve' },
180
423
  'approvals.action_mine': { type: 'client', page: 'approvals.Mine', label: 'My requests' },
@@ -183,17 +426,32 @@ export function approvalsModule(options = {}) {
183
426
  page: 'approvals.History',
184
427
  label: 'What I decided',
185
428
  },
429
+ 'approvals.action_matrix': { type: 'client', page: 'approvals.Matrix', label: 'Matrix' },
186
430
  'approvals.action_away': {
187
431
  model: 'approval.delegation',
188
432
  label: 'Away',
189
433
  views: ['list', 'form'],
190
434
  },
435
+ 'approvals.action_asks': action(ApprovalAsk, {
436
+ label: 'Requests',
437
+ views: ['list', 'kanban', 'form'],
438
+ }),
439
+ 'approvals.action_categories': action(ApprovalCategory, {
440
+ label: 'Request categories',
441
+ views: ['kanban', 'list', 'form'],
442
+ }),
191
443
  'approvals.action_policies': {
192
444
  model: 'approval.policy',
193
445
  label: 'Policies',
194
446
  views: ['list', 'form'],
195
447
  visibleTo: ['approvals.manager'],
196
448
  },
449
+ 'approvals.action_segments': {
450
+ model: 'res.segment',
451
+ label: 'Segments',
452
+ views: ['list', 'form'],
453
+ visibleTo: ['approvals.manager'],
454
+ },
197
455
  },
198
456
  menus: [
199
457
  { id: 'approvals.root', label: 'Approvals', app: 'approvals' },
@@ -218,6 +476,20 @@ export function approvalsModule(options = {}) {
218
476
  action: 'approvals.action_history',
219
477
  sequence: 3,
220
478
  },
479
+ {
480
+ id: 'approvals.matrix',
481
+ parent: 'approvals.root',
482
+ label: 'Matrix',
483
+ action: 'approvals.action_matrix',
484
+ sequence: 3.5,
485
+ },
486
+ {
487
+ id: 'approvals.asks',
488
+ parent: 'approvals.root',
489
+ label: 'Requests',
490
+ action: 'approvals.action_asks',
491
+ sequence: 2.5,
492
+ },
221
493
  {
222
494
  id: 'approvals.away',
223
495
  parent: 'approvals.root',
@@ -232,6 +504,14 @@ export function approvalsModule(options = {}) {
232
504
  sequence: 9,
233
505
  visibleTo: ['approvals.manager'],
234
506
  },
507
+ {
508
+ id: 'approvals.categories',
509
+ parent: 'approvals.configuration',
510
+ label: 'Request categories',
511
+ action: 'approvals.action_categories',
512
+ sequence: 0.5,
513
+ visibleTo: ['approvals.manager'],
514
+ },
235
515
  {
236
516
  id: 'approvals.policies',
237
517
  parent: 'approvals.configuration',
@@ -240,8 +520,31 @@ export function approvalsModule(options = {}) {
240
520
  sequence: 1,
241
521
  visibleTo: ['approvals.manager'],
242
522
  },
523
+ {
524
+ id: 'approvals.segments',
525
+ parent: 'approvals.configuration',
526
+ label: 'Segments',
527
+ action: 'approvals.action_segments',
528
+ sequence: 2,
529
+ visibleTo: ['approvals.manager'],
530
+ },
243
531
  ],
244
532
  views: {
533
+ 'res.segment.list': list('res.segment', {
534
+ columns: ['name', 'code', 'companies', 'active'],
535
+ }),
536
+ 'res.segment.form': form('res.segment', (k) => ({
537
+ sheet: [
538
+ k.group('main', ['name', 'code'], {
539
+ description: 'A group of companies (Feed, Poultry, Dairy): an approval policy of the segment covers every company in it.',
540
+ }),
541
+ k.group('members', [{ field: 'companies', id: 'segment_companies', widget: 'tags' }], {
542
+ label: 'Companies',
543
+ description: 'A company is in one segment at most.',
544
+ }),
545
+ k.group('notes', ['note'], { label: 'Note' }),
546
+ ],
547
+ })),
245
548
  'approval.delegation.list': list('approval.delegation', {
246
549
  columns: ['user', 'delegate', 'dateFrom', 'dateTo', 'note'],
247
550
  }),
@@ -252,11 +555,137 @@ export function approvalsModule(options = {}) {
252
555
  }),
253
556
  ],
254
557
  })),
558
+ 'approval.ask.list': list(ApprovalAsk, {
559
+ columns: [
560
+ 'name',
561
+ 'category',
562
+ 'title',
563
+ 'requester',
564
+ { field: 'amount', sum: true },
565
+ 'dateFrom',
566
+ { field: 'state', widget: 'badge' },
567
+ ],
568
+ decorations: {
569
+ warning: { state: 'submitted' },
570
+ success: { state: 'approved' },
571
+ danger: { state: 'refused' },
572
+ },
573
+ }),
574
+ 'approval.ask.kanban': kanban(ApprovalAsk, {
575
+ groupBy: 'state',
576
+ card: {
577
+ title: 'title',
578
+ subtitle: 'category',
579
+ avatar: 'requester',
580
+ footer: ['amount', 'name'],
581
+ },
582
+ }),
583
+ 'approval.ask.form': form(ApprovalAsk, (k) => ({
584
+ header: {
585
+ statusbar: 'state',
586
+ buttons: [
587
+ k.button('submit', { primary: true, label: 'Submit for approval' }),
588
+ k.button('redraft', { label: 'Set to draft' }),
589
+ k.button('cancel', { label: 'Cancel' }),
590
+ ],
591
+ },
592
+ sheet: [
593
+ k.group('main', ['category', 'title', 'name', 'requester']),
594
+ k.component('approvals', 'approvals.Panel'),
595
+ k.group('details', [
596
+ {
597
+ field: 'amount',
598
+ id: 'ask_amount',
599
+ visibleWhen: { askAmount: { ne: 'none' } },
600
+ requiredWhen: { askAmount: 'required' },
601
+ },
602
+ {
603
+ field: 'dateFrom',
604
+ id: 'ask_dateFrom',
605
+ visibleWhen: { askPeriod: { ne: 'none' } },
606
+ requiredWhen: { askPeriod: 'required' },
607
+ },
608
+ {
609
+ field: 'dateTo',
610
+ id: 'ask_dateTo',
611
+ visibleWhen: { askPeriod: { ne: 'none' } },
612
+ requiredWhen: { askPeriod: 'required' },
613
+ },
614
+ {
615
+ field: 'partner',
616
+ id: 'ask_partner',
617
+ visibleWhen: { askPartner: { ne: 'none' } },
618
+ requiredWhen: { askPartner: 'required' },
619
+ },
620
+ {
621
+ field: 'location',
622
+ id: 'ask_location',
623
+ visibleWhen: { askLocation: { ne: 'none' } },
624
+ requiredWhen: { askLocation: 'required' },
625
+ },
626
+ {
627
+ field: 'quantity',
628
+ id: 'ask_quantity',
629
+ visibleWhen: { askQuantity: { ne: 'none' } },
630
+ requiredWhen: { askQuantity: 'required' },
631
+ },
632
+ ], {
633
+ label: 'Details',
634
+ description: 'What the category asks for; required ones are marked. A file, when asked for, goes in the chatter.',
635
+ }),
636
+ k.group('about', ['description'], { columns: 1 }),
637
+ {
638
+ ...k.lines('lines', [
639
+ { field: 'name', id: 'line_name' },
640
+ { field: 'quantity', id: 'line_quantity' },
641
+ { field: 'priceUnit', id: 'line_price' },
642
+ { field: 'subtotal', id: 'line_subtotal', sum: true },
643
+ ]),
644
+ visibleWhen: { askLines: { ne: 'none' } },
645
+ },
646
+ k.group('result', ['approvedAt', 'resultName'], {
647
+ label: 'Outcome',
648
+ visibleWhen: { state: 'approved' },
649
+ }),
650
+ ],
651
+ chatter: true,
652
+ })),
653
+ 'approval.category.kanban': kanban(ApprovalCategory, {
654
+ groupBy: 'outcome',
655
+ card: { title: 'name', subtitle: 'description', footer: ['requestCount', 'code'] },
656
+ }),
657
+ 'approval.category.list': list(ApprovalCategory, {
658
+ columns: ['sequence', 'code', 'name', 'outcome', 'policy', 'requestCount'],
659
+ }),
660
+ 'approval.category.form': form(ApprovalCategory, (k) => ({
661
+ sheet: [
662
+ k.group('main', ['name', 'code', 'sequence', 'company']),
663
+ k.group('about', ['description'], { columns: 1 }),
664
+ k.group('fields', [
665
+ 'askAmount',
666
+ 'askPeriod',
667
+ 'askPartner',
668
+ 'askLocation',
669
+ 'askQuantity',
670
+ 'askLines',
671
+ 'askAttachment',
672
+ ], {
673
+ label: 'What a request asks for',
674
+ description: 'Not asked, optional or required; submitting checks the required ones.',
675
+ }),
676
+ k.group('decision', ['policy', 'outcome'], {
677
+ label: 'Who decides and what follows',
678
+ description: 'The policy’s levels decide (made with the first request: the requester’s manager, else an Approvals manager); edit them on the policy. The outcome runs once approved.',
679
+ }),
680
+ k.component('category_policy', 'approvals.CategoryPolicy'),
681
+ ],
682
+ })),
255
683
  'approval.policy.list': list('approval.policy', {
256
684
  columns: [
257
685
  'name',
258
686
  'targetModel',
259
687
  'company',
688
+ 'segment',
260
689
  'onApproved',
261
690
  'reasonRequired',
262
691
  'active',
@@ -264,10 +693,29 @@ export function approvalsModule(options = {}) {
264
693
  }),
265
694
  'approval.policy.form': form('approval.policy', (k) => ({
266
695
  sheet: [
267
- k.group('main', ['name', 'targetModel', 'company', 'sequence'], {
696
+ k.component('preview', 'approvals.PolicyPreview'),
697
+ k.group('main', ['name', 'targetModel', 'sequence', 'condition'], {
268
698
  description: 'A record of the model gets one approval per level whose condition it meets; levels with a lower sequence are decided first, those with the same side by side.',
269
699
  }),
270
- k.group('outcomes', ['onApproved', 'onRejected', 'onSentBack', 'onWithdrawn', 'reasonRequired'], {
700
+ k.group('scope', [
701
+ 'company',
702
+ { field: 'companies', id: 'policy_companies', widget: 'tags' },
703
+ 'segment',
704
+ ], {
705
+ label: 'Companies',
706
+ description: 'The policy covers this company, these companies and every company of the segment together; leave all three empty for every company.',
707
+ }),
708
+ k.group('outcomes', [
709
+ 'onApproved',
710
+ 'onRejected',
711
+ 'onSentBack',
712
+ 'onWithdrawn',
713
+ 'reasonRequired',
714
+ 'whenNobody',
715
+ 'skipDuplicates',
716
+ 'syncPending',
717
+ 'notifyOnSync',
718
+ ], {
271
719
  label: 'What happens',
272
720
  description: 'The transitions of the record run when it is approved, rejected, sent back or withdrawn.',
273
721
  }),
@@ -278,6 +726,8 @@ export function approvalsModule(options = {}) {
278
726
  { field: 'approverRole', id: 'level_role' },
279
727
  { field: 'approverUsers', id: 'level_users', widget: 'tags' },
280
728
  { field: 'approverField', id: 'level_field' },
729
+ { field: 'extraUsers', id: 'level_extra', widget: 'tags' },
730
+ { field: 'backupUsers', id: 'level_backups', widget: 'tags' },
281
731
  { field: 'quorum', id: 'level_quorum' },
282
732
  { field: 'quorumCount', id: 'level_count' },
283
733
  { field: 'deadlineHours', id: 'level_deadline' },
@@ -287,10 +737,30 @@ export function approvalsModule(options = {}) {
287
737
  })),
288
738
  },
289
739
  search: {
740
+ 'res.segment': search('res.segment', {
741
+ fields: ['name', 'code'],
742
+ }),
290
743
  'approval.delegation': search('approval.delegation', {
291
744
  fields: ['user.name', 'delegate.name'],
292
745
  groupBy: ['user', 'delegate'],
293
746
  }),
747
+ 'approval.ask': search(ApprovalAsk, {
748
+ fields: ['title', 'name', 'requester.name'],
749
+ filters: {
750
+ mine: { label: 'Mine', domain: { requester: { $env: 'uid' } } },
751
+ waiting: {
752
+ label: 'Waiting for approval',
753
+ domain: { state: 'submitted' },
754
+ group: 'state',
755
+ },
756
+ approved: { label: 'Approved', domain: { state: 'approved' }, group: 'state' },
757
+ },
758
+ groupBy: ['category', 'state', 'requester'],
759
+ }),
760
+ 'approval.category': search(ApprovalCategory, {
761
+ fields: ['name', 'code'],
762
+ groupBy: ['outcome'],
763
+ }),
294
764
  'approval.policy': search('approval.policy', {
295
765
  fields: ['name', 'targetModel'],
296
766
  groupBy: ['targetModel'],
@@ -17,9 +17,14 @@ declare const WHY: {
17
17
  readonly asked: (who: string, record: string) => string;
18
18
  readonly reminded: (_who: string, record: string) => string;
19
19
  readonly escalated: (_who: string, record: string) => string;
20
+ readonly added: (who: string, record: string) => string;
21
+ readonly backup: (_who: string, record: string) => string;
20
22
  };
21
- /** Emails each person who may decide `requests` now a link of their own; skips those already sent one. */
22
- export declare function mailDeciders(su: Env, requests: readonly ApprovalRequestInfo[], why: keyof typeof WHY): Promise<number>;
23
+ /**
24
+ * Emails each person who may decide `requests` now a link of their own (only `only`, when given: the people added
25
+ * to a request, its backups); for a new turn, skips requests already sent links.
26
+ */
27
+ export declare function mailDeciders(su: Env, requests: readonly ApprovalRequestInfo[], why: keyof typeof WHY, only?: readonly number[]): Promise<number>;
23
28
  /** After a record's approvals were asked, or one of its levels approved: the requests whose turn it is now. */
24
29
  export declare function mailTurn(su: Env, model: string, id: number): Promise<number>;
25
30
  export {};
@@ -21,9 +21,14 @@ const WHY = {
21
21
  asked: (who, record) => `${who} asks you to approve ${record}`,
22
22
  reminded: (_who, record) => `Reminder: ${record} waits for your approval`,
23
23
  escalated: (_who, record) => `${record} is late: you may decide it now`,
24
+ added: (who, record) => `${who} waits for your approval of ${record}`,
25
+ backup: (_who, record) => `As a backup approver: ${record} waits for a decision`,
24
26
  };
25
- /** Emails each person who may decide `requests` now a link of their own; skips those already sent one. */
26
- export async function mailDeciders(su, requests, why) {
27
+ /**
28
+ * Emails each person who may decide `requests` now a link of their own (only `only`, when given: the people added
29
+ * to a request, its backups); for a new turn, skips requests already sent links.
30
+ */
31
+ export async function mailDeciders(su, requests, why, only) {
27
32
  const mailer = config.mailer;
28
33
  let sent = 0;
29
34
  for (const request of requests) {
@@ -35,7 +40,7 @@ export async function mailDeciders(su, requests, why) {
35
40
  if (existing.length > 0)
36
41
  continue;
37
42
  }
38
- const links = await issueLinks(su, request, su.today(), () => randomToken(24), digest);
43
+ const links = await issueLinks(su, request, su.today(), () => randomToken(24), digest, only);
39
44
  if (links.length === 0)
40
45
  continue;
41
46
  const [record] = await read(await ref(su, request.targetModel)