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,538 @@
1
+ /**
2
+ * @packageDocumentation
3
+ * `shutro-erp/website_sale` (RFC 0024 §2.7): the **Shop** on a Sites site. Products published with a description in English
4
+ * and Bangla; delivery methods with fees (fixed, by weight, by zone — Dhaka or outside — free above an amount); a
5
+ * public API for a storefront (the Next.js site, or any other): the catalogue, a cart held by a secret token, the
6
+ * delivery methods with their fee, and checkout with cash on delivery or an online payment (RFC 0017 providers),
7
+ * which confirms, invoices and pays the order once the provider confirms. No sign-in; rate limited per address as
8
+ * every public route is; prices always the server's. The cart's token travels in the `x-cart-token` header.
9
+ *
10
+ * - `GET /api/v1/public/shop/:site/products?q=&category=&min=&max=&sort=price|-price|name|new&page=&lang=`
11
+ * - `GET /api/v1/public/shop/:site/products/:id?lang=` a product's page with related products
12
+ * - `GET /api/v1/public/shop/:site/categories?lang=`
13
+ * - `POST /api/v1/public/shop/:site/cart` a new cart → `{ token }`
14
+ * - `GET /api/v1/public/shop/:site/cart` the cart (lines, fee, taxes, total)
15
+ * - `PUT /api/v1/public/shop/:site/cart/lines` `{ product, quantity }` (0 removes)
16
+ * - `GET /api/v1/public/shop/:site/carriers?city=` the delivery methods with their fee for the cart
17
+ * - `GET /api/v1/public/shop/:site/payments` the online payment providers offered
18
+ * - `POST /api/v1/public/shop/:site/checkout` `{ name, email, phone, street, city, carrier,
19
+ * payment: 'cod' | provider id, note?, returnUrl? }`
20
+ * - `GET /api/v1/public/shop/:site/order` the placed order of the token: its state, payment
21
+ * and shipments
22
+ * - `PUT /api/v1/public/shop/:site/cart/coupon` `{ code }` (empty takes it off)
23
+ * - `PUT /api/v1/public/shop/:site/cart/contact` `{ email }`: one reminder if the cart is left
24
+ * - `POST /api/v1/public/shop/:site/cart/recover` `{ code }` from the reminder → `{ token }`
25
+ * - `GET /api/v1/public/shop/:site/products/:id/image?w=256` a published product's picture
26
+ * - `GET /api/v1/public/shop/:site/sitemap.xml` the site's pages and products for search engines
27
+ */
28
+ import { mailerFromEnv } from '../mail/index.js';
29
+ import { defineModule } from '../modules-sdk/index.js';
30
+ import { payment } from '../payment/index.js';
31
+ import { product } from '../product/index.js';
32
+ import { saleAccount } from '../sale_account/index.js';
33
+ import { sales } from '../sales/index.js';
34
+ import { HttpProblem } from '../server/index.js';
35
+ import { orm } from '../server/orm.js';
36
+ import { storageOf } from '../storage/index.js';
37
+ import { action, field, form, list, search, stat } from '../views/index.js';
38
+ import { website } from '../website/index.js';
39
+ import { setCouriers, testCourier } from './couriers.js';
40
+ import { shopDemo } from './demo.js';
41
+ import { productImage, recoverCart, remindAbandoned, setContact, setShopMailer, sitemap, } from './growth.js';
42
+ import { DeliveryCarrier, DeliveryShipment, ShopCoupon, websiteSaleShutro } from './module.js';
43
+ import { draftShipments, refreshShipments, trackingOf } from './shipments.js';
44
+ import { carriersFor, cartView, catalogue, categories, checkout, checkoutInput, inLang, newCart, orderOf, productPage, setCoupon, setLine, } from './shop.js';
45
+ export { courierOf, fakeCourier, setCouriers, testCourier, } from './couriers.js';
46
+ export { recoverCart, remindAbandoned, setContact, sitemap } from './growth.js';
47
+ export { COURIERS, DeliveryCarrier, DeliveryShipment, DeliveryShipmentEvent, feeOf, hashToken, LineShop, OrderShop, ProductShop, ShopCoupon, SiteShop, TransactionOrder, websiteSaleShutro, } from './module.js';
48
+ export { draftShipments, refreshShipments, trackingOf } from './shipments.js';
49
+ export { checkout, setDelivery, setLine } from './shop.js';
50
+ const notFound = (what) => new HttpProblem(404, 'not-found', 'Not found', `There is no ${what}.`);
51
+ const decimal = (v, what) => {
52
+ if (v === undefined || v === null || v === '')
53
+ return undefined;
54
+ try {
55
+ return orm.toDecimal(String(v));
56
+ }
57
+ catch {
58
+ throw new HttpProblem(400, 'invalid-input', `Invalid ${what}`, 'A number.');
59
+ }
60
+ };
61
+ const positive = (v) => {
62
+ const n = Number(v);
63
+ return v === undefined || v === '' || !Number.isSafeInteger(n) || n <= 0 ? undefined : n;
64
+ };
65
+ function registerShopRoutes(context) {
66
+ const { app, shutro } = context;
67
+ const pub = { config: { auth: false } };
68
+ const base = '/api/v1/public/shop/:site';
69
+ /** The site's shop, in a system scope of its company (as the superuser: visitors have no rights). */
70
+ const inShop = async (params, reason, fn) => {
71
+ const key = String(params['site'] ?? '');
72
+ const site = await shutro.bootstrap({ reason: `shop: ${reason}` }, async (raw) => {
73
+ const [s] = await (await raw
74
+ .withFlags({ checkCompany: false })
75
+ .model('website.site')
76
+ .search({ where: { key, shop: true }, limit: 1 })).load({});
77
+ return s === undefined ? null : { id: s.id, key: s.key, company: s.company.id };
78
+ });
79
+ if (site === null)
80
+ throw notFound(`shop ${key}`);
81
+ return shutro.bootstrap({ reason: `shop: ${reason}`, company: site.company }, (raw) => raw.asSuperuser({ reason: `shop ${site.key}: ${reason}` }, (su) => fn(su, site)));
82
+ };
83
+ const tokenOf = (headers) => String(headers['x-cart-token'] ?? '');
84
+ const langOf = (query) => String(query?.['lang'] ?? 'en');
85
+ const cartOr404 = async (env, site, token) => {
86
+ const id = await orderOf(env, site, token);
87
+ if (id === null)
88
+ throw notFound('cart for this token (it may be checked out)');
89
+ return id;
90
+ };
91
+ app.get(`${base}/products`, pub, async (request) => {
92
+ const q = (request.query ?? {});
93
+ return inShop(request.params, 'catalogue', (env, site) => catalogue(inLang(env, langOf(q)), {
94
+ ...(typeof q['q'] === 'string' ? { q: q['q'] } : {}),
95
+ ...(positive(q['category']) === undefined ? {} : { category: positive(q['category']) }),
96
+ ...(decimal(q['min'], 'minimum') === undefined
97
+ ? {}
98
+ : { min: decimal(q['min'], 'minimum') }),
99
+ ...(decimal(q['max'], 'maximum') === undefined
100
+ ? {}
101
+ : { max: decimal(q['max'], 'maximum') }),
102
+ ...(typeof q['sort'] === 'string' ? { sort: q['sort'] } : {}),
103
+ ...(positive(q['page']) === undefined ? {} : { page: positive(q['page']) }),
104
+ }, site));
105
+ });
106
+ app.get(`${base}/products/:id`, pub, async (request) => {
107
+ const id = positive(request.params['id']);
108
+ if (id === undefined)
109
+ throw notFound('such product');
110
+ const page = await inShop(request.params, 'product', (env, site) => productPage(inLang(env, langOf(request.query)), id, site));
111
+ if (page === null)
112
+ throw notFound('such product on this shop');
113
+ return page;
114
+ });
115
+ app.get(`${base}/categories`, pub, async (request) => inShop(request.params, 'categories', async (env) => ({
116
+ categories: await categories(inLang(env, langOf(request.query))),
117
+ })));
118
+ app.post(`${base}/cart`, pub, async (request, reply) => {
119
+ const made = await inShop(request.params, 'new cart', (env, site) => newCart(env, site));
120
+ return reply.status(201).send({ token: made.token });
121
+ });
122
+ app.get(`${base}/cart`, pub, async (request) => inShop(request.params, 'cart', async (env, site) => cartView(env, await cartOr404(env, site, tokenOf(request.headers)))));
123
+ app.put(`${base}/cart/lines`, pub, async (request) => {
124
+ const body = (request.body ?? {});
125
+ const productId = positive(body['product']);
126
+ if (productId === undefined)
127
+ throw new HttpProblem(400, 'invalid-input', 'Invalid product', 'A product id.');
128
+ const quantity = decimal(body['quantity'], 'quantity') ?? orm.toDecimal(1);
129
+ return inShop(request.params, 'cart line', async (env, site) => {
130
+ const id = await cartOr404(env, site, tokenOf(request.headers));
131
+ await setLine(env, id, productId, quantity);
132
+ return cartView(env, id);
133
+ });
134
+ });
135
+ app.get(`${base}/carriers`, pub, async (request) => {
136
+ const city = String(request.query?.['city'] ?? '').slice(0, 80);
137
+ return inShop(request.params, 'delivery methods', async (env, site) => ({
138
+ carriers: await carriersFor(inLang(env, langOf(request.query)), await cartOr404(env, site, tokenOf(request.headers)), city === '' ? null : city),
139
+ }));
140
+ });
141
+ app.get(`${base}/payments`, pub, async (request) => inShop(request.params, 'payment providers', async (env, site) => ({
142
+ providers: [
143
+ ...(await (await env.model('payment.provider').search({
144
+ where: { company: site.company, state: { in: ['test', 'live'] } },
145
+ })).load({})),
146
+ ].map((p) => ({ id: p.id, name: p.name, test: p.state === 'test' })),
147
+ })));
148
+ app.post(`${base}/checkout`, { ...pub, bodyLimit: 16 * 1024 }, async (request, reply) => {
149
+ const input = checkoutInput(request.body);
150
+ const placed = await inShop(request.params, 'checkout', async (env, site) => checkout(env, site, await cartOr404(env, site, tokenOf(request.headers)), input));
151
+ return reply.status(201).send(placed);
152
+ });
153
+ app.put(`${base}/cart/coupon`, pub, async (request) => {
154
+ const code = String((request.body ?? {})['code'] ?? '');
155
+ return inShop(request.params, 'coupon', async (env, site) => {
156
+ const id = await cartOr404(env, site, tokenOf(request.headers));
157
+ await setCoupon(env, site, id, code);
158
+ return cartView(env, id);
159
+ });
160
+ });
161
+ app.put(`${base}/cart/contact`, pub, async (request) => {
162
+ const email = String((request.body ?? {})['email'] ?? '');
163
+ return inShop(request.params, 'cart email', async (env, site) => {
164
+ const id = await cartOr404(env, site, tokenOf(request.headers));
165
+ await setContact(env, id, email);
166
+ return { saved: true };
167
+ });
168
+ });
169
+ app.post(`${base}/cart/recover`, pub, async (request) => {
170
+ const code = String((request.body ?? {})['code'] ?? '');
171
+ const token = await inShop(request.params, 'cart recovery', (env, site) => recoverCart(env, site, code));
172
+ if (token === null)
173
+ throw notFound('cart for this code (it may be used or checked out)');
174
+ return { token };
175
+ });
176
+ app.get(`${base}/sitemap.xml`, pub, async (request, reply) => {
177
+ const xml = await inShop(request.params, 'sitemap', (env, site) => sitemap(env, site));
178
+ if (xml === null)
179
+ throw notFound('sitemap: the site has no domain');
180
+ return reply
181
+ .type('application/xml; charset=utf-8')
182
+ .header('cache-control', 'public, max-age=3600')
183
+ .send(xml);
184
+ });
185
+ app.get(`${base}/products/:id/image`, pub, async (request, reply) => {
186
+ const id = positive(request.params['id']);
187
+ const width = positive(request.query?.['w']);
188
+ if (id === undefined)
189
+ throw notFound('such product');
190
+ const image = await inShop(request.params, 'picture', (env) => productImage(env, id, width));
191
+ if (image === null)
192
+ throw notFound('picture of this product on the shop');
193
+ const body = await storageOf(app).read(image.key);
194
+ return reply
195
+ .header('content-type', image.mime)
196
+ .header('content-length', String(image.size))
197
+ .header('x-content-type-options', 'nosniff')
198
+ .header('content-security-policy', "default-src 'none'; sandbox")
199
+ .header('cache-control', 'public, max-age=3600')
200
+ .send(body);
201
+ });
202
+ app.get(`${base}/order`, pub, async (request) => inShop(request.params, 'order', async (env, site) => {
203
+ const id = await orderOf(env, site, tokenOf(request.headers), true);
204
+ if (id === null)
205
+ throw notFound('order for this token');
206
+ return { ...(await cartView(env, id)), shipments: await trackingOf(env, id) };
207
+ }));
208
+ }
209
+ /** The subscriber that makes the draft shipments of confirmed shop orders; tests `drain()` it, the server starts it. */
210
+ export function shipmentWorker(context) {
211
+ return context.shutro.subscribe('website_sale.shipments', 'sale.order.confirmed', async (event, env) => {
212
+ const id = Number((event.payload ?? {})['id']);
213
+ if (Number.isSafeInteger(id) && id > 0)
214
+ await env.asSuperuser({ reason: 'shop shipment' }, (su) => draftShipments(su, [id]));
215
+ }, { pollMs: 5000 });
216
+ }
217
+ /**
218
+ * Shipments: `POST /api/v1/shop/shipments/refresh` `{ shipments? }` asks the couriers now (Sales users); hourly on the
219
+ * server every open shipment is asked; the subscriber makes the drafts of confirmed orders.
220
+ */
221
+ function registerShipmentRoutes(context) {
222
+ const { app } = context;
223
+ // The reminders of abandoned carts, now (Sales managers; hourly on the server).
224
+ app.post('/api/v1/shop/carts/remind', async (request) => request.env(async (raw) => {
225
+ const env = raw;
226
+ if (!env.administrator && !env.groups.has('sales.manager'))
227
+ throw new HttpProblem(403, 'access', 'Sales managers', 'This needs the Sales manager role.');
228
+ return {
229
+ reminded: await env.asSuperuser({ reason: 'abandoned carts' }, (su) => remindAbandoned(su)),
230
+ };
231
+ }, { write: true }));
232
+ app.post('/api/v1/shop/shipments/refresh', async (request) => {
233
+ const given = (request.body ?? {})['shipments'];
234
+ const ids = Array.isArray(given) ? given.map(Number).filter(Number.isSafeInteger) : undefined;
235
+ return request.env(async (raw) => {
236
+ const env = raw;
237
+ if (!env.administrator && !env.groups.has('sales.user'))
238
+ throw new HttpProblem(403, 'access', 'Sales users', 'This needs the Sales user role.');
239
+ const visible = (await env
240
+ .model('delivery.shipment')
241
+ .search(ids === undefined ? {} : { where: { id: { in: ids } } })).ids;
242
+ return {
243
+ moved: await env.asSuperuser({ reason: 'shipment tracking' }, (su) => refreshShipments(su, visible)),
244
+ };
245
+ }, { write: true });
246
+ });
247
+ if (process.env['KOSH_SCHEDULES'] === 'off')
248
+ return;
249
+ const worker = shipmentWorker(context);
250
+ worker.start();
251
+ const run = async () => {
252
+ try {
253
+ const companies = await context.shutro.bootstrap({ reason: 'shipment tracking' }, async (env) => (await env.model('res.company').search({})).ids);
254
+ for (const company of companies)
255
+ await context.shutro.bootstrap({ reason: 'shipment tracking', company }, (env) => env.asSuperuser({ reason: 'shipment tracking' }, async (su) => {
256
+ await refreshShipments(su);
257
+ await remindAbandoned(su);
258
+ }));
259
+ }
260
+ catch (error) {
261
+ app.log.error({ err: error }, 'shipment tracking');
262
+ }
263
+ };
264
+ const timer = setInterval(() => void run(), 3_600_000);
265
+ timer.unref();
266
+ app.addHook('onClose', async () => {
267
+ clearInterval(timer);
268
+ await worker.stop();
269
+ });
270
+ }
271
+ /** The Shop with explicit options (tests, installations wiring their couriers). */
272
+ export function websiteSaleModule(options = {}) {
273
+ setCouriers(options.couriers ?? new Map([['fake', testCourier]]));
274
+ setShopMailer('mailer' in options ? options.mailer : mailerFromEnv());
275
+ return defineModule({
276
+ shutro: websiteSaleShutro,
277
+ kosh: '^0.1.0',
278
+ hooks: { demo: shopDemo },
279
+ depends: [website, sales, saleAccount, payment, product],
280
+ accessLevels: {
281
+ manager: { label: 'Shop manager', groups: ['website_sale.manager'] },
282
+ },
283
+ routes: (context) => {
284
+ registerShopRoutes(context);
285
+ registerShipmentRoutes(context);
286
+ },
287
+ actions: {
288
+ 'shop.action_orders': action('sale.order', {
289
+ label: 'Shop orders',
290
+ views: ['list', 'form'],
291
+ domain: { website: { isNull: false }, placedAt: { isNull: false } },
292
+ }),
293
+ 'shop.action_shipments': action(DeliveryShipment, {
294
+ label: 'Shipments',
295
+ views: ['list', 'form'],
296
+ defaultFilters: ['open'],
297
+ }),
298
+ 'shop.action_coupons': action(ShopCoupon, { label: 'Coupons', views: ['list', 'form'] }),
299
+ 'shop.action_carriers': action(DeliveryCarrier, {
300
+ label: 'Delivery methods',
301
+ views: ['list', 'form'],
302
+ }),
303
+ 'shop.action_products': action('product.product', {
304
+ label: 'Shop products',
305
+ views: ['list', 'form'],
306
+ domain: { published: true },
307
+ }),
308
+ },
309
+ menus: [
310
+ {
311
+ id: 'sites.shop_orders',
312
+ parent: 'sites.root',
313
+ label: 'Shop orders',
314
+ action: 'shop.action_orders',
315
+ sequence: 0.5,
316
+ },
317
+ {
318
+ id: 'sites.shop_products',
319
+ parent: 'sites.root',
320
+ label: 'Shop products',
321
+ action: 'shop.action_products',
322
+ sequence: 0.6,
323
+ },
324
+ {
325
+ id: 'sites.shipments',
326
+ parent: 'sites.root',
327
+ label: 'Shipments',
328
+ action: 'shop.action_shipments',
329
+ sequence: 0.55,
330
+ },
331
+ {
332
+ id: 'sites.coupons',
333
+ parent: 'sites.root',
334
+ label: 'Coupons',
335
+ action: 'shop.action_coupons',
336
+ sequence: 0.7,
337
+ },
338
+ {
339
+ id: 'sites.carriers',
340
+ parent: 'sites.root',
341
+ label: 'Delivery methods',
342
+ action: 'shop.action_carriers',
343
+ sequence: 5,
344
+ },
345
+ ],
346
+ views: {
347
+ 'shop.coupon.list': list(ShopCoupon, {
348
+ columns: ['code', 'name', 'kind', 'value', 'minimum', 'validTo', 'uses', 'maxUses'],
349
+ }),
350
+ 'shop.coupon.form': form(ShopCoupon, (k) => ({
351
+ sheet: [
352
+ k.group('main', ['code', 'name', 'kind', 'value', 'minimum'], {
353
+ description: 'A percentage off the goods, an amount off, or free delivery — from a minimum, typed at checkout.',
354
+ }),
355
+ k.group('limits', ['validFrom', 'validTo', 'maxUses', 'uses', 'oncePerCustomer']),
356
+ ],
357
+ chatter: true,
358
+ })),
359
+ 'delivery.shipment.list': list(DeliveryShipment, {
360
+ columns: [
361
+ 'name',
362
+ 'order',
363
+ 'recipient',
364
+ 'city',
365
+ 'courier',
366
+ 'trackingRef',
367
+ 'cod',
368
+ 'codCollected',
369
+ { field: 'state', widget: 'badge' },
370
+ ],
371
+ decorations: { success: { state: 'delivered' }, danger: { state: 'returned' } },
372
+ }),
373
+ 'delivery.shipment.form': form(DeliveryShipment, (k) => ({
374
+ header: {
375
+ statusbar: 'state',
376
+ buttons: [
377
+ k.button('book', { primary: true, label: 'Book the courier' }),
378
+ k.button('cancel', {
379
+ label: 'Cancel',
380
+ confirm: 'Cancel this shipment with the courier?',
381
+ }),
382
+ ],
383
+ },
384
+ sheet: [
385
+ k.group('parcel', ['order', 'carrier', 'courier', 'trackingRef', 'labelUrl'], {
386
+ description: 'Booked with the courier, then moved along by what it says; the cash to collect is collected on delivery.',
387
+ }),
388
+ k.group('deliver_to', ['recipient', 'phone', 'address', 'city'], { label: 'Deliver to' }),
389
+ k.group('cash_to_collect', ['cod', 'codCollected', 'codCollectedAt', 'weight']),
390
+ k.lines('events', [
391
+ { field: 'at', id: 'event_at' },
392
+ { field: 'status', id: 'event_status' },
393
+ { field: 'note', id: 'event_note' },
394
+ ]),
395
+ k.group('about', ['note'], { columns: 1 }),
396
+ ],
397
+ chatter: true,
398
+ })),
399
+ 'delivery.carrier.list': list(DeliveryCarrier, {
400
+ columns: [
401
+ 'name',
402
+ 'kind',
403
+ 'price',
404
+ 'priceInside',
405
+ 'priceOutside',
406
+ 'freeOver',
407
+ 'cod',
408
+ 'courier',
409
+ ],
410
+ }),
411
+ 'delivery.carrier.form': form(DeliveryCarrier, (k) => ({
412
+ sheet: [
413
+ k.group('main', ['name', 'kind', 'courier', 'cod', 'sequence'], {
414
+ description: 'A fixed fee; by weight, the first kg and each one after it; by zone, a fee inside the listed cities and one outside.',
415
+ }),
416
+ k.group('fees', [
417
+ 'price',
418
+ 'pricePerKg',
419
+ 'zoneCities',
420
+ 'priceInside',
421
+ 'priceOutside',
422
+ 'freeOver',
423
+ ]),
424
+ k.group('about', ['description', 'product'], { columns: 1 }),
425
+ ],
426
+ chatter: true,
427
+ })),
428
+ },
429
+ viewExtensions: [
430
+ {
431
+ view: 'product.product.form',
432
+ operations: [
433
+ {
434
+ insertAfter: 'prices',
435
+ nodes: [
436
+ {
437
+ kind: 'group',
438
+ id: 'shop',
439
+ label: 'Shop',
440
+ children: [
441
+ field({ field: 'published', id: 'shop_published' }),
442
+ field({ field: 'shopSequence', id: 'shop_sequence' }),
443
+ field({ field: 'weight', id: 'shop_weight' }),
444
+ field({ field: 'related', id: 'shop_related', widget: 'tags' }),
445
+ field({ field: 'websiteDescription', id: 'shop_description' }),
446
+ field({ field: 'seoTitle', id: 'shop_seo_title' }),
447
+ field({ field: 'seoDescription', id: 'shop_seo_description' }),
448
+ ],
449
+ },
450
+ ],
451
+ },
452
+ ],
453
+ },
454
+ {
455
+ view: 'website.site.form',
456
+ operations: [
457
+ {
458
+ append: 'main',
459
+ nodes: [
460
+ field({ field: 'shop', id: 'site_shop' }),
461
+ field({ field: 'codLimit', id: 'site_cod_limit' }),
462
+ field({ field: 'fewLeft', id: 'site_few_left' }),
463
+ field({ field: 'allowBackorders', id: 'site_backorders' }),
464
+ field({ field: 'abandonedHours', id: 'site_abandoned_hours' }),
465
+ field({ field: 'salesperson', id: 'site_salesperson' }),
466
+ ],
467
+ },
468
+ ],
469
+ },
470
+ {
471
+ view: 'sale.order.form',
472
+ operations: [
473
+ {
474
+ append: 'related',
475
+ nodes: [
476
+ stat({
477
+ id: 'order_shipments',
478
+ label: 'Shipments',
479
+ model: 'delivery.shipment',
480
+ where: { order: { $record: 'id' } },
481
+ action: 'shop.action_shipments',
482
+ }),
483
+ stat({
484
+ id: 'order_online_payments',
485
+ label: 'Online payments',
486
+ model: 'payment.transaction',
487
+ where: { saleOrder: { $record: 'id' } },
488
+ action: 'payment.action_transactions',
489
+ }),
490
+ ],
491
+ },
492
+ ],
493
+ },
494
+ {
495
+ view: 'sale.order.form',
496
+ operations: [
497
+ {
498
+ insertAfter: 'partner',
499
+ nodes: [
500
+ field({ field: 'website', id: 'order_site' }),
501
+ field({ field: 'carrier', id: 'order_carrier' }),
502
+ field({ field: 'shopPayment', id: 'order_shop_payment' }),
503
+ field({ field: 'placedAt', id: 'order_placed_at' }),
504
+ field({ field: 'shopNote', id: 'order_shop_note' }),
505
+ field({ field: 'coupon', id: 'order_coupon' }),
506
+ field({ field: 'contactEmail', id: 'order_contact_email' }),
507
+ field({ field: 'remindedAt', id: 'order_reminded_at' }),
508
+ ],
509
+ },
510
+ ],
511
+ },
512
+ ],
513
+ search: {
514
+ 'shop.coupon': search(ShopCoupon, {
515
+ fields: ['code', 'name'],
516
+ groupBy: ['kind'],
517
+ }),
518
+ 'delivery.shipment': search(DeliveryShipment, {
519
+ fields: ['name', 'trackingRef', 'recipient', 'phone', 'order.name'],
520
+ filters: {
521
+ open: {
522
+ label: 'On the way',
523
+ domain: { state: { in: ['draft', 'booked', 'picked', 'in_transit'] } },
524
+ group: 'state',
525
+ },
526
+ cash: { label: 'Cash collected', domain: { codCollected: true } },
527
+ },
528
+ groupBy: ['state', 'courier', 'carrier'],
529
+ }),
530
+ 'delivery.carrier': search(DeliveryCarrier, {
531
+ fields: ['name'],
532
+ groupBy: ['kind', 'courier'],
533
+ }),
534
+ },
535
+ });
536
+ }
537
+ /** The Shop (the test courier; Pathao, Steadfast and RedX adapters come with their sandbox credentials). */
538
+ export const websiteSale = websiteSaleModule();