shutro-erp 0.3.5 → 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/account_asset/.kosh/bindings.js +15 -0
- package/dist/{mrp_account → account_asset}/.kosh/schema.d.ts +785 -614
- package/dist/account_asset/board.d.ts +61 -0
- package/dist/account_asset/board.js +86 -0
- package/dist/account_asset/books.d.ts +42 -0
- package/dist/account_asset/books.js +398 -0
- package/dist/account_asset/demo.d.ts +7 -0
- package/dist/account_asset/demo.js +72 -0
- package/dist/account_asset/i18n/bn.d.ts +2 -0
- package/dist/account_asset/i18n/bn.js +97 -0
- package/dist/account_asset/index.d.ts +9 -0
- package/dist/account_asset/index.js +337 -0
- package/dist/account_asset/module.d.ts +11076 -0
- package/dist/account_asset/module.js +230 -0
- package/dist/account_budget/.kosh/bindings.js +15 -0
- package/dist/account_budget/.kosh/schema.d.ts +2841 -0
- package/dist/account_budget/budget.d.ts +5 -0
- package/dist/account_budget/budget.js +142 -0
- package/dist/account_budget/demo.d.ts +6 -0
- package/dist/account_budget/demo.js +30 -0
- package/dist/account_budget/i18n/bn.d.ts +2 -0
- package/dist/account_budget/i18n/bn.js +63 -0
- package/dist/account_budget/index.d.ts +4 -0
- package/dist/account_budget/index.js +237 -0
- package/dist/account_budget/module.d.ts +27289 -0
- package/dist/account_budget/module.js +182 -0
- package/dist/account_portal/.kosh/bindings.js +1 -1
- package/dist/account_portal/.kosh/schema.d.ts +651 -10
- package/dist/account_portal/i18n/bn.d.ts +2 -0
- package/dist/account_portal/i18n/bn.js +6 -0
- package/dist/account_portal/index.js +2 -0
- package/dist/account_portal/module.d.ts +5212 -1592
- package/dist/accounting/.kosh/bindings.js +1 -1
- package/dist/accounting/.kosh/schema.d.ts +651 -10
- package/dist/accounting/closing.js +1 -0
- package/dist/accounting/fiscal.d.ts +578 -0
- package/dist/accounting/fiscal.js +401 -0
- package/dist/accounting/followups.d.ts +618 -0
- package/dist/accounting/followups.js +420 -0
- package/dist/accounting/i18n/bn.d.ts +2 -0
- package/dist/accounting/i18n/bn.js +425 -0
- package/dist/accounting/index.d.ts +3 -1
- package/dist/accounting/index.js +780 -5
- package/dist/accounting/module.d.ts +5386 -1543
- package/dist/accounting/module.js +155 -18
- package/dist/accounting/statements.d.ts +878 -0
- package/dist/accounting/statements.js +728 -0
- package/dist/accounting/web/BankReconcilePage.d.ts +9 -0
- package/dist/accounting/web/BankReconcilePage.js +138 -0
- package/dist/accounting/web/FollowupsPage.d.ts +8 -0
- package/dist/accounting/web/FollowupsPage.js +54 -0
- package/dist/accounting/web/PostingPreview.d.ts +8 -0
- package/dist/accounting/web/PostingPreview.js +26 -0
- package/dist/accounting/web/index.d.ts +3 -0
- package/dist/accounting/web/index.js +9 -0
- package/dist/accounting/web/messages.js +140 -0
- package/dist/approvals/.kosh/bindings.d.ts +22 -0
- package/dist/approvals/.kosh/bindings.js +15 -0
- package/dist/approvals/.kosh/schema.d.ts +879 -0
- package/dist/approvals/demo.d.ts +7 -0
- package/dist/approvals/demo.js +41 -0
- package/dist/approvals/i18n/bn.d.ts +2 -0
- package/dist/approvals/i18n/bn.js +133 -0
- package/dist/approvals/index.d.ts +36 -0
- package/dist/approvals/index.js +772 -0
- package/dist/approvals/mails.d.ts +30 -0
- package/dist/approvals/mails.js +87 -0
- package/dist/approvals/module.d.ts +2930 -0
- package/dist/approvals/module.js +473 -0
- package/dist/approvals/web/Config.d.ts +12 -0
- package/dist/approvals/web/Config.js +60 -0
- package/dist/approvals/web/History.d.ts +4 -0
- package/dist/approvals/web/History.js +13 -0
- package/dist/approvals/web/Inbox.d.ts +9 -0
- package/dist/approvals/web/Inbox.js +114 -0
- package/dist/approvals/web/Matrix.d.ts +9 -0
- package/dist/approvals/web/Matrix.js +26 -0
- package/dist/approvals/web/Mine.d.ts +7 -0
- package/dist/approvals/web/Mine.js +27 -0
- package/dist/approvals/web/index.d.ts +15 -0
- package/dist/approvals/web/index.js +29 -0
- package/dist/approvals/web/messages.d.ts +2 -0
- package/dist/approvals/web/messages.js +211 -0
- package/dist/approvals/web/shared.d.ts +59 -0
- package/dist/approvals/web/shared.js +46 -0
- package/dist/approvals_purchase/.kosh/bindings.d.ts +22 -0
- package/dist/approvals_purchase/.kosh/bindings.js +15 -0
- package/dist/approvals_purchase/.kosh/schema.d.ts +1997 -0
- package/dist/approvals_purchase/i18n/bn.d.ts +2 -0
- package/dist/approvals_purchase/i18n/bn.js +5 -0
- package/dist/approvals_purchase/index.d.ts +3 -0
- package/dist/approvals_purchase/index.js +47 -0
- package/dist/approvals_purchase/module.d.ts +12670 -0
- package/dist/approvals_purchase/module.js +84 -0
- package/dist/attendance/.kosh/bindings.d.ts +22 -0
- package/dist/attendance/.kosh/bindings.js +15 -0
- package/dist/attendance/.kosh/schema.d.ts +1106 -0
- package/dist/attendance/days.d.ts +96 -0
- package/dist/attendance/days.js +430 -0
- package/dist/attendance/demo.d.ts +7 -0
- package/dist/attendance/demo.js +58 -0
- package/dist/attendance/i18n/bn.d.ts +2 -0
- package/dist/attendance/i18n/bn.js +147 -0
- package/dist/attendance/index.d.ts +4 -0
- package/dist/attendance/index.js +515 -0
- package/dist/attendance/module.d.ts +4413 -0
- package/dist/attendance/module.js +412 -0
- package/dist/attendance/routes.d.ts +16 -0
- package/dist/attendance/routes.js +266 -0
- package/dist/attendance/web/Check.d.ts +8 -0
- package/dist/attendance/web/Check.js +40 -0
- package/dist/attendance/web/Kiosk.d.ts +8 -0
- package/dist/attendance/web/Kiosk.js +62 -0
- package/dist/attendance/web/PinButton.d.ts +7 -0
- package/dist/attendance/web/PinButton.js +29 -0
- package/dist/attendance/web/index.d.ts +13 -0
- package/dist/attendance/web/index.js +22 -0
- package/dist/attendance/web/messages.d.ts +2 -0
- package/dist/attendance/web/messages.js +61 -0
- package/dist/automation/engine.js +1 -1
- package/dist/calendar/.kosh/bindings.js +1 -1
- package/dist/calendar/.kosh/schema.d.ts +2 -1
- package/dist/calendar/i18n/bn.d.ts +2 -0
- package/dist/calendar/i18n/bn.js +80 -0
- package/dist/calendar/index.js +77 -0
- package/dist/calendar/module.d.ts +26 -0
- package/dist/calendar/module.js +14 -4
- package/dist/cli/apps.js +25 -5
- package/dist/cli/init.js +46 -4
- package/dist/cli/templates.d.ts +1 -1
- package/dist/cli/templates.js +123 -5
- package/dist/contacts/.kosh/bindings.js +1 -1
- package/dist/contacts/.kosh/schema.d.ts +2 -1
- package/dist/contacts/i18n/bn.d.ts +2 -0
- package/dist/contacts/i18n/bn.js +67 -0
- package/dist/contacts/index.js +3 -0
- package/dist/contacts/module.d.ts +42 -0
- package/dist/contacts/module.js +19 -3
- package/dist/crm/.kosh/bindings.js +1 -1
- package/dist/crm/.kosh/schema.d.ts +3 -1
- package/dist/crm/i18n/bn.d.ts +2 -0
- package/dist/crm/i18n/bn.js +80 -0
- package/dist/crm/index.js +22 -0
- package/dist/crm/module.d.ts +22 -0
- package/dist/crm/module.js +6 -3
- package/dist/documents/.kosh/bindings.d.ts +22 -0
- package/dist/documents/.kosh/bindings.js +15 -0
- package/dist/documents/.kosh/schema.d.ts +863 -0
- package/dist/documents/demo.d.ts +6 -0
- package/dist/documents/demo.js +22 -0
- package/dist/documents/documents.d.ts +98 -0
- package/dist/documents/documents.js +318 -0
- package/dist/documents/i18n/bn.d.ts +2 -0
- package/dist/documents/i18n/bn.js +83 -0
- package/dist/documents/index.d.ts +30 -0
- package/dist/documents/index.js +569 -0
- package/dist/documents/module.d.ts +2801 -0
- package/dist/documents/module.js +215 -0
- package/dist/documents/web/Versions.d.ts +7 -0
- package/dist/documents/web/Versions.js +45 -0
- package/dist/documents/web/index.d.ts +11 -0
- package/dist/documents/web/index.js +16 -0
- package/dist/documents/web/messages.d.ts +2 -0
- package/dist/documents/web/messages.js +21 -0
- package/dist/event/.kosh/bindings.js +1 -1
- package/dist/event/.kosh/schema.d.ts +2 -1
- package/dist/event/i18n/bn.d.ts +2 -0
- package/dist/event/i18n/bn.js +101 -0
- package/dist/event/index.js +66 -0
- package/dist/event/module.d.ts +20 -0
- package/dist/event/module.js +8 -1
- package/dist/event_account/.kosh/bindings.js +1 -1
- package/dist/event_account/.kosh/schema.d.ts +651 -10
- package/dist/event_account/i18n/bn.d.ts +2 -0
- package/dist/event_account/i18n/bn.js +5 -0
- package/dist/event_account/index.js +2 -0
- package/dist/event_account/module.d.ts +5133 -1513
- package/dist/expense/.kosh/bindings.d.ts +22 -0
- package/dist/expense/.kosh/bindings.js +15 -0
- package/dist/expense/.kosh/schema.d.ts +1620 -0
- package/dist/expense/demo.d.ts +7 -0
- package/dist/expense/demo.js +69 -0
- package/dist/expense/i18n/bn.d.ts +2 -0
- package/dist/expense/i18n/bn.js +155 -0
- package/dist/expense/index.d.ts +3 -0
- package/dist/expense/index.js +502 -0
- package/dist/expense/module.d.ts +6768 -0
- package/dist/expense/module.js +649 -0
- package/dist/expense_account/.kosh/bindings.d.ts +22 -0
- package/dist/expense_account/.kosh/bindings.js +15 -0
- package/dist/expense_account/.kosh/schema.d.ts +2515 -0
- package/dist/expense_account/i18n/bn.d.ts +2 -0
- package/dist/expense_account/i18n/bn.js +15 -0
- package/dist/expense_account/index.d.ts +3 -0
- package/dist/expense_account/index.js +76 -0
- package/dist/expense_account/module.d.ts +14628 -0
- package/dist/expense_account/module.js +318 -0
- package/dist/helpdesk/.kosh/bindings.d.ts +22 -0
- package/dist/helpdesk/.kosh/bindings.js +15 -0
- package/dist/helpdesk/.kosh/schema.d.ts +886 -0
- package/dist/helpdesk/demo.d.ts +7 -0
- package/dist/helpdesk/demo.js +65 -0
- package/dist/helpdesk/hours.d.ts +17 -0
- package/dist/helpdesk/hours.js +94 -0
- package/dist/helpdesk/i18n/bn.d.ts +2 -0
- package/dist/helpdesk/i18n/bn.js +127 -0
- package/dist/helpdesk/index.d.ts +10 -0
- package/dist/helpdesk/index.js +463 -0
- package/dist/helpdesk/module.d.ts +2960 -0
- package/dist/helpdesk/module.js +326 -0
- package/dist/helpdesk/routes.d.ts +12 -0
- package/dist/helpdesk/routes.js +132 -0
- package/dist/helpdesk/sla.d.ts +37 -0
- package/dist/helpdesk/sla.js +226 -0
- package/dist/hr/.kosh/bindings.js +1 -1
- package/dist/hr/.kosh/schema.d.ts +59 -1
- package/dist/hr/demo.js +11 -1
- package/dist/hr/i18n/bn.d.ts +2 -0
- package/dist/hr/i18n/bn.js +126 -0
- package/dist/hr/index.d.ts +1 -1
- package/dist/hr/index.js +158 -12
- package/dist/hr/module.d.ts +932 -59
- package/dist/hr/module.js +114 -17
- package/dist/indent/.kosh/bindings.d.ts +22 -0
- package/dist/indent/.kosh/bindings.js +15 -0
- package/dist/indent/.kosh/schema.d.ts +2084 -0
- package/dist/indent/demo.d.ts +7 -0
- package/dist/indent/demo.js +48 -0
- package/dist/indent/i18n/bn.d.ts +2 -0
- package/dist/indent/i18n/bn.js +143 -0
- package/dist/indent/index.d.ts +3 -0
- package/dist/indent/index.js +450 -0
- package/dist/indent/module.d.ts +13424 -0
- package/dist/indent/module.js +792 -0
- package/dist/indent_purchase/.kosh/bindings.d.ts +22 -0
- package/dist/indent_purchase/.kosh/bindings.js +15 -0
- package/dist/indent_purchase/.kosh/schema.d.ts +2710 -0
- package/dist/indent_purchase/i18n/bn.d.ts +2 -0
- package/dist/indent_purchase/i18n/bn.js +13 -0
- package/dist/indent_purchase/index.d.ts +3 -0
- package/dist/indent_purchase/index.js +61 -0
- package/dist/indent_purchase/module.d.ts +27950 -0
- package/dist/indent_purchase/module.js +163 -0
- package/dist/l10n_bd/.kosh/bindings.js +1 -1
- package/dist/l10n_bd/.kosh/schema.d.ts +651 -10
- package/dist/l10n_bd/i18n/bn.d.ts +2 -0
- package/dist/l10n_bd/i18n/bn.js +69 -0
- package/dist/l10n_bd/index.js +2 -0
- package/dist/l10n_bd/module.d.ts +5212 -1592
- package/dist/l10n_bd_payroll/.kosh/bindings.d.ts +22 -0
- package/dist/l10n_bd_payroll/.kosh/bindings.js +15 -0
- package/dist/l10n_bd_payroll/.kosh/schema.d.ts +2891 -0
- package/dist/l10n_bd_payroll/data.d.ts +47 -0
- package/dist/l10n_bd_payroll/data.js +347 -0
- package/dist/l10n_bd_payroll/i18n/bn.d.ts +2 -0
- package/dist/l10n_bd_payroll/i18n/bn.js +4 -0
- package/dist/l10n_bd_payroll/index.d.ts +4 -0
- package/dist/l10n_bd_payroll/index.js +26 -0
- package/dist/l10n_bd_payroll/module.d.ts +17294 -0
- package/dist/l10n_bd_payroll/module.js +86 -0
- package/dist/l10n_bd_pos/.kosh/bindings.d.ts +22 -0
- package/dist/{mrp_account → l10n_bd_pos}/.kosh/bindings.js +2 -2
- package/dist/l10n_bd_pos/.kosh/schema.d.ts +2341 -0
- package/dist/l10n_bd_pos/i18n/bn.d.ts +2 -0
- package/dist/l10n_bd_pos/i18n/bn.js +32 -0
- package/dist/l10n_bd_pos/index.d.ts +3 -0
- package/dist/l10n_bd_pos/index.js +111 -0
- package/dist/{mrp_account → l10n_bd_pos}/module.d.ts +9047 -6981
- package/dist/l10n_bd_pos/module.js +43 -0
- package/dist/l10n_in/.kosh/bindings.js +1 -1
- package/dist/l10n_in/.kosh/schema.d.ts +651 -10
- package/dist/l10n_in/i18n/bn.d.ts +2 -0
- package/dist/l10n_in/i18n/bn.js +95 -0
- package/dist/l10n_in/index.js +2 -0
- package/dist/l10n_in/module.d.ts +6778 -1580
- package/dist/l10n_in/module.js +25 -5
- package/dist/l10n_in/web/GstSettings.js +2 -2
- package/dist/mail/inbound/handle.js +8 -5
- package/dist/mail/inbound/models.js +5 -3
- package/dist/mail/index.d.ts +12 -1
- package/dist/mail/index.js +139 -2
- package/dist/mail/send.d.ts +56 -0
- package/dist/mail/send.js +394 -0
- package/dist/mail/web/SendButton.d.ts +9 -0
- package/dist/mail/web/SendButton.js +71 -0
- package/dist/mail/web/SendSelected.d.ts +8 -0
- package/dist/mail/web/SendSelected.js +33 -0
- package/dist/mail/web/index.d.ts +2 -0
- package/dist/mail/web/index.js +6 -0
- package/dist/mail/web/messages.js +36 -0
- package/dist/maintenance/.kosh/bindings.js +1 -1
- package/dist/maintenance/.kosh/schema.d.ts +2 -1
- package/dist/maintenance/i18n/bn.d.ts +2 -0
- package/dist/maintenance/i18n/bn.js +132 -0
- package/dist/maintenance/index.js +85 -0
- package/dist/maintenance/module.d.ts +25 -0
- package/dist/maintenance/module.js +27 -9
- package/dist/maintenance_stock/.kosh/bindings.js +1 -1
- package/dist/maintenance_stock/.kosh/schema.d.ts +374 -3
- package/dist/maintenance_stock/i18n/bn.d.ts +2 -0
- package/dist/maintenance_stock/i18n/bn.js +21 -0
- package/dist/maintenance_stock/index.js +2 -0
- package/dist/maintenance_stock/module.d.ts +6095 -1327
- package/dist/maintenance_stock/module.js +1 -0
- package/dist/modules-sdk/apps.d.ts +10 -0
- package/dist/modules-sdk/apps.js +32 -0
- package/dist/modules-sdk/index.d.ts +1 -1
- package/dist/modules-sdk/manifest.d.ts +105 -2
- package/dist/payment/.kosh/bindings.js +1 -1
- package/dist/payment/.kosh/schema.d.ts +653 -11
- package/dist/payment/i18n/bn.d.ts +2 -0
- package/dist/payment/i18n/bn.js +59 -0
- package/dist/payment/index.d.ts +41 -0
- package/dist/payment/index.js +216 -74
- package/dist/payment/module.d.ts +5353 -1675
- package/dist/payment/module.js +36 -6
- package/dist/payment/settle.js +11 -1
- package/dist/payroll/.kosh/bindings.d.ts +22 -0
- package/dist/payroll/.kosh/bindings.js +15 -0
- package/dist/payroll/.kosh/schema.d.ts +1448 -0
- package/dist/payroll/compute.d.ts +35 -0
- package/dist/payroll/compute.js +398 -0
- package/dist/payroll/demo.d.ts +55 -0
- package/dist/payroll/demo.js +121 -0
- package/dist/payroll/formula.d.ts +62 -0
- package/dist/payroll/formula.js +320 -0
- package/dist/payroll/i18n/bn.d.ts +2 -0
- package/dist/payroll/i18n/bn.js +206 -0
- package/dist/payroll/index.d.ts +230 -0
- package/dist/payroll/index.js +715 -0
- package/dist/{mrp → payroll}/module.d.ts +4294 -2624
- package/dist/payroll/module.js +606 -0
- package/dist/payroll/routes.d.ts +10 -0
- package/dist/payroll/routes.js +112 -0
- package/dist/payroll_account/.kosh/bindings.d.ts +22 -0
- package/dist/payroll_account/.kosh/bindings.js +15 -0
- package/dist/payroll_account/.kosh/schema.d.ts +2887 -0
- package/dist/payroll_account/i18n/bn.d.ts +2 -0
- package/dist/payroll_account/i18n/bn.js +10 -0
- package/dist/payroll_account/index.d.ts +3 -0
- package/dist/payroll_account/index.js +42 -0
- package/dist/payroll_account/module.d.ts +16738 -0
- package/dist/payroll_account/module.js +256 -0
- package/dist/permissions/approvals.d.ts +227 -12
- package/dist/permissions/approvals.js +1421 -67
- package/dist/permissions/index.d.ts +1 -1
- package/dist/permissions/index.js +2 -2
- package/dist/permissions/models.js +364 -13
- package/dist/permissions/routes.d.ts +9 -1
- package/dist/permissions/routes.js +72 -5
- package/dist/permissions/web/ApprovalPanel.d.ts +5 -4
- package/dist/permissions/web/ApprovalPanel.js +75 -11
- package/dist/permissions/web/index.d.ts +6 -4
- package/dist/permissions/web/index.js +13 -4
- package/dist/permissions/web/messages.d.ts +2 -0
- package/dist/permissions/web/messages.js +95 -0
- package/dist/portal/.kosh/bindings.js +1 -1
- package/dist/portal/.kosh/schema.d.ts +2 -1
- package/dist/portal/documents.d.ts +3 -0
- package/dist/portal/documents.js +21 -1
- package/dist/portal/i18n/bn.d.ts +2 -0
- package/dist/portal/i18n/bn.js +33 -0
- package/dist/portal/index.js +3 -1
- package/dist/portal/module.d.ts +20 -0
- package/dist/portal/routes-documents.js +76 -0
- package/dist/pos/.kosh/bindings.js +1 -1
- package/dist/pos/.kosh/schema.d.ts +652 -10
- package/dist/pos/i18n/bn.d.ts +2 -0
- package/dist/pos/i18n/bn.js +133 -0
- package/dist/pos/index.js +87 -1
- package/dist/pos/module.d.ts +6967 -1709
- package/dist/pos/module.js +49 -5
- package/dist/pos/routes.js +80 -7
- package/dist/pos/web/Register.js +2 -5
- package/dist/pos_stock/.kosh/bindings.js +1 -1
- package/dist/pos_stock/.kosh/schema.d.ts +822 -12
- package/dist/pos_stock/i18n/bn.d.ts +2 -0
- package/dist/pos_stock/i18n/bn.js +6 -0
- package/dist/pos_stock/index.js +2 -0
- package/dist/pos_stock/module.d.ts +11241 -2851
- package/dist/product/.kosh/bindings.js +1 -1
- package/dist/product/.kosh/schema.d.ts +203 -1
- package/dist/product/i18n/bn.d.ts +2 -0
- package/dist/product/i18n/bn.js +175 -0
- package/dist/product/index.d.ts +1 -0
- package/dist/product/index.js +301 -1
- package/dist/product/module.d.ts +1727 -0
- package/dist/product/module.js +67 -6
- package/dist/product/pricelist.d.ts +575 -0
- package/dist/product/pricelist.js +257 -0
- package/dist/product/variants.d.ts +908 -0
- package/dist/product/variants.js +251 -0
- package/dist/production/.kosh/bindings.d.ts +22 -0
- package/dist/production/.kosh/bindings.js +15 -0
- package/dist/production/.kosh/schema.d.ts +2345 -0
- package/dist/{mrp → production}/demo.d.ts +1 -1
- package/dist/{mrp → production}/demo.js +5 -5
- package/dist/production/depth.d.ts +790 -0
- package/dist/production/depth.js +262 -0
- package/dist/production/i18n/bn.d.ts +2 -0
- package/dist/production/i18n/bn.js +350 -0
- package/dist/production/index.d.ts +6 -0
- package/dist/production/index.js +1256 -0
- package/dist/production/module.d.ts +17327 -0
- package/dist/production/module.js +1333 -0
- package/dist/production/plan.d.ts +921 -0
- package/dist/production/plan.js +511 -0
- package/dist/production/schedule.d.ts +656 -0
- package/dist/production/schedule.js +309 -0
- package/dist/production_account/.kosh/bindings.d.ts +22 -0
- package/dist/production_account/.kosh/bindings.js +15 -0
- package/dist/production_account/.kosh/schema.d.ts +3496 -0
- package/dist/production_account/i18n/bn.d.ts +2 -0
- package/dist/production_account/i18n/bn.js +93 -0
- package/dist/production_account/index.d.ts +4 -0
- package/dist/production_account/index.js +246 -0
- package/dist/production_account/module.d.ts +1192 -0
- package/dist/{mrp_account → production_account}/module.js +72 -18
- package/dist/production_account/overhead.d.ts +1195 -0
- package/dist/production_account/overhead.js +554 -0
- package/dist/project/.kosh/bindings.js +1 -1
- package/dist/project/.kosh/schema.d.ts +735 -1
- package/dist/project/i18n/bn.d.ts +2 -0
- package/dist/project/i18n/bn.js +383 -0
- package/dist/project/index.d.ts +3 -1
- package/dist/project/index.js +1024 -14
- package/dist/project/module.d.ts +9912 -390
- package/dist/project/module.js +1590 -14
- package/dist/project/routes.d.ts +44 -0
- package/dist/project/routes.js +314 -0
- package/dist/project/schedule.d.ts +72 -0
- package/dist/project/schedule.js +192 -0
- package/dist/project/web/Refresh.d.ts +8 -0
- package/dist/project/web/Refresh.js +29 -0
- package/dist/project/web/Schedule.d.ts +9 -0
- package/dist/project/web/Schedule.js +93 -0
- package/dist/project/web/Structure.d.ts +8 -0
- package/dist/project/web/Structure.js +86 -0
- package/dist/project/web/Workload.d.ts +8 -0
- package/dist/project/web/Workload.js +43 -0
- package/dist/project/web/index.d.ts +14 -0
- package/dist/project/web/index.js +25 -0
- package/dist/project/web/messages.d.ts +2 -0
- package/dist/project/web/messages.js +85 -0
- package/dist/project_account/.kosh/bindings.d.ts +22 -0
- package/dist/project_account/.kosh/bindings.js +15 -0
- package/dist/project_account/.kosh/schema.d.ts +2763 -0
- package/dist/project_account/i18n/bn.d.ts +2 -0
- package/dist/project_account/i18n/bn.js +6 -0
- package/dist/project_account/index.d.ts +3 -0
- package/dist/project_account/index.js +29 -0
- package/dist/project_account/module.d.ts +15013 -0
- package/dist/project_account/module.js +76 -0
- package/dist/project_portal/.kosh/bindings.js +1 -1
- package/dist/project_portal/.kosh/schema.d.ts +735 -1
- package/dist/project_portal/i18n/bn.d.ts +2 -0
- package/dist/project_portal/i18n/bn.js +6 -0
- package/dist/project_portal/index.js +2 -0
- package/dist/project_portal/module.d.ts +4796 -87
- package/dist/project_purchase/.kosh/bindings.d.ts +22 -0
- package/dist/project_purchase/.kosh/bindings.js +15 -0
- package/dist/project_purchase/.kosh/schema.d.ts +3393 -0
- package/dist/project_purchase/i18n/bn.d.ts +2 -0
- package/dist/project_purchase/i18n/bn.js +4 -0
- package/dist/project_purchase/index.d.ts +9 -0
- package/dist/project_purchase/index.js +24 -0
- package/dist/project_purchase/module.d.ts +38613 -0
- package/dist/project_purchase/module.js +56 -0
- package/dist/purchase/.kosh/bindings.js +1 -1
- package/dist/purchase/.kosh/schema.d.ts +908 -5
- package/dist/purchase/comparison.d.ts +993 -0
- package/dist/purchase/comparison.js +415 -0
- package/dist/purchase/extras.d.ts +1509 -0
- package/dist/purchase/extras.js +445 -0
- package/dist/purchase/i18n/bn.d.ts +2 -0
- package/dist/purchase/i18n/bn.js +413 -0
- package/dist/purchase/index.d.ts +5 -0
- package/dist/purchase/index.js +1280 -4
- package/dist/purchase/module.d.ts +7147 -395
- package/dist/purchase/module.js +303 -10
- package/dist/purchase/request.d.ts +696 -0
- package/dist/purchase/request.js +446 -0
- package/dist/purchase/tender.d.ts +1208 -0
- package/dist/purchase/tender.js +507 -0
- package/dist/purchase/vendorprice.d.ts +340 -0
- package/dist/purchase/vendorprice.js +153 -0
- package/dist/purchase_account/.kosh/bindings.js +1 -1
- package/dist/purchase_account/.kosh/schema.d.ts +1209 -16
- package/dist/purchase_account/i18n/bn.d.ts +2 -0
- package/dist/purchase_account/i18n/bn.js +22 -0
- package/dist/purchase_account/index.js +20 -0
- package/dist/purchase_account/module.d.ts +12232 -2028
- package/dist/purchase_account/module.js +252 -9
- package/dist/purchase_portal/.kosh/bindings.js +1 -1
- package/dist/purchase_portal/.kosh/schema.d.ts +908 -5
- package/dist/purchase_portal/i18n/bn.d.ts +2 -0
- package/dist/purchase_portal/i18n/bn.js +5 -0
- package/dist/purchase_portal/index.js +2 -0
- package/dist/purchase_portal/module.d.ts +6853 -352
- package/dist/purchase_stock/.kosh/bindings.js +1 -1
- package/dist/purchase_stock/.kosh/schema.d.ts +1096 -21
- package/dist/purchase_stock/i18n/bn.d.ts +2 -0
- package/dist/purchase_stock/i18n/bn.js +19 -0
- package/dist/purchase_stock/index.d.ts +2 -2
- package/dist/purchase_stock/index.js +38 -2
- package/dist/purchase_stock/module.d.ts +12930 -1612
- package/dist/purchase_stock/module.js +317 -9
- package/dist/purchase_stock/scorecard.d.ts +22 -0
- package/dist/purchase_stock/scorecard.js +77 -0
- package/dist/purchase_stock/web/Scorecard.d.ts +7 -0
- package/dist/purchase_stock/web/Scorecard.js +22 -0
- package/dist/purchase_stock/web/index.d.ts +11 -0
- package/dist/purchase_stock/web/index.js +16 -0
- package/dist/purchase_stock/web/messages.d.ts +2 -0
- package/dist/purchase_stock/web/messages.js +27 -0
- package/dist/purchase_stock_account/.kosh/bindings.js +1 -1
- package/dist/purchase_stock_account/.kosh/schema.d.ts +1444 -20
- package/dist/purchase_stock_account/i18n/bn.d.ts +2 -0
- package/dist/purchase_stock_account/i18n/bn.js +8 -0
- package/dist/purchase_stock_account/index.js +18 -0
- package/dist/purchase_stock_account/module.d.ts +7 -35346
- package/dist/purchase_stock_account/module.js +35 -8
- package/dist/recruitment/.kosh/bindings.js +1 -1
- package/dist/recruitment/.kosh/schema.d.ts +60 -1
- package/dist/recruitment/i18n/bn.d.ts +2 -0
- package/dist/recruitment/i18n/bn.js +93 -0
- package/dist/recruitment/index.js +64 -0
- package/dist/recruitment/module.d.ts +460 -8
- package/dist/recruitment/module.js +13 -4
- package/dist/reporting/documents.d.ts +5 -0
- package/dist/reporting/documents.js +11 -1
- package/dist/reporting/index.d.ts +1 -1
- package/dist/reporting/index.js +1 -1
- package/dist/reporting/web/CalendarView.d.ts +18 -5
- package/dist/reporting/web/CalendarView.js +163 -29
- package/dist/reporting/web/messages.js +18 -0
- package/dist/sale_account/.kosh/bindings.js +1 -1
- package/dist/sale_account/.kosh/schema.d.ts +763 -18
- package/dist/sale_account/i18n/bn.d.ts +2 -0
- package/dist/sale_account/i18n/bn.js +48 -0
- package/dist/sale_account/index.d.ts +1 -1
- package/dist/sale_account/index.js +102 -4
- package/dist/sale_account/module.d.ts +8241 -2052
- package/dist/sale_account/module.js +535 -46
- package/dist/sale_crm/.kosh/bindings.d.ts +22 -0
- package/dist/sale_crm/.kosh/bindings.js +15 -0
- package/dist/{mrp → sale_crm}/.kosh/schema.d.ts +391 -494
- package/dist/sale_crm/i18n/bn.d.ts +2 -0
- package/dist/sale_crm/i18n/bn.js +9 -0
- package/dist/sale_crm/index.d.ts +7 -0
- package/dist/sale_crm/index.js +104 -0
- package/dist/sale_crm/module.d.ts +5609 -0
- package/dist/sale_crm/module.js +73 -0
- package/dist/sale_portal/.kosh/bindings.js +1 -1
- package/dist/sale_portal/.kosh/schema.d.ts +292 -4
- package/dist/sale_portal/i18n/bn.d.ts +2 -0
- package/dist/sale_portal/i18n/bn.js +7 -0
- package/dist/sale_portal/index.js +10 -0
- package/dist/sale_portal/module.d.ts +2563 -292
- package/dist/sale_project/.kosh/bindings.js +1 -1
- package/dist/sale_project/.kosh/schema.d.ts +1025 -4
- package/dist/sale_project/i18n/bn.d.ts +2 -0
- package/dist/sale_project/i18n/bn.js +12 -0
- package/dist/sale_project/index.js +2 -0
- package/dist/sale_project/module.d.ts +9280 -762
- package/dist/sale_project/module.js +17 -1
- package/dist/sale_stock/.kosh/bindings.js +1 -1
- package/dist/sale_stock/.kosh/schema.d.ts +463 -6
- package/dist/sale_stock/i18n/bn.d.ts +2 -0
- package/dist/sale_stock/i18n/bn.js +15 -0
- package/dist/sale_stock/index.js +2 -0
- package/dist/sale_stock/module.d.ts +8355 -1334
- package/dist/sale_stock/module.js +20 -3
- package/dist/sales/.kosh/bindings.js +1 -1
- package/dist/sales/.kosh/schema.d.ts +292 -4
- package/dist/sales/i18n/bn.d.ts +2 -0
- package/dist/sales/i18n/bn.js +128 -0
- package/dist/sales/index.js +124 -5
- package/dist/sales/module.d.ts +3568 -633
- package/dist/sales/module.js +306 -11
- package/dist/server/api/duplicate.d.ts +14 -0
- package/dist/server/api/duplicate.js +75 -0
- package/dist/server/api/explain.d.ts +70 -0
- package/dist/server/api/explain.js +111 -0
- package/dist/server/api/metadata.d.ts +2 -0
- package/dist/server/api/metadata.js +9 -0
- package/dist/server/api/openapi.js +15 -0
- package/dist/server/api/rest.d.ts +1 -0
- package/dist/server/api/rest.js +76 -12
- package/dist/server/api/views.js +1 -1
- package/dist/server/apps.d.ts +16 -1
- package/dist/server/apps.js +164 -2
- package/dist/server/auth/base.js +2 -0
- package/dist/server/auth/service.d.ts +8 -0
- package/dist/server/auth/service.js +19 -0
- package/dist/server/events.d.ts +13 -0
- package/dist/server/events.js +22 -0
- package/dist/server/i18n.d.ts +27 -0
- package/dist/server/i18n.js +143 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.js +2 -0
- package/dist/server/server.js +6 -0
- package/dist/settings/company.d.ts +3 -1
- package/dist/settings/company.js +26 -5
- package/dist/settings/routes.d.ts +10 -0
- package/dist/settings/routes.js +19 -3
- package/dist/settings/web/AppsPage.d.ts +3 -2
- package/dist/settings/web/AppsPage.js +26 -8
- package/dist/settings/web/CompaniesPage.js +91 -6
- package/dist/settings/web/messages.js +64 -0
- package/dist/sign/.kosh/bindings.d.ts +22 -0
- package/dist/{mrp → sign}/.kosh/bindings.js +2 -2
- package/dist/sign/.kosh/schema.d.ts +991 -0
- package/dist/sign/i18n/bn.d.ts +2 -0
- package/dist/sign/i18n/bn.js +97 -0
- package/dist/sign/index.d.ts +29 -0
- package/dist/sign/index.js +478 -0
- package/dist/sign/module.d.ts +4518 -0
- package/dist/sign/module.js +167 -0
- package/dist/sign/sign.d.ts +82 -0
- package/dist/sign/sign.js +474 -0
- package/dist/stock/.kosh/bindings.js +1 -1
- package/dist/stock/.kosh/schema.d.ts +374 -3
- package/dist/stock/demo.d.ts +2 -1
- package/dist/stock/demo.js +28 -1
- package/dist/stock/i18n/bn.d.ts +2 -0
- package/dist/stock/i18n/bn.js +311 -0
- package/dist/stock/index.d.ts +4 -1
- package/dist/stock/index.js +674 -6
- package/dist/stock/ledger.d.ts +78 -0
- package/dist/stock/ledger.js +582 -0
- package/dist/stock/module.d.ts +6142 -1380
- package/dist/stock/module.js +780 -26
- package/dist/stock/replenish.d.ts +38 -0
- package/dist/stock/replenish.js +191 -0
- package/dist/stock/returns.d.ts +157 -0
- package/dist/stock/returns.js +163 -0
- package/dist/stock/web/Ledger.d.ts +9 -0
- package/dist/stock/web/Ledger.js +108 -0
- package/dist/stock/web/Operations.d.ts +8 -0
- package/dist/stock/web/Operations.js +33 -0
- package/dist/stock/web/Replenishment.d.ts +8 -0
- package/dist/stock/web/Replenishment.js +84 -0
- package/dist/stock/web/ReturnButton.d.ts +7 -0
- package/dist/stock/web/ReturnButton.js +62 -0
- package/dist/stock/web/index.d.ts +7 -2
- package/dist/stock/web/index.js +15 -2
- package/dist/stock/web/messages.js +206 -0
- package/dist/stock_account/.kosh/bindings.js +1 -1
- package/dist/stock_account/.kosh/schema.d.ts +878 -12
- package/dist/stock_account/i18n/bn.d.ts +2 -0
- package/dist/stock_account/i18n/bn.js +73 -0
- package/dist/stock_account/index.d.ts +1 -0
- package/dist/stock_account/index.js +141 -3
- package/dist/stock_account/landed.d.ts +429 -0
- package/dist/stock_account/landed.js +335 -0
- package/dist/stock_account/module.d.ts +12143 -3391
- package/dist/stock_account/module.js +135 -6
- package/dist/stock_account/web/LandedPreview.d.ts +7 -0
- package/dist/stock_account/web/LandedPreview.js +23 -0
- package/dist/stock_account/web/index.d.ts +11 -0
- package/dist/stock_account/web/index.js +16 -0
- package/dist/stock_account/web/messages.d.ts +2 -0
- package/dist/stock_account/web/messages.js +27 -0
- package/dist/todo/i18n/bn.d.ts +2 -0
- package/dist/todo/i18n/bn.js +66 -0
- package/dist/todo/index.js +59 -0
- package/dist/todo/module.d.ts +5 -0
- package/dist/todo/module.js +5 -3
- package/dist/trade_finance/.kosh/bindings.js +1 -1
- package/dist/trade_finance/.kosh/schema.d.ts +2 -1
- package/dist/trade_finance/i18n/bn.d.ts +2 -0
- package/dist/trade_finance/i18n/bn.js +162 -0
- package/dist/trade_finance/index.js +95 -0
- package/dist/trade_finance/module.d.ts +26 -0
- package/dist/trade_finance/module.js +29 -8
- package/dist/trade_finance_account/.kosh/bindings.js +1 -1
- package/dist/trade_finance_account/.kosh/schema.d.ts +651 -10
- package/dist/trade_finance_account/i18n/bn.d.ts +2 -0
- package/dist/trade_finance_account/i18n/bn.js +27 -0
- package/dist/trade_finance_account/index.js +3 -0
- package/dist/trade_finance_account/module.d.ts +5129 -1509
- package/dist/trade_finance_account/module.js +2 -0
- package/dist/trade_finance_purchase/.kosh/bindings.js +1 -1
- package/dist/trade_finance_purchase/.kosh/schema.d.ts +908 -5
- package/dist/trade_finance_purchase/i18n/bn.d.ts +2 -0
- package/dist/trade_finance_purchase/i18n/bn.js +6 -0
- package/dist/trade_finance_purchase/index.js +2 -0
- package/dist/trade_finance_purchase/module.d.ts +6909 -408
- package/dist/trade_finance_sale/.kosh/bindings.js +1 -1
- package/dist/trade_finance_sale/.kosh/schema.d.ts +292 -4
- package/dist/trade_finance_sale/i18n/bn.d.ts +2 -0
- package/dist/trade_finance_sale/i18n/bn.js +6 -0
- package/dist/trade_finance_sale/index.js +2 -0
- package/dist/trade_finance_sale/module.d.ts +2602 -331
- package/dist/ui/api.d.ts +2 -0
- package/dist/ui/app.d.ts +9 -0
- package/dist/ui/app.js +47 -15
- package/dist/ui/components/AppIcon.js +9 -2
- package/dist/ui/components/Explain.d.ts +69 -0
- package/dist/ui/components/Explain.js +62 -0
- package/dist/ui/context.d.ts +8 -1
- package/dist/ui/context.js +34 -1
- package/dist/ui/i18n/messages.d.ts +40 -0
- package/dist/ui/i18n/messages.js +80 -0
- package/dist/ui/index.d.ts +2 -1
- package/dist/ui/index.js +1 -0
- package/dist/ui/registry.d.ts +14 -0
- package/dist/ui/registry.js +10 -0
- package/dist/ui/views/FormView.d.ts +6 -0
- package/dist/ui/views/FormView.js +51 -12
- package/dist/ui/views/KanbanView.js +9 -1
- package/dist/ui/views/ListView.d.ts +8 -0
- package/dist/ui/views/ListView.js +14 -5
- package/dist/ui/views/StatsRow.js +2 -1
- package/dist/ui/views/widgets.js +7 -1
- package/dist/views/extend.js +12 -0
- package/dist/views/types.d.ts +13 -2
- package/dist/views/validate.js +8 -1
- package/dist/website/.kosh/bindings.js +1 -1
- package/dist/website/.kosh/schema.d.ts +2 -1
- package/dist/website/i18n/bn.d.ts +2 -0
- package/dist/website/i18n/bn.js +113 -0
- package/dist/website/index.js +37 -0
- package/dist/website/module.d.ts +20 -0
- package/dist/website/module.js +30 -5
- package/dist/website_crm/.kosh/bindings.js +1 -1
- package/dist/website_crm/.kosh/schema.d.ts +3 -1
- package/dist/website_crm/i18n/bn.d.ts +2 -0
- package/dist/website_crm/i18n/bn.js +5 -0
- package/dist/website_crm/index.js +2 -0
- package/dist/website_crm/module.d.ts +41 -0
- package/dist/website_sale/.kosh/bindings.d.ts +22 -0
- package/dist/website_sale/.kosh/bindings.js +15 -0
- package/dist/website_sale/.kosh/schema.d.ts +2909 -0
- package/dist/website_sale/couriers.d.ts +50 -0
- package/dist/website_sale/couriers.js +59 -0
- package/dist/website_sale/demo.d.ts +7 -0
- package/dist/website_sale/demo.js +90 -0
- package/dist/website_sale/growth.d.ts +31 -0
- package/dist/website_sale/growth.js +163 -0
- package/dist/website_sale/i18n/bn.d.ts +2 -0
- package/dist/website_sale/i18n/bn.js +132 -0
- package/dist/website_sale/index.d.ts +49 -0
- package/dist/website_sale/index.js +620 -0
- package/dist/website_sale/module.d.ts +35182 -0
- package/dist/website_sale/module.js +419 -0
- package/dist/website_sale/shipments.d.ts +16 -0
- package/dist/website_sale/shipments.js +113 -0
- package/dist/website_sale/shop.d.ts +81 -0
- package/dist/website_sale/shop.js +662 -0
- package/dist/website_sale_stock/.kosh/bindings.d.ts +22 -0
- package/dist/website_sale_stock/.kosh/bindings.js +15 -0
- package/dist/website_sale_stock/.kosh/schema.d.ts +3400 -0
- package/dist/website_sale_stock/i18n/bn.d.ts +2 -0
- package/dist/website_sale_stock/i18n/bn.js +4 -0
- package/dist/website_sale_stock/index.d.ts +9 -0
- package/dist/website_sale_stock/index.js +22 -0
- package/dist/website_sale_stock/module.d.ts +11 -0
- package/dist/website_sale_stock/module.js +32 -0
- package/package.json +117 -8
- package/dist/mrp/index.d.ts +0 -3
- package/dist/mrp/index.js +0 -392
- package/dist/mrp/module.js +0 -695
- package/dist/mrp_account/index.d.ts +0 -3
- package/dist/mrp_account/index.js +0 -22
- /package/dist/{mrp → account_asset}/.kosh/bindings.d.ts +0 -0
- /package/dist/{mrp_account → account_budget}/.kosh/bindings.d.ts +0 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { type Decimal, type Id } from '../server/orm.js';
|
|
2
|
+
import type { Env } from './.kosh/bindings.js';
|
|
3
|
+
/** The installation's time zone for attendance; a wrong one falls back to Asia/Dhaka. */
|
|
4
|
+
export declare function timeZoneOf(env: Env): Promise<string>;
|
|
5
|
+
/** The date of an instant where the people work, `YYYY-MM-DD`. */
|
|
6
|
+
export declare function localDate(at: Date, tz: string): string;
|
|
7
|
+
/** The instant of `minutes` after midnight of `date` in `tz` (minutes may pass 1 440: the next day). */
|
|
8
|
+
export declare function instantOf(date: string, minutes: number, tz: string): Date;
|
|
9
|
+
/** `YYYY-MM-DD` plus `days`. */
|
|
10
|
+
export declare function addDays(date: string, days: number): string;
|
|
11
|
+
/** `HH:MM` as minutes after midnight. */
|
|
12
|
+
export declare const minutesOf: (hhmm: string) => number;
|
|
13
|
+
export interface ShiftRule {
|
|
14
|
+
readonly start: string;
|
|
15
|
+
readonly end: string;
|
|
16
|
+
readonly breakMinutes: number;
|
|
17
|
+
readonly graceMinutes: number;
|
|
18
|
+
readonly overtimeAfter: number;
|
|
19
|
+
readonly overtimeStep: number;
|
|
20
|
+
}
|
|
21
|
+
export interface DayInput {
|
|
22
|
+
readonly date: string;
|
|
23
|
+
readonly tz: string;
|
|
24
|
+
readonly shift: ShiftRule | null;
|
|
25
|
+
readonly weekend: boolean;
|
|
26
|
+
readonly holiday: boolean;
|
|
27
|
+
readonly leave: boolean;
|
|
28
|
+
readonly punches: readonly {
|
|
29
|
+
readonly checkIn: Date;
|
|
30
|
+
readonly checkOut: Date | null;
|
|
31
|
+
}[];
|
|
32
|
+
}
|
|
33
|
+
export interface DayResult {
|
|
34
|
+
readonly status: 'present' | 'absent' | 'leave' | 'holiday' | 'weekend' | 'incomplete' | 'off';
|
|
35
|
+
readonly firstIn: Date | null;
|
|
36
|
+
readonly lastOut: Date | null;
|
|
37
|
+
readonly workedMinutes: number;
|
|
38
|
+
readonly expectedMinutes: number;
|
|
39
|
+
readonly lateMinutes: number;
|
|
40
|
+
readonly earlyMinutes: number;
|
|
41
|
+
readonly overtimeMinutes: number;
|
|
42
|
+
}
|
|
43
|
+
/** The day: what the punches, the shift and the calendar say. */
|
|
44
|
+
export declare function computeDay(input: DayInput): DayResult;
|
|
45
|
+
/** A shift's length in minutes; a night shift ends the next day. */
|
|
46
|
+
export declare function shiftMinutes(shift: Pick<ShiftRule, 'start' | 'end'>): number;
|
|
47
|
+
/** Recomputes the days of `employees` from `from` to `to` (inclusive); approved days stay as they are. */
|
|
48
|
+
export declare function recomputeDays(env: Env, employees: readonly number[], from: string, to: string): Promise<number>;
|
|
49
|
+
/** A date-only value as `YYYY-MM-DD` (PostgreSQL dates read as local midnights). */
|
|
50
|
+
export declare function isoDate(v: unknown): string;
|
|
51
|
+
/** The distance in metres between two points (haversine). */
|
|
52
|
+
export declare function distanceMetres(a: {
|
|
53
|
+
lat: number;
|
|
54
|
+
lon: number;
|
|
55
|
+
}, b: {
|
|
56
|
+
lat: number;
|
|
57
|
+
lon: number;
|
|
58
|
+
}): number;
|
|
59
|
+
export interface PunchInput {
|
|
60
|
+
readonly source: 'phone' | 'kiosk' | 'device' | 'manual';
|
|
61
|
+
readonly site?: number | null;
|
|
62
|
+
readonly inside?: boolean | null;
|
|
63
|
+
readonly distance?: number | null;
|
|
64
|
+
}
|
|
65
|
+
/** Checks the employee in, or out when checked in; recomputes the day. */
|
|
66
|
+
export declare function punch(env: Env, employee: number, at: Date, input: PunchInput): Promise<{
|
|
67
|
+
action: 'in' | 'out';
|
|
68
|
+
record: number;
|
|
69
|
+
at: string;
|
|
70
|
+
}>;
|
|
71
|
+
/** A punch read from a device file: the person's number on the device and the local time. */
|
|
72
|
+
export interface DevicePunch {
|
|
73
|
+
readonly user: string;
|
|
74
|
+
/** `YYYY-MM-DD HH:MM[:SS]`, in the installation's time zone. */
|
|
75
|
+
readonly at: string;
|
|
76
|
+
}
|
|
77
|
+
/** A device file format (RFC 0024 §3: an adapter; ZKTeco's log and a CSV ship). */
|
|
78
|
+
export interface DeviceFormat {
|
|
79
|
+
readonly key: string;
|
|
80
|
+
readonly label: string;
|
|
81
|
+
readonly parse: (text: string) => DevicePunch[];
|
|
82
|
+
}
|
|
83
|
+
export declare const DEVICE_FORMATS: readonly DeviceFormat[];
|
|
84
|
+
export interface ImportResult {
|
|
85
|
+
readonly imported: number;
|
|
86
|
+
readonly skipped: number;
|
|
87
|
+
readonly unpaired: number;
|
|
88
|
+
readonly unknown: readonly string[];
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Device punches into check-ins and check-outs: each person's punches of a day in pairs (in, out); a punch left
|
|
92
|
+
* alone stays a check-in on the person's last day, and is reported as unpaired before it. A punch already imported
|
|
93
|
+
* (the same person and time) is skipped.
|
|
94
|
+
*/
|
|
95
|
+
export declare function importPunches(env: Env, punches: readonly DevicePunch[]): Promise<ImportResult>;
|
|
96
|
+
export type { Decimal, Id };
|
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attendance computed (RFC 0024 §2.2): the day of each person from their punches, their shift (the roster's, else
|
|
3
|
+
* their usual one), the weekend (Workforce's setting), public holidays and approved leave — in the installation's
|
|
4
|
+
* time zone (App settings › Attendance). Approved days are never recomputed.
|
|
5
|
+
*
|
|
6
|
+
* Also here: a punch from the phone or the kiosk (check in, or out when checked in), the geofence, and device files
|
|
7
|
+
* (ZKTeco's attendance log and a plain CSV) turned into punches, each once.
|
|
8
|
+
*/
|
|
9
|
+
import { weekendOf } from '../hr/index.js';
|
|
10
|
+
import { installationSetting } from '../server/index.js';
|
|
11
|
+
import { orm } from '../server/orm.js';
|
|
12
|
+
const DAY = 86_400_000;
|
|
13
|
+
// ---- time zones: dates and minutes of the day where the people work.
|
|
14
|
+
/** The installation's time zone for attendance; a wrong one falls back to Asia/Dhaka. */
|
|
15
|
+
export async function timeZoneOf(env) {
|
|
16
|
+
const tz = String(await installationSetting(env, 'attendance.timezone', 'Asia/Dhaka'));
|
|
17
|
+
try {
|
|
18
|
+
new Intl.DateTimeFormat('en-US', { timeZone: tz });
|
|
19
|
+
return tz;
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return 'Asia/Dhaka';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function parts(at, tz) {
|
|
26
|
+
const out = {};
|
|
27
|
+
for (const p of new Intl.DateTimeFormat('en-US', {
|
|
28
|
+
timeZone: tz,
|
|
29
|
+
hourCycle: 'h23',
|
|
30
|
+
year: 'numeric',
|
|
31
|
+
month: '2-digit',
|
|
32
|
+
day: '2-digit',
|
|
33
|
+
hour: '2-digit',
|
|
34
|
+
minute: '2-digit',
|
|
35
|
+
}).formatToParts(at))
|
|
36
|
+
if (p.type !== 'literal')
|
|
37
|
+
out[p.type] = Number(p.value);
|
|
38
|
+
return {
|
|
39
|
+
y: out['year'] ?? 0,
|
|
40
|
+
m: out['month'] ?? 1,
|
|
41
|
+
d: out['day'] ?? 1,
|
|
42
|
+
h: out['hour'] ?? 0,
|
|
43
|
+
min: out['minute'] ?? 0,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/** The date of an instant where the people work, `YYYY-MM-DD`. */
|
|
47
|
+
export function localDate(at, tz) {
|
|
48
|
+
const p = parts(at, tz);
|
|
49
|
+
return `${p.y}-${String(p.m).padStart(2, '0')}-${String(p.d).padStart(2, '0')}`;
|
|
50
|
+
}
|
|
51
|
+
/** The instant of `minutes` after midnight of `date` in `tz` (minutes may pass 1 440: the next day). */
|
|
52
|
+
export function instantOf(date, minutes, tz) {
|
|
53
|
+
const [y, m, d] = date.split('-').map(Number);
|
|
54
|
+
const guess = Date.UTC(y, m - 1, d, 0, minutes);
|
|
55
|
+
const offset = (t) => {
|
|
56
|
+
const p = parts(new Date(t), tz);
|
|
57
|
+
return Date.UTC(p.y, p.m - 1, p.d, p.h, p.min) - t;
|
|
58
|
+
};
|
|
59
|
+
const first = guess - offset(guess);
|
|
60
|
+
return new Date(guess - offset(first));
|
|
61
|
+
}
|
|
62
|
+
/** `YYYY-MM-DD` plus `days`. */
|
|
63
|
+
export function addDays(date, days) {
|
|
64
|
+
return new Date(Date.parse(`${date}T00:00:00Z`) + days * DAY).toISOString().slice(0, 10);
|
|
65
|
+
}
|
|
66
|
+
/** `HH:MM` as minutes after midnight. */
|
|
67
|
+
export const minutesOf = (hhmm) => {
|
|
68
|
+
const [h, m] = hhmm.split(':').map(Number);
|
|
69
|
+
return h * 60 + m;
|
|
70
|
+
};
|
|
71
|
+
/** The day: what the punches, the shift and the calendar say. */
|
|
72
|
+
export function computeDay(input) {
|
|
73
|
+
const { shift, punches } = input;
|
|
74
|
+
const workday = shift !== null && !input.weekend && !input.holiday && !input.leave;
|
|
75
|
+
const span = shift === null ? 0 : shiftMinutes(shift);
|
|
76
|
+
const expected = workday && shift !== null ? Math.max(0, span - shift.breakMinutes) : 0;
|
|
77
|
+
const sorted = [...punches].sort((a, b) => a.checkIn.getTime() - b.checkIn.getTime());
|
|
78
|
+
if (sorted.length === 0)
|
|
79
|
+
return {
|
|
80
|
+
status: input.leave
|
|
81
|
+
? 'leave'
|
|
82
|
+
: input.holiday
|
|
83
|
+
? 'holiday'
|
|
84
|
+
: input.weekend
|
|
85
|
+
? 'weekend'
|
|
86
|
+
: shift === null
|
|
87
|
+
? 'off'
|
|
88
|
+
: 'absent',
|
|
89
|
+
firstIn: null,
|
|
90
|
+
lastOut: null,
|
|
91
|
+
workedMinutes: 0,
|
|
92
|
+
expectedMinutes: expected,
|
|
93
|
+
lateMinutes: 0,
|
|
94
|
+
earlyMinutes: 0,
|
|
95
|
+
overtimeMinutes: 0,
|
|
96
|
+
};
|
|
97
|
+
const present = sorted.reduce((sum, p) => sum + (p.checkOut === null ? 0 : (p.checkOut.getTime() - p.checkIn.getTime()) / 60_000), 0);
|
|
98
|
+
// The shift's break is not work: deducted, less the breaks the punches already show (their gaps).
|
|
99
|
+
let gaps = 0;
|
|
100
|
+
for (let i = 1; i < sorted.length; i += 1) {
|
|
101
|
+
const before = sorted[i - 1]?.checkOut;
|
|
102
|
+
const next = sorted[i]?.checkIn;
|
|
103
|
+
if (before != null && next !== undefined)
|
|
104
|
+
gaps += Math.max(0, (next.getTime() - before.getTime()) / 60_000);
|
|
105
|
+
}
|
|
106
|
+
const unpaidBreak = shift === null ? 0 : Math.max(0, shift.breakMinutes - gaps);
|
|
107
|
+
const worked = present > unpaidBreak ? present - unpaidBreak : present;
|
|
108
|
+
const firstIn = sorted[0]?.checkIn ?? null;
|
|
109
|
+
const closed = sorted.filter((p) => p.checkOut !== null);
|
|
110
|
+
const lastOut = closed.length === 0 ? null : (closed[closed.length - 1]?.checkOut ?? null);
|
|
111
|
+
const open = sorted.some((p) => p.checkOut === null);
|
|
112
|
+
const midnight = instantOf(input.date, 0, input.tz).getTime();
|
|
113
|
+
const sinceMidnight = (d) => Math.round((d.getTime() - midnight) / 60_000);
|
|
114
|
+
let late = 0;
|
|
115
|
+
let early = 0;
|
|
116
|
+
let overtime = 0;
|
|
117
|
+
if (workday && shift !== null) {
|
|
118
|
+
const start = minutesOf(shift.start);
|
|
119
|
+
const end = start + span;
|
|
120
|
+
if (firstIn !== null)
|
|
121
|
+
late = Math.max(0, sinceMidnight(firstIn) - (start + shift.graceMinutes));
|
|
122
|
+
if (lastOut !== null && !open)
|
|
123
|
+
early = Math.max(0, end - sinceMidnight(lastOut));
|
|
124
|
+
const extra = worked - expected;
|
|
125
|
+
if (extra > shift.overtimeAfter)
|
|
126
|
+
overtime = floorTo(extra, shift.overtimeStep);
|
|
127
|
+
}
|
|
128
|
+
else if (shift !== null && (input.weekend || input.holiday)) {
|
|
129
|
+
// Every hour worked on a weekend or a holiday is overtime.
|
|
130
|
+
overtime = floorTo(worked, shift.overtimeStep);
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
status: open ? 'incomplete' : 'present',
|
|
134
|
+
firstIn,
|
|
135
|
+
lastOut,
|
|
136
|
+
workedMinutes: Math.round(worked),
|
|
137
|
+
expectedMinutes: expected,
|
|
138
|
+
lateMinutes: Math.round(late),
|
|
139
|
+
earlyMinutes: Math.round(early),
|
|
140
|
+
overtimeMinutes: overtime,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
/** A shift's length in minutes; a night shift ends the next day. */
|
|
144
|
+
export function shiftMinutes(shift) {
|
|
145
|
+
const start = minutesOf(shift.start);
|
|
146
|
+
let end = minutesOf(shift.end);
|
|
147
|
+
if (end <= start)
|
|
148
|
+
end += 1440;
|
|
149
|
+
return end - start;
|
|
150
|
+
}
|
|
151
|
+
const floorTo = (minutes, step) => Math.floor(minutes / Math.max(1, step)) * Math.max(1, step);
|
|
152
|
+
const hours = (minutes) => orm.toDecimal(minutes).div(60).toDecimalPlaces(2).toString();
|
|
153
|
+
// ---- days written for people and dates.
|
|
154
|
+
/** Recomputes the days of `employees` from `from` to `to` (inclusive); approved days stay as they are. */
|
|
155
|
+
export async function recomputeDays(env, employees, from, to) {
|
|
156
|
+
if (employees.length === 0 || to < from)
|
|
157
|
+
return 0;
|
|
158
|
+
const tz = await timeZoneOf(env);
|
|
159
|
+
const weekend = await weekendOf(env);
|
|
160
|
+
let written = 0;
|
|
161
|
+
for (const e of await env
|
|
162
|
+
.model('hr.employee')
|
|
163
|
+
.browse(employees)
|
|
164
|
+
.load({ attendanceShift: true, company: true })) {
|
|
165
|
+
const rosters = await (await env.model('attendance.roster').search({
|
|
166
|
+
where: { employee: e.id, dateFrom: { lte: to }, dateTo: { gte: from } },
|
|
167
|
+
})).load({ shift: true });
|
|
168
|
+
const holidays = new Set([
|
|
169
|
+
...(await (await env.model('attendance.holiday').search({
|
|
170
|
+
where: { company: e.company.id, date: { gte: from, lte: to } },
|
|
171
|
+
})).load(['date'])),
|
|
172
|
+
].map((h) => isoDate(h.date)));
|
|
173
|
+
const leaves = [
|
|
174
|
+
...(await (await env.model('hr.leave').search({
|
|
175
|
+
where: {
|
|
176
|
+
employee: e.id,
|
|
177
|
+
state: 'approved',
|
|
178
|
+
dateFrom: { lte: to },
|
|
179
|
+
dateTo: { gte: from },
|
|
180
|
+
},
|
|
181
|
+
})).load(['dateFrom', 'dateTo'])),
|
|
182
|
+
].map((l) => [isoDate(l.dateFrom), isoDate(l.dateTo)]);
|
|
183
|
+
const punches = [
|
|
184
|
+
...(await (await env.model('attendance.record').search({
|
|
185
|
+
where: {
|
|
186
|
+
employee: e.id,
|
|
187
|
+
checkIn: { gte: instantOf(from, 0, tz), lt: instantOf(addDays(to, 1), 0, tz) },
|
|
188
|
+
},
|
|
189
|
+
})).load(['checkIn', 'checkOut'])),
|
|
190
|
+
];
|
|
191
|
+
const existing = new Map([
|
|
192
|
+
...(await (await env.model('attendance.day').search({
|
|
193
|
+
where: { employee: e.id, date: { gte: from, lte: to } },
|
|
194
|
+
})).load(['date', 'state'])),
|
|
195
|
+
].map((d) => [isoDate(d.date), d]));
|
|
196
|
+
for (let date = from; date <= to; date = addDays(date, 1)) {
|
|
197
|
+
const old = existing.get(date);
|
|
198
|
+
if (old?.state === 'approved')
|
|
199
|
+
continue;
|
|
200
|
+
const roster = [...rosters].find((r) => isoDate(r.dateFrom) <= date && isoDate(r.dateTo) >= date);
|
|
201
|
+
const shift = roster?.shift ?? e.attendanceShift ?? null;
|
|
202
|
+
const mine = punches.filter((p) => localDate(p.checkIn, tz) === date);
|
|
203
|
+
const dow = new Date(`${date}T00:00:00Z`).getUTCDay();
|
|
204
|
+
const result = computeDay({
|
|
205
|
+
date,
|
|
206
|
+
tz,
|
|
207
|
+
shift,
|
|
208
|
+
weekend: weekend.includes(dow),
|
|
209
|
+
holiday: holidays.has(date),
|
|
210
|
+
leave: leaves.some(([a, b]) => a <= date && b >= date),
|
|
211
|
+
punches: mine,
|
|
212
|
+
});
|
|
213
|
+
// Nothing to say about a weekend, a holiday or a day without a shift nobody worked.
|
|
214
|
+
if (old === undefined &&
|
|
215
|
+
mine.length === 0 &&
|
|
216
|
+
['weekend', 'holiday', 'off'].includes(result.status))
|
|
217
|
+
continue;
|
|
218
|
+
const values = {
|
|
219
|
+
employee: e.id,
|
|
220
|
+
date,
|
|
221
|
+
company: e.company.id,
|
|
222
|
+
shift: shift?.id ?? null,
|
|
223
|
+
status: result.status,
|
|
224
|
+
firstIn: result.firstIn,
|
|
225
|
+
lastOut: result.lastOut,
|
|
226
|
+
workedHours: hours(result.workedMinutes),
|
|
227
|
+
expectedHours: hours(result.expectedMinutes),
|
|
228
|
+
lateMinutes: result.lateMinutes,
|
|
229
|
+
earlyMinutes: result.earlyMinutes,
|
|
230
|
+
overtimeHours: hours(result.overtimeMinutes),
|
|
231
|
+
overtimeApproved: hours(result.overtimeMinutes),
|
|
232
|
+
overtimeRate: (shift?.overtimeRate ?? orm.toDecimal(2)).toString(),
|
|
233
|
+
};
|
|
234
|
+
if (old === undefined)
|
|
235
|
+
await env.model('attendance.day').create([values]);
|
|
236
|
+
else
|
|
237
|
+
await env
|
|
238
|
+
.model('attendance.day')
|
|
239
|
+
.browse([old.id])
|
|
240
|
+
.write(values);
|
|
241
|
+
written += 1;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return written;
|
|
245
|
+
}
|
|
246
|
+
/** A date-only value as `YYYY-MM-DD` (PostgreSQL dates read as local midnights). */
|
|
247
|
+
export function isoDate(v) {
|
|
248
|
+
if (!(v instanceof Date))
|
|
249
|
+
return String(v ?? '').slice(0, 10);
|
|
250
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
251
|
+
return `${v.getFullYear()}-${pad(v.getMonth() + 1)}-${pad(v.getDate())}`;
|
|
252
|
+
}
|
|
253
|
+
// ---- punches.
|
|
254
|
+
/** The distance in metres between two points (haversine). */
|
|
255
|
+
export function distanceMetres(a, b) {
|
|
256
|
+
const rad = (x) => (x * Math.PI) / 180;
|
|
257
|
+
const dLat = rad(b.lat - a.lat);
|
|
258
|
+
const dLon = rad(b.lon - a.lon);
|
|
259
|
+
const h = Math.sin(dLat / 2) ** 2 + Math.cos(rad(a.lat)) * Math.cos(rad(b.lat)) * Math.sin(dLon / 2) ** 2;
|
|
260
|
+
return Math.round(2 * 6_371_000 * Math.asin(Math.sqrt(h)));
|
|
261
|
+
}
|
|
262
|
+
/** Checks the employee in, or out when checked in; recomputes the day. */
|
|
263
|
+
export async function punch(env, employee, at, input) {
|
|
264
|
+
const open = await env
|
|
265
|
+
.model('attendance.record')
|
|
266
|
+
.search({ where: { employee: employee, checkOut: { isNull: true } }, limit: 1 });
|
|
267
|
+
const [e] = await env
|
|
268
|
+
.model('hr.employee')
|
|
269
|
+
.browse([employee])
|
|
270
|
+
.load({ company: true });
|
|
271
|
+
if (e === undefined)
|
|
272
|
+
throw new orm.ValidationError('attendance.record', ['employee'], 'No such employee.', 'Choose an employee.');
|
|
273
|
+
let action;
|
|
274
|
+
let id;
|
|
275
|
+
let checkIn = at;
|
|
276
|
+
if (open.length > 0) {
|
|
277
|
+
const [current] = await open.load(['checkIn']);
|
|
278
|
+
checkIn = current?.checkIn ?? at;
|
|
279
|
+
if (at.getTime() - checkIn.getTime() < 60_000)
|
|
280
|
+
throw new orm.ValidationError('attendance.record', ['checkOut'], 'Checked in less than a minute ago.', 'A second tap is not a check-out: wait a minute.');
|
|
281
|
+
await open.write({ checkOut: at });
|
|
282
|
+
action = 'out';
|
|
283
|
+
id = open.ids[0];
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
const made = await env.model('attendance.record').create([
|
|
287
|
+
{
|
|
288
|
+
employee,
|
|
289
|
+
company: e.company.id,
|
|
290
|
+
checkIn: at,
|
|
291
|
+
source: input.source,
|
|
292
|
+
site: input.site ?? null,
|
|
293
|
+
...(input.inside == null ? {} : { inside: input.inside }),
|
|
294
|
+
distance: input.distance ?? null,
|
|
295
|
+
},
|
|
296
|
+
]);
|
|
297
|
+
action = 'in';
|
|
298
|
+
id = made.ids[0];
|
|
299
|
+
}
|
|
300
|
+
await env.flush();
|
|
301
|
+
const tz = await timeZoneOf(env);
|
|
302
|
+
await recomputeDays(env, [employee], localDate(checkIn, tz), localDate(at, tz));
|
|
303
|
+
return { action, record: id, at: at.toISOString() };
|
|
304
|
+
}
|
|
305
|
+
const LOCAL = /^(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2})(:\d{2})?$/;
|
|
306
|
+
export const DEVICE_FORMATS = [
|
|
307
|
+
{
|
|
308
|
+
key: 'zkteco',
|
|
309
|
+
label: 'ZKTeco attendance log (attlog.dat)',
|
|
310
|
+
// ` 12\t2026-10-20 08:58:12\t1\t0\t1\t0`: the user ID, the date and time, then flags.
|
|
311
|
+
parse: (text) => text
|
|
312
|
+
.split(/\r?\n/)
|
|
313
|
+
.map((line) => line.trim().split(/\s+/))
|
|
314
|
+
.filter((cols) => cols.length >= 3 && LOCAL.test(`${cols[1]} ${cols[2]}`))
|
|
315
|
+
.map((cols) => ({ user: cols[0], at: `${cols[1]} ${cols[2]}` })),
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
key: 'csv',
|
|
319
|
+
label: 'CSV: employee code and time',
|
|
320
|
+
// A header with `employee` (the badge or device user ID) and `time` (or `timestamp`) columns.
|
|
321
|
+
parse: (text) => {
|
|
322
|
+
const rows = text
|
|
323
|
+
.split(/\r?\n/)
|
|
324
|
+
.filter((l) => l.trim() !== '')
|
|
325
|
+
.map((l) => l.split(',').map((c) => c.trim().replace(/^"|"$/g, '')));
|
|
326
|
+
const header = (rows[0] ?? []).map((h) => h.toLowerCase());
|
|
327
|
+
const who = header.findIndex((h) => h === 'employee' || h === 'code' || h === 'user');
|
|
328
|
+
const when = header.findIndex((h) => h === 'time' || h === 'timestamp' || h === 'datetime');
|
|
329
|
+
if (who < 0 || when < 0)
|
|
330
|
+
return [];
|
|
331
|
+
return rows
|
|
332
|
+
.slice(1)
|
|
333
|
+
.map((r) => ({ user: r[who] ?? '', at: r[when] ?? '' }))
|
|
334
|
+
.filter((p) => p.user !== '' && LOCAL.test(p.at));
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
];
|
|
338
|
+
/**
|
|
339
|
+
* Device punches into check-ins and check-outs: each person's punches of a day in pairs (in, out); a punch left
|
|
340
|
+
* alone stays a check-in on the person's last day, and is reported as unpaired before it. A punch already imported
|
|
341
|
+
* (the same person and time) is skipped.
|
|
342
|
+
*/
|
|
343
|
+
export async function importPunches(env, punches) {
|
|
344
|
+
const tz = await timeZoneOf(env);
|
|
345
|
+
const codes = [...new Set(punches.map((p) => p.user))];
|
|
346
|
+
const people = new Map();
|
|
347
|
+
if (codes.length > 0) {
|
|
348
|
+
for (const e of await (await env.model('hr.employee').search({
|
|
349
|
+
where: { or: [{ deviceUserId: { in: codes } }, { attendanceBadge: { in: codes } }] },
|
|
350
|
+
})).load(['deviceUserId', 'attendanceBadge'])) {
|
|
351
|
+
if (e.deviceUserId !== null)
|
|
352
|
+
people.set(e.deviceUserId, e.id);
|
|
353
|
+
if (e.attendanceBadge !== null && !people.has(e.attendanceBadge))
|
|
354
|
+
people.set(e.attendanceBadge, e.id);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
const unknown = codes.filter((c) => !people.has(c));
|
|
358
|
+
const toInstant = (at) => {
|
|
359
|
+
const m = LOCAL.exec(at);
|
|
360
|
+
const [hh, mm] = m[2].split(':').map(Number);
|
|
361
|
+
const ss = m[3] === undefined ? 0 : Number(m[3].slice(1));
|
|
362
|
+
return new Date(instantOf(m[1], hh * 60 + mm, tz).getTime() + ss * 1000);
|
|
363
|
+
};
|
|
364
|
+
let imported = 0;
|
|
365
|
+
let skipped = 0;
|
|
366
|
+
let unpaired = 0;
|
|
367
|
+
const touched = new Map();
|
|
368
|
+
const byPerson = new Map();
|
|
369
|
+
for (const p of punches) {
|
|
370
|
+
const id = people.get(p.user);
|
|
371
|
+
if (id === undefined)
|
|
372
|
+
continue;
|
|
373
|
+
const list = byPerson.get(id) ?? [];
|
|
374
|
+
list.push(toInstant(p.at));
|
|
375
|
+
byPerson.set(id, list);
|
|
376
|
+
}
|
|
377
|
+
for (const [employee, times] of byPerson) {
|
|
378
|
+
const [e] = await env
|
|
379
|
+
.model('hr.employee')
|
|
380
|
+
.browse([employee])
|
|
381
|
+
.load({ company: true });
|
|
382
|
+
if (e === undefined)
|
|
383
|
+
continue;
|
|
384
|
+
const sorted = [...new Set(times.map((t) => t.getTime()))]
|
|
385
|
+
.sort((a, b) => a - b)
|
|
386
|
+
.map((t) => new Date(t));
|
|
387
|
+
const days = new Map();
|
|
388
|
+
for (const t of sorted) {
|
|
389
|
+
const d = localDate(t, tz);
|
|
390
|
+
days.set(d, [...(days.get(d) ?? []), t]);
|
|
391
|
+
}
|
|
392
|
+
const dates = [...days.keys()].sort();
|
|
393
|
+
for (const date of dates) {
|
|
394
|
+
const list = days.get(date);
|
|
395
|
+
for (let i = 0; i < list.length; i += 2) {
|
|
396
|
+
const checkIn = list[i];
|
|
397
|
+
const checkOut = list[i + 1] ?? null;
|
|
398
|
+
const exists = await env
|
|
399
|
+
.model('attendance.record')
|
|
400
|
+
.search({ where: { employee: employee, checkIn }, limit: 1 });
|
|
401
|
+
if (exists.length > 0) {
|
|
402
|
+
skipped += 1;
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
if (checkOut === null) {
|
|
406
|
+
const open = await env.model('attendance.record').search({
|
|
407
|
+
where: { employee: employee, checkOut: { isNull: true } },
|
|
408
|
+
limit: 1,
|
|
409
|
+
});
|
|
410
|
+
if (date !== dates[dates.length - 1] || open.length > 0) {
|
|
411
|
+
unpaired += 1;
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
await env
|
|
416
|
+
.model('attendance.record')
|
|
417
|
+
.create([
|
|
418
|
+
{ employee, company: e.company.id, checkIn, checkOut, source: 'device' },
|
|
419
|
+
]);
|
|
420
|
+
imported += 1;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
if (dates.length > 0)
|
|
424
|
+
touched.set(employee, { from: dates[0], to: dates[dates.length - 1] });
|
|
425
|
+
}
|
|
426
|
+
await env.flush();
|
|
427
|
+
for (const [employee, span] of touched)
|
|
428
|
+
await recomputeDays(env, [employee], span.from, span.to);
|
|
429
|
+
return { imported, skipped, unpaired, unknown };
|
|
430
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attendance's demo data (RFC 0008 §5.8): the head office as a site with its geofence, the General shift as Rahim's
|
|
3
|
+
* and Sumi's usual one, and their check-ins of the last working days — one late arrival, one evening of overtime —
|
|
4
|
+
* computed into days that wait for Dina's review.
|
|
5
|
+
*/
|
|
6
|
+
import type { DemoContext } from '../modules-sdk/index.js';
|
|
7
|
+
export declare function attendanceDemo(ctx: DemoContext): Promise<string>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { idByName } from '../modules-sdk/index.js';
|
|
2
|
+
import { instantOf, recomputeDays, timeZoneOf } from './days.js';
|
|
3
|
+
const DINA = { login: 'dina', name: 'Dina Rahman', groups: ['attendance.manager'] };
|
|
4
|
+
const RAHIM = { login: 'rahim', name: 'Rahim Uddin', groups: ['attendance.user'] };
|
|
5
|
+
const SUMI = { login: 'sumi', name: 'Sumi Begum', groups: ['attendance.user'] };
|
|
6
|
+
export async function attendanceDemo(ctx) {
|
|
7
|
+
const uid = async (user) => ctx.as(user, async (raw) => raw.userId);
|
|
8
|
+
const users = { rahim: await uid(RAHIM), sumi: await uid(SUMI) };
|
|
9
|
+
await ctx.as(DINA, async (raw) => {
|
|
10
|
+
const env = raw;
|
|
11
|
+
const general = await idByName(env, 'attendance.shift', 'General');
|
|
12
|
+
await env.model('attendance.site').create([
|
|
13
|
+
{
|
|
14
|
+
name: 'Head office',
|
|
15
|
+
latitude: '23.780600',
|
|
16
|
+
longitude: '90.407800',
|
|
17
|
+
radius: 200,
|
|
18
|
+
},
|
|
19
|
+
]);
|
|
20
|
+
const tz = await timeZoneOf(env);
|
|
21
|
+
const people = [];
|
|
22
|
+
for (const [name, user] of [
|
|
23
|
+
['Rahim Uddin', users.rahim],
|
|
24
|
+
['Sumi Begum', users.sumi],
|
|
25
|
+
]) {
|
|
26
|
+
const found = await env.model('hr.employee').search({ where: { user }, limit: 1 });
|
|
27
|
+
const id = found.ids[0] ?? (await env.model('hr.employee').create([{ name, user }])).ids[0];
|
|
28
|
+
if (id === undefined)
|
|
29
|
+
continue;
|
|
30
|
+
await env
|
|
31
|
+
.model('hr.employee')
|
|
32
|
+
.browse([id])
|
|
33
|
+
.write({ attendanceShift: general });
|
|
34
|
+
people.push(id);
|
|
35
|
+
}
|
|
36
|
+
// Five weekdays back: Rahim late on the first, Sumi two hours over on the second.
|
|
37
|
+
const days = [-5, -4, -3].map((d) => ctx.date(d));
|
|
38
|
+
for (const [i, date] of days.entries())
|
|
39
|
+
for (const [p, employee] of people.entries()) {
|
|
40
|
+
const late = p === 0 && i === 0 ? 35 : 0;
|
|
41
|
+
const over = p === 1 && i === 1 ? 120 : 0;
|
|
42
|
+
await env.model('attendance.record').create([
|
|
43
|
+
{
|
|
44
|
+
employee,
|
|
45
|
+
checkIn: instantOf(date, 9 * 60 - 5 + late, tz),
|
|
46
|
+
checkOut: instantOf(date, 18 * 60 + 2 + over, tz),
|
|
47
|
+
source: 'manual',
|
|
48
|
+
},
|
|
49
|
+
]);
|
|
50
|
+
}
|
|
51
|
+
await env.flush();
|
|
52
|
+
await env.asSuperuser({ reason: 'demo attendance days' }, async (su) => {
|
|
53
|
+
await recomputeDays(su, people, days[0], days[days.length - 1]);
|
|
54
|
+
await su.flush();
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
return 'Attendance: the head office site, the General shift, three days of check-ins to review.';
|
|
58
|
+
}
|