orangecat/module-company-credit

Company credit payment method and balance management for Magento 2 B2B — credit limits, ledger tracking, and automatic refund handling

Maintainers

Package info

github.com/olivertar/m2_companycredit

Type:magento2-module

pkg:composer/orangecat/module-company-credit

Statistics

Installs: 20

Dependents: 1

Suggesters: 1

Stars: 0

Open Issues: 0

0.0.2 2026-06-07 18:28 UTC

This package is auto-updated.

Last update: 2026-06-07 18:52:02 UTC


README

B2B company credit payment method and balance management for Magento 2. Assigns configurable credit limits per company, tracks usage via an immutable ledger, and exposes balance information to both store admins and company admins on the frontend.

Module: Orangecat_CompanyCredit Version: 1.0.0 License: OSL-3.0 Author: Oliverio Gombert olivertar@gmail.com

Table of Contents

  1. Overview
  2. Theme Compatibility
  3. Requirements
  4. Installation
  5. What Gets Installed
  6. Credit Balance Semantics
  7. Configuration Reference
  8. Store Admin Guide
  9. Company Admin Guide (Frontend)
  10. Developer Guide
  11. REST API
  12. Frontend Routes Reference
  13. DevOps & Integrator Notes

Overview

Orangecat_CompanyCredit extends Orangecat_Company with a credit-based payment system. Companies receive a configurable credit line; purchases consume credit, cancellations and credit memos restore it, and every transaction is logged in an auditable ledger.

The module handles:

  • Offline checkout payment method (companycredit) restricted to company customers
  • Per-company credit limit, currency, and exceed-limit toggle
  • Immutable transaction ledger with automatic debit/credit on order events
  • Admin UI for credit configuration and manual adjustments, embedded in the company edit form
  • Frontend credit page for company admins (balance summary + transaction history)
  • Full REST API for credit and ledger management

Position in the Orangecat B2B Dependency Chain

Orangecat_Core (via composer: orangecat/core)
  └── Orangecat_Company
        └── Orangecat_CompanyCredit     ← this module

Theme Compatibility

Theme Status Notes
Luma Supported Standard .phtml template. Less styles via _module.less.
Hyvä Supported Dedicated index_hyva.phtml template with Tailwind CSS. Loaded via hyva_* layout handles.
Breeze Evolution Partial No dedicated Breeze templates. Falls back to Luma index.phtml. Checkout payment JS uses standard RequireJS (Breeze-compatible).

For Breeze-specific overrides: create view/frontend/templates/credit/index_breeze.phtml and view/frontend/layout/breeze_company_credit_index.xml following Breeze conventions.

Requirements

Dependency Version
PHP 8.2+
Magento 2.4.x
Orangecat_Core composer: orangecat/core
Orangecat_Company must be enabled
Magento_Sales core
Magento_Payment core

Installation

Run inside the PHP container (reward shell):

bin/magento module:enable Orangecat_CompanyCredit
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento setup:static-content:deploy -f
bin/magento cache:flush

What Gets Installed

Database Tables

mycompany_credit

One record per company (1:1). Stores the credit configuration and running balance.

Column Type Notes
entity_id int, PK Auto-increment
company_id int, UNIQUE FK mycompany.entity_id (CASCADE DELETE)
currency_code varchar(3) ISO 4217, nullable
credit_limit decimal(20,4) Default 0.0000
balance decimal(20,4) Default 0.0000 — outstanding debt
allow_exceed_limit smallint 0 = no, 1 = yes

mycompany_credit_ledger

Append-only audit log. One row per credit event.

Column Type Notes
entity_id int, PK Auto-increment
company_id int, FK mycompany.entity_id (CASCADE DELETE)
amount decimal(20,4) Negative = purchase/debit; positive = refund/credit
order_id varchar(50) Order increment ID, nullable
comment text Nullable
created_at timestamp Auto CURRENT_TIMESTAMP

No data patches, EAV attributes, or CMS pages are installed by this module.

Credit Balance Semantics

Understanding the sign convention is critical:

Concept Column Direction Example
Balance mycompany_credit.balance Increases on purchase, decreases on refund $1,500 outstanding debt
Credit Limit mycompany_credit.credit_limit Static ceiling $10,000
Available Credit Computed: limit − balance Decreases on purchase $8,500
Ledger: purchase mycompany_credit_ledger.amount Negative number −$1,500
Ledger: refund mycompany_credit_ledger.amount Positive number +$500

A company starts with balance = 0 and available = credit_limit. Each purchase increases balance. Refunds and cancellations decrease balance.

Configuration Reference

Store Configuration — My Company > Company Credit

Path: Stores → Configuration → My Company → Company Credit

Label Config Path Default Description
Enable Company Credit mycompany/company_credit/enabled Yes Master switch. Disables the frontend menu link and the payment method.
Refund Credit on Order Cancel mycompany/company_credit/refund_on_cancel Yes Automatically restore credit when a company credit order is cancelled.
Refund Credit on Credit Memo mycompany/company_credit/refund_on_creditmemo Yes Automatically restore credit when a credit memo is issued.

Payment Methods — Company Credit

