diff --git a/Apps/DE/EDocumentDE/app/src/ZUGFeRD/ExportZUGFeRDDocument.Codeunit.al b/Apps/DE/EDocumentDE/app/src/ZUGFeRD/ExportZUGFeRDDocument.Codeunit.al index 7357b0168d..6a83dbf4f9 100644 --- a/Apps/DE/EDocumentDE/app/src/ZUGFeRD/ExportZUGFeRDDocument.Codeunit.al +++ b/Apps/DE/EDocumentDE/app/src/ZUGFeRD/ExportZUGFeRDDocument.Codeunit.al @@ -4,6 +4,7 @@ // ------------------------------------------------------------------------------------------------ namespace Microsoft.eServices.EDocument.Formats; +using Microsoft.Bank.BankAccount; using Microsoft.CRM.Team; using Microsoft.eServices.EDocument; using Microsoft.Finance.Currency; @@ -349,6 +350,7 @@ codeunit 13917 "Export ZUGFeRD Document" GetSetups(); FindEDocumentService(); PEPPOLMgt.TransferHeaderToSalesInvoiceHeader(ServiceInvoiceHeader, SalesInvoiceHeader); + SalesInvoiceHeader."Company Bank Account Code" := ServiceInvoiceHeader."Company Bank Account Code"; ServiceInvoiceLine.SetRange("Document No.", ServiceInvoiceHeader."No."); if ServiceInvoiceLine.FindSet() then repeat @@ -391,6 +393,7 @@ codeunit 13917 "Export ZUGFeRD Document" GetSetups(); FindEDocumentService(); PEPPOLMgt.TransferHeaderToSalesCrMemoHeader(ServiceCrMemoHeader, SalesCrMemoHeader); + SalesCrMemoHeader."Company Bank Account Code" := ServiceCrMemoHeader."Company Bank Account Code"; ServiceCrMemoLine.SetRange("Document No.", ServiceCrMemoHeader."No."); if ServiceCrMemoLine.FindSet() then repeat @@ -733,7 +736,7 @@ codeunit 13917 "Export ZUGFeRD Document" SettlementElement := XmlElement.Create('ApplicableHeaderTradeSettlement', XmlNamespaceRAM); SettlementElement.Add(XmlElement.Create('InvoiceCurrencyCode', XmlNamespaceRAM, CurrencyCode)); - InsertPaymentMethod(SettlementElement); + InsertPaymentMethod(SettlementElement, SalesInvHeader."Company Bank Account Code"); InsertTradeTax(SettlementElement, SalesInvLine, LineAmount, LineVATAmount); InsertInvDiscountAllowanceCharge(SettlementElement, SalesInvLine, LineDiscAmount, LineAmounts); @@ -758,7 +761,7 @@ codeunit 13917 "Export ZUGFeRD Document" SettlementElement := XmlElement.Create('ApplicableHeaderTradeSettlement', XmlNamespaceRAM); SettlementElement.Add(XmlElement.Create('InvoiceCurrencyCode', XmlNamespaceRAM, CurrencyCode)); - InsertPaymentMethod(SettlementElement); + InsertPaymentMethod(SettlementElement, SalesCrMemoHeader."Company Bank Account Code"); InsertTradeTax(SettlementElement, SalesCrMemoLine, LineAmount, LineVATAmount); InsertInvDiscountAllowanceCharge(SettlementElement, SalesCrMemoLine, LineDiscAmount, LineAmounts); @@ -1042,23 +1045,26 @@ codeunit 13917 "Export ZUGFeRD Document" RootXMLNode.Add(PaymentTermsElement); end; - local procedure InsertPaymentMethod(var RootXMLNode: XmlElement) + local procedure InsertPaymentMethod(var RootXMLNode: XmlElement; CompanyBankAccountCode: Code[20]) var PaymentMethodElement, PaymentMethodTypeCodeElement, PaymentMethodIBANElement, PaymentMethodBICElement : XmlElement; + IBAN: Text[50]; + SWIFTCode: Code[20]; begin + GetBankAccountPaymentDetails(CompanyBankAccountCode, IBAN, SWIFTCode); PaymentMethodElement := XmlElement.Create('SpecifiedTradeSettlementPaymentMeans', XmlNamespaceRAM); PaymentMethodTypeCodeElement := XmlElement.Create('TypeCode', XmlNamespaceRAM, '58'); //generic for Credit transfer PaymentMethodElement.Add(PaymentMethodTypeCodeElement); - if CompanyInformation.IBAN <> '' then begin + if IBAN <> '' then begin PaymentMethodIBANElement := XmlElement.Create('PayeePartyCreditorFinancialAccount', XmlNamespaceRAM); - PaymentMethodIBANElement.Add(XmlElement.Create('IBANID', XmlNamespaceRAM, GetIBAN(CompanyInformation.IBAN))); + PaymentMethodIBANElement.Add(XmlElement.Create('IBANID', XmlNamespaceRAM, GetIBAN(IBAN))); PaymentMethodElement.Add(PaymentMethodIBANElement); end; - if CompanyInformation."SWIFT Code" <> '' then begin + if SWIFTCode <> '' then begin PaymentMethodBICElement := XmlElement.Create('PayeeSpecifiedCreditorFinancialInstitution', XmlNamespaceRAM); - PaymentMethodBICElement.Add(XmlElement.Create('BICID', XmlNamespaceRAM, GetIBAN(CompanyInformation."SWIFT Code"))); + PaymentMethodBICElement.Add(XmlElement.Create('BICID', XmlNamespaceRAM, GetIBAN(SWIFTCode))); PaymentMethodElement.Add(PaymentMethodBICElement); end; RootXMLNode.Add(PaymentMethodElement); @@ -1376,6 +1382,21 @@ codeunit 13917 "Export ZUGFeRD Document" if EDocumentService.FindLast() then; OnAfterFindEDocumentService(EDocumentService); end; + + local procedure GetBankAccountPaymentDetails(BankAccountCode: Code[20]; var IBAN: Text[50]; var SWIFTCode: Code[20]) + var + BankAccount: Record "Bank Account"; + begin + if BankAccountCode <> '' then + if BankAccount.Get(BankAccountCode) then begin + IBAN := BankAccount.IBAN; + SWIFTCode := BankAccount."SWIFT Code"; + exit; + end; + + IBAN := CompanyInformation.IBAN; + SWIFTCode := CompanyInformation."SWIFT Code"; + end; #endregion [IntegrationEvent(false, false)] diff --git a/Apps/DE/EDocumentDE/app/src/ZUGFeRD/ZUGFeRDFormat.Codeunit.al b/Apps/DE/EDocumentDE/app/src/ZUGFeRD/ZUGFeRDFormat.Codeunit.al index a579031afd..9666840179 100644 --- a/Apps/DE/EDocumentDE/app/src/ZUGFeRD/ZUGFeRDFormat.Codeunit.al +++ b/Apps/DE/EDocumentDE/app/src/ZUGFeRD/ZUGFeRDFormat.Codeunit.al @@ -4,6 +4,7 @@ // ------------------------------------------------------------------------------------------------ namespace Microsoft.eServices.EDocument.Formats; +using Microsoft.Bank.BankAccount; using Microsoft.eServices.EDocument; using Microsoft.eServices.EDocument.IO.Peppol; using Microsoft.Foundation.Company; @@ -27,9 +28,12 @@ codeunit 13920 "ZUGFeRD Format" implements "E-Document" EDocImportZUGFeRD: Codeunit "Import ZUGFeRD Document"; procedure Check(var SourceDocumentHeader: RecordRef; EDocumentService: Record "E-Document Service"; EDocumentProcessingPhase: Enum "E-Document Processing Phase") + var + CompanyInformation: Record "Company Information"; begin OnBeforeCheck(SourceDocumentHeader, EDocumentService, EDocumentProcessingPhase); - CheckCompanyInfoMandatory(); + CheckCompanyInfoMandatory(CompanyInformation); + CheckBankAccountIBANMandatory(SourceDocumentHeader, CompanyInformation); CheckBuyerReferenceMandatory(EDocumentService, SourceDocumentHeader); EDocPEPPOLValidationDE.SetBuyerReference(EDocumentService."Buyer Reference"); BindSubscription(EDocPEPPOLValidationDE); @@ -141,14 +145,48 @@ codeunit 13920 "ZUGFeRD Format" implements "E-Document" FileExtension := PDFFileTypeTok; end; - local procedure CheckCompanyInfoMandatory() - var - CompanyInformation: Record "Company Information"; + local procedure CheckCompanyInfoMandatory(var CompanyInformation: Record "Company Information") begin CompanyInformation.Get(); CompanyInformation.TestField("E-Mail"); end; + local procedure CheckBankAccountIBANMandatory(SourceDocumentHeader: RecordRef; var CompanyInformation: Record "Company Information") + var + BankAccount: Record "Bank Account"; + SalesInvoiceHeader: Record "Sales Invoice Header"; + ServiceInvoiceHeader: Record "Service Invoice Header"; + BankAccountCodeFieldRef: FieldRef; + CheckBankAccount: Boolean; + BankAccountCode: Code[20]; + BankAccFieldNo: Integer; + begin + if not (SourceDocumentHeader.Number() in + [Database::"Sales Header", + Database::"Sales Invoice Header", + Database::"Sales Cr.Memo Header", + Database::"Service Header", + Database::"Service Invoice Header", + Database::"Service Cr.Memo Header"]) + then + exit; + + BankAccFieldNo := SalesInvoiceHeader.FieldNo("Company Bank Account Code"); + if SourceDocumentHeader.Number() in [Database::"Service Header", Database::"Service Invoice Header", Database::"Service Cr.Memo Header"] then + BankAccFieldNo := ServiceInvoiceHeader.FieldNo("Company Bank Account Code"); + + BankAccountCodeFieldRef := SourceDocumentHeader.Field(BankAccFieldNo); + BankAccountCode := BankAccountCodeFieldRef.Value(); + + if BankAccountCode <> '' then + CheckBankAccount := BankAccount.Get(BankAccountCode); + + if CheckBankAccount then + BankAccount.TestField(IBAN) + else + CompanyInformation.TestField(IBAN); + end; + local procedure CheckBuyerReferenceMandatory(EDocumentService: Record "E-Document Service"; SourceDocumentHeader: RecordRef) var SalesInvoiceHeader: Record "Sales Invoice Header"; diff --git a/Apps/DE/EDocumentDE/test/src/ZUGFeRDXMLDocumentTests.Codeunit.al b/Apps/DE/EDocumentDE/test/src/ZUGFeRDXMLDocumentTests.Codeunit.al index c10315bae6..a47d8e8d13 100644 --- a/Apps/DE/EDocumentDE/test/src/ZUGFeRDXMLDocumentTests.Codeunit.al +++ b/Apps/DE/EDocumentDE/test/src/ZUGFeRDXMLDocumentTests.Codeunit.al @@ -237,10 +237,40 @@ codeunit 13922 "ZUGFeRD XML Document Tests" // [WHEN] Export ZUGFeRD Electronic Document. ExportInvoice(SalesInvoiceHeader, TempXMLBuffer); - // [THEN] ZUGFeRD Electronic Document is created with bank informarion as payment means + // [THEN] ZUGFeRD Electronic Document is created with bank information as payment means VerifyPaymentMeans(TempXMLBuffer, '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement', SalesInvoiceHeader."Currency Code"); end; + [Test] + procedure ExportPostedSalesInvoiceInZUGFeRDFormatVerifyBankAccountPaymentMeans(); + var + BankAccount: Record "Bank Account"; + SalesInvoiceHeader: Record "Sales Invoice Header"; + TempXMLBuffer: Record "XML Buffer" temporary; + BankAccountIBAN: Code[50]; + BankAccountSWIFT: Code[20]; + begin + // [SCENARIO 496414] Export posted sales invoice uses Bank Account IBAN and SWIFT Code when Company Bank Account Code is specified + Initialize(); + + // [GIVEN] Create Bank Account with specific IBAN and SWIFT Code + BankAccountIBAN := LibraryUtility.GenerateMOD97CompliantCode(); + BankAccountSWIFT := LibraryUtility.GenerateGUID(); + LibraryERM.CreateBankAccount(BankAccount); + BankAccount.IBAN := BankAccountIBAN; + BankAccount."SWIFT Code" := BankAccountSWIFT; + BankAccount.Modify(true); + + // [GIVEN] Create and Post Sales Invoice with Bank Account Code + SalesInvoiceHeader.Get(CreateAndPostSalesDocumentWithBankAccount("Sales Document Type"::Invoice, Enum::"Sales Line Type"::Item, BankAccount."No.")); + + // [WHEN] Export ZUGFeRD Electronic Document. + ExportInvoice(SalesInvoiceHeader, TempXMLBuffer); + + // [THEN] ZUGFeRD Electronic Document uses Bank Account IBAN and SWIFT Code + VerifyPaymentMeans(TempXMLBuffer, '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement', BankAccountIBAN, BankAccountSWIFT); + end; + [Test] procedure ExportPostedSalesInvoiceInZUGFeRDFormatVerifyPaymentTerms(); var @@ -574,10 +604,40 @@ codeunit 13922 "ZUGFeRD XML Document Tests" // [WHEN] Export ZUGFeRD Electronic Document. ExportCreditMemo(SalesCrMemoHeader, TempXMLBuffer); - // [THEN] ZUGFeRD Electronic Document is created with bank informarion as payment means + // [THEN] ZUGFeRD Electronic Document is created with bank information as payment means VerifyPaymentMeans(TempXMLBuffer, '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement', SalesCrMemoHeader."Currency Code"); end; + [Test] + procedure ExportPostedSalesCrMemoInZUGFeRDFormatVerifyBankAccountPaymentMeans(); + var + BankAccount: Record "Bank Account"; + SalesCrMemoHeader: Record "Sales Cr.Memo Header"; + TempXMLBuffer: Record "XML Buffer" temporary; + BankAccountIBAN: Code[50]; + BankAccountSWIFT: Code[20]; + begin + // [SCENARIO 496414] Export posted sales credit memo uses Bank Account IBAN and SWIFT Code when Company Bank Account Code is specified + Initialize(); + + // [GIVEN] Create Bank Account with specific IBAN and SWIFT Code + BankAccountIBAN := LibraryUtility.GenerateMOD97CompliantCode(); + BankAccountSWIFT := LibraryUtility.GenerateGUID(); + LibraryERM.CreateBankAccount(BankAccount); + BankAccount.IBAN := BankAccountIBAN; + BankAccount."SWIFT Code" := BankAccountSWIFT; + BankAccount.Modify(true); + + // [GIVEN] Create and Post Sales Credit Memo with Bank Account Code + SalesCrMemoHeader.Get(CreateAndPostSalesDocumentWithBankAccount("Sales Document Type"::"Credit Memo", Enum::"Sales Line Type"::Item, BankAccount."No.")); + + // [WHEN] Export ZUGFeRD Electronic Document. + ExportCreditMemo(SalesCrMemoHeader, TempXMLBuffer); + + // [THEN] ZUGFeRD Electronic Document uses Bank Account IBAN and SWIFT Code + VerifyPaymentMeans(TempXMLBuffer, '/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement', BankAccountIBAN, BankAccountSWIFT); + end; + [Test] procedure ExportPostedSalesCrMemoInZUGFeRDFormatVerifyPaymentTerms(); var @@ -1345,6 +1405,17 @@ codeunit 13922 "ZUGFeRD XML Document Tests" exit(LibrarySales.PostSalesDocument(SalesHeader, true, true)); end; + local procedure CreateAndPostSalesDocumentWithBankAccount(DocumentType: Enum "Sales Document Type"; LineType: Enum "Sales Line Type"; BankAccountCode: Code[20]): Code[20]; + var + SalesHeader: Record "Sales Header"; + begin + CreateSalesHeader(SalesHeader, DocumentType); + SalesHeader.Validate("Company Bank Account Code", BankAccountCode); + SalesHeader.Modify(true); + CreateSalesLine(SalesHeader, LineType, false); + exit(LibrarySales.PostSalesDocument(SalesHeader, true, true)); + end; + local procedure CreateAndPostServiceDocument(): Code[20] var ServiceHeader: Record "Service Header"; @@ -1931,6 +2002,20 @@ codeunit 13922 "ZUGFeRD XML Document Tests" Assert.AreEqual(GetIBAN(CompanyInformation.IBAN), GetNodeByPathWithError(TempXMLBuffer, Path), StrSubstNo(IncorrectValueErr, Path)); end; + local procedure VerifyPaymentMeans(var TempXMLBuffer: Record "XML Buffer" temporary; DocumentTok: Text; ExpectedIBAN: Code[50]; ExpectedSWIFT: Code[20]) + var + Path: Text; + begin + Path := DocumentTok + '/ram:SpecifiedTradeSettlementPaymentMeans/ram:TypeCode'; + Assert.AreEqual('58', GetNodeByPathWithError(TempXMLBuffer, Path), StrSubstNo(IncorrectValueErr, Path)); + Path := DocumentTok + '/ram:SpecifiedTradeSettlementPaymentMeans/ram:PayeePartyCreditorFinancialAccount/ram:IBANID'; + Assert.AreEqual(GetIBAN(ExpectedIBAN), GetNodeByPathWithError(TempXMLBuffer, Path), StrSubstNo(IncorrectValueErr, Path)); + if ExpectedSWIFT <> '' then begin + Path := DocumentTok + '/ram:SpecifiedTradeSettlementPaymentMeans/ram:PayeeSpecifiedCreditorFinancialInstitution/ram:BICID'; + Assert.AreEqual(GetIBAN(ExpectedSWIFT), GetNodeByPathWithError(TempXMLBuffer, Path), StrSubstNo(IncorrectValueErr, Path)); + end; + end; + local procedure VerifyPaymentTerms(PaymentTermsCode: Code[10]; DueDate: Date; var TempXMLBuffer: Record "XML Buffer" temporary; DocumentTok: Text); var PaymentTerms: Record "Payment Terms";