mar-pod-b2b / module-b2b-budget
Company, organizational-unit, and cost-center budgets for Marpod B2B Advanced.
Package info
gitlab.com/mar-pod-b2b/module-b2b-budget
Type:magento2-module
pkg:composer/mar-pod-b2b/module-b2b-budget
Requires
- php: ^8.5
- magento/framework: ^103.0
- magento/module-webapi: ^100.4
- mar-pod-b2b/module-b2b-company: ^1.0
- mar-pod-b2b/module-b2b-core: ^1.0
- mar-pod-b2b/module-b2b-purchase-approval: ^1.0
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-08-24 16:10:46 UTC
README
Company, organizational-unit, and cost-center spending budgets, wired into the existing purchase approval workflow through a plugin — not a fork of it.
Status
Full reservation/consumption engine and Admin UI shipped.
Implemented foundation
- declarative schema:
marpod_b2b_budget(per company, with a period — monthly/quarterly/ yearly/custom — a soft or hard limit, currency, and optionalunit_id/cost_centerfields for manual reporting/tagging),marpod_b2b_budget_reservation(one row per budget × purchase request, status reserved/consumed/released); - automatic budget matching happens at the company level only — the frozen
Marpod_B2bPurchaseApproval\Api\Data\PurchaseRequestInterfacecarries onlycompany_id, sounit_id/cost_centeron a budget are available for manual reporting and filtering but are not used to automatically match a request to a specific unit or cost center's budget (the same, deliberate trade-off as thepayment_method/cost_centerplaceholders inMarpod_B2bAdvancedApproval); - reservation is a plugin, not a workflow fork:
EnforceBudgetOnSubmitPlugin::beforeTransition()hooks the frozenMarpod_B2bPurchaseApproval\Api\PurchaseRequestWorkflowInterface::transition()and reserves the request amount against every active budget covering the request date, on the transition topending_approvalor directly toapproved(covering the auto-approval path when no rule requires a step). Every hard-limit budget is checked before any reservation is written, all-or-nothing — a request that would exceed even one hard budget is blocked with none of the reservations partially applied. The operation is idempotent per budget, so a laterpending_approval -> approvedtransition on the same request does not double-reserve; SettleReservationOnStatusChangeObserverlistens for the existingmarpod_b2b_purchase_request_status_changedevent:approved→consumed,rejected/cancelled/expired→released;BudgetUsageReportInterface::getUsage()— a live aggregation of the reservation rows (reserved/consumed/released/remaining), not a denormalized, cached balance column.
Budget is a spending control, not trade credit — it does not merge with or read
Marpod_B2bCompanyCredit's ledger; the two are independent mechanisms with independent tables.
Integration with Marpod_B2bCompanyHierarchy is limited to the bare unit_id field on a budget
(no hard Composer dependency, no automatic matching) — the same pattern
Marpod_B2bSharedCatalog uses toward Marpod_B2bPricing.
Admin UI
Marpod_B2bBudget::manage (marpod_b2b_budget/budget/index) provides a budget grid and edit
screen with native Magento General, Usage, and Reservations tabs. Usage is rendered as an
informational summary; Reservations provides filtering, paging, empty-state handling, and a native
embedded-grid toolbar. The active tab is restored after reload and rejected form submissions keep
the operator's values.
Budgets expose ACL-protected REST CRUD/search routes under /V1/marpod-b2b/budgets. A
customer-facing GraphQL API is intentionally deferred until the
purchase workflow exposes a reliable authenticated company/unit context; accepting a submitted
company ID would risk cross-company disclosure.
Requirements
- PHP 8.5
- Magento 2.4.9-compatible framework packages
mar-pod-b2b/module-b2b-core,mar-pod-b2b/module-b2b-company,mar-pod-b2b/module-b2b-purchase-approval
Installation
Run from the Magento project root:
composer require mar-pod-b2b/module-b2b-budget:^1.1
bin/magento module:enable Marpod_B2bBudget
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:clean
Development
The planned scope, dependency rules, cache boundaries, security requirements, and test strategy
are documented in packages/B2B_LIGHT_PLAN.md in the development Magento project (section 9.6).
Unit tests:
vendor/bin/phpunit -c dev/tests/unit/phpunit.xml.dist packages/module-b2b-budget/Test/Unit
Admin smoke test:
cd packages/module-b2b-budget/Test/Playwright
npm install
npm test
Limitations
unit_id/cost_centermatching is manual-only, not automatic — see above;- no rollover of unused budget into the next period;
- no notification when a soft budget is exceeded (it is visible in the Usage report only).
Uninstallation
Do not remove the package while another installed module requires it. The marpod_b2b_budget*
tables contain business data and are retained when the module is disabled or its package is
removed; removing it also removes the reservation plugin, so purchase requests submitted
afterward are no longer checked against any budget.