quote → cash
EN/FR Contact

Pattern · Billing

Routing invoice lines to the ledger

Get invoice lines into the right accounting account when the invoice carries almost none of the information you need to route on.

Salesforce docs documented by SalesforceField experience observed on a real orgRecommended pattern what we recommendTo verify unverified

The problem

Finance needs each invoice line posted to the correct ledger account, by product family and by tax zone. The assignment rules exist. The information they need does not.

Context

A chart of accounts with several product families, and a tax dimension on top. Dozens of rules, maintained by an accountant rather than an administrator.

Recommended architecture

The constraint that drives the whole design: an invoice line cannot be routed on anything the invoice does not carry. And the invoice carries surprisingly little — no country field, a null billing-profile reference, and a TaxCode on the line that stays empty even after posting.

So bring the two routing dimensions down onto the line with formula fields: the tax zone from the account, the accounting family from the product. Rules then match on family × code, with a single source of truth.

Implementation

  1. Add the two dimensions where they are maintained: the zone on the account, the family on the product.
  2. Bring them down to the invoice line as formula fields.
  3. Deactivate the rule before adding any criterion.
  4. Prove every rule with a real posted invoice. Nothing else proves it.

Trade-offs

Formula fields mean the routing follows the current value of the source, not the value at invoice time. For a tax zone that is usually what finance wants; for anything that must be frozen at posting, use a text field written once.

Watch out

  • Criteria are insert-only. No update, no delete, in Apex or by API. A mistake is permanent, and a rule carrying a criterion can never be deleted — only deactivated. The way out is to add a higher-sequence criterion and change the filter logic.
  • No validation of the field name on insert. Any string is accepted, including a field that does not exist. The error surfaces only at posting.
  • Invoice.BillingAccountId points at Account, not at the BillingAccount object. A naming trap that sends rules looking in the wrong place.
  • A deployed custom field is invisible to SOQL and Apex until field-level security is granted — SOQL answers “No such column”, which reads exactly like a failed deployment.

Salesforce components

Salesforce resources