diff --git a/Apps/DE/EDocumentDE/app/src/XRechnung/ExportXRechnungDocument.Codeunit.al b/Apps/DE/EDocumentDE/app/src/XRechnung/ExportXRechnungDocument.Codeunit.al index 85b6207ba3..f92e1c717c 100644 --- a/Apps/DE/EDocumentDE/app/src/XRechnung/ExportXRechnungDocument.Codeunit.al +++ b/Apps/DE/EDocumentDE/app/src/XRechnung/ExportXRechnungDocument.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; @@ -158,7 +159,7 @@ codeunit 13916 "Export XRechnung Document" InsertAccountingSupplierParty(SalesInvoiceHeader."Responsibility Center", SalesInvoiceHeader."Salesperson Code", RootXMLNode); InsertAccountingCustomerParty(RootXMLNode, SalesInvoiceHeader); InsertDelivery(RootXMLNode, SalesInvoiceHeader); - InsertPaymentMeans(RootXMLNode, '68', 'PayeeFinancialAccount', SalesInvoiceHeader."Company Bank Account Code"); + InsertPaymentMeans(RootXMLNode, '58', 'PayeeFinancialAccount', SalesInvoiceHeader."Company Bank Account Code"); InsertPaymentTerms(RootXMLNode, SalesInvoiceHeader."Payment Terms Code"); InsertVATAmounts(SalesInvLine, LineVATAmount, LineAmount, LineDiscAmount, SalesInvoiceHeader."Prices Including VAT", Currency); InsertInvDiscountAllowanceCharge(LineAmounts, SalesInvLine, CurrencyCode, RootXMLNode, LineDiscAmount, LineAmount, Currency."Amount Rounding Precision"); @@ -203,7 +204,7 @@ codeunit 13916 "Export XRechnung Document" InsertAccountingSupplierParty(SalesCrMemoHeader."Responsibility Center", SalesCrMemoHeader."Salesperson Code", RootXMLNode); InsertAccountingCustomerParty(RootXMLNode, SalesCrMemoHeader); InsertDelivery(RootXMLNode, SalesCrMemoHeader); - InsertPaymentMeans(RootXMLNode, '68', '', SalesCrMemoHeader."Company Bank Account Code"); + InsertPaymentMeans(RootXMLNode, '58', '', SalesCrMemoHeader."Company Bank Account Code"); InsertPaymentTerms(RootXMLNode, SalesCrMemoHeader."Payment Terms Code"); InsertVATAmounts(SalesCrMemoLine, LineVATAmount, LineAmount, LineDiscAmount, SalesCrMemoHeader."Prices Including VAT", Currency); InsertInvDiscountAllowanceCharge(LineAmounts, SalesCrMemoLine, CurrencyCode, RootXMLNode, LineDiscAmount, LineAmount, Currency."Amount Rounding Precision"); @@ -233,6 +234,7 @@ codeunit 13916 "Export XRechnung Document" begin GetSetups(); 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 @@ -258,7 +260,7 @@ codeunit 13916 "Export XRechnung Document" InsertAccountingSupplierParty(SalesInvoiceHeader."Responsibility Center", SalesInvoiceHeader."Salesperson Code", RootXMLNode); InsertAccountingCustomerParty(RootXMLNode, SalesInvoiceHeader); InsertDelivery(RootXMLNode, SalesInvoiceHeader); - InsertPaymentMeans(RootXMLNode, '68', 'PayeeFinancialAccount', SalesInvoiceHeader."Company Bank Account Code"); + InsertPaymentMeans(RootXMLNode, '58', 'PayeeFinancialAccount', SalesInvoiceHeader."Company Bank Account Code"); InsertPaymentTerms(RootXMLNode, SalesInvoiceHeader."Payment Terms Code"); InsertVATAmounts(TempSalesInvLine, LineVATAmount, LineAmount, LineDiscAmount, SalesInvoiceHeader."Prices Including VAT", Currency); InsertInvDiscountAllowanceCharge(LineAmounts, TempSalesInvLine, CurrencyCode, RootXMLNode, LineDiscAmount, LineAmount, Currency."Amount Rounding Precision"); @@ -288,6 +290,7 @@ codeunit 13916 "Export XRechnung Document" begin GetSetups(); 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 @@ -312,7 +315,7 @@ codeunit 13916 "Export XRechnung Document" InsertAccountingSupplierParty(SalesCrMemoHeader."Responsibility Center", SalesCrMemoHeader."Salesperson Code", RootXMLNode); InsertAccountingCustomerParty(RootXMLNode, SalesCrMemoHeader); InsertDelivery(RootXMLNode, SalesCrMemoHeader); - InsertPaymentMeans(RootXMLNode, '68', '', SalesCrMemoHeader."Company Bank Account Code"); + InsertPaymentMeans(RootXMLNode, '58', '', SalesCrMemoHeader."Company Bank Account Code"); InsertPaymentTerms(RootXMLNode, SalesCrMemoHeader."Payment Terms Code"); InsertVATAmounts(TempSalesCrMemoLine, LineVATAmount, LineAmount, LineDiscAmount, SalesCrMemoHeader."Prices Including VAT", Currency); InsertInvDiscountAllowanceCharge(LineAmounts, TempSalesCrMemoLine, CurrencyCode, RootXMLNode, LineDiscAmount, LineAmount, Currency."Amount Rounding Precision"); @@ -536,22 +539,23 @@ codeunit 13916 "Export XRechnung Document" local procedure InsertPayeeFinancialAccount(var PaymentMeansElement: XmlElement; PayeeFinancialAccount: Text[30]; CompanyBankAccountCode: Code[20]); var PayeeFinancialAccountElement: XmlElement; + IBAN: Text[50]; + SWIFTCode: Code[20]; begin PayeeFinancialAccountElement := XmlElement.Create(PayeeFinancialAccount, XmlNamespaceCAC); - if CompanyBankAccountCode <> '' then - PayeeFinancialAccountElement.Add(XmlElement.Create('ID', XmlNamespaceCBC, CompanyBankAccountCode)) - else - PayeeFinancialAccountElement.Add(XmlElement.Create('ID', XmlNamespaceCBC, CompanyInformation."Bank Account No.")); - InsertFinancialInstitutionBranch(PayeeFinancialAccountElement); + GetBankAccountPaymentDetails(CompanyBankAccountCode, IBAN, SWIFTCode); + PayeeFinancialAccountElement.Add(XmlElement.Create('ID', XmlNamespaceCBC, GetIBAN(IBAN))); + if SWIFTCode <> '' then + InsertFinancialInstitutionBranch(PayeeFinancialAccountElement, SWIFTCode); PaymentMeansElement.Add(PayeeFinancialAccountElement); end; - local procedure InsertFinancialInstitutionBranch(var RootElement: XmlElement); + local procedure InsertFinancialInstitutionBranch(var RootElement: XmlElement; SWIFTCode: Code[20]); var FinancialInstitutionBranchElement: XmlElement; begin FinancialInstitutionBranchElement := XmlElement.Create('FinancialInstitutionBranch', XmlNamespaceCAC); - FinancialInstitutionBranchElement.Add(XmlElement.Create('ID', XmlNamespaceCBC, CompanyInformation."Bank Branch No.")); + FinancialInstitutionBranchElement.Add(XmlElement.Create('ID', XmlNamespaceCBC, GetIBAN(SWIFTCode))); RootElement.Add(FinancialInstitutionBranchElement); end; @@ -1438,6 +1442,33 @@ codeunit 13916 "Export XRechnung Document" GeneralLedgerSetup.Get(); OnAfterGetSetups(CompanyInformation, GeneralLedgerSetup); end; + + local procedure GetIBAN(IBAN: Text[50]) IBANFormatted: Text[50] + begin + // Format IBAN to remove spaces and ensure it is in uppercase + if IBAN = '' then + exit(''); + IBANFormatted := UpperCase(DelChr(IBAN, '=', ' ')); + exit(CopyStr(IBANFormatted, 1, 50)); + end; + + local procedure GetBankAccountPaymentDetails(BankAccountCode: Code[20]; var IBAN: Text[50]; var SWIFTCode: Code[20]) + var + BankAccount: Record "Bank Account"; + begin + Clear(IBAN); + Clear(SWIFTCode); + + 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/XRechnung/XRechnungFormat.Codeunit.al b/Apps/DE/EDocumentDE/app/src/XRechnung/XRechnungFormat.Codeunit.al index 83bcc9e5b4..55465f3792 100644 --- a/Apps/DE/EDocumentDE/app/src/XRechnung/XRechnungFormat.Codeunit.al +++ b/Apps/DE/EDocumentDE/app/src/XRechnung/XRechnungFormat.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 13914 "XRechnung Format" implements "E-Document" EDocImportXRechnung: Codeunit "Import XRechnung 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); BindSubscription(EDocPEPPOLValidationDE); EDocPEPPOLBIS30.Check(SourceDocumentHeader, EDocumentService, EDocumentProcessingPhase); @@ -77,18 +81,52 @@ codeunit 13914 "XRechnung Format" implements "E-Document" TempBlob.FromRecord(TempRecordExportBuffer, TempRecordExportBuffer.FieldNo("File Content")); 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 CheckBuyerReferenceMandatory(EDocumentService: Record "E-Document Service"; SourceDocumentHeader: RecordRef) + 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 Customer: Record Customer; + SalesInvoiceHeader: Record "Sales Invoice Header"; CustomerNoFieldRef: FieldRef; YourReferenceFieldRef: FieldRef; begin diff --git a/Apps/DE/EDocumentDE/test/src/XRechnungXMLDocumentTests.Codeunit.al b/Apps/DE/EDocumentDE/test/src/XRechnungXMLDocumentTests.Codeunit.al index b550cc5f52..2d4de7df52 100644 --- a/Apps/DE/EDocumentDE/test/src/XRechnungXMLDocumentTests.Codeunit.al +++ b/Apps/DE/EDocumentDE/test/src/XRechnungXMLDocumentTests.Codeunit.al @@ -4,6 +4,7 @@ // ------------------------------------------------------------------------------------------------ namespace Microsoft.eServices.EDocument.Formats; +using Microsoft.Bank.BankAccount; using Microsoft.eServices.EDocument; using Microsoft.eServices.EDocument.Integration; using Microsoft.Finance.Currency; @@ -194,7 +195,37 @@ codeunit 13918 "XRechnung XML Document Tests" ExportInvoice(SalesInvoiceHeader, TempXMLBuffer); // [THEN] XRechnung Electronic Document is created with bank informarion as payment means - VerifyPaymentMeans(TempXMLBuffer, '/ubl:Invoice/cac:PaymentMeans'); + VerifyPaymentMeans(TempXMLBuffer, '/ubl:Invoice/cac:PaymentMeans', CompanyInformation.IBAN, CompanyInformation."SWIFT Code"); + end; + + [Test] + procedure ExportPostedSalesInvoiceInXRechnungFormatVerifyBankAccountPaymentMeans(); + var + BankAccount: Record "Bank Account"; + SalesInvoiceHeader: Record "Sales Invoice Header"; + TempXMLBuffer: Record "XML Buffer" temporary; + BankAccountIBAN: Text; + BankAccountSWIFT: Text; + 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 XRechnung Electronic Document. + ExportInvoice(SalesInvoiceHeader, TempXMLBuffer); + + // [THEN] XRechnung Electronic Document uses Bank Account IBAN and SWIFT Code + VerifyPaymentMeans(TempXMLBuffer, '/ubl:Invoice/cac:PaymentMeans', BankAccountIBAN, BankAccountSWIFT); end; [Test] @@ -760,7 +791,37 @@ codeunit 13918 "XRechnung XML Document Tests" // [WHEN] Export XRechnung Electronic Document. ExportCreditMemo(SalesCrMemoHeader, TempXMLBuffer); - // [THEN] XRechnung Electronic Document is created with bank informarion as payment means + // [THEN] XRechnung Electronic Document is created with payment means code + VerifyPaymentMeans(TempXMLBuffer, '/ns0:CreditNote/cac:PaymentMeans'); + end; + + [Test] + procedure ExportPostedSalesCrMemoInXRechnungFormatVerifyBankAccountPaymentMeans(); + var + BankAccount: Record "Bank Account"; + SalesCrMemoHeader: Record "Sales Cr.Memo Header"; + TempXMLBuffer: Record "XML Buffer" temporary; + BankAccountIBAN: Text; + BankAccountSWIFT: Text; + begin + // [SCENARIO 496414] Export posted sales cr. 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 cr. memo with Bank Account Code + SalesCrMemoHeader.Get(CreateAndPostSalesDocumentWithBankAccount("Sales Document Type"::"Credit Memo", Enum::"Sales Line Type"::Item, BankAccount."No.")); + + // [WHEN] Export XRechnung Electronic Document. + ExportCreditMemo(SalesCrMemoHeader, TempXMLBuffer); + + // [THEN] XRechnung Electronic Document has payment means code VerifyPaymentMeans(TempXMLBuffer, '/ns0:CreditNote/cac:PaymentMeans'); end; @@ -1388,6 +1449,17 @@ codeunit 13918 "XRechnung 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 CreatePurchDocument(var PurchaseHeader: Record "Purchase Header"; DocumentType: Enum "Purchase Document Type") var PurchaseLine: Record "Purchase Line"; @@ -1851,7 +1923,20 @@ codeunit 13918 "XRechnung XML Document Tests" Path: Text; begin Path := DocumentTok + '/cbc:PaymentMeansCode'; - Assert.AreEqual('68', GetNodeByPathWithError(TempXMLBuffer, Path), StrSubstNo(IncorrectValueErr, Path)); + Assert.AreEqual('58', GetNodeByPathWithError(TempXMLBuffer, Path), StrSubstNo(IncorrectValueErr, Path)); + end; + + local procedure VerifyPaymentMeans(var TempXMLBuffer: Record "XML Buffer" temporary; DocumentTok: Text; ExpectedIBAN: Text; ExpectedSWIFT: Text); + var + Path: Text; + begin + VerifyPaymentMeans(TempXMLBuffer, DocumentTok); + Path := DocumentTok + '/cac:PayeeFinancialAccount/cbc:ID'; + Assert.AreEqual(ExpectedIBAN, GetNodeByPathWithError(TempXMLBuffer, Path), StrSubstNo(IncorrectValueErr, Path)); + if ExpectedSWIFT <> '' then begin + Path := DocumentTok + '/cac:PayeeFinancialAccount/cac:FinancialInstitutionBranch/cbc:ID'; + Assert.AreEqual(ExpectedSWIFT, GetNodeByPathWithError(TempXMLBuffer, Path), StrSubstNo(IncorrectValueErr, Path)); + end; end; local procedure VerifyPaymentTerms(PaymentTermsCode: Code[10]; var TempXMLBuffer: Record "XML Buffer" temporary; DocumentTok: Text); @@ -2519,6 +2604,9 @@ codeunit 13918 "XRechnung XML Document Tests" LibraryTestInitialize.OnBeforeTestSuiteInitialize(Codeunit::"XRechnung XML Document Tests"); IsInitialized := true; CompanyInformation.Get(); + CompanyInformation.IBAN := LibraryUtility.GenerateMOD97CompliantCode(); + CompanyInformation."SWIFT Code" := LibraryUtility.GenerateGUID(); + CompanyInformation.Modify(); GeneralLedgerSetup.Get(); EDocumentService.DeleteAll(); EDocumentService.Get(LibraryEdocument.CreateService("E-Document Format"::XRechnung, "Service Integration"::"No Integration"));