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
@@ -12,8 +12,10 @@
12
12
  * (`shutro-erp/accounting/web`).
13
13
  */
14
14
  import { contacts } from '../contacts/index.js';
15
+ import { mailerFromEnv } from '../mail/index.js';
15
16
  import { messaging } from '../messaging/index.js';
16
17
  import { defineModule } from '../modules-sdk/index.js';
18
+ import { messengerFromEnv } from '../notify/index.js';
17
19
  import { permissions } from '../permissions/index.js';
18
20
  import { product } from '../product/index.js';
19
21
  import { reporting } from '../reporting/index.js';
@@ -22,12 +24,17 @@ import { action, field, form, hierarchy, list, pivot, search, stat } from '../vi
22
24
  import { ChartInstalledError, chartsOf, installChart, installedChart, installImmutability, installLocalization, localizationsOf, } from './chart.js';
23
25
  import { agingReport, closeFiscalYear, readSettings, reopenFiscalYear, updateSettings, } from './closing.js';
24
26
  import { accountingDemo } from './demo.js';
27
+ import { AccountFiscalPosition, previewMove } from './fiscal.js';
28
+ import { AccountFollowupLevel, AccountFollowupSent, configureFollowups, followUp, followupRows, installFollowupLevels, pauseFollowup, runFollowups, } from './followups.js';
25
29
  import { AccountAccount, AccountAnalytic, AccountFiscalYear, AccountJournal, AccountMove, AccountMoveLine, AccountPayment, AccountPaymentTerm, AccountWithholding, accountingShutro, REVERSED_KIND, ResBankAccount, ResCurrencyRate, } from './module.js';
26
30
  import { openLines, proposeWithholdings, reconcile, registerPayment, unreconcile, } from './payments.js';
31
+ import { AccountBankStatement, AccountReconcileRule, applyRules, dryRunRule, importStatement, matchLine, parseCamt, parseCsv, parseOfx, proposalsFor, pullFeed, undoLine, writeOffLine, } from './statements.js';
27
32
  export { CHARTS, ChartInstalledError, COMMON_ACCOUNTS, chartsOf, DEFAULT_ACCOUNTS, installChart, installedChart, installImmutability, installLocalization, localizationsOf, } from './chart.js';
28
33
  export { agingReport, closeFiscalYear, readSettings, reopenFiscalYear, updateSettings, } from './closing.js';
34
+ export { configureFollowups, followUp, followupRows, overdueCustomers, pauseFollowup, runFollowups, salesStopped, } from './followups.js';
29
35
  export { ACCOUNT_TYPES, AccountAccount, AccountAnalytic, AccountFiscalYear, AccountFullReconcile, AccountJournal, AccountMove, AccountMoveLine, AccountPartialReconcile, AccountPayment, AccountPaymentTerm, AccountPaymentTermLine, AccountPaymentWithholding, AccountTaxComponent, AccountWithholding, accountingShutro, addDays, CompanyAccounting, fiscalYearOf, isRefund, JOURNAL_TYPES, MOVE_KINDS, NUMBER_FIELD, owedToUs, PartnerWithholdings, REVERSED_KIND, ResBankAccount, ResCurrencyRate, supplyScope, TaxAccounts, } from './module.js';
30
36
  export { openLines, proposeWithholdings, reconcile, registerPayment, unreconcile, } from './payments.js';
