[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
Miljan Milosavljević (miljance) wants to merge 1 commit into
Conversation
…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)
Good Sense Reviewer - Round 1Recommendation: AcceptWhat this PR doesThis 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 fitFit: 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. SuggestionsNone. Risk assessment and necessityRisk: 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.
|
Pull request was closed
What & why
This is a backport of #9646 to
releases/29.0. It cherry-picks the samemainsquash 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
What I tested and the outcome
This is a backport of the already-merged and validated #9646. The cherry-pick of the
mainsquash commit ontoreleases/29.0applied cleanly with no conflicts, and the resulting diff is byte-identical to the diff of #9646 (5 files, +717, noapp.jsonchange). 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
Checkand ignoresEDocumentProcessingPhase, so it also blocks export of documents posted beforethis change. Same behaviour as the existing IBAN and buyer-reference checks.
No opt-out:
OnBeforeCheckhas noIsHandled, so extensions cannot suppressthe check. Adding it would be the follow-up if customers with incomplete master
data need an escape hatch.
Untested:
GetSalespersonCoderesolves the field number the same wayCheckBankAccountIBANMandatoryalready does, but tests only coverSales Headerand
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