shutro-erp 0.3.6 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (623) hide show
  1. package/dist/account_asset/.kosh/bindings.js +1 -1
  2. package/dist/account_asset/.kosh/schema.d.ts +530 -8
  3. package/dist/account_asset/i18n/bn.d.ts +2 -0
  4. package/dist/account_asset/i18n/bn.js +97 -0
  5. package/dist/account_asset/index.js +2 -0
  6. package/dist/account_asset/module.d.ts +4899 -1445
  7. package/dist/account_budget/.kosh/bindings.js +1 -1
  8. package/dist/account_budget/.kosh/schema.d.ts +1130 -56
  9. package/dist/account_budget/i18n/bn.d.ts +2 -0
  10. package/dist/account_budget/i18n/bn.js +63 -0
  11. package/dist/account_budget/index.js +14 -0
  12. package/dist/account_budget/module.d.ts +17958 -4532
  13. package/dist/account_budget/module.js +15 -0
  14. package/dist/account_portal/.kosh/bindings.js +1 -1
  15. package/dist/account_portal/.kosh/schema.d.ts +530 -8
  16. package/dist/account_portal/i18n/bn.d.ts +2 -0
  17. package/dist/account_portal/i18n/bn.js +6 -0
  18. package/dist/account_portal/index.js +2 -0
  19. package/dist/account_portal/module.d.ts +5167 -1693
  20. package/dist/accounting/.kosh/bindings.js +1 -1
  21. package/dist/accounting/.kosh/schema.d.ts +530 -8
  22. package/dist/accounting/closing.js +1 -0
  23. package/dist/accounting/fiscal.d.ts +578 -0
  24. package/dist/accounting/fiscal.js +401 -0
  25. package/dist/accounting/followups.d.ts +618 -0
  26. package/dist/accounting/followups.js +420 -0
  27. package/dist/accounting/i18n/bn.d.ts +2 -0
  28. package/dist/accounting/i18n/bn.js +425 -0
  29. package/dist/accounting/index.d.ts +2 -0
  30. package/dist/accounting/index.js +649 -2
  31. package/dist/accounting/module.d.ts +4998 -1451
  32. package/dist/accounting/module.js +124 -18
  33. package/dist/accounting/statements.d.ts +878 -0
  34. package/dist/accounting/statements.js +728 -0
  35. package/dist/accounting/web/BankReconcilePage.d.ts +9 -0
  36. package/dist/accounting/web/BankReconcilePage.js +138 -0
  37. package/dist/accounting/web/FollowupsPage.d.ts +8 -0
  38. package/dist/accounting/web/FollowupsPage.js +54 -0
  39. package/dist/accounting/web/PostingPreview.d.ts +8 -0
  40. package/dist/accounting/web/PostingPreview.js +26 -0
  41. package/dist/accounting/web/index.d.ts +3 -0
  42. package/dist/accounting/web/index.js +9 -0
  43. package/dist/accounting/web/messages.js +140 -0
  44. package/dist/approvals/.kosh/bindings.js +1 -1
  45. package/dist/approvals/.kosh/schema.d.ts +272 -4
  46. package/dist/approvals/demo.d.ts +7 -0
  47. package/dist/approvals/demo.js +41 -0
  48. package/dist/approvals/i18n/bn.d.ts +2 -0
  49. package/dist/approvals/i18n/bn.js +133 -0
  50. package/dist/approvals/index.d.ts +19 -1
  51. package/dist/approvals/index.js +477 -7
  52. package/dist/approvals/mails.d.ts +7 -2
  53. package/dist/approvals/mails.js +8 -3
  54. package/dist/approvals/module.d.ts +2930 -1
  55. package/dist/approvals/module.js +468 -7
  56. package/dist/approvals/web/Config.d.ts +12 -0
  57. package/dist/approvals/web/Config.js +60 -0
  58. package/dist/approvals/web/Matrix.d.ts +9 -0
  59. package/dist/approvals/web/Matrix.js +26 -0
  60. package/dist/approvals/web/index.d.ts +3 -1
  61. package/dist/approvals/web/index.js +8 -1
  62. package/dist/approvals/web/messages.js +92 -0
  63. package/dist/approvals_purchase/.kosh/bindings.js +15 -0
  64. package/dist/approvals_purchase/.kosh/schema.d.ts +1997 -0
  65. package/dist/approvals_purchase/i18n/bn.d.ts +2 -0
  66. package/dist/approvals_purchase/i18n/bn.js +5 -0
  67. package/dist/approvals_purchase/index.d.ts +3 -0
  68. package/dist/approvals_purchase/index.js +47 -0
  69. package/dist/approvals_purchase/module.d.ts +12670 -0
  70. package/dist/approvals_purchase/module.js +84 -0
  71. package/dist/attendance/.kosh/bindings.js +1 -1
  72. package/dist/attendance/.kosh/schema.d.ts +59 -1
  73. package/dist/attendance/i18n/bn.d.ts +2 -0
  74. package/dist/attendance/i18n/bn.js +147 -0
  75. package/dist/attendance/index.js +3 -1
  76. package/dist/attendance/module.d.ts +452 -8
  77. package/dist/automation/engine.js +1 -1
  78. package/dist/calendar/.kosh/bindings.js +1 -1
  79. package/dist/calendar/.kosh/schema.d.ts +2 -1
  80. package/dist/calendar/i18n/bn.d.ts +2 -0
  81. package/dist/calendar/i18n/bn.js +80 -0
  82. package/dist/calendar/index.js +77 -0
  83. package/dist/calendar/module.d.ts +26 -0
  84. package/dist/calendar/module.js +14 -4
  85. package/dist/cli/apps.js +25 -5
  86. package/dist/cli/init.js +14 -4
  87. package/dist/cli/templates.d.ts +1 -1
  88. package/dist/cli/templates.js +34 -5
  89. package/dist/contacts/.kosh/bindings.js +1 -1
  90. package/dist/contacts/.kosh/schema.d.ts +2 -1
  91. package/dist/contacts/i18n/bn.d.ts +2 -0
  92. package/dist/contacts/i18n/bn.js +67 -0
  93. package/dist/contacts/index.js +3 -0
  94. package/dist/contacts/module.d.ts +42 -0
  95. package/dist/contacts/module.js +6 -1
  96. package/dist/crm/.kosh/bindings.js +1 -1
  97. package/dist/crm/.kosh/schema.d.ts +2 -1
  98. package/dist/crm/i18n/bn.d.ts +2 -0
  99. package/dist/crm/i18n/bn.js +80 -0
  100. package/dist/crm/index.js +22 -0
  101. package/dist/crm/module.d.ts +20 -0
  102. package/dist/crm/module.js +4 -2
  103. package/dist/documents/.kosh/bindings.js +1 -1
  104. package/dist/documents/.kosh/schema.d.ts +2 -1
  105. package/dist/documents/i18n/bn.d.ts +2 -0
  106. package/dist/documents/i18n/bn.js +83 -0
  107. package/dist/documents/index.js +128 -1
  108. package/dist/documents/module.d.ts +20 -0
  109. package/dist/documents/module.js +1 -0
  110. package/dist/event/.kosh/bindings.js +1 -1
  111. package/dist/event/.kosh/schema.d.ts +2 -1
  112. package/dist/event/i18n/bn.d.ts +2 -0
  113. package/dist/event/i18n/bn.js +101 -0
  114. package/dist/event/index.js +66 -0
  115. package/dist/event/module.d.ts +20 -0
  116. package/dist/event/module.js +8 -1
  117. package/dist/event_account/.kosh/bindings.js +1 -1
  118. package/dist/event_account/.kosh/schema.d.ts +530 -8
  119. package/dist/event_account/i18n/bn.d.ts +2 -0
  120. package/dist/event_account/i18n/bn.js +5 -0
  121. package/dist/event_account/index.js +2 -0
  122. package/dist/event_account/module.d.ts +4905 -1431
  123. package/dist/expense/.kosh/bindings.js +1 -1
  124. package/dist/expense/.kosh/schema.d.ts +323 -2
  125. package/dist/expense/i18n/bn.d.ts +2 -0
  126. package/dist/expense/i18n/bn.js +155 -0
  127. package/dist/expense/index.js +8 -1
  128. package/dist/expense/module.d.ts +2715 -694
  129. package/dist/expense/module.js +3 -1
  130. package/dist/expense_account/.kosh/bindings.js +1 -1
  131. package/dist/expense_account/.kosh/schema.d.ts +587 -8
  132. package/dist/expense_account/i18n/bn.d.ts +2 -0
  133. package/dist/expense_account/i18n/bn.js +15 -0
  134. package/dist/expense_account/index.js +2 -0
  135. package/dist/expense_account/module.d.ts +8094 -2619
  136. package/dist/helpdesk/.kosh/bindings.js +1 -1
  137. package/dist/helpdesk/.kosh/schema.d.ts +2 -1
  138. package/dist/helpdesk/i18n/bn.d.ts +2 -0
  139. package/dist/helpdesk/i18n/bn.js +127 -0
  140. package/dist/helpdesk/index.js +2 -0
  141. package/dist/helpdesk/module.d.ts +20 -0
  142. package/dist/hr/.kosh/bindings.js +1 -1
  143. package/dist/hr/.kosh/schema.d.ts +59 -1
  144. package/dist/hr/demo.js +11 -1
  145. package/dist/hr/i18n/bn.d.ts +2 -0
  146. package/dist/hr/i18n/bn.js +126 -0
  147. package/dist/hr/index.d.ts +1 -1
  148. package/dist/hr/index.js +158 -12
  149. package/dist/hr/module.d.ts +932 -59
  150. package/dist/hr/module.js +114 -17
  151. package/dist/{mrp → indent}/.kosh/bindings.js +2 -2
  152. package/dist/indent/.kosh/schema.d.ts +2084 -0
  153. package/dist/indent/demo.d.ts +7 -0
  154. package/dist/indent/demo.js +48 -0
  155. package/dist/indent/i18n/bn.d.ts +2 -0
  156. package/dist/indent/i18n/bn.js +143 -0
  157. package/dist/indent/index.d.ts +3 -0
  158. package/dist/indent/index.js +450 -0
  159. package/dist/{mrp → indent}/module.d.ts +7164 -3075
  160. package/dist/indent/module.js +792 -0
  161. package/dist/indent_purchase/.kosh/bindings.d.ts +22 -0
  162. package/dist/indent_purchase/.kosh/bindings.js +15 -0
  163. package/dist/indent_purchase/.kosh/schema.d.ts +2710 -0
  164. package/dist/indent_purchase/i18n/bn.d.ts +2 -0
  165. package/dist/indent_purchase/i18n/bn.js +13 -0
  166. package/dist/indent_purchase/index.d.ts +3 -0
  167. package/dist/indent_purchase/index.js +61 -0
  168. package/dist/indent_purchase/module.d.ts +27950 -0
  169. package/dist/indent_purchase/module.js +163 -0
  170. package/dist/l10n_bd/.kosh/bindings.js +1 -1
  171. package/dist/l10n_bd/.kosh/schema.d.ts +530 -8
  172. package/dist/l10n_bd/i18n/bn.d.ts +2 -0
  173. package/dist/l10n_bd/i18n/bn.js +69 -0
  174. package/dist/l10n_bd/index.js +2 -0
  175. package/dist/l10n_bd/module.d.ts +5167 -1693
  176. package/dist/l10n_bd_payroll/.kosh/bindings.js +1 -1
  177. package/dist/l10n_bd_payroll/.kosh/schema.d.ts +587 -8
  178. package/dist/l10n_bd_payroll/i18n/bn.d.ts +2 -0
  179. package/dist/l10n_bd_payroll/i18n/bn.js +4 -0
  180. package/dist/l10n_bd_payroll/index.js +2 -0
  181. package/dist/l10n_bd_payroll/module.d.ts +5910 -1548
  182. package/dist/l10n_bd_pos/.kosh/bindings.d.ts +22 -0
  183. package/dist/{mrp_account → l10n_bd_pos}/.kosh/bindings.js +2 -2
  184. package/dist/{mrp_account → l10n_bd_pos}/.kosh/schema.d.ts +693 -651
  185. package/dist/l10n_bd_pos/i18n/bn.d.ts +2 -0
  186. package/dist/l10n_bd_pos/i18n/bn.js +32 -0
  187. package/dist/l10n_bd_pos/index.d.ts +3 -0
  188. package/dist/l10n_bd_pos/index.js +111 -0
  189. package/dist/{mrp_account → l10n_bd_pos}/module.d.ts +7402 -7647
  190. package/dist/l10n_bd_pos/module.js +43 -0
  191. package/dist/l10n_in/.kosh/bindings.js +1 -1
  192. package/dist/l10n_in/.kosh/schema.d.ts +530 -8
  193. package/dist/l10n_in/i18n/bn.d.ts +2 -0
  194. package/dist/l10n_in/i18n/bn.js +95 -0
  195. package/dist/l10n_in/index.js +2 -0
  196. package/dist/l10n_in/module.d.ts +6703 -1652
  197. package/dist/l10n_in/module.js +25 -5
  198. package/dist/l10n_in/web/GstSettings.js +2 -2
  199. package/dist/mail/inbound/handle.js +2 -4
  200. package/dist/mail/inbound/models.js +5 -3
  201. package/dist/mail/index.d.ts +12 -1
  202. package/dist/mail/index.js +139 -2
  203. package/dist/mail/send.d.ts +56 -0
  204. package/dist/mail/send.js +394 -0
  205. package/dist/mail/web/SendButton.d.ts +9 -0
  206. package/dist/mail/web/SendButton.js +71 -0
  207. package/dist/mail/web/SendSelected.d.ts +8 -0
  208. package/dist/mail/web/SendSelected.js +33 -0
  209. package/dist/mail/web/index.d.ts +2 -0
  210. package/dist/mail/web/index.js +6 -0
  211. package/dist/mail/web/messages.js +36 -0
  212. package/dist/maintenance/.kosh/bindings.js +1 -1
  213. package/dist/maintenance/.kosh/schema.d.ts +2 -1
  214. package/dist/maintenance/i18n/bn.d.ts +2 -0
  215. package/dist/maintenance/i18n/bn.js +132 -0
  216. package/dist/maintenance/index.js +85 -0
  217. package/dist/maintenance/module.d.ts +25 -0
  218. package/dist/maintenance/module.js +27 -9
  219. package/dist/maintenance_stock/.kosh/bindings.js +1 -1
  220. package/dist/maintenance_stock/.kosh/schema.d.ts +298 -2
  221. package/dist/maintenance_stock/i18n/bn.d.ts +2 -0
  222. package/dist/maintenance_stock/i18n/bn.js +21 -0
  223. package/dist/maintenance_stock/index.js +2 -0
  224. package/dist/maintenance_stock/module.d.ts +5302 -1256
  225. package/dist/maintenance_stock/module.js +1 -0
  226. package/dist/modules-sdk/apps.d.ts +10 -0
  227. package/dist/modules-sdk/apps.js +32 -0
  228. package/dist/modules-sdk/index.d.ts +1 -1
  229. package/dist/modules-sdk/manifest.d.ts +68 -2
  230. package/dist/payment/.kosh/bindings.js +1 -1
  231. package/dist/payment/.kosh/schema.d.ts +530 -8
  232. package/dist/payment/i18n/bn.d.ts +2 -0
  233. package/dist/payment/i18n/bn.js +59 -0
  234. package/dist/payment/index.js +85 -0
  235. package/dist/payment/module.d.ts +5134 -1660
  236. package/dist/payment/module.js +17 -3
  237. package/dist/payment/settle.js +1 -0
  238. package/dist/payroll/.kosh/bindings.js +1 -1
  239. package/dist/payroll/.kosh/schema.d.ts +59 -1
  240. package/dist/payroll/i18n/bn.d.ts +2 -0
  241. package/dist/payroll/i18n/bn.js +206 -0
  242. package/dist/payroll/index.js +2 -0
  243. package/dist/payroll/module.d.ts +936 -48
  244. package/dist/payroll_account/.kosh/bindings.js +1 -1
  245. package/dist/payroll_account/.kosh/schema.d.ts +587 -8
  246. package/dist/payroll_account/i18n/bn.d.ts +2 -0
  247. package/dist/payroll_account/i18n/bn.js +10 -0
  248. package/dist/payroll_account/index.js +2 -0
  249. package/dist/payroll_account/module.d.ts +7534 -3192
  250. package/dist/permissions/approvals.d.ts +97 -4
  251. package/dist/permissions/approvals.js +780 -31
  252. package/dist/permissions/index.d.ts +1 -1
  253. package/dist/permissions/index.js +2 -2
  254. package/dist/permissions/models.js +177 -5
  255. package/dist/permissions/routes.d.ts +3 -0
  256. package/dist/permissions/routes.js +36 -2
  257. package/dist/permissions/web/ApprovalPanel.js +43 -5
  258. package/dist/permissions/web/messages.js +52 -0
  259. package/dist/portal/.kosh/bindings.js +1 -1
  260. package/dist/portal/.kosh/schema.d.ts +2 -1
  261. package/dist/portal/documents.d.ts +3 -0
  262. package/dist/portal/documents.js +21 -1
  263. package/dist/portal/i18n/bn.d.ts +2 -0
  264. package/dist/portal/i18n/bn.js +33 -0
  265. package/dist/portal/index.js +2 -0
  266. package/dist/portal/module.d.ts +20 -0
  267. package/dist/portal/routes-documents.js +76 -0
  268. package/dist/pos/.kosh/bindings.js +1 -1
  269. package/dist/pos/.kosh/schema.d.ts +531 -8
  270. package/dist/pos/i18n/bn.d.ts +2 -0
  271. package/dist/pos/i18n/bn.js +133 -0
  272. package/dist/pos/index.js +83 -1
  273. package/dist/pos/module.d.ts +6888 -1777
  274. package/dist/pos/module.js +49 -5
  275. package/dist/pos/routes.js +80 -7
  276. package/dist/pos/web/Register.js +2 -5
  277. package/dist/pos_stock/.kosh/bindings.js +1 -1
  278. package/dist/pos_stock/.kosh/schema.d.ts +626 -9
  279. package/dist/pos_stock/i18n/bn.d.ts +2 -0
  280. package/dist/pos_stock/i18n/bn.js +6 -0
  281. package/dist/pos_stock/index.js +2 -0
  282. package/dist/pos_stock/module.d.ts +10798 -3276
  283. package/dist/product/.kosh/bindings.js +1 -1
  284. package/dist/product/.kosh/schema.d.ts +202 -1
  285. package/dist/product/i18n/bn.d.ts +2 -0
  286. package/dist/product/i18n/bn.js +175 -0
  287. package/dist/product/index.d.ts +1 -0
  288. package/dist/product/index.js +288 -1
  289. package/dist/product/module.d.ts +1725 -0
  290. package/dist/product/module.js +66 -6
  291. package/dist/product/pricelist.d.ts +575 -0
  292. package/dist/product/pricelist.js +257 -0
  293. package/dist/product/variants.d.ts +908 -0
  294. package/dist/product/variants.js +251 -0
  295. package/dist/production/.kosh/bindings.d.ts +22 -0
  296. package/dist/production/.kosh/bindings.js +15 -0
  297. package/dist/production/.kosh/schema.d.ts +2345 -0
  298. package/dist/{mrp → production}/demo.d.ts +1 -1
  299. package/dist/{mrp → production}/demo.js +5 -5
  300. package/dist/production/depth.d.ts +790 -0
  301. package/dist/production/depth.js +262 -0
  302. package/dist/production/i18n/bn.d.ts +2 -0
  303. package/dist/production/i18n/bn.js +350 -0
  304. package/dist/production/index.d.ts +6 -0
  305. package/dist/production/index.js +1256 -0
  306. package/dist/production/module.d.ts +17327 -0
  307. package/dist/production/module.js +1333 -0
  308. package/dist/production/plan.d.ts +921 -0
  309. package/dist/production/plan.js +511 -0
  310. package/dist/production/schedule.d.ts +656 -0
  311. package/dist/production/schedule.js +309 -0
  312. package/dist/production_account/.kosh/bindings.d.ts +22 -0
  313. package/dist/production_account/.kosh/bindings.js +15 -0
  314. package/dist/production_account/.kosh/schema.d.ts +3496 -0
  315. package/dist/production_account/i18n/bn.d.ts +2 -0
  316. package/dist/production_account/i18n/bn.js +93 -0
  317. package/dist/production_account/index.d.ts +4 -0
  318. package/dist/production_account/index.js +246 -0
  319. package/dist/production_account/module.d.ts +1192 -0
  320. package/dist/{mrp_account → production_account}/module.js +72 -18
  321. package/dist/production_account/overhead.d.ts +1195 -0
  322. package/dist/production_account/overhead.js +554 -0
  323. package/dist/project/.kosh/bindings.js +1 -1
  324. package/dist/project/.kosh/schema.d.ts +65 -2
  325. package/dist/project/i18n/bn.d.ts +2 -0
  326. package/dist/project/i18n/bn.js +383 -0
  327. package/dist/project/index.js +123 -0
  328. package/dist/project/module.d.ts +20 -0
  329. package/dist/project/module.js +73 -14
  330. package/dist/project_account/.kosh/bindings.js +1 -1
  331. package/dist/project_account/.kosh/schema.d.ts +530 -8
  332. package/dist/project_account/i18n/bn.d.ts +2 -0
  333. package/dist/project_account/i18n/bn.js +6 -0
  334. package/dist/project_account/index.js +2 -0
  335. package/dist/project_account/module.d.ts +4926 -1452
  336. package/dist/project_portal/.kosh/bindings.js +1 -1
  337. package/dist/project_portal/.kosh/schema.d.ts +65 -2
  338. package/dist/project_portal/i18n/bn.d.ts +2 -0
  339. package/dist/project_portal/i18n/bn.js +6 -0
  340. package/dist/project_portal/index.js +2 -0
  341. package/dist/project_portal/module.d.ts +40 -0
  342. package/dist/project_purchase/.kosh/bindings.js +1 -1
  343. package/dist/project_purchase/.kosh/schema.d.ts +1126 -53
  344. package/dist/project_purchase/i18n/bn.d.ts +2 -0
  345. package/dist/project_purchase/i18n/bn.js +4 -0
  346. package/dist/project_purchase/index.js +2 -0
  347. package/dist/project_purchase/module.d.ts +17912 -4446
  348. package/dist/purchase/.kosh/bindings.js +1 -1
  349. package/dist/purchase/.kosh/schema.d.ts +813 -3
  350. package/dist/purchase/comparison.d.ts +993 -0
  351. package/dist/purchase/comparison.js +415 -0
  352. package/dist/purchase/extras.d.ts +1509 -0
  353. package/dist/purchase/extras.js +445 -0
  354. package/dist/purchase/i18n/bn.d.ts +2 -0
  355. package/dist/purchase/i18n/bn.js +413 -0
  356. package/dist/purchase/index.d.ts +5 -0
  357. package/dist/purchase/index.js +1280 -4
  358. package/dist/purchase/module.d.ts +7139 -398
  359. package/dist/purchase/module.js +295 -11
  360. package/dist/purchase/request.d.ts +696 -0
  361. package/dist/purchase/request.js +446 -0
  362. package/dist/purchase/tender.d.ts +1208 -0
  363. package/dist/purchase/tender.js +507 -0
  364. package/dist/purchase/vendorprice.d.ts +340 -0
  365. package/dist/purchase/vendorprice.js +153 -0
  366. package/dist/purchase_account/.kosh/bindings.js +1 -1
  367. package/dist/purchase_account/.kosh/schema.d.ts +1130 -57
  368. package/dist/purchase_account/i18n/bn.d.ts +2 -0
  369. package/dist/purchase_account/i18n/bn.js +22 -0
  370. package/dist/purchase_account/index.js +19 -0
  371. package/dist/purchase_account/module.d.ts +12276 -2247
  372. package/dist/purchase_account/module.js +241 -9
  373. package/dist/purchase_portal/.kosh/bindings.js +1 -1
  374. package/dist/purchase_portal/.kosh/schema.d.ts +813 -3
  375. package/dist/purchase_portal/i18n/bn.d.ts +2 -0
  376. package/dist/purchase_portal/i18n/bn.js +5 -0
  377. package/dist/purchase_portal/index.js +2 -0
  378. package/dist/purchase_portal/module.d.ts +6849 -353
  379. package/dist/purchase_stock/.kosh/bindings.js +1 -1
  380. package/dist/purchase_stock/.kosh/schema.d.ts +910 -4
  381. package/dist/purchase_stock/i18n/bn.d.ts +2 -0
  382. package/dist/purchase_stock/i18n/bn.js +19 -0
  383. package/dist/purchase_stock/index.d.ts +1 -1
  384. package/dist/purchase_stock/index.js +29 -0
  385. package/dist/purchase_stock/module.d.ts +12410 -1864
  386. package/dist/purchase_stock/module.js +81 -9
  387. package/dist/purchase_stock/scorecard.d.ts +22 -0
  388. package/dist/purchase_stock/scorecard.js +77 -0
  389. package/dist/purchase_stock/web/Scorecard.d.ts +7 -0
  390. package/dist/purchase_stock/web/Scorecard.js +22 -0
  391. package/dist/purchase_stock/web/index.d.ts +11 -0
  392. package/dist/purchase_stock/web/index.js +16 -0
  393. package/dist/purchase_stock/web/messages.d.ts +2 -0
  394. package/dist/purchase_stock/web/messages.js +27 -0
  395. package/dist/purchase_stock_account/.kosh/bindings.js +1 -1
  396. package/dist/purchase_stock_account/.kosh/schema.d.ts +1286 -58
  397. package/dist/purchase_stock_account/i18n/bn.d.ts +2 -0
  398. package/dist/purchase_stock_account/i18n/bn.js +8 -0
  399. package/dist/purchase_stock_account/index.js +18 -0
  400. package/dist/purchase_stock_account/module.d.ts +7 -37995
  401. package/dist/purchase_stock_account/module.js +24 -3
  402. package/dist/recruitment/.kosh/bindings.js +1 -1
  403. package/dist/recruitment/.kosh/schema.d.ts +59 -1
  404. package/dist/recruitment/i18n/bn.d.ts +2 -0
  405. package/dist/recruitment/i18n/bn.js +93 -0
  406. package/dist/recruitment/index.js +64 -0
  407. package/dist/recruitment/module.d.ts +458 -8
  408. package/dist/recruitment/module.js +11 -3
  409. package/dist/reporting/documents.d.ts +5 -0
  410. package/dist/reporting/documents.js +11 -1
  411. package/dist/reporting/index.d.ts +1 -1
  412. package/dist/reporting/index.js +1 -1
  413. package/dist/reporting/web/CalendarView.d.ts +18 -5
  414. package/dist/reporting/web/CalendarView.js +163 -29
  415. package/dist/reporting/web/messages.js +18 -0
  416. package/dist/sale_account/.kosh/bindings.js +1 -1
  417. package/dist/sale_account/.kosh/schema.d.ts +642 -16
  418. package/dist/sale_account/i18n/bn.d.ts +2 -0
  419. package/dist/sale_account/i18n/bn.js +48 -0
  420. package/dist/sale_account/index.d.ts +1 -1
  421. package/dist/sale_account/index.js +102 -4
  422. package/dist/sale_account/module.d.ts +8254 -2212
  423. package/dist/sale_account/module.js +535 -46
  424. package/dist/sale_crm/.kosh/bindings.d.ts +22 -0
  425. package/dist/sale_crm/.kosh/bindings.js +15 -0
  426. package/dist/{mrp → sale_crm}/.kosh/schema.d.ts +389 -567
  427. package/dist/sale_crm/i18n/bn.d.ts +2 -0
  428. package/dist/sale_crm/i18n/bn.js +9 -0
  429. package/dist/sale_crm/index.d.ts +7 -0
  430. package/dist/sale_crm/index.js +104 -0
  431. package/dist/sale_crm/module.d.ts +5609 -0
  432. package/dist/sale_crm/module.js +73 -0
  433. package/dist/sale_portal/.kosh/bindings.js +1 -1
  434. package/dist/sale_portal/.kosh/schema.d.ts +291 -4
  435. package/dist/sale_portal/i18n/bn.d.ts +2 -0
  436. package/dist/sale_portal/i18n/bn.js +7 -0
  437. package/dist/sale_portal/index.js +10 -0
  438. package/dist/sale_portal/module.d.ts +2564 -294
  439. package/dist/sale_project/.kosh/bindings.js +1 -1
  440. package/dist/sale_project/.kosh/schema.d.ts +354 -5
  441. package/dist/sale_project/i18n/bn.d.ts +2 -0
  442. package/dist/sale_project/i18n/bn.js +12 -0
  443. package/dist/sale_project/index.js +2 -0
  444. package/dist/sale_project/module.d.ts +6249 -2402
  445. package/dist/sale_stock/.kosh/bindings.js +1 -1
  446. package/dist/sale_stock/.kosh/schema.d.ts +387 -5
  447. package/dist/sale_stock/i18n/bn.d.ts +2 -0
  448. package/dist/sale_stock/i18n/bn.js +15 -0
  449. package/dist/sale_stock/index.js +2 -0
  450. package/dist/sale_stock/module.d.ts +8057 -1759
  451. package/dist/sale_stock/module.js +20 -3
  452. package/dist/sales/.kosh/bindings.js +1 -1
  453. package/dist/sales/.kosh/schema.d.ts +291 -4
  454. package/dist/sales/i18n/bn.d.ts +2 -0
  455. package/dist/sales/i18n/bn.js +128 -0
  456. package/dist/sales/index.js +120 -5
  457. package/dist/sales/module.d.ts +3567 -633
  458. package/dist/sales/module.js +306 -11
  459. package/dist/server/api/duplicate.d.ts +14 -0
  460. package/dist/server/api/duplicate.js +75 -0
  461. package/dist/server/api/explain.d.ts +70 -0
  462. package/dist/server/api/explain.js +111 -0
  463. package/dist/server/api/metadata.d.ts +2 -0
  464. package/dist/server/api/metadata.js +9 -0
  465. package/dist/server/api/openapi.js +15 -0
  466. package/dist/server/api/rest.d.ts +1 -0
  467. package/dist/server/api/rest.js +76 -12
  468. package/dist/server/api/views.js +1 -1
  469. package/dist/server/apps.d.ts +16 -1
  470. package/dist/server/apps.js +164 -2
  471. package/dist/server/auth/base.js +2 -0
  472. package/dist/server/auth/service.d.ts +8 -0
  473. package/dist/server/auth/service.js +19 -0
  474. package/dist/server/events.d.ts +13 -0
  475. package/dist/server/events.js +22 -0
  476. package/dist/server/i18n.d.ts +27 -0
  477. package/dist/server/i18n.js +143 -0
  478. package/dist/server/index.d.ts +2 -0
  479. package/dist/server/index.js +2 -0
  480. package/dist/server/server.js +6 -0
  481. package/dist/settings/company.d.ts +3 -1
  482. package/dist/settings/company.js +26 -5
  483. package/dist/settings/routes.d.ts +10 -0
  484. package/dist/settings/routes.js +19 -3
  485. package/dist/settings/web/AppsPage.d.ts +3 -2
  486. package/dist/settings/web/AppsPage.js +26 -8
  487. package/dist/settings/web/CompaniesPage.js +91 -6
  488. package/dist/settings/web/messages.js +64 -0
  489. package/dist/sign/.kosh/bindings.js +1 -1
  490. package/dist/sign/.kosh/schema.d.ts +2 -1
  491. package/dist/sign/i18n/bn.d.ts +2 -0
  492. package/dist/sign/i18n/bn.js +97 -0
  493. package/dist/sign/index.d.ts +15 -0
  494. package/dist/sign/index.js +129 -1
  495. package/dist/sign/module.d.ts +40 -0
  496. package/dist/sign/module.js +11 -2
  497. package/dist/stock/.kosh/bindings.js +1 -1
  498. package/dist/stock/.kosh/schema.d.ts +298 -2
  499. package/dist/stock/i18n/bn.d.ts +2 -0
  500. package/dist/stock/i18n/bn.js +311 -0
  501. package/dist/stock/index.d.ts +3 -1
  502. package/dist/stock/index.js +442 -3
  503. package/dist/stock/ledger.d.ts +78 -0
  504. package/dist/stock/ledger.js +582 -0
  505. package/dist/stock/module.d.ts +5280 -2044
  506. package/dist/stock/module.js +222 -23
  507. package/dist/stock/replenish.js +16 -1
  508. package/dist/stock/returns.d.ts +157 -0
  509. package/dist/stock/returns.js +163 -0
  510. package/dist/stock/web/Ledger.d.ts +9 -0
  511. package/dist/stock/web/Ledger.js +108 -0
  512. package/dist/stock/web/Operations.d.ts +8 -0
  513. package/dist/stock/web/Operations.js +33 -0
  514. package/dist/stock/web/ReturnButton.d.ts +7 -0
  515. package/dist/stock/web/ReturnButton.js +62 -0
  516. package/dist/stock/web/index.d.ts +3 -0
  517. package/dist/stock/web/index.js +9 -0
  518. package/dist/stock/web/messages.js +154 -0
  519. package/dist/stock_account/.kosh/bindings.js +1 -1
  520. package/dist/stock_account/.kosh/schema.d.ts +682 -9
  521. package/dist/stock_account/i18n/bn.d.ts +2 -0
  522. package/dist/stock_account/i18n/bn.js +73 -0
  523. package/dist/stock_account/index.d.ts +1 -0
  524. package/dist/stock_account/index.js +131 -3
  525. package/dist/stock_account/landed.d.ts +429 -0
  526. package/dist/stock_account/landed.js +335 -0
  527. package/dist/stock_account/module.d.ts +11247 -3363
  528. package/dist/stock_account/module.js +135 -6
  529. package/dist/stock_account/web/LandedPreview.d.ts +7 -0
  530. package/dist/stock_account/web/LandedPreview.js +23 -0
  531. package/dist/stock_account/web/index.d.ts +11 -0
  532. package/dist/stock_account/web/index.js +16 -0
  533. package/dist/stock_account/web/messages.d.ts +2 -0
  534. package/dist/stock_account/web/messages.js +27 -0
  535. package/dist/todo/i18n/bn.d.ts +2 -0
  536. package/dist/todo/i18n/bn.js +66 -0
  537. package/dist/todo/index.js +59 -0
  538. package/dist/todo/module.d.ts +5 -0
  539. package/dist/todo/module.js +5 -3
  540. package/dist/trade_finance/.kosh/bindings.js +1 -1
  541. package/dist/trade_finance/.kosh/schema.d.ts +2 -1
  542. package/dist/trade_finance/i18n/bn.d.ts +2 -0
  543. package/dist/trade_finance/i18n/bn.js +162 -0
  544. package/dist/trade_finance/index.js +93 -0
  545. package/dist/trade_finance/module.d.ts +26 -0
  546. package/dist/trade_finance/module.js +27 -8
  547. package/dist/trade_finance_account/.kosh/bindings.js +1 -1
  548. package/dist/trade_finance_account/.kosh/schema.d.ts +530 -8
  549. package/dist/trade_finance_account/i18n/bn.d.ts +2 -0
  550. package/dist/trade_finance_account/i18n/bn.js +27 -0
  551. package/dist/trade_finance_account/index.js +2 -0
  552. package/dist/trade_finance_account/module.d.ts +4906 -1432
  553. package/dist/trade_finance_account/module.js +1 -0
  554. package/dist/trade_finance_purchase/.kosh/bindings.js +1 -1
  555. package/dist/trade_finance_purchase/.kosh/schema.d.ts +813 -3
  556. package/dist/trade_finance_purchase/i18n/bn.d.ts +2 -0
  557. package/dist/trade_finance_purchase/i18n/bn.js +6 -0
  558. package/dist/trade_finance_purchase/index.js +2 -0
  559. package/dist/trade_finance_purchase/module.d.ts +6909 -413
  560. package/dist/trade_finance_sale/.kosh/bindings.js +1 -1
  561. package/dist/trade_finance_sale/.kosh/schema.d.ts +291 -4
  562. package/dist/trade_finance_sale/i18n/bn.d.ts +2 -0
  563. package/dist/trade_finance_sale/i18n/bn.js +6 -0
  564. package/dist/trade_finance_sale/index.js +2 -0
  565. package/dist/trade_finance_sale/module.d.ts +2601 -331
  566. package/dist/ui/api.d.ts +2 -0
  567. package/dist/ui/app.d.ts +9 -0
  568. package/dist/ui/app.js +24 -4
  569. package/dist/ui/components/AppIcon.js +2 -2
  570. package/dist/ui/components/Explain.d.ts +69 -0
  571. package/dist/ui/components/Explain.js +62 -0
  572. package/dist/ui/context.d.ts +8 -1
  573. package/dist/ui/context.js +34 -1
  574. package/dist/ui/i18n/messages.d.ts +36 -0
  575. package/dist/ui/i18n/messages.js +72 -0
  576. package/dist/ui/index.d.ts +2 -1
  577. package/dist/ui/index.js +1 -0
  578. package/dist/ui/registry.d.ts +14 -0
  579. package/dist/ui/registry.js +10 -0
  580. package/dist/ui/views/FormView.d.ts +6 -0
  581. package/dist/ui/views/FormView.js +47 -10
  582. package/dist/ui/views/ListView.d.ts +8 -0
  583. package/dist/ui/views/ListView.js +10 -3
  584. package/dist/ui/views/StatsRow.js +2 -1
  585. package/dist/views/extend.js +12 -0
  586. package/dist/views/types.d.ts +13 -2
  587. package/dist/views/validate.js +8 -1
  588. package/dist/website/.kosh/bindings.js +1 -1
  589. package/dist/website/.kosh/schema.d.ts +2 -1
  590. package/dist/website/i18n/bn.d.ts +2 -0
  591. package/dist/website/i18n/bn.js +113 -0
  592. package/dist/website/index.js +36 -0
  593. package/dist/website/module.d.ts +20 -0
  594. package/dist/website/module.js +29 -5
  595. package/dist/website_crm/.kosh/bindings.js +1 -1
  596. package/dist/website_crm/.kosh/schema.d.ts +2 -1
  597. package/dist/website_crm/i18n/bn.d.ts +2 -0
  598. package/dist/website_crm/i18n/bn.js +5 -0
  599. package/dist/website_crm/index.js +2 -0
  600. package/dist/website_crm/module.d.ts +40 -0
  601. package/dist/website_sale/.kosh/bindings.js +1 -1
  602. package/dist/website_sale/.kosh/schema.d.ts +642 -17
  603. package/dist/website_sale/i18n/bn.d.ts +2 -0
  604. package/dist/website_sale/i18n/bn.js +132 -0
  605. package/dist/website_sale/index.js +83 -1
  606. package/dist/website_sale/module.d.ts +18705 -5550
  607. package/dist/website_sale/module.js +32 -10
  608. package/dist/website_sale/shop.js +22 -9
  609. package/dist/website_sale_stock/.kosh/bindings.js +1 -1
  610. package/dist/website_sale_stock/.kosh/schema.d.ts +737 -18
  611. package/dist/website_sale_stock/i18n/bn.d.ts +2 -0
  612. package/dist/website_sale_stock/i18n/bn.js +4 -0
  613. package/dist/website_sale_stock/index.js +2 -0
  614. package/dist/website_sale_stock/module.d.ts +10 -24997
  615. package/dist/website_sale_stock/module.js +7 -3
  616. package/package.json +36 -8
  617. package/dist/mrp/index.d.ts +0 -3
  618. package/dist/mrp/index.js +0 -393
  619. package/dist/mrp/module.js +0 -757
  620. package/dist/mrp_account/index.d.ts +0 -3
  621. package/dist/mrp_account/index.js +0 -22
  622. /package/dist/{mrp → approvals_purchase}/.kosh/bindings.d.ts +0 -0
  623. /package/dist/{mrp_account → indent}/.kosh/bindings.d.ts +0 -0
