Posted on 23/07/2026 11:47:07
Hi Jason,
there were new features implemented for the Discounts and now the property TotalDiscount is recalculated on the getter access. So that is why setting it in the custom provider doesn't work.
The workaround is to use the framework's own existing mechanism for an explicit, exact discount amount: a sibling OrderLineType.ProductDiscount line, which CalculateTotalDiscount() sums additively on top of the percentage-based part:
orderLine.DiscountPercentage = 0; // avoid double-applying a percentage-based discount too
var marker = "LiveIntegrationDiscount"; // any stable identifier you control
var discountLine = order.OrderLines.FirstOrDefault(l =>
l.OrderLineType == OrderLineType.ProductDiscount &&
string.Equals(l.ParentLineId, orderLine.Id, StringComparison.OrdinalIgnoreCase) &&
string.Equals(l.DiscountId, marker, StringComparison.Ordinal));
bool isNew = discountLine is null;
discountLine ??= new OrderLine(order)
{
OrderLineType = OrderLineType.ProductDiscount,
ParentLineId = orderLine.Id,
Quantity = 1,
DiscountId = marker,
ProductName = "Discount"
};
var discountPrice = new PriceInfo(order.Currency)
{
PriceWithVAT = -Math.Abs(orderLineTotalDiscountWithVAT),
PriceWithoutVAT = -Math.Abs(orderLineTotalDiscountWithoutVAT)
};
// forcePriceRecalculation:true is required here — Order.Calculate is false for imported/live-integration
// orders, so OrderLine.Price would otherwise stay at its old stored value instead of picking up UnitPrice.
Services.OrderLines.SetUnitPrice(discountLine, discountPrice, forcePriceRecalculation: true);
if (isNew)
order.OrderLines.Add(discountLine);
The DiscountId marker + lookup means re-running the live integration against the same order updates the existing discount line instead of stacking a new one every time (which would otherwise double/triple the discount on each sync).
After this, orderLine.TotalDiscount.PriceWithVAT/PriceWithoutVAT will read back correctly (via the getter, which now sums this child line's Price plus a zero percentage-based contribution) — matching what the integration intended, without touching any of the currently-broken direct-assignment paths.
Kind regards,
Dmitrij