Pricing·Advanced·11 min·Updated 2026-10-13
Negative amendment at zero: the line that does not know it has a price
Removing licences by amendment produces a line at zero, so no credit note. Three weeks of dead ends, a dead branch inside the standard procedure, and the Map Line Item step that was missing.
How claims are labelled
Scroll the diagram sideways
The rule that keeps a catalog maintainable: a decision table only when there is a condition or a tier. A flat price belongs on the PricebookEntry. Decision tables added by reflex are what fills a procedure up to its element ceiling.
And the procedure that runs is the compiled _Auto version, not the source you edit.
The positive amendment works perfectly: +2 licences, prorated amount, correct invoice. That asymmetry is what takes three weeks to explain.
The engine knew the price
First instinct: the price is lost somewhere. Wrong.
The line detail — the detail record attached to the quote line, and its equivalent on the order — carries the correct negotiated price, the correct negative quantity, and the reference to the original sale. Only its total price is zero. Terrain
The engine never lacked information. It lacked a multiplication.
The dead branch
In the standard procedure, the group that handles “last transaction price” lines is filtered
on an ItemPricingSource attribute equal to LastTransaction. That
attribute is fed by a pricing source field on the quote line and the order line. On our org on
Summer ’26, that field existed on the asset only. The attribute was therefore
empty everywhere, and the group never ran. Terrain
Normal lines take the opposite branch, “not equal to LastTransaction”, which an empty value satisfies. That is exactly why the positive amendment worked and the negative one did not.
We revived the filter to test it. The line stayed at zero: the group’s formula was multiplying a net price that was empty at line level. The price was on the detail, not on the line. It was not a mis-set filter, it was a missing step.
The dead ends, and why they fail
- An Apex hook in the procedure plan. To set the price before the procedure runs. The hook does write into the context, but the pricing section that follows re-reads the records and overwrites everything. Terrain
- Setting the price by hand on the amendment order. “Reprice All” clears it, then locks it: “You can’t edit the Unit Price because the Order Product has related Order Product Detail records.” Terrain
- Blaming the quote. The order behaves identically. The problem is in the procedure, not in the entry object. Terrain
The answer: Map Line Item
Salesforce support gave us the key. With Advanced Transaction Detail Line Pricing enabled, the procedure must contain the Map Line Item element, in second position, right after pricing settings. It connects the line to its details. Without it, values do not travel between the two levels. Doc
A demo sandbox without that advanced setting did not have the problem. That is what made the bug so hard to reproduce — and why it is documented nowhere as a symptom.
In metadata the element is called BreakdownLineMapping: a value of the action
type on an expression set step, from API 64 onwards. Its parameters are documented
nowhere. We took them from a public reference repository: one section per attribute,
input to output, from the transaction item to its detail, eighteen sections in total.
Terrain
Result: the −1 amendment comes out prorated, at the right price, and the negative schedule follows. Terrain
The Winter ’27 trap that blocked everything
In production, on Winter ’27, no procedure containing a list price step could be saved at all: “Ensure that the lookup table in the ListPrice step is valid.” Not even a brand new procedure generated by Salesforce itself. Terrain
The cause: the pricing recipe, created before Winter ’27, had an empty usage subtype. Winter ’27 validates lookup tables against a recipe with the Revenue Cloud subtype, and the field cannot be changed on an existing recipe. A second recipe has to be created, with the same mappings and the right subtype. Terrain
And two reflexes that save a day:
- An active version cannot be edited. Add a higher-ranked version; the previous one stays in place to roll back to.
- Never deactivate the production version before the new one is active. A procedure with no active version means pricing is dead — and the symptom, every line at list price, looks exactly like the bug you just fixed.
What remains open
- The detail picks up list price, not the negotiated price. When nothing feeds it the last transaction. Depending on your credit policy, that is a finance decision, not a configuration one.
- Billing a native swap. Rejects SwapIn and SwapOut lines as soon as one is present in the call. Filtering those lines lets you bill the new bundle, not credit the old one. Terrain
The neighbouring symptom — a renewal coming out at list price — has a different cause and its own walkthrough: see Renewal at list price.
Salesforce components
Select one to open its detail.
What this is based on
- The problem only appears with Advanced Transaction Detail Line Pricing enabled. Check that setting first: without it, this is not your bug.
- The pricing source field has since appeared on our org. The behaviour of the last transaction branch may therefore change with a release: verify on yours.
- The
BreakdownLineMappingparameters come from a public repository, not from official documentation. They work; they are not guaranteed. - Observed on an org running Summer ’26 / Winter ’27.