@@ -5,18 +5,20 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
5
5
  * assistance, and saves with compare-and-set (a record changed by someone else since it was opened is not
6
6
  * overwritten: the user reloads). Conditions only decide display; the server re-checks every write.
7
7
  */
8
- import { evaluate, holds, } from '../../views/index.js';
8
+ import { evaluate, holds, resolveRecord, } from '../../views/index.js';
9
9
  import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
10
- import { useBlocker, useParams } from '@tanstack/react-router';
11
- import { ArrowLeft, Check, ChevronLeft, ChevronRight, CircleDot, MoreHorizontal, PanelRight, Plus, Trash2, } from 'lucide-react';
10
+ import { useBlocker, useNavigate, useParams } from '@tanstack/react-router';
11
+ import { ArrowLeft, Check, ChevronLeft, ChevronRight, CircleDot, Copy, MoreHorizontal, PanelRight, Plus, Trash2, } from 'lucide-react';
12
12
  import { useEffect, useId, useMemo, useRef, useState } from 'react';
13
13
  import { useTranslation } from 'react-i18next';
14
14
  import { ApiError, NetworkError, } from '../api.js';
15
+ import { Explain } from '../components/Explain.js';
15
16
  import { Alert, Button, Dialog, Label, Menu, MenuContent, MenuItem, MenuTrigger, Spinner, Tabs, TabsContent, TabsList, TabsTrigger, } from '../components/primitives.js';
