From de06a995dc53400c6246963495eb5cce1d1c5f86 Mon Sep 17 00:00:00 2001 From: Sven Harazim Date: Mon, 12 Aug 2024 09:55:15 +0200 Subject: [PATCH] sync with c# lib 2024 08 12 v14 --- Test/DUnitXZUGFeRDTest.dpr | 1 + Test/intf.XRechnungUBLTests.UnitTests.pas | 136 +++++++++++++++++++ Test/intf.ZUGFeRD22Tests.UnitTests.pas | 93 ++++++------- intf.ZUGFeRDInvoiceDescriptor20Reader.pas | 1 + intf.ZUGFeRDInvoiceDescriptor22CIIReader.pas | 6 +- intf.ZUGFeRDInvoiceDescriptor22CIIWriter.pas | 4 +- 6 files changed, 186 insertions(+), 55 deletions(-) create mode 100644 Test/intf.XRechnungUBLTests.UnitTests.pas diff --git a/Test/DUnitXZUGFeRDTest.dpr b/Test/DUnitXZUGFeRDTest.dpr index 77e1bae..72d08ca 100644 --- a/Test/DUnitXZUGFeRDTest.dpr +++ b/Test/DUnitXZUGFeRDTest.dpr @@ -85,6 +85,7 @@ uses intf.ZUGFeRDInvoiceDescriptor20Reader,intf.ZUGFeRDInvoiceDescriptor20Writer,intf.ZUGFeRD20Tests.UnitTests, intf.ZUGFeRDInvoiceDescriptor22CIIReader,intf.ZUGFeRDInvoiceDescriptor22Writer,intf.ZUGFeRD22Tests.UnitTests, intf.ZUGFeRDInvoiceDescriptor22UBLReader, + intf.XRechnungUBLTests.UnitTests, intf.ZUGFeRDBaseTests.UnitTests ; diff --git a/Test/intf.XRechnungUBLTests.UnitTests.pas b/Test/intf.XRechnungUBLTests.UnitTests.pas new file mode 100644 index 0000000..dfef6f7 --- /dev/null +++ b/Test/intf.XRechnungUBLTests.UnitTests.pas @@ -0,0 +1,136 @@ +{* Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License.} + +unit intf.XRechnungUBLTests.UnitTests; + +interface + +uses + System.SysUtils + ,DUnitX.TestFramework + ,intf.ZUGFeRDInvoiceDescriptor + ,intf.ZUGFeRDProfile,intf.ZUGFeRDInvoiceTypes + ,intf.ZUGFeRDInvoiceProvider + ,intf.ZUGFeRDVersion + ; + +type + [TestFixture] + TXRechnungUBLTests = class + public + [Test] + procedure TestInvoiceCreation; + [Test] + procedure TestTradelineitemProductCharacterstics; + /// + /// https://github.com/stephanstapel/ZUGFeRD-csharp/issues/319 + /// + [Test] + procedure TestSkippingOfAllowanceChargeBasisAmount; + end; + +implementation + +{ TXRechnungUBLTests } + +procedure TXRechnungUBLTests.TestInvoiceCreation; +begin +// InvoiceDescriptor desc = this.InvoiceProvider.CreateInvoice(); +// MemoryStream ms = new MemoryStream(); +// +// desc.Save(ms, ZUGFeRDVersion.Version22, Profile.XRechnung, ZUGFeRDFormats.UBL); +// ms.Seek(0, SeekOrigin.Begin); +// +// InvoiceDescriptor loadedInvoice = InvoiceDescriptor.Load(ms); +// +// Assert.AreEqual(loadedInvoice.Invoicee, null); +// Assert.AreNotEqual(loadedInvoice.Seller, null); +// Assert.AreEqual(loadedInvoice.Taxes.Count, 2); +// Assert.AreEqual(loadedInvoice.SellerContact.Name, "Max Mustermann"); +// Assert.IsNull(loadedInvoice.BuyerContact); +end; + +procedure TXRechnungUBLTests.TestSkippingOfAllowanceChargeBasisAmount; +begin +// // actual values do not matter +// decimal basisAmount = 123.0m; +// decimal percent = 11.0m; +// decimal allowanceChargeBasisAmount = 121.0m; +// +// InvoiceDescriptor desc = this.InvoiceProvider.CreateInvoice(); +// desc.AddApplicableTradeTax(basisAmount, percent, TaxTypes.LOC, TaxCategoryCodes.K, allowanceChargeBasisAmount); +// MemoryStream ms = new MemoryStream(); +// +// desc.Save(ms, ZUGFeRDVersion.Version22, Profile.XRechnung, ZUGFeRDFormats.UBL); +// ms.Seek(0, SeekOrigin.Begin); +// +// InvoiceDescriptor loadedInvoice = InvoiceDescriptor.Load(ms); +// +// Tax tax = loadedInvoice.Taxes.FirstOrDefault(t => t.TypeCode == TaxTypes.LOC); +// Assert.IsNotNull(tax); +// Assert.AreEqual(basisAmount, tax.BasisAmount); +// Assert.AreEqual(percent, tax.Percent); +// Assert.AreEqual(null, tax.AllowanceChargeBasisAmount); +end; + +procedure TXRechnungUBLTests.TestTradelineitemProductCharacterstics; +begin +// InvoiceDescriptor desc = this.InvoiceProvider.CreateInvoice(); +// +// desc.TradeLineItems[0].ApplicableProductCharacteristics = new ApplicableProductCharacteristic[] +// { +// new ApplicableProductCharacteristic() +// { +// Description = "Test Description", +// Value = "1.5 kg" +// }, +// new ApplicableProductCharacteristic() +// { +// Description = "UBL Characterstics 2", +// Value = "3 kg" +// }, +// }.ToList(); +// +// MemoryStream ms = new MemoryStream(); +// +// desc.Save(ms, ZUGFeRDVersion.Version22, Profile.XRechnung, ZUGFeRDFormats.UBL); +// ms.Seek(0, SeekOrigin.Begin); +// +// InvoiceDescriptor loadedInvoice = InvoiceDescriptor.Load(ms); +// +// Assert.IsNotNull(loadedInvoice.TradeLineItems); +// Assert.AreEqual(loadedInvoice.TradeLineItems[0].ApplicableProductCharacteristics.Count, 2); +// Assert.AreEqual(loadedInvoice.TradeLineItems[0].ApplicableProductCharacteristics[0].Description, "Test Description"); +// Assert.AreEqual(loadedInvoice.TradeLineItems[0].ApplicableProductCharacteristics[1].Value, "3 kg"); +end; + +initialization + +//I was hoping to use RTTI to discover the TestFixture classes, however unlike .NET +//if we don't touch the class somehow then the linker will remove +//the class from the resulting exe. +//We could just do this: +//TMyExampleTests.ClassName; +//TExampleFixture2.ClassName; +//which is enough to make the compiler link the classes into the exe, but that seems a +//bit redundent so I guess we'll just use manual registration. If you use the +//{$STRONGLINKTYPES ON} compiler directive then it will link the TestFixtures in and you +//can use RTTI. The downside to that is the resulting exe will potentially much larger. +//Not sure which version {$STRONGLINKTYPES ON} was introduced so we'll allow RTTI and +//manual registration for now. + +end. diff --git a/Test/intf.ZUGFeRD22Tests.UnitTests.pas b/Test/intf.ZUGFeRD22Tests.UnitTests.pas index 2b26bba..6f64595 100644 --- a/Test/intf.ZUGFeRD22Tests.UnitTests.pas +++ b/Test/intf.ZUGFeRD22Tests.UnitTests.pas @@ -128,11 +128,9 @@ TZUGFeRD22Tests = class [Test] procedure TestSpecifiedTradeAllowanceCharge; [Test] - procedure TestUBLInvoiceCreation; - [Test] - procedure TestUBLTradelineitemProductCharacterstics; - [Test] procedure TestSellerDescription; + [Test] + procedure TestSellerContact; end; implementation @@ -1245,6 +1243,45 @@ procedure TZUGFeRD22Tests.TestOrderInformation; // end; +procedure TZUGFeRD22Tests.TestSellerContact; +begin +// InvoiceDescriptor invoice = InvoiceProvider.CreateInvoice(); +// +// string description = "Test description"; +// +// invoice.SetSeller(name: "Lieferant GmbH", +// postcode: "80333", +// city: "München", +// street: "Lieferantenstraße 20", +// country: CountryCodes.DE, +// id: "", +// globalID: new GlobalID(GlobalIDSchemeIdentifiers.GLN, "4000001123452"), +// legalOrganization: new LegalOrganization(GlobalIDSchemeIdentifiers.GLN, "4000001123452", "Lieferant GmbH"), +// description: description +// ); +// +// string SELLER_CONTACT = "1-123"; +// string ORG_UNIT = "2-123"; +// string EMAIL_ADDRESS = "3-123"; +// string PHONE_NO = "4-123"; +// string FAX_NO = "5-123"; +// invoice.SetSellerContact(SELLER_CONTACT, ORG_UNIT, EMAIL_ADDRESS, PHONE_NO, FAX_NO); +// +// MemoryStream ms = new MemoryStream(); +// invoice.Save(ms, ZUGFeRDVersion.Version22, Profile.Extended); +// ms.Position = 0; +// +// InvoiceDescriptor loadedInvoice = InvoiceDescriptor.Load(ms); +// +// Assert.AreEqual(SELLER_CONTACT, loadedInvoice.SellerContact.Name); +// Assert.AreEqual(ORG_UNIT, loadedInvoice.SellerContact.OrgUnit); +// Assert.AreEqual(EMAIL_ADDRESS, loadedInvoice.SellerContact.EmailAddress); +// Assert.AreEqual(PHONE_NO, loadedInvoice.SellerContact.PhoneNo); +// Assert.AreEqual(FAX_NO, loadedInvoice.SellerContact.FaxNo); +// +// Assert.AreEqual(loadedInvoice.Seller.Description, description); +end; + procedure TZUGFeRD22Tests.TestSellerDescription; begin // InvoiceDescriptor invoice = InvoiceProvider.CreateInvoice(); @@ -1785,54 +1822,6 @@ procedure TZUGFeRD22Tests.TestTradeAllowanceChargeWithoutExplicitPercentage; // Assert.AreEqual(allowanceCharges[0].ChargePercentage, null); end; -procedure TZUGFeRD22Tests.TestUBLInvoiceCreation; -begin -// InvoiceDescriptor desc = this.InvoiceProvider.CreateInvoice(); -// MemoryStream ms = new MemoryStream(); -// -// desc.Save(ms, ZUGFeRDVersion.Version22,Profile.XRechnung,ZUGFeRDFormats.UBL); -// ms.Seek(0, SeekOrigin.Begin); -// -// InvoiceDescriptor loadedInvoice = InvoiceDescriptor.Load(ms); -// -// Assert.AreEqual(loadedInvoice.Invoicee, null); -// Assert.AreNotEqual(loadedInvoice.Seller, null); -// Assert.AreEqual(loadedInvoice.Taxes.Count, 2); -// Assert.AreEqual(loadedInvoice.SellerContact.Name, "Max Mustermann"); -// Assert.IsNull(loadedInvoice.BuyerContact); -end; - -procedure TZUGFeRD22Tests.TestUBLTradelineitemProductCharacterstics; -begin -// InvoiceDescriptor desc = this.InvoiceProvider.CreateInvoice(); -// -// desc.TradeLineItems[0].ApplicableProductCharacteristics = new ApplicableProductCharacteristic[] -// { -// new ApplicableProductCharacteristic() -// { -// Description = "Test Description", -// Value = "1.5 kg" -// }, -// new ApplicableProductCharacteristic() -// { -// Description = "UBL Characterstics 2", -// Value = "3 kg" -// }, -// }.ToList(); -// -// MemoryStream ms = new MemoryStream(); -// -// desc.Save(ms, ZUGFeRDVersion.Version22, Profile.XRechnung, ZUGFeRDFormats.UBL); -// ms.Seek(0, SeekOrigin.Begin); -// -// InvoiceDescriptor loadedInvoice = InvoiceDescriptor.Load(ms); -// -// Assert.IsNotNull(loadedInvoice.TradeLineItems); -// Assert.AreEqual(loadedInvoice.TradeLineItems[0].ApplicableProductCharacteristics.Count, 2); -// Assert.AreEqual(loadedInvoice.TradeLineItems[0].ApplicableProductCharacteristics[0].Description, "Test Description"); -// Assert.AreEqual(loadedInvoice.TradeLineItems[0].ApplicableProductCharacteristics[1].Value, "3 kg"); -end; - // !TestTradeAllowanceChargeWithoutExplicitPercentage() procedure TZUGFeRD22Tests.TestTradeAllowanceChargeWithExplicitPercentage; diff --git a/intf.ZUGFeRDInvoiceDescriptor20Reader.pas b/intf.ZUGFeRDInvoiceDescriptor20Reader.pas index ce84584..03ccc5b 100644 --- a/intf.ZUGFeRDInvoiceDescriptor20Reader.pas +++ b/intf.ZUGFeRDInvoiceDescriptor20Reader.pas @@ -231,6 +231,7 @@ function TZUGFeRDInvoiceDescriptor20Reader.Load(xmldocument : IXMLDocument): TZU Result.PaymentReference := _nodeAsString(doc.DocumentElement, '//ram:ApplicableHeaderTradeSettlement/ram:PaymentReference'); Result.Currency := TZUGFeRDCurrencyCodesExtensions.FromString(_nodeAsString(doc.DocumentElement, '//ram:ApplicableHeaderTradeSettlement/ram:InvoiceCurrencyCode')); + Result.SellerReferenceNo := _nodeAsString(doc.DocumentElement, '//ram:ApplicableHeaderTradeSettlement/ram:InvoiceIssuerReference'); // TODO: Multiple SpecifiedTradeSettlementPaymentMeans can exist for each account/institution (with different SEPA?) var _tempPaymentMeans : TZUGFeRDPaymentMeans := TZUGFeRDPaymentMeans.Create; diff --git a/intf.ZUGFeRDInvoiceDescriptor22CIIReader.pas b/intf.ZUGFeRDInvoiceDescriptor22CIIReader.pas index 14c596e..bc2f6df 100644 --- a/intf.ZUGFeRDInvoiceDescriptor22CIIReader.pas +++ b/intf.ZUGFeRDInvoiceDescriptor22CIIReader.pas @@ -321,7 +321,11 @@ function TZUGFeRDInvoiceDescriptor22CIIReader.Load(xmldocument : IXMLDocument): Result.PaymentReference := _nodeAsString(doc.DocumentElement, '//ram:ApplicableHeaderTradeSettlement/ram:PaymentReference'); Result.Currency := TZUGFeRDCurrencyCodesExtensions.FromString(_nodeAsString(doc.DocumentElement, '//ram:ApplicableHeaderTradeSettlement/ram:InvoiceCurrencyCode')); - Result.TaxCurrency := TZUGFeRDCurrencyCodesExtensions.FromString(_nodeAsString(doc.DocumentElement, '//ram:ApplicableHeaderTradeSettlement/ram:TaxCurrencyCode')); // BT-6 + Result.SellerReferenceNo := _nodeAsString(doc.DocumentElement, '//ram:ApplicableHeaderTradeSettlement/ram:InvoiceIssuerReference'); + + var optionalTaxCurrency : TZUGFeRDCurrencyCodes := TZUGFeRDCurrencyCodesExtensions.FromString(_nodeAsString(doc.DocumentElement, '//ram:ApplicableHeaderTradeSettlement/ram:TaxCurrencyCode')); // BT-6 + if (optionalTaxCurrency <> TZUGFeRDCurrencyCodes.Unknown) then + Result.TaxCurrency := optionalTaxCurrency; // TODO: Multiple SpecifiedTradeSettlementPaymentMeans can exist for each account/institution (with different SEPA?) var _tempPaymentMeans : TZUGFeRDPaymentMeans := TZUGFeRDPaymentMeans.Create; diff --git a/intf.ZUGFeRDInvoiceDescriptor22CIIWriter.pas b/intf.ZUGFeRDInvoiceDescriptor22CIIWriter.pas index fdf5dd3..9b3caec 100644 --- a/intf.ZUGFeRDInvoiceDescriptor22CIIWriter.pas +++ b/intf.ZUGFeRDInvoiceDescriptor22CIIWriter.pas @@ -281,7 +281,7 @@ procedure TZUGFeRDInvoiceDescriptor22CIIWriter.Save( //#region IssuerAssignedID //Bestellnummer - Writer.WriteOptionalElementString('ram:IssuerAssignedID', tradeLineItem.BuyerOrderReferencedDocument.ID); + Writer.WriteOptionalElementString('ram:IssuerAssignedID', tradeLineItem.BuyerOrderReferencedDocument.ID,[TZUGFeRDProfile.Extended]); //#endregion //#region LineID @@ -292,7 +292,7 @@ procedure TZUGFeRDInvoiceDescriptor22CIIWriter.Save( //#region IssueDateTime if (tradeLineItem.BuyerOrderReferencedDocument.IssueDateTime.HasValue) then begin - Writer.WriteStartElement('ram:FormattedIssueDateTime'); + Writer.WriteStartElement('ram:FormattedIssueDateTime',[TZUGFeRDProfile.Extended]); Writer.WriteStartElement('qdt:DateTimeString'); Writer.WriteAttributeString('format', '102'); Writer.WriteValue(_formatDate(tradeLineItem.BuyerOrderReferencedDocument.IssueDateTime.Value));