Search by

mar-pod-b2b / module-b2b-budget

Company, organizational-unit, and cost-center budgets for Marpod B2B Advanced.

Maintainers

Package info

gitlab.com/mar-pod-b2b/module-b2b-budget

Issues

Type:magento2-module

pkg:composer/mar-pod-b2b/module-b2b-budget

Transparency log

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

1.1.10 2026-08-24 16:09 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 optional unit_id/cost_center fields 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\PurchaseRequestInterface carries only company_id, so unit_id/cost_center on 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 the payment_method/cost_center placeholders in Marpod_B2bAdvancedApproval);
  • reservation is a plugin, not a workflow fork: EnforceBudgetOnSubmitPlugin::beforeTransition() hooks the frozen Marpod_B2bPurchaseApproval\Api\PurchaseRequestWorkflowInterface::transition() and reserves the request amount against every active budget covering the request date, on the transition to pending_approval or directly to approved (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 later pending_approval -> approved transition on the same request does not double-reserve;
  • SettleReservationOnStatusChangeObserver listens for the existing marpod_b2b_purchase_request_status_changed event: approvedconsumed, rejected/cancelled/expiredreleased;
  • 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_center matching 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.