diff --git a/ZUGFeRD-Test/XRechnungUBLTests.cs b/ZUGFeRD-Test/XRechnungUBLTests.cs
index 9d5b14b..9f18623 100644
--- a/ZUGFeRD-Test/XRechnungUBLTests.cs
+++ b/ZUGFeRD-Test/XRechnungUBLTests.cs
@@ -184,8 +184,10 @@ public void TestInvoiceWithAttachment()
}
} // !TestInvoiceWithAttachment()
+
+
[TestMethod]
- public void TestActualDeliveryDate()
+ public void TestActualDeliveryDateWithoutDeliveryAddress()
{
DateTime timestamp = new DateTime(2024,08,11);
InvoiceDescriptor desc = this.InvoiceProvider.CreateInvoice();
@@ -200,7 +202,87 @@ public void TestActualDeliveryDate()
// test the ActualDeliveryDate
Assert.AreEqual(timestamp, loadedInvoice.ActualDeliveryDate);
- } // !TestActualDeliveryDate()
+ Assert.IsNull(loadedInvoice.ShipTo);
+ } // !TestActualDeliveryDateWithoutDeliveryAddress()
+
+
+
+ [TestMethod]
+ public void TestActualDeliveryDateWithDeliveryAddress()
+ {
+ DateTime timestamp = new DateTime(2024, 08, 11);
+ InvoiceDescriptor desc = this.InvoiceProvider.CreateInvoice();
+ MemoryStream ms = new MemoryStream();
+
+ desc.ActualDeliveryDate = timestamp;
+
+ string shipToID = "1234";
+ string shipToName = "Test ShipTo Name";
+ CountryCodes shipToCountry = CountryCodes.DE;
+
+ desc.ShipTo = new Party()
+ {
+ ID = new GlobalID()
+ {
+ ID = shipToID
+ },
+ Name = shipToName,
+ Country = shipToCountry
+ };
+
+ desc.Save(ms, ZUGFeRDVersion.Version23, Profile.XRechnung, ZUGFeRDFormats.UBL);
+ ms.Seek(0, SeekOrigin.Begin);
+
+ InvoiceDescriptor loadedInvoice = InvoiceDescriptor.Load(ms);
+
+ // test the ActualDeliveryDate
+ Assert.AreEqual(timestamp, loadedInvoice.ActualDeliveryDate);
+ Assert.IsNotNull(loadedInvoice.ShipTo);
+ Assert.IsNotNull(loadedInvoice.ShipTo.ID);
+ Assert.AreEqual(loadedInvoice.ShipTo.ID.ID, shipToID);
+ Assert.AreEqual(loadedInvoice.ShipTo.Name, shipToName);
+ Assert.AreEqual(loadedInvoice.ShipTo.Country, shipToCountry);
+ } // !TestActualDeliveryDateWithDeliveryAddress()
+
+
+
+ [TestMethod]
+ public void TestActualDeliveryAddressWithoutDeliveryDate()
+ {
+ InvoiceDescriptor desc = this.InvoiceProvider.CreateInvoice();
+ MemoryStream ms = new MemoryStream();
+
+ // ActualDeliveryDate is set by the InvoiceProvider, we are resetting it to the default value
+ desc.ActualDeliveryDate = null;
+
+ string shipToID = "1234";
+ string shipToName = "Test ShipTo Name";
+ CountryCodes shipToCountry = CountryCodes.DE;
+
+ desc.ShipTo = new Party()
+ {
+ ID = new GlobalID()
+ {
+ ID = shipToID
+ },
+ Name = shipToName,
+ Country = shipToCountry
+ };
+
+ desc.Save(ms, ZUGFeRDVersion.Version23, Profile.XRechnung, ZUGFeRDFormats.UBL);
+ ms.Seek(0, SeekOrigin.Begin);
+
+ InvoiceDescriptor loadedInvoice = InvoiceDescriptor.Load(ms);
+
+ // test the ActualDeliveryDate
+ Assert.IsNull(loadedInvoice.ActualDeliveryDate);
+ Assert.IsNotNull(loadedInvoice.ShipTo);
+ Assert.IsNotNull(loadedInvoice.ShipTo.ID);
+ Assert.AreEqual(loadedInvoice.ShipTo.ID.ID, shipToID);
+ Assert.AreEqual(loadedInvoice.ShipTo.Name, shipToName);
+ Assert.AreEqual(loadedInvoice.ShipTo.Country, shipToCountry);
+ } // !TestActualDeliveryAddressWithoutDeliveryDate()
+
[TestMethod]
public void TestTaxTypes()
diff --git a/ZUGFeRD/InvoiceDescriptor.cs b/ZUGFeRD/InvoiceDescriptor.cs
index 1d9705b..a888f40 100644
--- a/ZUGFeRD/InvoiceDescriptor.cs
+++ b/ZUGFeRD/InvoiceDescriptor.cs
@@ -118,6 +118,7 @@ public class InvoiceDescriptor
///
/// Information about the buyer
+ /// BG-7
///
public Party Buyer { get; set; }
@@ -128,10 +129,24 @@ public class InvoiceDescriptor
///
public Contact BuyerContact { get; set; }
public List BuyerTaxRegistration { get; set; } = new List();
+
+ ///
+ /// Buyer electronic address
+ /// BT-49
+ ///
public ElectronicAddress BuyerElectronicAddress { get; set; }
+
+ ///
+ /// BG-4
+ ///
public Party Seller { get; set; }
public Contact SellerContact { get; set; }
public List SellerTaxRegistration { get; set; } = new List();
+
+ ///
+ /// Seller electronic address
+ /// BT-34
+ ///
public ElectronicAddress SellerElectronicAddress { get; set; }
///
diff --git a/ZUGFeRD/InvoiceDescriptor22UBLWriter.cs b/ZUGFeRD/InvoiceDescriptor22UBLWriter.cs
index 824e9a6..2a69b64 100644
--- a/ZUGFeRD/InvoiceDescriptor22UBLWriter.cs
+++ b/ZUGFeRD/InvoiceDescriptor22UBLWriter.cs
@@ -194,15 +194,66 @@ public override void Save(InvoiceDescriptor descriptor, Stream stream, ZUGFeRDFo
#region SellerTradeParty
- //AccountingSupplierParty
+
+ // AccountingSupplierParty = PartyTypes.SellerTradeParty
_writeOptionalParty(Writer, PartyTypes.SellerTradeParty, this.Descriptor.Seller, this.Descriptor.SellerContact, this.Descriptor.SellerElectronicAddress, this.Descriptor.SellerTaxRegistration);
#endregion
#region BuyerTradeParty
- //AccountingCustomerParty
+ //AccountingCustomerParty = PartyTypes.BuyerTradeParty
_writeOptionalParty(Writer, PartyTypes.BuyerTradeParty, this.Descriptor.Buyer, this.Descriptor.BuyerContact, this.Descriptor.BuyerElectronicAddress, this.Descriptor.BuyerTaxRegistration);
#endregion
-
+
+
+ // Deliery = ShipToTradeParty
+ if ((this.Descriptor.ShipTo != null) || (this.Descriptor.ActualDeliveryDate.HasValue))
+ {
+ Writer.WriteStartElement("cac", "Delivery");
+
+ if (this.Descriptor.ActualDeliveryDate.HasValue)
+ {
+ Writer.WriteStartElement("cbc", "ActualDeliveryDate");
+ Writer.WriteValue(_formatDate(this.Descriptor.ActualDeliveryDate.Value, false, true));
+ Writer.WriteEndElement(); // !ActualDeliveryDate
+ }
+
+ if (this.Descriptor.ShipTo != null)
+ {
+ Writer.WriteStartElement("cac", "DeliveryLocation");
+
+ if (this.Descriptor.ShipTo.ID != null) // despite this is a mandatory field, the component should not throw an exception if this is not the case
+ {
+ Writer.WriteOptionalElementString("cbc", "ID", this.Descriptor.ShipTo.ID.ID);
+ }
+ Writer.WriteStartElement("cac", "Address");
+ Writer.WriteOptionalElementString("cbc", "StreetName", this.Descriptor.ShipTo.Street);
+ Writer.WriteOptionalElementString("cbc", "AdditionalStreetName", this.Descriptor.ShipTo.AddressLine3);
+ Writer.WriteOptionalElementString("cbc", "CityName", this.Descriptor.ShipTo.City);
+ Writer.WriteOptionalElementString("cbc", "PostalZone", this.Descriptor.ShipTo.Postcode);
+ Writer.WriteOptionalElementString("cbc", "CountrySubentity", this.Descriptor.ShipTo.CountrySubdivisionName);
+ Writer.WriteStartElement("cac", "Country");
+ if (this.Descriptor.ShipTo.Country != CountryCodes.Unknown)
+ {
+ Writer.WriteElementString("cbc", "IdentificationCode", this.Descriptor.ShipTo.Country.ToString());
+ }
+ Writer.WriteEndElement(); //!Country
+ Writer.WriteEndElement(); // !Address
+ Writer.WriteEndElement(); // !DeliveryLocation
+
+ if (!string.IsNullOrWhiteSpace(this.Descriptor.ShipTo.Name))
+ {
+ Writer.WriteStartElement("cac", "DeliveryParty");
+ Writer.WriteStartElement("cac", "PartyName");
+ Writer.WriteStartElement("cbc", "Name");
+ Writer.WriteValue(this.Descriptor.ShipTo.Name);
+ Writer.WriteEndElement(); // !Name
+ Writer.WriteEndElement(); // !PartyName
+ Writer.WriteEndElement(); // !DeliveryParty
+ }
+ }
+ }
+
+
#region AllowanceCharge
foreach (TradeAllowanceCharge tradeAllowanceCharge in descriptor.GetTradeAllowanceCharges())
{
@@ -243,16 +294,7 @@ public override void Save(InvoiceDescriptor descriptor, Stream stream, ZUGFeRDFo
Writer.WriteEndElement(); // !AllowanceCharge()
}
- #endregion
-
- if (this.Descriptor.ActualDeliveryDate.HasValue)
- {
- Writer.WriteStartElement("cac", "Delivery");
- Writer.WriteStartElement("cbc", "ActualDeliveryDate");
- Writer.WriteValue(_formatDate(this.Descriptor.ActualDeliveryDate.Value, false, true));
- Writer.WriteEndElement(); // !ActualDeliveryDate
- Writer.WriteEndElement(); // !Delivery
- }
+ #endregion
// PaymentMeans
if (this.Descriptor.PaymentMeans != null)
@@ -546,39 +588,8 @@ private void _writeOptionalParty(ProfileAwareXmlTextWriter writer, PartyTypes pa
break;
case PartyTypes.ShipFromTradeParty:
return;
- //case PartyTypes.ShipToTradeParty:
- // if ((this.Descriptor.Profile != Profile.Extended) && (this.Descriptor.Profile != Profile.XRechnung1) && (this.Descriptor.Profile != Profile.XRechnung)) { return; } // extended, XRechnung1, XRechnung profile only
- // break;
- //case PartyTypes.UltimateShipToTradeParty:
- // if ((this.Descriptor.Profile != Profile.Extended) && (this.Descriptor.Profile != Profile.XRechnung1) && (this.Descriptor.Profile != Profile.XRechnung)) { return; } // extended, XRechnung1, XRechnung profile only
- // break;
- //case PartyTypes.ShipFromTradeParty:
- // if ((this.Descriptor.Profile != Profile.Extended) && (this.Descriptor.Profile != Profile.XRechnung1) && (this.Descriptor.Profile != Profile.XRechnung)) { return; } // extended, XRechnung1, XRechnung profile only
- // break;
- //case PartyTypes.InvoiceeTradeParty:
- // if ((this.Descriptor.Profile != Profile.Extended) && (this.Descriptor.Profile != Profile.XRechnung1) && (this.Descriptor.Profile != Profile.XRechnung)) { return; } // extended, XRechnung1, XRechnung profile only
- // break;
- //case PartyTypes.PayeeTradeParty:
- // if (this.Descriptor.Profile == Profile.Minimum) { return; } // party is written for all profiles but minimum
- // break;
- //case PartyTypes.SalesAgentTradeParty:
- // if ((this.Descriptor.Profile != Profile.Extended) && (this.Descriptor.Profile != Profile.XRechnung1) && (this.Descriptor.Profile != Profile.XRechnung)) { return; } // extended, XRechnung1, XRechnung profile only
- // break;
- //case PartyTypes.BuyerTaxRepresentativeTradeParty:
- // if ((this.Descriptor.Profile != Profile.Extended) && (this.Descriptor.Profile != Profile.XRechnung1) && (this.Descriptor.Profile != Profile.XRechnung)) { return; } // extended, XRechnung1, XRechnung profile only
- // break;
- //case PartyTypes.ProductEndUserTradeParty:
- // if ((this.Descriptor.Profile != Profile.Extended) && (this.Descriptor.Profile != Profile.XRechnung1) && (this.Descriptor.Profile != Profile.XRechnung)) { return; } // extended, XRechnung1, XRechnung profile only
- // break;
- //case PartyTypes.BuyerAgentTradeParty:
- // if ((this.Descriptor.Profile != Profile.Extended) && (this.Descriptor.Profile != Profile.XRechnung1) && (this.Descriptor.Profile != Profile.XRechnung)) { return; } // extended, XRechnung1, XRechnung profile only
- // break;
- //case PartyTypes.InvoicerTradeParty:
- // if ((this.Descriptor.Profile != Profile.Extended) && (this.Descriptor.Profile != Profile.XRechnung1) && (this.Descriptor.Profile != Profile.XRechnung)) { return; } // extended, XRechnung1, XRechnung profile only
- // break;
- //case PartyTypes.PayerTradeParty:
- // if ((this.Descriptor.Profile != Profile.Extended) && (this.Descriptor.Profile != Profile.XRechnung1) && (this.Descriptor.Profile != Profile.XRechnung)) { return; } // extended, XRechnung1, XRechnung profile only
- // break;
+ case PartyTypes.ShipToTradeParty: // ship to trade party/ cac:Delivery has very minimized information, thus generic _writeOptionalParty() cannot be used
+ return;
default:
return;
}
diff --git a/ZUGFeRD/InvoiceDescriptor23CIIWriter.cs b/ZUGFeRD/InvoiceDescriptor23CIIWriter.cs
index 8de3947..effd905 100644
--- a/ZUGFeRD/InvoiceDescriptor23CIIWriter.cs
+++ b/ZUGFeRD/InvoiceDescriptor23CIIWriter.cs
@@ -1414,7 +1414,7 @@ private void _writeOptionalLegalOrganization(ProfileAwareXmlTextWriter writer, s
} // !_writeOptionalLegalOrganization()
- private void _writeOptionalParty(ProfileAwareXmlTextWriter writer, PartyTypes partyType, Party party, Profile profile, Contact contact = null, ElectronicAddress ElectronicAddress = null, List taxRegistrations = null)
+ private void _writeOptionalParty(ProfileAwareXmlTextWriter writer, PartyTypes partyType, Party party, Profile profile, Contact contact = null, ElectronicAddress electronicAddress = null, List taxRegistrations = null)
{
if (party == null)
{
@@ -1512,14 +1512,14 @@ private void _writeOptionalParty(ProfileAwareXmlTextWriter writer, PartyTypes pa
writer.WriteEndElement(); // !PostalTradeAddress
}
- if (ElectronicAddress != null)
+ if (electronicAddress != null)
{
- if (!String.IsNullOrWhiteSpace(ElectronicAddress.Address))
+ if (!String.IsNullOrWhiteSpace(electronicAddress.Address))
{
writer.WriteStartElement("ram", "URIUniversalCommunication");
writer.WriteStartElement("ram", "URIID");
- writer.WriteAttributeString("schemeID", ElectronicAddress.ElectronicAddressSchemeID.EnumToString());
- writer.WriteValue(ElectronicAddress.Address);
+ writer.WriteAttributeString("schemeID", electronicAddress.ElectronicAddressSchemeID.EnumToString());
+ writer.WriteValue(electronicAddress.Address);
writer.WriteEndElement();
writer.WriteEndElement();
}