Path: Stores → Configuration → Sales → Payment Methods → Company Credit

Label Config Path Default Description
Enabled payment/companycredit/active Yes Activates the payment method entry. Still hidden if mycompany/company_credit/enabled = No.
Title payment/companycredit/title Company Credit Label shown at checkout.
New Order Status payment/companycredit/order_status Pending Status assigned to new orders placed with this method.
Payment from Applicable Countries payment/companycredit/allowspecific All Allowed Countries Restrict to specific countries if needed.
Sort Order payment/companycredit/sort_order Display order among payment methods.

Per-Company Credit Settings (Admin Company Form)

These are stored in mycompany_credit, not core_config_data:

Field Description
Currency Code Currency for this company's credit line (must match store currency at checkout).
Credit Limit Maximum credit amount the company can carry as outstanding balance.
Allow Exceed Limit Yes: company can place orders even if order total > available credit.

Store Admin Guide

Accessing Credit Settings

  1. Go to Companies (main menu) → open any company.
  2. The Company Credit fieldset appears in the company edit form.

Credit Fieldset

UI Element Purpose
Outstanding Balance Read-only. Current used credit (balance).
Available Credit Read-only. Computed: credit_limit − balance.
Credit Limit Editable. Set the ceiling for this company.
Currency Code Editable. ISO 4217 code (e.g., USD, EUR).
Allow Exceed Limit Editable. Yes/No toggle.

Save the company form to persist changes. Credit data is saved via CompanyRepositoryPlugin after the main company save.

Transaction Ledger Grid

Below the credit fieldset, an embedded grid lists all ledger entries for the company:

Column Description
ID entity_id
Amount Positive = refund/credit; negative = purchase/debit.
Order Related order increment ID (if applicable).
Comment Free-text note.
Date UTC timestamp.

Manual Refund / Adjustment

  1. Click Refund button in the credit fieldset.
  2. A modal opens with three fields:
    • Amount (required, must be > 0) — credit to restore.
    • Order ID (optional) — reference to a specific order.
    • Comment (required) — reason for adjustment.
  3. Submit. The system creates a positive ledger entry and decreases balance accordingly.

To edit an existing manual entry (amount > 0, no order ID), click the row action in the ledger grid. The modal reopens pre-populated; saving recalculates the balance delta.

Company Admin Guide (Frontend)

Where to Find Credit Information

After logging in, go to My Account → Company Credit (link in the account navigation sidebar).

Direct URL: https://<store-domain>/company/credit/index

What You See

Credit Summary (three tiles at the top):

Tile Meaning
Outstanding Balance How much your company currently owes.
Available Credit How much you can still spend (limit − outstanding).
Credit Limit Maximum credit your company has been granted.

Transaction History table below the tiles:

Column Meaning
Date When the transaction occurred.
Amount Positive (green) = credit was restored. Negative (red) = credit was consumed.
Comment Description (order reference or admin note).

The list is sorted newest-first. An empty-state message appears if no transactions exist yet.

Paying with Company Credit at Checkout

If your company has available credit (or is allowed to exceed the limit), Company Credit appears as a payment option at checkout. Select it and place the order — no card or external payment is required. The amount is deducted from your available credit immediately upon order placement.

If the payment method is not visible, one of the following applies:

  • The feature is disabled by the store admin.
  • Your company has no credit configuration.
  • The order currency does not match your company's credit currency.
  • Your available credit is insufficient (and the store does not allow exceeding the limit).

Developer Guide

Module Structure

CompanyCredit/
├── Api/                         # Service contracts and data interfaces
├── Block/                       # View blocks (frontend credit page, admin fieldset, modal)
├── Controller/
│   ├── Credit/Index.php         # Frontend credit page
│   └── Adminhtml/Ledger/Save.php  # Admin manual refund save
├── Model/
│   ├── Credit.php               # Entity: mycompany_credit
│   ├── Ledger.php               # Entity: mycompany_credit_ledger
│   ├── CreditRepository.php
│   ├── LedgerRepository.php
│   ├── CreditManagement.php     # Service layer
│   └── Payment/CompanyCredit.php  # Payment method
├── Observer/                    # Three event observers (see below)
├── Plugin/                      # Two interceptors (see below)
├── Ui/Component/                # Admin grid data provider + actions column
└── view/
    ├── adminhtml/               # Admin templates, UI component XML, JS
    └── frontend/                # Luma and Hyvä templates, layouts, Less, CSS, JS

Key Classes

Service Layer

Model/CreditManagement.php — implements Api/CreditManagementInterface.php. All business operations go through here:

Method Description
updateCredit(companyId, currencyCode, creditLimit, allowExceedLimit) Upsert credit record. Only non-null parameters are updated.
getBalance(companyId) Return CreditInterface with current state.
getLedgerByCompanyId(companyId) Return ledger entries sorted by created_at DESC.
refund(companyId, amount, comment) Create positive ledger entry, decrease balance. Validates amount > 0.
updateLedgerEntry(entryId, amount, comment) Edit existing entry; recalculates balance delta.

Payment Method

Model/Payment/CompanyCredit.php — extends Magento\Payment\Model\Method\AbstractMethod. Payment code: companycredit.

