In B2B wholesale, the time between an order arriving and leaving is mostly spent waiting for two decisions: whether this customer has credit available, and what price they are contractually owed. Both are answerable by the system and are usually answered by a person.

Where the hours go

  1. Credit check. The order sits while someone looks at the account. On a busy day it either ships unchecked or waits until tomorrow.
  2. Price verification. The rep quoted something. Somebody confirms it against a contract that lives in a document.
  3. Quote to order. The CRM has a quote. The ERP needs an order. Frequently a person retypes it.
  4. Pick release. The only genuinely physical step, and usually the fastest one.

Warehouse automation projects target the fourth item because it is visible. The first three are where the day goes.

Credit as a system state

Codeunit 50190 Wholesale Credit Manager.al
codeunit 50190 "Wholesale Credit Manager"
{
    Access = Public;
    Subtype = Normal;

    [EventSubscriber(ObjectType::Table, Database::"Sales Header", 'OnBeforeReleaseSalesDoc', '', false, false)]
    local procedure CheckCustomerCreditLimit(var SalesHeader: Record "Sales Header"; var IsHandled: Boolean)
    var
        Customer: Record Customer;
        OutstandingBalance: Decimal;
        OpenOrderCommitments: Decimal;
        TotalExposure: Decimal;
    begin
        if SalesHeader."Document Type" <> SalesHeader."Document Type"::Order then
            exit;

        if not Customer.Get(SalesHeader."Sell-to Customer No.") then
            exit;

        if Customer."Credit Limit (LCY)" = 0 then
            exit; // Unlimited credit or not configured

        // Calculate Current Credit Exposure
        Customer.CalcFields("Balance (LCY)");
        OutstandingBalance := Customer."Balance (LCY)";
        OpenOrderCommitments := CalculateOpenOrderCommitments(Customer."No.");

        TotalExposure := OutstandingBalance + OpenOrderCommitments + SalesHeader."Amount Including VAT";

        if TotalExposure > Customer."Credit Limit (LCY)" then begin
            SalesHeader.Status := SalesHeader.Status::"On Hold";
            SalesHeader."On Hold" := 'CREDIT_LIMIT';
            SalesHeader.Modify(true);

            Message('Credit Warning: Customer %1 exceeds Credit Limit of %2. Order %3 placed on Hold.',
                Customer."Name",
                Customer."Credit Limit (LCY)",
                SalesHeader."No.");

            IsHandled := true;
        end;
    end;

    local procedure CalculateOpenOrderCommitments(CustNo: Code[20]): Decimal
    var
        SalesLine: Record "Sales Line";
    begin
        SalesLine.SetRange("Sell-to Customer No.", CustNo);
        SalesLine.SetRange("Document Type", SalesLine."Document Type"::Order);
        SalesLine.CalcSums("Outstanding Amount (LCY)");
        exit(SalesLine."Outstanding Amount (LCY)");
    end;
}

The design requirement is that the hold blocks the action instead of notifying someone about it. A warning that can be clicked through is not a control, and under pressure it will be clicked through.

Equally important: define the release path. Who can override a hold, on what basis, and where is that recorded? An override with no audit trail is worse than no hold at all, because it looks like a control in a review.

Contract pricing

Where the price livesWhat goes wrong
A maintained price matrix with effective datesNothing. This is the target state.
A signed contract PDFCorrect and unenforceable — nobody checks it per order.
The rep's spreadsheetDiverges from the contract within a quarter.
Institutional memoryLeaves when the person does.

CRM and ERP, one customer

Where Dynamics 365 Sales sits in front of Business Central, the synchronisation question that matters is not technical. It is which system owns the customer record.

Two systems that both believe they own the customer will overwrite each other, and the pattern is only discovered when a credit limit set in one is reverted by the other.

Measuring it end to end

Track hours from order receipt to shipment across the entire path, not by stage. Stage-level metrics reward moving delay rather than removing it, and every function can show an improvement while the customer's wait is unchanged.