37
+ export { AccountReconcileRule, applyRules, bankFeed, dryRunRule, importStatement, matchLine, parseCamt, parseCsv, parseOfx, proposalsFor, pullFeed, registerBankFeed, testBankFeed, undoLine, writeOffLine, } from './statements.js';
31
38
  /**
32
39
  * Reverses a posted entry: a new entry in the same journal with every line negated, linked both ways, posted when
33
40
  * asked. The original is never touched beyond its `reversedBy` link.
@@ -109,6 +116,51 @@ export const accounting = defineModule({
109
116
  // Exceptions to the module standard (RFC 0023), each with its reason.
110
117
  standard: {
111
118
  waive: [
119
+ {
120
+ rule: 'I1',
121
+ model: 'account.bank.statement',
122
+ reason: 'Imported by its own CSV / OFX / CAMT import (Accounting › Reconcile bank), or pulled from a feed.',
123
+ },
124
+ {
125
+ rule: 'I1',
126
+ model: 'account.fiscal.position',
127
+ reason: 'A few per company, set up on screen with their mappings.',
128
+ },
129
+ {
130
+ rule: 'I1',
131
+ model: 'account.fiscal.position.tax',
132
+ reason: 'Lines of a fiscal position, edited on its form.',
133
+ },
134
+ {
135
+ rule: 'I1',
136
+ model: 'account.fiscal.position.account',
137
+ reason: 'Lines of a fiscal position, edited on its form.',
138
+ },
139
+ {
140
+ rule: 'I1',
141
+ model: 'account.followup.level',
142
+ reason: 'Three per company to start with, set up on screen.',
143
+ },
144
+ {
145
+ rule: 'I1',
146
+ model: 'account.followup',
147
+ reason: 'Kept by the follow-up run and the Follow-ups screen, never imported.',
148
+ },
149
+ {
150
+ rule: 'I1',
151
+ model: 'account.followup.sent',
152
+ reason: 'A log written when a reminder is sent.',
153
+ },
154
+ {
155
+ rule: 'I1',
156
+ model: 'account.reconcile.rule',
157
+ reason: 'A handful per company, set up on screen with its dry run.',
158
+ },
159
+ {
160
+ rule: 'I1',
161
+ model: 'account.full.reconcile',
162
+ reason: 'Made by reconciling, never imported.',
163
+ },
112
164
  {
113
165
  rule: 'M3',
114
166
  model: 'account.full.reconcile',
@@ -135,6 +187,8 @@ export const accounting = defineModule({
135
187
  category: 'Finance',
136
188
  summary: 'Invoices, bills, journals and entries posted in exact money',
137
189
  },
190
+ // Bangla for the labels it serves (RFC 0023 §3.1; `pnpm i18n:extract`).
191
+ i18n: { bn: () => import('./i18n/bn.js') },
138
192
  accessLevels: {
139
193
  invoicing: { label: 'Invoicing (invoices and their payments)', groups: ['account.invoicing'] },
140
194
  user: {
@@ -381,12 +435,45 @@ export const accounting = defineModule({
381
435
  page: 'accounting.Reconcile',
382
436
  label: 'Reconciliation',
383
437
  },
438
+ 'accounting.action_bank_reconcile': {
439
+ type: 'client',
440
+ page: 'accounting.BankReconcile',
441
+ label: 'Reconcile bank',
442
+ visibleTo: ['account.reconcile'],
443
+ },
444
+ 'accounting.action_followups': {
445
+ type: 'client',
446
+ page: 'accounting.Followups',
447
+ label: 'Follow-ups',
448
+ visibleTo: ['account.user'],
449
+ },
450
+ 'accounting.action_fiscal_positions': action(AccountFiscalPosition, {
451
+ label: 'Fiscal positions',
452
+ views: ['list', 'form'],
453
+ }),
454
+ 'accounting.action_followup_levels': action(AccountFollowupLevel, {
455
+ label: 'Follow-up levels',
456
+ views: ['list', 'form'],
457
+ }),
458
+ 'accounting.action_followup_sent': action(AccountFollowupSent, {
459
+ label: 'Reminders sent',
460
+ views: ['list'],
461
+ }),
462
+ 'accounting.action_statements': {
463
+ model: 'account.bank.statement',
464
+ label: 'Bank statements',
465
+ views: ['list', 'form'],
466
+ },
384
467
  'accounting.action_settings': {
385
468
  type: 'client',
386
469
  page: 'accounting.Settings',
387
470
  label: 'Settings',
388
471
  visibleTo: ['account.manager'],
389
472
  },
473
+ 'accounting.action_reconcile_rules': action(AccountReconcileRule, {
474
+ label: 'Reconciliation rules',
475
+ views: ['list', 'form'],
476
+ }),
390
477
  'accounting.action_payment_terms': action(AccountPaymentTerm, {
391
478
  label: 'Payment terms',
392
479
  views: ['list', 'form'],
@@ -463,6 +550,50 @@ export const accounting = defineModule({
463
550
  action: 'accounting.action_reconcile',
464
551
  sequence: 5,
465
552
  },
553
+ {
554
+ id: 'accounting.bank_reconcile',
555
+ parent: 'accounting.root',
556
+ label: 'Reconcile bank',
557
+ action: 'accounting.action_bank_reconcile',
558
+ sequence: 4.5,
559
+ visibleTo: ['account.reconcile'],
560
+ },
561
+ {
562
+ id: 'accounting.followups',
563
+ parent: 'accounting.root',
564
+ label: 'Follow-ups',
565
+ action: 'accounting.action_followups',
566
+ sequence: 4.7,
567
+ visibleTo: ['account.user'],
568
+ },
569
+ {
570
+ id: 'accounting.fiscal_positions',
571
+ parent: 'accounting.configuration',
572
+ label: 'Fiscal positions',
573
+ action: 'accounting.action_fiscal_positions',
574
+ sequence: 8,
575
+ },
576
+ {
577
+ id: 'accounting.followup_levels',
578
+ parent: 'accounting.configuration',
579
+ label: 'Follow-up levels',
580
+ action: 'accounting.action_followup_levels',
581
+ sequence: 7,
582
+ },
583
+ {
584
+ id: 'accounting.followup_sent',
585
+ parent: 'accounting.reporting',
586
+ label: 'Reminders sent',
587
+ action: 'accounting.action_followup_sent',
588
+ sequence: 9,
589
+ },
590
+ {
591
+ id: 'accounting.statements',
592
+ parent: 'accounting.root',
593
+ label: 'Bank statements',
594
+ action: 'accounting.action_statements',
595
+ sequence: 4.6,
596
+ },
466
597
  { id: 'accounting.reporting', parent: 'accounting.root', label: 'Reporting', sequence: 8 },
467
598
  {
468
599
  id: 'accounting.trial_balance',
@@ -589,12 +720,129 @@ export const accounting = defineModule({
589
720
  action: 'accounting.action_payment_terms',
590
721
  sequence: 5,
591
722
  },
723
+ {
724
+ id: 'accounting.reconcile_rules',
725
+ parent: 'accounting.configuration',
726
+ label: 'Reconciliation rules',
727
+ action: 'accounting.action_reconcile_rules',
728
+ sequence: 6,
729
+ },
592
730
  ],
593
731
  // What webhooks may subscribe to besides record changes (RFC 0017 §5.3).
594
732
  events: [
733
+ {
734
+ topic: 'account.bank.statement.closed',
735
+ model: 'account.bank.statement',
736
+ label: 'Bank statement closed',
737
+ },
738
+ {
739
+ topic: 'account.fiscal.year.closed',
740
+ model: 'account.fiscal.year',
741
+ label: 'Fiscal year closed',
742
+ },
743
+ { topic: 'account.payment.posted', model: 'account.payment', label: 'Payment posted' },
595
744
  { topic: 'account.move.posted', model: 'account.move', label: 'Entry, invoice or bill posted' },
596
745
  ],
597
746
  importTemplates: [
747
+ {
748
+ key: 'account_withholding',
749
+ model: 'account.withholding',
750
+ label: 'Withholding',
751
+ columns: [
752
+ { header: 'Name', field: 'name' },
753
+ { header: 'Direction', field: 'direction' },
754
+ { header: 'Computed on', field: 'base' },
755
+ { header: 'Rate', field: 'rate' },
756
+ { header: 'Applies from (document total)', field: 'threshold' },
757
+ { header: 'Account', field: 'account' },
758
+ ],
759
+ },
760
+ {
761
+ key: 'account_account',
762
+ model: 'account.account',
763
+ label: 'Account',
764
+ columns: [
765
+ { header: 'Code', field: 'code' },
766
+ { header: 'Name', field: 'name' },
767
+ { header: 'Type', field: 'type' },
768
+ { header: 'Allow reconciliation', field: 'reconcile' },
769
+ { header: 'Account currency', field: 'currency' },
770
+ { header: 'Note', field: 'note' },
771
+ ],
772
+ },
773
+ {
774
+ key: 'account_journal',
775
+ model: 'account.journal',
776
+ label: 'Journal',
777
+ columns: [
778
+ { header: 'Code', field: 'code' },
779
+ { header: 'Name', field: 'name' },
780
+ { header: 'Type', field: 'type' },
781
+ { header: 'Default account', field: 'defaultAccount' },
782
+ ],
783
+ },
784
+ {
785
+ key: 'account_fiscal_year',
786
+ model: 'account.fiscal.year',
787
+ label: 'Fiscal year',
788
+ columns: [
789
+ { header: 'Name', field: 'name' },
790
+ { header: 'From', field: 'dateFrom' },
791
+ { header: 'To', field: 'dateTo' },
792
+ ],
793
+ },
794
+ {
795
+ key: 'account_payment_term',
796
+ model: 'account.payment.term',
797
+ label: 'Payment term',
798
+ columns: [
799
+ { header: 'Name', field: 'name' },
800
+ { header: 'Shown on documents', field: 'note' },
801
+ { header: 'Lines › Days', field: 'lines.days' },
802
+ { header: 'Lines › Percent', field: 'lines.percent' },
803
+ ],
804
+ },
805
+ {
806
+ key: 'account_move',
807
+ model: 'account.move',
808
+ label: 'Journal entry',
809
+ columns: [
810
+ { header: 'Journal', field: 'journal' },
811
+ { header: 'Date', field: 'date' },
812
+ { header: 'Type', field: 'kind' },
813
+ { header: 'Partner', field: 'partner' },
814
+ { header: 'Reference', field: 'ref' },
815
+ { header: 'Currency', field: 'currency' },
816
+ { header: 'Rate', field: 'rate' },
817
+ { header: 'Notes', field: 'narration' },
818
+ { header: 'Due date', field: 'dateDue' },
819
+ { header: 'Payment terms', field: 'paymentTerm' },
820
+ { header: 'Source document', field: 'invoiceOrigin' },
821
+ { header: 'Place of supply', field: 'placeOfSupply' },
822
+ { header: 'Lines › Account', field: 'lines.account' },
823
+ { header: 'Lines › Partner', field: 'lines.partner' },
824
+ { header: 'Lines › Label', field: 'lines.name' },
825
+ { header: 'Lines › Due date', field: 'lines.dateMaturity' },
826
+ { header: 'Lines › Debit', field: 'lines.debit' },
827
+ ],
828
+ },
829
+ {
830
+ key: 'account_payment',
831
+ model: 'account.payment',
832
+ label: 'Payment',
833
+ columns: [
834
+ { header: 'Direction', field: 'kind' },
835
+ { header: 'Partner', field: 'partner' },
836
+ { header: 'Journal', field: 'journal' },
837
+ { header: 'Date', field: 'date' },
838
+ { header: 'Currency', field: 'currency' },
839
+ { header: 'Amount', field: 'amount' },
840
+ { header: 'Memo', field: 'memo' },
841
+ { header: 'Withholdings › Withholding', field: 'withholdings.withholding' },
842
+ { header: 'Withholdings › Base', field: 'withholdings.base' },
843
+ { header: 'Withholdings › Amount', field: 'withholdings.amount' },
844
+ ],
845
+ },
598
846
  {
599
847
  key: 'cost_centres',
600
848
  model: 'account.analytic',
@@ -707,11 +955,134 @@ export const accounting = defineModule({
707
955
  {
708
956
  view: 'res.partner.form',
709
957
  operations: [
710
- { append: 'roles', nodes: [field({ field: 'withholdings', id: 'withholdings' })] },
958
+ {
959
+ append: 'roles',
960
+ nodes: [
961
+ field({ field: 'withholdings', id: 'withholdings' }),
962
+ field({ field: 'sendInvoicesByEmail', id: 'send_invoices_by_email' }),
963
+ field({ field: 'fiscalPosition', id: 'partner_fiscal_position' }),
964
+ field({ field: 'receivableAccount', id: 'partner_receivable_account' }),
965
+ field({ field: 'payableAccount', id: 'partner_payable_account' }),
966
+ ],
967
+ },
968
+ ],
969
+ },
970
+ {
971
+ view: 'product.product.form',
972
+ operations: [
973
+ {
974
+ append: 'sell',
975
+ nodes: [field({ field: 'incomeAccount', id: 'product_income_account' })],
976
+ },
977
+ {
978
+ append: 'buy',
979
+ nodes: [field({ field: 'expenseAccount', id: 'product_expense_account' })],
980
+ },
981
+ ],
982
+ },
983
+ {
984
+ view: 'product.category.form',
985
+ operations: [
986
+ {
987
+ append: 'main',
988
+ nodes: [
989
+ field({ field: 'incomeAccount', id: 'category_income_account' }),
990
+ field({ field: 'expenseAccount', id: 'category_expense_account' }),
991
+ ],
992
+ },
711
993
  ],
712
994
  },
713
995
  ],
996
+ // Invoices and credit notes sent by email with their PDF (RFC 0029 §3.3).
997
+ mailTemplates: [
998
+ {
999
+ key: 'invoice',
1000
+ name: 'Invoice',
1001
+ model: 'account.move',
1002
+ document: 'accounting.invoice',
1003
+ subject: '{{company.name}}: {{kind}} {{name}}',
1004
+ body: 'Dear {{partner.name}},\n\nPlease find attached {{kind}} {{name}} of {{amountTotal}}, due on {{dateDue}}.\n\nThank you for your business.\n\n{{company.name}}',
1005
+ translations: {
1006
+ bn_BD: {
1007
+ subject: '{{company.name}}: {{kind}} {{name}}',
1008
+ body: 'প্রিয় {{partner.name}},\n\n{{amountTotal}}-এর {{kind}} {{name}} সংযুক্ত করা হলো, পরিশোধের তারিখ {{dateDue}}।\n\nআপনার সঙ্গে ব্যবসার জন্য ধন্যবাদ।\n\n{{company.name}}',
1009
+ },
1010
+ },
1011
+ },
1012
+ ],
1013
+ sendable: [
1014
+ {
1015
+ model: 'account.move',
1016
+ template: 'accounting.invoice',
1017
+ partner: 'partner',
1018
+ when: { state: 'posted', kind: { in: ['out_invoice', 'out_refund'] } },
1019
+ autoSend: { topic: 'account.move.posted', flag: 'sendInvoicesByEmail' },
1020
+ },
1021
+ ],
714
1022
  documents: [
1023
+ {
1024
+ key: 'bank_statement',
1025
+ name: 'Bank statement',
1026
+ model: 'account.bank.statement',
1027
+ layout: {
1028
+ paper: 'A4',
1029
+ header: '{{company.name}}',
1030
+ footer: 'Page {{page}} of {{pages}}',
1031
+ blocks: [
1032
+ { kind: 'heading', id: 'title', text: 'Bank statement {{name}}', level: 1 },
1033
+ {
1034
+ kind: 'fields',
1035
+ id: 'statement',
1036
+ items: [
1037
+ { label: 'Journal', bind: 'journal.name' },
1038
+ { label: 'Date', bind: 'date' },
1039
+ { label: 'Opening balance', bind: 'balanceStart' },
1040
+ { label: 'Closing balance', bind: 'balanceEnd' },
1041
+ { label: 'Status', bind: 'state' },
1042
+ ],
1043
+ },
1044
+ {
1045
+ kind: 'table',
1046
+ id: 'lines',
1047
+ bind: 'lines',
1048
+ columns: [
1049
+ { label: 'Date', bind: 'date' },
1050
+ { label: 'Label', bind: 'label' },
1051
+ { label: 'Reference', bind: 'reference' },
1052
+ { label: 'Partner', bind: 'partner.name' },
1053
+ { label: 'Amount', bind: 'amount', align: 'end', sum: true },
1054
+ { label: 'Status', bind: 'state' },
1055
+ ],
1056
+ },
1057
+ ],
1058
+ },
1059
+ },
1060
+ {
1061
+ key: 'fiscal_year',
1062
+ name: 'Fiscal year',
1063
+ model: 'account.fiscal.year',
1064
+ layout: {
1065
+ paper: 'A4',
1066
+ header: '{{company.name}}',
1067
+ footer: 'Page {{page}} of {{pages}}',
1068
+ blocks: [
1069
+ { kind: 'heading', id: 'title', text: 'Fiscal year {{name}}', level: 1 },
1070
+ {
1071
+ kind: 'fields',
1072
+ id: 'year',
1073
+ items: [
1074
+ { label: 'From', bind: 'dateFrom' },
1075
+ { label: 'To', bind: 'dateTo' },
1076
+ { label: 'Status', bind: 'state' },
1077
+ { label: 'Locked until', bind: 'lockDate' },
1078
+ { label: 'Closing entry', bind: 'closingMove.name' },
1079
+ { label: 'Reopened because', bind: 'reopenReason' },
1080
+ ],
1081
+ },
1082
+ { kind: 'signature', id: 'sign', labels: ['Prepared by', 'Approved by'] },
1083
+ ],
1084
+ },
1085
+ },
715
1086
  {
716
1087
  key: 'withholding_certificate',
717
1088
  name: 'Withholding certificate',
@@ -815,6 +1186,84 @@ export const accounting = defineModule({
815
1186
  },
816
1187
  ],
817
1188
  views: {
1189
+ 'account.bank.statement.list': list(AccountBankStatement, {
1190
+ columns: ['date', 'name', 'journal', 'balanceStart', 'balanceEnd', 'state'],
1191
+ }),
1192
+ 'account.bank.statement.form': form(AccountBankStatement, (k) => ({
1193
+ header: {
1194
+ statusbar: 'state',
1195
+ buttons: [
1196
+ k.button('close', { primary: true, label: 'Close' }),
1197
+ k.button('reopen', { label: 'Reopen' }),
1198
+ ],
1199
+ },
1200
+ sheet: [
1201
+ k.group('main', ['name', 'journal', 'date', 'balanceStart', 'balanceEnd'], {
1202
+ description: 'Match its lines in Accounting › Reconcile bank; it closes once every line is matched and the balances agree.',
1203
+ }),
1204
+ k.lines('lines', [
1205
+ { field: 'date', id: 'statement_line_date' },
1206
+ { field: 'label', id: 'statement_line_label' },
1207
+ { field: 'reference', id: 'statement_line_reference' },
1208
+ { field: 'partner', id: 'statement_line_partner' },
1209
+ { field: 'amount', id: 'statement_line_amount' },
1210
+ { field: 'state', id: 'statement_line_state' },
1211
+ ]),
1212
+ ],
1213
+ chatter: true,
1214
+ })),
1215
+ 'account.fiscal.position.list': list(AccountFiscalPosition, {
1216
+ columns: ['sequence', 'name', 'autoApply', 'countries', 'states', 'vatRequired'],
1217
+ }),
1218
+ 'account.fiscal.position.form': form(AccountFiscalPosition, (k) => ({
1219
+ header: { buttons: [] },
1220
+ sheet: [
1221
+ k.group('main', ['name', 'sequence', 'company', 'note']),
1222
+ k.group('when', ['autoApply', 'countries', 'states', 'vatRequired'], {
1223
+ label: 'Applies to',
1224
+ description: 'A document uses the position chosen on it, else its partner’s, else the first that applies by itself.',
1225
+ }),
1226
+ k.lines('taxes', [
1227
+ { field: 'taxSrc', id: 'map_tax_src' },
1228
+ { field: 'taxDest', id: 'map_tax_dest' },
1229
+ ]),
1230
+ k.lines('accounts', [
1231
+ { field: 'accountSrc', id: 'map_account_src' },
1232
+ { field: 'accountDest', id: 'map_account_dest' },
1233
+ ]),
1234
+ ],
1235
+ })),
1236
+ 'account.followup.level.list': list(AccountFollowupLevel, {
1237
+ columns: ['days', 'name', 'sendEmail', 'sendSms', 'sendWhatsapp', 'blockSales'],
1238
+ }),
1239
+ 'account.followup.level.form': form(AccountFollowupLevel, (k) => ({
1240
+ header: { buttons: [] },
1241
+ sheet: [
1242
+ k.group('main', ['name', 'days', 'company', 'blockSales'], {
1243
+ description: 'Each day, a late customer gets one reminder for the highest level their oldest overdue invoice reached.',
1244
+ }),
1245
+ k.group('how', ['sendEmail', 'sendSms', 'sendWhatsapp'], { label: 'Sent by' }),
1246
+ k.group('text', ['subject', 'body', 'shortText'], { label: 'What it says', columns: 1 }),
1247
+ ],
1248
+ })),
1249
+ 'account.followup.sent.list': list(AccountFollowupSent, {
1250
+ columns: ['createdAt', 'partner', 'level', 'amount', 'channels', 'automatic'],
1251
+ }),
1252
+ 'account.reconcile.rule.list': list(AccountReconcileRule, {
1253
+ columns: ['sequence', 'name', 'direction', 'labelContains', 'outcome', 'hits'],
1254
+ }),
1255
+ 'account.reconcile.rule.form': form(AccountReconcileRule, (k) => ({
1256
+ header: { buttons: [] },
1257
+ sheet: [
1258
+ k.group('main', ['name', 'sequence', 'company'], {
1259
+ description: 'Rules run in order on every imported line; the first that applies wins. Try one with its dry run from Reconcile bank.',
1260
+ }),
1261
+ k.group('when', ['journals', 'direction', 'labelContains', 'amountMin', 'amountMax', 'partner'], {
1262
+ label: 'When',
1263
+ }),
1264
+ k.group('then', ['outcome', 'writeOffAccount', 'writeOffLabel', 'hits'], { label: 'Then' }),
1265
+ ],
1266
+ })),
818
1267
  'account.move.invoice.list': list(AccountMove, {
819
1268
  columns: [
820
1269
  'name',
@@ -864,7 +1313,15 @@ export const accounting = defineModule({
864
1313
  tone: 'success',
865
1314
  },
866
1315
  ]),
867
- k.group('party', ['partner', 'kind', 'invoiceOrigin', 'ref', 'debitOf', 'placeOfSupply']),
1316
+ k.group('party', [
1317
+ 'partner',
1318
+ 'kind',
1319
+ 'invoiceOrigin',
1320
+ 'ref',
1321
+ 'debitOf',
1322
+ 'placeOfSupply',
1323
+ 'fiscalPosition',
1324
+ ]),
868
1325
  k.group('dates', ['date', 'dateDue', 'paymentTerm', 'journal']),
869
1326
  k.lines('lines', [
870
1327
  'product',
@@ -877,6 +1334,8 @@ export const accounting = defineModule({
877
1334
  'taxes',
878
1335
  'subtotal',
879
1336
  ], { readonlyWhen: { state: { ne: 'draft' } } }),
1337
+ // What posting will do: each line's taxes and account after the fiscal position, and why (RFC 0029 §3.5).
1338
+ k.component('posting_preview', 'accounting.PostingPreview'),
880
1339
  k.group('totals', [
881
1340
  'amountUntaxed',
882
1341
  'amountTax',
@@ -1124,7 +1583,24 @@ export const accounting = defineModule({
1124
1583
  })),
1125
1584
  },
1126
1585
  search: {
1586
+ 'account.bank.statement': search(AccountBankStatement, {
1587
+ fields: ['name', 'journal.name'],
1588
+ groupBy: ['journal', 'state'],
1589
+ }),
1127
1590
  'account.payment.term': search(AccountPaymentTerm, { fields: ['name'] }),
1591
+ 'account.followup.level': search(AccountFollowupLevel, { fields: ['name'] }),
1592
+ 'account.fiscal.position': search(AccountFiscalPosition, {
1593
+ fields: ['name', 'countries'],
1594
+ groupBy: ['autoApply'],
1595
+ }),
1596
+ 'account.followup.sent': search(AccountFollowupSent, {
1597
+ fields: ['partner.name', 'amount'],
1598
+ groupBy: ['partner', 'level'],
1599
+ }),
1600
+ 'account.reconcile.rule': search(AccountReconcileRule, {
1601
+ fields: ['name', 'labelContains'],
1602
+ groupBy: ['outcome', 'direction'],
1603
+ }),
1128
1604
  'account.journal': search(AccountJournal, { fields: ['name', 'code'], groupBy: ['type'] }),
1129
1605
  'account.fiscal.year': search(AccountFiscalYear, {
1130
1606
  fields: ['name'],
@@ -1229,11 +1705,88 @@ export const accounting = defineModule({
1229
1705
  // The immutability triggers, idempotent (with every seed and app install).
1230
1706
  defaults: async (env) => {
1231
1707
  await installImmutability(env);
1708
+ // The follow-up levels a company starts with (RFC 0029 §3.4).
1709
+ const company = Number(env.companyId);
1710
+ if (Number.isSafeInteger(company) &&
1711
+ company > 0 &&
1712
+ (await env
1713
+ .model('res.company')
1714
+ .search({ where: { id: company } })).ids.length > 0)
1715
+ await installFollowupLevels(env);
1232
1716
  return undefined;
1233
1717
  },
1234
1718
  demo: accountingDemo,
1719
+ // The books are kept (RFC 0008 §5.4): with posted entries, Accounting is disabled, never removed with its data.
1720
+ preUninstall: async (env) => {
1721
+ const posted = await env
1722
+ .model('account.move')
1723
+ .search({ where: { state: 'posted' }, limit: 1 });
1724
+ if (posted.ids.length > 0)
1725
+ throw new Error('posted journal entries exist, and the books are kept for the legal retention period');
1726
+ },
1235
1727
  },
1236
1728
  routes: (context) => {
1729
+ // Payment follow-ups (RFC 0029 §3.4): reminders by email and texts, links to the portal when it is installed.
1730
+ const portal = context.registry.loaded.modules.some((m) => m.name === 'account_portal');
1731
+ configureFollowups({
1732
+ mailer: mailerFromEnv(),
1733
+ messenger: messengerFromEnv(),
1734
+ portalUrl: portal
1735
+ ? (process.env['KOSH_PORTAL_URL'] ?? 'http://localhost:5174').replace(/\/$/, '')
1736
+ : null,
1737
+ });
1738
+ const partnerId = (params) => {
1739
+ const id = Number(params.partner);
1740
+ if (!Number.isSafeInteger(id) || id <= 0)
1741
+ throw new HttpProblem(400, 'invalid-path', 'Invalid customer', 'A customer id.');
1742
+ return id;
1743
+ };
1744
+ // What posting a draft would do (RFC 0029 §3.5).
1745
+ context.app.get('/api/v1/accounting/moves/:id/preview', async (request) => {
1746
+ const id = Number(request.params.id);
1747
+ if (!Number.isSafeInteger(id) || id <= 0)
1748
+ throw new HttpProblem(400, 'invalid-path', 'Invalid entry', 'An entry id.');
1749
+ return request.env((env) => previewMove(env, id));
1750
+ });
1751
+ context.app.get('/api/v1/accounting/followups', async (request) => request.env(async (env) => ({ rows: await followupRows(env) })));
1752
+ context.app.post('/api/v1/accounting/followups/:partner/send', async (request) => {
1753
+ const partner = partnerId(request.params);
1754
+ return request.env((env) => followUp(env, partner, { force: true }), {
1755
+ write: true,
1756
+ });
1757
+ });
1758
+ context.app.post('/api/v1/accounting/followups/:partner/pause', async (request) => {
1759
+ const partner = partnerId(request.params);
1760
+ const body = (request.body ?? {});
1761
+ const until = body.until === null || body.until === undefined ? null : String(body.until);
1762
+ const note = typeof body.note === 'string' && body.note.trim() !== '' ? body.note.trim() : null;
1763
+ return request.env(async (env) => {
1764
+ await pauseFollowup(env, partner, until, note);
1765
+ return { partner, pausedUntil: until };
1766
+ }, { write: true });
1767
+ });
1768
+ if (process.env['KOSH_SCHEDULES'] !== 'off') {
1769
+ const run = async () => {
1770
+ try {
1771
+ const companies = await context.shutro.bootstrap({ reason: 'payment follow-ups' }, async (env) => (await env.model('res.company').search({}))
1772
+ .ids);
1773
+ for (const company of companies)
1774
+ await context.shutro.bootstrap({ reason: 'payment follow-ups', company }, (env) => runFollowups(env));
1775
+ }
1776
+ catch (error) {
1777
+ context.app.log.error({ err: error }, 'payment follow-ups');
1778
+ }
1779
+ };
1780
+ // Once a day (a run sends each level once, so a restart sending again finds nothing new).
1781
+ const timer = setInterval(() => void run(), 86_400_000);
1782
+ timer.unref();
1783
+ const first = setTimeout(() => void run(), 60_000);
1784
+ first.unref();
1785
+ context.app.addHook('onClose', async () => {
1786
+ clearInterval(timer);
1787
+ clearTimeout(first);
1788
+ });
1789
+ }
1237
1790
  // The charts: the generic one and the installed localizations' (RFC 0016).
1238
1791
  const charts = chartsOf(context.registry.loaded.modules);
1239
1792
  const localizations = localizationsOf(context.registry.loaded.modules);
@@ -1313,6 +1866,100 @@ export const accounting = defineModule({
1313
1866
  throw new HttpProblem(400, 'invalid-body', 'Invalid request', 'lines is a list of journal item ids.');
1314
1867
  return ids;
1315
1868
  };
1869
+ // Bank statements (RFC 0029 §3.1): import, the proposals of a line, matching, writing off, pulling a feed.
1870
+ const reconciler = (env) => {
1871
+ if (!env.su && !env.administrator && !env.access.has('account.reconcile'))
1872
+ throw new HttpProblem(403, 'access', 'Reconciliation', 'Bank statements need the reconcile permission.');
1873
+ };
1874
+ const positiveId = (value, what) => {
1875
+ const id = Number(value);
1876
+ if (!Number.isSafeInteger(id) || id <= 0)
1877
+ throw new HttpProblem(400, 'invalid-body', 'Invalid request', `${what} is an id.`);
1878
+ return id;
1879
+ };
1880
+ context.app.post('/api/v1/accounting/statements/import', async (request) => {
1881
+ const body = (request.body ?? {});
1882
+ const journal = positiveId(body.journal, 'journal');
1883
+ const content = typeof body.content === 'string' ? body.content : '';
1884
+ if (content === '' || content.length > 5_000_000)
1885
+ throw new HttpProblem(400, 'invalid-body', 'Invalid request', 'content is the file’s text.');
1886
+ const format = String(body.format ?? 'csv');
1887
+ const rows = format === 'ofx'
1888
+ ? parseOfx(content)
1889
+ : format === 'camt'
1890
+ ? parseCamt(content)
1891
+ : format === 'csv'
1892
+ ? parseCsv(content, (body.mapping ?? {}))
1893
+ : null;
1894
+ if (rows === null)
1895
+ throw new HttpProblem(400, 'invalid-body', 'Invalid request', "format is 'csv', 'ofx' or 'camt'.");
1896
+ const money = (v) => v === undefined || v === null || v === '' ? undefined : String(v);
1897
+ return request.env(async (raw) => {
1898
+ const env = raw;
1899
+ reconciler(env);
1900
+ const start = money(body.balanceStart);
1901
+ const end = money(body.balanceEnd);
1902
+ return importStatement(env, {
1903
+ journal,
1904
+ rows,
1905
+ ...(typeof body.name === 'string' && body.name !== '' ? { name: body.name } : {}),
1906
+ ...(start === undefined ? {} : { balanceStart: start }),
1907
+ ...(end === undefined ? {} : { balanceEnd: end }),
1908
+ });
1909
+ }, { write: true });
1910
+ });
1911
+ context.app.get('/api/v1/accounting/statement-lines/:id/proposals', async (request) => {
1912
+ const id = positiveId(request.params.id, 'id');
1913
+ return request.env(async (raw) => {
1914
+ const env = raw;
1915
+ reconciler(env);
1916
+ return { proposals: await proposalsFor(env, id) };
1917
+ });
1918
+ });
1919
+ context.app.post('/api/v1/accounting/statement-lines/:id/match', async (request) => {
1920
+ const id = positiveId(request.params.id, 'id');
1921
+ const moves = request.body?.moves;
1922
+ if (!Array.isArray(moves) || moves.length === 0)
1923
+ throw new HttpProblem(400, 'invalid-body', 'Invalid request', 'moves is a list of document ids.');
1924
+ const ids = moves.map((m) => positiveId(m, 'moves'));
1925
+ return request.env((raw) => matchLine(raw, id, ids), { write: true });
1926
+ });
1927
+ context.app.post('/api/v1/accounting/statement-lines/:id/write-off', async (request) => {
1928
+ const id = positiveId(request.params.id, 'id');
1929
+ const body = (request.body ?? {});
1930
+ const account = positiveId(body.account, 'account');
1931
+ return request.env((raw) => writeOffLine(raw, id, {
1932
+ account,
1933
+ ...(typeof body.label === 'string' && body.label !== '' ? { label: body.label } : {}),
1934
+ }), { write: true });
1935
+ });
1936
+ context.app.post('/api/v1/accounting/statement-lines/:id/undo', async (request) => {
1937
+ const id = positiveId(request.params.id, 'id');
1938
+ return request.env((raw) => undoLine(raw, id), { write: true });
1939
+ });
1940
+ // Reconciliation rules (RFC 0029 §3.2): run on the open lines now, or a rule's dry run over the last days.
1941
+ context.app.post('/api/v1/accounting/reconcile-rules/run', async (request) => request.env(async (raw) => {
1942
+ const env = raw;
1943
+ reconciler(env);
1944
+ const open = await env
1945
+ .model('account.bank.statement.line')
1946
+ .search({ where: { state: 'open' }, limit: 2000 });
1947
+ return { results: await applyRules(env, open.ids) };
1948
+ }, { write: true }));
1949
+ context.app.get('/api/v1/accounting/reconcile-rules/:id/dry-run', async (request) => {
1950
+ const id = positiveId(request.params.id, 'id');
1951
+ const raw = Number(request.query.days ?? 90);
1952
+ const days = Number.isInteger(raw) && raw > 0 && raw <= 366 ? raw : 90;
1953
+ return request.env((env) => dryRunRule(env, id, days));
1954
+ });
1955
+ context.app.post('/api/v1/accounting/journals/:id/pull', async (request) => {
1956
+ const id = positiveId(request.params.id, 'id');
1957
+ return request.env(async (raw) => {
1958
+ const env = raw;
1959
+ reconciler(env);
1960
+ return pullFeed(env, id);
1961
+ }, { write: true });
1962
+ });
1316
1963
  context.app.post('/api/v1/accounting/reconcile', async (request) => {
1317
1964
  const ids = lineIds(request.body);
1318
1965
  const writeOff = request.body