shutro-erp 0.3.4 → 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.
- package/dist/account_asset/.kosh/bindings.d.ts +22 -0
- package/dist/account_asset/.kosh/bindings.js +15 -0
- package/dist/account_asset/.kosh/schema.d.ts +1755 -0
- 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/index.d.ts +9 -0
- package/dist/account_asset/index.js +335 -0
- package/dist/account_asset/module.d.ts +7622 -0
- package/dist/account_asset/module.js +230 -0
- package/dist/account_budget/.kosh/bindings.d.ts +22 -0
- package/dist/account_budget/.kosh/bindings.js +15 -0
- package/dist/account_budget/.kosh/schema.d.ts +1767 -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/index.d.ts +4 -0
- package/dist/account_budget/index.js +223 -0
- package/dist/account_budget/module.d.ts +13863 -0
- package/dist/account_budget/module.js +167 -0
- package/dist/account_portal/.kosh/bindings.js +1 -1
- package/dist/account_portal/.kosh/schema.d.ts +176 -6
- package/dist/account_portal/module.d.ts +505 -6
- package/dist/accounting/.kosh/bindings.js +1 -1
- package/dist/accounting/.kosh/schema.d.ts +176 -6
- package/dist/accounting/index.d.ts +1 -1
- package/dist/accounting/index.js +344 -4
- package/dist/accounting/module.d.ts +513 -5
- package/dist/accounting/module.js +55 -3
- package/dist/approvals/.kosh/bindings.d.ts +22 -0
- package/dist/approvals/.kosh/bindings.js +15 -0
- package/dist/approvals/.kosh/schema.d.ts +611 -0
- package/dist/approvals/index.d.ts +18 -0
- package/dist/approvals/index.js +302 -0
- package/dist/approvals/mails.d.ts +25 -0
- package/dist/approvals/mails.js +82 -0
- package/dist/approvals/module.d.ts +1 -0
- package/dist/approvals/module.js +12 -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/Mine.d.ts +7 -0
- package/dist/approvals/web/Mine.js +27 -0
- package/dist/approvals/web/index.d.ts +13 -0
- package/dist/approvals/web/index.js +22 -0
- package/dist/approvals/web/messages.d.ts +2 -0
- package/dist/approvals/web/messages.js +119 -0
- package/dist/approvals/web/shared.d.ts +59 -0
- package/dist/approvals/web/shared.js +46 -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 +1048 -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/index.d.ts +4 -0
- package/dist/attendance/index.js +513 -0
- package/dist/attendance/module.d.ts +3969 -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/calendar/.kosh/bindings.d.ts +22 -0
- package/dist/calendar/.kosh/bindings.js +15 -0
- package/dist/calendar/.kosh/schema.d.ts +795 -0
- package/dist/calendar/demo.d.ts +6 -0
- package/dist/calendar/demo.js +24 -0
- package/dist/calendar/index.d.ts +3 -0
- package/dist/calendar/index.js +291 -0
- package/dist/calendar/module.d.ts +1705 -0
- package/dist/calendar/module.js +180 -0
- package/dist/cli/init.js +80 -0
- package/dist/cli/templates.d.ts +1 -1
- package/dist/cli/templates.js +226 -0
- package/dist/contacts/.kosh/bindings.js +1 -1
- package/dist/contacts/.kosh/schema.d.ts +78 -3
- package/dist/contacts/demo.js +30 -1
- package/dist/contacts/index.d.ts +1 -1
- package/dist/contacts/index.js +155 -9
- package/dist/contacts/module.d.ts +338 -2
- package/dist/contacts/module.js +93 -5
- package/dist/crm/.kosh/bindings.d.ts +22 -0
- package/dist/crm/.kosh/bindings.js +15 -0
- package/dist/crm/.kosh/schema.d.ts +800 -0
- package/dist/crm/demo.d.ts +6 -0
- package/dist/crm/demo.js +45 -0
- package/dist/crm/index.d.ts +3 -0
- package/dist/crm/index.js +361 -0
- package/dist/crm/module.d.ts +1845 -0
- package/dist/crm/module.js +208 -0
- package/dist/documents/.kosh/bindings.d.ts +22 -0
- package/dist/documents/.kosh/bindings.js +15 -0
- package/dist/documents/.kosh/schema.d.ts +862 -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/index.d.ts +30 -0
- package/dist/documents/index.js +442 -0
- package/dist/documents/module.d.ts +2781 -0
- package/dist/documents/module.js +214 -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.d.ts +22 -0
- package/dist/event/.kosh/bindings.js +15 -0
- package/dist/event/.kosh/schema.d.ts +843 -0
- package/dist/event/demo.d.ts +6 -0
- package/dist/event/demo.js +65 -0
- package/dist/event/index.d.ts +14 -0
- package/dist/event/index.js +333 -0
- package/dist/event/mails.d.ts +15 -0
- package/dist/event/mails.js +112 -0
- package/dist/event/module.d.ts +2800 -0
- package/dist/event/module.js +323 -0
- package/dist/event/web/CheckInBox.d.ts +9 -0
- package/dist/event/web/CheckInBox.js +87 -0
- package/dist/event/web/index.d.ts +11 -0
- package/dist/event/web/index.js +16 -0
- package/dist/event/web/messages.d.ts +2 -0
- package/dist/event/web/messages.js +23 -0
- package/dist/event_account/.kosh/bindings.d.ts +22 -0
- package/dist/event_account/.kosh/bindings.js +15 -0
- package/dist/event_account/.kosh/schema.d.ts +1758 -0
- package/dist/event_account/index.d.ts +3 -0
- package/dist/event_account/index.js +28 -0
- package/dist/event_account/module.d.ts +7114 -0
- package/dist/event_account/module.js +90 -0
- package/dist/expense/.kosh/bindings.d.ts +22 -0
- package/dist/expense/.kosh/bindings.js +15 -0
- package/dist/expense/.kosh/schema.d.ts +1299 -0
- package/dist/expense/demo.d.ts +7 -0
- package/dist/expense/demo.js +69 -0
- package/dist/expense/index.d.ts +3 -0
- package/dist/expense/index.js +495 -0
- package/dist/expense/module.d.ts +4747 -0
- package/dist/expense/module.js +647 -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 +1936 -0
- package/dist/expense_account/index.d.ts +3 -0
- package/dist/expense_account/index.js +74 -0
- package/dist/expense_account/module.d.ts +9153 -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 +885 -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/index.d.ts +10 -0
- package/dist/helpdesk/index.js +461 -0
- package/dist/helpdesk/module.d.ts +2940 -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.d.ts +22 -0
- package/dist/hr/.kosh/bindings.js +15 -0
- package/dist/hr/.kosh/schema.d.ts +878 -0
- package/dist/hr/demo.d.ts +6 -0
- package/dist/hr/demo.js +60 -0
- package/dist/hr/index.d.ts +3 -0
- package/dist/hr/index.js +483 -0
- package/dist/hr/module.d.ts +2611 -0
- package/dist/hr/module.js +350 -0
- package/dist/l10n_bd/.kosh/bindings.js +1 -1
- package/dist/l10n_bd/.kosh/schema.d.ts +176 -6
- package/dist/l10n_bd/module.d.ts +505 -6
- 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 +2312 -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/index.d.ts +4 -0
- package/dist/l10n_bd_payroll/index.js +24 -0
- package/dist/l10n_bd_payroll/module.d.ts +12932 -0
- package/dist/l10n_bd_payroll/module.js +86 -0
- package/dist/l10n_in/.kosh/bindings.js +1 -1
- package/dist/l10n_in/.kosh/schema.d.ts +176 -6
- package/dist/l10n_in/module.d.ts +527 -7
- package/dist/mail/inbound/handle.js +6 -1
- package/dist/maintenance/.kosh/bindings.d.ts +22 -0
- package/dist/maintenance/.kosh/bindings.js +15 -0
- package/dist/maintenance/.kosh/schema.d.ts +911 -0
- package/dist/maintenance/demo.d.ts +6 -0
- package/dist/maintenance/demo.js +60 -0
- package/dist/maintenance/index.d.ts +3 -0
- package/dist/maintenance/index.js +422 -0
- package/dist/maintenance/module.d.ts +3545 -0
- package/dist/maintenance/module.js +446 -0
- package/dist/maintenance_stock/.kosh/bindings.d.ts +22 -0
- package/dist/maintenance_stock/.kosh/bindings.js +15 -0
- package/dist/maintenance_stock/.kosh/schema.d.ts +1446 -0
- package/dist/maintenance_stock/index.d.ts +9 -0
- package/dist/maintenance_stock/index.js +52 -0
- package/dist/maintenance_stock/module.d.ts +7675 -0
- package/dist/maintenance_stock/module.js +192 -0
- package/dist/modules-sdk/index.d.ts +1 -1
- package/dist/modules-sdk/manifest.d.ts +109 -2
- package/dist/modules-sdk/manifest.js +35 -1
- package/dist/mrp/.kosh/bindings.d.ts +22 -0
- package/dist/mrp/.kosh/bindings.js +15 -0
- package/dist/mrp/.kosh/schema.d.ts +1453 -0
- package/dist/mrp/demo.d.ts +7 -0
- package/dist/mrp/demo.js +42 -0
- package/dist/mrp/index.d.ts +3 -0
- package/dist/mrp/index.js +393 -0
- package/dist/mrp/module.d.ts +9335 -0
- package/dist/mrp/module.js +757 -0
- package/dist/mrp_account/.kosh/bindings.d.ts +22 -0
- package/dist/mrp_account/.kosh/bindings.js +15 -0
- package/dist/mrp_account/.kosh/schema.d.ts +2299 -0
- package/dist/mrp_account/index.d.ts +3 -0
- package/dist/mrp_account/index.js +22 -0
- package/dist/mrp_account/module.d.ts +23151 -0
- package/dist/mrp_account/module.js +123 -0
- package/dist/payment/.kosh/bindings.js +1 -1
- package/dist/payment/.kosh/schema.d.ts +178 -7
- package/dist/payment/index.d.ts +41 -0
- package/dist/payment/index.js +131 -74
- package/dist/payment/module.d.ts +569 -12
- package/dist/payment/module.js +19 -3
- package/dist/payment/settle.js +10 -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 +1390 -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/index.d.ts +230 -0
- package/dist/payroll/index.js +713 -0
- package/dist/payroll/module.d.ts +9390 -0
- 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 +2308 -0
- package/dist/payroll_account/index.d.ts +3 -0
- package/dist/payroll_account/index.js +40 -0
- package/dist/payroll_account/module.d.ts +12396 -0
- package/dist/payroll_account/module.js +256 -0
- package/dist/permissions/approvals.d.ts +131 -9
- package/dist/permissions/approvals.js +662 -57
- package/dist/permissions/index.d.ts +1 -1
- package/dist/permissions/index.js +2 -2
- package/dist/permissions/models.js +191 -12
- package/dist/permissions/routes.d.ts +6 -1
- package/dist/permissions/routes.js +37 -4
- package/dist/permissions/web/ApprovalPanel.d.ts +5 -4
- package/dist/permissions/web/ApprovalPanel.js +39 -13
- 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 +43 -0
- package/dist/portal/.kosh/bindings.js +1 -1
- package/dist/portal/.kosh/schema.d.ts +78 -3
- package/dist/portal/index.js +1 -1
- package/dist/portal/module.d.ts +166 -2
- package/dist/pos/.kosh/bindings.d.ts +22 -0
- package/dist/pos/.kosh/bindings.js +15 -0
- package/dist/pos/.kosh/schema.d.ts +1809 -0
- package/dist/pos/accounting.d.ts +10 -0
- package/dist/pos/accounting.js +149 -0
- package/dist/pos/demo.d.ts +6 -0
- package/dist/pos/demo.js +90 -0
- package/dist/pos/index.d.ts +9 -0
- package/dist/pos/index.js +353 -0
- package/dist/pos/module.d.ts +9783 -0
- package/dist/pos/module.js +423 -0
- package/dist/pos/routes.d.ts +39 -0
- package/dist/pos/routes.js +368 -0
- package/dist/pos/web/Register.d.ts +9 -0
- package/dist/pos/web/Register.js +252 -0
- package/dist/pos/web/index.d.ts +11 -0
- package/dist/pos/web/index.js +16 -0
- package/dist/pos/web/messages.d.ts +2 -0
- package/dist/pos/web/messages.js +87 -0
- package/dist/pos_stock/.kosh/bindings.d.ts +22 -0
- package/dist/pos_stock/.kosh/bindings.js +15 -0
- package/dist/pos_stock/.kosh/schema.d.ts +2208 -0
- package/dist/pos_stock/index.d.ts +9 -0
- package/dist/pos_stock/index.js +35 -0
- package/dist/pos_stock/module.d.ts +12803 -0
- package/dist/pos_stock/module.js +115 -0
- package/dist/product/.kosh/bindings.js +1 -1
- package/dist/product/.kosh/schema.d.ts +52 -1
- package/dist/product/index.js +94 -4
- package/dist/product/module.d.ts +45 -1
- package/dist/product/module.js +11 -3
- package/dist/project/.kosh/bindings.js +1 -1
- package/dist/project/.kosh/schema.d.ts +725 -3
- package/dist/project/index.d.ts +3 -1
- package/dist/project/index.js +1045 -18
- package/dist/project/module.d.ts +10168 -458
- package/dist/project/module.js +1578 -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 +2241 -0
- package/dist/project_account/index.d.ts +3 -0
- package/dist/project_account/index.js +27 -0
- package/dist/project_account/module.d.ts +11539 -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 +725 -3
- package/dist/project_portal/module.d.ts +5137 -119
- 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 +2320 -0
- package/dist/project_purchase/index.d.ts +9 -0
- package/dist/project_purchase/index.js +22 -0
- package/dist/project_purchase/module.d.ts +25147 -0
- package/dist/project_purchase/module.js +56 -0
- package/dist/purchase/.kosh/bindings.js +1 -1
- package/dist/purchase/.kosh/schema.d.ts +150 -6
- package/dist/purchase/index.js +163 -3
- package/dist/purchase/module.d.ts +228 -5
- package/dist/purchase/module.js +30 -3
- package/dist/purchase_account/.kosh/bindings.js +1 -1
- package/dist/purchase_account/.kosh/schema.d.ts +180 -8
- package/dist/purchase_account/index.js +27 -1
- package/dist/purchase_account/module.d.ts +591 -30
- package/dist/purchase_account/module.js +13 -2
- package/dist/purchase_portal/.kosh/bindings.js +1 -1
- package/dist/purchase_portal/.kosh/schema.d.ts +150 -6
- package/dist/purchase_portal/module.d.ts +372 -6
- package/dist/purchase_stock/.kosh/bindings.d.ts +22 -0
- package/dist/purchase_stock/.kosh/bindings.js +15 -0
- package/dist/purchase_stock/.kosh/schema.d.ts +1479 -0
- package/dist/purchase_stock/index.d.ts +7 -0
- package/dist/purchase_stock/index.js +98 -0
- package/dist/purchase_stock/module.d.ts +7535 -0
- package/dist/purchase_stock/module.js +380 -0
- package/dist/purchase_stock_account/.kosh/bindings.d.ts +22 -0
- package/dist/purchase_stock_account/.kosh/bindings.js +15 -0
- package/dist/purchase_stock_account/.kosh/schema.d.ts +2155 -0
- package/dist/purchase_stock_account/index.d.ts +3 -0
- package/dist/purchase_stock_account/index.js +24 -0
- package/dist/purchase_stock_account/module.d.ts +38015 -0
- package/dist/purchase_stock_account/module.js +168 -0
- package/dist/recruitment/.kosh/bindings.d.ts +22 -0
- package/dist/recruitment/.kosh/bindings.js +15 -0
- package/dist/recruitment/.kosh/schema.d.ts +991 -0
- package/dist/recruitment/demo.d.ts +6 -0
- package/dist/recruitment/demo.js +45 -0
- package/dist/recruitment/index.d.ts +3 -0
- package/dist/recruitment/index.js +385 -0
- package/dist/recruitment/module.d.ts +3249 -0
- package/dist/recruitment/module.js +194 -0
- package/dist/recruitment/web/HireButton.d.ts +9 -0
- package/dist/recruitment/web/HireButton.js +32 -0
- package/dist/recruitment/web/index.d.ts +11 -0
- package/dist/recruitment/web/index.js +16 -0
- package/dist/recruitment/web/messages.d.ts +2 -0
- package/dist/recruitment/web/messages.js +19 -0
- package/dist/reporting/documents.d.ts +5 -0
- package/dist/reporting/documents.js +28 -1
- package/dist/reporting/index.d.ts +1 -1
- package/dist/reporting/index.js +4 -2
- package/dist/reporting/models.js +9 -0
- package/dist/reporting/overviews.d.ts +16 -0
- package/dist/reporting/overviews.js +56 -0
- package/dist/reporting/routes-documents.js +1 -1
- package/dist/reporting/routes.js +138 -80
- package/dist/reporting/web/DashboardView.d.ts +11 -0
- package/dist/reporting/web/DashboardView.js +2 -2
- package/dist/reporting/web/DesignerView.js +5 -0
- package/dist/reporting/web/Overview.d.ts +9 -0
- package/dist/reporting/web/Overview.js +53 -0
- package/dist/reporting/web/index.d.ts +1 -0
- package/dist/reporting/web/index.js +4 -1
- package/dist/reporting/web/messages.js +9 -0
- package/dist/sale_account/.kosh/bindings.js +1 -1
- package/dist/sale_account/.kosh/schema.d.ts +181 -6
- package/dist/sale_account/index.js +22 -1
- package/dist/sale_account/module.d.ts +639 -38
- package/dist/sale_portal/.kosh/bindings.js +1 -1
- package/dist/sale_portal/.kosh/schema.d.ts +59 -3
- package/dist/sale_portal/module.d.ts +435 -5
- package/dist/sale_project/.kosh/bindings.js +1 -1
- package/dist/sale_project/.kosh/schema.d.ts +732 -3
- package/dist/sale_project/module.d.ts +5349 -208
- package/dist/sale_project/module.js +17 -1
- package/dist/sale_stock/.kosh/bindings.d.ts +22 -0
- package/dist/sale_stock/.kosh/bindings.js +15 -0
- package/dist/sale_stock/.kosh/schema.d.ts +1303 -0
- package/dist/sale_stock/index.d.ts +7 -0
- package/dist/sale_stock/index.js +84 -0
- package/dist/sale_stock/module.d.ts +7514 -0
- package/dist/sale_stock/module.js +146 -0
- package/dist/sales/.kosh/bindings.js +1 -1
- package/dist/sales/.kosh/schema.d.ts +59 -3
- package/dist/sales/index.js +195 -4
- package/dist/sales/module.d.ts +356 -3
- package/dist/sales/module.js +78 -3
- package/dist/server/api/metadata.d.ts +5 -0
- package/dist/server/api/metadata.js +5 -0
- package/dist/server/api/rest.js +64 -1
- package/dist/server/api/views.js +1 -0
- package/dist/server/app-settings.d.ts +7 -0
- package/dist/server/app-settings.js +10 -0
- package/dist/server/auth/base.js +9 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +1 -0
- package/dist/settings/app-settings.d.ts +2 -0
- package/dist/settings/app-settings.js +518 -0
- package/dist/settings/index.d.ts +1 -0
- package/dist/settings/index.js +15 -0
- package/dist/settings/people.js +29 -5
- package/dist/settings/web/AppSettingsPage.d.ts +11 -0
- package/dist/settings/web/AppSettingsPage.js +210 -0
- package/dist/settings/web/OverviewPage.js +16 -3
- package/dist/settings/web/PeoplePage.js +20 -6
- package/dist/settings/web/index.d.ts +1 -0
- package/dist/settings/web/index.js +3 -0
- package/dist/settings/web/messages.js +118 -2
- package/dist/sign/.kosh/bindings.d.ts +22 -0
- package/dist/sign/.kosh/bindings.js +15 -0
- package/dist/sign/.kosh/schema.d.ts +990 -0
- package/dist/sign/index.d.ts +14 -0
- package/dist/sign/index.js +350 -0
- package/dist/sign/module.d.ts +4478 -0
- package/dist/sign/module.js +158 -0
- package/dist/sign/sign.d.ts +82 -0
- package/dist/sign/sign.js +474 -0
- package/dist/stock/.kosh/bindings.d.ts +22 -0
- package/dist/stock/.kosh/bindings.js +15 -0
- package/dist/stock/.kosh/schema.d.ts +1222 -0
- package/dist/stock/demo.d.ts +8 -0
- package/dist/stock/demo.js +82 -0
- package/dist/stock/index.d.ts +4 -0
- package/dist/stock/index.js +903 -0
- package/dist/stock/module.d.ts +7856 -0
- package/dist/stock/module.js +1880 -0
- package/dist/stock/replenish.d.ts +38 -0
- package/dist/stock/replenish.js +176 -0
- package/dist/stock/web/Replenishment.d.ts +8 -0
- package/dist/stock/web/Replenishment.js +84 -0
- package/dist/stock/web/ScanBox.d.ts +8 -0
- package/dist/stock/web/ScanBox.js +90 -0
- package/dist/stock/web/index.d.ts +13 -0
- package/dist/stock/web/index.js +20 -0
- package/dist/stock/web/messages.d.ts +2 -0
- package/dist/stock/web/messages.js +77 -0
- package/dist/stock_account/.kosh/bindings.d.ts +22 -0
- package/dist/stock_account/.kosh/bindings.js +15 -0
- package/dist/stock_account/.kosh/schema.d.ts +2068 -0
- package/dist/stock_account/index.d.ts +3 -0
- package/dist/stock_account/index.js +140 -0
- package/dist/stock_account/module.d.ts +11523 -0
- package/dist/stock_account/module.js +339 -0
- package/dist/storage/attachments.d.ts +5 -0
- package/dist/storage/attachments.js +12 -1
- package/dist/storage/models.js +3 -0
- package/dist/storage/routes.js +13 -2
- package/dist/todo/.kosh/bindings.d.ts +22 -0
- package/dist/todo/.kosh/bindings.js +15 -0
- package/dist/todo/.kosh/schema.d.ts +732 -0
- package/dist/todo/demo.d.ts +6 -0
- package/dist/todo/demo.js +35 -0
- package/dist/todo/index.d.ts +3 -0
- package/dist/todo/index.js +187 -0
- package/dist/todo/module.d.ts +1180 -0
- package/dist/todo/module.js +130 -0
- package/dist/trade_finance/.kosh/bindings.d.ts +22 -0
- package/dist/trade_finance/.kosh/bindings.js +15 -0
- package/dist/trade_finance/.kosh/schema.d.ts +884 -0
- package/dist/trade_finance/demo.d.ts +6 -0
- package/dist/trade_finance/demo.js +63 -0
- package/dist/trade_finance/index.d.ts +3 -0
- package/dist/trade_finance/index.js +415 -0
- package/dist/trade_finance/module.d.ts +3779 -0
- package/dist/trade_finance/module.js +507 -0
- package/dist/trade_finance_account/.kosh/bindings.d.ts +22 -0
- package/dist/trade_finance_account/.kosh/bindings.js +15 -0
- package/dist/trade_finance_account/.kosh/schema.d.ts +1830 -0
- package/dist/trade_finance_account/index.d.ts +3 -0
- package/dist/trade_finance_account/index.js +93 -0
- package/dist/trade_finance_account/module.d.ts +8074 -0
- package/dist/trade_finance_account/module.js +245 -0
- package/dist/trade_finance_purchase/.kosh/bindings.d.ts +22 -0
- package/dist/trade_finance_purchase/.kosh/bindings.js +15 -0
- package/dist/trade_finance_purchase/.kosh/schema.d.ts +1246 -0
- package/dist/trade_finance_purchase/index.d.ts +8 -0
- package/dist/trade_finance_purchase/index.js +50 -0
- package/dist/trade_finance_purchase/module.d.ts +4257 -0
- package/dist/trade_finance_purchase/module.js +44 -0
- package/dist/trade_finance_sale/.kosh/bindings.d.ts +22 -0
- package/dist/trade_finance_sale/.kosh/bindings.js +15 -0
- package/dist/trade_finance_sale/.kosh/schema.d.ts +1072 -0
- package/dist/trade_finance_sale/index.d.ts +8 -0
- package/dist/trade_finance_sale/index.js +50 -0
- package/dist/trade_finance_sale/module.d.ts +4281 -0
- package/dist/trade_finance_sale/module.js +44 -0
- package/dist/ui/api.d.ts +2 -1
- package/dist/ui/api.js +2 -1
- package/dist/ui/app.js +26 -13
- package/dist/ui/components/AppIcon.js +30 -1
- package/dist/ui/components/primitives.d.ts +2 -0
- package/dist/ui/components/primitives.js +7 -1
- package/dist/ui/i18n/messages.d.ts +27 -0
- package/dist/ui/i18n/messages.js +46 -0
- package/dist/ui/index.d.ts +1 -0
- package/dist/ui/index.js +1 -0
- package/dist/ui/offline/queue.d.ts +5 -1
- package/dist/ui/offline/queue.js +2 -0
- package/dist/ui/registry.d.ts +5 -0
- package/dist/ui/shell/Home.js +55 -4
- package/dist/ui/views/FormView.js +102 -19
- package/dist/ui/views/KanbanView.d.ts +2 -0
- package/dist/ui/views/KanbanView.js +40 -3
- package/dist/ui/views/ListView.js +110 -11
- package/dist/ui/views/StatsRow.d.ts +14 -0
- package/dist/ui/views/StatsRow.js +88 -0
- package/dist/ui/views/widgets.d.ts +2 -1
- package/dist/ui/views/widgets.js +200 -1
- package/dist/views/builders.d.ts +19 -2
- package/dist/views/builders.js +21 -1
- package/dist/views/condition.d.ts +6 -0
- package/dist/views/condition.js +20 -0
- package/dist/views/documents.d.ts +8 -0
- package/dist/views/extend.d.ts +2 -2
- package/dist/views/extend.js +11 -1
- package/dist/views/index.d.ts +2 -2
- package/dist/views/index.js +2 -2
- package/dist/views/types.d.ts +52 -5
- package/dist/views/validate.js +39 -1
- package/dist/website/.kosh/bindings.d.ts +22 -0
- package/dist/website/.kosh/bindings.js +15 -0
- package/dist/website/.kosh/schema.d.ts +881 -0
- package/dist/website/demo.d.ts +6 -0
- package/dist/website/demo.js +115 -0
- package/dist/website/index.d.ts +9 -0
- package/dist/website/index.js +251 -0
- package/dist/website/module.d.ts +2987 -0
- package/dist/website/module.js +282 -0
- package/dist/website/render.d.ts +45 -0
- package/dist/website/render.js +102 -0
- package/dist/website/routes.d.ts +12 -0
- package/dist/website/routes.js +246 -0
- package/dist/website/web/PagePreview.d.ts +7 -0
- package/dist/website/web/PagePreview.js +33 -0
- package/dist/website/web/index.d.ts +11 -0
- package/dist/website/web/index.js +16 -0
- package/dist/website/web/messages.d.ts +2 -0
- package/dist/website/web/messages.js +15 -0
- package/dist/website_crm/.kosh/bindings.d.ts +22 -0
- package/dist/website_crm/.kosh/bindings.js +15 -0
- package/dist/website_crm/.kosh/schema.d.ts +967 -0
- package/dist/website_crm/index.d.ts +3 -0
- package/dist/website_crm/index.js +39 -0
- package/dist/website_crm/module.d.ts +2956 -0
- package/dist/website_crm/module.js +44 -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 +2284 -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/index.d.ts +49 -0
- package/dist/website_sale/index.js +538 -0
- package/dist/website_sale/module.d.ts +22027 -0
- package/dist/website_sale/module.js +397 -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 +649 -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 +2681 -0
- package/dist/website_sale_stock/index.d.ts +9 -0
- package/dist/website_sale_stock/index.js +20 -0
- package/dist/website_sale_stock/module.d.ts +24998 -0
- package/dist/website_sale_stock/module.js +28 -0
- package/package.json +200 -2
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The data layer of Helpdesk (RFC 0024 §2.4): teams with their members, business hours and how tickets are
|
|
3
|
+
* assigned; stages for each team's board; ticket types; SLA policies (a first reply and a resolution, in business
|
|
4
|
+
* hours, by team, priority and customer); canned replies; and tickets — open, waiting on the customer (the SLA clock
|
|
5
|
+
* paused), solved, closed — with their SLA deadlines and status, the customer's rating, and merging.
|
|
6
|
+
*
|
|
7
|
+
* Agents see their teams' tickets; Helpdesk managers every ticket; customers their own through the portal later.
|
|
8
|
+
* The SLA is refreshed by `sla.ts` (every few minutes on the server, and on request).
|
|
9
|
+
*/
|
|
10
|
+
import { contactsShutro } from '../contacts/index.js';
|
|
11
|
+
import { messagingShutro } from '../messaging/index.js';
|
|
12
|
+
import { orm } from '../server/orm.js';
|
|
13
|
+
import { defineModel, defineModule, f, record, records } from './.kosh/bindings.js';
|
|
14
|
+
const READ = ['read'];
|
|
15
|
+
const ALL = ['read', 'write', 'create', 'unlink'];
|
|
16
|
+
const me = { $env: 'uid' };
|
|
17
|
+
const HHMM = orm.sql `~ '^([01][0-9]|2[0-3]):[0-5][0-9]$'`;
|
|
18
|
+
export const PRIORITIES = { low: 'Low', normal: 'Normal', high: 'High', urgent: 'Urgent' };
|
|
19
|
+
/** A priority's rank, for “this priority or higher”. */
|
|
20
|
+
export const RANK = { low: 0, normal: 1, high: 2, urgent: 3 };
|
|
21
|
+
export const HelpdeskTeam = defineModel('helpdesk.team', {
|
|
22
|
+
label: 'Helpdesk team',
|
|
23
|
+
recName: 'name',
|
|
24
|
+
order: ['name asc'],
|
|
25
|
+
archivable: true,
|
|
26
|
+
companyScoped: { required: true },
|
|
27
|
+
access: { 'helpdesk.user': READ, 'helpdesk.manager': [...ALL, 'export', 'import'] },
|
|
28
|
+
fields: {
|
|
29
|
+
name: f.char({ required: true, translate: true }),
|
|
30
|
+
members: f.many2many('res.users', { relation: 'helpdesk_team_member', label: 'Agents' }),
|
|
31
|
+
assignment: f.selection({ manual: 'By hand', round_robin: 'In turn', load: 'To the least busy' }, {
|
|
32
|
+
required: true,
|
|
33
|
+
default: 'round_robin',
|
|
34
|
+
help: 'How new tickets get their agent: in turn among the agents, or to the one with the fewest open tickets.',
|
|
35
|
+
}),
|
|
36
|
+
open: f.char({ size: 5, required: true, default: '09:00', label: 'Opens (HH:MM)' }),
|
|
37
|
+
close: f.char({ size: 5, required: true, default: '18:00', label: 'Closes (HH:MM)' }),
|
|
38
|
+
weekend: f.selection({
|
|
39
|
+
fri_sat: 'Friday and Saturday',
|
|
40
|
+
sat_sun: 'Saturday and Sunday',
|
|
41
|
+
fri: 'Friday only',
|
|
42
|
+
none: 'None (every day)',
|
|
43
|
+
}, {
|
|
44
|
+
required: true,
|
|
45
|
+
default: 'fri_sat',
|
|
46
|
+
help: 'SLA targets count working hours only: from opening to closing, outside the weekend.',
|
|
47
|
+
}),
|
|
48
|
+
rating: f.boolean({
|
|
49
|
+
default: true,
|
|
50
|
+
label: 'Ask for a rating',
|
|
51
|
+
help: 'When a ticket is solved, its customer is asked to rate the help (one to five).',
|
|
52
|
+
}),
|
|
53
|
+
},
|
|
54
|
+
sqlConstraints: {
|
|
55
|
+
hours: {
|
|
56
|
+
check: orm.sql `open ${HHMM} AND close ${HHMM} AND close > open`,
|
|
57
|
+
message: 'Hours are written HH:MM, the closing after the opening.',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
export const HelpdeskStage = defineModel('helpdesk.stage', {
|
|
62
|
+
label: 'Ticket stage',
|
|
63
|
+
recName: 'name',
|
|
64
|
+
order: ['sequence asc', 'id asc'],
|
|
65
|
+
archivable: true,
|
|
66
|
+
access: { 'helpdesk.user': READ, 'helpdesk.manager': [...ALL, 'export', 'import'] },
|
|
67
|
+
fields: {
|
|
68
|
+
name: f.char({ required: true, translate: true }),
|
|
69
|
+
sequence: f.integer({ required: true, default: 10 }),
|
|
70
|
+
fold: f.boolean({ default: false, label: 'Folded on the board' }),
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
export const HelpdeskType = defineModel('helpdesk.type', {
|
|
74
|
+
label: 'Ticket type',
|
|
75
|
+
recName: 'name',
|
|
76
|
+
order: ['name asc'],
|
|
77
|
+
archivable: true,
|
|
78
|
+
access: { 'helpdesk.user': READ, 'helpdesk.manager': [...ALL, 'export', 'import'] },
|
|
79
|
+
fields: { name: f.char({ required: true, translate: true }) },
|
|
80
|
+
});
|
|
81
|
+
export const HelpdeskSla = defineModel('helpdesk.sla', {
|
|
82
|
+
label: 'SLA policy',
|
|
83
|
+
recName: 'name',
|
|
84
|
+
order: ['sequence asc', 'id asc'],
|
|
85
|
+
archivable: true,
|
|
86
|
+
companyScoped: { required: true },
|
|
87
|
+
tracking: ['firstReplyHours', 'resolveHours'],
|
|
88
|
+
access: { 'helpdesk.user': READ, 'helpdesk.manager': [...ALL, 'export', 'import'] },
|
|
89
|
+
fields: {
|
|
90
|
+
name: f.char({ required: true }),
|
|
91
|
+
sequence: f.integer({
|
|
92
|
+
required: true,
|
|
93
|
+
default: 10,
|
|
94
|
+
help: 'The first policy that matches a ticket applies.',
|
|
95
|
+
}),
|
|
96
|
+
team: f.many2one('helpdesk.team', { ondelete: 'cascade', help: 'Empty: every team.' }),
|
|
97
|
+
priority: f.selection(PRIORITIES, {
|
|
98
|
+
label: 'From priority',
|
|
99
|
+
help: 'Tickets of this priority or higher; empty: every priority.',
|
|
100
|
+
}),
|
|
101
|
+
partner: f.many2one('res.partner', {
|
|
102
|
+
ondelete: 'cascade',
|
|
103
|
+
label: 'Customer',
|
|
104
|
+
help: 'Empty: every customer.',
|
|
105
|
+
}),
|
|
106
|
+
firstReplyHours: f.decimal({
|
|
107
|
+
scale: 2,
|
|
108
|
+
required: true,
|
|
109
|
+
default: '4',
|
|
110
|
+
label: 'First reply within (hours)',
|
|
111
|
+
}),
|
|
112
|
+
resolveHours: f.decimal({
|
|
113
|
+
scale: 2,
|
|
114
|
+
required: true,
|
|
115
|
+
default: '24',
|
|
116
|
+
label: 'Solved within (hours)',
|
|
117
|
+
}),
|
|
118
|
+
},
|
|
119
|
+
sqlConstraints: {
|
|
120
|
+
positive: {
|
|
121
|
+
check: orm.sql `first_reply_hours > 0 AND resolve_hours >= first_reply_hours`,
|
|
122
|
+
message: 'Targets are positive, the resolution no sooner than the first reply.',
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
export const HelpdeskCanned = defineModel('helpdesk.canned', {
|
|
127
|
+
label: 'Canned reply',
|
|
128
|
+
recName: 'name',
|
|
129
|
+
order: ['name asc'],
|
|
130
|
+
archivable: true,
|
|
131
|
+
access: { 'helpdesk.user': READ, 'helpdesk.manager': [...ALL, 'export', 'import'] },
|
|
132
|
+
fields: {
|
|
133
|
+
name: f.char({ required: true, translate: true }),
|
|
134
|
+
body: f.text({
|
|
135
|
+
required: true,
|
|
136
|
+
translate: true,
|
|
137
|
+
help: 'Placeholders: {{customer}}, {{ticket}}, {{agent}} — filled in when used.',
|
|
138
|
+
}),
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
const TICKET_STATES = {
|
|
142
|
+
open: 'Open',
|
|
143
|
+
waiting: 'Waiting on the customer',
|
|
144
|
+
solved: 'Solved',
|
|
145
|
+
closed: 'Closed',
|
|
146
|
+
merged: 'Merged',
|
|
147
|
+
};
|
|
148
|
+
/** Writes `values` on the tickets as the system: the SLA bookkeeping of a transition. */
|
|
149
|
+
async function stamp(tickets, values) {
|
|
150
|
+
const { env, ids } = tickets;
|
|
151
|
+
await env.flush();
|
|
152
|
+
await env.asSuperuser({ reason: 'helpdesk ticket clock' }, async (su) => {
|
|
153
|
+
await su
|
|
154
|
+
.model('helpdesk.ticket')
|
|
155
|
+
.browse([...ids])
|
|
156
|
+
.write(values);
|
|
157
|
+
await su.flush();
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
export const HelpdeskTicket = defineModel('helpdesk.ticket', {
|
|
161
|
+
label: 'Ticket',
|
|
162
|
+
recName: 'name',
|
|
163
|
+
order: ['id desc'],
|
|
164
|
+
companyScoped: { required: true },
|
|
165
|
+
tracking: ['state', 'stage', 'assignee', 'priority', 'team'],
|
|
166
|
+
access: {
|
|
167
|
+
'helpdesk.user': [...ALL, 'export'],
|
|
168
|
+
'helpdesk.manager': [...ALL, 'export', 'import'],
|
|
169
|
+
},
|
|
170
|
+
rules: {
|
|
171
|
+
// Agents: the tickets of their teams, and the ones given to them.
|
|
172
|
+
teams: {
|
|
173
|
+
groups: ['helpdesk.user'],
|
|
174
|
+
perms: ['read', 'write', 'create'],
|
|
175
|
+
domain: {
|
|
176
|
+
or: [{ 'team.members': { any: { id: me } } }, { assignee: me }, { team: { isNull: true } }],
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
all: { groups: ['helpdesk.manager'], perms: [...ALL], domain: {} },
|
|
180
|
+
},
|
|
181
|
+
fields: {
|
|
182
|
+
name: f.char({ required: true, sequence: 'helpdesk.ticket', label: 'Reference' }),
|
|
183
|
+
subject: f.char({ required: true }),
|
|
184
|
+
description: f.text(),
|
|
185
|
+
team: f.many2one('helpdesk.team', { ondelete: 'restrict' }),
|
|
186
|
+
stage: f.many2one('helpdesk.stage', { ondelete: 'restrict' }),
|
|
187
|
+
type: f.many2one('helpdesk.type', { ondelete: 'set null' }),
|
|
188
|
+
partner: f.many2one('res.partner', { ondelete: 'set null', label: 'Customer' }),
|
|
189
|
+
email: f.char({
|
|
190
|
+
label: 'Customer email',
|
|
191
|
+
help: 'Where replies go when the customer is not a contact yet.',
|
|
192
|
+
}),
|
|
193
|
+
assignee: f.many2one('res.users', { ondelete: 'set null', label: 'Agent' }),
|
|
194
|
+
priority: f.selection(PRIORITIES, {
|
|
195
|
+
required: true,
|
|
196
|
+
default: 'normal',
|
|
197
|
+
help: 'Decides the SLA policy: a policy from a priority covers that one and the ones above.',
|
|
198
|
+
}),
|
|
199
|
+
sla: f.many2one('helpdesk.sla', { ondelete: 'set null', label: 'SLA policy' }),
|
|
200
|
+
firstReplyDeadline: f.datetime({ label: 'First reply by' }),
|
|
201
|
+
resolveDeadline: f.datetime({ label: 'Solved by' }),
|
|
202
|
+
firstRepliedAt: f.datetime({ label: 'First replied' }),
|
|
203
|
+
solvedAt: f.datetime({ label: 'Solved' }),
|
|
204
|
+
waitingSince: f.datetime({ label: 'Waiting since' }),
|
|
205
|
+
pausedMinutes: f.integer({
|
|
206
|
+
required: true,
|
|
207
|
+
default: 0,
|
|
208
|
+
label: 'Paused (working minutes)',
|
|
209
|
+
help: 'Time waiting on the customer: added to the resolution target.',
|
|
210
|
+
}),
|
|
211
|
+
slaStatus: f.selection({
|
|
212
|
+
none: 'No SLA',
|
|
213
|
+
on_track: 'On track',
|
|
214
|
+
at_risk: 'At risk',
|
|
215
|
+
breached: 'Breached',
|
|
216
|
+
met: 'Met',
|
|
217
|
+
}, {
|
|
218
|
+
required: true,
|
|
219
|
+
default: 'none',
|
|
220
|
+
label: 'SLA',
|
|
221
|
+
help: 'At risk: less than a fifth of the time left; breached: a target passed; met: solved in time.',
|
|
222
|
+
}),
|
|
223
|
+
mergedInto: f.many2one('helpdesk.ticket', { ondelete: 'set null', label: 'Merged into' }),
|
|
224
|
+
rating: f.integer({ label: 'Rating (1–5)' }),
|
|
225
|
+
ratingComment: f.text({ label: 'The customer’s comment' }),
|
|
226
|
+
ratingToken: f.char({
|
|
227
|
+
size: 64,
|
|
228
|
+
label: 'Rating link',
|
|
229
|
+
groups: { read: ['helpdesk.manager'], write: [] },
|
|
230
|
+
}),
|
|
231
|
+
state: f.state({
|
|
232
|
+
states: TICKET_STATES,
|
|
233
|
+
initial: 'open',
|
|
234
|
+
help: 'Waiting on the customer pauses the resolution clock; a customer’s reply resumes it.',
|
|
235
|
+
transitions: {
|
|
236
|
+
wait: {
|
|
237
|
+
from: ['open'],
|
|
238
|
+
to: 'waiting',
|
|
239
|
+
after: records('helpdesk.ticket', (tickets) => stamp(tickets, { waitingSince: new Date() })),
|
|
240
|
+
},
|
|
241
|
+
resume: {
|
|
242
|
+
from: ['waiting'],
|
|
243
|
+
to: 'open',
|
|
244
|
+
after: records('helpdesk.ticket', (tickets) => closePause(tickets)),
|
|
245
|
+
},
|
|
246
|
+
solve: {
|
|
247
|
+
from: ['open', 'waiting'],
|
|
248
|
+
to: 'solved',
|
|
249
|
+
after: records('helpdesk.ticket', async (tickets) => {
|
|
250
|
+
await closePause(tickets);
|
|
251
|
+
await stamp(tickets, { solvedAt: new Date() });
|
|
252
|
+
const env = tickets.env;
|
|
253
|
+
const { askRating } = await import('./sla.js');
|
|
254
|
+
await env.asSuperuser({ reason: 'helpdesk rating' }, (su) => askRating(su, tickets.ids));
|
|
255
|
+
for (const id of tickets.ids)
|
|
256
|
+
await env.emit('helpdesk.ticket.solved', { id });
|
|
257
|
+
}),
|
|
258
|
+
},
|
|
259
|
+
reopen: { from: ['solved'], to: 'open' },
|
|
260
|
+
close: { from: ['solved'], to: 'closed' },
|
|
261
|
+
merge: { from: ['open', 'waiting'], to: 'merged' },
|
|
262
|
+
},
|
|
263
|
+
}),
|
|
264
|
+
},
|
|
265
|
+
sqlConstraints: {
|
|
266
|
+
rating: {
|
|
267
|
+
check: orm.sql `rating IS NULL OR rating BETWEEN 1 AND 5`,
|
|
268
|
+
message: 'A rating is from one to five.',
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
});
|
|
272
|
+
/** Ends a waiting interval: its working minutes added to the pause. */
|
|
273
|
+
async function closePause(tickets) {
|
|
274
|
+
const { env, ids } = tickets;
|
|
275
|
+
await env.flush();
|
|
276
|
+
await env.asSuperuser({ reason: 'helpdesk ticket clock' }, async (su) => {
|
|
277
|
+
const { pausedSince } = await import('./sla.js');
|
|
278
|
+
for (const t of await su
|
|
279
|
+
.model('helpdesk.ticket')
|
|
280
|
+
.browse([...ids])
|
|
281
|
+
.load({ team: true })) {
|
|
282
|
+
if (t.waitingSince === null)
|
|
283
|
+
continue;
|
|
284
|
+
const minutes = await pausedSince(su, t, new Date());
|
|
285
|
+
await su
|
|
286
|
+
.model('helpdesk.ticket')
|
|
287
|
+
.browse([t.id])
|
|
288
|
+
.write({ waitingSince: null, pausedMinutes: t.pausedMinutes + minutes });
|
|
289
|
+
}
|
|
290
|
+
await su.flush();
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
export const helpdeskShutro = defineModule({
|
|
294
|
+
name: 'helpdesk',
|
|
295
|
+
version: '0.1.0',
|
|
296
|
+
depends: [contactsShutro, messagingShutro],
|
|
297
|
+
groups: [
|
|
298
|
+
orm.defineGroup({
|
|
299
|
+
code: 'helpdesk.user',
|
|
300
|
+
label: 'Helpdesk agent',
|
|
301
|
+
implies: ['contacts.user', 'messaging.user'],
|
|
302
|
+
}),
|
|
303
|
+
orm.defineGroup({
|
|
304
|
+
code: 'helpdesk.manager',
|
|
305
|
+
label: 'Helpdesk manager',
|
|
306
|
+
implies: ['helpdesk.user'],
|
|
307
|
+
}),
|
|
308
|
+
],
|
|
309
|
+
sequences: [
|
|
310
|
+
orm.defineSequence({
|
|
311
|
+
code: 'helpdesk.ticket',
|
|
312
|
+
prefix: 'HD/{year}/',
|
|
313
|
+
padding: 5,
|
|
314
|
+
reset: 'yearly',
|
|
315
|
+
}),
|
|
316
|
+
],
|
|
317
|
+
models: [HelpdeskTeam, HelpdeskStage, HelpdeskType, HelpdeskSla, HelpdeskCanned, HelpdeskTicket],
|
|
318
|
+
data: [
|
|
319
|
+
record('helpdesk.stage', 'stage_new', { name: 'New', sequence: 1 }, { noupdate: true }),
|
|
320
|
+
record('helpdesk.stage', 'stage_progress', { name: 'In progress', sequence: 2 }, { noupdate: true }),
|
|
321
|
+
record('helpdesk.stage', 'stage_done', { name: 'Done', sequence: 9, fold: true }, { noupdate: true }),
|
|
322
|
+
record('helpdesk.type', 'type_question', { name: 'Question' }, { noupdate: true }),
|
|
323
|
+
record('helpdesk.type', 'type_problem', { name: 'Problem' }, { noupdate: true }),
|
|
324
|
+
record('helpdesk.type', 'type_request', { name: 'Request' }, { noupdate: true }),
|
|
325
|
+
],
|
|
326
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpdesk's routes (RFC 0024 §2.4):
|
|
3
|
+
*
|
|
4
|
+
* - `POST /api/v1/helpdesk/refresh` managers: the SLA, assignment and resumption, now
|
|
5
|
+
* - `POST /api/v1/helpdesk/tickets/:id/merge` `{ into }`: the ticket's conversation moved into another, it
|
|
6
|
+
* marked merged (agents of both tickets' teams)
|
|
7
|
+
* - `GET /api/v1/helpdesk/tickets/:id/canned/:reply` a canned reply filled in for the ticket
|
|
8
|
+
* - `GET /api/v1/public/helpdesk/rate?token=&score=` the customer's rating from the emailed link, once (no sign-in,
|
|
9
|
+
* rate limited)
|
|
10
|
+
*/
|
|
11
|
+
import { type ModuleContext } from '../server/index.js';
|
|
12
|
+
export declare function registerHelpdeskRoutes(context: ModuleContext): void;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpdesk's routes (RFC 0024 §2.4):
|
|
3
|
+
*
|
|
4
|
+
* - `POST /api/v1/helpdesk/refresh` managers: the SLA, assignment and resumption, now
|
|
5
|
+
* - `POST /api/v1/helpdesk/tickets/:id/merge` `{ into }`: the ticket's conversation moved into another, it
|
|
6
|
+
* marked merged (agents of both tickets' teams)
|
|
7
|
+
* - `GET /api/v1/helpdesk/tickets/:id/canned/:reply` a canned reply filled in for the ticket
|
|
8
|
+
* - `GET /api/v1/public/helpdesk/rate?token=&score=` the customer's rating from the emailed link, once (no sign-in,
|
|
9
|
+
* rate limited)
|
|
10
|
+
*/
|
|
11
|
+
import { audit, HttpProblem } from '../server/index.js';
|
|
12
|
+
import { rate, refreshSla } from './sla.js';
|
|
13
|
+
const escapeHtml = (s) => s.replace(/[&<>"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[c]);
|
|
14
|
+
export function registerHelpdeskRoutes(context) {
|
|
15
|
+
const { app } = context;
|
|
16
|
+
app.post('/api/v1/helpdesk/refresh', async (request) => request.env(async (raw) => {
|
|
17
|
+
const env = raw;
|
|
18
|
+
if (!env.administrator && !env.groups.has('helpdesk.manager'))
|
|
19
|
+
throw new HttpProblem(403, 'access', 'Helpdesk managers', 'This needs the Helpdesk manager role.');
|
|
20
|
+
return env.asSuperuser({ reason: 'helpdesk refresh' }, async (su) => ({
|
|
21
|
+
tickets: await refreshSla(su),
|
|
22
|
+
}));
|
|
23
|
+
}, { write: true }));
|
|
24
|
+
app.post('/api/v1/helpdesk/tickets/:id/merge', async (request) => {
|
|
25
|
+
const id = Number(request.params.id);
|
|
26
|
+
const into = Number(request.body?.['into']);
|
|
27
|
+
if (!Number.isSafeInteger(into) || into === id)
|
|
28
|
+
throw new HttpProblem(422, 'invalid-merge', 'Merge into which ticket?', 'Give another ticket as `into`.');
|
|
29
|
+
return request.env(async (raw) => {
|
|
30
|
+
const env = raw;
|
|
31
|
+
// Both tickets as the agent sees them: their rules decide.
|
|
32
|
+
const both = await env
|
|
33
|
+
.model('helpdesk.ticket')
|
|
34
|
+
.search({ where: { id: { in: [id, into] } } });
|
|
35
|
+
if (both.length !== 2)
|
|
36
|
+
throw new HttpProblem(404, 'missing-record', 'Not found', 'Both tickets must be yours to see.');
|
|
37
|
+
return env.asSuperuser({ reason: 'helpdesk merge' }, async (su) => {
|
|
38
|
+
const [source] = await su
|
|
39
|
+
.model('helpdesk.ticket')
|
|
40
|
+
.browse([id])
|
|
41
|
+
.load(['name', 'state']);
|
|
42
|
+
const [target] = await su
|
|
43
|
+
.model('helpdesk.ticket')
|
|
44
|
+
.browse([into])
|
|
45
|
+
.load(['name', 'state']);
|
|
46
|
+
if (source === undefined ||
|
|
47
|
+
target === undefined ||
|
|
48
|
+
!['open', 'waiting'].includes(source.state))
|
|
49
|
+
throw new HttpProblem(409, 'not-open', 'Not open', 'Only an open ticket is merged.');
|
|
50
|
+
if (target.state === 'merged')
|
|
51
|
+
throw new HttpProblem(409, 'merged', 'Already merged', 'Merge into a ticket that is not merged itself.');
|
|
52
|
+
const messages = await su
|
|
53
|
+
.model('mail.message')
|
|
54
|
+
.search({ where: { resModel: 'helpdesk.ticket', resId: id } });
|
|
55
|
+
if (messages.length > 0)
|
|
56
|
+
await messages.write({ resId: into });
|
|
57
|
+
await su
|
|
58
|
+
.model('helpdesk.ticket')
|
|
59
|
+
.browse([id])
|
|
60
|
+
.write({ mergedInto: into });
|
|
61
|
+
await su.flush();
|
|
62
|
+
await su
|
|
63
|
+
.model('helpdesk.ticket')
|
|
64
|
+
.browse([id])
|
|
65
|
+
.merge();
|
|
66
|
+
await audit(env, {
|
|
67
|
+
kind: 'helpdesk.merged',
|
|
68
|
+
summary: `${source.name} merged into ${target.name}.`,
|
|
69
|
+
targetModel: 'helpdesk.ticket',
|
|
70
|
+
targetId: into,
|
|
71
|
+
ip: request.ip,
|
|
72
|
+
});
|
|
73
|
+
await su.flush();
|
|
74
|
+
return { id, into, moved: messages.length };
|
|
75
|
+
});
|
|
76
|
+
}, { write: true });
|
|
77
|
+
});
|
|
78
|
+
app.get('/api/v1/helpdesk/tickets/:id/canned/:reply', async (request) => {
|
|
79
|
+
const { id, reply } = request.params;
|
|
80
|
+
return request.env(async (raw) => {
|
|
81
|
+
const env = raw;
|
|
82
|
+
const [ticket] = await (await env.model('helpdesk.ticket').search({ where: { id: Number(id) }, limit: 1 })).load({ partner: true, assignee: true });
|
|
83
|
+
const [canned] = await (await env
|
|
84
|
+
.model('helpdesk.canned')
|
|
85
|
+
.search({ where: { id: Number(reply) }, limit: 1 })).load(['body']);
|
|
86
|
+
if (ticket === undefined || canned === undefined)
|
|
87
|
+
throw new HttpProblem(404, 'missing-record', 'Not found', 'No such ticket or canned reply.');
|
|
88
|
+
const fill = {
|
|
89
|
+
customer: ticket.partner?.name ?? ticket.email ?? '',
|
|
90
|
+
ticket: ticket.name,
|
|
91
|
+
agent: ticket.assignee?.name ?? '',
|
|
92
|
+
};
|
|
93
|
+
return {
|
|
94
|
+
text: canned.body.replace(/\{\{\s*(customer|ticket|agent)\s*\}\}/g, (_, k) => fill[k] ?? ''),
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
app.get('/api/v1/public/helpdesk/rate', { config: { auth: false } }, async (request, reply) => {
|
|
99
|
+
const q = request.query;
|
|
100
|
+
const token = typeof q.token === 'string' ? q.token : '';
|
|
101
|
+
const score = Number(q.score);
|
|
102
|
+
const comment = typeof q.comment === 'string' && q.comment.trim() !== '' ? q.comment.slice(0, 2000) : null;
|
|
103
|
+
const name = token.length < 20
|
|
104
|
+
? null
|
|
105
|
+
: await context.shutro.bootstrap({ reason: 'helpdesk rating' }, (env) =>
|
|
106
|
+
// The token names the ticket, whatever its company.
|
|
107
|
+
env.asSuperuser({ reason: 'helpdesk rating' }, (su) => rate(su.withFlags({ checkCompany: false }), token, score, comment)));
|
|
108
|
+
const text = name === null
|
|
109
|
+
? 'This link was used already, or is not valid.'
|
|
110
|
+
: `Thank you — your rating of ${'★'.repeat(score)} for ${name} is recorded.`;
|
|
111
|
+
return reply
|
|
112
|
+
.code(name === null ? 404 : 200)
|
|
113
|
+
.header('content-type', 'text/html; charset=utf-8')
|
|
114
|
+
.send(`<!doctype html><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>Rating</title><p style="font:16px system-ui;margin:3em auto;max-width:30em;text-align:center">${escapeHtml(text)}</p>`);
|
|
115
|
+
});
|
|
116
|
+
// The clock, every five minutes, company by company (off in the CLI and in tests).
|
|
117
|
+
if (process.env['KOSH_SCHEDULES'] === 'off')
|
|
118
|
+
return;
|
|
119
|
+
const run = async () => {
|
|
120
|
+
try {
|
|
121
|
+
const companies = await context.shutro.bootstrap({ reason: 'helpdesk clock' }, async (env) => (await env.model('res.company').search({})).ids);
|
|
122
|
+
for (const company of companies)
|
|
123
|
+
await context.shutro.bootstrap({ reason: 'helpdesk clock', company }, (env) => env.asSuperuser({ reason: 'helpdesk clock' }, (su) => refreshSla(su)));
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
app.log.error({ err: error }, 'helpdesk clock');
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
const timer = setInterval(() => void run(), 5 * 60_000);
|
|
130
|
+
timer.unref();
|
|
131
|
+
app.addHook('onClose', async () => clearInterval(timer));
|
|
132
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Helpdesk clock (RFC 0024 §2.4), refreshed every few minutes on the server and on request:
|
|
3
|
+
*
|
|
4
|
+
* - each open ticket gets its **SLA policy** (the first, by sequence, of its team or every team, from its priority,
|
|
5
|
+
* for its customer or every customer) and its **deadlines** in the team's business hours — the first reply from
|
|
6
|
+
* the ticket's opening, the resolution pushed back by the time spent waiting on the customer;
|
|
7
|
+
* - the **first reply** is the first message (not a note) an agent posted on it;
|
|
8
|
+
* - a ticket waiting on the customer **resumes** when the customer writes back (a message by email);
|
|
9
|
+
* - unassigned tickets of teams that assign get their **agent**: in turn, or the one with the fewest open tickets;
|
|
10
|
+
* - the **status**: met (solved in time), breached (a target passed), at risk (less than a fifth left), on track.
|
|
11
|
+
*
|
|
12
|
+
* A solved ticket asks its customer for a **rating** through a link (`/api/v1/public/helpdesk/rate`).
|
|
13
|
+
*/
|
|
14
|
+
import { orm } from '../server/orm.js';
|
|
15
|
+
import type { Env } from './.kosh/bindings.js';
|
|
16
|
+
import { type Hours } from './hours.js';
|
|
17
|
+
/** The installation's time zone for business hours (App settings › Helpdesk). */
|
|
18
|
+
export declare function timeZoneOf(env: Env): Promise<string>;
|
|
19
|
+
interface TeamHours {
|
|
20
|
+
readonly open: string;
|
|
21
|
+
readonly close: string;
|
|
22
|
+
readonly weekend: string;
|
|
23
|
+
}
|
|
24
|
+
/** A team's business hours; without a team, every day from 09:00 to 18:00. */
|
|
25
|
+
export declare function hoursOf(env: Env, team: TeamHours | null): Promise<Hours>;
|
|
26
|
+
/** The working minutes a ticket has been waiting on the customer, up to `now`. */
|
|
27
|
+
export declare function pausedSince(env: Env, ticket: {
|
|
28
|
+
readonly waitingSince: Date | null;
|
|
29
|
+
readonly team: TeamHours | null;
|
|
30
|
+
}, now: Date): Promise<number>;
|
|
31
|
+
/** Refreshes the tickets given (every open, waiting and just-solved ticket when none). */
|
|
32
|
+
export declare function refreshSla(env: Env, ids?: readonly number[], now?: Date): Promise<number>;
|
|
33
|
+
/** Solved tickets of teams that ask: a rating link for the customer, sent by email when a mailer is set. */
|
|
34
|
+
export declare function askRating(env: Env, ids: readonly number[]): Promise<void>;
|
|
35
|
+
/** A rating from the link, once. @returns the ticket's reference, or `null` for an unknown or used link */
|
|
36
|
+
export declare function rate(env: Env, token: string, score: number, comment: string | null): Promise<string | null>;
|
|
37
|
+
export { orm };
|