bcquality/microsoft/knowledge/data-modeling/report-barcodes-must-use-barcode-module-and-production-font-name.md
Michael Dieringer eb9cae0af4 Fix 5 merge-critical issues from Jesper's 2026-09-24 review round
- 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>
2026-09-24 21:10:19 +02:00

5.1 KiB

bc-version domain keywords technologies countries application-area
all
data-modeling
barcode
qr-code
barcode-font-provider
barcode-font-provider-2d
report-layout
saas
idautomation
code-39
checksum
al
w1
all

Generate report barcodes through the Barcode module, with the production font name

Description

Business Central's barcode support lives in the System Application's Barcode module (src/System Application/App/Barcode): interface "Barcode Font Provider" / "Barcode Font Provider 2D", enum "Barcode Symbology" / "Barcode Symbology 2D", and built-in implementations (codeunit 9215/9221). A report encodes a data string via this API; the layout then displays it using a barcode font.

The two interfaces are not symmetric: "Barcode Font Provider" (1D) declares both ValidateInput and EncodeFont; "Barcode Font Provider 2D" declares only EncodeFont (see Source). BCApps' Item GTIN Label report reflects that split exactly — it validates then encodes through the 1D provider, but only encodes through the 2D provider, for the same "No." value.

On Business Central online this needs no setup ("the IDAutomation fonts are automatically available as part of the service" — Microsoft Learn), unlike on-premises, where fonts must be purchased and installed. That ease hides a SaaS-specific trap the API doesn't cover: naming the actual font. IDAutomation ships both a purchased font and a same-looking evaluation font per version (Code 39: IDAutomationHC39M purchased vs. IDAutomationSHC39M Demo) — per Microsoft Learn, "be sure to use the purchased font name... If you use the evaluation font name, the barcode won't render." The wrong name produces nothing, in the layout not AL, so no reviewer catches it reading the object.

Best Practice

Encode through the real API, matching the calls to what the chosen interface actually declares. One-dimensional: declare Interface "Barcode Font Provider" and call both ValidateInput and EncodeFont — skipping validation lets a value outside the character set, or one needing a checksum setting never applied, reach the font unchecked. Two-dimensional: declare Interface "Barcode Font Provider 2D" and call EncodeFont alone — there is no ValidateInput on this interface.

Treat naming the production font in the layout as equally required, not an afterthought. Two-dimensional symbologies other than Maxicode use IDAutomation2D (Maxicode: IDAutomation2D MaxiCode); one-dimensional symbologies use the purchased version name (e.g. IDAutomationHC39M for Code 39), never a name containing Demo.

See sample: report-barcodes-must-use-barcode-module-and-production-font-name.good.al.

Anti Pattern

Constructing a barcode string by hand instead of using the module's provider/encoder API — not because a manual delimiter is inherently wrong (Code 39's own symbology does use * as start/stop; Microsoft Learn's font table says so), but because hand-rolled construction is demonstrably mismatched with what the real encoder produces: it skips ValidateInput (so a value outside the character set, or needing a checksum/extended-charset setting never applied, reaches the font unvalidated), and IDAutomation 1D Provider's own Code 39 output is wrapped in (/), not literal * (BCApps test: EncodeFont('1234', Code39) = '(1234)') — the paired font maps those parentheses to the real start/stop glyph, so '*' + value + '*' is simply the wrong characters, plus no checksum.

Flag demonstrably invalid or mismatched hand construction, not manual delimiter use as a category — a custom provider paired with a font that genuinely expects literal * delimiters is a different, legitimate case.

A second version of the same mistake: encoding correctly, but naming the evaluation font instead of the purchased one. Both look complete in review and fail silently — the first because the data was never a real barcode, the second because BC online refuses to render it.

See sample: report-barcodes-must-use-barcode-module-and-production-font-name.bad.al.

Source

BCApps (src/System Application/App/Barcode/src/): Barcode Provider/Font/BarcodeFontProvider.Interface.al (1D: ValidateInput + EncodeFont); Barcode Provider 2D/Font/ BarcodeFontProvider2D.Interface.al (2D: only EncodeFont); both read fresh from source. IDAutomation 1D Provider/Encoders/ IDA1DCode39Encoder.Codeunit.al (codeunit 9204, regex accepts literal * as plain input; EncodeFont → DotNet FontEncoder.Code39). Split and delimiter mismatch both confirmed live: .../Inventory/Item/ ItemGTINLabel.Report.al (report 6625, validates+encodes 1D, only encodes 2D, same value) and .../Test/Barcode/.../IDA1DCode39Test. Codeunit.al (codeunit 135044): EncodeFontSuccessTest('1234', Code39, '(1234)') — wrapped in (/), never literal *.

Microsoft Learn "Adding Barcodes to Reports" and "Barcode Fonts with Business Central Online" — quoted above, incl. the Code39 row ("* is used for both start and stop delimiters").