Company Credit Limits in Magento 2: Modeling Credit for Company Accounts
AI generated
M2
di.xml
Magento 2 · B2B Suite
Company Credit Limits
Modeling credit limits for company accounts

Company Credit Limits let company customers order against an invoice up to a defined balance, with its own history, its own checkout validation, and a connection to the Payment on Account method. Building a custom approval workflow for overruns means understanding exactly how and when Magento actually calculates and reserves the available balance.

12 min read Company Credit · B2B Suite Magento 2.4.x Commerce

1. Placing Company Credit Limits in the B2B module

Company Credit Limits are part of the Magento_CompanyCredit module from the B2B Suite and model a classic credit limit, the kind familiar from B2B business outside Magento: a company receives a defined balance against which orders can be booked through the Payment on Account method, without requiring immediate payment for every single order.

Functionally this differs significantly from a simple payment term: it is not just about when an invoice becomes due, but also about how much open amount is allowed to be outstanding at the same time. Only the interplay of credit limit, currently outstanding amount, and payment terms produces the full picture Magento maintains for a company.

2. The data model: company_credit and company_credit_history

A company's credit balance is stored in the company_credit table, with fields such as company_id, credit_limit for the total granted balance, outstanding_balance for the currently open amount, and currency_code for the currency the balance is maintained in. The actually available balance does not come from its own stored column but is calculated as the difference between credit_limit and outstanding_balance.

Every change to the balance, whether from a new order, a payment, a credit memo, or a manual adjustment by an administrator, is additionally logged as its own entry in company_credit_history, including operation type, amount, and a reference to the triggering object. That history is the primary source of traceability and should always be preferred over company_credit as a plain state store for custom reporting.

3. How checkout validates the available balance

As soon as a customer selects Payment on Account as the payment method at checkout, the credit limit logic checks that the order value does not exceed the company's currently available balance. Technically this check runs through a dedicated service that compares credit_limit and outstanding_balance against the current order's grand total before the payment method is even offered as a valid option or finally accepted.

What matters for custom extensions is the timing of the reservation: the outstanding balance is increased already when the order is placed, not only once it is later invoiced. That prevents multiple orders placed nearly simultaneously from jointly exceeding the credit limit, since each order reduces the available balance immediately rather than only after asynchronous processing.


<?php

declare(strict_types=1);

namespace Mironsoft\CompanyCreditExtension\Model;

use Magento\CompanyCredit\Api\CreditLimitRepositoryInterface;

/**
 * Resolves the currently available credit balance for a company.
 */
class AvailableCreditReader
{
    /**
     * @param CreditLimitRepositoryInterface $creditLimitRepository
     */
    public function __construct(private readonly CreditLimitRepositoryInterface $creditLimitRepository)
    {
    }

    /**
     * Returns the available balance as the difference between limit and outstanding amount.
     *
     * @param int $companyId
     * @return float
     */
    public function getAvailableCredit(int $companyId): float
    {
        $credit = $this->creditLimitRepository->getByCompanyId($companyId);

        return (float) $credit->getCreditLimit() - (float) $credit->getOutstandingBalance();
    }
}

4. Custom approval workflows on overrun

By default, Magento hard-blocks an order via Payment on Account when the available balance is insufficient, unless an administrator has explicitly allowed orders to push the balance negative. For many B2B projects this binary logic falls short, because a sales rep may well want to approve a minor overrun on a case-by-case basis without permanently raising the global limit.

A clean approach is replacing the hard block with a custom intermediate step: instead of rejecting the order, it gets marked with a custom status such as pending_credit_approval and routed to a defined approver role. Technically this combines cleanly with the B2B Suite's existing purchase order approval rules, adding a custom rule that reacts specifically to a credit limit overrun rather than rebuilding the entire approval logic from scratch.

5. Replacing the block with an approval requirement

Technically, the hard block can be intercepted through an around plugin on the credit check. Instead of passing the original exception through unchanged, the plugin checks whether the overrun falls within a defined tolerance, and in that case marks the order for manual approval instead of rejecting checkout entirely.

When implementing this, it matters that the custom tolerance check does not bypass the fundamental credit limit check, but only refines the behavior on overrun. An order far beyond any reasonable tolerance should still be hard-blocked, so the credit limit is not undermined as a control mechanism by the custom extension.


<!-- app/code/Mironsoft/CompanyCreditExtension/etc/di.xml -->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\CompanyCredit\Model\Validator\CreditLimitValidator">
        <plugin name="mironsoft_credit_tolerance"
                type="Mironsoft\CompanyCreditExtension\Plugin\CreditToleranceApprovalPlugin"
                sortOrder="10"/>
    </type>
</config>

6. Interplay with payment terms

