[29.0] Fix item charge unit codes in XRechnung/ZUGFeRD - #11100
Open
Milica Đukić (djukicmilica) wants to merge 1 commit into
Open
[29.0] Fix item charge unit codes in XRechnung/ZUGFeRD#11100Milica Đukić (djukicmilica) wants to merge 1 commit into
Milica Đukić (djukicmilica) wants to merge 1 commit into
Conversation
…valid unit of measure code (BR-CL-23 / BR-23 on BT-130) (microsoft#9860) <!-- 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 --> Item charge lines (Type = Charge (Item)) were exported as synthetic invoice lines carrying an empty unit code or PCE on BT-130, which fails EN 16931 validation with BR-23 and BR-CL-23. Semantically most item charges are allowances or charges and belong in the allowance/charge structures rather than in a fabricated invoice line. E-Document Core gains the classification: - Enum "Item Charge E-Invoice Mapping" with Automatic (default), Document Allowance/Charge, Line Allowance/Charge and Line with Unit Code, held on E-Document Service. - A per-item-charge override (mapping, reason text, reason code, fallback unit code) on a table extension of Item Charge. - Codeunit "E-Doc. Item Charge Mapping" resolves the structure for posted sales invoices and credit memos. Automatic exports a charge as line-level when it is assigned to exactly one line whose VAT calculation type and rate match, as document-level when the assignment is absent or ambiguous, and as a regular line otherwise. The assignment is recovered from Value Entry, because item charge assignments no longer exist once the document is posted. - Integration events let subscribers override the resolved structure. The controls are hidden in Core. E-Document for Germany makes them visible, and both German exporters consume the classification: - XRechnung emits cac:AllowanceCharge under Invoice or inside the target cac:InvoiceLine; ZUGFeRD emits ram:SpecifiedTradeAllowanceCharge in the header or line settlement. - A document-level allowance/charge carries its tax category, a line-level one does not. - Negative amounts are exported as allowances with a positive amount. - The fallback line reports quantity 1 with unit code C62; a negative charge uses a negative quantity with a non-negative net price so that BR-27 holds. - A document whose only lines are item charges keeps a regular line, so BR-16 is not violated. Document and line totals are corrected so that the monetary totals and tax subtotals still add up once charges leave the line set. Also removes a duplicate "features" key from the DE demo data manifest, which prevented that app from compiling. <!-- 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#8417 [AB#641600](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/641600) - [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)* Manual, against a BC 29 DE container (bc29de), validating every exported document with online EN 16931 / XRechnung validators (KoSIT): - Exported a posted sales invoice with item charges under **all four** values of the new **Item Charge Mapping** service setting — Automatic, Document Level Allowance/Charge, Invoice Line Allowance/Charge and Invoice Line with Unit Code. All four produce documents that pass XSD, EN 16931 Schematron and the XRechnung CIUS rules. - Overrode the setting per item charge on the **Item Charges** page and confirmed the per-charge **E-Invoice Mapping** takes precedence over the service-level setting, including a blank override falling through to the service setting. Automated (all executed against the container, not just compiled): | Test codeunit | Result | |---|---| | `E-Doc. Item Charge Tests` (139520) | 27 / 0 | | `E-Doc. Item Charge UI Tests` (139522) | 3 / 0 | | `Item Charge UI DE Tests` (13927) | 5 / 0 | | `XRechnung XML Document Tests` (13918) | 93 / 2 | | `ZUGFeRD XML Document Tests` (13922) | 93 / 2 | 73 tests were added in total. The 2 + 2 failures are **pre-existing and unrelated** — `AdditionalDocumentReference` counts in two attachment tests, and `ram:GlobalID` in two ZUGFeRD tests. They were measured as failing on an unmodified tree before this work started, and the failure sets are unchanged by this PR. Coverage was verified by mutation: each classification branch, the sign convention, the totals corrections and the fallback quantity/unit code were deliberately broken and confirmed to fail a specific test. Two genuine bugs were caught this way — a signed amount reaching `AllowanceCharge`, and a missing guard that let a charge-only document export zero invoice lines (BR-16). <!-- 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. --> - **Behaviour changes by default.** `Automatic` is the default mapping, so existing services start exporting item charges as document- or line-level allowances/charges instead of synthetic invoice lines. This is the point of the fix — the old output was invalid — but the XML shape changes for anyone already exporting item charges, and downstream systems that parse charges out of `cac:InvoiceLine` / `ram:IncludedSupplyChainTradeLineItem` will see them move. Reviewers should confirm this is acceptable as a default rather than opt-in. - **Schema change.** New field on `E-Document Service`, and a table extension on `Item Charge` with four new fields. Requires a schema sync; no data migration, all fields default to blank/`Automatic`, which preserves the intended behaviour. - **Monetary totals are recomputed.** `cac:LegalMonetaryTotal` / `ram:...HeaderMonetarySummation` and the tax subtotals are adjusted when charges leave the line set. Tax base and payable amounts are unchanged by construction and asserted in tests, but this is the area most worth a careful read. - **Known limitation:** a PEPPOL BIS 3.0 DE service shows the Item Charge Mapping setting, but that format's export ignores it — it delegates XML generation to the W1 PEPPOL BIS 3.0 implementation, which is deliberately out of scope here. Follow-up work if PEPPOL BIS DE should honour the setting. - **Deliberately out of scope:** the generic W1 PEPPOL BIS 3.0 export is untouched, and service documents keep opting out (they cannot carry item charges). - **New public surface:** integration events allow subscribers to override the resolved structure for invoices and credit memos. Once shipped these are a compatibility commitment. - **Permissions:** the new `E-Doc. Item Charge Mapping` codeunit is granted execute in `E-Doc. Core - Objects`, which flows to Read/User/Basic/Edit/Admin and the D365 permission set extensions. The codeunit itself elevates the table reads it needs (`Item Charge`, `Value Entry`, posted sales lines) via its `Permissions` property. <!-- 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. --> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: djukicmilica <milicadjukic@microsoft.com>
Milica Đukić (djukicmilica)
temporarily deployed
to
triage
September 6, 2026 09:45 — with
GitHub Actions
Inactive
Contributor
|
Could not find linked issues in the pull request description. Please make sure the pull request description contains a line that contains 'Fixes #' followed by the issue number being fixed. Use that pattern for every issue you want to link. |
Milica Đukić (djukicmilica)
enabled auto-merge (squash)
September 6, 2026 09:55
auto-merge was automatically disabled
September 6, 2026 10:25
Pull request was closed
Milica Đukić (djukicmilica)
temporarily deployed
to
triage
September 6, 2026 10:25 — with
GitHub Actions
Inactive
Milica Đukić (djukicmilica)
enabled auto-merge (squash)
September 6, 2026 10:25
Wenjie Fan (gggdttt)
approved these changes
Sep 6, 2026
auto-merge was automatically disabled
September 6, 2026 14:57
Pull request was closed
Milica Đukić (djukicmilica)
temporarily deployed
to
triage
September 6, 2026 14:58 — with
GitHub Actions
Inactive
Milica Đukić (djukicmilica)
enabled auto-merge (squash)
September 6, 2026 14:58
auto-merge was automatically disabled
September 7, 2026 10:56
Pull request was closed
Milica Đukić (djukicmilica)
temporarily deployed
to
triage
September 7, 2026 10:56 — with
GitHub Actions
Inactive
Milica Đukić (djukicmilica)
enabled auto-merge (squash)
September 7, 2026 10:56
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Backport of #9860.
Why
Item charges exported as synthetic invoice lines can carry an empty or invalid unit code on BT-130, causing EN16931 BR-23 / BR-CL-23 validation failures in XRechnung and ZUGFeRD documents.
Summary
Fixes
AB#649224