shutro-erp 0.3.5 → 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/account_asset/.kosh/bindings.js +15 -0
- package/dist/{mrp_account → account_asset}/.kosh/schema.d.ts +785 -614
- package/dist/account_asset/board.d.ts +61 -0
- package/dist/account_asset/board.js +86 -0
- package/dist/account_asset/books.d.ts +42 -0
- package/dist/account_asset/books.js +398 -0
- package/dist/account_asset/demo.d.ts +7 -0
- package/dist/account_asset/demo.js +72 -0
- package/dist/account_asset/i18n/bn.d.ts +2 -0
- package/dist/account_asset/i18n/bn.js +97 -0
- package/dist/account_asset/index.d.ts +9 -0
- package/dist/account_asset/index.js +337 -0
- package/dist/account_asset/module.d.ts +11076 -0
- package/dist/account_asset/module.js +230 -0
- package/dist/account_budget/.kosh/bindings.js +15 -0
- package/dist/account_budget/.kosh/schema.d.ts +2841 -0
- package/dist/account_budget/budget.d.ts +5 -0
- package/dist/account_budget/budget.js +142 -0
- package/dist/account_budget/demo.d.ts +6 -0
- package/dist/account_budget/demo.js +30 -0
- package/dist/account_budget/i18n/bn.d.ts +2 -0
- package/dist/account_budget/i18n/bn.js +63 -0
- package/dist/account_budget/index.d.ts +4 -0
- package/dist/account_budget/index.js +237 -0
- package/dist/account_budget/module.d.ts +27289 -0
- package/dist/account_budget/module.js +182 -0
- package/dist/account_portal/.kosh/bindings.js +1 -1
- package/dist/account_portal/.kosh/schema.d.ts +651 -10
- package/dist/account_portal/i18n/bn.d.ts +2 -0
- package/dist/account_portal/i18n/bn.js +6 -0
- package/dist/account_portal/index.js +2 -0
- package/dist/account_portal/module.d.ts +5212 -1592
- package/dist/accounting/.kosh/bindings.js +1 -1
- package/dist/accounting/.kosh/schema.d.ts +651 -10
- package/dist/accounting/closing.js +1 -0
- package/dist/accounting/fiscal.d.ts +578 -0
- package/dist/accounting/fiscal.js +401 -0
- package/dist/accounting/followups.d.ts +618 -0
- package/dist/accounting/followups.js +420 -0
- package/dist/accounting/i18n/bn.d.ts +2 -0
- package/dist/accounting/i18n/bn.js +425 -0
- package/dist/accounting/index.d.ts +3 -1
- package/dist/accounting/index.js +780 -5
- package/dist/accounting/module.d.ts +5386 -1543
- package/dist/accounting/module.js +155 -18
- package/dist/accounting/statements.d.ts +878 -0
- package/dist/accounting/statements.js +728 -0
- package/dist/accounting/web/BankReconcilePage.d.ts +9 -0
- package/dist/accounting/web/BankReconcilePage.js +138 -0
- package/dist/accounting/web/FollowupsPage.d.ts +8 -0
- package/dist/accounting/web/FollowupsPage.js +54 -0
- package/dist/accounting/web/PostingPreview.d.ts +8 -0
- package/dist/accounting/web/PostingPreview.js +26 -0
- package/dist/accounting/web/index.d.ts +3 -0
- package/dist/accounting/web/index.js +9 -0
- package/dist/accounting/web/messages.js +140 -0
- package/dist/approvals/.kosh/bindings.d.ts +22 -0
- package/dist/approvals/.kosh/bindings.js +15 -0
- package/dist/approvals/.kosh/schema.d.ts +879 -0
- package/dist/approvals/demo.d.ts +7 -0
- package/dist/approvals/demo.js +41 -0
- package/dist/approvals/i18n/bn.d.ts +2 -0
- package/dist/approvals/i18n/bn.js +133 -0
- package/dist/approvals/index.d.ts +36 -0
- package/dist/approvals/index.js +772 -0
- package/dist/approvals/mails.d.ts +30 -0
- package/dist/approvals/mails.js +87 -0
- package/dist/approvals/module.d.ts +2930 -0
- package/dist/approvals/module.js +473 -0
- package/dist/approvals/web/Config.d.ts +12 -0
- package/dist/approvals/web/Config.js +60 -0
- package/dist/approvals/web/History.d.ts +4 -0
- package/dist/approvals/web/History.js +13 -0
- package/dist/approvals/web/Inbox.d.ts +9 -0
- package/dist/approvals/web/Inbox.js +114 -0
- package/dist/approvals/web/Matrix.d.ts +9 -0
- package/dist/approvals/web/Matrix.js +26 -0
- package/dist/approvals/web/Mine.d.ts +7 -0
- package/dist/approvals/web/Mine.js +27 -0
- package/dist/approvals/web/index.d.ts +15 -0
- package/dist/approvals/web/index.js +29 -0
- package/dist/approvals/web/messages.d.ts +2 -0
- package/dist/approvals/web/messages.js +211 -0
- package/dist/approvals/web/shared.d.ts +59 -0
- package/dist/approvals/web/shared.js +46 -0
- package/dist/approvals_purchase/.kosh/bindings.d.ts +22 -0
- package/dist/approvals_purchase/.kosh/bindings.js +15 -0
- package/dist/approvals_purchase/.kosh/schema.d.ts +1997 -0
- package/dist/approvals_purchase/i18n/bn.d.ts +2 -0
- package/dist/approvals_purchase/i18n/bn.js +5 -0
- package/dist/approvals_purchase/index.d.ts +3 -0
- package/dist/approvals_purchase/index.js +47 -0
- package/dist/approvals_purchase/module.d.ts +12670 -0
- package/dist/approvals_purchase/module.js +84 -0
- package/dist/attendance/.kosh/bindings.d.ts +22 -0
- package/dist/attendance/.kosh/bindings.js +15 -0
- package/dist/attendance/.kosh/schema.d.ts +1106 -0
- package/dist/attendance/days.d.ts +96 -0
- package/dist/attendance/days.js +430 -0
- package/dist/attendance/demo.d.ts +7 -0
- package/dist/attendance/demo.js +58 -0
- package/dist/attendance/i18n/bn.d.ts +2 -0
- package/dist/attendance/i18n/bn.js +147 -0
- package/dist/attendance/index.d.ts +4 -0
- package/dist/attendance/index.js +515 -0
- package/dist/attendance/module.d.ts +4413 -0
- package/dist/attendance/module.js +412 -0
- package/dist/attendance/routes.d.ts +16 -0
- package/dist/attendance/routes.js +266 -0
- package/dist/attendance/web/Check.d.ts +8 -0
- package/dist/attendance/web/Check.js +40 -0
- package/dist/attendance/web/Kiosk.d.ts +8 -0
- package/dist/attendance/web/Kiosk.js +62 -0
- package/dist/attendance/web/PinButton.d.ts +7 -0
- package/dist/attendance/web/PinButton.js +29 -0
- package/dist/attendance/web/index.d.ts +13 -0
- package/dist/attendance/web/index.js +22 -0
- package/dist/attendance/web/messages.d.ts +2 -0
- package/dist/attendance/web/messages.js +61 -0
- package/dist/automation/engine.js +1 -1
- package/dist/calendar/.kosh/bindings.js +1 -1
- package/dist/calendar/.kosh/schema.d.ts +2 -1
- package/dist/calendar/i18n/bn.d.ts +2 -0
- package/dist/calendar/i18n/bn.js +80 -0
- package/dist/calendar/index.js +77 -0
- package/dist/calendar/module.d.ts +26 -0
- package/dist/calendar/module.js +14 -4
- package/dist/cli/apps.js +25 -5
- package/dist/cli/init.js +46 -4
- package/dist/cli/templates.d.ts +1 -1
- package/dist/cli/templates.js +123 -5
- package/dist/contacts/.kosh/bindings.js +1 -1
- package/dist/contacts/.kosh/schema.d.ts +2 -1
- package/dist/contacts/i18n/bn.d.ts +2 -0
- package/dist/contacts/i18n/bn.js +67 -0
- package/dist/contacts/index.js +3 -0
- package/dist/contacts/module.d.ts +42 -0
- package/dist/contacts/module.js +19 -3
- package/dist/crm/.kosh/bindings.js +1 -1
- package/dist/crm/.kosh/schema.d.ts +3 -1
- package/dist/crm/i18n/bn.d.ts +2 -0
- package/dist/crm/i18n/bn.js +80 -0
- package/dist/crm/index.js +22 -0
- package/dist/crm/module.d.ts +22 -0
- package/dist/crm/module.js +6 -3
- package/dist/documents/.kosh/bindings.d.ts +22 -0
- package/dist/documents/.kosh/bindings.js +15 -0
- package/dist/documents/.kosh/schema.d.ts +863 -0
- package/dist/documents/demo.d.ts +6 -0
- package/dist/documents/demo.js +22 -0
- package/dist/documents/documents.d.ts +98 -0
- package/dist/documents/documents.js +318 -0
- package/dist/documents/i18n/bn.d.ts +2 -0
- package/dist/documents/i18n/bn.js +83 -0
- package/dist/documents/index.d.ts +30 -0
- package/dist/documents/index.js +569 -0
- package/dist/documents/module.d.ts +2801 -0
- package/dist/documents/module.js +215 -0
- package/dist/documents/web/Versions.d.ts +7 -0
- package/dist/documents/web/Versions.js +45 -0
- package/dist/documents/web/index.d.ts +11 -0
- package/dist/documents/web/index.js +16 -0
- package/dist/documents/web/messages.d.ts +2 -0
- package/dist/documents/web/messages.js +21 -0
- package/dist/event/.kosh/bindings.js +1 -1
- package/dist/event/.kosh/schema.d.ts +2 -1
- package/dist/event/i18n/bn.d.ts +2 -0
- package/dist/event/i18n/bn.js +101 -0
- package/dist/event/index.js +66 -0
- package/dist/event/module.d.ts +20 -0
- package/dist/event/module.js +8 -1
- package/dist/event_account/.kosh/bindings.js +1 -1
- package/dist/event_account/.kosh/schema.d.ts +651 -10
- package/dist/event_account/i18n/bn.d.ts +2 -0
- package/dist/event_account/i18n/bn.js +5 -0
- package/dist/event_account/index.js +2 -0
- package/dist/event_account/module.d.ts +5133 -1513
- package/dist/expense/.kosh/bindings.d.ts +22 -0
- package/dist/expense/.kosh/bindings.js +15 -0
- package/dist/expense/.kosh/schema.d.ts +1620 -0
- package/dist/expense/demo.d.ts +7 -0
- package/dist/expense/demo.js +69 -0
- package/dist/expense/i18n/bn.d.ts +2 -0
- package/dist/expense/i18n/bn.js +155 -0
- package/dist/expense/index.d.ts +3 -0
- package/dist/expense/index.js +502 -0
- package/dist/expense/module.d.ts +6768 -0
- package/dist/expense/module.js +649 -0
- package/dist/expense_account/.kosh/bindings.d.ts +22 -0
- package/dist/expense_account/.kosh/bindings.js +15 -0
- package/dist/expense_account/.kosh/schema.d.ts +2515 -0
- package/dist/expense_account/i18n/bn.d.ts +2 -0
- package/dist/expense_account/i18n/bn.js +15 -0
- package/dist/expense_account/index.d.ts +3 -0
- package/dist/expense_account/index.js +76 -0
- package/dist/expense_account/module.d.ts +14628 -0
- package/dist/expense_account/module.js +318 -0
- package/dist/helpdesk/.kosh/bindings.d.ts +22 -0
- package/dist/helpdesk/.kosh/bindings.js +15 -0
- package/dist/helpdesk/.kosh/schema.d.ts +886 -0
- package/dist/helpdesk/demo.d.ts +7 -0
- package/dist/helpdesk/demo.js +65 -0
- package/dist/helpdesk/hours.d.ts +17 -0
- package/dist/helpdesk/hours.js +94 -0
- package/dist/helpdesk/i18n/bn.d.ts +2 -0
- package/dist/helpdesk/i18n/bn.js +127 -0
- package/dist/helpdesk/index.d.ts +10 -0
- package/dist/helpdesk/index.js +463 -0
- package/dist/helpdesk/module.d.ts +2960 -0
- package/dist/helpdesk/module.js +326 -0
- package/dist/helpdesk/routes.d.ts +12 -0
- package/dist/helpdesk/routes.js +132 -0
- package/dist/helpdesk/sla.d.ts +37 -0
- package/dist/helpdesk/sla.js +226 -0
- package/dist/hr/.kosh/bindings.js +1 -1
- package/dist/hr/.kosh/schema.d.ts +59 -1
- package/dist/hr/demo.js +11 -1
- package/dist/hr/i18n/bn.d.ts +2 -0
- package/dist/hr/i18n/bn.js +126 -0
- package/dist/hr/index.d.ts +1 -1
- package/dist/hr/index.js +158 -12
- package/dist/hr/module.d.ts +932 -59
- package/dist/hr/module.js +114 -17
- package/dist/indent/.kosh/bindings.d.ts +22 -0
- package/dist/indent/.kosh/bindings.js +15 -0
- package/dist/indent/.kosh/schema.d.ts +2084 -0
- package/dist/indent/demo.d.ts +7 -0
- package/dist/indent/demo.js +48 -0
- package/dist/indent/i18n/bn.d.ts +2 -0
- package/dist/indent/i18n/bn.js +143 -0
- package/dist/indent/index.d.ts +3 -0
- package/dist/indent/index.js +450 -0
- package/dist/indent/module.d.ts +13424 -0
- package/dist/indent/module.js +792 -0
- package/dist/indent_purchase/.kosh/bindings.d.ts +22 -0
- package/dist/indent_purchase/.kosh/bindings.js +15 -0
- package/dist/indent_purchase/.kosh/schema.d.ts +2710 -0
- package/dist/indent_purchase/i18n/bn.d.ts +2 -0
- package/dist/indent_purchase/i18n/bn.js +13 -0
- package/dist/indent_purchase/index.d.ts +3 -0
- package/dist/indent_purchase/index.js +61 -0
- package/dist/indent_purchase/module.d.ts +27950 -0
- package/dist/indent_purchase/module.js +163 -0
- package/dist/l10n_bd/.kosh/bindings.js +1 -1
- package/dist/l10n_bd/.kosh/schema.d.ts +651 -10
- package/dist/l10n_bd/i18n/bn.d.ts +2 -0
- package/dist/l10n_bd/i18n/bn.js +69 -0
- package/dist/l10n_bd/index.js +2 -0
- package/dist/l10n_bd/module.d.ts +5212 -1592
- package/dist/l10n_bd_payroll/.kosh/bindings.d.ts +22 -0
- package/dist/l10n_bd_payroll/.kosh/bindings.js +15 -0
- package/dist/l10n_bd_payroll/.kosh/schema.d.ts +2891 -0
- package/dist/l10n_bd_payroll/data.d.ts +47 -0
- package/dist/l10n_bd_payroll/data.js +347 -0
- package/dist/l10n_bd_payroll/i18n/bn.d.ts +2 -0
- package/dist/l10n_bd_payroll/i18n/bn.js +4 -0
- package/dist/l10n_bd_payroll/index.d.ts +4 -0
- package/dist/l10n_bd_payroll/index.js +26 -0
- package/dist/l10n_bd_payroll/module.d.ts +17294 -0
- package/dist/l10n_bd_payroll/module.js +86 -0
- package/dist/l10n_bd_pos/.kosh/bindings.d.ts +22 -0
- package/dist/{mrp_account → l10n_bd_pos}/.kosh/bindings.js +2 -2
- package/dist/l10n_bd_pos/.kosh/schema.d.ts +2341 -0
- package/dist/l10n_bd_pos/i18n/bn.d.ts +2 -0
- package/dist/l10n_bd_pos/i18n/bn.js +32 -0
- package/dist/l10n_bd_pos/index.d.ts +3 -0
- package/dist/l10n_bd_pos/index.js +111 -0
- package/dist/{mrp_account → l10n_bd_pos}/module.d.ts +9047 -6981
- package/dist/l10n_bd_pos/module.js +43 -0
- package/dist/l10n_in/.kosh/bindings.js +1 -1
- package/dist/l10n_in/.kosh/schema.d.ts +651 -10
- package/dist/l10n_in/i18n/bn.d.ts +2 -0
- package/dist/l10n_in/i18n/bn.js +95 -0
- package/dist/l10n_in/index.js +2 -0
- package/dist/l10n_in/module.d.ts +6778 -1580
- package/dist/l10n_in/module.js +25 -5
- package/dist/l10n_in/web/GstSettings.js +2 -2
- package/dist/mail/inbound/handle.js +8 -5
- package/dist/mail/inbound/models.js +5 -3
- package/dist/mail/index.d.ts +12 -1
- package/dist/mail/index.js +139 -2
- package/dist/mail/send.d.ts +56 -0
- package/dist/mail/send.js +394 -0
- package/dist/mail/web/SendButton.d.ts +9 -0
- package/dist/mail/web/SendButton.js +71 -0
- package/dist/mail/web/SendSelected.d.ts +8 -0
- package/dist/mail/web/SendSelected.js +33 -0
- package/dist/mail/web/index.d.ts +2 -0
- package/dist/mail/web/index.js +6 -0
- package/dist/mail/web/messages.js +36 -0
- package/dist/maintenance/.kosh/bindings.js +1 -1
- package/dist/maintenance/.kosh/schema.d.ts +2 -1
- package/dist/maintenance/i18n/bn.d.ts +2 -0
- package/dist/maintenance/i18n/bn.js +132 -0
- package/dist/maintenance/index.js +85 -0
- package/dist/maintenance/module.d.ts +25 -0
- package/dist/maintenance/module.js +27 -9
- package/dist/maintenance_stock/.kosh/bindings.js +1 -1
- package/dist/maintenance_stock/.kosh/schema.d.ts +374 -3
- package/dist/maintenance_stock/i18n/bn.d.ts +2 -0
- package/dist/maintenance_stock/i18n/bn.js +21 -0
- package/dist/maintenance_stock/index.js +2 -0
- package/dist/maintenance_stock/module.d.ts +6095 -1327
- package/dist/maintenance_stock/module.js +1 -0
- package/dist/modules-sdk/apps.d.ts +10 -0
- package/dist/modules-sdk/apps.js +32 -0
- package/dist/modules-sdk/index.d.ts +1 -1
- package/dist/modules-sdk/manifest.d.ts +105 -2
- package/dist/payment/.kosh/bindings.js +1 -1
- package/dist/payment/.kosh/schema.d.ts +653 -11
- package/dist/payment/i18n/bn.d.ts +2 -0
- package/dist/payment/i18n/bn.js +59 -0
- package/dist/payment/index.d.ts +41 -0
- package/dist/payment/index.js +216 -74
- package/dist/payment/module.d.ts +5353 -1675
- package/dist/payment/module.js +36 -6
- package/dist/payment/settle.js +11 -1
- package/dist/payroll/.kosh/bindings.d.ts +22 -0
- package/dist/payroll/.kosh/bindings.js +15 -0
- package/dist/payroll/.kosh/schema.d.ts +1448 -0
- package/dist/payroll/compute.d.ts +35 -0
- package/dist/payroll/compute.js +398 -0
- package/dist/payroll/demo.d.ts +55 -0
- package/dist/payroll/demo.js +121 -0
- package/dist/payroll/formula.d.ts +62 -0
- package/dist/payroll/formula.js +320 -0
- package/dist/payroll/i18n/bn.d.ts +2 -0
- package/dist/payroll/i18n/bn.js +206 -0
- package/dist/payroll/index.d.ts +230 -0
- package/dist/payroll/index.js +715 -0
- package/dist/{mrp → payroll}/module.d.ts +4294 -2624
- package/dist/payroll/module.js +606 -0
- package/dist/payroll/routes.d.ts +10 -0
- package/dist/payroll/routes.js +112 -0
- package/dist/payroll_account/.kosh/bindings.d.ts +22 -0
- package/dist/payroll_account/.kosh/bindings.js +15 -0
- package/dist/payroll_account/.kosh/schema.d.ts +2887 -0
- package/dist/payroll_account/i18n/bn.d.ts +2 -0
- package/dist/payroll_account/i18n/bn.js +10 -0
- package/dist/payroll_account/index.d.ts +3 -0
- package/dist/payroll_account/index.js +42 -0
- package/dist/payroll_account/module.d.ts +16738 -0
- package/dist/payroll_account/module.js +256 -0
- package/dist/permissions/approvals.d.ts +227 -12
- package/dist/permissions/approvals.js +1421 -67
- package/dist/permissions/index.d.ts +1 -1
- package/dist/permissions/index.js +2 -2
- package/dist/permissions/models.js +364 -13
- package/dist/permissions/routes.d.ts +9 -1
- package/dist/permissions/routes.js +72 -5
- package/dist/permissions/web/ApprovalPanel.d.ts +5 -4
- package/dist/permissions/web/ApprovalPanel.js +75 -11
- package/dist/permissions/web/index.d.ts +6 -4
- package/dist/permissions/web/index.js +13 -4
- package/dist/permissions/web/messages.d.ts +2 -0
- package/dist/permissions/web/messages.js +95 -0
- package/dist/portal/.kosh/bindings.js +1 -1
- package/dist/portal/.kosh/schema.d.ts +2 -1
- package/dist/portal/documents.d.ts +3 -0
- package/dist/portal/documents.js +21 -1
- package/dist/portal/i18n/bn.d.ts +2 -0
- package/dist/portal/i18n/bn.js +33 -0
- package/dist/portal/index.js +3 -1
- package/dist/portal/module.d.ts +20 -0
- package/dist/portal/routes-documents.js +76 -0
- package/dist/pos/.kosh/bindings.js +1 -1
- package/dist/pos/.kosh/schema.d.ts +652 -10
- package/dist/pos/i18n/bn.d.ts +2 -0
- package/dist/pos/i18n/bn.js +133 -0
- package/dist/pos/index.js +87 -1
- package/dist/pos/module.d.ts +6967 -1709
- package/dist/pos/module.js +49 -5
- package/dist/pos/routes.js +80 -7
- package/dist/pos/web/Register.js +2 -5
- package/dist/pos_stock/.kosh/bindings.js +1 -1
- package/dist/pos_stock/.kosh/schema.d.ts +822 -12
- package/dist/pos_stock/i18n/bn.d.ts +2 -0
- package/dist/pos_stock/i18n/bn.js +6 -0
- package/dist/pos_stock/index.js +2 -0
- package/dist/pos_stock/module.d.ts +11241 -2851
- package/dist/product/.kosh/bindings.js +1 -1
- package/dist/product/.kosh/schema.d.ts +203 -1
- package/dist/product/i18n/bn.d.ts +2 -0
- package/dist/product/i18n/bn.js +175 -0
- package/dist/product/index.d.ts +1 -0
- package/dist/product/index.js +301 -1
- package/dist/product/module.d.ts +1727 -0
- package/dist/product/module.js +67 -6
- package/dist/product/pricelist.d.ts +575 -0
- package/dist/product/pricelist.js +257 -0
- package/dist/product/variants.d.ts +908 -0
- package/dist/product/variants.js +251 -0
- package/dist/production/.kosh/bindings.d.ts +22 -0
- package/dist/production/.kosh/bindings.js +15 -0
- package/dist/production/.kosh/schema.d.ts +2345 -0
- package/dist/{mrp → production}/demo.d.ts +1 -1
- package/dist/{mrp → production}/demo.js +5 -5
- package/dist/production/depth.d.ts +790 -0
- package/dist/production/depth.js +262 -0
- package/dist/production/i18n/bn.d.ts +2 -0
- package/dist/production/i18n/bn.js +350 -0
- package/dist/production/index.d.ts +6 -0
- package/dist/production/index.js +1256 -0
- package/dist/production/module.d.ts +17327 -0
- package/dist/production/module.js +1333 -0
- package/dist/production/plan.d.ts +921 -0
- package/dist/production/plan.js +511 -0
- package/dist/production/schedule.d.ts +656 -0
- package/dist/production/schedule.js +309 -0
- package/dist/production_account/.kosh/bindings.d.ts +22 -0
- package/dist/production_account/.kosh/bindings.js +15 -0
- package/dist/production_account/.kosh/schema.d.ts +3496 -0
- package/dist/production_account/i18n/bn.d.ts +2 -0
- package/dist/production_account/i18n/bn.js +93 -0
- package/dist/production_account/index.d.ts +4 -0
- package/dist/production_account/index.js +246 -0
- package/dist/production_account/module.d.ts +1192 -0
- package/dist/{mrp_account → production_account}/module.js +72 -18
- package/dist/production_account/overhead.d.ts +1195 -0
- package/dist/production_account/overhead.js +554 -0
- package/dist/project/.kosh/bindings.js +1 -1
- package/dist/project/.kosh/schema.d.ts +735 -1
- package/dist/project/i18n/bn.d.ts +2 -0
- package/dist/project/i18n/bn.js +383 -0
- package/dist/project/index.d.ts +3 -1
- package/dist/project/index.js +1024 -14
- package/dist/project/module.d.ts +9912 -390
- package/dist/project/module.js +1590 -14
- package/dist/project/routes.d.ts +44 -0
- package/dist/project/routes.js +314 -0
- package/dist/project/schedule.d.ts +72 -0
- package/dist/project/schedule.js +192 -0
- package/dist/project/web/Refresh.d.ts +8 -0
- package/dist/project/web/Refresh.js +29 -0
- package/dist/project/web/Schedule.d.ts +9 -0
- package/dist/project/web/Schedule.js +93 -0
- package/dist/project/web/Structure.d.ts +8 -0
- package/dist/project/web/Structure.js +86 -0
- package/dist/project/web/Workload.d.ts +8 -0
- package/dist/project/web/Workload.js +43 -0
- package/dist/project/web/index.d.ts +14 -0
- package/dist/project/web/index.js +25 -0
- package/dist/project/web/messages.d.ts +2 -0
- package/dist/project/web/messages.js +85 -0
- package/dist/project_account/.kosh/bindings.d.ts +22 -0
- package/dist/project_account/.kosh/bindings.js +15 -0
- package/dist/project_account/.kosh/schema.d.ts +2763 -0
- package/dist/project_account/i18n/bn.d.ts +2 -0
- package/dist/project_account/i18n/bn.js +6 -0
- package/dist/project_account/index.d.ts +3 -0
- package/dist/project_account/index.js +29 -0
- package/dist/project_account/module.d.ts +15013 -0
- package/dist/project_account/module.js +76 -0
- package/dist/project_portal/.kosh/bindings.js +1 -1
- package/dist/project_portal/.kosh/schema.d.ts +735 -1
- package/dist/project_portal/i18n/bn.d.ts +2 -0
- package/dist/project_portal/i18n/bn.js +6 -0
- package/dist/project_portal/index.js +2 -0
- package/dist/project_portal/module.d.ts +4796 -87
- package/dist/project_purchase/.kosh/bindings.d.ts +22 -0
- package/dist/project_purchase/.kosh/bindings.js +15 -0
- package/dist/project_purchase/.kosh/schema.d.ts +3393 -0
- package/dist/project_purchase/i18n/bn.d.ts +2 -0
- package/dist/project_purchase/i18n/bn.js +4 -0
- package/dist/project_purchase/index.d.ts +9 -0
- package/dist/project_purchase/index.js +24 -0
- package/dist/project_purchase/module.d.ts +38613 -0
- package/dist/project_purchase/module.js +56 -0
- package/dist/purchase/.kosh/bindings.js +1 -1
- package/dist/purchase/.kosh/schema.d.ts +908 -5
- package/dist/purchase/comparison.d.ts +993 -0
- package/dist/purchase/comparison.js +415 -0
- package/dist/purchase/extras.d.ts +1509 -0
- package/dist/purchase/extras.js +445 -0
- package/dist/purchase/i18n/bn.d.ts +2 -0
- package/dist/purchase/i18n/bn.js +413 -0
- package/dist/purchase/index.d.ts +5 -0
- package/dist/purchase/index.js +1280 -4
- package/dist/purchase/module.d.ts +7147 -395
- package/dist/purchase/module.js +303 -10
- package/dist/purchase/request.d.ts +696 -0
- package/dist/purchase/request.js +446 -0
- package/dist/purchase/tender.d.ts +1208 -0
- package/dist/purchase/tender.js +507 -0
- package/dist/purchase/vendorprice.d.ts +340 -0
- package/dist/purchase/vendorprice.js +153 -0
- package/dist/purchase_account/.kosh/bindings.js +1 -1
- package/dist/purchase_account/.kosh/schema.d.ts +1209 -16
- package/dist/purchase_account/i18n/bn.d.ts +2 -0
- package/dist/purchase_account/i18n/bn.js +22 -0
- package/dist/purchase_account/index.js +20 -0
- package/dist/purchase_account/module.d.ts +12232 -2028
- package/dist/purchase_account/module.js +252 -9
- package/dist/purchase_portal/.kosh/bindings.js +1 -1
- package/dist/purchase_portal/.kosh/schema.d.ts +908 -5
- package/dist/purchase_portal/i18n/bn.d.ts +2 -0
- package/dist/purchase_portal/i18n/bn.js +5 -0
- package/dist/purchase_portal/index.js +2 -0
- package/dist/purchase_portal/module.d.ts +6853 -352
- package/dist/purchase_stock/.kosh/bindings.js +1 -1
- package/dist/purchase_stock/.kosh/schema.d.ts +1096 -21
- package/dist/purchase_stock/i18n/bn.d.ts +2 -0
- package/dist/purchase_stock/i18n/bn.js +19 -0
- package/dist/purchase_stock/index.d.ts +2 -2
- package/dist/purchase_stock/index.js +38 -2
- package/dist/purchase_stock/module.d.ts +12930 -1612
- package/dist/purchase_stock/module.js +317 -9
- package/dist/purchase_stock/scorecard.d.ts +22 -0
- package/dist/purchase_stock/scorecard.js +77 -0
- package/dist/purchase_stock/web/Scorecard.d.ts +7 -0
- package/dist/purchase_stock/web/Scorecard.js +22 -0
- package/dist/purchase_stock/web/index.d.ts +11 -0
- package/dist/purchase_stock/web/index.js +16 -0
- package/dist/purchase_stock/web/messages.d.ts +2 -0
- package/dist/purchase_stock/web/messages.js +27 -0
- package/dist/purchase_stock_account/.kosh/bindings.js +1 -1
- package/dist/purchase_stock_account/.kosh/schema.d.ts +1444 -20
- package/dist/purchase_stock_account/i18n/bn.d.ts +2 -0
- package/dist/purchase_stock_account/i18n/bn.js +8 -0
- package/dist/purchase_stock_account/index.js +18 -0
- package/dist/purchase_stock_account/module.d.ts +7 -35346
- package/dist/purchase_stock_account/module.js +35 -8
- package/dist/recruitment/.kosh/bindings.js +1 -1
- package/dist/recruitment/.kosh/schema.d.ts +60 -1
- package/dist/recruitment/i18n/bn.d.ts +2 -0
- package/dist/recruitment/i18n/bn.js +93 -0
- package/dist/recruitment/index.js +64 -0
- package/dist/recruitment/module.d.ts +460 -8
- package/dist/recruitment/module.js +13 -4
- package/dist/reporting/documents.d.ts +5 -0
- package/dist/reporting/documents.js +11 -1
- package/dist/reporting/index.d.ts +1 -1
- package/dist/reporting/index.js +1 -1
- package/dist/reporting/web/CalendarView.d.ts +18 -5
- package/dist/reporting/web/CalendarView.js +163 -29
- package/dist/reporting/web/messages.js +18 -0
- package/dist/sale_account/.kosh/bindings.js +1 -1
- package/dist/sale_account/.kosh/schema.d.ts +763 -18
- package/dist/sale_account/i18n/bn.d.ts +2 -0
- package/dist/sale_account/i18n/bn.js +48 -0
- package/dist/sale_account/index.d.ts +1 -1
- package/dist/sale_account/index.js +102 -4
- package/dist/sale_account/module.d.ts +8241 -2052
- package/dist/sale_account/module.js +535 -46
- package/dist/sale_crm/.kosh/bindings.d.ts +22 -0
- package/dist/sale_crm/.kosh/bindings.js +15 -0
- package/dist/{mrp → sale_crm}/.kosh/schema.d.ts +391 -494
- package/dist/sale_crm/i18n/bn.d.ts +2 -0
- package/dist/sale_crm/i18n/bn.js +9 -0
- package/dist/sale_crm/index.d.ts +7 -0
- package/dist/sale_crm/index.js +104 -0
- package/dist/sale_crm/module.d.ts +5609 -0
- package/dist/sale_crm/module.js +73 -0
- package/dist/sale_portal/.kosh/bindings.js +1 -1
- package/dist/sale_portal/.kosh/schema.d.ts +292 -4
- package/dist/sale_portal/i18n/bn.d.ts +2 -0
- package/dist/sale_portal/i18n/bn.js +7 -0
- package/dist/sale_portal/index.js +10 -0
- package/dist/sale_portal/module.d.ts +2563 -292
- package/dist/sale_project/.kosh/bindings.js +1 -1
- package/dist/sale_project/.kosh/schema.d.ts +1025 -4
- package/dist/sale_project/i18n/bn.d.ts +2 -0
- package/dist/sale_project/i18n/bn.js +12 -0
- package/dist/sale_project/index.js +2 -0
- package/dist/sale_project/module.d.ts +9280 -762
- package/dist/sale_project/module.js +17 -1
- package/dist/sale_stock/.kosh/bindings.js +1 -1
- package/dist/sale_stock/.kosh/schema.d.ts +463 -6
- package/dist/sale_stock/i18n/bn.d.ts +2 -0
- package/dist/sale_stock/i18n/bn.js +15 -0
- package/dist/sale_stock/index.js +2 -0
- package/dist/sale_stock/module.d.ts +8355 -1334
- package/dist/sale_stock/module.js +20 -3
- package/dist/sales/.kosh/bindings.js +1 -1
- package/dist/sales/.kosh/schema.d.ts +292 -4
- package/dist/sales/i18n/bn.d.ts +2 -0
- package/dist/sales/i18n/bn.js +128 -0
- package/dist/sales/index.js +124 -5
- package/dist/sales/module.d.ts +3568 -633
- package/dist/sales/module.js +306 -11
- package/dist/server/api/duplicate.d.ts +14 -0
- package/dist/server/api/duplicate.js +75 -0
- package/dist/server/api/explain.d.ts +70 -0
- package/dist/server/api/explain.js +111 -0
- package/dist/server/api/metadata.d.ts +2 -0
- package/dist/server/api/metadata.js +9 -0
- package/dist/server/api/openapi.js +15 -0
- package/dist/server/api/rest.d.ts +1 -0
- package/dist/server/api/rest.js +76 -12
- package/dist/server/api/views.js +1 -1
- package/dist/server/apps.d.ts +16 -1
- package/dist/server/apps.js +164 -2
- package/dist/server/auth/base.js +2 -0
- package/dist/server/auth/service.d.ts +8 -0
- package/dist/server/auth/service.js +19 -0
- package/dist/server/events.d.ts +13 -0
- package/dist/server/events.js +22 -0
- package/dist/server/i18n.d.ts +27 -0
- package/dist/server/i18n.js +143 -0
- package/dist/server/index.d.ts +2 -0
- package/dist/server/index.js +2 -0
- package/dist/server/server.js +6 -0
- package/dist/settings/company.d.ts +3 -1
- package/dist/settings/company.js +26 -5
- package/dist/settings/routes.d.ts +10 -0
- package/dist/settings/routes.js +19 -3
- package/dist/settings/web/AppsPage.d.ts +3 -2
- package/dist/settings/web/AppsPage.js +26 -8
- package/dist/settings/web/CompaniesPage.js +91 -6
- package/dist/settings/web/messages.js +64 -0
- package/dist/sign/.kosh/bindings.d.ts +22 -0
- package/dist/{mrp → sign}/.kosh/bindings.js +2 -2
- package/dist/sign/.kosh/schema.d.ts +991 -0
- package/dist/sign/i18n/bn.d.ts +2 -0
- package/dist/sign/i18n/bn.js +97 -0
- package/dist/sign/index.d.ts +29 -0
- package/dist/sign/index.js +478 -0
- package/dist/sign/module.d.ts +4518 -0
- package/dist/sign/module.js +167 -0
- package/dist/sign/sign.d.ts +82 -0
- package/dist/sign/sign.js +474 -0
- package/dist/stock/.kosh/bindings.js +1 -1
- package/dist/stock/.kosh/schema.d.ts +374 -3
- package/dist/stock/demo.d.ts +2 -1
- package/dist/stock/demo.js +28 -1
- package/dist/stock/i18n/bn.d.ts +2 -0
- package/dist/stock/i18n/bn.js +311 -0
- package/dist/stock/index.d.ts +4 -1
- package/dist/stock/index.js +674 -6
- package/dist/stock/ledger.d.ts +78 -0
- package/dist/stock/ledger.js +582 -0
- package/dist/stock/module.d.ts +6142 -1380
- package/dist/stock/module.js +780 -26
- package/dist/stock/replenish.d.ts +38 -0
- package/dist/stock/replenish.js +191 -0
- package/dist/stock/returns.d.ts +157 -0
- package/dist/stock/returns.js +163 -0
- package/dist/stock/web/Ledger.d.ts +9 -0
- package/dist/stock/web/Ledger.js +108 -0
- package/dist/stock/web/Operations.d.ts +8 -0
- package/dist/stock/web/Operations.js +33 -0
- package/dist/stock/web/Replenishment.d.ts +8 -0
- package/dist/stock/web/Replenishment.js +84 -0
- package/dist/stock/web/ReturnButton.d.ts +7 -0
- package/dist/stock/web/ReturnButton.js +62 -0
- package/dist/stock/web/index.d.ts +7 -2
- package/dist/stock/web/index.js +15 -2
- package/dist/stock/web/messages.js +206 -0
- package/dist/stock_account/.kosh/bindings.js +1 -1
- package/dist/stock_account/.kosh/schema.d.ts +878 -12
- package/dist/stock_account/i18n/bn.d.ts +2 -0
- package/dist/stock_account/i18n/bn.js +73 -0
- package/dist/stock_account/index.d.ts +1 -0
- package/dist/stock_account/index.js +141 -3
- package/dist/stock_account/landed.d.ts +429 -0
- package/dist/stock_account/landed.js +335 -0
- package/dist/stock_account/module.d.ts +12143 -3391
- package/dist/stock_account/module.js +135 -6
- package/dist/stock_account/web/LandedPreview.d.ts +7 -0
- package/dist/stock_account/web/LandedPreview.js +23 -0
- package/dist/stock_account/web/index.d.ts +11 -0
- package/dist/stock_account/web/index.js +16 -0
- package/dist/stock_account/web/messages.d.ts +2 -0
- package/dist/stock_account/web/messages.js +27 -0
- package/dist/todo/i18n/bn.d.ts +2 -0
- package/dist/todo/i18n/bn.js +66 -0
- package/dist/todo/index.js +59 -0
- package/dist/todo/module.d.ts +5 -0
- package/dist/todo/module.js +5 -3
- package/dist/trade_finance/.kosh/bindings.js +1 -1
- package/dist/trade_finance/.kosh/schema.d.ts +2 -1
- package/dist/trade_finance/i18n/bn.d.ts +2 -0
- package/dist/trade_finance/i18n/bn.js +162 -0
- package/dist/trade_finance/index.js +95 -0
- package/dist/trade_finance/module.d.ts +26 -0
- package/dist/trade_finance/module.js +29 -8
- package/dist/trade_finance_account/.kosh/bindings.js +1 -1
- package/dist/trade_finance_account/.kosh/schema.d.ts +651 -10
- package/dist/trade_finance_account/i18n/bn.d.ts +2 -0
- package/dist/trade_finance_account/i18n/bn.js +27 -0
- package/dist/trade_finance_account/index.js +3 -0
- package/dist/trade_finance_account/module.d.ts +5129 -1509
- package/dist/trade_finance_account/module.js +2 -0
- package/dist/trade_finance_purchase/.kosh/bindings.js +1 -1
- package/dist/trade_finance_purchase/.kosh/schema.d.ts +908 -5
- package/dist/trade_finance_purchase/i18n/bn.d.ts +2 -0
- package/dist/trade_finance_purchase/i18n/bn.js +6 -0
- package/dist/trade_finance_purchase/index.js +2 -0
- package/dist/trade_finance_purchase/module.d.ts +6909 -408
- package/dist/trade_finance_sale/.kosh/bindings.js +1 -1
- package/dist/trade_finance_sale/.kosh/schema.d.ts +292 -4
- package/dist/trade_finance_sale/i18n/bn.d.ts +2 -0
- package/dist/trade_finance_sale/i18n/bn.js +6 -0
- package/dist/trade_finance_sale/index.js +2 -0
- package/dist/trade_finance_sale/module.d.ts +2602 -331
- package/dist/ui/api.d.ts +2 -0
- package/dist/ui/app.d.ts +9 -0
- package/dist/ui/app.js +47 -15
- package/dist/ui/components/AppIcon.js +9 -2
- package/dist/ui/components/Explain.d.ts +69 -0
- package/dist/ui/components/Explain.js +62 -0
- package/dist/ui/context.d.ts +8 -1
- package/dist/ui/context.js +34 -1
- package/dist/ui/i18n/messages.d.ts +40 -0
- package/dist/ui/i18n/messages.js +80 -0
- package/dist/ui/index.d.ts +2 -1
- package/dist/ui/index.js +1 -0
- package/dist/ui/registry.d.ts +14 -0
- package/dist/ui/registry.js +10 -0
- package/dist/ui/views/FormView.d.ts +6 -0
- package/dist/ui/views/FormView.js +51 -12
- package/dist/ui/views/KanbanView.js +9 -1
- package/dist/ui/views/ListView.d.ts +8 -0
- package/dist/ui/views/ListView.js +14 -5
- package/dist/ui/views/StatsRow.js +2 -1
- package/dist/ui/views/widgets.js +7 -1
- package/dist/views/extend.js +12 -0
- package/dist/views/types.d.ts +13 -2
- package/dist/views/validate.js +8 -1
- package/dist/website/.kosh/bindings.js +1 -1
- package/dist/website/.kosh/schema.d.ts +2 -1
- package/dist/website/i18n/bn.d.ts +2 -0
- package/dist/website/i18n/bn.js +113 -0
- package/dist/website/index.js +37 -0
- package/dist/website/module.d.ts +20 -0
- package/dist/website/module.js +30 -5
- package/dist/website_crm/.kosh/bindings.js +1 -1
- package/dist/website_crm/.kosh/schema.d.ts +3 -1
- package/dist/website_crm/i18n/bn.d.ts +2 -0
- package/dist/website_crm/i18n/bn.js +5 -0
- package/dist/website_crm/index.js +2 -0
- package/dist/website_crm/module.d.ts +41 -0
- package/dist/website_sale/.kosh/bindings.d.ts +22 -0
- package/dist/website_sale/.kosh/bindings.js +15 -0
- package/dist/website_sale/.kosh/schema.d.ts +2909 -0
- package/dist/website_sale/couriers.d.ts +50 -0
- package/dist/website_sale/couriers.js +59 -0
- package/dist/website_sale/demo.d.ts +7 -0
- package/dist/website_sale/demo.js +90 -0
- package/dist/website_sale/growth.d.ts +31 -0
- package/dist/website_sale/growth.js +163 -0
- package/dist/website_sale/i18n/bn.d.ts +2 -0
- package/dist/website_sale/i18n/bn.js +132 -0
- package/dist/website_sale/index.d.ts +49 -0
- package/dist/website_sale/index.js +620 -0
- package/dist/website_sale/module.d.ts +35182 -0
- package/dist/website_sale/module.js +419 -0
- package/dist/website_sale/shipments.d.ts +16 -0
- package/dist/website_sale/shipments.js +113 -0
- package/dist/website_sale/shop.d.ts +81 -0
- package/dist/website_sale/shop.js +662 -0
- package/dist/website_sale_stock/.kosh/bindings.d.ts +22 -0
- package/dist/website_sale_stock/.kosh/bindings.js +15 -0
- package/dist/website_sale_stock/.kosh/schema.d.ts +3400 -0
- package/dist/website_sale_stock/i18n/bn.d.ts +2 -0
- package/dist/website_sale_stock/i18n/bn.js +4 -0
- package/dist/website_sale_stock/index.d.ts +9 -0
- package/dist/website_sale_stock/index.js +22 -0
- package/dist/website_sale_stock/module.d.ts +11 -0
- package/dist/website_sale_stock/module.js +32 -0
- package/package.json +117 -8
- package/dist/mrp/index.d.ts +0 -3
- package/dist/mrp/index.js +0 -392
- package/dist/mrp/module.js +0 -695
- package/dist/mrp_account/index.d.ts +0 -3
- package/dist/mrp_account/index.js +0 -22
- /package/dist/{mrp → account_asset}/.kosh/bindings.d.ts +0 -0
- /package/dist/{mrp_account → account_budget}/.kosh/bindings.d.ts +0 -0
|
@@ -0,0 +1,792 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The data layer of Requests (RFC 0032 §3.1): a section asks its store for goods by an **indent**. Product groups
|
|
3
|
+
* name who approves their products; an indent is decided through the approval engine (the requester's department
|
|
4
|
+
* head, then the approvers of its products' groups), each level able to lower the approved quantities. The store
|
|
5
|
+
* issues what was approved by an internal transfer from the warehouse to an internal-use location — reserved,
|
|
6
|
+
* lots first-expiry-first-out, valued by `stock_account` — partly or at once; what each line still owes follows from
|
|
7
|
+
* the validated transfers. The requester acknowledges what arrived, which closes the indent.
|
|
8
|
+
*
|
|
9
|
+
* Requesters see their own indents and those they decide; store keepers the indents of every warehouse of their
|
|
10
|
+
* companies; Requests managers everything and the configuration.
|
|
11
|
+
*/
|
|
12
|
+
import { hrShutro } from '../hr/index.js';
|
|
13
|
+
import { approvalGuard, permissionsShutro, requestApprovals } from '../permissions/index.js';
|
|
14
|
+
import { productShutro } from '../product/index.js';
|
|
15
|
+
import { orm } from '../server/orm.js';
|
|
16
|
+
import { defaultLocations, onHandIn, stockShutro, transitLocation } from '../stock/index.js';
|
|
17
|
+
import { check, compute, defineModel, defineModule, extendModel, f, method, onchange, records, } from './.kosh/bindings.js';
|
|
18
|
+
const READ = ['read'];
|
|
19
|
+
const ALL = ['read', 'write', 'create', 'unlink'];
|
|
20
|
+
const me = { $env: 'uid' };
|
|
21
|
+
const zero = orm.toDecimal(0);
|
|
22
|
+
export const IndentProductGroup = defineModel('indent.product.group', {
|
|
23
|
+
label: 'Product group',
|
|
24
|
+
recName: 'name',
|
|
25
|
+
order: ['name asc'],
|
|
26
|
+
archivable: true,
|
|
27
|
+
access: {
|
|
28
|
+
'indent.user': READ,
|
|
29
|
+
'indent.store': READ,
|
|
30
|
+
'indent.manager': [...ALL, 'export', 'import'],
|
|
31
|
+
},
|
|
32
|
+
fields: {
|
|
33
|
+
name: f.char({ required: true, translate: true }),
|
|
34
|
+
categories: f.many2many('product.category', {
|
|
35
|
+
relation: 'indent_group_category',
|
|
36
|
+
label: 'Product categories',
|
|
37
|
+
help: 'Products of these categories, and of the categories inside them, belong to the group.',
|
|
38
|
+
}),
|
|
39
|
+
approvalUsers: f.many2many('res.users', {
|
|
40
|
+
relation: 'indent_group_approver',
|
|
41
|
+
label: 'Approvers',
|
|
42
|
+
help: 'Who approves indents for the group’s products (the approval level where the record names the approvers).',
|
|
43
|
+
}),
|
|
44
|
+
note: f.text({ label: 'Guidance', translate: true }),
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
/** The group of a product: the first group naming its category or a category above it. */
|
|
48
|
+
async function groupOf(env, product) {
|
|
49
|
+
if (product === null)
|
|
50
|
+
return null;
|
|
51
|
+
const [p] = await env
|
|
52
|
+
.model('product.product')
|
|
53
|
+
.browse([product])
|
|
54
|
+
.load({ category: true });
|
|
55
|
+
let category = p?.category?.id ?? null;
|
|
56
|
+
for (let depth = 0; category !== null && depth < 10; depth += 1) {
|
|
57
|
+
const found = await env
|
|
58
|
+
.model('indent.product.group')
|
|
59
|
+
.search({ where: { categories: { any: { id: category } } }, limit: 1 });
|
|
60
|
+
if (found.ids[0] !== undefined)
|
|
61
|
+
return found.ids[0];
|
|
62
|
+
const [c] = await env
|
|
63
|
+
.model('product.category')
|
|
64
|
+
.browse([category])
|
|
65
|
+
.load({ parent: true });
|
|
66
|
+
category = c?.parent?.id ?? null;
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
/** What validated transfers of the given notes moved, by their moves. */
|
|
71
|
+
function done(moves, note) {
|
|
72
|
+
return [...moves]
|
|
73
|
+
.filter((m) => m.picking.state === 'done' && note(m.picking.noteKind))
|
|
74
|
+
.reduce((s, m) => s.plus(m.quantityDone ?? m.quantity), zero);
|
|
75
|
+
}
|
|
76
|
+
/** The employee of a user, with their department, if they have one. */
|
|
77
|
+
async function employeeOf(env, user) {
|
|
78
|
+
const found = await env.model('hr.employee').search({ where: { user: user }, limit: 1 });
|
|
79
|
+
const [e] = await found.load({ department: true });
|
|
80
|
+
return e === undefined
|
|
81
|
+
? null
|
|
82
|
+
: { id: e.id, department: e.department?.id ?? null };
|
|
83
|
+
}
|
|
84
|
+
const STATES = {
|
|
85
|
+
draft: 'Draft',
|
|
86
|
+
to_approve: 'Waiting for approval',
|
|
87
|
+
approved: 'Approved',
|
|
88
|
+
acknowledged: 'Acknowledged',
|
|
89
|
+
rejected: 'Rejected',
|
|
90
|
+
cancel: 'Cancelled',
|
|
91
|
+
};
|
|
92
|
+
export const IndentRequest = defineModel('indent.request', {
|
|
93
|
+
label: 'Indent',
|
|
94
|
+
recName: 'name',
|
|
95
|
+
order: ['id desc'],
|
|
96
|
+
companyScoped: { required: true },
|
|
97
|
+
tracking: ['state', 'kind', 'warehouse', 'destination', 'priority', 'dateRequired'],
|
|
98
|
+
access: {
|
|
99
|
+
'indent.user': ALL,
|
|
100
|
+
'indent.store': ALL,
|
|
101
|
+
'indent.manager': [...ALL, 'export', 'import'],
|
|
102
|
+
},
|
|
103
|
+
rules: {
|
|
104
|
+
// One's own indents; changed while a draft (or sent back as rejected).
|
|
105
|
+
seeOwn: { groups: ['indent.user'], perms: ['read'], domain: { requester: me } },
|
|
106
|
+
draftOwn: {
|
|
107
|
+
groups: ['indent.user'],
|
|
108
|
+
perms: ['write', 'create', 'unlink'],
|
|
109
|
+
domain: { requester: me, state: { in: ['draft', 'rejected'] } },
|
|
110
|
+
},
|
|
111
|
+
// The requester acknowledges an approved indent.
|
|
112
|
+
acknowledgeOwn: {
|
|
113
|
+
groups: ['indent.user'],
|
|
114
|
+
perms: ['write'],
|
|
115
|
+
domain: { requester: me, state: 'approved' },
|
|
116
|
+
},
|
|
117
|
+
// Who decides: the department's head and the approvers of the products' groups see the indent.
|
|
118
|
+
deciders: {
|
|
119
|
+
groups: ['indent.user'],
|
|
120
|
+
perms: ['read'],
|
|
121
|
+
domain: {
|
|
122
|
+
or: [
|
|
123
|
+
{ 'department.head.user': me },
|
|
124
|
+
{ lines: { any: { 'group.approvalUsers': { any: { id: me } } } } },
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
// Store keepers: every indent of their companies (the company rule applies).
|
|
129
|
+
store: { groups: ['indent.store'], perms: ['read', 'write'], domain: {} },
|
|
130
|
+
all: { groups: ['indent.manager'], perms: [...ALL], domain: {} },
|
|
131
|
+
},
|
|
132
|
+
fields: {
|
|
133
|
+
name: f.char({ required: true, sequence: 'indent.request', label: 'Reference' }),
|
|
134
|
+
requester: f.many2one('res.users', {
|
|
135
|
+
required: true,
|
|
136
|
+
ondelete: 'restrict',
|
|
137
|
+
default: (env) => env.userId,
|
|
138
|
+
label: 'Requested by',
|
|
139
|
+
}),
|
|
140
|
+
kind: f.selection({ issue: 'Issue for use', transfer: 'Transfer to a warehouse' }, {
|
|
141
|
+
required: true,
|
|
142
|
+
default: 'issue',
|
|
143
|
+
label: 'Request',
|
|
144
|
+
help: 'Goods issued for a section’s use, or stock sent from the store to another warehouse through transit.',
|
|
145
|
+
}),
|
|
146
|
+
employee: f.many2one('hr.employee', { ondelete: 'set null' }),
|
|
147
|
+
department: f.many2one('hr.department', {
|
|
148
|
+
ondelete: 'set null',
|
|
149
|
+
help: 'The requester’s department: its head approves the indent first.',
|
|
150
|
+
}),
|
|
151
|
+
warehouse: f.many2one('stock.warehouse', {
|
|
152
|
+
required: true,
|
|
153
|
+
ondelete: 'restrict',
|
|
154
|
+
label: 'Store',
|
|
155
|
+
help: 'The warehouse asked for the goods.',
|
|
156
|
+
}),
|
|
157
|
+
destination: f.many2one('stock.location', {
|
|
158
|
+
required: true,
|
|
159
|
+
ondelete: 'restrict',
|
|
160
|
+
label: 'Goes to',
|
|
161
|
+
help: 'An internal-use location of the section (issued goods leave stock there), or the stock location of the warehouse receiving a transfer.',
|
|
162
|
+
}),
|
|
163
|
+
dateRequired: f.date({
|
|
164
|
+
required: true,
|
|
165
|
+
label: 'Needed by',
|
|
166
|
+
default: (env) => env.today(),
|
|
167
|
+
}),
|
|
168
|
+
priority: f.selection({ normal: 'Normal', high: 'High', urgent: 'Urgent', critical: 'Critical' }, { required: true, default: 'normal', help: 'How soon the goods are needed, shown as stars.' }),
|
|
169
|
+
purpose: f.text(),
|
|
170
|
+
lines: f.one2many('indent.request.line', 'request', { label: 'Products' }),
|
|
171
|
+
pickings: f.one2many('stock.picking', 'indent', { label: 'Transfers' }),
|
|
172
|
+
issueCount: f.integer({
|
|
173
|
+
label: 'Transfers',
|
|
174
|
+
...compute('indent.request', 'issueCount', ['pickings'], (requests) => {
|
|
175
|
+
for (const r of requests)
|
|
176
|
+
r.issueCount = r.pickings.length;
|
|
177
|
+
}),
|
|
178
|
+
}),
|
|
179
|
+
issueStatus: f.selection({ none: 'Nothing issued', partial: 'Partly issued', full: 'Issued in full' }, {
|
|
180
|
+
store: true,
|
|
181
|
+
label: 'Issued',
|
|
182
|
+
help: 'What arrived of the approved quantities, by validated transfers (for a transfer: received; a shortage recorded counts as settled).',
|
|
183
|
+
...compute('indent.request', 'issueStatus', ['lines.qtyApproved', 'lines.qtyIssued', 'lines.qtyShort'], (requests) => {
|
|
184
|
+
for (const r of requests) {
|
|
185
|
+
const lines = [...r.lines].filter((l) => (l.qtyApproved ?? zero).gt(0));
|
|
186
|
+
const issued = lines.filter((l) => (l.qtyIssued ?? zero).gt(0));
|
|
187
|
+
r.issueStatus =
|
|
188
|
+
issued.length === 0
|
|
189
|
+
? 'none'
|
|
190
|
+
: lines.every((l) => (l.qtyIssued ?? zero).plus(l.qtyShort ?? zero).gte(l.qtyApproved ?? zero))
|
|
191
|
+
? 'full'
|
|
192
|
+
: 'partial';
|
|
193
|
+
}
|
|
194
|
+
}),
|
|
195
|
+
}),
|
|
196
|
+
rejectReason: f.char({ size: 300, label: 'Rejected because' }),
|
|
197
|
+
shortageReason: f.char({
|
|
198
|
+
size: 300,
|
|
199
|
+
label: 'Shortage because',
|
|
200
|
+
help: 'Why goods shipped were not received (lost, damaged on the road): written off from transit.',
|
|
201
|
+
}),
|
|
202
|
+
acknowledgedOn: f.date({ label: 'Acknowledged on' }),
|
|
203
|
+
state: f.state({
|
|
204
|
+
states: STATES,
|
|
205
|
+
initial: 'draft',
|
|
206
|
+
help: 'Drafted by the requester, approved by the department head and the products’ group approvers, issued by the store, then acknowledged by the requester.',
|
|
207
|
+
transitions: {
|
|
208
|
+
submit: {
|
|
209
|
+
from: ['draft', 'rejected'],
|
|
210
|
+
to: 'to_approve',
|
|
211
|
+
guard: records('indent.request', async (requests) => [...(await requests.load({ lines: true }))]
|
|
212
|
+
.filter((r) => r.lines.length === 0)
|
|
213
|
+
.map((r) => r.id)),
|
|
214
|
+
message: 'Add the products before submitting the indent.',
|
|
215
|
+
// Approved quantities start as requested; approvers may lower them.
|
|
216
|
+
before: records('indent.request', async (requests) => {
|
|
217
|
+
for (const r of await requests.load({ lines: true }))
|
|
218
|
+
for (const l of r.lines)
|
|
219
|
+
await l.write({ qtyApproved: l.quantity, rejectReason: null });
|
|
220
|
+
await requests.write({ rejectReason: null });
|
|
221
|
+
}),
|
|
222
|
+
after: records('indent.request', async (requests) => {
|
|
223
|
+
await requestApprovals(requests);
|
|
224
|
+
for (const r of await requests.load({}))
|
|
225
|
+
await requests.env.emit('indent.request.submitted', { id: r.id });
|
|
226
|
+
}),
|
|
227
|
+
},
|
|
228
|
+
approve: {
|
|
229
|
+
from: ['to_approve'],
|
|
230
|
+
to: 'approved',
|
|
231
|
+
guard: records('indent.request', (requests) => approvalGuard(requests)),
|
|
232
|
+
message: 'Waiting for approvals.',
|
|
233
|
+
after: records('indent.request', async (requests) => {
|
|
234
|
+
for (const r of await requests.load({}))
|
|
235
|
+
await requests.env.emit('indent.request.approved', { id: r.id });
|
|
236
|
+
}),
|
|
237
|
+
},
|
|
238
|
+
reject: { from: ['to_approve'], to: 'rejected' },
|
|
239
|
+
redraft: { from: ['rejected', 'cancel'], to: 'draft' },
|
|
240
|
+
cancel: {
|
|
241
|
+
from: ['draft', 'to_approve', 'rejected'],
|
|
242
|
+
to: 'cancel',
|
|
243
|
+
},
|
|
244
|
+
/**
|
|
245
|
+
* Issues what is still owed: one transfer from the store to where the goods are used (RFC 0032 §3.1), or for a
|
|
246
|
+
* transfer the Stock Transfer Note into the store's transit location (§3.1, step 2).
|
|
247
|
+
*/
|
|
248
|
+
issue: {
|
|
249
|
+
from: ['approved'],
|
|
250
|
+
to: 'approved',
|
|
251
|
+
requires: 'indent.issue',
|
|
252
|
+
guard: records('indent.request', async (requests) => [...(await requests.load({ lines: true }))]
|
|
253
|
+
.filter((r) => [...r.lines].every((l) => (l.qtyRemaining ?? zero).lte(0)))
|
|
254
|
+
.map((r) => r.id)),
|
|
255
|
+
message: 'Nothing is left to issue.',
|
|
256
|
+
after: records('indent.request', async (requests) => {
|
|
257
|
+
const env = requests.env;
|
|
258
|
+
await env.flush();
|
|
259
|
+
for (const id of requests.ids)
|
|
260
|
+
await issueRemaining(env, id);
|
|
261
|
+
}),
|
|
262
|
+
},
|
|
263
|
+
/** What was shipped and not received is written off from transit, with the reason (RFC 0032 §3.1). */
|
|
264
|
+
shortage: {
|
|
265
|
+
from: ['approved'],
|
|
266
|
+
to: 'approved',
|
|
267
|
+
requires: 'indent.issue',
|
|
268
|
+
guard: records('indent.request', async (requests) => [...(await requests.load({ pickings: true }))]
|
|
269
|
+
.filter((r) => (r.shortageReason ?? '').trim() === '' ||
|
|
270
|
+
![...r.pickings].some((p) => p.noteKind === 'srn' && p.state === 'confirmed'))
|
|
271
|
+
.map((r) => r.id)),
|
|
272
|
+
message: 'Say why, on a transfer with goods still in transit.',
|
|
273
|
+
after: records('indent.request', async (requests) => {
|
|
274
|
+
const env = requests.env;
|
|
275
|
+
await env.flush();
|
|
276
|
+
for (const id of requests.ids)
|
|
277
|
+
await writeOffShortage(env, id);
|
|
278
|
+
}),
|
|
279
|
+
},
|
|
280
|
+
/** The requester confirms what arrived; what was not issued is no longer owed. */
|
|
281
|
+
acknowledge: {
|
|
282
|
+
from: ['approved'],
|
|
283
|
+
to: 'acknowledged',
|
|
284
|
+
guard: records('indent.request', async (requests) => [...(await requests.load({}))]
|
|
285
|
+
.filter((r) => r.issueStatus === 'none' || r.requester.id !== requests.env.userId)
|
|
286
|
+
.map((r) => r.id)),
|
|
287
|
+
message: 'The requester acknowledges what the store issued.',
|
|
288
|
+
after: records('indent.request', async (requests) => {
|
|
289
|
+
const env = requests.env;
|
|
290
|
+
await requests.write({ acknowledgedOn: env.today() });
|
|
291
|
+
for (const r of await requests.load({}))
|
|
292
|
+
await env.emit('indent.request.acknowledged', { id: r.id });
|
|
293
|
+
}),
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
extensible: true, // indent_purchase asks Purchase for the shortfall
|
|
297
|
+
}),
|
|
298
|
+
},
|
|
299
|
+
constraints: {
|
|
300
|
+
// An internal-use location: issued goods leave stock there.
|
|
301
|
+
usedAt: {
|
|
302
|
+
...check('indent.request', ['destination', 'kind'], async (requests) => [...(await requests.load({ destination: true }))]
|
|
303
|
+
.filter((r) => r.kind === 'issue' && r.destination.usage !== 'consumption')
|
|
304
|
+
.map((r) => r.id)),
|
|
305
|
+
message: 'Goods are issued to an internal-use location.',
|
|
306
|
+
},
|
|
307
|
+
// A transfer goes to the stock of another warehouse.
|
|
308
|
+
transferTo: {
|
|
309
|
+
...check('indent.request', ['destination', 'kind', 'warehouse'], async (requests) => [...(await requests.load({ destination: true }))]
|
|
310
|
+
.filter((r) => r.kind === 'transfer' &&
|
|
311
|
+
(r.destination.usage !== 'internal' ||
|
|
312
|
+
r.destination.transit === true ||
|
|
313
|
+
r.destination.warehouse === null ||
|
|
314
|
+
r.destination.warehouse.id === r.warehouse.id))
|
|
315
|
+
.map((r) => r.id)),
|
|
316
|
+
message: 'A transfer goes to a stock location of another warehouse.',
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
methods: {
|
|
320
|
+
/**
|
|
321
|
+
* The approvers each indent names for a level where "the record decides" (RFC 0027 §2.1): those of its lines'
|
|
322
|
+
* product groups.
|
|
323
|
+
*/
|
|
324
|
+
approvalUsers: method('indent.request', async function (_key) {
|
|
325
|
+
const requests = this;
|
|
326
|
+
const out = new Map();
|
|
327
|
+
for (const r of await requests.env
|
|
328
|
+
.model('indent.request')
|
|
329
|
+
.browse([...requests.ids])
|
|
330
|
+
.load({ lines: { group: { approvalUsers: true } } })) {
|
|
331
|
+
const people = new Set();
|
|
332
|
+
for (const l of r.lines)
|
|
333
|
+
for (const u of l.group?.approvalUsers ?? [])
|
|
334
|
+
people.add(u.id);
|
|
335
|
+
out.set(r.id, [...people]);
|
|
336
|
+
}
|
|
337
|
+
return out;
|
|
338
|
+
}),
|
|
339
|
+
},
|
|
340
|
+
onchange: {
|
|
341
|
+
// The requester's employee and department, the company's first store and the internal-use location: when the
|
|
342
|
+
// requester changes, and when the purpose is typed on a new indent.
|
|
343
|
+
requester: onchange('indent.request', async (d, env) => fillRequest(d, env, true)),
|
|
344
|
+
purpose: onchange('indent.request', async (d, env) => fillRequest(d, env, false)),
|
|
345
|
+
// Where the goods go follows the kind: internal use for an issue, chosen for a transfer.
|
|
346
|
+
kind: onchange('indent.request', async (d, env) => {
|
|
347
|
+
const draft = d;
|
|
348
|
+
draft.set('destination', draft.get('kind') === 'transfer' ? null : await internalUse(env));
|
|
349
|
+
}),
|
|
350
|
+
},
|
|
351
|
+
});
|
|
352
|
+
async function fillRequest(d, env, requesterChanged) {
|
|
353
|
+
if (requesterChanged || (d.get('department') ?? null) === null) {
|
|
354
|
+
const user = d.get('requester') ?? env.userId;
|
|
355
|
+
const employee = await employeeOf(env, user);
|
|
356
|
+
d.set('employee', employee?.id ?? null);
|
|
357
|
+
d.set('department', employee?.department ?? null);
|
|
358
|
+
}
|
|
359
|
+
if ((d.get('warehouse') ?? null) === null) {
|
|
360
|
+
const places = await defaultLocations(env, 'internal');
|
|
361
|
+
if (places.warehouse !== null)
|
|
362
|
+
d.set('warehouse', places.warehouse);
|
|
363
|
+
}
|
|
364
|
+
if ((d.get('destination') ?? null) === null && d.get('kind') !== 'transfer') {
|
|
365
|
+
const used = await internalUse(env);
|
|
366
|
+
if (used !== null)
|
|
367
|
+
d.set('destination', used);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
/** The shared internal-use location (`Internal use`), if any. */
|
|
371
|
+
async function internalUse(env) {
|
|
372
|
+
const found = await env
|
|
373
|
+
.model('stock.location')
|
|
374
|
+
.search({ where: { usage: 'consumption' }, order: ['id asc'], limit: 1 });
|
|
375
|
+
return found.ids[0] ?? null;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Makes and confirms one transfer for what an approved indent still owes, from the store's stock to where the goods
|
|
379
|
+
* are used (reserved on confirmation). Runs as the store keeper; the moves link the indent lines.
|
|
380
|
+
*/
|
|
381
|
+
async function issueRemaining(env, id) {
|
|
382
|
+
const [r] = await env
|
|
383
|
+
.model('indent.request')
|
|
384
|
+
.browse([id])
|
|
385
|
+
.load({
|
|
386
|
+
lines: { product: true, uom: true },
|
|
387
|
+
warehouse: true,
|
|
388
|
+
destination: true,
|
|
389
|
+
company: true,
|
|
390
|
+
});
|
|
391
|
+
if (r === undefined)
|
|
392
|
+
return null;
|
|
393
|
+
const owed = r.lines.filter((l) => (l.qtyRemaining ?? zero).gt(0));
|
|
394
|
+
if (owed.length === 0)
|
|
395
|
+
return null;
|
|
396
|
+
const places = await defaultLocations(env, 'internal', r.warehouse.id, r.company.id);
|
|
397
|
+
if (places.source === null)
|
|
398
|
+
throw new orm.ValidationError('indent.request', ['warehouse'], `${r.warehouse.name} has no stock location.`, 'Add its stock location in Stockroom › Configuration › Locations.');
|
|
399
|
+
// A transfer ships into the store's transit location first (the Stock Transfer Note); the receipt follows.
|
|
400
|
+
const transfer = r.kind === 'transfer';
|
|
401
|
+
const made = await env.model('stock.picking').create([
|
|
402
|
+
{
|
|
403
|
+
kind: 'internal',
|
|
404
|
+
company: r.company.id,
|
|
405
|
+
warehouse: r.warehouse.id,
|
|
406
|
+
source: places.source,
|
|
407
|
+
destination: transfer
|
|
408
|
+
? await transitLocation(env, r.warehouse.id)
|
|
409
|
+
: r.destination.id,
|
|
410
|
+
origin: r.name,
|
|
411
|
+
indent: r.id,
|
|
412
|
+
noteKind: transfer ? 'stn' : null,
|
|
413
|
+
moves: {
|
|
414
|
+
create: owed.map((l) => ({
|
|
415
|
+
product: l.product.id,
|
|
416
|
+
name: l.product.name,
|
|
417
|
+
quantity: l.qtyRemaining,
|
|
418
|
+
uom: l.uom?.id ?? null,
|
|
419
|
+
indentLine: l.id,
|
|
420
|
+
})),
|
|
421
|
+
},
|
|
422
|
+
},
|
|
423
|
+
]);
|
|
424
|
+
await made.confirm();
|
|
425
|
+
await env.emit('indent.request.issued', { id: r.id });
|
|
426
|
+
return made.ids[0] ?? null;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* For each validated Stock Transfer Note, the Stock Receive Note of what it shipped: from the store's transit
|
|
430
|
+
* location to the receiving warehouse, confirmed so the goods in transit are reserved for it. Runs in the
|
|
431
|
+
* validation's audited superuser scope.
|
|
432
|
+
*/
|
|
433
|
+
async function receiveNotes(env, pickings) {
|
|
434
|
+
for (const p of await env
|
|
435
|
+
.model('stock.picking')
|
|
436
|
+
.browse([...pickings])
|
|
437
|
+
.load({
|
|
438
|
+
moves: { product: true, uom: true, indentLine: true },
|
|
439
|
+
indent: { destination: true },
|
|
440
|
+
})) {
|
|
441
|
+
if (p.noteKind !== 'stn' || p.indent === null)
|
|
442
|
+
continue;
|
|
443
|
+
const shipped = p.moves.filter((m) => (m.doneQty ?? zero).gt(0));
|
|
444
|
+
if (shipped.length === 0)
|
|
445
|
+
continue;
|
|
446
|
+
const made = await env.model('stock.picking').create([
|
|
447
|
+
{
|
|
448
|
+
kind: 'internal',
|
|
449
|
+
company: p.company.id,
|
|
450
|
+
warehouse: p.indent.destination.warehouse?.id ?? null,
|
|
451
|
+
source: p.destination.id,
|
|
452
|
+
destination: p.indent.destination.id,
|
|
453
|
+
origin: `${p.indent.name} · ${p.name}`,
|
|
454
|
+
indent: p.indent.id,
|
|
455
|
+
noteKind: 'srn',
|
|
456
|
+
moves: {
|
|
457
|
+
create: shipped.map((m) => ({
|
|
458
|
+
product: m.product.id,
|
|
459
|
+
name: m.name,
|
|
460
|
+
quantity: m.doneQty,
|
|
461
|
+
uom: m.uom?.id ?? null,
|
|
462
|
+
indentLine: m.indentLine?.id ?? null,
|
|
463
|
+
})),
|
|
464
|
+
},
|
|
465
|
+
},
|
|
466
|
+
]);
|
|
467
|
+
await made.confirm();
|
|
468
|
+
await env.emit('indent.request.shipped', { id: p.indent.id });
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Writes off what an indent's open receive notes still carry: each is cancelled (its reservations released) and an
|
|
473
|
+
* inventory adjustment takes the goods out of transit, valued as a loss by `stock_account`.
|
|
474
|
+
*/
|
|
475
|
+
async function writeOffShortage(env, id) {
|
|
476
|
+
const [r] = await env
|
|
477
|
+
.model('indent.request')
|
|
478
|
+
.browse([id])
|
|
479
|
+
.load({ pickings: { moves: { product: true, uom: true, indentLine: true } }, company: true });
|
|
480
|
+
if (r === undefined)
|
|
481
|
+
return;
|
|
482
|
+
const open = r.pickings.filter((p) => p.noteKind === 'srn' && p.state === 'confirmed');
|
|
483
|
+
if (open.length === 0)
|
|
484
|
+
return;
|
|
485
|
+
const adjustment = (await env
|
|
486
|
+
.model('stock.location')
|
|
487
|
+
.search({ where: { usage: 'adjustment' }, order: ['id asc'], limit: 1 })).ids[0];
|
|
488
|
+
if (adjustment === undefined)
|
|
489
|
+
return;
|
|
490
|
+
for (const p of open) {
|
|
491
|
+
await env.model('stock.picking').browse([p.id]).cancel();
|
|
492
|
+
const loss = await env.model('stock.picking').create([
|
|
493
|
+
{
|
|
494
|
+
kind: 'adjustment',
|
|
495
|
+
company: r.company.id,
|
|
496
|
+
warehouse: p.warehouse?.id ?? null,
|
|
497
|
+
source: p.source.id,
|
|
498
|
+
destination: adjustment,
|
|
499
|
+
origin: `${r.name} · ${p.name} · ${r.shortageReason ?? ''}`,
|
|
500
|
+
indent: r.id,
|
|
501
|
+
noteKind: 'short',
|
|
502
|
+
note: r.shortageReason,
|
|
503
|
+
moves: {
|
|
504
|
+
create: p.moves.map((m) => ({
|
|
505
|
+
product: m.product.id,
|
|
506
|
+
name: m.name,
|
|
507
|
+
quantity: m.quantity,
|
|
508
|
+
uom: m.uom?.id ?? null,
|
|
509
|
+
indentLine: m.indentLine?.id ?? null,
|
|
510
|
+
})),
|
|
511
|
+
},
|
|
512
|
+
},
|
|
513
|
+
]);
|
|
514
|
+
await loss.confirm();
|
|
515
|
+
await loss.validate();
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
export const IndentRequestLine = defineModel('indent.request.line', {
|
|
519
|
+
label: 'Indent line',
|
|
520
|
+
order: ['request desc', 'sequence asc', 'id asc'],
|
|
521
|
+
access: {
|
|
522
|
+
'indent.user': ALL,
|
|
523
|
+
'indent.store': ALL,
|
|
524
|
+
'indent.manager': [...ALL, 'export', 'import'],
|
|
525
|
+
},
|
|
526
|
+
rules: {
|
|
527
|
+
seeOwn: { groups: ['indent.user'], perms: ['read'], domain: { 'request.requester': me } },
|
|
528
|
+
draftOwn: {
|
|
529
|
+
groups: ['indent.user'],
|
|
530
|
+
perms: ['write', 'create', 'unlink'],
|
|
531
|
+
domain: { 'request.requester': me, 'request.state': { in: ['draft', 'rejected'] } },
|
|
532
|
+
},
|
|
533
|
+
// The deciders see the lines and lower approved quantities while the indent waits for them.
|
|
534
|
+
deciders: {
|
|
535
|
+
groups: ['indent.user'],
|
|
536
|
+
perms: ['read'],
|
|
537
|
+
domain: {
|
|
538
|
+
or: [
|
|
539
|
+
{ 'request.department.head.user': me },
|
|
540
|
+
{ 'request.lines': { any: { 'group.approvalUsers': { any: { id: me } } } } },
|
|
541
|
+
],
|
|
542
|
+
},
|
|
543
|
+
},
|
|
544
|
+
lowering: {
|
|
545
|
+
groups: ['indent.user'],
|
|
546
|
+
perms: ['write'],
|
|
547
|
+
domain: {
|
|
548
|
+
'request.state': 'to_approve',
|
|
549
|
+
or: [
|
|
550
|
+
{ 'request.department.head.user': me },
|
|
551
|
+
{ 'group.approvalUsers': { any: { id: me } } },
|
|
552
|
+
],
|
|
553
|
+
},
|
|
554
|
+
},
|
|
555
|
+
store: { groups: ['indent.store'], perms: ['read', 'write'], domain: {} },
|
|
556
|
+
all: { groups: ['indent.manager'], perms: [...ALL], domain: {} },
|
|
557
|
+
},
|
|
558
|
+
fields: {
|
|
559
|
+
request: f.many2one('indent.request', { required: true, ondelete: 'cascade', label: 'Indent' }),
|
|
560
|
+
sequence: f.integer({ default: 10 }),
|
|
561
|
+
product: f.many2one('product.product', { required: true, ondelete: 'restrict' }),
|
|
562
|
+
group: f.many2one('indent.product.group', {
|
|
563
|
+
ondelete: 'set null',
|
|
564
|
+
label: 'Product group',
|
|
565
|
+
help: 'The group naming the product’s category (or one above it); its approvers decide the indent.',
|
|
566
|
+
store: true,
|
|
567
|
+
...compute('indent.request.line', 'group', ['product', 'product.category'], async (lines) => {
|
|
568
|
+
const env = lines.env;
|
|
569
|
+
for (const l of lines)
|
|
570
|
+
l.group = (await groupOf(env, l.product.id));
|
|
571
|
+
}),
|
|
572
|
+
}),
|
|
573
|
+
uom: f.many2one('uom.uom', { ondelete: 'restrict', label: 'Unit' }),
|
|
574
|
+
quantity: f.decimal({ scale: 3, required: true, default: '1', label: 'Requested' }),
|
|
575
|
+
qtyApproved: f.decimal({
|
|
576
|
+
scale: 3,
|
|
577
|
+
label: 'Approved',
|
|
578
|
+
help: 'As requested when submitted; an approver may lower it, never raise it.',
|
|
579
|
+
}),
|
|
580
|
+
moves: f.one2many('stock.move', 'indentLine'),
|
|
581
|
+
qtyIssued: f.decimal({
|
|
582
|
+
scale: 3,
|
|
583
|
+
store: true,
|
|
584
|
+
label: 'Issued',
|
|
585
|
+
help: 'Issued by validated transfers from the store; for a transfer, received at the other warehouse.',
|
|
586
|
+
...compute('indent.request.line', 'qtyIssued', ['moves.quantity', 'moves.quantityDone', 'moves.picking.state', 'moves.picking.noteKind'], (lines) => {
|
|
587
|
+
for (const l of lines)
|
|
588
|
+
l.qtyIssued = done(l.moves, (k) => k === null || k === 'srn');
|
|
589
|
+
}),
|
|
590
|
+
}),
|
|
591
|
+
qtyShipped: f.decimal({
|
|
592
|
+
scale: 3,
|
|
593
|
+
store: true,
|
|
594
|
+
label: 'Shipped',
|
|
595
|
+
help: 'For a transfer: sent by validated Stock Transfer Notes.',
|
|
596
|
+
...compute('indent.request.line', 'qtyShipped', ['moves.quantity', 'moves.quantityDone', 'moves.picking.state', 'moves.picking.noteKind'], (lines) => {
|
|
597
|
+
for (const l of lines)
|
|
598
|
+
l.qtyShipped = done(l.moves, (k) => k === 'stn');
|
|
599
|
+
}),
|
|
600
|
+
}),
|
|
601
|
+
qtyShort: f.decimal({
|
|
602
|
+
scale: 3,
|
|
603
|
+
store: true,
|
|
604
|
+
label: 'Short',
|
|
605
|
+
help: 'Shipped and never received: written off from transit with the reason.',
|
|
606
|
+
...compute('indent.request.line', 'qtyShort', ['moves.quantity', 'moves.quantityDone', 'moves.picking.state', 'moves.picking.noteKind'], (lines) => {
|
|
607
|
+
for (const l of lines)
|
|
608
|
+
l.qtyShort = done(l.moves, (k) => k === 'short');
|
|
609
|
+
}),
|
|
610
|
+
}),
|
|
611
|
+
inTransit: f.decimal({
|
|
612
|
+
scale: 3,
|
|
613
|
+
label: 'In transit',
|
|
614
|
+
help: 'Shipped, not received yet and not written off.',
|
|
615
|
+
...compute('indent.request.line', 'inTransit', ['qtyShipped', 'qtyIssued', 'qtyShort', 'request.kind'], (lines) => {
|
|
616
|
+
for (const l of lines) {
|
|
617
|
+
const left = (l.qtyShipped ?? zero)
|
|
618
|
+
.minus(l.qtyIssued ?? zero)
|
|
619
|
+
.minus(l.qtyShort ?? zero);
|
|
620
|
+
l.inTransit = l.request.kind === 'transfer' && left.gt(0) ? left : zero;
|
|
621
|
+
}
|
|
622
|
+
}),
|
|
623
|
+
}),
|
|
624
|
+
qtyRemaining: f.decimal({
|
|
625
|
+
scale: 3,
|
|
626
|
+
store: true,
|
|
627
|
+
label: 'Still owed',
|
|
628
|
+
help: 'Approved and not issued yet (in transfers waiting, or not issued at all).',
|
|
629
|
+
...compute('indent.request.line', 'qtyRemaining', [
|
|
630
|
+
'qtyApproved',
|
|
631
|
+
'moves.quantity',
|
|
632
|
+
'moves.quantityDone',
|
|
633
|
+
'moves.picking.state',
|
|
634
|
+
'moves.picking.noteKind',
|
|
635
|
+
'request.state',
|
|
636
|
+
], (lines) => {
|
|
637
|
+
for (const l of lines) {
|
|
638
|
+
if (l.request.state !== 'approved') {
|
|
639
|
+
l.qtyRemaining = zero;
|
|
640
|
+
continue;
|
|
641
|
+
}
|
|
642
|
+
// What open transfers already carry is not owed again (for a transfer: what was shipped or will be).
|
|
643
|
+
const planned = [...l.moves]
|
|
644
|
+
.filter((m) => m.picking.state !== 'cancel' &&
|
|
645
|
+
(m.picking.noteKind === null || m.picking.noteKind === 'stn'))
|
|
646
|
+
.reduce((s, m) => s.plus(m.picking.state === 'done' ? (m.quantityDone ?? m.quantity) : m.quantity), zero);
|
|
647
|
+
const left = (l.qtyApproved ?? zero).minus(planned);
|
|
648
|
+
l.qtyRemaining = left.gt(0) ? left : zero;
|
|
649
|
+
}
|
|
650
|
+
}),
|
|
651
|
+
}),
|
|
652
|
+
onHand: f.decimal({
|
|
653
|
+
scale: 3,
|
|
654
|
+
label: 'On hand in the store',
|
|
655
|
+
help: 'What the store’s warehouse holds of the product now.',
|
|
656
|
+
...compute('indent.request.line', 'onHand', ['product', 'request.warehouse', 'request.company'], async (lines) => {
|
|
657
|
+
const env = lines.env;
|
|
658
|
+
for (const l of lines) {
|
|
659
|
+
const places = await defaultLocations(env, 'internal', l.request.warehouse.id, l.request.company.id);
|
|
660
|
+
l.onHand =
|
|
661
|
+
places.source === null
|
|
662
|
+
? zero
|
|
663
|
+
: await onHandIn(env, l.product.id, places.source);
|
|
664
|
+
}
|
|
665
|
+
}),
|
|
666
|
+
}),
|
|
667
|
+
note: f.char({ size: 300 }),
|
|
668
|
+
rejectReason: f.char({ size: 300, label: 'Lowered because' }),
|
|
669
|
+
},
|
|
670
|
+
sqlConstraints: {
|
|
671
|
+
positive: {
|
|
672
|
+
check: orm.sql `quantity > 0 AND (qty_approved IS NULL OR qty_approved >= 0)`,
|
|
673
|
+
message: 'Requested quantities are positive.',
|
|
674
|
+
},
|
|
675
|
+
},
|
|
676
|
+
constraints: {
|
|
677
|
+
notAbove: {
|
|
678
|
+
...check('indent.request.line', ['quantity', 'qtyApproved'], async (lines) => [...lines].filter((l) => l.qtyApproved?.gt(l.quantity)).map((l) => l.id)),
|
|
679
|
+
message: 'An approved quantity is never above the requested one.',
|
|
680
|
+
},
|
|
681
|
+
},
|
|
682
|
+
onchange: {
|
|
683
|
+
product: onchange('indent.request.line', async (d) => {
|
|
684
|
+
const product = (await d.record('product'));
|
|
685
|
+
if (product === null)
|
|
686
|
+
return;
|
|
687
|
+
if (product.uom !== null)
|
|
688
|
+
d.set('uom', product.uom.id);
|
|
689
|
+
}),
|
|
690
|
+
},
|
|
691
|
+
});
|
|
692
|
+
// Requesters read the stores and locations they ask from, and the issues of their own indents.
|
|
693
|
+
export const WarehouseIndent = extendModel('stock.warehouse', { access: { 'indent.user': READ } });
|
|
694
|
+
export const LocationIndent = extendModel('stock.location', { access: { 'indent.user': READ } });
|
|
695
|
+
// What the store holds, beside each line.
|
|
696
|
+
export const QuantIndent = extendModel('stock.quant', { access: { 'indent.user': READ } });
|
|
697
|
+
export const PickingIndent = extendModel('stock.picking', {
|
|
698
|
+
access: { 'indent.user': READ },
|
|
699
|
+
rules: {
|
|
700
|
+
indentIssues: {
|
|
701
|
+
groups: ['indent.user'],
|
|
702
|
+
perms: ['read'],
|
|
703
|
+
domain: { 'indent.requester': me },
|
|
704
|
+
},
|
|
705
|
+
// Stockroom's own users stay unrestricted (a rule naming indent.user would otherwise bind store keepers).
|
|
706
|
+
stockroom: { groups: ['stock.user'], perms: [...ALL], domain: {} },
|
|
707
|
+
},
|
|
708
|
+
fields: {
|
|
709
|
+
indent: f.many2one('indent.request', { ondelete: 'set null', label: 'Indent' }),
|
|
710
|
+
noteKind: f.selection({ stn: 'Stock Transfer Note', srn: 'Stock Receive Note', short: 'Shortage in transit' }, {
|
|
711
|
+
label: 'Note',
|
|
712
|
+
help: 'For a transfer indent: the shipment into transit, its receipt at the other warehouse, or what was lost on the road.',
|
|
713
|
+
}),
|
|
714
|
+
},
|
|
715
|
+
overrides: {
|
|
716
|
+
// The rest of a partial issue stays with its indent.
|
|
717
|
+
backorderValues: async function (next) {
|
|
718
|
+
const out = await next();
|
|
719
|
+
for (const p of await this.load({}))
|
|
720
|
+
out.set(p.id, { ...out.get(p.id), indent: p.indent?.id ?? null, noteKind: p.noteKind });
|
|
721
|
+
return out;
|
|
722
|
+
},
|
|
723
|
+
// A shipped Stock Transfer Note brings its Stock Receive Note.
|
|
724
|
+
validated: async function (next) {
|
|
725
|
+
await next();
|
|
726
|
+
const pickings = this;
|
|
727
|
+
await receiveNotes(pickings.env, pickings.ids);
|
|
728
|
+
},
|
|
729
|
+
},
|
|
730
|
+
});
|
|
731
|
+
export const MoveIndent = extendModel('stock.move', {
|
|
732
|
+
access: { 'indent.user': READ },
|
|
733
|
+
rules: {
|
|
734
|
+
indentIssues: {
|
|
735
|
+
groups: ['indent.user'],
|
|
736
|
+
perms: ['read'],
|
|
737
|
+
domain: { 'indentLine.request.requester': me },
|
|
738
|
+
},
|
|
739
|
+
// Stockroom's own users stay unrestricted (a rule naming indent.user would otherwise bind store keepers).
|
|
740
|
+
stockroom: { groups: ['stock.user'], perms: [...ALL], domain: {} },
|
|
741
|
+
},
|
|
742
|
+
fields: {
|
|
743
|
+
indentLine: f.many2one('indent.request.line', { ondelete: 'set null', label: 'Indent line' }),
|
|
744
|
+
},
|
|
745
|
+
overrides: {
|
|
746
|
+
backorderValues: async function (next) {
|
|
747
|
+
const out = await next();
|
|
748
|
+
for (const m of await this.load({}))
|
|
749
|
+
out.set(m.id, { ...out.get(m.id), indentLine: m.indentLine?.id ?? null });
|
|
750
|
+
return out;
|
|
751
|
+
},
|
|
752
|
+
},
|
|
753
|
+
});
|
|
754
|
+
export const indentShutro = defineModule({
|
|
755
|
+
name: 'indent',
|
|
756
|
+
version: '0.1.0',
|
|
757
|
+
depends: [hrShutro, productShutro, stockShutro, permissionsShutro],
|
|
758
|
+
groups: [
|
|
759
|
+
orm.defineGroup({
|
|
760
|
+
code: 'indent.user',
|
|
761
|
+
label: 'Requests: own indents',
|
|
762
|
+
implies: ['hr.user', 'product.user'],
|
|
763
|
+
}),
|
|
764
|
+
orm.defineGroup({
|
|
765
|
+
code: 'indent.store',
|
|
766
|
+
label: 'Requests: store keeper',
|
|
767
|
+
implies: ['indent.user', 'stock.user'],
|
|
768
|
+
}),
|
|
769
|
+
orm.defineGroup({
|
|
770
|
+
code: 'indent.manager',
|
|
771
|
+
label: 'Requests manager',
|
|
772
|
+
implies: ['indent.store'],
|
|
773
|
+
}),
|
|
774
|
+
],
|
|
775
|
+
permissions: [
|
|
776
|
+
orm.definePermission({
|
|
777
|
+
code: 'indent.issue',
|
|
778
|
+
label: 'Issue goods for indents',
|
|
779
|
+
groups: ['indent.store'],
|
|
780
|
+
}),
|
|
781
|
+
],
|
|
782
|
+
sequences: [
|
|
783
|
+
orm.defineSequence({
|
|
784
|
+
code: 'indent.request',
|
|
785
|
+
prefix: 'IND/{year}/',
|
|
786
|
+
padding: 5,
|
|
787
|
+
reset: 'yearly',
|
|
788
|
+
}),
|
|
789
|
+
],
|
|
790
|
+
models: [IndentProductGroup, IndentRequest, IndentRequestLine],
|
|
791
|
+
extensions: [WarehouseIndent, LocationIndent, QuantIndent, PickingIndent, MoveIndent],
|
|
792
|
+
});
|