The credit limit and payment terms such as Net 30 are two separate but interacting mechanisms. The credit limit controls how much total amount may be outstanding at the same time, while the payment term determines by when a single invoice has to be settled. A company with generous payment terms but a low credit limit can still quickly hit its ceiling if several orders accumulate within the payment window.

For custom reports or dashboards it therefore matters to look at both values together instead of relying on just one of them. A company can have a technically available balance of zero and still not have shown an overdue invoice for weeks, if all open amounts are still within their payment term, which represents a different priority for finance teams than a genuinely overdue receivable.

7. Adjusting credit limits programmatically

Through CreditLimitRepositoryInterface and the associated management service, a company's credit limit can be read and adjusted programmatically, which matters for integration with an external ERP or accounting system when creditworthiness checks and limit adjustments are maintained centrally in another system and Magento is only meant to take over the current limit as a downstream system.

For such an integration, it is worth logging every external adjustment of the limit as its own entry in company_credit_history as well, with a clearly identifiable operation type such as external_sync, so it can later be traced whether a change originated in Magento itself or in the connected external system.

8. Notifications on critical balances

Magento offers notifications out of the box when an order cannot be placed via Payment on Account due to insufficient balance, but does not cover a proactive warning, for example when the available balance drops below a certain threshold before any concrete order actually fails. For an early-warning system, an observer on the event triggered by every change to the outstanding amount is a good fit.

That observer can check the new available balance against a configured warning threshold and trigger a notification to the sales or finance team when it falls below it, ideally through asynchronous processing so the actual credit booking is not delayed by the notification logic.

9. Operations: multi-currency and accounting reconciliation

Since the credit balance is maintained in a fixed currency, handling multi-currency stores deserves particular attention: an order in a different currency than the stored credit currency has to be converted correctly before the check, and rounding differences from that conversion should be traceably documented in the history rather than vanishing unexplained into the outstanding amount.

For stores with connected accounting, a regular reconciliation between the outstanding_balance maintained in Magento and the actual open item in the accounting system is also worthwhile, since manual adjustments in the accounting system, such as early payment discounts or partial payments, do not automatically sync back to Magento unless a custom integration exists for that.

Term Meaning Stored in Affects
credit_limit Total granted balance company_credit Available balance at checkout
outstanding_balance Currently open amount company_credit Available balance at checkout
Available balance credit_limit minus outstanding_balance Calculated, not stored Whether Payment on Account is allowed
History entry A single balance change with type company_credit_history Traceability and audits
Payment term Due date of individual invoices Order/Invoice Due date, not the limit itself

Mironsoft

Magento development, module consulting, and system architecture

A Magento project that needs a second opinion or experienced execution?

We build custom Magento modules, advise on architecture decisions, and take on complex implementations, from service contract planning to production-ready deployment.

Architecture Consulting

Have module and system architecture thought through properly before you build.

Custom Module Development

Build custom Magento modules cleanly, following best practices.

Code Review & Audit

Have existing modules reviewed for performance, security, and maintainability.

10. Summary

Company Credit Limits

Data model

company_credit holds the limit and outstanding amount, company_credit_history logs every single change.

Validation

The balance is reserved already at order placement, not only when the order is later invoiced.

Extensibility

An around plugin on the credit check can replace hard blocks with an approval workflow.

Operations

Multi-currency conversion and regular reconciliation with accounting deserve particular attention.

11. FAQ: Company Credit Limits

1Where is a company's credit limit stored?
In the company_credit table, with the fields credit_limit for the total balance and outstanding_balance for the currently open amount.
2How is the available balance calculated?
As the difference between credit_limit and outstanding_balance, calculated at check time rather than maintained as its own stored column.
3When is the outstanding balance increased?
Already when the order is placed, not only when it is later invoiced, to prevent near-simultaneous orders from jointly exceeding the limit.
4Does Magento always hard-block an order on overrun?
By default yes, unless an administrator has explicitly allowed orders to push the balance negative.
5How can an approval workflow replace a hard block?
Through an around plugin on the credit check that marks an overrun within a defined tolerance for manual approval instead of rejecting it.
6How do the credit limit and payment terms relate to each other?
The credit limit controls the total allowed open amount, the payment term controls the due date of individual invoices. Both values should be viewed together.
7Can the credit limit be adjusted from an external system?
Yes, through CreditLimitRepositoryInterface, with every external adjustment ideally logged with its own operation type in company_credit_history.
8Is there a way to proactively warn about a low balance?
Not by default, but an observer on balance changes can check the available balance against a warning threshold and trigger a notification when needed.
9What should be considered on multi-currency stores?
Orders in a currency other than the credit currency have to be converted before the check, and rounding differences should stay traceable in the history.
10Does Magento sync automatically with accounting?
No, manual adjustments in the accounting system, such as partial payments, do not sync back to Magento automatically without a custom integration.