isAvailable(?CartInterface $quote) returns false if any of these fail:

  1. mycompany/company_credit/enabled is off.
  2. Customer not logged in or not in a company.
  3. No credit record for the company.
  4. Currency code mismatch between quote and credit record.
  5. quote->getGrandTotal() > available credit AND allow_exceed_limit = 0.

Observers

Class Event Action
Observer/OrderPlaceObserver sales_model_service_quote_submit_success Creates negative ledger entry; increases balance.
Observer/OrderCancelObserver order_cancel_after If refund_on_cancel enabled: finds original entry by order ID, creates positive entry, decreases balance.
Observer/CreditMemoRefundObserver sales_order_creditmemo_save_after If refund_on_creditmemo enabled: same logic as cancel observer but for credit memo amount.

All observers are no-ops when the order's payment method is not companycredit.

Plugins

Class Target Hook Purpose
Plugin/Api/CompanyRepositoryPlugin Orangecat\Company\Api\CompanyRepositoryInterface afterSave() Reads company_credit POST data; upserts mycompany_credit record after company save.
Plugin/Ui/Component/Form/Company/DataProviderPlugin Orangecat\Company\Ui\Component\Form\Company\DataProvider afterGetData() Injects credit_limit, currency_code, allow_exceed_limit into company form data from mycompany_credit.

Both plugins are registered in etc/adminhtml/di.xml (admin area only).

Frontend JS

File Purpose
view/frontend/web/js/view/payment/companycredit.js Registers companycredit renderer in Magento checkout JS.
view/frontend/web/js/view/payment/method-renderer/companycredit-method.js Extends Magento_Checkout/js/view/payment/default.
view/frontend/web/template/payment/companycredit.html Knockout template for the checkout payment step.

Admin JS

File Purpose
view/adminhtml/web/js/grid/columns/refund-actions.js Extends Magento_Ui/js/grid/columns/actions. Manages modal open/close, pre-populates the refund form for edit mode, clears fields on new entry.

ACL Resources

Resource ID Title Location
Orangecat_CompanyCredit::credit Company Credit Under Orangecat_Company::company_manage

Adding Custom Logic

Before credit is deducted — listen to sales_model_service_quote_submit_success (same event, earlier sort order) or create a plugin on CreditManagement::updateCredit.

To extend the Credit or Ledger data objects — add a new preference or extension attribute via extension_attributes.xml targeting CreditInterface / LedgerInterface.

To add a column to the ledger grid — extend view/adminhtml/ui_component/mycompany_credit_ledger_listing.xml via a module merge.

REST API

All endpoints require the Orangecat_CompanyCredit::credit ACL resource (admin token or integration token with that permission).

Method Endpoint Description
GET /V1/mycompany/credit/:companyId Get credit balance and configuration for a company.
PUT /V1/mycompany/credit/:companyId Update credit limit, currency, or allow-exceed flag.
GET /V1/mycompany/credit/:companyId/ledger Get all ledger entries for a company (newest first).
POST /V1/mycompany/credit/:companyId/refund Create a manual credit refund entry.
PUT /V1/mycompany/credit/ledger/:entryId Edit an existing ledger entry and recalculate balance.
DELETE /V1/mycompany/credit/ledger/:entityId Delete a ledger entry by ID.

Examples

# Get credit state for company 5
GET /rest/V1/mycompany/credit/5

# Set credit limit to $50,000 USD, disallow exceed
PUT /rest/V1/mycompany/credit/5
Content-Type: application/json
{
  "creditLimit": 50000,
  "currencyCode": "USD",
  "allowExceedLimit": 0
}

# Manual refund of $1,200
POST /rest/V1/mycompany/credit/5/refund
Content-Type: application/json
{
  "amount": 1200,
  "comment": "Goodwill adjustment — ticket #4412"
}

# Get ledger history
GET /rest/V1/mycompany/credit/5/ledger

Frontend Routes Reference

Route Controller Access
GET /company/credit/index Controller\Credit\Index Logged-in company customer

DevOps & Integrator Notes

Deployment Checklist

# After deploying or updating this module:
bin/magento setup:upgrade          # runs db_schema.xml migrations
bin/magento setup:di:compile       # regenerates interceptors and proxies
bin/magento setup:static-content:deploy -f
bin/magento cache:flush

Integration Token Scope

When creating a Magento integration for ERP/external system credit sync, grant:

  • Orangecat_CompanyCredit::credit
  • Orangecat_Company::company_manage (parent required)

Disabling Without Uninstalling

Set mycompany/company_credit/enabled = No in store config. This hides the frontend menu item and makes the payment method unavailable at checkout without removing any data or database schema.

To also hide the payment method from the admin payment method list: set payment/companycredit/active = No.

Data Integrity

  • Both tables use ON DELETE CASCADE from mycompany.entity_id. Deleting a company removes all its credit and ledger data automatically.
  • There is no soft-delete on ledger entries. Manual deletions via the REST API are permanent.
  • Currency code is stored per-company. If your store currency changes, update the credit record accordingly or the payment method will be unavailable at checkout (currency mismatch check in isAvailable).