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.
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
- Add the two dimensions where they are maintained: the zone on the account, the family on the product.
- Bring them down to the invoice line as formula fields.
- Deactivate the rule before adding any criterion.
- 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.BillingAccountIdpoints 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
Architecture
Guide