Skip to content

[Bug]: [DE] XRechnung/ZUGFeRD — no posting-time error when SELLER CONTACT (BG-6) source data is incomplete, producing non-compliant e-invoices#9646

Open
miljance wants to merge 1 commit into
microsoft:mainfrom
miljance:EDocDESellerContactBG6
Open

[Bug]: [DE] XRechnung/ZUGFeRD — no posting-time error when SELLER CONTACT (BG-6) source data is incomplete, producing non-compliant e-invoices#9646
miljance wants to merge 1 commit into
microsoft:mainfrom
miljance:EDocDESellerContactBG6

Conversation

@miljance

@miljance miljance commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

What & why

The SELLER CONTACT group (BG-6) is filled from the assigned salesperson, or from Company Information when no salesperson resolves. Neither source was validated at posting time, so a document with incomplete contact data posted successfully and produced XML that fails XRechnung validation (BR-DE-2, BR-DE-5, BR-DE-6, BR-DE-7).

Add "E-Document DE Helper".CheckSellerContactMandatory and call it from the Check of the XRechnung and ZUGFeRD formats. It mirrors the resolution order the export uses: the salesperson supplies BT-41, BT-42 and BT-43 only when the code is set and the record exists, otherwise Company Information supplies them. The error names the missing field and the source it was expected from.

The Company Information E-Mail is deliberately not checked there. It is the same field that supplies the seller electronic address (BT-34), which CheckCompanyInfoMandatory already requires, so the BG-6 fallback cannot be blank once that check passes. CheckCompanyInfoMandatory now documents that BT-34 relationship and runs before the seller contact check.

Tests: 11 mirrored tests in each of the XRechnung and ZUGFeRD suites, covering both branches, every mandatory field, the fallback when the assigned salesperson no longer exists, service documents and the positive cases. The suites are kept in sync deliberately: the check logic is shared, but each format wires it up in its own Check, so a format-specific regression is only caught by that format's own tests.

Linked work

Fixes #8416

How I validated this

  • I read the full diff and it contains only changes I intended.
  • I built the affected app(s) locally with no new analyzer warnings.
  • I ran the change in Business Central and confirmed it behaves as expected.
  • I added or updated tests for the new behavior, or explained below why none are needed.

What I tested and the outcome (required — be specific: scenarios, commands, screenshots for UI changes)

I have tried posting invoices with missing data with and without Salesperson assigned.

Risk & compatibility

Risk & compatibility

Breaking: posting XRechnung/ZUGFeRD documents now fails when the salesperson
(Name / Phone No. / E-Mail) or Company Information (Contact Person / Phone No.)
is incomplete. Intended by the issue, but it surfaces as a new posting failure on
existing data — worth a release note.

Wider than posting: the check sits in the format's Check and ignores
EDocumentProcessingPhase, so it also blocks export of documents posted before
this change. Same behaviour as the existing IBAN and buyer-reference checks.

No opt-out: OnBeforeCheck has no IsHandled, so extensions cannot suppress
the check. Adding it would be the follow-up if customers with incomplete master
data need an escape hatch.

Untested: GetSalespersonCode resolves the field number the same way
CheckBankAccountIBANMandatory already does, but tests only cover Sales Header
and Service Header — not the four posted-document tables.

No impact: no schema, upgrade, permission, telemetry or feature-flag changes.
Translations are build-generated. PEPPOL BIS 3.0 DE is untouched.

…ZUGFeRD documents

The SELLER CONTACT group (BG-6) is filled from the assigned salesperson, or from
Company Information when no salesperson resolves. Neither source was validated at
posting time, so a document with incomplete contact data posted successfully and
produced XML that fails XRechnung validation (BR-DE-2, BR-DE-5, BR-DE-6, BR-DE-7).

Add "E-Document DE Helper".CheckSellerContactMandatory and call it from the Check
of the XRechnung and ZUGFeRD formats. It mirrors the resolution order the export
uses: the salesperson supplies BT-41, BT-42 and BT-43 only when the code is set
and the record exists, otherwise Company Information supplies them. The error
names the missing field and the source it was expected from.

The Company Information E-Mail is deliberately not checked there. It is the same
field that supplies the seller electronic address (BT-34), which
CheckCompanyInfoMandatory already requires, so the BG-6 fallback cannot be blank
once that check passes. CheckCompanyInfoMandatory now documents that BT-34
relationship and runs before the seller contact check.

PEPPOL BIS 3.0 DE is not wired to the new check, so its behaviour is unchanged.

Tests: 11 mirrored tests in each of the XRechnung and ZUGFeRD suites, covering
both branches, every mandatory field, the fallback when the assigned salesperson
no longer exists, service documents and the positive cases. The suites are kept
in sync deliberately: the check logic is shared, but each format wires it up in
its own Check, so a format-specific regression is only caught by that format's
own tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@miljance
miljance requested a review from a team July 21, 2026 12:38
@github-actions github-actions Bot added From Fork Pull request is coming from a fork Finance GitHub request for Finance area needs-approval Workflow runs require maintainer approval to start labels Jul 21, 2026
exit;

SalespersonCode := GetSalespersonCode(SourceDocumentHeader);
if SalespersonCode <> '' then begin

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟡\ Medium\ Severity\ —\ Error\ Handling}$

CheckSellerContactMandatory hand-builds Error() calls with FieldCaption()/TableCaption() to report a mandatory-field violation on Salesperson/Purchaser (Name, Phone No., E-Mail) and Company Information (Contact Person, Phone No.), instead of using TestField or FieldError. Both built-ins already attach the field caption and the record's primary-key context automatically, so this reimplements behavior the platform provides for free and risks the manual composition drifting from the built-in format over time. Since the extra business context here ("required for the seller contact (BG-6)") is a genuine custom reason beyond a generic mandatory-field message, FieldError(FieldNo, CustomMessage) on the record itself is the better fit: it keeps the custom BG-6 reasoning while reusing the platform's caption/record-context formatting instead of assembling it manually with FieldCaption/TableCaption/SalespersonCode.

Knowledge:

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.13.4

@github-actions

Copy link
Copy Markdown
Contributor

$\textbf{🟡\ Medium\ Severity\ —\ Style}$

The new XML doc comment on ZUGFeRDFormat.Codeunit.al's CheckCompanyInfoMandatory says "which XRechnung requires (PEPPOL-EN16931-R020)", but this is the ZUGFeRD format codeunit, not XRechnung. This is a copy-paste artifact from XRechnungFormat.Codeunit.al's identical comment and misattributes the requirement to the wrong format when read by IntelliSense or generated docs. Recommend changing "XRechnung" to "ZUGFeRD" in the comment.

Suggested fix (apply manually — could not be anchored as a one-click suggestion):

    /// <summary>
    /// Checks the Company Information data that the electronic document requires.
    /// The E-Mail supplies the seller electronic address (BT-34), which ZUGFeRD requires
    /// (PEPPOL-EN16931-R020). BT-34 is a party level routing address and is always taken from Company
    /// Information, never from the salesperson, so it is independent of the seller contact (BG-6).
    /// </summary>

Agent judgement — not directly backed by a BCQuality knowledge article.

Line mapping was unavailable, so this was posted as an issue comment.

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why · AL review agent v1.13.4

@github-actions github-actions Bot removed the needs-approval Workflow runs require maintainer approval to start label Jul 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Finance GitHub request for Finance area From Fork Pull request is coming from a fork

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: [DE] XRechnung/ZUGFeRD — no posting-time error when SELLER CONTACT (BG-6) source data is incomplete, producing non-compliant e-invoices

1 participant