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 (backport to releases/29.0) - #11818

Open
Miljan Milosavljević (miljance) wants to merge 1 commit into
microsoft:releases/29.0from
miljance:backport/releases/29.0/9646/20260923171736

Conversation

@miljance

@miljance Miljan Milosavljević (miljance) commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

What & why

This is a backport of #9646 to releases/29.0. It cherry-picks the same main squash commit (c14b01a2) — no code adaptation was needed (clean cherry-pick).

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

Backport of #9646.

Fixes #8416
AB#651267

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

This is a backport of the already-merged and validated #9646. The cherry-pick of the main squash commit onto releases/29.0 applied cleanly with no conflicts, and the resulting diff is byte-identical to the diff of #9646 (5 files, +717, no app.json change). The backport itself was not built or run against a container. The original change was built and validated in #9646 (posting invoices with missing data, with and without an assigned Salesperson).

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.

🤖 Generated with Claude Code

…TACT (BG-6) source data is incomplete, producing non-compliant e-invoices (microsoft#9646)

<!--
Thanks for contributing to BCApps!

A few things before you hit "Create pull request":
- Your PR must link to an approved issue. New here? See CONTRIBUTING.md.
- You must have built and run your change yourself. CI is a safety net,
not a substitute.
- If you used AI or an agent to write this PR, you are still the author.
Read the diff,
  build it, and try it before requesting review.

Contributing guide:
https://github.com/microsoft/BCApps/blob/main/CONTRIBUTING.md
Local dev environment:
https://github.com/microsoft/BCApps/blob/main/LOCAL_DEV_ENV.md
-->

## 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.

<!-- A few sentences: what does this change do, and what problem does it
solve? -->

## Linked work

<!-- Required: link an approved GitHub issue using "Fixes #<number>".
Microsoft contributors: also link the ADO work item with "AB#<number>"
if you have one. -->

Fixes microsoft#8416

[AB#650455](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/650455)

## How I validated this

- [x] I read the full diff and it contains only changes I intended.
- [x] I built the affected app(s) locally with no new analyzer warnings.
- [x] I ran the change in Business Central and confirmed it behaves as
expected.
- [x] 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)*

<!-- Example:
- Ran the new "Post and Send" action on a sales invoice in a fresh
container; document posted and email queued (see screenshot).
- New unit tests in MyFeatureTest.Codeunit.al pass locally; full module
test suite green.
- No tests added because change is comment-only / refactor with existing
coverage. -->

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

## Risk & compatibility

<!-- Anything reviewers should watch for: breaking changes, upgrade/data
impact, permissions,
telemetry, feature flags, follow-up work. Write "None" if there's
nothing to call out. -->
## 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.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(cherry picked from commit c14b01a)
@github-actions github-actions Bot added From Fork Pull request is coming from a fork Team: Finance GitHub request for Finance area needs-approval Workflow runs require maintainer approval to start and removed needs-approval Workflow runs require maintainer approval to start labels Sep 23, 2026
@alexei-dobriansky

Copy link
Copy Markdown
Contributor

Good Sense Reviewer - Round 1

Recommendation: Accept

What this PR does

This change validates the mandatory seller contact data before XRechnung or ZUGFeRD documents are posted or exported. It uses the same source order as XML generation: the assigned salesperson when available, otherwise Company Information.

The shared helper correctly covers the supported sales and service document tables. Both format checks call it after the Company Information e-mail validation, and the tests cover missing fields, successful paths, service documents, and fallback when a salesperson record no longer exists.

Problem-solution fit

Fit: Strong

The change directly prevents documents with incomplete mandatory seller contact data from producing invalid XML. The implementation is targeted and preserves the existing contact-source behavior.

Suggestions

None.

Risk assessment and necessity

Risk: Posting or exporting German XRechnung and ZUGFeRD documents now fails when the selected contact source is incomplete, including export of older posted documents. This is intentional and limited to these formats; there are no schema, public API, event, permission, or upgrade changes.

Necessity: The validation is required to prevent non-compliant invoices and give users a clear missing-field error before downstream validation or receiver rejection. The scope and test coverage are proportionate to the compliance issue.


[AI-PR-REVIEW] version=1 promptVersion=4 system=github pr=11818 round=1 by=alexei-dobriansky at=2026-09-23T19:21:09.857Z lastSha=b368860ecc8fcb2427965a6bad9576667545a676 reviewKey=d5e55866d77207baf35c8d1852782270f26026ce5ab3d7992acceadbd4df430b suggestions=none

@github-actions github-actions Bot removed the needs-approval Workflow runs require maintainer approval to start label Sep 23, 2026
auto-merge was automatically disabled September 23, 2026 20:50

Pull request was closed

@github-actions github-actions Bot added the ADO: Sync Creates an Azure DevOps work item if needed and indicates that one is linked label Sep 23, 2026
@github-actions github-actions Bot added this to the Version 29.0 milestone Sep 23, 2026

This branch was successfully deployed

1 active deployment
triage b368860e Deployed Sep 23, 2026 by djukicmilica via Classify team ownership #5623
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ADO: Sync Creates an Azure DevOps work item if needed and indicates that one is linked From Fork Pull request is coming from a fork Team: Finance GitHub request for Finance area

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants