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,412 @@
1
+ /**
2
+ * The data layer of Attendance (RFC 0024 §2.2): shifts (hours, break, grace, overtime after so many minutes and in
3
+ * steps, the overtime rate; night shifts end after midnight), rosters that assign them, sites with a geofence,
4
+ * punches (`attendance.record`) from the phone, the kiosk or a device file, public holidays, and the **attendance
5
+ * day** of each person — worked hours, late arrival, early leave, absence, leave and holidays from Workforce,
6
+ * overtime — computed by `days.ts` and approved by HR before Payroll reads it.
7
+ *
8
+ * People see their own punches and days; Attendance managers everyone's. A kiosk device signs in with the kiosk
9
+ * group and identifies people by badge or PIN; it reads nothing else.
10
+ */
11
+ import { hrShutro } from '../hr/index.js';
12
+ import { orm } from '../server/orm.js';
13
+ import { check, compute, defineModel, defineModule, extendModel, f, record, records, } from './.kosh/bindings.js';
14
+ const READ = ['read'];
15
+ const ALL = ['read', 'write', 'create', 'unlink'];
16
+ const MANAGERS = ['attendance.manager'];
17
+ const me = { $env: 'uid' };
18
+ const HHMM = orm.sql `~ '^([01][0-9]|2[0-3]):[0-5][0-9]$'`;
19
+ export const AttendanceShift = defineModel('attendance.shift', {
20
+ label: 'Shift',
21
+ recName: 'name',
22
+ order: ['start asc', 'name asc'],
23
+ archivable: true,
24
+ // Shared by every company (seed data is installed before any company exists).
25
+ access: { 'attendance.user': READ, 'attendance.manager': [...ALL, 'export', 'import'] },
26
+ fields: {
27
+ name: f.char({ required: true, translate: true }),
28
+ start: f.char({ size: 5, required: true, default: '09:00', label: 'Starts (HH:MM)' }),
29
+ end: f.char({
30
+ size: 5,
31
+ required: true,
32
+ default: '18:00',
33
+ label: 'Ends (HH:MM)',
34
+ help: 'Earlier than the start: the shift ends the next day (a night shift).',
35
+ }),
36
+ breakMinutes: f.integer({ required: true, default: 60, label: 'Break (minutes)' }),
37
+ graceMinutes: f.integer({
38
+ required: true,
39
+ default: 10,
40
+ label: 'Grace (minutes)',
41
+ help: 'Arrivals within these minutes after the start are not late.',
42
+ }),
43
+ overtimeAfter: f.integer({
44
+ required: true,
45
+ default: 30,
46
+ label: 'Overtime after (minutes)',
47
+ help: 'Work beyond the shift counts as overtime once it passes these minutes.',
48
+ }),
49
+ overtimeStep: f.integer({
50
+ required: true,
51
+ default: 30,
52
+ label: 'Overtime in steps of (minutes)',
53
+ help: 'Overtime is counted down to whole steps (30: half hours).',
54
+ }),
55
+ overtimeRate: f.decimal({
56
+ scale: 2,
57
+ required: true,
58
+ default: '2',
59
+ label: 'Overtime rate',
60
+ help: 'Times the hourly basic (Bangladesh Labour Act: twice), for Payroll.',
61
+ }),
62
+ },
63
+ sqlConstraints: {
64
+ times: {
65
+ check: orm.sql `start ${HHMM} AND "end" ${HHMM}`,
66
+ message: 'Times are written HH:MM, from 00:00 to 23:59.',
67
+ },
68
+ minutes: {
69
+ check: orm.sql `break_minutes >= 0 AND grace_minutes >= 0 AND overtime_after >= 0 AND overtime_step > 0`,
70
+ message: 'Minutes are not negative; the overtime step is at least one minute.',
71
+ },
72
+ },
73
+ });
74
+ export const AttendanceRoster = defineModel('attendance.roster', {
75
+ label: 'Roster',
76
+ order: ['dateFrom desc', 'id desc'],
77
+ companyScoped: { required: true },
78
+ tracking: ['shift', 'dateFrom', 'dateTo'],
79
+ access: { 'attendance.user': READ, 'attendance.manager': [...ALL, 'export', 'import'] },
80
+ rules: {
81
+ own: { groups: ['attendance.user'], perms: ['read'], domain: { 'employee.user': me } },
82
+ all: { groups: ['attendance.manager'], perms: [...ALL], domain: {} },
83
+ },
84
+ fields: {
85
+ employee: f.many2one('hr.employee', { required: true, ondelete: 'cascade' }),
86
+ shift: f.many2one('attendance.shift', { required: true, ondelete: 'restrict' }),
87
+ dateFrom: f.date({ required: true, label: 'From' }),
88
+ dateTo: f.date({ required: true, label: 'To' }),
89
+ note: f.char(),
90
+ },
91
+ sqlConstraints: {
92
+ ordered: {
93
+ check: orm.sql `date_to >= date_from`,
94
+ message: 'A roster ends on or after it starts.',
95
+ },
96
+ },
97
+ constraints: {
98
+ // One shift a day: rosters of a person do not overlap.
99
+ noOverlap: {
100
+ ...check('attendance.roster', ['employee', 'dateFrom', 'dateTo'], async (rosters) => rosters.env.asSuperuser({ reason: 'overlapping rosters' }, async (su) => {
101
+ const failing = [];
102
+ for (const r of rosters) {
103
+ const clash = await su.model('attendance.roster').search({
104
+ where: {
105
+ employee: r.employee.id,
106
+ id: { ne: r.id },
107
+ dateFrom: { lte: r.dateTo },
108
+ dateTo: { gte: r.dateFrom },
109
+ },
110
+ limit: 1,
111
+ });
112
+ if (clash.length > 0)
113
+ failing.push(r.id);
114
+ }
115
+ return failing;
116
+ })),
117
+ message: 'This person is already on another roster for some of these days.',
118
+ },
119
+ },
120
+ });
121
+ export const AttendanceSite = defineModel('attendance.site', {
122
+ label: 'Site',
123
+ recName: 'name',
124
+ order: ['name asc'],
125
+ archivable: true,
126
+ companyScoped: { required: true },
127
+ access: {
128
+ 'attendance.user': READ,
129
+ 'attendance.kiosk': READ,
130
+ 'attendance.manager': [...ALL, 'export', 'import'],
131
+ },
132
+ fields: {
133
+ name: f.char({ required: true }),
134
+ latitude: f.decimal({ scale: 6 }),
135
+ longitude: f.decimal({ scale: 6 }),
136
+ radius: f.integer({
137
+ required: true,
138
+ default: 150,
139
+ label: 'Radius (metres)',
140
+ help: 'Check-ins from a phone count at this site within this distance.',
141
+ }),
142
+ geofence: f.boolean({
143
+ default: true,
144
+ label: 'Phones check in on site only',
145
+ help: 'Refuse phone check-ins outside the radius (the location is kept only as inside or outside and the distance).',
146
+ }),
147
+ },
148
+ sqlConstraints: {
149
+ position: {
150
+ check: orm.sql `(latitude IS NULL) = (longitude IS NULL) AND radius > 0`,
151
+ message: 'A site has both coordinates or neither, and a positive radius.',
152
+ },
153
+ },
154
+ });
155
+ export const AttendanceRecord = defineModel('attendance.record', {
156
+ label: 'Attendance',
157
+ order: ['checkIn desc', 'id desc'],
158
+ companyScoped: { required: true },
159
+ tracking: ['checkIn', 'checkOut'],
160
+ access: {
161
+ 'attendance.user': READ,
162
+ 'attendance.manager': [...ALL, 'export', 'import'],
163
+ },
164
+ rules: {
165
+ own: { groups: ['attendance.user'], perms: ['read'], domain: { 'employee.user': me } },
166
+ all: { groups: ['attendance.manager'], perms: [...ALL], domain: {} },
167
+ },
168
+ fields: {
169
+ employee: f.many2one('hr.employee', { required: true, ondelete: 'cascade' }),
170
+ checkIn: f.datetime({ required: true, label: 'Check-in' }),
171
+ checkOut: f.datetime({ label: 'Check-out' }),
172
+ source: f.selection({ phone: 'Phone', kiosk: 'Kiosk', device: 'Device file', manual: 'By hand' }, {
173
+ required: true,
174
+ default: 'manual',
175
+ help: 'Where the punch came from; a punch by hand is recorded with who made it.',
176
+ }),
177
+ site: f.many2one('attendance.site', { ondelete: 'set null' }),
178
+ inside: f.boolean({
179
+ default: true,
180
+ label: 'On site',
181
+ help: 'Off only for a phone check-in outside the radius of a site without a geofence.',
182
+ }),
183
+ distance: f.integer({ label: 'Distance (metres)', help: 'Phone check-ins: from the site.' }),
184
+ workedHours: f.decimal({
185
+ scale: 2,
186
+ label: 'Hours',
187
+ help: 'From the check-in to the check-out.',
188
+ ...compute('attendance.record', 'workedHours', ['checkIn', 'checkOut'], (punches) => {
189
+ for (const p of punches)
190
+ p.workedHours =
191
+ p.checkOut === null
192
+ ? null
193
+ : orm
194
+ .toDecimal(p.checkOut.getTime() - p.checkIn.getTime())
195
+ .div(3_600_000)
196
+ .toDecimalPlaces(2);
197
+ }),
198
+ store: true,
199
+ }),
200
+ note: f.char(),
201
+ },
202
+ sqlConstraints: {
203
+ ordered: {
204
+ check: orm.sql `check_out IS NULL OR check_out > check_in`,
205
+ message: 'A check-out comes after its check-in.',
206
+ },
207
+ oneOpen: {
208
+ unique: ['employee'],
209
+ where: orm.sql `check_out IS NULL`,
210
+ message: 'This person is already checked in.',
211
+ },
212
+ },
213
+ constraints: {
214
+ noOverlap: {
215
+ ...check('attendance.record', ['employee', 'checkIn', 'checkOut'], async (punches) => punches.env.asSuperuser({ reason: 'overlapping punches' }, async (su) => {
216
+ const failing = [];
217
+ for (const p of punches) {
218
+ const end = p.checkOut ?? new Date(p.checkIn.getTime() + 1);
219
+ const clash = await su.model('attendance.record').search({
220
+ where: {
221
+ employee: p.employee.id,
222
+ id: { ne: p.id },
223
+ checkIn: { lt: end },
224
+ checkOut: { gt: p.checkIn },
225
+ },
226
+ limit: 1,
227
+ });
228
+ if (clash.length > 0)
229
+ failing.push(p.id);
230
+ }
231
+ return failing;
232
+ })),
233
+ message: 'This overlaps another check-in of the same person.',
234
+ },
235
+ },
236
+ });
237
+ export const AttendanceHoliday = defineModel('attendance.holiday', {
238
+ label: 'Public holiday',
239
+ recName: 'name',
240
+ order: ['date asc'],
241
+ companyScoped: { required: true },
242
+ access: { 'attendance.user': READ, 'attendance.manager': [...ALL, 'export', 'import'] },
243
+ fields: {
244
+ name: f.char({ required: true, translate: true }),
245
+ date: f.date({ required: true }),
246
+ },
247
+ sqlConstraints: {
248
+ oneADay: { unique: ['company', 'date'], message: 'There is already a holiday on this date.' },
249
+ },
250
+ });
251
+ const DAY_STATUS = {
252
+ present: 'Present',
253
+ absent: 'Absent',
254
+ leave: 'On leave',
255
+ holiday: 'Holiday',
256
+ weekend: 'Weekend',
257
+ incomplete: 'Check-out missing',
258
+ off: 'No shift',
259
+ };
260
+ export const AttendanceDay = defineModel('attendance.day', {
261
+ label: 'Attendance day',
262
+ order: ['date desc', 'employee asc'],
263
+ companyScoped: { required: true },
264
+ tracking: ['state', 'overtimeApproved'],
265
+ access: {
266
+ 'attendance.user': READ,
267
+ 'attendance.manager': [...ALL, 'export'],
268
+ },
269
+ rules: {
270
+ own: { groups: ['attendance.user'], perms: ['read'], domain: { 'employee.user': me } },
271
+ all: { groups: ['attendance.manager'], perms: [...ALL], domain: {} },
272
+ },
273
+ fields: {
274
+ employee: f.many2one('hr.employee', { required: true, ondelete: 'cascade' }),
275
+ date: f.date({ required: true }),
276
+ shift: f.many2one('attendance.shift', { ondelete: 'set null' }),
277
+ status: f.selection(DAY_STATUS, {
278
+ required: true,
279
+ default: 'present',
280
+ help: 'From the punches, the roster, the weekend, public holidays and approved leave.',
281
+ }),
282
+ firstIn: f.datetime({ label: 'First in' }),
283
+ lastOut: f.datetime({ label: 'Last out' }),
284
+ workedHours: f.decimal({ scale: 2, required: true, default: '0', label: 'Worked (hours)' }),
285
+ expectedHours: f.decimal({ scale: 2, required: true, default: '0', label: 'Expected (hours)' }),
286
+ lateMinutes: f.integer({ required: true, default: 0, label: 'Late (minutes)' }),
287
+ earlyMinutes: f.integer({ required: true, default: 0, label: 'Left early (minutes)' }),
288
+ overtimeHours: f.decimal({
289
+ scale: 2,
290
+ required: true,
291
+ default: '0',
292
+ label: 'Overtime (hours)',
293
+ help: 'Beyond the shift past its threshold, in its steps; all hours worked on weekends and holidays.',
294
+ }),
295
+ overtimeApproved: f.decimal({
296
+ scale: 2,
297
+ required: true,
298
+ default: '0',
299
+ label: 'Overtime approved (hours)',
300
+ help: 'What Payroll pays; set to the overtime on approval, lowered by the approver when needed.',
301
+ }),
302
+ overtimeRate: f.decimal({ scale: 2, required: true, default: '2', label: 'Overtime rate' }),
303
+ state: f.state({
304
+ states: { draft: 'To review', approved: 'Approved' },
305
+ initial: 'draft',
306
+ help: 'Approved days are locked and read by Payroll; recomputing leaves them as they are.',
307
+ transitions: {
308
+ approve: {
309
+ from: ['draft'],
310
+ to: 'approved',
311
+ requires: 'attendance.approve',
312
+ guard: records('attendance.day', (days) => notOwn(days)),
313
+ message: 'Someone else approves your attendance.',
314
+ after: records('attendance.day', async (days) => {
315
+ for (const id of days.ids)
316
+ await days.env.emit('attendance.day.approved', { id });
317
+ }),
318
+ },
319
+ reopen: { from: ['approved'], to: 'draft', requires: 'attendance.approve' },
320
+ },
321
+ }),
322
+ },
323
+ sqlConstraints: {
324
+ oneADay: { unique: ['employee', 'date'], message: 'One attendance day per person and date.' },
325
+ approvedWithin: {
326
+ check: orm.sql `overtime_approved >= 0 AND overtime_approved <= overtime_hours`,
327
+ message: 'Approved overtime is between none and the overtime worked.',
328
+ },
329
+ },
330
+ });
331
+ /** The days among `records` of the acting user's own employee. */
332
+ async function notOwn(records) {
333
+ const { env, ids } = records;
334
+ return env.asSuperuser({ reason: 'own attendance' }, async (su) => {
335
+ const days = (await su
336
+ .model('attendance.day')
337
+ .browse([...ids])
338
+ .load(['employee'])).read(['id', 'employee']);
339
+ const people = new Map((await su
340
+ .model('hr.employee')
341
+ .browse(days.map((d) => d['employee']))
342
+ .load(['user']))
343
+ .read(['id', 'user'])
344
+ .map((e) => [e['id'], e['user']]));
345
+ return days.filter((d) => people.get(d['employee']) === env.uid).map((d) => d['id']);
346
+ });
347
+ }
348
+ /** Each employee's attendance details: the default shift, the kiosk PIN (hashed), the badge and the device user. */
349
+ export const EmployeeAttendance = extendModel('hr.employee', {
350
+ fields: {
351
+ attendanceShift: f.many2one('attendance.shift', {
352
+ ondelete: 'set null',
353
+ label: 'Usual shift',
354
+ help: 'The shift on days without a roster.',
355
+ }),
356
+ attendancePin: f.char({
357
+ size: 200,
358
+ label: 'Kiosk PIN (hashed)',
359
+ groups: { read: MANAGERS, write: MANAGERS },
360
+ }),
361
+ attendanceBadge: f.char({
362
+ size: 64,
363
+ label: 'Badge',
364
+ help: 'The code on the person’s badge (QR or barcode), scanned at the kiosk.',
365
+ groups: { read: MANAGERS, write: MANAGERS },
366
+ }),
367
+ deviceUserId: f.char({
368
+ size: 32,
369
+ label: 'Device user ID',
370
+ help: 'The person’s number on the attendance device (ZKTeco user ID).',
371
+ groups: { read: MANAGERS, write: MANAGERS },
372
+ }),
373
+ },
374
+ });
375
+ export const attendanceShutro = defineModule({
376
+ name: 'attendance',
377
+ version: '0.1.0',
378
+ depends: [hrShutro],
379
+ groups: [
380
+ orm.defineGroup({ code: 'attendance.user', label: 'Attendance: own', implies: ['hr.user'] }),
381
+ orm.defineGroup({
382
+ code: 'attendance.manager',
383
+ label: 'Attendance manager',
384
+ implies: ['attendance.user'],
385
+ }),
386
+ orm.defineGroup({
387
+ code: 'attendance.kiosk',
388
+ label: 'Attendance kiosk (a device at the gate)',
389
+ implies: [],
390
+ }),
391
+ ],
392
+ permissions: [
393
+ orm.definePermission({
394
+ code: 'attendance.approve',
395
+ label: 'Approve attendance days and overtime',
396
+ groups: ['attendance.manager'],
397
+ }),
398
+ ],
399
+ models: [
400
+ AttendanceShift,
401
+ AttendanceRoster,
402
+ AttendanceSite,
403
+ AttendanceRecord,
404
+ AttendanceHoliday,
405
+ AttendanceDay,
406
+ ],
407
+ extensions: [EmployeeAttendance],
408
+ data: [
409
+ record('attendance.shift', 'shift_general', { name: 'General', start: '09:00', end: '18:00', breakMinutes: 60 }, { noupdate: true }),
410
+ record('attendance.shift', 'shift_night', { name: 'Night', start: '22:00', end: '06:00', breakMinutes: 30 }, { noupdate: true }),
411
+ ],
412
+ });
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Attendance's routes (RFC 0024 §2.2):
3
+ *
4
+ * - `GET /api/v1/attendance/me` the user's employee, whether checked in and since when, today's day
5
+ * - `POST /api/v1/attendance/punch` `{ latitude?, longitude? }`: the user checks in or out from the
6
+ * phone — inside a site's radius where its geofence is on
7
+ * - `GET /api/v1/attendance/kiosk/people` kiosks: the people who check in there (names only)
8
+ * - `POST /api/v1/attendance/kiosk/punch` kiosks: `{ badge }` or `{ employee, pin }`; five wrong PINs lock
9
+ * the person at the kiosks for 15 minutes
10
+ * - `POST /api/v1/attendance/employees/:id/pin` managers: `{ pin }` (4 to 8 digits), stored hashed
11
+ * - `POST /api/v1/attendance/import` managers: `{ format: 'zkteco' | 'csv', content }`
12
+ * - `POST /api/v1/attendance/days/compute` managers: `{ from, to, employees? }`
13
+ * - `GET /api/v1/attendance/formats` the device file formats
14
+ */
15
+ import { type ModuleContext } from '../server/index.js';
16
+ export declare function registerAttendanceRoutes({ app }: ModuleContext): void;