16
17
  import { useKosh } from '../context.js';
17
18
  import { useDesign } from '../design.js';
18
19
  import { cn } from '../lib/cn.js';
19
20
  import { useLiveRecord } from '../live.js';
21
+ import { setPrefill } from '../prefill.js';
20
22
  import { useToast } from '../shell/toast.js';
21
23
  import { StatsRow } from './StatsRow.js';
22
24
  import { StatusChip } from './StatusChip.js';
@@ -188,6 +190,7 @@ export function FormView({ served, recordId, defaults, onSaved, onBack, crumbs,
188
190
  const design = useDesign();
189
191
  const toast = useToast();
190
192
  const queryClient = useQueryClient();
193
+ const navigateTo = useNavigate();
191
194
  const formId = useId();
192
195
  const [railOpen, setRailOpen] = useRail();
193
196
  const route = useParams({ strict: false });
@@ -380,6 +383,16 @@ export function FormView({ served, recordId, defaults, onSaved, onBack, crumbs,
380
383
  },
381
384
  onError: fail,
382
385
  });
386
+ // Duplicate (RFC 0023 R1): a copy made by the server as the user; the form opens it.
387
+ const duplicate = useMutation({
388
+ mutationFn: () => api.call('POST', `/api/v1/models/${model}/${String(recordId)}/duplicate`, {}),
389
+ onSuccess: async (copy) => {
390
+ await queryClient.invalidateQueries({ queryKey: ['list', model] });
391
+ toast({ title: t('views.duplicated') });
392
+ onSaved(copy.id);
393
+ },
394
+ onError: fail,
395
+ });
383
396
  const remove = useMutation({
384
397
  mutationFn: () => api.remove(model, recordId),
385
398
  onSuccess: async () => {
@@ -447,7 +460,7 @@ export function FormView({ served, recordId, defaults, onSaved, onBack, crumbs,
447
460
  const readonly = locked || field.readonly || holds(node.readonlyWhen, values, env);
448
461
  const id = `${formId}-${node.id}`;
449
462
  const invalid = problem?.problem.detail.includes(node.field) === true;
450
- return (_jsxs("div", { className: cn('grid gap-1', (field.kind === 'text' || field.kind === 'html') && 'col-span-full'), children: [_jsxs(Label, { htmlFor: id, children: [node.label ?? field.label, (field.required || holds(node.requiredWhen, values, env)) && !readonly ? (_jsxs("span", { "aria-hidden": true, className: "text-danger", children: [' ', "*"] })) : null, recordId === 'new' && proposed?.includes(node.field) === true ? (_jsx("span", { className: "ms-2 rounded bg-accent px-1.5 py-0.5 text-[10px] font-medium text-accent-foreground", children: t('views.proposed') })) : null] }), _jsx("div", { className: "min-h-9 py-1.5 text-sm", children: _jsx(Widget, { id: id, node: node, field: field, value: values[node.field], record: values, model: model, readonly: readonly, onChange: (v) => change(node.field, v), invalid: invalid }) }), (node.help ?? field.help) === undefined ? null : (_jsx("p", { className: "text-xs text-muted-foreground", children: node.help ?? field.help }))] }, node.id));
463
+ return (_jsxs("div", { className: cn('grid gap-1', (field.kind === 'text' || field.kind === 'html') && 'col-span-full'), children: [_jsxs(Label, { htmlFor: id, children: [_jsx(Explain, { model: model, target: { field: node.field }, children: node.label ?? field.label }), (field.required || holds(node.requiredWhen, values, env)) && !readonly ? (_jsxs("span", { "aria-hidden": true, className: "text-danger", children: [' ', "*"] })) : null, recordId === 'new' && proposed?.includes(node.field) === true ? (_jsx("span", { className: "ms-2 rounded bg-accent px-1.5 py-0.5 text-[10px] font-medium text-accent-foreground", children: t('views.proposed') })) : null] }), _jsx("div", { className: "min-h-9 py-1.5 text-sm", children: _jsx(Widget, { id: id, node: node, field: field, value: values[node.field], record: values, model: model, readonly: readonly, onChange: (v) => change(node.field, v), invalid: invalid }) }), (node.help ?? field.help) === undefined ? null : (_jsx("p", { className: "text-xs text-muted-foreground", children: node.help ?? field.help }))] }, node.id));
451
464
  };
452
465
  const renderNodes = (nodes) => nodes.map((node) => {
453
466
  switch (node.kind) {
@@ -518,9 +531,27 @@ export function FormView({ served, recordId, defaults, onSaved, onBack, crumbs,
518
531
  (v === null || v === undefined || v === '' || (Array.isArray(v) && v.length === 0)));
519
532
  })
520
533
  .map((n) => n.field);
534
+ // A button that opens a new record of another model, filled from this one (RFC 0028 §3.4).
535
+ const openNew = (open) => {
536
+ void api.routes().then((routes) => {
537
+ const route = routes[open.model];
538
+ const action = open.action ?? route?.action;
539
+ if (action === undefined || route?.app === undefined)
540
+ return;
541
+ const filled = resolveRecord(open.values, values);
542
+ setPrefill(action, { values: filled, proposed: [] });
543
+ void navigateTo({
544
+ to: '/$app/a/$action/$id',
545
+ params: { app: route.app, action, id: 'new' },
546
+ });
547
+ });
548
+ };
521
549
  // RFC 0022 §3.5: the record's document templates as a Print menu, when reporting's web is registered.
522
550
  const Print = registry.component('reporting.Documents');
551
+ const Send = registry.component('mail.Send');
523
552
  const buttons = view.header.buttons.filter((b) => {
553
+ if (b.open !== undefined)
554
+ return !isNew && visible(b.visibleWhen);
524
555
  const spec = served.transitions.find((tr) => tr.name === b.transition);
525
556
  return (!isNew &&
526
557
  spec !== undefined &&
@@ -600,7 +631,7 @@ export function FormView({ served, recordId, defaults, onSaved, onBack, crumbs,
600
631
  e.preventDefault();
601
632
  if (dirty && !locked)
602
633
  save.mutate();
603
- }, children: [_jsxs("div", { className: "sticky top-12 z-20 -mx-4 flex flex-wrap items-center justify-between gap-2 border-b bg-background/95 px-4 py-2 backdrop-blur", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx(Button, { type: "button", variant: "ghost", size: "icon", "aria-label": t('views.back'), "data-kosh-back": true, onClick: onBack, children: _jsx(ArrowLeft, { className: "rtl:-scale-x-100", "aria-hidden": true }) }), _jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-2.5", children: [_jsx("h1", { className: "truncate text-xl font-semibold", children: title }), statusbar === undefined || fields[statusbar] === undefined || isNew ? null : (_jsx(StatusChip, { field: fields[statusbar], value: state, transitions: served.transitions.filter((tr) => tr.field === statusbar) })), locked && !isNew ? (_jsx("span", { className: "rounded-full border px-2 py-0.5 text-xs text-muted-foreground", children: t('views.readonly') })) : null] }), facts.length === 0 ? null : (_jsx("p", { className: "mt-0.5 flex flex-wrap items-center gap-x-2 text-sm text-muted-foreground", children: facts.map((node, i) => {
634
+ }, children: [_jsxs("div", { className: "sticky top-12 z-20 -mx-4 flex flex-wrap items-center justify-between gap-2 border-b bg-background/95 px-4 py-2 backdrop-blur", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx(Button, { type: "button", variant: "ghost", size: "icon", "aria-label": t('views.back'), "data-kosh-back": true, onClick: onBack, children: _jsx(ArrowLeft, { className: "rtl:-scale-x-100", "aria-hidden": true }) }), _jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-2.5", children: [_jsx("h1", { className: "truncate text-xl font-semibold", children: _jsx(Explain, { model: model, target: { model: true }, children: title }) }), statusbar === undefined || fields[statusbar] === undefined || isNew ? null : (_jsx(StatusChip, { field: fields[statusbar], value: state, transitions: served.transitions.filter((tr) => tr.field === statusbar) })), locked && !isNew ? (_jsx("span", { className: "rounded-full border px-2 py-0.5 text-xs text-muted-foreground", children: t('views.readonly') })) : null] }), facts.length === 0 ? null : (_jsx("p", { className: "mt-0.5 flex flex-wrap items-center gap-x-2 text-sm text-muted-foreground", children: facts.map((node, i) => {
604
635
  const field = fields[node.field];
605
636
  const Widget = registry.widget(node, field);
606
637
  return (_jsxs("span", { className: "flex items-center gap-2", title: field.label, children: [i === 0 ? null : _jsx("span", { "aria-hidden": true, children: "\u00B7" }), _jsxs("span", { className: "sr-only", children: [field.label, ": "] }), _jsx(Widget, { id: `${formId}-fact-${node.id}`, node: node, field: field, value: values[node.field], record: values, readonly: true })] }, node.id));
@@ -614,7 +645,7 @@ export function FormView({ served, recordId, defaults, onSaved, onBack, crumbs,
614
645
  setChanges({});
615
646
  setLines(new Map());
616
647
  setProblem(null);
617
- }, children: t('views.discard') }), _jsx(Button, { type: "submit", variant: "primary", busy: save.isPending, "data-kosh-save": true, children: t('views.save') })] })) : null, _jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "hidden xl:inline-flex", "aria-pressed": railOpen, "aria-label": railOpen ? t('views.hidePanel') : t('views.showPanel'), title: railOpen ? t('views.hidePanel') : t('views.showPanel'), onClick: () => setRailOpen(!railOpen), children: _jsx(PanelRight, { className: "rtl:-scale-x-100", "aria-hidden": true }) }), !isNew && served.operations.unlink ? (_jsxs(Menu, { children: [_jsx(MenuTrigger, { asChild: true, children: _jsx(Button, { type: "button", variant: "ghost", size: "icon", "aria-label": "Actions", children: _jsx(MoreHorizontal, { "aria-hidden": true }) }) }), _jsx(MenuContent, { children: _jsxs(MenuItem, { onSelect: () => setDeleting(true), children: [_jsx(Trash2, { className: "size-4", "aria-hidden": true }), t('views.delete')] }) })] })) : null] })] }), _jsxs("div", { className: cn('grid gap-4', showRail && 'xl:grid-cols-[minmax(0,1fr)_20rem] xl:items-start'), children: [_jsxs("div", { className: "grid min-w-0 content-start gap-4", children: [live.changedByOther ? (_jsx(Alert, { tone: "warning", action: _jsx(Button, { type: "button", size: "sm", onClick: () => {
648
+ }, children: t('views.discard') }), _jsx(Button, { type: "submit", variant: "primary", busy: save.isPending, "data-kosh-save": true, children: t('views.save') })] })) : null, _jsx(Button, { type: "button", variant: "ghost", size: "icon", className: "hidden xl:inline-flex", "aria-pressed": railOpen, "aria-label": railOpen ? t('views.hidePanel') : t('views.showPanel'), title: railOpen ? t('views.hidePanel') : t('views.showPanel'), onClick: () => setRailOpen(!railOpen), children: _jsx(PanelRight, { className: "rtl:-scale-x-100", "aria-hidden": true }) }), !isNew && (served.operations.unlink || served.operations.create) ? (_jsxs(Menu, { children: [_jsx(MenuTrigger, { asChild: true, children: _jsx(Button, { type: "button", variant: "ghost", size: "icon", "aria-label": t('views.actions'), children: _jsx(MoreHorizontal, { "aria-hidden": true }) }) }), _jsxs(MenuContent, { children: [served.operations.create ? (_jsxs(MenuItem, { disabled: duplicate.isPending, onSelect: () => duplicate.mutate(), children: [_jsx(Copy, { className: "size-4", "aria-hidden": true }), t('views.duplicate')] })) : null, served.operations.unlink ? (_jsxs(MenuItem, { onSelect: () => setDeleting(true), children: [_jsx(Trash2, { className: "size-4", "aria-hidden": true }), t('views.delete')] })) : null] })] })) : null] })] }), _jsxs("div", { className: cn('grid gap-4', showRail && 'xl:grid-cols-[minmax(0,1fr)_20rem] xl:items-start'), children: [_jsxs("div", { className: "grid min-w-0 content-start gap-4", children: [live.changedByOther ? (_jsx(Alert, { tone: "warning", action: _jsx(Button, { type: "button", size: "sm", onClick: () => {
618
649
  setChanges({});
619
650
  setLines(new Map());
620
651
  live.dismiss();
@@ -625,12 +656,18 @@ export function FormView({ served, recordId, defaults, onSaved, onBack, crumbs,
625
656
  void loaded.refetch();
626
657
  }, children: t('views.reload') })) : undefined, children: problem.kind === 'stale-record' ? t('views.stale') : problem.message })), warnings.map((w) => (_jsx(Alert, { tone: "info", children: w }, w))), nextStep === undefined || nextButton === undefined || locked ? null : (_jsx(Alert, { tone: nextStep.allowed ? 'info' : 'warning', children: nextStep.allowed
627
658
  ? t('views.nextStep.ready', { step: nextButton.label ?? nextButton.transition })
628
- : `${t('views.nextStep.before', { step: nextButton.label ?? nextButton.transition })} ${nextStep.message ?? ''}`.trim() })), buttons.length === 0 && (isNew || Print === undefined) ? null : (_jsxs("div", { role: "toolbar", "aria-label": t('views.recordActions'), className: "flex flex-wrap gap-2", children: [isNew || Print === undefined ? null : (_jsx(Print, { node: { kind: 'component', id: 'print', component: 'reporting.Documents' }, record: record ?? null, model: model, served: served, api: api, version: loaded.data?.etag ?? null, reload: () => void loaded.refetch() })), _jsx("div", { className: "contents", children: buttons.map((b, i) => (_jsx(Button, { type: "button", size: "sm", variant: b.primary === true || (i === 0 && !buttons.some((x) => x.primary === true))
629
- ? 'primary'
630
- : 'secondary', busy: transition.isPending && transition.variables === b.transition, onClick: () => b.confirm === undefined ? transition.mutate(b.transition) : setConfirming(b), children: b.label ?? b.transition }, b.id))) })] })), sections.map((section) => section.nodes[0]?.kind === 'stats' ? (_jsx("div", { className: "grid", children: renderNodes(section.nodes) }, section.key)) : (_jsx("section", { className: "rounded-lg border bg-surface p-5", children: _jsx("div", { className: "grid gap-x-6 gap-y-4 sm:grid-cols-2", children: renderNodes(section.nodes) }) }, section.key))), showRail ? null : rail] }), showRail ? (_jsx("aside", { "aria-label": t('views.recordPanel'),
659
+ : `${t('views.nextStep.before', { step: nextButton.label ?? nextButton.transition })} ${nextStep.message ?? ''}`.trim() })), buttons.length === 0 &&
660
+ (isNew || (Print === undefined && Send === undefined)) ? null : (_jsxs("div", { role: "toolbar", "aria-label": t('views.recordActions'), className: "flex flex-wrap gap-2", children: [isNew || Print === undefined ? null : (_jsx(Print, { node: { kind: 'component', id: 'print', component: 'reporting.Documents' }, record: record ?? null, model: model, served: served, api: api, version: loaded.data?.etag ?? null, reload: () => void loaded.refetch() })), isNew || Send === undefined ? null : (_jsx(Send, { node: { kind: 'component', id: 'send', component: 'mail.Send' }, record: record ?? null, model: model, served: served, api: api, version: loaded.data?.etag ?? null, reload: () => void loaded.refetch() })), _jsx("div", { className: "contents", children: buttons.map((b, i) => (_jsx(Explain, { model: model, asChild: true, target: b.transition === undefined ? { action: b.id } : { transition: b.transition }, children: _jsx(Button, { type: "button", size: "sm", variant: b.primary === true ||
661
+ (i === 0 && !buttons.some((x) => x.primary === true))
662
+ ? 'primary'
663
+ : 'secondary', busy: transition.isPending && transition.variables === b.transition, onClick: () => b.open !== undefined
664
+ ? openNew(b.open)
665
+ : b.confirm === undefined
666
+ ? transition.mutate(b.transition ?? '')
667
+ : setConfirming(b), children: b.label ?? b.transition ?? b.id }) }, b.id))) })] })), sections.map((section) => section.nodes[0]?.kind === 'stats' ? (_jsx("div", { className: "grid", children: renderNodes(section.nodes) }, section.key)) : (_jsx("section", { className: "rounded-lg border bg-surface p-5", children: _jsx("div", { className: "grid gap-x-6 gap-y-4 sm:grid-cols-2", children: renderNodes(section.nodes) }) }, section.key))), showRail ? null : rail] }), showRail ? (_jsx("aside", { "aria-label": t('views.recordPanel'),
631
668
  // Beside the record when wide; under it otherwise (one grid column).
632
669
  className: "grid content-start gap-4 xl:sticky xl:top-28", children: rail })) : null] })] }), _jsx(Dialog, { open: confirming !== null, onOpenChange: (open) => !open && setConfirming(null), title: confirming?.label ?? confirming?.transition ?? '', description: confirming?.confirm ?? '', footer: _jsxs(_Fragment, { children: [_jsx(Button, { onClick: () => setConfirming(null), children: t('views.no') }), _jsx(Button, { variant: "primary", onClick: () => {
633
- if (confirming !== null)
670
+ if (confirming?.transition !== undefined)
634
671
  transition.mutate(confirming.transition);
635
672
  setConfirming(null);
636
673
  }, children: t('views.yes') })] }) }), _jsx(Dialog, { open: deleting, onOpenChange: setDeleting, title: t('views.confirmDelete'), footer: _jsxs(_Fragment, { children: [_jsx(Button, { onClick: () => setDeleting(false), children: t('views.no') }), _jsx(Button, { variant: "danger", busy: remove.isPending, onClick: () => remove.mutate(), children: t('views.delete') })] }) })] }));
