From 2b6efaa7d2b020f23e2d83cdb04c6cb0a0e01d6c Mon Sep 17 00:00:00 2001
From: Kilian Seizinger <56249171+pri-kise@users.noreply.github.com>
Date: Wed, 25 Mar 2026 08:18:15 +0100
Subject: [PATCH 1/4] XRechnung - FormatDecimal with Two Decimal Places
---
.../ExportXRechnungDocument.Codeunit.al | 71 ++++++++++++++-----
.../src/XRechnungXMLDocumentTests.Codeunit.al | 38 ++++++++--
2 files changed, 86 insertions(+), 23 deletions(-)
diff --git a/Apps/DE/EDocumentDE/app/src/XRechnung/ExportXRechnungDocument.Codeunit.al b/Apps/DE/EDocumentDE/app/src/XRechnung/ExportXRechnungDocument.Codeunit.al
index 59f8b2dd05..6e3712f92e 100644
--- a/Apps/DE/EDocumentDE/app/src/XRechnung/ExportXRechnungDocument.Codeunit.al
+++ b/Apps/DE/EDocumentDE/app/src/XRechnung/ExportXRechnungDocument.Codeunit.al
@@ -39,11 +39,13 @@ codeunit 13916 "Export XRechnung Document"
EDocumentService: Record "E-Document Service";
FeatureTelemetry: Codeunit "Feature Telemetry";
PEPPOLMgt: Codeunit "PEPPOL Management";
+ TypeHelper: Codeunit "Type Helper";
FeatureNameTok: Label 'E-document XRechnung Format', Locked = true;
StartEventNameTok: Label 'E-document XRechnung export started', Locked = true;
EndEventNameTok: Label 'E-document XRechnung export completed', Locked = true;
XmlNamespaceCBC: Text;
XmlNamespaceCAC: Text;
+ AlwaysIncludeTwoDecimalPlacesForAmountFields: Boolean;
trigger OnRun();
begin
@@ -70,6 +72,7 @@ codeunit 13916 "Export XRechnung Document"
RecordRef.SetTable(SalesInvoiceHeader);
FindEDocumentService(RecordExportBuffer."Electronic Document Format");
+ CheckShouldIncludeTwoDecimalPlacesForAmountFields();
RecordExportBuffer."File Content".CreateOutStream(FileOutStream, TextEncoding::UTF8);
CreateXML(SalesInvoiceHeader, FileOutStream);
RecordExportBuffer.Modify();
@@ -87,6 +90,7 @@ codeunit 13916 "Export XRechnung Document"
RecordRef.SetTable(SalesCrMemoHeader);
FindEDocumentService(RecordExportBuffer."Electronic Document Format");
+ CheckShouldIncludeTwoDecimalPlacesForAmountFields();
RecordExportBuffer."File Content".CreateOutStream(FileOutStream, TextEncoding::UTF8);
CreateXML(SalesCrMemoHeader, FileOutStream);
RecordExportBuffer.Modify();
@@ -104,6 +108,7 @@ codeunit 13916 "Export XRechnung Document"
RecordRef.SetTable(ServiceInvoiceHeader);
FindEDocumentService(RecordExportBuffer."Electronic Document Format");
+ CheckShouldIncludeTwoDecimalPlacesForAmountFields();
RecordExportBuffer."File Content".CreateOutStream(FileOutStream, TextEncoding::UTF8);
CreateXML(ServiceInvoiceHeader, FileOutStream);
RecordExportBuffer.Modify();
@@ -121,6 +126,7 @@ codeunit 13916 "Export XRechnung Document"
RecordRef.SetTable(ServiceCrMemoHeader);
FindEDocumentService(RecordExportBuffer."Electronic Document Format");
+ CheckShouldIncludeTwoDecimalPlacesForAmountFields();
RecordExportBuffer."File Content".CreateOutStream(FileOutStream, TextEncoding::UTF8);
CreateXML(ServiceCrMemoHeader, FileOutStream);
RecordExportBuffer.Modify();
@@ -856,8 +862,8 @@ codeunit 13916 "Export XRechnung Document"
AllowanceChargeElement.Add(XmlElement.Create('ChargeIndicator', XmlNamespaceCBC, 'false'));
AllowanceChargeElement.Add(XmlElement.Create('AllowanceChargeReason', XmlNamespaceCBC, AllowanceChargeReason));
AllowanceChargeElement.Add(XmlElement.Create('MultiplierFactorNumeric', XmlNamespaceCBC, FormatFiveDecimal(MultiplierFactorNumeric)));
- AllowanceChargeElement.Add(XmlElement.Create('Amount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(Amount)));
- AllowanceChargeElement.Add(XmlElement.Create('BaseAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(BaseAmount)));
+ AllowanceChargeElement.Add(XmlElement.Create('Amount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(Amount, AlwaysIncludeTwoDecimalPlacesForAmountFields)));
+ AllowanceChargeElement.Add(XmlElement.Create('BaseAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(BaseAmount, AlwaysIncludeTwoDecimalPlacesForAmountFields)));
if InsertTaxCat then
InsertTaxCategory(AllowanceChargeElement, 'TaxCategory', TaxCategory, Percent);
RootXMLNode.Add(AllowanceChargeElement);
@@ -868,8 +874,8 @@ codeunit 13916 "Export XRechnung Document"
TaxSubtotalElement: XmlElement;
begin
TaxSubtotalElement := XmlElement.Create('TaxSubtotal', XmlNamespaceCAC);
- TaxSubtotalElement.Add(XmlElement.Create('TaxableAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(TaxableAmount)));
- TaxSubtotalElement.Add(XmlElement.Create('TaxAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(TaxAmount)));
+ TaxSubtotalElement.Add(XmlElement.Create('TaxableAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(TaxableAmount, AlwaysIncludeTwoDecimalPlacesForAmountFields)));
+ TaxSubtotalElement.Add(XmlElement.Create('TaxAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(TaxAmount, AlwaysIncludeTwoDecimalPlacesForAmountFields)));
InsertTaxCategory(TaxSubtotalElement, 'TaxCategory', TaxCategory, VATPercentage);
RootElement.Add(TaxSubtotalElement);
end;
@@ -890,7 +896,7 @@ codeunit 13916 "Export XRechnung Document"
TaxTotalElement: XmlElement;
begin
TaxTotalElement := XmlElement.Create('TaxTotal', XmlNamespaceCAC);
- TaxTotalElement.Add(XmlElement.Create('TaxAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(GetTotalTaxAmount(SalesInvLine))));
+ TaxTotalElement.Add(XmlElement.Create('TaxAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(GetTotalTaxAmount(SalesInvLine), AlwaysIncludeTwoDecimalPlacesForAmountFields)));
if SalesInvLine.FindSet() then
repeat
@@ -916,7 +922,7 @@ codeunit 13916 "Export XRechnung Document"
TaxTotalElement: XmlElement;
begin
TaxTotalElement := XmlElement.Create('TaxTotal', XmlNamespaceCAC);
- TaxTotalElement.Add(XmlElement.Create('TaxAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(GetTotalTaxAmount(SalesCrMemoLine))));
+ TaxTotalElement.Add(XmlElement.Create('TaxAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(GetTotalTaxAmount(SalesCrMemoLine), AlwaysIncludeTwoDecimalPlacesForAmountFields)));
if SalesCrMemoLine.FindSet() then
repeat
@@ -942,12 +948,12 @@ codeunit 13916 "Export XRechnung Document"
LegalMonetaryTotalElement: XmlElement;
begin
LegalMonetaryTotalElement := XmlElement.Create('LegalMonetaryTotal', XmlNamespaceCAC);
- LegalMonetaryTotalElement.Add(XmlElement.Create('LineExtensionAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(LineAmounts.Get(SalesInvLine.FieldName(Amount)) + LineAmounts.Get(SalesInvLine.FieldName("Inv. Discount Amount")))));
- LegalMonetaryTotalElement.Add(XmlElement.Create('TaxExclusiveAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(LineAmounts.Get(SalesInvLine.FieldName(Amount)))));
- LegalMonetaryTotalElement.Add(XmlElement.Create('TaxInclusiveAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(LineAmounts.Get(SalesInvLine.FieldName("Amount Including VAT")))));
+ LegalMonetaryTotalElement.Add(XmlElement.Create('LineExtensionAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(LineAmounts.Get(SalesInvLine.FieldName(Amount)) + LineAmounts.Get(SalesInvLine.FieldName("Inv. Discount Amount")), AlwaysIncludeTwoDecimalPlacesForAmountFields)));
+ LegalMonetaryTotalElement.Add(XmlElement.Create('TaxExclusiveAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(LineAmounts.Get(SalesInvLine.FieldName(Amount)), AlwaysIncludeTwoDecimalPlacesForAmountFields)));
+ LegalMonetaryTotalElement.Add(XmlElement.Create('TaxInclusiveAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(LineAmounts.Get(SalesInvLine.FieldName("Amount Including VAT")), AlwaysIncludeTwoDecimalPlacesForAmountFields)));
if LineAmounts.Get(SalesInvLine.FieldName("Inv. Discount Amount")) > 0 then
- LegalMonetaryTotalElement.Add(XmlElement.Create('AllowanceTotalAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(LineAmounts.Get(SalesInvLine.FieldName("Inv. Discount Amount")))));
- LegalMonetaryTotalElement.Add(XmlElement.Create('PayableAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(LineAmounts.Get(SalesInvLine.FieldName("Amount Including VAT")))));
+ LegalMonetaryTotalElement.Add(XmlElement.Create('AllowanceTotalAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(LineAmounts.Get(SalesInvLine.FieldName("Inv. Discount Amount")), AlwaysIncludeTwoDecimalPlacesForAmountFields)));
+ LegalMonetaryTotalElement.Add(XmlElement.Create('PayableAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(LineAmounts.Get(SalesInvLine.FieldName("Amount Including VAT")), AlwaysIncludeTwoDecimalPlacesForAmountFields)));
RootXMLNode.Add(LegalMonetaryTotalElement);
end;
@@ -956,12 +962,12 @@ codeunit 13916 "Export XRechnung Document"
LegalMonetaryTotalElement: XmlElement;
begin
LegalMonetaryTotalElement := XmlElement.Create('LegalMonetaryTotal', XmlNamespaceCAC);
- LegalMonetaryTotalElement.Add(XmlElement.Create('LineExtensionAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(LineAmounts.Get(SalesCrMemoLine.FieldName(Amount)) + LineAmounts.Get(SalesCrMemoLine.FieldName("Inv. Discount Amount")))));
- LegalMonetaryTotalElement.Add(XmlElement.Create('TaxExclusiveAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(LineAmounts.Get(SalesCrMemoLine.FieldName(Amount)))));
- LegalMonetaryTotalElement.Add(XmlElement.Create('TaxInclusiveAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(LineAmounts.Get(SalesCrMemoLine.FieldName("Amount Including VAT")))));
+ LegalMonetaryTotalElement.Add(XmlElement.Create('LineExtensionAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(LineAmounts.Get(SalesCrMemoLine.FieldName(Amount)) + LineAmounts.Get(SalesCrMemoLine.FieldName("Inv. Discount Amount")), AlwaysIncludeTwoDecimalPlacesForAmountFields)));
+ LegalMonetaryTotalElement.Add(XmlElement.Create('TaxExclusiveAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(LineAmounts.Get(SalesCrMemoLine.FieldName(Amount)), AlwaysIncludeTwoDecimalPlacesForAmountFields)));
+ LegalMonetaryTotalElement.Add(XmlElement.Create('TaxInclusiveAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(LineAmounts.Get(SalesCrMemoLine.FieldName("Amount Including VAT")), AlwaysIncludeTwoDecimalPlacesForAmountFields)));
if LineAmounts.Get(SalesCrMemoLine.FieldName("Inv. Discount Amount")) > 0 then
- LegalMonetaryTotalElement.Add(XmlElement.Create('AllowanceTotalAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(LineAmounts.Get(SalesCrMemoLine.FieldName("Inv. Discount Amount")))));
- LegalMonetaryTotalElement.Add(XmlElement.Create('PayableAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(LineAmounts.Get(SalesCrMemoLine.FieldName("Amount Including VAT")))));
+ LegalMonetaryTotalElement.Add(XmlElement.Create('AllowanceTotalAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(LineAmounts.Get(SalesCrMemoLine.FieldName("Inv. Discount Amount")), AlwaysIncludeTwoDecimalPlacesForAmountFields)));
+ LegalMonetaryTotalElement.Add(XmlElement.Create('PayableAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(LineAmounts.Get(SalesCrMemoLine.FieldName("Amount Including VAT")), AlwaysIncludeTwoDecimalPlacesForAmountFields)));
RootXMLNode.Add(LegalMonetaryTotalElement);
end;
@@ -1028,7 +1034,7 @@ codeunit 13916 "Export XRechnung Document"
ExcludeVAT(SalesInvLine, Currency."Amount Rounding Precision");
InvoiceLineElement.Add(XmlElement.Create('ID', XmlNamespaceCBC, Format(SalesInvLine."Line No.")));
InvoiceLineElement.Add(XmlElement.Create('InvoicedQuantity', XmlNamespaceCBC, XmlAttribute.Create('unitCode', GetUoMCode(SalesInvLine."Unit of Measure Code")), FormatDecimalUnlimited(SalesInvLine.Quantity)));
- InvoiceLineElement.Add(XmlElement.Create('LineExtensionAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(SalesInvLine.Amount + SalesInvLine."Inv. Discount Amount")));
+ InvoiceLineElement.Add(XmlElement.Create('LineExtensionAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(SalesInvLine.Amount + SalesInvLine."Inv. Discount Amount", AlwaysIncludeTwoDecimalPlacesForAmountFields)));
if SalesInvLine."Shipment Date" <> 0D then
InsertInvoicePeriod(InvoiceLineElement, SalesInvLine."Shipment Date", SalesInvLine."Shipment Date");
InsertOrderLineReference(InvoiceLineElement, SalesInvLine."Line No.");
@@ -1067,7 +1073,7 @@ codeunit 13916 "Export XRechnung Document"
ExcludeVAT(SalesCrMemoLine, Currency."Amount Rounding Precision");
CrMemoLineElement.Add(XmlElement.Create('ID', XmlNamespaceCBC, Format(SalesCrMemoLine."Line No.")));
CrMemoLineElement.Add(XmlElement.Create('CreditedQuantity', XmlNamespaceCBC, XmlAttribute.Create('unitCode', GetUoMCode(SalesCrMemoLine."Unit of Measure Code")), FormatDecimalUnlimited(SalesCrMemoLine.Quantity)));
- CrMemoLineElement.Add(XmlElement.Create('LineExtensionAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(SalesCrMemoLine.Amount + SalesCrMemoLine."Inv. Discount Amount")));
+ CrMemoLineElement.Add(XmlElement.Create('LineExtensionAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimal(SalesCrMemoLine.Amount + SalesCrMemoLine."Inv. Discount Amount", AlwaysIncludeTwoDecimalPlacesForAmountFields)));
InsertOrderLineReference(CrMemoLineElement, SalesCrMemoLine."Line No.");
if SalesCrMemoLine."Shipment Date" <> 0D then
InsertInvoicePeriod(CrMemoLineElement, SalesCrMemoLine."Shipment Date", SalesCrMemoLine."Shipment Date");
@@ -1355,6 +1361,13 @@ codeunit 13916 "Export XRechnung Document"
if EDocumentService.FindLast() then;
OnAfterFindEDocumentService(EDocumentService, EDocumentFormat);
end;
+
+ local procedure CheckShouldIncludeTwoDecimalPlacesForAmountFields()
+ begin
+ AlwaysIncludeTwoDecimalPlacesForAmountFields := false;
+ OnCheckShouldIncludeTwoDecimalPlacesForAmountFields(AlwaysIncludeTwoDecimalPlacesForAmountFields);
+ end;
+
#region CommonFunctions
procedure FormatDate(VarDate: Date): Text[20];
begin
@@ -1365,7 +1378,18 @@ codeunit 13916 "Export XRechnung Document"
procedure FormatDecimal(VarDecimal: Decimal): Text[30];
begin
- exit(Format(Round(VarDecimal, 0.01), 0, 9));
+ exit(FormatDecimal(VarDecimal, false));
+ end;
+
+ procedure FormatDecimal(VarDecimal: Decimal; IncludeDecimalPlaces: Boolean): Text[30];
+ var
+ DecimalRounded: Decimal;
+ begin
+ DecimalRounded := Round(VarDecimal, 0.01);
+ if IncludeDecimalPlaces then
+ exit(Format(DecimalRounded, 0, TypeHelper.GetXMLAmountFormatWithTwoDecimalPlaces()))
+ else
+ exit(Format(DecimalRounded, 0, 9));
end;
procedure FormatDecimalUnlimited(VarDecimal: Decimal): Text
@@ -1609,4 +1633,13 @@ codeunit 13916 "Export XRechnung Document"
local procedure OnInsertAttachmentOnAfterSetFilters(TableNo: Integer; DocumentNo: Code[20]; var DocumentAttachment: Record "Document Attachment")
begin
end;
+
+ ///
+ /// Use this event to always include two decimal places for amount fields
+ ///
+ /// Set to true to force all amount fields to include two decimal places (e.g. 1.10 instead of 1.1)
+ [IntegrationEvent(false, false)]
+ local procedure OnCheckShouldIncludeTwoDecimalPlacesForAmountFields(var AlwaysIncludeTwoDecimalPlacesForAmountFields: Boolean)
+ begin
+ end;
}
\ No newline at end of file
diff --git a/Apps/DE/EDocumentDE/test/src/XRechnungXMLDocumentTests.Codeunit.al b/Apps/DE/EDocumentDE/test/src/XRechnungXMLDocumentTests.Codeunit.al
index 15f7228733..706c239486 100644
--- a/Apps/DE/EDocumentDE/test/src/XRechnungXMLDocumentTests.Codeunit.al
+++ b/Apps/DE/EDocumentDE/test/src/XRechnungXMLDocumentTests.Codeunit.al
@@ -1421,6 +1421,36 @@ codeunit 13918 "XRechnung XML Document Tests"
VerifyCSVAttachmentInXML(TempXMLBuffer, 'data.csv', 'text/csv', CSVText);
end;
+ #region TwoDecimalPlaces
+ [Test]
+ procedure FormatDecimalWithTwoDecimalPlacesFlagReturnsTrailingZero();
+ begin
+ // [SCENARIO] FormatDecimal with IncludeDecimalPlaces = true always formats amount with exactly two decimal places
+ Initialize();
+
+ // [WHEN/THEN] A value with one significant decimal place gets the trailing zero
+ Assert.AreEqual('1.10', ExportXRechnungDocument.FormatDecimal(1.1, true), 'FormatDecimal(1.1, true) should return ''1.10''');
+ // [WHEN/THEN] A whole number gets two decimal zeros
+ Assert.AreEqual('1.00', ExportXRechnungDocument.FormatDecimal(1, true), 'FormatDecimal(1, true) should return ''1.00''');
+ // [WHEN/THEN] A value with two decimal places is unchanged
+ Assert.AreEqual('1.23', ExportXRechnungDocument.FormatDecimal(1.23, true), 'FormatDecimal(1.23, true) should return ''1.23''');
+ end;
+
+ [Test]
+ procedure FormatDecimalWithoutTwoDecimalPlacesFlagNoTrailingZero();
+ begin
+ // [SCENARIO] FormatDecimal with IncludeDecimalPlaces = false uses the default format without trailing zeros
+ Initialize();
+
+ // [WHEN/THEN] A value with one significant decimal place has no trailing zero
+ Assert.AreEqual('1.1', ExportXRechnungDocument.FormatDecimal(1.1, false), 'FormatDecimal(1.1, false) should return ''1.1''');
+ // [WHEN/THEN] A whole number has no decimal places
+ Assert.AreEqual('1', ExportXRechnungDocument.FormatDecimal(1, false), 'FormatDecimal(1, false) should return ''1''');
+ // [WHEN/THEN] A value with two decimal places is unchanged
+ Assert.AreEqual('1.23', ExportXRechnungDocument.FormatDecimal(1.23, false), 'FormatDecimal(1.23, false) should return ''1.23''');
+ end;
+ #endregion
+
local procedure CreateAndPostSalesDocument(DocumentType: Enum "Sales Document Type"; LineType: Enum "Sales Line Type"; InvoiceDiscount: Boolean): Code[20];
var
SalesHeader: Record "Sales Header";
@@ -2813,10 +2843,10 @@ codeunit 13918 "XRechnung XML Document Tests"
local procedure GetCurrencyCode(DocumentCurrencyCode: Code[10]; var Currency: Record Currency): Code[10]
begin
- if DocumentCurrencyCode = '' then begin
- Currency.InitRoundingPrecision();
- exit(GeneralLedgerSetup."LCY Code");
- end else begin
+ if DocumentCurrencyCode = ';
+
+ exit(GeneralLedgerSe;
+
Currency.Get(DocumentCurrencyCode);
Currency.TestField("Amount Rounding Precision");
Currency.TestField("Unit-Amount Rounding Precision");
From c178ad29dd5af10d437a56f7318b4d5de4435127 Mon Sep 17 00:00:00 2001
From: Kilian Seizinger <56249171+pri-kise@users.noreply.github.com>
Date: Wed, 25 Mar 2026 08:18:16 +0100
Subject: [PATCH 2/4] revert wrong changes
---
.../test/src/XRechnungXMLDocumentTests.Codeunit.al | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/Apps/DE/EDocumentDE/test/src/XRechnungXMLDocumentTests.Codeunit.al b/Apps/DE/EDocumentDE/test/src/XRechnungXMLDocumentTests.Codeunit.al
index 706c239486..c7a49e641d 100644
--- a/Apps/DE/EDocumentDE/test/src/XRechnungXMLDocumentTests.Codeunit.al
+++ b/Apps/DE/EDocumentDE/test/src/XRechnungXMLDocumentTests.Codeunit.al
@@ -2843,10 +2843,10 @@ codeunit 13918 "XRechnung XML Document Tests"
local procedure GetCurrencyCode(DocumentCurrencyCode: Code[10]; var Currency: Record Currency): Code[10]
begin
- if DocumentCurrencyCode = ';
-
- exit(GeneralLedgerSe;
-
+ if DocumentCurrencyCode = '' then begin
+ Currency.InitRoundingPrecision();
+ exit(GeneralLedgerSetup."LCY Code");
+ end else begin
Currency.Get(DocumentCurrencyCode);
Currency.TestField("Amount Rounding Precision");
Currency.TestField("Unit-Amount Rounding Precision");
From 626f0d3302285eb5e2763520324686892ba02fa7 Mon Sep 17 00:00:00 2001
From: Kilian Seizinger <56249171+pri-kise@users.noreply.github.com>
Date: Wed, 25 Mar 2026 09:05:59 +0100
Subject: [PATCH 3/4] add at least two decimals to unit price
---
.../ExportXRechnungDocument.Codeunit.al | 12 +++++--
.../src/XRechnungXMLDocumentTests.Codeunit.al | 32 +++++++++++++++++++
2 files changed, 42 insertions(+), 2 deletions(-)
diff --git a/Apps/DE/EDocumentDE/app/src/XRechnung/ExportXRechnungDocument.Codeunit.al b/Apps/DE/EDocumentDE/app/src/XRechnung/ExportXRechnungDocument.Codeunit.al
index 6e3712f92e..352a120f10 100644
--- a/Apps/DE/EDocumentDE/app/src/XRechnung/ExportXRechnungDocument.Codeunit.al
+++ b/Apps/DE/EDocumentDE/app/src/XRechnung/ExportXRechnungDocument.Codeunit.al
@@ -609,7 +609,7 @@ codeunit 13916 "Export XRechnung Document"
PriceElement: XmlElement;
begin
PriceElement := XmlElement.Create('Price', XmlNamespaceCAC);
- PriceElement.Add(XmlElement.Create('PriceAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimalUnlimited(UnitPrice)));
+ PriceElement.Add(XmlElement.Create('PriceAmount', XmlNamespaceCBC, XmlAttribute.Create('currencyID', CurrencyCode), FormatDecimalUnlimited(UnitPrice, AlwaysIncludeTwoDecimalPlacesForAmountFields)));
RootElement.Add(PriceElement);
end;
@@ -1394,7 +1394,15 @@ codeunit 13916 "Export XRechnung Document"
procedure FormatDecimalUnlimited(VarDecimal: Decimal): Text
begin
- exit(Format(VarDecimal, 0, 9));
+ exit(FormatDecimalUnlimited(VarDecimal, false));
+ end;
+
+ procedure FormatDecimalUnlimited(VarDecimal: Decimal; IncludeMinTwoDecimals: Boolean): Text
+ begin
+ if IncludeMinTwoDecimals then
+ exit(Format(VarDecimal, 0, ''))
+ else
+ exit(Format(VarDecimal, 0, 9));
end;
#if not CLEAN29
diff --git a/Apps/DE/EDocumentDE/test/src/XRechnungXMLDocumentTests.Codeunit.al b/Apps/DE/EDocumentDE/test/src/XRechnungXMLDocumentTests.Codeunit.al
index c7a49e641d..a716c311f8 100644
--- a/Apps/DE/EDocumentDE/test/src/XRechnungXMLDocumentTests.Codeunit.al
+++ b/Apps/DE/EDocumentDE/test/src/XRechnungXMLDocumentTests.Codeunit.al
@@ -1449,6 +1449,38 @@ codeunit 13918 "XRechnung XML Document Tests"
// [WHEN/THEN] A value with two decimal places is unchanged
Assert.AreEqual('1.23', ExportXRechnungDocument.FormatDecimal(1.23, false), 'FormatDecimal(1.23, false) should return ''1.23''');
end;
+
+ [Test]
+ procedure FormatDecimalUnlimitedWithMinTwoDecimalsReturnsTrailingZero();
+ begin
+ // [SCENARIO] FormatDecimalUnlimited with IncludeMinTwoDecimals = true ensures minimum two decimal places while preserving extended precision
+ Initialize();
+
+ // [WHEN/THEN] A value with one significant decimal place gets the trailing zero
+ Assert.AreEqual('1.10', ExportXRechnungDocument.FormatDecimalUnlimited(1.1, true), 'FormatDecimalUnlimited(1.1, true) should return ''1.10''');
+ // [WHEN/THEN] A whole number gets two decimal zeros
+ Assert.AreEqual('1.00', ExportXRechnungDocument.FormatDecimalUnlimited(1, true), 'FormatDecimalUnlimited(1, true) should return ''1.00''');
+ // [WHEN/THEN] A value with two decimal places is unchanged
+ Assert.AreEqual('1.23', ExportXRechnungDocument.FormatDecimalUnlimited(1.23, true), 'FormatDecimalUnlimited(1.23, true) should return ''1.23''');
+ // [WHEN/THEN] A value with extended decimal places preserves full precision
+ Assert.AreEqual('5.12345', ExportXRechnungDocument.FormatDecimalUnlimited(5.12345, true), 'FormatDecimalUnlimited(5.12345, true) should return ''5.12345''');
+ end;
+
+ [Test]
+ procedure FormatDecimalUnlimitedWithoutMinTwoDecimalsUnbounded();
+ begin
+ // [SCENARIO] FormatDecimalUnlimited with IncludeMinTwoDecimals = false uses unlimited precision without minimum decimal places
+ Initialize();
+
+ // [WHEN/THEN] A value with one significant decimal place has no trailing zero
+ Assert.AreEqual('1.1', ExportXRechnungDocument.FormatDecimalUnlimited(1.1, false), 'FormatDecimalUnlimited(1.1, false) should return ''1.1''');
+ // [WHEN/THEN] A whole number has no decimal places
+ Assert.AreEqual('1', ExportXRechnungDocument.FormatDecimalUnlimited(1, false), 'FormatDecimalUnlimited(1, false) should return ''1''');
+ // [WHEN/THEN] A value with two decimal places is unchanged
+ Assert.AreEqual('1.23', ExportXRechnungDocument.FormatDecimalUnlimited(1.23, false), 'FormatDecimalUnlimited(1.23, false) should return ''1.23''');
+ // [WHEN/THEN] A value with extended decimal places preserves full precision
+ Assert.AreEqual('5.12345', ExportXRechnungDocument.FormatDecimalUnlimited(5.12345, false), 'FormatDecimalUnlimited(5.12345, false) should return ''5.12345''');
+ end;
#endregion
local procedure CreateAndPostSalesDocument(DocumentType: Enum "Sales Document Type"; LineType: Enum "Sales Line Type"; InvoiceDiscount: Boolean): Code[20];
From 197add835901769ef865710e36c7ee857b68930e Mon Sep 17 00:00:00 2001
From: Kilian Seizinger <56249171+pri-kise@users.noreply.github.com>
Date: Wed, 25 Mar 2026 09:36:06 +0100
Subject: [PATCH 4/4] update the procedure name to InitializeDecimalFormatFlags
---
.../XRechnung/ExportXRechnungDocument.Codeunit.al | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/Apps/DE/EDocumentDE/app/src/XRechnung/ExportXRechnungDocument.Codeunit.al b/Apps/DE/EDocumentDE/app/src/XRechnung/ExportXRechnungDocument.Codeunit.al
index 352a120f10..b13dc34b51 100644
--- a/Apps/DE/EDocumentDE/app/src/XRechnung/ExportXRechnungDocument.Codeunit.al
+++ b/Apps/DE/EDocumentDE/app/src/XRechnung/ExportXRechnungDocument.Codeunit.al
@@ -72,7 +72,7 @@ codeunit 13916 "Export XRechnung Document"
RecordRef.SetTable(SalesInvoiceHeader);
FindEDocumentService(RecordExportBuffer."Electronic Document Format");
- CheckShouldIncludeTwoDecimalPlacesForAmountFields();
+ InitializeDecimalFormatFlags();
RecordExportBuffer."File Content".CreateOutStream(FileOutStream, TextEncoding::UTF8);
CreateXML(SalesInvoiceHeader, FileOutStream);
RecordExportBuffer.Modify();
@@ -90,7 +90,7 @@ codeunit 13916 "Export XRechnung Document"
RecordRef.SetTable(SalesCrMemoHeader);
FindEDocumentService(RecordExportBuffer."Electronic Document Format");
- CheckShouldIncludeTwoDecimalPlacesForAmountFields();
+ InitializeDecimalFormatFlags();
RecordExportBuffer."File Content".CreateOutStream(FileOutStream, TextEncoding::UTF8);
CreateXML(SalesCrMemoHeader, FileOutStream);
RecordExportBuffer.Modify();
@@ -108,7 +108,7 @@ codeunit 13916 "Export XRechnung Document"
RecordRef.SetTable(ServiceInvoiceHeader);
FindEDocumentService(RecordExportBuffer."Electronic Document Format");
- CheckShouldIncludeTwoDecimalPlacesForAmountFields();
+ InitializeDecimalFormatFlags();
RecordExportBuffer."File Content".CreateOutStream(FileOutStream, TextEncoding::UTF8);
CreateXML(ServiceInvoiceHeader, FileOutStream);
RecordExportBuffer.Modify();
@@ -126,7 +126,7 @@ codeunit 13916 "Export XRechnung Document"
RecordRef.SetTable(ServiceCrMemoHeader);
FindEDocumentService(RecordExportBuffer."Electronic Document Format");
- CheckShouldIncludeTwoDecimalPlacesForAmountFields();
+ InitializeDecimalFormatFlags();
RecordExportBuffer."File Content".CreateOutStream(FileOutStream, TextEncoding::UTF8);
CreateXML(ServiceCrMemoHeader, FileOutStream);
RecordExportBuffer.Modify();
@@ -1362,10 +1362,10 @@ codeunit 13916 "Export XRechnung Document"
OnAfterFindEDocumentService(EDocumentService, EDocumentFormat);
end;
- local procedure CheckShouldIncludeTwoDecimalPlacesForAmountFields()
+ local procedure InitializeDecimalFormatFlags()
begin
AlwaysIncludeTwoDecimalPlacesForAmountFields := false;
- OnCheckShouldIncludeTwoDecimalPlacesForAmountFields(AlwaysIncludeTwoDecimalPlacesForAmountFields);
+ OnInitializeDecimalFormatFlags(AlwaysIncludeTwoDecimalPlacesForAmountFields);
end;
#region CommonFunctions
@@ -1647,7 +1647,7 @@ codeunit 13916 "Export XRechnung Document"
///
/// Set to true to force all amount fields to include two decimal places (e.g. 1.10 instead of 1.1)
[IntegrationEvent(false, false)]
- local procedure OnCheckShouldIncludeTwoDecimalPlacesForAmountFields(var AlwaysIncludeTwoDecimalPlacesForAmountFields: Boolean)
+ local procedure OnInitializeDecimalFormatFlags(var AlwaysIncludeTwoDecimalPlacesForAmountFields: Boolean)
begin
end;
}
\ No newline at end of file