shutro-erp 0.3.5 → 0.3.6

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 (384) hide show
  1. package/dist/account_asset/.kosh/bindings.d.ts +22 -0
  2. package/dist/account_asset/.kosh/bindings.js +15 -0
  3. package/dist/account_asset/.kosh/schema.d.ts +1755 -0
  4. package/dist/account_asset/board.d.ts +61 -0
  5. package/dist/account_asset/board.js +86 -0
  6. package/dist/account_asset/books.d.ts +42 -0
  7. package/dist/account_asset/books.js +398 -0
  8. package/dist/account_asset/demo.d.ts +7 -0
  9. package/dist/account_asset/demo.js +72 -0
  10. package/dist/account_asset/index.d.ts +9 -0
  11. package/dist/account_asset/index.js +335 -0
  12. package/dist/account_asset/module.d.ts +7622 -0
  13. package/dist/account_asset/module.js +230 -0
  14. package/dist/account_budget/.kosh/bindings.d.ts +22 -0
  15. package/dist/account_budget/.kosh/bindings.js +15 -0
  16. package/dist/account_budget/.kosh/schema.d.ts +1767 -0
  17. package/dist/account_budget/budget.d.ts +5 -0
  18. package/dist/account_budget/budget.js +142 -0
  19. package/dist/account_budget/demo.d.ts +6 -0
  20. package/dist/account_budget/demo.js +30 -0
  21. package/dist/account_budget/index.d.ts +4 -0
  22. package/dist/account_budget/index.js +223 -0
  23. package/dist/account_budget/module.d.ts +13863 -0
  24. package/dist/account_budget/module.js +167 -0
  25. package/dist/account_portal/.kosh/bindings.js +1 -1
  26. package/dist/account_portal/.kosh/schema.d.ts +123 -4
  27. package/dist/account_portal/module.d.ts +146 -0
  28. package/dist/accounting/.kosh/bindings.js +1 -1
  29. package/dist/accounting/.kosh/schema.d.ts +123 -4
  30. package/dist/accounting/index.d.ts +1 -1
  31. package/dist/accounting/index.js +131 -3
  32. package/dist/accounting/module.d.ts +296 -0
  33. package/dist/accounting/module.js +32 -1
  34. package/dist/approvals/.kosh/bindings.d.ts +22 -0
  35. package/dist/approvals/.kosh/bindings.js +15 -0
  36. package/dist/approvals/.kosh/schema.d.ts +611 -0
  37. package/dist/approvals/index.d.ts +18 -0
  38. package/dist/approvals/index.js +302 -0
  39. package/dist/approvals/mails.d.ts +25 -0
  40. package/dist/approvals/mails.js +82 -0
  41. package/dist/approvals/module.d.ts +1 -0
  42. package/dist/approvals/module.js +12 -0
  43. package/dist/approvals/web/History.d.ts +4 -0
  44. package/dist/approvals/web/History.js +13 -0
  45. package/dist/approvals/web/Inbox.d.ts +9 -0
  46. package/dist/approvals/web/Inbox.js +114 -0
  47. package/dist/approvals/web/Mine.d.ts +7 -0
  48. package/dist/approvals/web/Mine.js +27 -0
  49. package/dist/approvals/web/index.d.ts +13 -0
  50. package/dist/approvals/web/index.js +22 -0
  51. package/dist/approvals/web/messages.d.ts +2 -0
  52. package/dist/approvals/web/messages.js +119 -0
  53. package/dist/approvals/web/shared.d.ts +59 -0
  54. package/dist/approvals/web/shared.js +46 -0
  55. package/dist/attendance/.kosh/bindings.d.ts +22 -0
  56. package/dist/attendance/.kosh/bindings.js +15 -0
  57. package/dist/attendance/.kosh/schema.d.ts +1048 -0
  58. package/dist/attendance/days.d.ts +96 -0
  59. package/dist/attendance/days.js +430 -0
  60. package/dist/attendance/demo.d.ts +7 -0
  61. package/dist/attendance/demo.js +58 -0
  62. package/dist/attendance/index.d.ts +4 -0
  63. package/dist/attendance/index.js +513 -0
  64. package/dist/attendance/module.d.ts +3969 -0
  65. package/dist/attendance/module.js +412 -0
  66. package/dist/attendance/routes.d.ts +16 -0
  67. package/dist/attendance/routes.js +266 -0
  68. package/dist/attendance/web/Check.d.ts +8 -0
  69. package/dist/attendance/web/Check.js +40 -0
  70. package/dist/attendance/web/Kiosk.d.ts +8 -0
  71. package/dist/attendance/web/Kiosk.js +62 -0
  72. package/dist/attendance/web/PinButton.d.ts +7 -0
  73. package/dist/attendance/web/PinButton.js +29 -0
  74. package/dist/attendance/web/index.d.ts +13 -0
  75. package/dist/attendance/web/index.js +22 -0
  76. package/dist/attendance/web/messages.d.ts +2 -0
  77. package/dist/attendance/web/messages.js +61 -0
  78. package/dist/cli/init.js +32 -0
  79. package/dist/cli/templates.d.ts +1 -1
  80. package/dist/cli/templates.js +89 -0
  81. package/dist/contacts/module.js +13 -2
  82. package/dist/crm/.kosh/bindings.js +1 -1
  83. package/dist/crm/.kosh/schema.d.ts +2 -1
  84. package/dist/crm/module.d.ts +2 -0
  85. package/dist/crm/module.js +2 -1
  86. package/dist/documents/.kosh/bindings.d.ts +22 -0
  87. package/dist/documents/.kosh/bindings.js +15 -0
  88. package/dist/documents/.kosh/schema.d.ts +862 -0
  89. package/dist/documents/demo.d.ts +6 -0
  90. package/dist/documents/demo.js +22 -0
  91. package/dist/documents/documents.d.ts +98 -0
  92. package/dist/documents/documents.js +318 -0
  93. package/dist/documents/index.d.ts +30 -0
  94. package/dist/documents/index.js +442 -0
  95. package/dist/documents/module.d.ts +2781 -0
  96. package/dist/documents/module.js +214 -0
  97. package/dist/documents/web/Versions.d.ts +7 -0
  98. package/dist/documents/web/Versions.js +45 -0
  99. package/dist/documents/web/index.d.ts +11 -0
  100. package/dist/documents/web/index.js +16 -0
  101. package/dist/documents/web/messages.d.ts +2 -0
  102. package/dist/documents/web/messages.js +21 -0
  103. package/dist/event_account/.kosh/bindings.js +1 -1
  104. package/dist/event_account/.kosh/schema.d.ts +123 -4
  105. package/dist/event_account/module.d.ts +146 -0
  106. package/dist/expense/.kosh/bindings.d.ts +22 -0
  107. package/dist/expense/.kosh/bindings.js +15 -0
  108. package/dist/expense/.kosh/schema.d.ts +1299 -0
  109. package/dist/expense/demo.d.ts +7 -0
  110. package/dist/expense/demo.js +69 -0
  111. package/dist/expense/index.d.ts +3 -0
  112. package/dist/expense/index.js +495 -0
  113. package/dist/expense/module.d.ts +4747 -0
  114. package/dist/expense/module.js +647 -0
  115. package/dist/expense_account/.kosh/bindings.d.ts +22 -0
  116. package/dist/expense_account/.kosh/bindings.js +15 -0
  117. package/dist/expense_account/.kosh/schema.d.ts +1936 -0
  118. package/dist/expense_account/index.d.ts +3 -0
  119. package/dist/expense_account/index.js +74 -0
  120. package/dist/expense_account/module.d.ts +9153 -0
  121. package/dist/expense_account/module.js +318 -0
  122. package/dist/helpdesk/.kosh/bindings.d.ts +22 -0
  123. package/dist/helpdesk/.kosh/bindings.js +15 -0
  124. package/dist/helpdesk/.kosh/schema.d.ts +885 -0
  125. package/dist/helpdesk/demo.d.ts +7 -0
  126. package/dist/helpdesk/demo.js +65 -0
  127. package/dist/helpdesk/hours.d.ts +17 -0
  128. package/dist/helpdesk/hours.js +94 -0
  129. package/dist/helpdesk/index.d.ts +10 -0
  130. package/dist/helpdesk/index.js +461 -0
  131. package/dist/helpdesk/module.d.ts +2940 -0
  132. package/dist/helpdesk/module.js +326 -0
  133. package/dist/helpdesk/routes.d.ts +12 -0
  134. package/dist/helpdesk/routes.js +132 -0
  135. package/dist/helpdesk/sla.d.ts +37 -0
  136. package/dist/helpdesk/sla.js +226 -0
  137. package/dist/hr/index.d.ts +1 -1
  138. package/dist/hr/index.js +1 -1
  139. package/dist/l10n_bd/.kosh/bindings.js +1 -1
  140. package/dist/l10n_bd/.kosh/schema.d.ts +123 -4
  141. package/dist/l10n_bd/module.d.ts +146 -0
  142. package/dist/l10n_bd_payroll/.kosh/bindings.d.ts +22 -0
  143. package/dist/l10n_bd_payroll/.kosh/bindings.js +15 -0
  144. package/dist/l10n_bd_payroll/.kosh/schema.d.ts +2312 -0
  145. package/dist/l10n_bd_payroll/data.d.ts +47 -0
  146. package/dist/l10n_bd_payroll/data.js +347 -0
  147. package/dist/l10n_bd_payroll/index.d.ts +4 -0
  148. package/dist/l10n_bd_payroll/index.js +24 -0
  149. package/dist/l10n_bd_payroll/module.d.ts +12932 -0
  150. package/dist/l10n_bd_payroll/module.js +86 -0
  151. package/dist/l10n_in/.kosh/bindings.js +1 -1
  152. package/dist/l10n_in/.kosh/schema.d.ts +123 -4
  153. package/dist/l10n_in/module.d.ts +147 -0
  154. package/dist/mail/inbound/handle.js +6 -1
  155. package/dist/maintenance_stock/.kosh/bindings.js +1 -1
  156. package/dist/maintenance_stock/.kosh/schema.d.ts +77 -2
  157. package/dist/maintenance_stock/module.d.ts +788 -66
  158. package/dist/modules-sdk/index.d.ts +1 -1
  159. package/dist/modules-sdk/manifest.d.ts +39 -2
  160. package/dist/mrp/.kosh/bindings.js +1 -1
  161. package/dist/mrp/.kosh/schema.d.ts +77 -2
  162. package/dist/mrp/index.d.ts +1 -1
  163. package/dist/mrp/index.js +2 -1
  164. package/dist/mrp/module.d.ts +781 -54
  165. package/dist/mrp/module.js +64 -2
  166. package/dist/mrp_account/.kosh/bindings.js +1 -1
  167. package/dist/mrp_account/.kosh/schema.d.ts +198 -5
  168. package/dist/mrp_account/module.d.ts +4852 -2541
  169. package/dist/payment/.kosh/bindings.js +1 -1
  170. package/dist/payment/.kosh/schema.d.ts +125 -5
  171. package/dist/payment/index.d.ts +41 -0
  172. package/dist/payment/index.js +131 -74
  173. package/dist/payment/module.d.ts +210 -6
  174. package/dist/payment/module.js +19 -3
  175. package/dist/payment/settle.js +10 -1
  176. package/dist/payroll/.kosh/bindings.d.ts +22 -0
  177. package/dist/payroll/.kosh/bindings.js +15 -0
  178. package/dist/payroll/.kosh/schema.d.ts +1390 -0
  179. package/dist/payroll/compute.d.ts +35 -0
  180. package/dist/payroll/compute.js +398 -0
  181. package/dist/payroll/demo.d.ts +55 -0
  182. package/dist/payroll/demo.js +121 -0
  183. package/dist/payroll/formula.d.ts +62 -0
  184. package/dist/payroll/formula.js +320 -0
  185. package/dist/payroll/index.d.ts +230 -0
  186. package/dist/payroll/index.js +713 -0
  187. package/dist/payroll/module.d.ts +9390 -0
  188. package/dist/payroll/module.js +606 -0
  189. package/dist/payroll/routes.d.ts +10 -0
  190. package/dist/payroll/routes.js +112 -0
  191. package/dist/payroll_account/.kosh/bindings.d.ts +22 -0
  192. package/dist/payroll_account/.kosh/bindings.js +15 -0
  193. package/dist/payroll_account/.kosh/schema.d.ts +2308 -0
  194. package/dist/payroll_account/index.d.ts +3 -0
  195. package/dist/payroll_account/index.js +40 -0
  196. package/dist/payroll_account/module.d.ts +12396 -0
  197. package/dist/payroll_account/module.js +256 -0
  198. package/dist/permissions/approvals.d.ts +131 -9
  199. package/dist/permissions/approvals.js +662 -57
  200. package/dist/permissions/index.d.ts +1 -1
  201. package/dist/permissions/index.js +2 -2
  202. package/dist/permissions/models.js +191 -12
  203. package/dist/permissions/routes.d.ts +6 -1
  204. package/dist/permissions/routes.js +37 -4
  205. package/dist/permissions/web/ApprovalPanel.d.ts +5 -4
  206. package/dist/permissions/web/ApprovalPanel.js +39 -13
  207. package/dist/permissions/web/index.d.ts +6 -4
  208. package/dist/permissions/web/index.js +13 -4
  209. package/dist/permissions/web/messages.d.ts +2 -0
  210. package/dist/permissions/web/messages.js +43 -0
  211. package/dist/portal/index.js +1 -1
  212. package/dist/pos/.kosh/bindings.js +1 -1
  213. package/dist/pos/.kosh/schema.d.ts +123 -4
  214. package/dist/pos/index.js +4 -0
  215. package/dist/pos/module.d.ts +147 -0
  216. package/dist/pos_stock/.kosh/bindings.js +1 -1
  217. package/dist/pos_stock/.kosh/schema.d.ts +198 -5
  218. package/dist/pos_stock/module.d.ts +914 -46
  219. package/dist/product/.kosh/bindings.js +1 -1
  220. package/dist/product/.kosh/schema.d.ts +2 -1
  221. package/dist/product/index.js +13 -0
  222. package/dist/product/module.d.ts +2 -0
  223. package/dist/product/module.js +2 -1
  224. package/dist/project/.kosh/bindings.js +1 -1
  225. package/dist/project/.kosh/schema.d.ts +672 -1
  226. package/dist/project/index.d.ts +3 -1
  227. package/dist/project/index.js +901 -14
  228. package/dist/project/module.d.ts +9892 -390
  229. package/dist/project/module.js +1530 -13
  230. package/dist/project/routes.d.ts +44 -0
  231. package/dist/project/routes.js +314 -0
  232. package/dist/project/schedule.d.ts +72 -0
  233. package/dist/project/schedule.js +192 -0
  234. package/dist/project/web/Refresh.d.ts +8 -0
  235. package/dist/project/web/Refresh.js +29 -0
  236. package/dist/project/web/Schedule.d.ts +9 -0
  237. package/dist/project/web/Schedule.js +93 -0
  238. package/dist/project/web/Structure.d.ts +8 -0
  239. package/dist/project/web/Structure.js +86 -0
  240. package/dist/project/web/Workload.d.ts +8 -0
  241. package/dist/project/web/Workload.js +43 -0
  242. package/dist/project/web/index.d.ts +14 -0
  243. package/dist/project/web/index.js +25 -0
  244. package/dist/project/web/messages.d.ts +2 -0
  245. package/dist/project/web/messages.js +85 -0
  246. package/dist/project_account/.kosh/bindings.d.ts +22 -0
  247. package/dist/project_account/.kosh/bindings.js +15 -0
  248. package/dist/project_account/.kosh/schema.d.ts +2241 -0
  249. package/dist/project_account/index.d.ts +3 -0
  250. package/dist/project_account/index.js +27 -0
  251. package/dist/project_account/module.d.ts +11539 -0
  252. package/dist/project_account/module.js +76 -0
  253. package/dist/project_portal/.kosh/bindings.js +1 -1
  254. package/dist/project_portal/.kosh/schema.d.ts +672 -1
  255. package/dist/project_portal/module.d.ts +4798 -129
  256. package/dist/project_purchase/.kosh/bindings.d.ts +22 -0
  257. package/dist/project_purchase/.kosh/bindings.js +15 -0
  258. package/dist/project_purchase/.kosh/schema.d.ts +2320 -0
  259. package/dist/project_purchase/index.d.ts +9 -0
  260. package/dist/project_purchase/index.js +22 -0
  261. package/dist/project_purchase/module.d.ts +25147 -0
  262. package/dist/project_purchase/module.js +56 -0
  263. package/dist/purchase/.kosh/bindings.js +1 -1
  264. package/dist/purchase/.kosh/schema.d.ts +97 -4
  265. package/dist/purchase/module.d.ts +13 -2
  266. package/dist/purchase/module.js +10 -1
  267. package/dist/purchase_account/.kosh/bindings.js +1 -1
  268. package/dist/purchase_account/.kosh/schema.d.ts +126 -6
  269. package/dist/purchase_account/index.js +1 -0
  270. package/dist/purchase_account/module.d.ts +176 -1
  271. package/dist/purchase_account/module.js +13 -2
  272. package/dist/purchase_portal/.kosh/bindings.js +1 -1
  273. package/dist/purchase_portal/.kosh/schema.d.ts +97 -4
  274. package/dist/purchase_portal/module.d.ts +6 -1
  275. package/dist/purchase_stock/.kosh/bindings.js +1 -1
  276. package/dist/purchase_stock/.kosh/schema.d.ts +174 -5
  277. package/dist/purchase_stock/index.d.ts +1 -1
  278. package/dist/purchase_stock/index.js +9 -2
  279. package/dist/purchase_stock/module.d.ts +840 -68
  280. package/dist/purchase_stock/module.js +242 -6
  281. package/dist/purchase_stock_account/.kosh/bindings.js +1 -1
  282. package/dist/purchase_stock_account/.kosh/schema.d.ts +203 -7
  283. package/dist/purchase_stock_account/module.d.ts +8163 -5514
  284. package/dist/purchase_stock_account/module.js +11 -5
  285. package/dist/recruitment/.kosh/bindings.js +1 -1
  286. package/dist/recruitment/.kosh/schema.d.ts +2 -1
  287. package/dist/recruitment/module.d.ts +2 -0
  288. package/dist/recruitment/module.js +2 -1
  289. package/dist/sale_account/.kosh/bindings.js +1 -1
  290. package/dist/sale_account/.kosh/schema.d.ts +123 -4
  291. package/dist/sale_account/module.d.ts +147 -0
  292. package/dist/sale_portal/.kosh/bindings.js +1 -1
  293. package/dist/sale_portal/.kosh/schema.d.ts +2 -1
  294. package/dist/sale_portal/module.d.ts +1 -0
  295. package/dist/sale_project/.kosh/bindings.js +1 -1
  296. package/dist/sale_project/.kosh/schema.d.ts +673 -1
  297. package/dist/sale_project/module.d.ts +4800 -129
  298. package/dist/sale_project/module.js +17 -1
  299. package/dist/sale_stock/.kosh/bindings.js +1 -1
  300. package/dist/sale_stock/.kosh/schema.d.ts +77 -2
  301. package/dist/sale_stock/module.d.ts +789 -66
  302. package/dist/sales/.kosh/bindings.js +1 -1
  303. package/dist/sales/.kosh/schema.d.ts +2 -1
  304. package/dist/sales/index.js +4 -0
  305. package/dist/sales/module.d.ts +1 -0
  306. package/dist/sign/.kosh/bindings.d.ts +22 -0
  307. package/dist/sign/.kosh/bindings.js +15 -0
  308. package/dist/sign/.kosh/schema.d.ts +990 -0
  309. package/dist/sign/index.d.ts +14 -0
  310. package/dist/sign/index.js +350 -0
  311. package/dist/sign/module.d.ts +4478 -0
  312. package/dist/sign/module.js +158 -0
  313. package/dist/sign/sign.d.ts +82 -0
  314. package/dist/sign/sign.js +474 -0
  315. package/dist/stock/.kosh/bindings.js +1 -1
  316. package/dist/stock/.kosh/schema.d.ts +77 -2
  317. package/dist/stock/demo.d.ts +2 -1
  318. package/dist/stock/demo.js +28 -1
  319. package/dist/stock/index.d.ts +2 -1
  320. package/dist/stock/index.js +233 -4
  321. package/dist/stock/module.d.ts +2363 -837
  322. package/dist/stock/module.js +569 -14
  323. package/dist/stock/replenish.d.ts +38 -0
  324. package/dist/stock/replenish.js +176 -0
  325. package/dist/stock/web/Replenishment.d.ts +8 -0
  326. package/dist/stock/web/Replenishment.js +84 -0
  327. package/dist/stock/web/index.d.ts +4 -2
  328. package/dist/stock/web/index.js +6 -2
  329. package/dist/stock/web/messages.js +52 -0
  330. package/dist/stock_account/.kosh/bindings.js +1 -1
  331. package/dist/stock_account/.kosh/schema.d.ts +198 -5
  332. package/dist/stock_account/index.js +10 -0
  333. package/dist/stock_account/module.d.ts +969 -101
  334. package/dist/trade_finance/index.js +2 -0
  335. package/dist/trade_finance/module.js +2 -0
  336. package/dist/trade_finance_account/.kosh/bindings.js +1 -1
  337. package/dist/trade_finance_account/.kosh/schema.d.ts +123 -4
  338. package/dist/trade_finance_account/index.js +1 -0
  339. package/dist/trade_finance_account/module.d.ts +146 -0
  340. package/dist/trade_finance_account/module.js +1 -0
  341. package/dist/trade_finance_purchase/.kosh/bindings.js +1 -1
  342. package/dist/trade_finance_purchase/.kosh/schema.d.ts +97 -4
  343. package/dist/trade_finance_purchase/module.d.ts +6 -1
  344. package/dist/trade_finance_sale/.kosh/bindings.js +1 -1
  345. package/dist/trade_finance_sale/.kosh/schema.d.ts +2 -1
  346. package/dist/trade_finance_sale/module.d.ts +1 -0
  347. package/dist/ui/app.js +24 -12
  348. package/dist/ui/components/AppIcon.js +8 -1
  349. package/dist/ui/i18n/messages.d.ts +4 -0
  350. package/dist/ui/i18n/messages.js +8 -0
  351. package/dist/ui/views/FormView.js +4 -2
  352. package/dist/ui/views/KanbanView.js +9 -1
  353. package/dist/ui/views/ListView.js +4 -2
  354. package/dist/ui/views/widgets.js +7 -1
  355. package/dist/website/index.js +1 -0
  356. package/dist/website/module.js +1 -0
  357. package/dist/website_crm/.kosh/bindings.js +1 -1
  358. package/dist/website_crm/.kosh/schema.d.ts +2 -1
  359. package/dist/website_crm/module.d.ts +1 -0
  360. package/dist/website_sale/.kosh/bindings.d.ts +22 -0
  361. package/dist/website_sale/.kosh/bindings.js +15 -0
  362. package/dist/website_sale/.kosh/schema.d.ts +2284 -0
  363. package/dist/website_sale/couriers.d.ts +50 -0
  364. package/dist/website_sale/couriers.js +59 -0
  365. package/dist/website_sale/demo.d.ts +7 -0
  366. package/dist/website_sale/demo.js +90 -0
  367. package/dist/website_sale/growth.d.ts +31 -0
  368. package/dist/website_sale/growth.js +163 -0
  369. package/dist/website_sale/index.d.ts +49 -0
  370. package/dist/website_sale/index.js +538 -0
  371. package/dist/website_sale/module.d.ts +22027 -0
  372. package/dist/website_sale/module.js +397 -0
  373. package/dist/website_sale/shipments.d.ts +16 -0
  374. package/dist/website_sale/shipments.js +113 -0
  375. package/dist/website_sale/shop.d.ts +81 -0
  376. package/dist/website_sale/shop.js +649 -0
  377. package/dist/website_sale_stock/.kosh/bindings.d.ts +22 -0
  378. package/dist/website_sale_stock/.kosh/bindings.js +15 -0
  379. package/dist/website_sale_stock/.kosh/schema.d.ts +2681 -0
  380. package/dist/website_sale_stock/index.d.ts +9 -0
  381. package/dist/website_sale_stock/index.js +20 -0
  382. package/dist/website_sale_stock/module.d.ts +24998 -0
  383. package/dist/website_sale_stock/module.js +28 -0
  384. package/package.json +83 -2
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Helpdesk's demo data (RFC 0008 §5.8): a Support team (Dina and Rahim, assigned in turn, Sunday to Thursday 09:00
3
+ * to 18:00), a standard SLA and a faster one for urgent tickets, a canned reply, and three tickets from customers —
4
+ * one answered and waiting on the customer, one urgent, one solved — with the clock refreshed.
5
+ */
6
+ import type { DemoContext } from '../modules-sdk/index.js';
7
+ export declare function helpdeskDemo(ctx: DemoContext): Promise<string>;
@@ -0,0 +1,65 @@
1
+ import { refreshSla } from './sla.js';
2
+ const DINA = { login: 'dina', name: 'Dina Rahman', groups: ['helpdesk.manager'] };
3
+ const RAHIM = { login: 'rahim', name: 'Rahim Uddin', groups: ['helpdesk.user'] };
4
+ export async function helpdeskDemo(ctx) {
5
+ const rahim = await ctx.as(RAHIM, async (raw) => raw.userId);
6
+ await ctx.as(DINA, async (raw) => {
7
+ const env = raw;
8
+ const team = (await env.model('helpdesk.team').create([
9
+ {
10
+ name: 'Support',
11
+ members: { set: [env.userId, rahim] },
12
+ assignment: 'round_robin',
13
+ },
14
+ ])).ids[0];
15
+ await env.model('helpdesk.sla').create([
16
+ { name: 'Standard', sequence: 20, team, firstReplyHours: '4', resolveHours: '24' },
17
+ {
18
+ name: 'Urgent',
19
+ sequence: 10,
20
+ team,
21
+ priority: 'urgent',
22
+ firstReplyHours: '1',
23
+ resolveHours: '8',
24
+ },
25
+ ]);
26
+ await env.model('helpdesk.canned').create([
27
+ {
28
+ name: 'Thanks, looking into it',
29
+ body: 'Dear {{customer}},\n\nThank you for writing about {{ticket}}. We are looking into it and will be back to you soon.\n\n{{agent}}',
30
+ },
31
+ ]);
32
+ const partner = async (name, email) => (await env.model('res.partner').search({ where: { name }, limit: 1 })).ids[0] ??
33
+ (await env.model('res.partner').create([{ name, email }])).ids[0];
34
+ const made = await env.model('helpdesk.ticket').create([
35
+ {
36
+ subject: 'Invoice INV/2026/0007 shows the wrong VAT',
37
+ description: 'The VAT on line 2 should be 15%, not 7.5%.',
38
+ team,
39
+ partner: await partner('Meghna Mills', 'accounts@meghna.example'),
40
+ priority: 'normal',
41
+ },
42
+ {
43
+ subject: 'Delivery to the Gazipur warehouse did not arrive',
44
+ description: 'The order was due yesterday; the line is stopped.',
45
+ team,
46
+ partner: await partner('Bengal Steel', 'stores@bengalsteel.example'),
47
+ priority: 'urgent',
48
+ },
49
+ {
50
+ subject: 'How do I download my statement?',
51
+ team,
52
+ partner: await partner('Padma Foods', 'office@padmafoods.example'),
53
+ priority: 'low',
54
+ },
55
+ ]);
56
+ await env.flush();
57
+ const [first, , third] = made.ids;
58
+ if (first !== undefined)
59
+ await env.model('helpdesk.ticket').browse([first]).wait();
60
+ if (third !== undefined)
61
+ await env.model('helpdesk.ticket').browse([third]).solve();
62
+ await env.asSuperuser({ reason: 'demo helpdesk clock' }, (su) => refreshSla(su));
63
+ });
64
+ return 'Helpdesk: the Support team, two SLA policies, a canned reply, three tickets (waiting, urgent, solved).';
65
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Business hours (RFC 0024 §2.4): a team works from `open` to `close` (`HH:MM`) on the days outside its weekend, in
3
+ * a time zone; SLA targets count only those minutes. Pure functions, without a database.
4
+ */
5
+ export interface Hours {
6
+ readonly open: string;
7
+ readonly close: string;
8
+ /** JavaScript day numbers off (0: Sunday). */
9
+ readonly weekend: readonly number[];
10
+ readonly tz: string;
11
+ }
12
+ /** The weekend of each choice, as JavaScript day numbers. */
13
+ export declare const WEEKENDS: Readonly<Record<string, readonly number[]>>;
14
+ /** The moment `minutes` working minutes after `from`. */
15
+ export declare function addBusinessMinutes(from: Date, minutes: number, hours: Hours): Date;
16
+ /** The working minutes between two moments (0 when `to` is not after `from`). */
17
+ export declare function businessMinutesBetween(from: Date, to: Date, hours: Hours): number;
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Business hours (RFC 0024 §2.4): a team works from `open` to `close` (`HH:MM`) on the days outside its weekend, in
3
+ * a time zone; SLA targets count only those minutes. Pure functions, without a database.
4
+ */
5
+ /** The weekend of each choice, as JavaScript day numbers. */
6
+ export const WEEKENDS = {
7
+ fri_sat: [5, 6],
8
+ sat_sun: [6, 0],
9
+ fri: [5],
10
+ none: [],
11
+ };
12
+ const DAY = 86_400_000;
13
+ const minutesOf = (hhmm) => {
14
+ const [h, m] = hhmm.split(':').map(Number);
15
+ return h * 60 + m;
16
+ };
17
+ function parts(at, tz) {
18
+ const out = {};
19
+ for (const p of new Intl.DateTimeFormat('en-US', {
20
+ timeZone: tz,
21
+ hourCycle: 'h23',
22
+ year: 'numeric',
23
+ month: '2-digit',
24
+ day: '2-digit',
25
+ hour: '2-digit',
26
+ minute: '2-digit',
27
+ }).formatToParts(at))
28
+ if (p.type !== 'literal')
29
+ out[p.type] = Number(p.value);
30
+ return {
31
+ y: out['year'] ?? 0,
32
+ m: out['month'] ?? 1,
33
+ d: out['day'] ?? 1,
34
+ h: out['hour'] ?? 0,
35
+ min: out['minute'] ?? 0,
36
+ };
37
+ }
38
+ /** The instant of `minutes` after midnight of the local date `y-m-d` in `tz`. */
39
+ function instant(y, m, d, minutes, tz) {
40
+ const guess = Date.UTC(y, m - 1, d, 0, minutes);
41
+ const offset = (t) => {
42
+ const p = parts(new Date(t), tz);
43
+ return Date.UTC(p.y, p.m - 1, p.d, p.h, p.min) - t;
44
+ };
45
+ const first = guess - offset(guess);
46
+ return guess - offset(first);
47
+ }
48
+ /** The working window of each local day from the one of `from`, as instants, for at most `days` days. */
49
+ function* windows(from, hours, days = 3660) {
50
+ const p = parts(from, hours.tz);
51
+ let day = Date.UTC(p.y, p.m - 1, p.d);
52
+ const open = minutesOf(hours.open);
53
+ const close = minutesOf(hours.close);
54
+ if (close <= open)
55
+ return;
56
+ for (let i = 0; i < days; i += 1, day += DAY) {
57
+ const date = new Date(day);
58
+ if (hours.weekend.includes(date.getUTCDay()))
59
+ continue;
60
+ const y = date.getUTCFullYear();
61
+ const m = date.getUTCMonth() + 1;
62
+ const d = date.getUTCDate();
63
+ yield [instant(y, m, d, open, hours.tz), instant(y, m, d, close, hours.tz)];
64
+ }
65
+ }
66
+ /** The moment `minutes` working minutes after `from`. */
67
+ export function addBusinessMinutes(from, minutes, hours) {
68
+ let left = Math.max(0, minutes) * 60_000;
69
+ const start = from.getTime();
70
+ for (const [a, b] of windows(from, hours)) {
71
+ const s = Math.max(a, start);
72
+ if (s >= b)
73
+ continue;
74
+ if (s + left <= b)
75
+ return new Date(s + left);
76
+ left -= b - s;
77
+ }
78
+ return new Date(start + minutes * 60_000);
79
+ }
80
+ /** The working minutes between two moments (0 when `to` is not after `from`). */
81
+ export function businessMinutesBetween(from, to, hours) {
82
+ if (to <= from)
83
+ return 0;
84
+ let total = 0;
85
+ for (const [a, b] of windows(from, hours)) {
86
+ if (a >= to.getTime())
87
+ break;
88
+ const s = Math.max(a, from.getTime());
89
+ const e = Math.min(b, to.getTime());
90
+ if (e > s)
91
+ total += e - s;
92
+ }
93
+ return Math.round(total / 60_000);
94
+ }
@@ -0,0 +1,10 @@
1
+ import { defineModule } from '../modules-sdk/index.js';
2
+ export { addBusinessMinutes, businessMinutesBetween, type Hours, WEEKENDS } from './hours.js';
3
+ export { HelpdeskCanned, HelpdeskSla, HelpdeskStage, HelpdeskTeam, HelpdeskTicket, HelpdeskType, helpdeskShutro, PRIORITIES, } from './module.js';
4
+ export { askRating, hoursOf, pausedSince, rate, refreshSla, timeZoneOf } from './sla.js';
5
+ /** A ticket's values from an email to `helpdesk@`: the first team, the sender as the customer (added when new). */
6
+ export declare function ticketFromEmail(raw: unknown, sender: {
7
+ readonly address: string;
8
+ readonly name: string | null;
9
+ }): Promise<Record<string, unknown> | null>;
10
+ export declare const helpdesk: ReturnType<typeof defineModule>;
@@ -0,0 +1,461 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * `shutro-erp/helpdesk` (RFC 0024 §2.4): the **Helpdesk** app. Teams with business hours and assignment in turn or by
4
+ * load; tickets from email (`helpdesk@`, the sender found or added as a contact; replies thread into the ticket) and
5
+ * from the back-office; SLA policies by team, priority and customer, counted in business hours with the clock paused
6
+ * while waiting on the customer, resumed when they write back; drafted replies from the chatter's assistant; canned
7
+ * replies; merging; and the customer's rating of the help.
8
+ */
9
+ import { contacts } from '../contacts/index.js';
10
+ import { messaging } from '../messaging/index.js';
11
+ import { defineModule } from '../modules-sdk/index.js';
12
+ import { reporting } from '../reporting/index.js';
13
+ import { action, form, kanban, list, pivot, search, stat } from '../views/index.js';
14
+ import { helpdeskDemo } from './demo.js';
15
+ import { HelpdeskCanned, HelpdeskSla, HelpdeskStage, HelpdeskTeam, HelpdeskTicket, HelpdeskType, helpdeskShutro, } from './module.js';
16
+ import { registerHelpdeskRoutes } from './routes.js';
17
+ export { addBusinessMinutes, businessMinutesBetween, WEEKENDS } from './hours.js';
18
+ export { HelpdeskCanned, HelpdeskSla, HelpdeskStage, HelpdeskTeam, HelpdeskTicket, HelpdeskType, helpdeskShutro, PRIORITIES, } from './module.js';
19
+ export { askRating, hoursOf, pausedSince, rate, refreshSla, timeZoneOf } from './sla.js';
20
+ /** A ticket's values from an email to `helpdesk@`: the first team, the sender as the customer (added when new). */
21
+ export async function ticketFromEmail(raw, sender) {
22
+ const env = raw;
23
+ const team = (await env.model('helpdesk.team').search({ order: ['id asc'], limit: 1 })).ids[0] ?? null;
24
+ const address = sender.address.trim().toLowerCase();
25
+ if (address === '')
26
+ return { team };
27
+ const known = (await env.model('res.partner').search({ where: { email: { ilike: address } }, limit: 1 })).ids[0];
28
+ const partner = known ??
29
+ (await env
30
+ .model('res.partner')
31
+ .create([{ name: sender.name ?? address, email: address }])).ids[0];
32
+ return { team, partner: partner ?? null, email: address };
33
+ }
34
+ export const helpdesk = defineModule({
35
+ shutro: helpdeskShutro,
36
+ kosh: '^0.1.0',
37
+ hooks: { demo: helpdeskDemo },
38
+ depends: [contacts, messaging, reporting],
39
+ app: {
40
+ code: 'helpdesk',
41
+ label: 'Helpdesk',
42
+ icon: 'helpdesk',
43
+ sequence: 12,
44
+ category: 'Services',
45
+ summary: 'Tickets from email, SLAs in business hours, assignment, ratings',
46
+ },
47
+ accessLevels: {
48
+ user: { label: 'Agent (the tickets of their teams)', groups: ['helpdesk.user'] },
49
+ manager: {
50
+ label: 'Helpdesk manager (teams, SLAs, every ticket)',
51
+ groups: ['helpdesk.manager'],
52
+ implies: ['user'],
53
+ },
54
+ },
55
+ routes: (context) => registerHelpdeskRoutes(context),
56
+ // helpdesk@<inbound domain>: a ticket for the sender (RFC 0006 §7.1); replies thread in through the reply address.
57
+ inboundAliases: [
58
+ {
59
+ alias: 'helpdesk',
60
+ model: 'helpdesk.ticket',
61
+ subjectField: 'subject',
62
+ bodyField: 'description',
63
+ defaults: ticketFromEmail,
64
+ },
65
+ ],
66
+ // Automation rules can act on a ticket's fields (an SLA breached, a priority raised).
67
+ changeEvents: ['helpdesk.ticket'],
68
+ settings: {
69
+ sections: [
70
+ {
71
+ key: 'clock',
72
+ label: 'Time zone',
73
+ description: 'The teams’ business hours are read in this time zone.',
74
+ keywords: 'timezone time zone sla business hours',
75
+ scope: 'installation',
76
+ editors: ['helpdesk.manager'],
77
+ fields: [
78
+ {
79
+ key: 'timezone',
80
+ type: 'char',
81
+ label: 'Time zone',
82
+ default: 'Asia/Dhaka',
83
+ help: 'An IANA name such as Asia/Dhaka or Asia/Kolkata.',
84
+ },
85
+ ],
86
+ },
87
+ ],
88
+ },
89
+ events: [{ topic: 'helpdesk.ticket.solved', model: 'helpdesk.ticket', label: 'Ticket solved' }],
90
+ documents: [
91
+ {
92
+ key: 'ticket',
93
+ name: 'Ticket',
94
+ model: 'helpdesk.ticket',
95
+ layout: {
96
+ paper: 'A4',
97
+ header: '{{company.name}}',
98
+ blocks: [
99
+ { kind: 'heading', id: 'title', text: '{{name}} — {{subject}}', level: 1 },
100
+ {
101
+ kind: 'fields',
102
+ id: 'ticket',
103
+ items: [
104
+ { label: 'Customer', bind: 'partner.name' },
105
+ { label: 'Team', bind: 'team.name' },
106
+ { label: 'Agent', bind: 'assignee.name' },
107
+ { label: 'Priority', bind: 'priority' },
108
+ { label: 'Status', bind: 'state' },
109
+ { label: 'SLA', bind: 'slaStatus' },
110
+ { label: 'Solved by', bind: 'resolveDeadline' },
111
+ ],
112
+ },
113
+ { kind: 'text', id: 'description', text: '{{description}}' },
114
+ ],
115
+ },
116
+ },
117
+ ],
118
+ importTemplates: [
119
+ {
120
+ key: 'tickets',
121
+ model: 'helpdesk.ticket',
122
+ label: 'Tickets',
123
+ columns: [
124
+ { header: 'Subject', field: 'subject' },
125
+ { header: 'Description', field: 'description' },
126
+ { header: 'Customer', field: 'partner' },
127
+ { header: 'Team', field: 'team' },
128
+ { header: 'Priority', field: 'priority' },
129
+ ],
130
+ },
131
+ {
132
+ key: 'teams',
133
+ model: 'helpdesk.team',
134
+ label: 'Teams',
135
+ columns: [
136
+ { header: 'Name', field: 'name' },
137
+ { header: 'Opens', field: 'open' },
138
+ { header: 'Closes', field: 'close' },
139
+ { header: 'Weekend', field: 'weekend' },
140
+ ],
141
+ },
142
+ {
143
+ key: 'slas',
144
+ model: 'helpdesk.sla',
145
+ label: 'SLA policies',
146
+ columns: [
147
+ { header: 'Name', field: 'name' },
148
+ { header: 'Team', field: 'team' },
149
+ { header: 'From priority', field: 'priority' },
150
+ { header: 'First reply within (hours)', field: 'firstReplyHours' },
151
+ { header: 'Solved within (hours)', field: 'resolveHours' },
152
+ ],
153
+ },
154
+ {
155
+ key: 'types',
156
+ model: 'helpdesk.type',
157
+ label: 'Ticket types',
158
+ columns: [{ header: 'Name', field: 'name' }],
159
+ },
160
+ {
161
+ key: 'stages',
162
+ model: 'helpdesk.stage',
163
+ label: 'Stages',
164
+ columns: [
165
+ { header: 'Name', field: 'name' },
166
+ { header: 'Sequence', field: 'sequence' },
167
+ ],
168
+ },
169
+ ],
170
+ overview: {
171
+ cards: [
172
+ {
173
+ id: 'open',
174
+ title: 'Open tickets',
175
+ kind: 'kpi',
176
+ model: 'helpdesk.ticket',
177
+ measure: 'count',
178
+ filter: { state: { in: ['open', 'waiting'] } },
179
+ w: 3,
180
+ },
181
+ {
182
+ id: 'breached',
183
+ title: 'SLA breached',
184
+ kind: 'kpi',
185
+ model: 'helpdesk.ticket',
186
+ measure: 'count',
187
+ filter: { slaStatus: 'breached', state: { in: ['open', 'waiting'] } },
188
+ w: 3,
189
+ },
190
+ {
191
+ id: 'solved_month',
192
+ title: 'Solved this month',
193
+ kind: 'kpi',
194
+ model: 'helpdesk.ticket',
195
+ measure: 'count',
196
+ filter: { state: { in: ['solved', 'closed'] } },
197
+ comparison: { field: 'solvedAt', mode: 'previous' },
198
+ w: 3,
199
+ },
200
+ {
201
+ id: 'rating',
202
+ title: 'Average rating',
203
+ kind: 'kpi',
204
+ model: 'helpdesk.ticket',
205
+ measure: 'avg:rating',
206
+ filter: { rating: { isNull: false } },
207
+ w: 3,
208
+ },
209
+ {
210
+ id: 'by_sla',
211
+ title: 'Tickets by SLA',
212
+ kind: 'chart',
213
+ model: 'helpdesk.ticket',
214
+ measure: 'count',
215
+ groupBy: 'slaStatus',
216
+ chart: 'pie',
217
+ filter: { state: { in: ['open', 'waiting'] } },
218
+ w: 6,
219
+ },
220
+ {
221
+ id: 'by_agent',
222
+ title: 'Open by agent',
223
+ kind: 'pivot',
224
+ model: 'helpdesk.ticket',
225
+ measure: 'count',
226
+ groupBy: 'assignee',
227
+ filter: { state: { in: ['open', 'waiting'] } },
228
+ w: 6,
229
+ },
230
+ ],
231
+ },
232
+ actions: {
233
+ 'helpdesk.action_tickets': action(HelpdeskTicket, {
234
+ label: 'Tickets',
235
+ views: ['kanban', 'list', 'form', 'pivot'],
236
+ }),
237
+ 'helpdesk.action_teams': action(HelpdeskTeam, { label: 'Teams', views: ['list', 'form'] }),
238
+ 'helpdesk.action_slas': action(HelpdeskSla, { label: 'SLA policies', views: ['list', 'form'] }),
239
+ 'helpdesk.action_canned': action(HelpdeskCanned, {
240
+ label: 'Canned replies',
241
+ views: ['list', 'form'],
242
+ }),
243
+ 'helpdesk.action_stages': action(HelpdeskStage, { label: 'Stages', views: ['list', 'form'] }),
244
+ 'helpdesk.action_types': action(HelpdeskType, {
245
+ label: 'Ticket types',
246
+ views: ['list', 'form'],
247
+ }),
248
+ },
249
+ menus: [
250
+ { id: 'helpdesk.root', label: 'Helpdesk', app: 'helpdesk' },
251
+ {
252
+ id: 'helpdesk.tickets',
253
+ parent: 'helpdesk.root',
254
+ label: 'Tickets',
255
+ action: 'helpdesk.action_tickets',
256
+ sequence: 1,
257
+ },
258
+ {
259
+ id: 'helpdesk.canned',
260
+ parent: 'helpdesk.root',
261
+ label: 'Canned replies',
262
+ action: 'helpdesk.action_canned',
263
+ sequence: 2,
264
+ },
265
+ { id: 'helpdesk.configuration', parent: 'helpdesk.root', label: 'Configuration', sequence: 9 },
266
+ {
267
+ id: 'helpdesk.teams',
268
+ parent: 'helpdesk.configuration',
269
+ label: 'Teams',
270
+ action: 'helpdesk.action_teams',
271
+ sequence: 1,
272
+ },
273
+ {
274
+ id: 'helpdesk.slas',
275
+ parent: 'helpdesk.configuration',
276
+ label: 'SLA policies',
277
+ action: 'helpdesk.action_slas',
278
+ sequence: 2,
279
+ },
280
+ {
281
+ id: 'helpdesk.stages',
282
+ parent: 'helpdesk.configuration',
283
+ label: 'Stages',
284
+ action: 'helpdesk.action_stages',
285
+ sequence: 3,
286
+ },
287
+ {
288
+ id: 'helpdesk.types',
289
+ parent: 'helpdesk.configuration',
290
+ label: 'Ticket types',
291
+ action: 'helpdesk.action_types',
292
+ sequence: 4,
293
+ },
294
+ ],
295
+ views: {
296
+ 'helpdesk.ticket.kanban': kanban(HelpdeskTicket, {
297
+ groupBy: 'stage',
298
+ card: {
299
+ title: 'subject',
300
+ subtitle: 'partner',
301
+ avatar: 'assignee',
302
+ footer: [{ field: 'resolveDeadline', widget: 'daysLeft' }, 'name'],
303
+ badges: [{ field: 'slaStatus', widget: 'badge' }],
304
+ },
305
+ }),
306
+ 'helpdesk.ticket.list': list(HelpdeskTicket, {
307
+ columns: [
308
+ 'name',
309
+ 'subject',
310
+ 'partner',
311
+ 'team',
312
+ 'assignee',
313
+ 'priority',
314
+ 'state',
315
+ 'slaStatus',
316
+ 'resolveDeadline',
317
+ ],
318
+ defaultOrder: ['id desc'],
319
+ decorations: { danger: { slaStatus: 'breached' }, warning: { slaStatus: 'at_risk' } },
320
+ }),
321
+ 'helpdesk.ticket.pivot': pivot(HelpdeskTicket, {
322
+ rows: ['team'],
323
+ cols: ['slaStatus'],
324
+ measures: ['count'],
325
+ }),
326
+ 'helpdesk.ticket.form': form(HelpdeskTicket, (k) => ({
327
+ header: {
328
+ statusbar: 'state',
329
+ buttons: [
330
+ k.button('solve', { primary: true, label: 'Solved' }),
331
+ k.button('wait', { label: 'Waiting on the customer' }),
332
+ k.button('resume', { label: 'Resume' }),
333
+ k.button('reopen', { label: 'Reopen' }),
334
+ k.button('close', { label: 'Close' }),
335
+ ],
336
+ },
337
+ sheet: [
338
+ k.group('main', [
339
+ 'name',
340
+ 'subject',
341
+ 'partner',
342
+ 'email',
343
+ 'team',
344
+ 'assignee',
345
+ 'type',
346
+ 'priority',
347
+ 'stage',
348
+ ]),
349
+ k.group('details', ['description'], { label: 'Description' }),
350
+ k.group('service_level', [
351
+ 'sla',
352
+ 'slaStatus',
353
+ 'firstReplyDeadline',
354
+ 'firstRepliedAt',
355
+ 'resolveDeadline',
356
+ 'pausedMinutes',
357
+ ], {
358
+ label: 'SLA',
359
+ description: 'In the team’s business hours; waiting on the customer pauses the resolution target.',
360
+ }),
361
+ k.group('outcome', ['solvedAt', 'rating', 'ratingComment', 'mergedInto'], {
362
+ label: 'Outcome',
363
+ }),
364
+ ],
365
+ chatter: true,
366
+ })),
367
+ 'helpdesk.team.list': list(HelpdeskTeam, {
368
+ columns: ['name', 'assignment', 'open', 'close', 'weekend'],
369
+ }),
370
+ 'helpdesk.team.form': form(HelpdeskTeam, (k) => ({
371
+ header: { buttons: [] },
372
+ sheet: [
373
+ k.stats('related', [
374
+ stat({
375
+ id: 'team_open',
376
+ label: 'Open tickets',
377
+ model: 'helpdesk.ticket',
378
+ where: { team: { $record: 'id' }, state: { in: ['open', 'waiting'] } },
379
+ action: 'helpdesk.action_tickets',
380
+ }),
381
+ ]),
382
+ k.group('main', ['name', 'members', 'assignment', 'rating']),
383
+ k.group('hours', ['open', 'close', 'weekend'], { label: 'Business hours' }),
384
+ ],
385
+ })),
386
+ 'helpdesk.sla.list': list(HelpdeskSla, {
387
+ columns: [
388
+ 'sequence',
389
+ 'name',
390
+ 'team',
391
+ 'priority',
392
+ 'partner',
393
+ 'firstReplyHours',
394
+ 'resolveHours',
395
+ ],
396
+ }),
397
+ 'helpdesk.sla.form': form(HelpdeskSla, (k) => ({
398
+ header: { buttons: [] },
399
+ sheet: [
400
+ k.group('main', ['name', 'sequence', 'team', 'priority', 'partner'], {
401
+ description: 'The first policy, by sequence, that matches a ticket applies to it.',
402
+ }),
403
+ k.group('targets', ['firstReplyHours', 'resolveHours'], {
404
+ label: 'Targets (business hours)',
405
+ }),
406
+ ],
407
+ })),
408
+ 'helpdesk.canned.list': list(HelpdeskCanned, { columns: ['name'] }),
409
+ 'helpdesk.canned.form': form(HelpdeskCanned, (k) => ({
410
+ header: { buttons: [] },
411
+ sheet: [k.group('main', ['name', 'body'])],
412
+ })),
413
+ 'helpdesk.stage.list': list(HelpdeskStage, { columns: ['sequence', 'name', 'fold'] }),
414
+ 'helpdesk.stage.form': form(HelpdeskStage, (k) => ({
415
+ header: { buttons: [] },
416
+ sheet: [k.group('main', ['name', 'sequence', 'fold'])],
417
+ })),
418
+ 'helpdesk.type.list': list(HelpdeskType, { columns: ['name'] }),
419
+ 'helpdesk.type.form': form(HelpdeskType, (k) => ({
420
+ header: { buttons: [] },
421
+ sheet: [k.group('main', ['name'])],
422
+ })),
423
+ },
424
+ viewExtensions: [
425
+ {
426
+ view: 'res.partner.form',
427
+ operations: [
428
+ {
429
+ append: 'related',
430
+ nodes: [
431
+ stat({
432
+ id: 'partner_tickets',
433
+ label: 'Tickets',
434
+ model: 'helpdesk.ticket',
435
+ where: { partner: { $record: 'id' } },
436
+ action: 'helpdesk.action_tickets',
437
+ }),
438
+ ],
439
+ },
440
+ ],
441
+ },
442
+ ],
443
+ search: {
444
+ 'helpdesk.ticket': search(HelpdeskTicket, {
445
+ fields: ['name', 'subject', 'partner.name', 'email'],
446
+ filters: {
447
+ mine: { label: 'Mine', domain: { assignee: { $env: 'uid' } }, group: 'who' },
448
+ unassigned: { label: 'Unassigned', domain: { assignee: { isNull: true } }, group: 'who' },
449
+ open: { label: 'Open', domain: { state: { in: ['open', 'waiting'] } }, group: 'state' },
450
+ breached: { label: 'SLA breached', domain: { slaStatus: 'breached' }, group: 'sla' },
451
+ at_risk: { label: 'SLA at risk', domain: { slaStatus: 'at_risk' }, group: 'sla' },
452
+ },
453
+ groupBy: ['team', 'assignee', 'stage', 'priority', 'slaStatus', 'partner'],
454
+ }),
455
+ 'helpdesk.team': search(HelpdeskTeam, { fields: ['name'] }),
456
+ 'helpdesk.sla': search(HelpdeskSla, { fields: ['name'], groupBy: ['team', 'priority'] }),
457
+ 'helpdesk.canned': search(HelpdeskCanned, { fields: ['name', 'body'] }),
458
+ 'helpdesk.stage': search(HelpdeskStage, { fields: ['name'] }),
459
+ 'helpdesk.type': search(HelpdeskType, { fields: ['name'] }),
460
+ },
461
+ });