@@ -1,3 +1,11 @@
1
+ /**
2
+ * The list renderer (RFC 0007 §5, RFC 0010 §3.5): server-side order, paging and totals, grouping (one level,
3
+ * expandable), inline edit of `inlineEdit` columns with compare-and-set, row virtualization (TanStack Virtual) so
4
+ * large pages scroll smoothly, selection with a bulk bar (archive and delete with Undo, export, the transitions every
5
+ * selected record allows), export to CSV and Excel, a column chooser and density remembered per user, skeleton rows
6
+ * while loading and an empty state that offers the next step. Rows are a semantic table: keyboard users move with
7
+ * Tab and open with Enter. Every bulk action is one request per record to the existing, permission-checked routes.
8
+ */
1
9
  import { type ReactElement } from 'react';
2
10
  import type { ViewProps } from '../registry.js';
3
11
  /** The default list renderer. */
@@ -15,6 +15,7 @@ import { Archive, ArrowDown, ArrowUp, ChevronRight, Columns3, Download, Inbox, P
15
15
  import { useEffect, useMemo, useRef, useState, } from 'react';
16
16
  import { useTranslation } from 'react-i18next';
17
17
  import { ApiError } from '../api.js';
18
+ import { Explain } from '../components/Explain.js';
18
19
  import { Alert, Button, Checkbox, Dialog, EmptyState, Menu, MenuCheckboxItem, MenuContent, MenuItem, MenuLabel, MenuSeparator, MenuTrigger, Skeleton, } from '../components/primitives.js';
19
20
  import { useKosh } from '../context.js';
20
21
  import { useDesign } from '../design.js';
@@ -603,7 +604,7 @@ function Rows({ props, where, columns, fields, offset, limit, height, selection,
603
604
  ? 'ascending'
604
605
  : direction === 'desc'
605
606
  ? 'descending'
606
- : 'none', className: cn('relative px-3 py-2 text-start font-medium text-muted-foreground', pinnedClass(node.id)), children: [_jsxs("button", { type: "button", className: "inline-flex items-center gap-1", onClick: () => toggleOrder(node.field), children: [_jsx(table.FlexRender, { header: header }), direction === 'asc' ? (_jsx(ArrowUp, { className: "size-3", "aria-hidden": true })) : direction === 'desc' ? (_jsx(ArrowDown, { className: "size-3", "aria-hidden": true })) : null] }), _jsx(ResizeHandle, { label: t('views.resize', {
607
+ : 'none', className: cn('relative px-3 py-2 text-start font-medium text-muted-foreground', pinnedClass(node.id)), children: [_jsx(Explain, { model: model, target: { field: node.field }, asChild: true, children: _jsxs("button", { type: "button", className: "inline-flex items-center gap-1", onClick: () => toggleOrder(node.field), children: [_jsx(table.FlexRender, { header: header }), direction === 'asc' ? (_jsx(ArrowUp, { className: "size-3", "aria-hidden": true })) : direction === 'desc' ? (_jsx(ArrowDown, { className: "size-3", "aria-hidden": true })) : null] }) }), _jsx(ResizeHandle, { label: t('views.resize', {
607
608
  column: node.label ?? fields[node.field]?.label ?? node.field,
608
609
  }), width: widths[node.id] ?? null, onResize: (w) => setWidth(node.id, w), onReset: () => setWidth(node.id, null) })] }, header.id));
609
610
  })] }, group.id))) }), _jsxs("tbody", { children: [top > 0 ? (_jsx("tr", { "aria-hidden": true, children: _jsx("td", { style: { height: top }, colSpan: span }) })) : null, virtual.map((v) => {
@@ -759,7 +760,7 @@ export function totalLabel(word, label) {
759
760
  : `${word} ${label}`;
760
761
  }
761
762
  export function ListView(props) {
762
- const { api, uid } = useKosh();
763
+ const { api, uid, registry } = useKosh();
763
764
  const { t } = useTranslation();
764
765
  const toast = useToast();
765
766
  const queryClient = useQueryClient();
@@ -934,7 +935,13 @@ export function ListView(props) {
934
935
  }),
935
936
  });
936
937
  // Selected rows: a floating bar at the bottom of the screen (RFC 0018 §4.3); the list's own toolbar stays put.
937
- const floating = ids.length > 0 ? (_jsxs("div", { role: "toolbar", "aria-label": t('views.selected', { count: ids.length }), "data-kosh-selection-bar": true, className: "fixed inset-x-0 bottom-4 z-30 mx-auto flex w-fit max-w-[calc(100vw-2rem)] flex-wrap items-center gap-2 rounded-xl border bg-surface px-3 py-2 text-sm shadow-lg", children: [_jsx("span", { className: "font-medium", children: t('views.selected', { count: ids.length }) }), _jsx(Button, { size: "sm", variant: "ghost", "aria-label": t('views.clearSelection'), onClick: () => setSelected(new Set()), children: _jsx(X, { "aria-hidden": true }) }), _jsx("span", { className: "flex-1" }), transitions.map((tr) => (_jsx(Button, { size: "sm", busy: transition.isPending && transition.variables?.name === tr.name, onClick: () => transition.mutate({ name: tr.name, what: ids }), children: tr.name.charAt(0).toUpperCase() + tr.name.slice(1).replace(/_/g, ' ') }, tr.name))), archivable ? (_jsxs(Button, { size: "sm", busy: archive.isPending, onClick: () => archive.mutate(ids), children: [_jsx(Archive, { "aria-hidden": true }), t('views.archive')] })) : null, served.operations.unlink ? (_jsxs(Button, { size: "sm", variant: "danger", onClick: () => setConfirmingDelete(true), children: [_jsx(Trash2, { "aria-hidden": true }), t('views.delete')] })) : null, canExport ? (_jsxs(Button, { size: "sm", busy: exportAs.isPending, onClick: () => exportAs.mutate('csv'), children: [_jsx(Download, { "aria-hidden": true }), t('views.export')] })) : null] })) : null;
938
+ const floating = ids.length > 0 ? (_jsxs("div", { role: "toolbar", "aria-label": t('views.selected', { count: ids.length }), "data-kosh-selection-bar": true, className: "fixed inset-x-0 bottom-4 z-30 mx-auto flex w-fit max-w-[calc(100vw-2rem)] flex-wrap items-center gap-2 rounded-xl border bg-surface px-3 py-2 text-sm shadow-lg", children: [_jsx("span", { className: "font-medium", children: t('views.selected', { count: ids.length }) }), _jsx(Button, { size: "sm", variant: "ghost", "aria-label": t('views.clearSelection'), onClick: () => setSelected(new Set()), children: _jsx(X, { "aria-hidden": true }) }), _jsx("span", { className: "flex-1" }), transitions.map((tr) => (_jsx(Button, { size: "sm", busy: transition.isPending && transition.variables?.name === tr.name, onClick: () => transition.mutate({ name: tr.name, what: ids }), children: tr.name.charAt(0).toUpperCase() + tr.name.slice(1).replace(/_/g, ' ') }, tr.name))), registry.selectionActions().map((Action, i) => (_jsx(Action
939
+ // biome-ignore lint/suspicious/noArrayIndexKey: registered once, in a fixed order
940
+ , { api: api, model: model, ids: ids, done: (message, tone) => {
941
+ setSelected(new Set());
942
+ void refresh();
943
+ toast({ title: message, tone: tone ?? 'info' });
944
+ } }, i))), archivable ? (_jsxs(Button, { size: "sm", busy: archive.isPending, onClick: () => archive.mutate(ids), children: [_jsx(Archive, { "aria-hidden": true }), t('views.archive')] })) : null, served.operations.unlink ? (_jsxs(Button, { size: "sm", variant: "danger", onClick: () => setConfirmingDelete(true), children: [_jsx(Trash2, { "aria-hidden": true }), t('views.delete')] })) : null, canExport ? (_jsxs(Button, { size: "sm", busy: exportAs.isPending, onClick: () => exportAs.mutate('csv'), children: [_jsx(Download, { "aria-hidden": true }), t('views.export')] })) : null] })) : null;
938
945
  const toolbar = (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2 border-b px-3 py-1.5 text-sm", children: [_jsx("span", { className: "text-muted-foreground", children: count === null ? (_jsx(Skeleton, { className: "inline-block h-4 w-20" })) : (t('views.records', { count })) }), _jsx("span", { className: "flex-1" }), design.active ? (_jsxs(Button, { size: "sm", variant: "ghost", className: "border border-dashed border-primary/50 text-primary", onClick: () => design.choose({
939
946
  kind: 'list',
940
947
  view: view.id,
@@ -7,6 +7,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
7
7
  import { holds, resolveRecord, } from '../../views/index.js';
8
8
  import { useQueries, useQuery } from '@tanstack/react-query';
9
9
  import { useNavigate } from '@tanstack/react-router';
10
+ import { Explain } from '../components/Explain.js';
10
11
  import { useKosh } from '../context.js';
11
12
  import { cn } from '../lib/cn.js';
12
13
  // The badge's tones (primitives), on the figure only.
@@ -81,7 +82,7 @@ export function StatsRow({ node, values, env, version, }) {
81
82
  const result = results[i];
82
83
  const value = textOf(result?.data, format);
83
84
  const clickable = routes.data?.[tile.model]?.app !== undefined;
84
- const body = (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-xs font-medium text-muted-foreground", children: tile.label }), _jsxs("span", { className: cn('text-xl font-semibold tabular-nums leading-tight', TONES[tile.tone ?? 'neutral']), children: [result?.isPending === true ? '…' : value.text, value.currency === undefined ? null : (_jsx("span", { className: "ms-1 text-xs font-normal text-muted-foreground", children: value.currency }))] })] }));
85
+ const body = (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-xs font-medium text-muted-foreground", children: _jsx(Explain, { model: tile.model, focusable: false, target: { action: tile.id, domain: wheres[i] }, children: tile.label }) }), _jsxs("span", { className: cn('text-xl font-semibold tabular-nums leading-tight', TONES[tile.tone ?? 'neutral']), children: [result?.isPending === true ? '…' : value.text, value.currency === undefined ? null : (_jsx("span", { className: "ms-1 text-xs font-normal text-muted-foreground", children: value.currency }))] })] }));
85
86
  const className = 'grid gap-0.5 rounded-lg border bg-surface px-3 py-2 text-start transition-colors';
86
87
  return clickable ? (_jsx("button", { type: "button", className: cn(className, 'hover:bg-muted focus-visible:ring-2 focus-visible:ring-ring'), onClick: () => open(i), children: body }, tile.id)) : (_jsx("div", { className: className, children: body }, tile.id));
87
88
  }) }));
@@ -153,6 +153,18 @@ function apply(view, op) {
153
153
  break;
154
154
  }
155
155
  case 'form': {
156
+ // `append: 'header'` adds buttons to the header, which may have none yet (RFC 0028 §3.4).
157
+ if ('append' in op && op.append === 'header') {
158
+ next = {
159
+ ...view,
160
+ header: {
161
+ ...view.header,
162
+ buttons: [...view.header.buttons, ...op.nodes],
163
+ },
164
+ };
165
+ done = true;
166
+ break;
167
+ }
156
168
  const [buttons, inHeader] = applyIn(view.header.buttons, op);
157
169
  if (inHeader)
158
170
  [next, done] = [
@@ -99,7 +99,18 @@ export type FormNode = FieldNode | GroupNode | NotebookNode | LinesNode | Compon
99
99
  export interface ButtonNode {
100
100
  readonly kind: 'button';
101
101
  readonly id: string;
102
- readonly transition: string;
102
+ /** The transition it runs (a button runs a transition, or opens a new record: `open`). */
103
+ readonly transition?: string;
104
+ /**
105
+ * Opens a new record of another model, filled from this one (RFC 0028 §3.4: "New quotation" on a deal): `values`
106
+ * may refer to the record (`{ $record: 'partner' }`); `action` defaults to the model's own. Saved like any new
107
+ * record: the server checks the rights then.
108
+ */
109
+ readonly open?: {
110
+ readonly model: string;
111
+ readonly action?: string;
112
+ readonly values: Readonly<Record<string, unknown>>;
113
+ };
103
114
  readonly label?: string;
104
115
  readonly primary?: boolean;
105
116
  readonly visibleWhen?: Condition;
@@ -213,7 +224,7 @@ export interface CalendarView extends ViewBase {
213
224
  readonly title: string;
214
225
  /** A field whose value colours the events. */
215
226
  readonly color?: string;
216
- readonly mode?: 'month' | 'week';
227
+ readonly mode?: 'month' | 'week' | 'day';
217
228
  }
218
229
  /** Records as bars on a timeline. */
219
230
  export interface GanttView extends ViewBase {
@@ -71,7 +71,14 @@ export function validateView(view, models) {
71
71
  problems.push(`stat '${node.id}': '$record' names no field '${key}' of ${view.model}`);
72
72
  }
73
73
  }
74
- if (node.kind === 'button' && !info.transitions.includes(node.transition))
74
+ if (node.kind === 'button' && node.open !== undefined) {
75
+ if (models(node.open.model) === undefined)
76
+ problems.push(`button '${node.id}': opens unknown model ${node.open.model}`);
77
+ for (const key of recordKeys(node.open.values))
78
+ if (!info.fields.has(key))
79
+ problems.push(`button '${node.id}': '$record' names no field '${key}' of ${view.model}`);
80
+ }
81
+ else if (node.kind === 'button' && !info.transitions.includes(node.transition ?? ''))
75
82
  problems.push(`unknown transition '${node.transition}' (has ${info.transitions.join(', ') || 'none'})`);
76
83
  }
77
84
  if (view.type === 'form')
@@ -1,4 +1,4 @@
1
- // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 91d347eb721a67c2
1
+ // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 5f477c497bbd660c
2
2
  // Bindings of module `website`: import the definition API from here to get types scoped to what it can see.
3
3
  export { defineModel, defineModule, extendModel, f, replace } from '../../server/orm.js';
4
4
  import { definitions } from '../../server/orm.js';
@@ -1,4 +1,4 @@
1
- // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 91d347eb721a67c2
1
+ // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: 5f477c497bbd660c
2
2
  // Schema view of module `website` (RFC 0002 §7.7): the models it owns or depends on, with the extensions it can see.
3
3
  import type { F } from '../../server/orm.js';
4
4
 
@@ -624,6 +624,7 @@ export interface ResPartner {
624
624
  readonly parent: F.Many2one<'res.partner'>;
625
625
  readonly contacts: F.One2many<'res.partner', { readonly required: true }>;
626
626
  readonly email: F.Char;
627
+ readonly lang: F.Selection<'en' | 'bn'>;
627
628
  readonly phone: F.Char;
628
629
  readonly mobile: F.Char;
629
630
  readonly website: F.Char;
@@ -0,0 +1,2 @@
1
+ /** Bangla for the module's labels, keyed by their English text (RFC 0023 §3.1; `pnpm i18n:extract`). */
2
+ export declare const bn: Readonly<Record<string, string>>;
@@ -0,0 +1,113 @@
1
+ /** Bangla for the module's labels, keyed by their English text (RFC 0023 §3.1; `pnpm i18n:extract`). */
2
+ export const bn = {
3
+ '/ for the home page, /about, /contact': 'হোম পাতার জন্য /, /about, /contact',
4
+ 'A form block names its form.': 'ফর্ম ব্লকে তার ফর্মের নাম দিতে হবে।',
5
+ 'A key is lower-case letters, digits and dashes, e.g. contact-us.': 'কী-তে ছোট হাতের অক্ষর, অঙ্ক ও ড্যাশ থাকে, যেমন contact-us।',
6
+ 'A key is lower-case letters, digits and dashes, e.g. padma-traders.': 'কী-তে ছোট হাতের অক্ষর, অঙ্ক ও ড্যাশ থাকে, যেমন padma-traders।',
7
+ 'A link is a path on the site (/contact) or an http(s) address.': 'লিংক হলো সাইটের একটি পাথ (/contact) বা একটি http(s) ঠিকানা।',
8
+ 'A page translates another page of the same site.': 'একটি পাতা একই সাইটের অন্য পাতার অনুবাদ হতে পারে।',
9
+ 'A path starts with / and has letters, digits, dashes, dots or underscores: /about-us.': 'পাথ / দিয়ে শুরু হয় এবং এতে অক্ষর, অঙ্ক, ড্যাশ, ডট বা আন্ডারস্কোর থাকে: /about-us।',
10
+ 'A website form creates contacts, or what an installed app allows (a lead with Pipeline).': 'ওয়েবসাইট ফর্ম যোগাযোগ তৈরি করে, অথবা ইনস্টল করা অ্যাপ যা অনুমতি দেয় (পাইপলাইন থাকলে একটি লিড)।',
11
+ Active: 'সক্রিয়',
12
+ 'An input name is lower-case letters, digits and underscores, starting with a letter.': 'ইনপুটের নামে ছোট হাতের অক্ষর, অঙ্ক ও আন্ডারস্কোর থাকে এবং তা অক্ষর দিয়ে শুরু হয়।',
13
+ 'Another form has this key.': 'অন্য একটি ফর্মে এই কী আছে।',
14
+ 'Another site has this key.': 'অন্য একটি সাইটে এই কী আছে।',
15
+ Bangla: 'বাংলা',
16
+ Block: 'ব্লক',
17
+ Button: 'বোতাম',
18
+ 'Button link': 'বোতামের লিংক',
19
+ 'Call to action': 'কল টু অ্যাকশন',
20
+ Company: 'প্রতিষ্ঠান',
21
+ Content: 'বিষয়বস্তু',
22
+ Created: 'তৈরি হয়েছে',
23
+ 'Created (id)': 'তৈরি (আইডি)',
24
+ 'Created (model)': 'তৈরি (মডেল)',
25
+ 'Created At': 'তৈরির সময়',
26
+ 'Created By': 'তৈরি করেছেন',
27
+ Creates: 'তৈরি করে',
28
+ Data: 'ডেটা',
29
+ Date: 'তারিখ',
30
+ 'Default language': 'ডিফল্ট ভাষা',
31
+ 'Display Name': 'প্রদর্শিত নাম',
32
+ Domain: 'ডোমেইন',
33
+ Draft: 'খসড়া',
34
+ Drafts: 'খসড়া',
35
+ 'Editor (pages, submissions)': 'সম্পাদক (পাতা, জমা)',
36
+ Email: 'ইমেইল',
37
+ English: 'ইংরেজি',
38
+ Fields: 'ফিল্ড',
39
+ 'Fields › Fills': 'ফিল্ড › পূরণ করে',
40
+ 'Fields › Input name': 'ফিল্ড › ইনপুটের নাম',
41
+ 'Fields › Label': 'ফিল্ড › লেবেল',
42
+ 'Fields › Required': 'ফিল্ড › আবশ্যক',
43
+ 'Fields › Type': 'ফিল্ড › ধরন',
44
+ Fills: 'পূরণ করে',
45
+ Form: 'ফর্ম',
46
+ 'Form field': 'ফর্ম ফিল্ড',
47
+ Forms: 'ফর্ম',
48
+ Hero: 'হিরো',
49
+ ID: 'আইডি',
50
+ Image: 'ছবি',
51
+ 'Image URL': 'ছবির URL',
52
+ 'In the menu': 'মেনুতে',
53
+ 'Input name': 'ইনপুটের নাম',
54
+ Key: 'কী',
55
+ Kind: 'ধরন',
56
+ Label: 'লেবেল',
57
+ Language: 'ভাষা',
58
+ 'Long text': 'দীর্ঘ লেখা',
59
+ 'Manager (sites, forms, everything)': 'ব্যবস্থাপক (সাইট, ফর্ম, সবকিছু)',
60
+ 'Message after sending': 'পাঠানোর পরের বার্তা',
61
+ Name: 'নাম',
62
+ Number: 'সংখ্যা',
63
+ 'Only published pages are shown on the public site.': 'পাবলিক ওয়েবসাইটে শুধু প্রকাশিত পাতাগুলো দেখানো হয়।',
64
+ Overview: 'সারসংক্ষেপ',
65
+ Page: 'পাতা',
66
+ Pages: 'পাতা',
67
+ 'Pages › In the menu': 'পাতা › মেনুতে',
68
+ 'Pages › Language': 'পাতা › ভাষা',
69
+ 'Pages › Path': 'পাতা › পাথ',
70
+ 'Pages › Summary': 'পাতা › সারাংশ',
71
+ 'Pages › Title': 'পাতা › শিরোনাম',
72
+ 'Pages published': 'প্রকাশিত পাতা',
73
+ Path: 'পাথ',
74
+ Phone: 'ফোন',
75
+ Publish: 'প্রকাশ করুন',
76
+ Published: 'প্রকাশিত',
77
+ 'Published on': 'প্রকাশের তারিখ',
78
+ Received: 'প্রাপ্ত',
79
+ Required: 'আবশ্যক',
80
+ Sequence: 'ক্রম',
81
+ Site: 'সাইট',
82
+ Sites: 'সাইট',
83
+ 'Sites editor': 'সাইট সম্পাদক',
84
+ 'Sites manager': 'সাইট ব্যবস্থাপক',
85
+ Spam: 'স্প্যাম',
86
+ 'Spam caught this month': 'এ মাসে ধরা পড়া স্প্যাম',
87
+ 'Spam when a bot filled in the hidden field; received submissions create their record.': 'কোনো বট লুকানো ঘরটি পূরণ করলে এটি স্প্যাম; গৃহীত জমাগুলো থেকে তাদের রেকর্ড তৈরি হয়।',
88
+ State: 'অবস্থা',
89
+ Submission: 'জমা',
90
+ Submissions: 'জমা',
91
+ 'Submissions by form': 'ফর্ম অনুযায়ী জমা',
92
+ 'Submissions by month': 'মাস অনুযায়ী জমা',
93
+ 'Submissions this month': 'এ মাসের জমা',
94
+ Summary: 'সারাংশ',
95
+ Text: 'লেখা',
96
+ 'The form already has an input with this name.': 'ফর্মে এই নামের একটি ইনপুট আগে থেকেই আছে।',
97
+ 'The kind of value the visitor types in this input.': 'দর্শনার্থী এই ঘরে কোন ধরনের মান লিখবেন।',
98
+ 'The language the page is written in.': 'পাতাটি যে ভাষায় লেখা।',
99
+ 'The language the site shows when a visitor has not chosen one.': 'দর্শনার্থী কোনো ভাষা বেছে না নিলে ওয়েবসাইট যে ভাষায় দেখায়।',
100
+ 'The site already has a page at this path in this language.': 'সাইটে এই ভাষায় এই পাথে একটি পাতা আগে থেকেই আছে।',
101
+ Title: 'শিরোনাম',
102
+ 'Translation of': 'যার অনুবাদ',
103
+ Type: 'ধরন',
104
+ Unpublish: 'প্রকাশ বন্ধ করুন',
105
+ 'Updated At': 'হালনাগাদের সময়',
106
+ 'Updated By': 'হালনাগাদ করেছেন',
107
+ Website: 'ওয়েবসাইট',
108
+ 'Website form': 'ওয়েবসাইট ফর্ম',
109
+ 'Website form submitted': 'ওয়েবসাইট ফর্ম জমা হয়েছে',
110
+ 'Website pages from blocks, forms that create records, a public API': 'ব্লক দিয়ে তৈরি ওয়েবসাইট পাতা, রেকর্ড তৈরি করা ফর্ম, একটি পাবলিক API',
111
+ 'What the block shows: a hero banner, text, an image, a call to action or a form.': 'ব্লকটি কী দেখায়: একটি হিরো ব্যানার, লেখা, ছবি, কাজের আহ্বান বা ফর্ম।',
112
+ 'Where the public site is served, e.g. www.example.com': 'যেখানে পাবলিক সাইটটি চলে, যেমন www.example.com',
113
+ };
@@ -36,6 +36,42 @@ export function websiteModule(options = {}) {
36
36
  category: 'Website',
37
37
  summary: 'Website pages from blocks, forms that create records, a public API',
38
38
  },
39
+ importTemplates: [
40
+ {
41
+ key: 'website_site',
42
+ model: 'website.site',
43
+ label: 'Site',
44
+ columns: [
45
+ { header: 'Name', field: 'name' },
46
+ { header: 'Key', field: 'key' },
47
+ { header: 'Domain', field: 'domain' },
48
+ { header: 'Default language', field: 'lang' },
49
+ { header: 'Pages › Path', field: 'pages.path' },
50
+ { header: 'Pages › Language', field: 'pages.lang' },
51
+ { header: 'Pages › Title', field: 'pages.title' },
52
+ { header: 'Pages › Summary', field: 'pages.description' },
53
+ { header: 'Pages › In the menu', field: 'pages.inMenu' },
54
+ ],
55
+ },
56
+ {
57
+ key: 'website_form',
58
+ model: 'website.form',
59
+ label: 'Website form',
60
+ columns: [
61
+ { header: 'Name', field: 'name' },
62
+ { header: 'Key', field: 'key' },
63
+ { header: 'Creates', field: 'target' },
64
+ { header: 'Message after sending', field: 'successMessage' },
65
+ { header: 'Fields › Input name', field: 'fields.name' },
66
+ { header: 'Fields › Label', field: 'fields.label' },
67
+ { header: 'Fields › Type', field: 'fields.kind' },
68
+ { header: 'Fields › Required', field: 'fields.required' },
69
+ { header: 'Fields › Fills', field: 'fields.targetField' },
70
+ ],
71
+ },
72
+ ],
73
+ // Bangla for the labels it serves (RFC 0023 §3.1; `pnpm i18n:extract`).
74
+ i18n: { bn: () => import('./i18n/bn.js') },
39
75
  accessLevels: {
40
76
  editor: { label: 'Editor (pages, submissions)', groups: ['website.editor'] },
41
77
  manager: {
@@ -2612,6 +2612,16 @@ export declare const websiteShutro: import("../server/orm.js").Module<readonly [
2612
2612
  readonly hasDefault: false;
2613
2613
  readonly readonly: false;
2614
2614
  }, string>;
2615
+ readonly lang: import("../server/orm.js").SelectionField<"bn" | "en", {
2616
+ readonly required: false;
2617
+ readonly computed: false;
2618
+ readonly inverse: false;
2619
+ readonly sequence: false;
2620
+ readonly computeName: undefined;
2621
+ readonly store: true;
2622
+ readonly hasDefault: false;
2623
+ readonly readonly: false;
2624
+ }>;
2615
2625
  readonly phone: import("../server/orm.js").CharField<{
2616
2626
  readonly required: false;
2617
2627
  readonly computed: false;
@@ -2833,6 +2843,16 @@ export declare const websiteShutro: import("../server/orm.js").Module<readonly [
2833
2843
  readonly hasDefault: false;
2834
2844
  readonly readonly: false;
2835
2845
  }, string>;
2846
+ readonly lang: import("../server/orm.js").SelectionField<"bn" | "en", {
2847
+ readonly required: false;
2848
+ readonly computed: false;
2849
+ readonly inverse: false;
2850
+ readonly sequence: false;
2851
+ readonly computeName: undefined;
2852
+ readonly store: true;
2853
+ readonly hasDefault: false;
2854
+ readonly readonly: false;
2855
+ }>;
2836
2856
  readonly phone: import("../server/orm.js").CharField<{
2837
2857
  readonly required: false;
2838
2858
  readonly computed: false;
@@ -33,7 +33,12 @@ export const WebsiteSite = defineModel('website.site', {
33
33
  label: 'Domain',
34
34
  help: 'Where the public site is served, e.g. www.example.com',
35
35
  }),
36
- lang: f.selection(LANGS, { required: true, default: 'en', label: 'Default language' }),
36
+ lang: f.selection(LANGS, {
37
+ required: true,
38
+ default: 'en',
39
+ label: 'Default language',
40
+ help: 'The language the site shows when a visitor has not chosen one.',
41
+ }),
37
42
  pages: f.one2many('website.page', 'site'),
38
43
  },
39
44
  sqlConstraints: {
@@ -59,7 +64,12 @@ export const WebsitePage = defineModel('website.page', {
59
64
  fields: {
60
65
  site: f.many2one('website.site', { required: true, ondelete: 'cascade' }),
61
66
  path: f.char({ required: true, default: '/', help: '/ for the home page, /about, /contact' }),
62
- lang: f.selection(LANGS, { required: true, default: 'en', label: 'Language' }),
67
+ lang: f.selection(LANGS, {
68
+ required: true,
69
+ default: 'en',
70
+ label: 'Language',
71
+ help: 'The language the page is written in.',
72
+ }),
63
73
  title: f.char({ required: true }),
64
74
  /** For search engines and link previews. */
65
75
  description: f.text({ label: 'Summary' }),
@@ -69,6 +79,7 @@ export const WebsitePage = defineModel('website.page', {
69
79
  translationOf: f.many2one('website.page', { ondelete: 'set null', label: 'Translation of' }),
70
80
  blocks: f.one2many('website.block', 'page', { label: 'Content' }),
71
81
  state: f.state({
82
+ help: 'Only published pages are shown on the public site.',
72
83
  states: { draft: 'Draft', published: 'Published' },
73
84
  initial: 'draft',
74
85
  transitions: {
@@ -115,7 +126,11 @@ export const WebsiteBlock = defineModel('website.block', {
115
126
  fields: {
116
127
  page: f.many2one('website.page', { required: true, ondelete: 'cascade' }),
117
128
  sequence: f.integer({ required: true, default: 10 }),
118
- kind: f.selection({ hero: 'Hero', text: 'Text', image: 'Image', cta: 'Call to action', form: 'Form' }, { required: true, default: 'text' }),
129
+ kind: f.selection({ hero: 'Hero', text: 'Text', image: 'Image', cta: 'Call to action', form: 'Form' }, {
130
+ required: true,
131
+ default: 'text',
132
+ help: 'What the block shows: a hero banner, text, an image, a call to action or a form.',
133
+ }),
119
134
  title: f.char(),
120
135
  body: f.text({ label: 'Text' }),
121
136
  imageUrl: f.char({ label: 'Image URL', size: 1000 }),
@@ -220,7 +235,12 @@ export const WebsiteFormField = defineModel('website.form.field', {
220
235
  textarea: 'Long text',
221
236
  number: 'Number',
222
237
  date: 'Date',
223
- }, { required: true, default: 'text', label: 'Type' }),
238
+ }, {
239
+ required: true,
240
+ default: 'text',
241
+ label: 'Type',
242
+ help: 'The kind of value the visitor types in this input.',
243
+ }),
224
244
  required: f.boolean({ default: false }),
225
245
  /** The field of the created record it fills (`email`); plain fields only, checked on submission. */
226
246
  targetField: f.char({ required: true, size: 80, label: 'Fills' }),
@@ -252,7 +272,11 @@ export const WebsiteSubmission = defineModel('website.submission', {
252
272
  site: f.many2one('website.site', { ondelete: 'set null' }),
253
273
  /** The values as sent (the form's inputs only). */
254
274
  data: f.json({ required: true, default: {} }),
255
- state: f.selection({ received: 'Received', spam: 'Spam' }, { required: true, default: 'received' }),
275
+ state: f.selection({ received: 'Received', spam: 'Spam' }, {
276
+ required: true,
277
+ default: 'received',
278
+ help: 'Spam when a bot filled in the hidden field; received submissions create their record.',
279
+ }),
256
280
  resModel: f.char({ label: 'Created (model)' }),
257
281
  resId: f.integer({ label: 'Created (id)' }),
258
282
  /** The created record's name, as it was. */
@@ -1,4 +1,4 @@
1
- // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: fe2c56640a3ed761
1
+ // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: e98d0ed6cfa09eb4
2
2
  // Bindings of module `website_crm`: import the definition API from here to get types scoped to what it can see.
3
3
  export { defineModel, defineModule, extendModel, f, replace } from '../../server/orm.js';
4
4
  import { definitions } from '../../server/orm.js';
@@ -1,4 +1,4 @@
1
- // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: fe2c56640a3ed761
1
+ // GENERATED by `pnpm generate:models` (Shutro’s generator). Do not edit. definitions-hash: e98d0ed6cfa09eb4
2
2
  // Schema view of module `website_crm` (RFC 0002 §7.7): the models it owns or depends on, with the extensions it can see.
3
3
  import type { F } from '../../server/orm.js';
4
4
 
@@ -710,6 +710,7 @@ export interface ResPartner {
710
710
  readonly parent: F.Many2one<'res.partner'>;
711
711
  readonly contacts: F.One2many<'res.partner', { readonly required: true }>;
712
712
  readonly email: F.Char;
713
+ readonly lang: F.Selection<'en' | 'bn'>;
713
714
  readonly phone: F.Char;
714
715
  readonly mobile: F.Char;
715
716
  readonly website: F.Char;