- activate-new-price-calculation-handler-via-onfindsupportedsetup: Default := true is required only for the fallback branch of PriceCalculationMgt's two-stage FindSetup - a handler reachable via a specific Dtld. Price Calculation Setup row needs no Default. Softened the article and its worklist cue accordingly. Also fixed an undefined "Sample Price Calc - Special" codeunit referenced but never declared in the eval fixtures - added a real implementation of interface "Price Calculation" with stub methods. - new-price-source-must-add-candidate-and-trigger-recalculation: the good fixture called UpdateUnitPriceByField directly, which is a silent no-op without a prior PlanPriceCalcByField call (FieldCausedPriceCalculation gating, verified against SalesLine.Table.al). Switched to the public UpdateUnitPrice wrapper, matching real BCApps usage in ItemReferenceManagement.Codeunit.al. - report-barcodes-must-use-barcode-module-and-production-font-name: split the 1D (ValidateInput + EncodeFont) and 2D (EncodeFont only) Barcode Font Provider interfaces, which the article previously conflated. Reframed the Code 39 anti-pattern around demonstrable encoding/checksum mismatch (verified against IDA1DCode39Encoder.Codeunit.al's real '(value)' output) rather than rejecting all manual delimiter use, since '*' is a legitimate Code 39 start/stop character. Also fixed extend-find-entries-navigate- for-new-document-types' eval fixtures, which referenced an undefined "Sample Posted Document Header" table/page - declared both. All claims re-verified against live microsoft/BCApps source. Validators: frontmatter 0/0, review-fixtures 126/20 domains PASSED, knowledge-index 342/575 PASSED, skill-index 19 leaves PASSED. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
5.4 KiB
| bc-version | domain | keywords | technologies | countries | application-area | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
data-modeling |
|
|
|
|
Activate a new Price Calculation Handler through OnFindSupportedSetup, not just by implementing it
Description
enum 7011 "Price Calculation Handler" (implements "Price Calculation") is how a new pricing engine plugs into Business Central —
extend the enum with a value pointing at a codeunit that implements the
Price Calculation interface. That alone does not make the new handler
usable on any document. codeunit 7001 "Price Calculation Mgt." decides
which handler applies to a given line by looking up table 7006 "Price Calculation Setup", a table of (Code, Method, Type, Asset Type, Implementation, Enabled, Default) rows populated at startup by its own
OnFindSupportedSetup event — every implementation codeunit is expected
to subscribe to that event and insert its own setup row(s). A handler
enum value with no matching setup row is real and selectable in the enum
itself, but never chosen for any actual sale, purchase, or job line,
because Price Calculation Mgt. has no setup row that names it.
FindSetup resolves a handler in two stages, and only the second one
looks at Default. It first asks codeunit 7004 "Price Calculation Dtld. Setup" to match the line against table 7008 "Dtld. Price Calculation Setup" ("Detailed Price Calculation Setup", keyed to an exact
Method/Type/Asset Type/Source/Asset No. combination via its own
"Setup Code"); on a match it does PriceCalculationSetup.Get(... "Setup Code") directly, with no Default filter. Only when no detailed
row matches does it fall back to SetRange(Default, true) plus
SetRange(Method, ...) to pick the one catch-all row for that
combination. A row without Default := true is invisible to that
fallback, but not invisible outright — a detailed-setup row can still
select it by naming its Code. A row whose Method matches neither path
is invisible either way — same symptom, different cause.
Best Practice
Ship a new Price Calculation Handler value together with an
OnFindSupportedSetup subscriber that inserts at least one Price Calculation Setup record naming it as the Implementation, for the
relevant Method (e.g. "Lowest Price"), Type (Sale/Purchase), and
Asset Type. Default := true is required only when this row is the
fallback for that combination — the row FindSetup's own
SetRange(Default, true) branch selects when no more specific setup
applies. A handler meant to be selected only for specific customers or
items should instead be reachable through a matching "Dtld. Price Calculation Setup" row; FindSetup resolves that before it ever checks
Default, so it needs no Default := true.
See sample: activate-new-price-calculation-handler-via-onfindsupportedsetup.good.al.
Anti Pattern
Extending Price Calculation Handler and implementing the Price Calculation interface, without subscribing to OnFindSupportedSetup to
insert a setup record. The new handler exists, compiles, and can even be
selected manually if a user creates their own Price Calculation Setup
row through the UI — but ships with no default row, so it's never active
for anyone until someone notices it's missing and configures it by hand.
See sample: activate-new-price-calculation-handler-via-onfindsupportedsetup.bad.al.
Source
BCApps (src/Layers/W1/BaseApp/Pricing/Calculation/):
PriceCalculationHandler.Enum.al (enum 7011 "Price Calculation Handler" implements "Price Calculation"); PriceCalculationMgt.Codeunit.al
(OnFindSupportedSetup(var TempPriceCalculationSetup: Record "Price Calculation Setup" temporary), and FindSetup(...): Boolean, which
first calls PriceCalculationDtldSetup.FindSetup(DtldPriceCalcSetup) and
on a match does PriceCalculationSetup.Get(... "Setup Code") with no
Default filter — only on failure does it fall back to
SetRange(Enabled, true), SetRange(Default, true), SetRange(Method, ...)); PriceCalculationSetup.Table.al (table 7006 "Price Calculation Setup": Code, Method, Type, "Asset Type", Implementation,
Enabled, Default); PriceCalculationDtldSetup.Codeunit.al (codeunit 7004 "Price Calculation Dtld. Setup", FindSetup(var DtldPriceCalcSetup: Record "Dtld. Price Calculation Setup"): Boolean, matching progressively
looser Source Group/Source No./Asset Type/Asset No. combinations —
never Default); DtldPriceCalculationSetup.Table.al (table 7008 "Dtld. Price Calculation Setup", Caption "Detailed Price Calculation Setup",
"Setup Code" relates to "Price Calculation Setup".Code where(Enabled = const(true)) — no Default condition).
Microsoft Learn, "Extending Price Calculations": "Each codeunit that implements the Price Calculation interface must subscribe to the OnFindSupportedSetup() event... to fill the price calculation setup table." Same article: "You can enter detailed setup records for non-default setup lines... If a matching setup is found its implementation is used... If there is no matching setup exception, we use the default implementation." (https://learn.microsoft.com/dynamics365/business-central/dev-itpro/developer/devenv-extending-best-price-calculations)