Override Behavior with an IsHandled Event
Your freight calculator ships inside a base extension that other teams build on. Marketing wants a free-freight promotion for large orders — but they must not edit your calculator, and you must not hardcode their campaign into it. The Business Central answer is the OnBefore + IsHandled pattern: the calculator raises an integration event before doing its own work, and any subscriber may take over the calculation entirely. The starter already declares the event publisher; wiring it into the calculation and honouring IsHandled is your job.
Requirements
Complete the codeunit named "Freight Charge Calculator" with its public procedure:
procedure CalculateFreight(Amount: Decimal): Decimal- By default, the freight charge is 10% of
Amount, rounded to the nearest cent (0.01). - Before the default runs, the calculator raises the integration event the starter already declares, with exactly this name and signature (the grading tests subscribe to it, so name, parameter order, and
varmodifiers must stay character for character as provided):
OnBeforeCalculateFreight(Amount: Decimal; var Freight: Decimal; var IsHandled: Boolean)- If a subscriber sets
IsHandledtotrue,CalculateFreightreturns whatever that subscriber left inFreight— even when that value is 0 — and the default calculation must not run. - If no subscriber sets
IsHandled— even if one wrote something intoFreight— the default calculation decides the result. OnlyIsHandledmay make that decision.
Then create a second codeunit named "Free Freight Promotion" that subscribes to OnBeforeCalculateFreight:
- For an
Amountof 1000 or more, it grants free freight: the returned charge is 0 and the default must not run. - Below 1000 it leaves the event untouched, so the default charge applies.
- The promotion participates only while a caller has explicitly bound it with
BindSubscription. When nothing has bound it,CalculateFreightmust return the default charge even for an order of 5000.
What the tests check
The tests call CalculateFreight with generated amounts and compare against the 10% formula computed independently, so a hardcoded result fails. A test subscriber overrides Freight with a random value plus IsHandled and expects exactly that value back; another overrides it to exactly 0; a third writes a junk Freight without touching IsHandled and expects the default. The promotion is graded bound (free at exactly 1000, free above 1000, default below 1000) and unbound (default even at a large amount) — the tests bind it with BindSubscription, which errors unless the codeunit is built for manual binding.
Learn More
OnBeforeCalculateFreight is an integration event: a procedure with an empty body and the [IntegrationEvent(false, false)] attribute. Declaring it does nothing by itself — calling it from CalculateFreight is what raises the event, and every subscriber gets to write to its var parameters before your next statement runs.CalculateFreight, raise the event first and run the default formula only when IsHandled is still false afterwards. Base that decision on IsHandled alone: one test writes a junk Freight without setting IsHandled, another overrides Freight to exactly 0.EventSubscriberInstance = Manual; — then it participates only while someone holds it bound via BindSubscription. The promotion's subscriber is [EventSubscriber(ObjectType::Codeunit, Codeunit::"Freight Charge Calculator", 'OnBeforeCalculateFreight', '', false, false)], and at 1000 or more it must set both Freight := 0 and IsHandled := true.