Skip to content

Commit f1b22c1

Browse files
Mandatory Customer Data in Sales for xRechnung and ZUGFeRD (#29306)
<!-- Thank you for submitting a Pull Request. If you're new to contributing to AlAppExtensions please read our pull request guideline below * https://github.com/microsoft/ALAppExtensions/blob/main/CONTRIBUTING.md --> #### Summary <!-- Provide a general summary of your changes --> * **Pre-posting validation:** Run Peppol validation before posting a sales document to ensure all required data is present (customer and Company Information), guaranteeing the exported E-Document is valid. * **Customer email requirement:** For xRechnung, the customer’s email is mandatory and included in the XML. For ZUGFeRD, email is not mandatory in the schema, but operationally required to deliver the document to the customer. * **ZUGFeRD due date export:** Export “Due Date” when no “Payment Terms” are defined for the customer, ensuring a valid ZUGFeRD format. * **ZUGFeRD XML tag corrections:** Correct the XML mapping so IBAN is exported under PayeePartyCreditorFinancialAccount and SWIFT Code under PayeeSpecifiedCreditorFinancialInstitution, instead of both under PayeePartyCreditorFinancialAccount. #### Work Item(s) <!-- Add the issue number here after the #. The issue needs to be open and approved. Submitting PRs with no linked issues or unapproved issues is highly discouraged. --> Fixes #29264 Fixes [AB#609594](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/609594) --------- Co-authored-by: Jesper Schulz-Wedde <[email protected]>
1 parent 75af6c1 commit f1b22c1

File tree

6 files changed

+96
-14
lines changed

6 files changed

+96
-14
lines changed

Apps/DE/EDocumentDE/app/src/PEPPOL/EDocPEPPOLBIS30DE.Codeunit.al

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ codeunit 11035 "EDoc PEPPOL BIS 3.0 DE" implements "E-Document"
2020

2121
var
2222
EDocPEPPOLBIS30: Codeunit "EDoc PEPPOL BIS 3.0";
23+
EDocPEPPOLValidationDE: Codeunit "EDoc PEPPOL Validation DE";
2324
UBLInvoiceNamespaceTxt: Label 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2', Locked = true;
2425
UBLCrMemoNamespaceTxt: Label 'urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2', Locked = true;
2526
UBLCACNamespaceTxt: Label 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2', Locked = true;
@@ -28,7 +29,9 @@ codeunit 11035 "EDoc PEPPOL BIS 3.0 DE" implements "E-Document"
2829
procedure Check(var SourceDocumentHeader: RecordRef; EDocumentService: Record "E-Document Service"; EDocumentProcessingPhase: Enum "E-Document Processing Phase")
2930
begin
3031
CheckBuyerReferenceMandatory(EDocumentService, SourceDocumentHeader);
32+
BindSubscription(EDocPEPPOLValidationDE);
3133
EDocPEPPOLBIS30.Check(SourceDocumentHeader, EDocumentService, EDocumentProcessingPhase);
34+
UnbindSubscription(EDocPEPPOLValidationDE);
3235
end;
3336

3437
procedure Create(EDocumentService: Record "E-Document Service"; var EDocument: Record "E-Document"; var SourceDocumentHeader: RecordRef; var SourceDocumentLines: RecordRef; var TempBlob: Codeunit "Temp Blob")
@@ -231,12 +234,6 @@ codeunit 11035 "EDoc PEPPOL BIS 3.0 DE" implements "E-Document"
231234
begin
232235
end;
233236

234-
[EventSubscriber(ObjectType::Codeunit, Codeunit::"PEPPOL Validation", 'OnCheckSalesDocumentOnBeforeCheckYourReference', '', false, false)]
235-
local procedure SkipCheckOnCheckSalesDocumentOnBeforeCheckYourReference(SalesHeader: Record "Sales Header"; var IsHandled: Boolean)
236-
begin
237-
IsHandled := true;
238-
end;
239-
240237
[EventSubscriber(ObjectType::Codeunit, Codeunit::"PEPPOL Management", 'OnAfterGetBuyerReference', '', false, false)]
241238
local procedure SetReferenceOnAfterGetBuyerReference(SalesHeader: Record "Sales Header"; var BuyerReference: Text)
242239
begin
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
namespace Microsoft.eServices.EDocument.IO.Peppol;
2+
3+
using Microsoft.Sales.Document;
4+
using Microsoft.Sales.Peppol;
5+
6+
codeunit 13921 "EDoc PEPPOL Validation DE"
7+
{
8+
EventSubscriberInstance = Manual;
9+
10+
[EventSubscriber(ObjectType::Codeunit, Codeunit::"PEPPOL Validation", 'OnCheckSalesDocumentOnBeforeCheckYourReference', '', false, false)]
11+
local procedure SkipCheckOnCheckSalesDocumentOnBeforeCheckYourReference(SalesHeader: Record "Sales Header"; var IsHandled: Boolean)
12+
begin
13+
IsHandled := true;
14+
end;
15+
16+
[EventSubscriber(ObjectType::Codeunit, Codeunit::"PEPPOL Validation", 'OnAfterCheckSalesDocument', '', false, false)]
17+
local procedure OnAfterCheckSalesDocument(SalesHeader: Record "Sales Header")
18+
begin
19+
SalesHeader.TestField("Sell-to E-Mail");
20+
end;
21+
}

Apps/DE/EDocumentDE/app/src/XRechnung/XRechnungFormat.Codeunit.al

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ using System.IO;
1111
using Microsoft.Sales.Customer;
1212
using Microsoft.Foundation.Company;
1313
using Microsoft.eServices.EDocument;
14+
using Microsoft.eServices.EDocument.IO.Peppol;
1415
using Microsoft.Service.History;
1516

1617
codeunit 13914 "XRechnung Format" implements "E-Document"
@@ -19,12 +20,17 @@ codeunit 13914 "XRechnung Format" implements "E-Document"
1920
InherentPermissions = X;
2021

2122
var
23+
EDocPEPPOLBIS30: Codeunit "EDoc PEPPOL BIS 3.0";
24+
EDocPEPPOLValidationDE: Codeunit "EDoc PEPPOL Validation DE";
2225
EDocImportXRechnung: Codeunit "Import XRechnung Document";
2326

2427
procedure Check(var SourceDocumentHeader: RecordRef; EDocumentService: Record "E-Document Service"; EDocumentProcessingPhase: Enum "E-Document Processing Phase")
2528
begin
2629
CheckCompanyInfoMandatory();
2730
CheckBuyerReferenceMandatory(EDocumentService, SourceDocumentHeader);
31+
BindSubscription(EDocPEPPOLValidationDE);
32+
EDocPEPPOLBIS30.Check(SourceDocumentHeader, EDocumentService, EDocumentProcessingPhase);
33+
UnbindSubscription(EDocPEPPOLValidationDE);
2834
end;
2935

3036
procedure Create(EDocumentService: Record "E-Document Service"; var EDocument: Record "E-Document"; var SourceDocumentHeader: RecordRef; var SourceDocumentLines: RecordRef; var TempBlob: Codeunit "Temp Blob")

Apps/DE/EDocumentDE/app/src/ZUGFeRD/ExportZUGFeRDDocument.Codeunit.al

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -644,14 +644,12 @@ codeunit 13917 "Export ZUGFeRD Document"
644644
PaymentTermsDescriptionElement: XmlElement;
645645
DueDateElement: XmlElement;
646646
begin
647-
if PaymentTermsCode = '' then
648-
exit;
649-
if not PaymentTerms.Get(PaymentTermsCode) then
650-
exit;
651-
652647
PaymentTermsElement := XmlElement.Create('SpecifiedTradePaymentTerms', XmlNamespaceRAM);
653-
PaymentTermsDescriptionElement := XmlElement.Create('Description', XmlNamespaceRAM, PaymentTerms.Description);
654-
PaymentTermsElement.Add(PaymentTermsDescriptionElement);
648+
if PaymentTermsCode <> '' then
649+
if PaymentTerms.Get(PaymentTermsCode) then begin
650+
PaymentTermsDescriptionElement := XmlElement.Create('Description', XmlNamespaceRAM, PaymentTerms.Description);
651+
PaymentTermsElement.Add(PaymentTermsDescriptionElement);
652+
end;
655653

656654
DueDateElement := XmlElement.Create('DueDateDateTime', XmlNamespaceRAM);
657655
DueDateElement.Add(XmlElement.Create('DateTimeString', XmlNamespaceUDT, XmlAttribute.Create('format', '102'), FormatDate(DueDate)));
@@ -674,7 +672,7 @@ codeunit 13917 "Export ZUGFeRD Document"
674672
end;
675673

676674
if CompanyInformation."SWIFT Code" <> '' then begin
677-
PaymentMethodBICElement := XmlElement.Create('PayeePartyCreditorFinancialAccount', XmlNamespaceRAM);
675+
PaymentMethodBICElement := XmlElement.Create('PayeeSpecifiedCreditorFinancialInstitution', XmlNamespaceRAM);
678676
PaymentMethodBICElement.Add(XmlElement.Create('BICID', XmlNamespaceRAM, GetIBAN(CompanyInformation."SWIFT Code")));
679677
PaymentMethodElement.Add(PaymentMethodBICElement);
680678
end;

Apps/DE/EDocumentDE/app/src/ZUGFeRD/ZUGFeRDFormat.Codeunit.al

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,25 @@ using Microsoft.Sales.History;
1111
using Microsoft.Purchases.Document;
1212
using Microsoft.eServices.EDocument;
1313
using System.IO;
14+
using Microsoft.eServices.EDocument.IO.Peppol;
1415

1516
codeunit 13920 "ZUGFeRD Format" implements "E-Document"
1617
{
1718
InherentEntitlements = X;
1819
InherentPermissions = X;
1920

2021
var
22+
EDocPEPPOLBIS30: Codeunit "EDoc PEPPOL BIS 3.0";
23+
EDocPEPPOLValidationDE: Codeunit "EDoc PEPPOL Validation DE";
2124
EDocImportZUGFeRD: Codeunit "Import ZUGFeRD Document";
2225

2326
procedure Check(var SourceDocumentHeader: RecordRef; EDocumentService: Record "E-Document Service"; EDocumentProcessingPhase: Enum "E-Document Processing Phase")
2427
begin
2528
CheckCompanyInfoMandatory();
2629
CheckBuyerReferenceMandatory(EDocumentService, SourceDocumentHeader);
30+
BindSubscription(EDocPEPPOLValidationDE);
31+
EDocPEPPOLBIS30.Check(SourceDocumentHeader, EDocumentService, EDocumentProcessingPhase);
32+
UnbindSubscription(EDocPEPPOLValidationDE);
2733
end;
2834

2935
procedure Create(EDocumentService: Record "E-Document Service"; var EDocument: Record "E-Document"; var SourceDocumentHeader: RecordRef; var SourceDocumentLines: RecordRef; var TempBlob: Codeunit "Temp Blob")

Apps/DE/EDocumentDE/test/src/ZUGFeRDXMLDocumentTests.Codeunit.al

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,29 @@ codeunit 13922 "ZUGFeRD XML Document Tests"
187187
VerifyPaymentTerms(SalesInvoiceHeader."Payment Terms Code", SalesInvoiceHeader."Due Date", TempXMLBuffer, '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradePaymentTerms');
188188
end;
189189

190+
[Test]
191+
procedure ExportPostedSalesInvoiceInZUGFeRDFormatVerifyDueDate();
192+
var
193+
SalesHeader: Record "Sales Header";
194+
SalesInvoiceHeader: Record "Sales Invoice Header";
195+
TempXMLBuffer: Record "XML Buffer" temporary;
196+
begin
197+
// [SCENARIO] Export "Due Date" when no "Payment Terms" are defined for the customer, ensuring a valid ZUGFeRD format.
198+
Initialize();
199+
200+
// [GIVEN] Create and Post Sales Invoice without Payment Terms.
201+
SalesHeader.Get("Sales Document Type"::Invoice, CreateSalesDocumentWithLine("Sales Document Type"::Invoice, Enum::"Sales Line Type"::Item, false));
202+
SalesHeader."Payment Terms Code" := '';
203+
SalesHeader.Modify();
204+
SalesInvoiceHeader.Get(LibrarySales.PostSalesDocument(SalesHeader, true, true));
205+
206+
// [WHEN] Export ZUGFeRD Electronic Document.
207+
ExportInvoice(SalesInvoiceHeader, TempXMLBuffer);
208+
209+
// [THEN] ZUGFeRD Electronic Document is created with due date
210+
VerifyDueDate(SalesInvoiceHeader."Due Date", TempXMLBuffer, '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradePaymentTerms');
211+
end;
212+
190213
[Test]
191214
procedure ExportPostedSalesInvoiceInZUGFeRDFormatVerifyTaxTotal();
192215
var
@@ -445,6 +468,29 @@ codeunit 13922 "ZUGFeRD XML Document Tests"
445468
VerifyPaymentTerms(SalesCrMemoHeader."Payment Terms Code", SalesCrMemoHeader."Due Date", TempXMLBuffer, '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradePaymentTerms');
446469
end;
447470

471+
[Test]
472+
procedure ExportPostedSalesCrMemoInZUGFeRDFormatVerifyDueDate();
473+
var
474+
SalesHeader: Record "Sales Header";
475+
SalesCrMemoHeader: Record "Sales Cr.Memo Header";
476+
TempXMLBuffer: Record "XML Buffer" temporary;
477+
begin
478+
// [SCENARIO] Export "Due Date" when no "Payment Terms" are defined for the customer, ensuring a valid ZUGFeRD format.
479+
Initialize();
480+
481+
// [GIVEN] Create and Post Credit Memo without Payment Terms.
482+
SalesHeader.Get("Sales Document Type"::"Credit Memo", CreateSalesDocumentWithLine("Sales Document Type"::"Credit Memo", Enum::"Sales Line Type"::Item, false));
483+
SalesHeader."Payment Terms Code" := '';
484+
SalesHeader.Modify();
485+
SalesCrMemoHeader.Get(LibrarySales.PostSalesDocument(SalesHeader, true, true));
486+
487+
// [WHEN] Export ZUGFeRD Electronic Document.
488+
ExportCreditMemo(SalesCrMemoHeader, TempXMLBuffer);
489+
490+
// [THEN] ZUGFeRD Electronic Document is created with due date
491+
VerifyDueDate(SalesCrMemoHeader."Due Date", TempXMLBuffer, '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradePaymentTerms');
492+
end;
493+
448494
[Test]
449495
procedure ExportPostedSalesCrMemoInZUGFeRDFormatVerifyTaxTotal();
450496
var
@@ -807,6 +853,14 @@ codeunit 13922 "ZUGFeRD XML Document Tests"
807853
Assert.AreEqual(FormatDate(DueDate), GetNodeByPathWithError(TempXMLBuffer, Path), StrSubstNo(IncorrectValueErr, Path));
808854
end;
809855

856+
local procedure VerifyDueDate(DueDate: Date; var TempXMLBuffer: Record "XML Buffer" temporary; DocumentTok: Text);
857+
var
858+
Path: Text;
859+
begin
860+
Path := DocumentTok + '/ram:DueDateDateTime/udt:DateTimeString';
861+
Assert.AreEqual(FormatDate(DueDate), GetNodeByPathWithError(TempXMLBuffer, Path), StrSubstNo(IncorrectValueErr, Path));
862+
end;
863+
810864
local procedure VerifyTaxTotals(SalesInvoiceHeader: Record "Sales Invoice Header"; var TempXMLBuffer: Record "XML Buffer" temporary);
811865
var
812866
DocumentTaxTotalTok: Label '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:ApplicableTradeTax', Locked = true;

0 commit comments

Comments
 (0)