shutro-erp 0.3.3 → 0.3.5
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_portal/.kosh/bindings.js +1 -1
- package/dist/account_portal/.kosh/schema.d.ts +181 -3
- package/dist/account_portal/module.d.ts +359 -6
- package/dist/accounting/.kosh/bindings.js +1 -1
- package/dist/accounting/.kosh/schema.d.ts +181 -3
- package/dist/accounting/index.js +214 -2
- package/dist/accounting/module.d.ts +217 -5
- package/dist/accounting/module.js +23 -2
- 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 +48 -0
- package/dist/cli/templates.d.ts +1 -1
- package/dist/cli/templates.js +137 -0
- package/dist/contacts/.kosh/bindings.js +1 -1
- package/dist/contacts/.kosh/schema.d.ts +205 -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 +82 -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 +799 -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 +1843 -0
- package/dist/crm/module.js +207 -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 +1639 -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 +6968 -0
- package/dist/event_account/module.js +90 -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/integrations/index.js +12 -0
- package/dist/integrations/web/OAuthAppsPage.d.ts +9 -0
- package/dist/integrations/web/OAuthAppsPage.js +79 -0
- package/dist/integrations/web/index.d.ts +1 -0
- package/dist/integrations/web/index.js +3 -0
- package/dist/integrations/web/messages.js +58 -0
- package/dist/l10n_bd/.kosh/bindings.js +1 -1
- package/dist/l10n_bd/.kosh/schema.d.ts +181 -3
- package/dist/l10n_bd/module.d.ts +359 -6
- package/dist/l10n_in/.kosh/bindings.js +1 -1
- package/dist/l10n_in/.kosh/schema.d.ts +181 -3
- package/dist/l10n_in/module.d.ts +380 -7
- 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 +1371 -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 +6953 -0
- package/dist/maintenance_stock/module.js +192 -0
- package/dist/messaging/web/index.js +1 -1
- package/dist/modules-sdk/index.d.ts +1 -1
- package/dist/modules-sdk/manifest.d.ts +70 -0
- 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 +1378 -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 +392 -0
- package/dist/mrp/module.d.ts +8608 -0
- package/dist/mrp/module.js +695 -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 +2106 -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 +20840 -0
- package/dist/mrp_account/module.js +123 -0
- package/dist/notify/web/index.js +1 -1
- package/dist/payment/.kosh/bindings.js +1 -1
- package/dist/payment/.kosh/schema.d.ts +181 -3
- package/dist/payment/module.d.ts +359 -6
- package/dist/portal/.kosh/bindings.js +1 -1
- package/dist/portal/.kosh/schema.d.ts +205 -3
- 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 +1690 -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 +349 -0
- package/dist/pos/module.d.ts +9636 -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 +2015 -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 +11935 -0
- package/dist/pos_stock/module.js +115 -0
- package/dist/product/.kosh/bindings.js +1 -1
- package/dist/product/.kosh/schema.d.ts +178 -1
- package/dist/product/index.js +81 -4
- package/dist/product/module.d.ts +43 -1
- package/dist/product/module.js +9 -2
- package/dist/project/.kosh/bindings.js +1 -1
- package/dist/project/.kosh/schema.d.ts +181 -3
- package/dist/project/index.js +147 -7
- package/dist/project/module.d.ts +210 -2
- package/dist/project/module.js +52 -5
- package/dist/project_portal/.kosh/bindings.js +1 -1
- package/dist/project_portal/.kosh/schema.d.ts +181 -3
- package/dist/project_portal/module.d.ts +353 -4
- package/dist/purchase/.kosh/bindings.js +1 -1
- package/dist/purchase/.kosh/schema.d.ts +181 -3
- package/dist/purchase/index.js +163 -3
- package/dist/purchase/module.d.ts +215 -3
- package/dist/purchase/module.js +21 -3
- package/dist/purchase_account/.kosh/bindings.js +1 -1
- package/dist/purchase_account/.kosh/schema.d.ts +182 -3
- package/dist/purchase_account/index.js +26 -1
- package/dist/purchase_account/module.d.ts +393 -7
- package/dist/purchase_portal/.kosh/bindings.js +1 -1
- package/dist/purchase_portal/.kosh/schema.d.ts +181 -3
- package/dist/purchase_portal/module.d.ts +366 -5
- 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 +1310 -0
- package/dist/purchase_stock/index.d.ts +7 -0
- package/dist/purchase_stock/index.js +91 -0
- package/dist/purchase_stock/module.d.ts +6763 -0
- package/dist/purchase_stock/module.js +144 -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 +1959 -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 +35366 -0
- package/dist/purchase_stock_account/module.js +162 -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 +990 -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 +3247 -0
- package/dist/recruitment/module.js +193 -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 +186 -3
- package/dist/sale_account/index.js +22 -1
- package/dist/sale_account/module.d.ts +461 -7
- package/dist/sale_portal/.kosh/bindings.js +1 -1
- package/dist/sale_portal/.kosh/schema.d.ts +185 -3
- package/dist/sale_portal/module.d.ts +434 -5
- package/dist/sale_project/.kosh/bindings.js +1 -1
- package/dist/sale_project/.kosh/schema.d.ts +187 -3
- package/dist/sale_project/module.d.ts +476 -6
- 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 +1228 -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 +6791 -0
- package/dist/sale_stock/module.js +146 -0
- package/dist/sales/.kosh/bindings.js +1 -1
- package/dist/sales/.kosh/schema.d.ts +185 -3
- package/dist/sales/index.js +191 -4
- package/dist/sales/module.d.ts +355 -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 +85 -0
- package/dist/server/auth/oauth.d.ts +21 -0
- package/dist/server/auth/oauth.js +579 -0
- package/dist/server/auth/service.d.ts +4 -0
- package/dist/server/auth/service.js +17 -0
- package/dist/server/identity.d.ts +2 -0
- package/dist/server/images.d.ts +12 -0
- package/dist/server/images.js +139 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.js +2 -0
- package/dist/server/server.d.ts +4 -0
- package/dist/server/server.js +9 -1
- package/dist/settings/app-settings.d.ts +2 -0
- package/dist/settings/app-settings.js +518 -0
- package/dist/settings/company.js +3 -1
- package/dist/settings/index.d.ts +1 -0
- package/dist/settings/index.js +15 -0
- package/dist/settings/people.js +32 -6
- package/dist/settings/web/AppSettingsPage.d.ts +11 -0
- package/dist/settings/web/AppSettingsPage.js +210 -0
- package/dist/settings/web/CompaniesPage.js +2 -2
- package/dist/settings/web/CompanyPage.js +13 -2
- package/dist/settings/web/ConnectedAppsPage.d.ts +7 -0
- package/dist/settings/web/ConnectedAppsPage.js +33 -0
- package/dist/settings/web/OverviewPage.js +28 -4
- package/dist/settings/web/PeoplePage.js +23 -18
- package/dist/settings/web/ProfilePage.js +9 -7
- package/dist/settings/web/index.d.ts +2 -0
- package/dist/settings/web/index.js +8 -0
- package/dist/settings/web/messages.js +146 -2
- package/dist/stock/.kosh/bindings.d.ts +22 -0
- package/dist/stock/.kosh/bindings.js +15 -0
- package/dist/stock/.kosh/schema.d.ts +1147 -0
- package/dist/stock/demo.d.ts +7 -0
- package/dist/stock/demo.js +55 -0
- package/dist/stock/index.d.ts +3 -0
- package/dist/stock/index.js +674 -0
- package/dist/stock/module.d.ts +6330 -0
- package/dist/stock/module.js +1325 -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 +11 -0
- package/dist/stock/web/index.js +16 -0
- package/dist/stock/web/messages.d.ts +2 -0
- package/dist/stock/web/messages.js +25 -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 +1875 -0
- package/dist/stock_account/index.d.ts +3 -0
- package/dist/stock_account/index.js +130 -0
- package/dist/stock_account/module.d.ts +10655 -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 +413 -0
- package/dist/trade_finance/module.d.ts +3779 -0
- package/dist/trade_finance/module.js +505 -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 +1711 -0
- package/dist/trade_finance_account/index.d.ts +3 -0
- package/dist/trade_finance_account/index.js +92 -0
- package/dist/trade_finance_account/module.d.ts +7928 -0
- package/dist/trade_finance_account/module.js +244 -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 +1153 -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 +4252 -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 +1071 -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 +4280 -0
- package/dist/trade_finance_sale/module.js +44 -0
- package/dist/ui/api.d.ts +6 -1
- package/dist/ui/api.js +2 -1
- package/dist/ui/app.js +51 -17
- package/dist/ui/components/AppIcon.js +33 -1
- package/dist/ui/components/Avatar.d.ts +21 -0
- package/dist/ui/components/Avatar.js +71 -0
- package/dist/ui/components/primitives.d.ts +2 -0
- package/dist/ui/components/primitives.js +7 -1
- package/dist/ui/i18n/messages.d.ts +53 -0
- package/dist/ui/i18n/messages.js +98 -0
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.js +2 -0
- package/dist/ui/offline/queue.d.ts +5 -1
- package/dist/ui/offline/queue.js +2 -0
- package/dist/ui/registry.d.ts +12 -1
- package/dist/ui/registry.js +10 -1
- package/dist/ui/search/ViewTabs.d.ts +14 -0
- package/dist/ui/search/ViewTabs.js +42 -0
- package/dist/ui/shell/Consent.d.ts +5 -0
- package/dist/ui/shell/Consent.js +35 -0
- package/dist/ui/shell/Home.js +136 -16
- package/dist/ui/shell/Sidebar.js +15 -22
- package/dist/ui/views/FormView.js +98 -17
- package/dist/ui/views/KanbanView.d.ts +2 -0
- package/dist/ui/views/KanbanView.js +32 -3
- package/dist/ui/views/ListView.js +155 -31
- 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 +194 -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 +250 -0
- package/dist/website/module.d.ts +2987 -0
- package/dist/website/module.js +281 -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 +966 -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 +2955 -0
- package/dist/website_crm/module.js +44 -0
- package/package.json +118 -1
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The data layer of Counter (RFC 0021): shops with their payment methods, the cashier's sessions with opening and
|
|
3
|
+
* closing counts, and the orders sold at the counter — lines with taxes, several payments and the change given —
|
|
4
|
+
* each accepted once by the device's client id (sales queued offline arrive later, in order). What a closed session
|
|
5
|
+
* means to Stockroom and Accounting is the bridges' (`pos_stock`, `pos_account`).
|
|
6
|
+
*/
|
|
7
|
+
import { accountingShutro } from '../accounting/index.js';
|
|
8
|
+
import { contactsShutro } from '../contacts/index.js';
|
|
9
|
+
import { messagingShutro } from '../messaging/index.js';
|
|
10
|
+
import { productShutro } from '../product/index.js';
|
|
11
|
+
import { orm } from '../server/orm.js';
|
|
12
|
+
import { check, compute, defineModel, defineModule, f, method, records, } from './.kosh/bindings.js';
|
|
13
|
+
import { bookSessions } from './accounting.js';
|
|
14
|
+
const ALL = ['read', 'write', 'create', 'unlink'];
|
|
15
|
+
const me = { $env: 'uid' };
|
|
16
|
+
const ZERO = orm.toDecimal(0);
|
|
17
|
+
/** A monetary value's amount (a Money object or a plain Decimal), or null. */
|
|
18
|
+
export function amountOf(value) {
|
|
19
|
+
if (value === null || value === undefined)
|
|
20
|
+
return null;
|
|
21
|
+
if (typeof value === 'object' && 'amount' in value)
|
|
22
|
+
return value.amount;
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
export const PosShop = defineModel('pos.shop', {
|
|
26
|
+
label: 'Shop',
|
|
27
|
+
recName: 'name',
|
|
28
|
+
order: ['name asc'],
|
|
29
|
+
companyScoped: { required: true },
|
|
30
|
+
archivable: true,
|
|
31
|
+
access: { 'pos.cashier': ['read'], 'pos.manager': [...ALL, 'export'] },
|
|
32
|
+
fields: {
|
|
33
|
+
name: f.char({ required: true }),
|
|
34
|
+
/** Prices on the register include the taxes (a shop) or not (a wholesale counter). */
|
|
35
|
+
pricesIncludeTax: f.boolean({ default: true, label: 'Prices include taxes' }),
|
|
36
|
+
salesJournal: f.many2one('account.journal', { ondelete: 'restrict', label: 'Sales journal' }),
|
|
37
|
+
methods: f.one2many('pos.payment.method', 'shop', { label: 'Payment methods' }),
|
|
38
|
+
sessions: f.one2many('pos.session', 'shop'),
|
|
39
|
+
/** The receipt's footer line (thanks, the return policy). */
|
|
40
|
+
receiptFooter: f.char({ size: 200, label: 'Receipt footer' }),
|
|
41
|
+
/** Where a closing's cash difference goes (a gain or a loss); the income account otherwise. */
|
|
42
|
+
differenceAccount: f.many2one('account.account', {
|
|
43
|
+
ondelete: 'restrict',
|
|
44
|
+
label: 'Cash difference account',
|
|
45
|
+
}),
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
/** How a shop takes money: cash, a card terminal, mobile money, a transfer; each to its journal. */
|
|
49
|
+
export const PosPaymentMethod = defineModel('pos.payment.method', {
|
|
50
|
+
label: 'Payment method',
|
|
51
|
+
recName: 'name',
|
|
52
|
+
order: ['sequence asc', 'id asc'],
|
|
53
|
+
archivable: true,
|
|
54
|
+
access: { 'pos.cashier': ['read'], 'pos.manager': ALL },
|
|
55
|
+
fields: {
|
|
56
|
+
shop: f.many2one('pos.shop', { required: true, ondelete: 'cascade' }),
|
|
57
|
+
name: f.char({ required: true }),
|
|
58
|
+
kind: f.selection({ cash: 'Cash', card: 'Card', mobile: 'Mobile money', transfer: 'Bank transfer' }, { required: true, default: 'cash' }),
|
|
59
|
+
journal: f.many2one('account.journal', { ondelete: 'restrict' }),
|
|
60
|
+
sequence: f.integer({ required: true, default: 10 }),
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
export const PosSession = defineModel('pos.session', {
|
|
64
|
+
label: 'Session',
|
|
65
|
+
recName: 'name',
|
|
66
|
+
order: ['id desc'],
|
|
67
|
+
companyScoped: { required: true },
|
|
68
|
+
tracking: ['state', 'cashier', 'closingDifference'],
|
|
69
|
+
access: { 'pos.cashier': ['read', 'write', 'create'], 'pos.manager': [...ALL, 'export'] },
|
|
70
|
+
rules: {
|
|
71
|
+
// Cashiers see and work in their own sessions; managers every session.
|
|
72
|
+
own: { groups: ['pos.cashier'], perms: ['read', 'write', 'create'], domain: { cashier: me } },
|
|
73
|
+
all: { groups: ['pos.manager'], perms: [...ALL], domain: {} },
|
|
74
|
+
},
|
|
75
|
+
fields: {
|
|
76
|
+
name: f.char({ required: true, sequence: 'pos.session' }),
|
|
77
|
+
shop: f.many2one('pos.shop', { required: true, ondelete: 'restrict' }),
|
|
78
|
+
cashier: f.many2one('res.users', { required: true, default: (env) => env.userId }),
|
|
79
|
+
openedAt: f.datetime({ required: true, default: () => new Date(), label: 'Opened' }),
|
|
80
|
+
closedAt: f.datetime({ label: 'Closed' }),
|
|
81
|
+
/** The cash in the drawer when the session opened. */
|
|
82
|
+
openingCash: f.decimal({ scale: 2, required: true, default: '0', label: 'Opening cash' }),
|
|
83
|
+
/** The cash counted when closing. */
|
|
84
|
+
closingCash: f.decimal({ scale: 2, label: 'Closing cash counted' }),
|
|
85
|
+
expectedCash: f.decimal({
|
|
86
|
+
scale: 2,
|
|
87
|
+
store: true,
|
|
88
|
+
label: 'Cash expected',
|
|
89
|
+
...compute('pos.session', 'expectedCash', [
|
|
90
|
+
'openingCash',
|
|
91
|
+
'orders.state',
|
|
92
|
+
'orders.change',
|
|
93
|
+
'orders.payments.amount',
|
|
94
|
+
'orders.payments.kind',
|
|
95
|
+
], (sessions) => {
|
|
96
|
+
for (const s of sessions) {
|
|
97
|
+
let cash = s.openingCash;
|
|
98
|
+
for (const o of s.orders) {
|
|
99
|
+
if (o.state !== 'paid')
|
|
100
|
+
continue;
|
|
101
|
+
for (const p of o.payments)
|
|
102
|
+
if (p.kind === 'cash')
|
|
103
|
+
cash = cash.plus(p.amount);
|
|
104
|
+
if (o.change !== null)
|
|
105
|
+
cash = cash.minus(o.change);
|
|
106
|
+
}
|
|
107
|
+
s.expectedCash = cash;
|
|
108
|
+
}
|
|
109
|
+
}),
|
|
110
|
+
}),
|
|
111
|
+
closingDifference: f.decimal({
|
|
112
|
+
scale: 2,
|
|
113
|
+
store: true,
|
|
114
|
+
label: 'Difference',
|
|
115
|
+
...compute('pos.session', 'closingDifference', ['closingCash', 'expectedCash'], (sessions) => {
|
|
116
|
+
for (const s of sessions)
|
|
117
|
+
s.closingDifference =
|
|
118
|
+
s.closingCash === null ? null : s.closingCash.minus(s.expectedCash ?? ZERO);
|
|
119
|
+
}),
|
|
120
|
+
}),
|
|
121
|
+
differenceReason: f.char({ size: 200, label: 'Difference explained' }),
|
|
122
|
+
/** The journal entry of the closed session (one per session; none without a sales journal). */
|
|
123
|
+
entry: f.many2one('account.move', { ondelete: 'set null', label: 'Journal entry' }),
|
|
124
|
+
orders: f.one2many('pos.order', 'session'),
|
|
125
|
+
orderCount: f.integer({
|
|
126
|
+
store: true,
|
|
127
|
+
label: 'Sales',
|
|
128
|
+
...compute('pos.session', 'orderCount', ['orders.state'], (sessions) => {
|
|
129
|
+
for (const s of sessions)
|
|
130
|
+
s.orderCount = [...s.orders].filter((o) => o.state === 'paid').length;
|
|
131
|
+
}),
|
|
132
|
+
}),
|
|
133
|
+
total: f.decimal({
|
|
134
|
+
scale: 2,
|
|
135
|
+
store: true,
|
|
136
|
+
label: 'Sold',
|
|
137
|
+
...compute('pos.session', 'total', ['orders.state', 'orders.total'], (sessions) => {
|
|
138
|
+
for (const s of sessions)
|
|
139
|
+
s.total = [...s.orders]
|
|
140
|
+
.filter((o) => o.state === 'paid')
|
|
141
|
+
.reduce((sum, o) => sum.plus(o.total ?? ZERO), ZERO);
|
|
142
|
+
}),
|
|
143
|
+
}),
|
|
144
|
+
state: f.state({
|
|
145
|
+
states: { open: 'Open', closed: 'Closed' },
|
|
146
|
+
initial: 'open',
|
|
147
|
+
transitions: {
|
|
148
|
+
close: {
|
|
149
|
+
from: ['open'],
|
|
150
|
+
to: 'closed',
|
|
151
|
+
guard: records('pos.session', async (sessions) => sessions.filter((s) => s.closingCash === null)),
|
|
152
|
+
message: 'Count the cash in the drawer before closing.',
|
|
153
|
+
before: records('pos.session', async (sessions) => {
|
|
154
|
+
const open = (await sessions.load({ orders: true })).filter((s) => [...s.orders].some((o) => o.state === 'draft'));
|
|
155
|
+
if (open.length > 0)
|
|
156
|
+
throw new orm.ValidationError('pos.session', ['state'], 'A sale is still being paid; finish or void it before closing.', 'Open the register and finish the sale.');
|
|
157
|
+
}),
|
|
158
|
+
after: records('pos.session', async (sessions) => {
|
|
159
|
+
await sessions.write({ closedAt: new Date() });
|
|
160
|
+
const env = sessions.env;
|
|
161
|
+
await env.flush();
|
|
162
|
+
// The entry reads journals, accounts and taxes a cashier may not: booked as the system, audited.
|
|
163
|
+
await env.asSuperuser({ reason: 'counter session books' }, (su) => bookSessions(su, sessions.ids));
|
|
164
|
+
await env.model('pos.session').browse(sessions.ids).closed();
|
|
165
|
+
}),
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
}),
|
|
169
|
+
},
|
|
170
|
+
methods: {
|
|
171
|
+
/** Runs once these sessions are closed. Nothing here; `pos_stock` and `pos_account` act on it. */
|
|
172
|
+
closed: method('pos.session', async () => undefined),
|
|
173
|
+
},
|
|
174
|
+
constraints: {
|
|
175
|
+
oneOpenPerCashier: {
|
|
176
|
+
...check('pos.session', ['cashier', 'state'], async (sessions) => {
|
|
177
|
+
const env = sessions.env;
|
|
178
|
+
const out = [];
|
|
179
|
+
for (const s of sessions) {
|
|
180
|
+
if (s.state !== 'open')
|
|
181
|
+
continue;
|
|
182
|
+
const others = await env.model('pos.session').search({
|
|
183
|
+
where: { cashier: s.cashier.id, state: 'open', id: { ne: s.id } },
|
|
184
|
+
limit: 1,
|
|
185
|
+
});
|
|
186
|
+
if (others.length > 0)
|
|
187
|
+
out.push(s.id);
|
|
188
|
+
}
|
|
189
|
+
return out;
|
|
190
|
+
}),
|
|
191
|
+
message: 'This cashier already has an open session; close it first.',
|
|
192
|
+
},
|
|
193
|
+
explainedDifference: {
|
|
194
|
+
...check('pos.session', ['closingDifference', 'differenceReason', 'state'], async (sessions) => sessions
|
|
195
|
+
.filter((s) => s.state === 'closed' &&
|
|
196
|
+
s.closingDifference !== null &&
|
|
197
|
+
!s.closingDifference.isZero() &&
|
|
198
|
+
(s.differenceReason === null || s.differenceReason.trim() === ''))
|
|
199
|
+
.map((s) => s.id)),
|
|
200
|
+
message: 'Say why the cash counted differs from the cash expected.',
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
/** Taxes of a line: percentages add up on the untaxed amount; fixed taxes per unit add to it. */
|
|
205
|
+
function taxesOnLine(untaxedOrGross, quantity, taxes, included) {
|
|
206
|
+
const percent = taxes
|
|
207
|
+
.filter((t) => t.amountType === 'percent')
|
|
208
|
+
.reduce((sum, t) => sum.plus(t.rate), ZERO);
|
|
209
|
+
const fixed = taxes
|
|
210
|
+
.filter((t) => t.amountType === 'fixed')
|
|
211
|
+
.reduce((sum, t) => sum.plus(t.fixedAmount.times(quantity)), ZERO);
|
|
212
|
+
if (!included) {
|
|
213
|
+
const tax = untaxedOrGross.times(percent).div(100).plus(fixed);
|
|
214
|
+
return { untaxed: untaxedOrGross, tax };
|
|
215
|
+
}
|
|
216
|
+
// The price holds the taxes: the untaxed part is what remains once the percentage and the fixed part are out.
|
|
217
|
+
const untaxed = untaxedOrGross.minus(fixed).times(100).div(percent.plus(100));
|
|
218
|
+
return {
|
|
219
|
+
untaxed: untaxed.toDecimalPlaces(2),
|
|
220
|
+
tax: untaxedOrGross.minus(untaxed.toDecimalPlaces(2)),
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
export const PosOrder = defineModel('pos.order', {
|
|
224
|
+
label: 'Sale',
|
|
225
|
+
recName: 'name',
|
|
226
|
+
order: ['id desc'],
|
|
227
|
+
companyScoped: { required: true },
|
|
228
|
+
tracking: ['state', 'total'],
|
|
229
|
+
access: { 'pos.cashier': ['read', 'write', 'create'], 'pos.manager': [...ALL, 'export'] },
|
|
230
|
+
rules: {
|
|
231
|
+
own: {
|
|
232
|
+
groups: ['pos.cashier'],
|
|
233
|
+
perms: ['read', 'write', 'create'],
|
|
234
|
+
domain: { 'session.cashier': me },
|
|
235
|
+
},
|
|
236
|
+
all: { groups: ['pos.manager'], perms: [...ALL], domain: {} },
|
|
237
|
+
},
|
|
238
|
+
fields: {
|
|
239
|
+
name: f.char({ required: true, sequence: 'pos.order' }),
|
|
240
|
+
session: f.many2one('pos.session', { required: true, ondelete: 'restrict' }),
|
|
241
|
+
/** The id the device gave the sale: a sale queued offline is accepted once. */
|
|
242
|
+
clientId: f.char({ size: 64, label: 'Device reference' }),
|
|
243
|
+
partner: f.many2one('res.partner', { ondelete: 'set null', label: 'Customer' }),
|
|
244
|
+
date: f.datetime({ required: true, default: () => new Date() }),
|
|
245
|
+
lines: f.one2many('pos.order.line', 'order'),
|
|
246
|
+
payments: f.one2many('pos.order.payment', 'order'),
|
|
247
|
+
/** Copied from the shop when the sale is made: how its prices were shown. */
|
|
248
|
+
pricesIncludeTax: f.boolean({ default: true, label: 'Prices include taxes' }),
|
|
249
|
+
/** The sale this one refunds, if any (its quantities are negative). */
|
|
250
|
+
refundOf: f.many2one('pos.order', { ondelete: 'set null', label: 'Refund of' }),
|
|
251
|
+
refunds: f.one2many('pos.order', 'refundOf'),
|
|
252
|
+
/** Why the customer brought it back (a refund). */
|
|
253
|
+
refundReason: f.char({ size: 200, label: 'Refund reason' }),
|
|
254
|
+
note: f.char({ size: 200 }),
|
|
255
|
+
amountUntaxed: f.decimal({
|
|
256
|
+
scale: 2,
|
|
257
|
+
store: true,
|
|
258
|
+
label: 'Untaxed',
|
|
259
|
+
...compute('pos.order', 'amountUntaxed', ['lines.subtotal'], (orders) => {
|
|
260
|
+
for (const o of orders)
|
|
261
|
+
o.amountUntaxed = [...o.lines].reduce((sum, l) => sum.plus(l.subtotal ?? ZERO), ZERO);
|
|
262
|
+
}),
|
|
263
|
+
}),
|
|
264
|
+
amountTax: f.decimal({
|
|
265
|
+
scale: 2,
|
|
266
|
+
store: true,
|
|
267
|
+
label: 'Taxes',
|
|
268
|
+
...compute('pos.order', 'amountTax', ['lines.taxAmount'], (orders) => {
|
|
269
|
+
for (const o of orders)
|
|
270
|
+
o.amountTax = [...o.lines].reduce((sum, l) => sum.plus(l.taxAmount ?? ZERO), ZERO);
|
|
271
|
+
}),
|
|
272
|
+
}),
|
|
273
|
+
total: f.decimal({
|
|
274
|
+
scale: 2,
|
|
275
|
+
store: true,
|
|
276
|
+
label: 'Total',
|
|
277
|
+
...compute('pos.order', 'total', ['amountUntaxed', 'amountTax'], (orders) => {
|
|
278
|
+
for (const o of orders)
|
|
279
|
+
o.total = (o.amountUntaxed ?? ZERO).plus(o.amountTax ?? ZERO);
|
|
280
|
+
}),
|
|
281
|
+
}),
|
|
282
|
+
amountPaid: f.decimal({
|
|
283
|
+
scale: 2,
|
|
284
|
+
store: true,
|
|
285
|
+
label: 'Paid',
|
|
286
|
+
...compute('pos.order', 'amountPaid', ['payments.amount'], (orders) => {
|
|
287
|
+
for (const o of orders)
|
|
288
|
+
o.amountPaid = [...o.payments].reduce((sum, p) => sum.plus(p.amount), ZERO);
|
|
289
|
+
}),
|
|
290
|
+
}),
|
|
291
|
+
/** What the cashier gives back when the payments exceed the total (cash only). */
|
|
292
|
+
change: f.decimal({
|
|
293
|
+
scale: 2,
|
|
294
|
+
store: true,
|
|
295
|
+
label: 'Change',
|
|
296
|
+
...compute('pos.order', 'change', ['amountPaid', 'total'], (orders) => {
|
|
297
|
+
for (const o of orders) {
|
|
298
|
+
const over = (o.amountPaid ?? ZERO).minus(o.total ?? ZERO);
|
|
299
|
+
o.change = over.gt(0) && (o.total ?? ZERO).gte(0) ? over : ZERO;
|
|
300
|
+
}
|
|
301
|
+
}),
|
|
302
|
+
}),
|
|
303
|
+
state: f.state({
|
|
304
|
+
states: { draft: 'Being paid', paid: 'Paid', void: 'Voided' },
|
|
305
|
+
initial: 'draft',
|
|
306
|
+
transitions: {
|
|
307
|
+
pay: {
|
|
308
|
+
from: ['draft'],
|
|
309
|
+
to: 'paid',
|
|
310
|
+
guard: records('pos.order', async (orders) => (await orders.load({ lines: true, session: true })).filter((o) => [...o.lines].length === 0 ||
|
|
311
|
+
((o.total ?? ZERO).gte(0)
|
|
312
|
+
? (o.amountPaid ?? ZERO).lt(o.total ?? ZERO)
|
|
313
|
+
: !(o.amountPaid ?? ZERO).eq(o.total ?? ZERO)) ||
|
|
314
|
+
o.session.state !== 'open')),
|
|
315
|
+
message: 'A sale is paid when its lines are in, the payments cover the total and the session is open.',
|
|
316
|
+
after: records('pos.order', async (orders) => {
|
|
317
|
+
for (const id of orders.ids)
|
|
318
|
+
await orders.env.emit('pos.order.paid', { id });
|
|
319
|
+
}),
|
|
320
|
+
},
|
|
321
|
+
void: { from: ['draft'], to: 'void' },
|
|
322
|
+
},
|
|
323
|
+
}),
|
|
324
|
+
},
|
|
325
|
+
sqlConstraints: {
|
|
326
|
+
oneClientId: {
|
|
327
|
+
unique: ['session', 'clientId'],
|
|
328
|
+
where: orm.sql `client_id IS NOT NULL`,
|
|
329
|
+
message: 'This sale was already received from the device.',
|
|
330
|
+
},
|
|
331
|
+
},
|
|
332
|
+
});
|
|
333
|
+
/** The untaxed amount and the tax of a line, from its price, quantity, discount, taxes and the shop's pricing. */
|
|
334
|
+
const lineAmounts = compute('pos.order.line', ['subtotal', 'taxAmount'], [
|
|
335
|
+
'quantity',
|
|
336
|
+
'priceUnit',
|
|
337
|
+
'discount',
|
|
338
|
+
'taxes.rate',
|
|
339
|
+
'taxes.amountType',
|
|
340
|
+
'taxes.fixedAmount',
|
|
341
|
+
'order.pricesIncludeTax',
|
|
342
|
+
], (lines) => {
|
|
343
|
+
for (const l of lines) {
|
|
344
|
+
const gross = l.priceUnit
|
|
345
|
+
.times(l.quantity)
|
|
346
|
+
.times(orm.toDecimal(100).minus(l.discount))
|
|
347
|
+
.div(100);
|
|
348
|
+
const { untaxed, tax } = taxesOnLine(gross, l.quantity, [...l.taxes], l.order.pricesIncludeTax === true);
|
|
349
|
+
l.subtotal = untaxed.toDecimalPlaces(2);
|
|
350
|
+
l.taxAmount = tax.toDecimalPlaces(2);
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
export const PosOrderLine = defineModel('pos.order.line', {
|
|
354
|
+
label: 'Sale line',
|
|
355
|
+
order: ['id asc'],
|
|
356
|
+
access: { 'pos.cashier': ['read', 'write', 'create', 'unlink'], 'pos.manager': ALL },
|
|
357
|
+
fields: {
|
|
358
|
+
order: f.many2one('pos.order', { required: true, ondelete: 'cascade' }),
|
|
359
|
+
product: f.many2one('product.product', { required: true, ondelete: 'restrict' }),
|
|
360
|
+
name: f.char({ required: true, label: 'Description' }),
|
|
361
|
+
quantity: f.decimal({ scale: 3, required: true, default: '1' }),
|
|
362
|
+
/** The unit price as shown on the register (taxes included when the shop's prices include them). */
|
|
363
|
+
priceUnit: f.decimal({ scale: 2, required: true, default: '0', label: 'Unit price' }),
|
|
364
|
+
discount: f.decimal({ scale: 2, required: true, default: '0', label: 'Discount %' }),
|
|
365
|
+
taxes: f.many2many('account.tax', { relation: 'pos_line_tax_rel' }),
|
|
366
|
+
subtotal: f.decimal({ scale: 2, store: true, label: 'Untaxed', ...lineAmounts }),
|
|
367
|
+
taxAmount: f.decimal({ scale: 2, store: true, label: 'Tax', ...lineAmounts }),
|
|
368
|
+
},
|
|
369
|
+
});
|
|
370
|
+
export const PosOrderPayment = defineModel('pos.order.payment', {
|
|
371
|
+
label: 'Payment',
|
|
372
|
+
order: ['id asc'],
|
|
373
|
+
access: { 'pos.cashier': ['read', 'write', 'create', 'unlink'], 'pos.manager': ALL },
|
|
374
|
+
fields: {
|
|
375
|
+
order: f.many2one('pos.order', { required: true, ondelete: 'cascade' }),
|
|
376
|
+
method: f.many2one('pos.payment.method', { required: true, ondelete: 'restrict' }),
|
|
377
|
+
amount: f.decimal({ scale: 2, required: true }),
|
|
378
|
+
/** The provider's or terminal's reference (a bKash transaction id, a card slip). */
|
|
379
|
+
reference: f.char({ size: 80 }),
|
|
380
|
+
/** The method's kind, kept on the payment so a session's cash adds up without a second hop. */
|
|
381
|
+
kind: f.selection({ cash: 'Cash', card: 'Card', mobile: 'Mobile money', transfer: 'Bank transfer' }, {
|
|
382
|
+
store: true,
|
|
383
|
+
...compute('pos.order.payment', 'kind', ['method.kind'], (payments) => {
|
|
384
|
+
for (const p of payments)
|
|
385
|
+
p.kind = p.method.kind;
|
|
386
|
+
}),
|
|
387
|
+
}),
|
|
388
|
+
},
|
|
389
|
+
constraints: {
|
|
390
|
+
methodOfTheShop: {
|
|
391
|
+
...check('pos.order.payment', ['method', 'order'], async (payments) => (await payments.load({ method: true, order: { session: true } }))
|
|
392
|
+
.filter((p) => p.method.shop.id !== p.order.session.shop.id)
|
|
393
|
+
.map((p) => p.id)),
|
|
394
|
+
message: 'The payment method belongs to another shop.',
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
});
|
|
398
|
+
export const posShutro = defineModule({
|
|
399
|
+
name: 'pos',
|
|
400
|
+
version: '0.1.0',
|
|
401
|
+
depends: [productShutro, contactsShutro, accountingShutro, messagingShutro],
|
|
402
|
+
groups: [
|
|
403
|
+
orm.defineGroup({
|
|
404
|
+
code: 'pos.cashier',
|
|
405
|
+
label: 'Counter cashier',
|
|
406
|
+
// Receipts are documents: cashiers read the templates.
|
|
407
|
+
implies: ['product.user', 'contacts.user', 'reporting.user'],
|
|
408
|
+
}),
|
|
409
|
+
orm.defineGroup({ code: 'pos.manager', label: 'Counter manager', implies: ['pos.cashier'] }),
|
|
410
|
+
],
|
|
411
|
+
permissions: [
|
|
412
|
+
orm.definePermission({
|
|
413
|
+
code: 'pos.refund_any',
|
|
414
|
+
label: 'Refund any sale (not only those of one’s own open session)',
|
|
415
|
+
groups: ['pos.manager'],
|
|
416
|
+
}),
|
|
417
|
+
],
|
|
418
|
+
sequences: [
|
|
419
|
+
orm.defineSequence({ code: 'pos.session', prefix: 'S/{year}/', padding: 5, reset: 'yearly' }),
|
|
420
|
+
orm.defineSequence({ code: 'pos.order', prefix: 'R/{year}/', padding: 6, reset: 'yearly' }),
|
|
421
|
+
],
|
|
422
|
+
models: [PosShop, PosPaymentMethod, PosSession, PosOrder, PosOrderLine, PosOrderPayment],
|
|
423
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Counter's routes (RFC 0021): what the register needs in few calls — the shop's catalogue, the cashier's open
|
|
3
|
+
* session, a sale posted whole (lines and payments, accepted once by its client id, paid at once), a session
|
|
4
|
+
* closed with its count.
|
|
5
|
+
*
|
|
6
|
+
* - `GET /api/v1/counter/shops` the shops the cashier may sell in, with their payment methods
|
|
7
|
+
* - `GET /api/v1/counter/catalogue?shop=` products for the register: price, taxes, barcode, picture
|
|
8
|
+
* - `GET /api/v1/counter/session?shop=` the cashier's open session at the shop, or null
|
|
9
|
+
* - `POST /api/v1/counter/sessions` `{ shop, openingCash }`: a session opened
|
|
10
|
+
* - `POST /api/v1/counter/orders` a sale: `{ session, clientId, partner?, lines, payments, note? }`
|
|
11
|
+
* - `POST /api/v1/counter/sessions/:id/close` `{ closingCash, differenceReason? }`: the count, then closed
|
|
12
|
+
*/
|
|
13
|
+
import { type Mailer } from '../mail/index.js';
|
|
14
|
+
import { type Messenger } from '../notify/index.js';
|
|
15
|
+
import { type ModuleContext } from '../server/index.js';
|
|
16
|
+
export interface SaleInput {
|
|
17
|
+
readonly session: number;
|
|
18
|
+
readonly clientId?: string;
|
|
19
|
+
readonly partner?: number | null;
|
|
20
|
+
readonly note?: string;
|
|
21
|
+
readonly lines: readonly {
|
|
22
|
+
readonly product: number;
|
|
23
|
+
readonly quantity: string;
|
|
24
|
+
readonly priceUnit?: string;
|
|
25
|
+
readonly discount?: string;
|
|
26
|
+
}[];
|
|
27
|
+
readonly payments: readonly {
|
|
28
|
+
readonly method: number;
|
|
29
|
+
readonly amount: string;
|
|
30
|
+
readonly reference?: string;
|
|
31
|
+
}[];
|
|
32
|
+
}
|
|
33
|
+
export interface CounterOptions {
|
|
34
|
+
/** Who sends receipts by email; default: SMTP from the environment (`SMTP_URL`), none without it. */
|
|
35
|
+
readonly mailer?: Mailer | undefined;
|
|
36
|
+
/** Who sends receipts by text; default: the messenger from the environment, none without it. */
|
|
37
|
+
readonly messenger?: Messenger | undefined;
|
|
38
|
+
}
|
|
39
|
+
export declare function registerCounterRoutes(context: ModuleContext, options?: CounterOptions): void;
|