diff --git a/drafthorse/models/accounting.py b/drafthorse/models/accounting.py
index 421a6f3..fef9af6 100644
--- a/drafthorse/models/accounting.py
+++ b/drafthorse/models/accounting.py
@@ -3,6 +3,7 @@
from .elements import Element
from .fields import (
CurrencyField,
+ DateField,
DateTimeField,
DecimalField,
IndicatorField,
@@ -78,7 +79,7 @@ class ApplicableTradeTax(Element):
profile=BASIC,
_d="Grund der Steuerbefreiung (Code)",
)
- tax_point_date = DateTimeField(
+ tax_point_date = DateField(
NS_RAM, "TaxPointDate", required=False, profile=COMFORT
)
due_date_type_code = StringField(
diff --git a/drafthorse/models/elements.py b/drafthorse/models/elements.py
index 31a0e3d..1d0cf54 100644
--- a/drafthorse/models/elements.py
+++ b/drafthorse/models/elements.py
@@ -399,6 +399,62 @@ def __str__(self):
return "{}".format(self._value)
+class DateElement(StringElement):
+ def __init__(
+ self, namespace, tag, value=None, format="102", date_namespace=NS_UDT
+ ):
+ super().__init__(namespace, tag)
+ self._value = value
+ self._format = format
+ self._date_namespace = date_namespace
+
+ def to_etree(self):
+ t = self._etree_node()
+ node = ET.Element("{%s}%s" % (self._date_namespace, "DateString"))
+ if self._value:
+ if self._format == "102":
+ node.text = self._value.strftime("%Y%m%d")
+ elif self._format == "616":
+ if sys.version_info < (3, 6):
+ node.text = "{}{}".format(
+ self._value.isocalendar()[0], self._value.isocalendar()[1]
+ )
+ else:
+ node.text = self._value.strftime("%G%V")
+ node.attrib["format"] = self._format
+ t.append(node)
+ return t
+
+ def from_etree(self, root, strict=True):
+ if len(root) != 1:
+ raise TypeError("Date containers should have one child")
+ if root[0].tag != "{%s}%s" % (self._date_namespace, "DateString"):
+ if strict:
+ raise TypeError("Tag %s not recognized" % root[0].tag)
+ else:
+ return self
+ self._format = root[0].attrib["format"]
+ if self._format == "102":
+ self._value = datetime.strptime(root[0].text, "%Y%m%d").date()
+ elif self._format == "616":
+ if sys.version_info < (3, 6):
+ from isoweek import Week
+
+ w = Week(int(root[0].text[:4]), int(root[0].text[4:]))
+ self._value = w.monday()
+ else:
+ self._value = datetime.strptime(root[0].text + "1", "%G%V%u").date()
+ elif strict:
+ raise TypeError(
+ "Date format %s cannot be parsed" % root[0].attrib["format"]
+ )
+ self._set_on_input = True
+ return self
+
+ def __str__(self):
+ return "{}".format(self._value)
+
+
class IndicatorElement(StringElement):
def __init__(self, namespace, tag, value=None):
super().__init__(namespace, tag)
diff --git a/drafthorse/models/fields.py b/drafthorse/models/fields.py
index 6c68c9c..3228ba6 100644
--- a/drafthorse/models/fields.py
+++ b/drafthorse/models/fields.py
@@ -292,6 +292,35 @@ def initialize(self):
return self.cls(self.namespace, self.tag)
+class DateField(Field):
+ def __init__(
+ self,
+ namespace,
+ tag,
+ default=False,
+ required=False,
+ profile=BASIC,
+ _d=None,
+ date_namespace=NS_UDT,
+ ):
+ from .elements import DateElement
+
+ super().__init__(DateElement, default, required, profile, _d)
+ self.namespace = namespace
+ self.tag = tag
+ self._date_namespace = date_namespace
+
+ def __set__(self, instance, value):
+ if instance._data.get(self.name, None) is None:
+ instance._data[self.name] = self.initialize()
+ instance._data[self.name]._value = value
+
+ def initialize(self):
+ return self.cls(
+ self.namespace, self.tag, date_namespace=self._date_namespace
+ )
+
+
class MultiField(Field):
def __init__(
self, inner_type, default=False, required=False, profile=BASIC, _d=None
diff --git a/tests/samples/zugferd_2p1_EN16931_Einfach_TaxPointDate.xml b/tests/samples/zugferd_2p1_EN16931_Einfach_TaxPointDate.xml
new file mode 100644
index 0000000..97edd82
--- /dev/null
+++ b/tests/samples/zugferd_2p1_EN16931_Einfach_TaxPointDate.xml
@@ -0,0 +1,247 @@
+
+
+
+
+
+
+
+
+
+ urn:cen.eu:en16931:2017
+
+
+
+ 471102
+ 380
+
+ 20180305
+
+
+ Rechnung gemäß Bestellung vom 01.03.2018.
+
+
+ Lieferant GmbH
+Lieferantenstraße 20
+80333 München
+Deutschland
+Geschäftsführer: Hans Muster
+Handelsregisternummer: H A 123
+
+ REG
+
+
+
+
+
+ 1
+
+
+ 4012345001235
+ TB100A4
+ Trennblätter A4
+
+
+
+ 9.9000
+
+
+ 9.9000
+
+
+
+ 20.0000
+
+
+
+ VAT
+ S
+ 19.00
+
+
+ 198.00
+
+
+
+
+
+ 2
+
+
+ 4000050986428
+ ARNR2
+ Joghurt Banane
+
+
+
+ 5.5000
+
+
+ 5.5000
+
+
+
+ 50.0000
+
+
+
+ VAT
+ S
+ 7.00
+
+
+ 275.00
+
+
+
+
+
+ 549910
+ 4000001123452
+ Lieferant GmbH
+
+ 80333
+ Lieferantenstraße 20
+ München
+ DE
+
+
+ 201/113/40209
+
+
+ DE123456789
+
+
+
+ GE2020211
+ Kunden AG Mitte
+
+ 69876
+ Kundenstraße 15
+ Frankfurt
+ DE
+
+
+
+
+
+
+ 20180305
+
+
+
+
+ EUR
+
+ 19.25
+ VAT
+ 275.00
+ S
+
+ 20180305
+
+ 7.00
+
+
+ 37.62
+ VAT
+ 198.00
+ S
+ 19.00
+
+
+ Zahlbar innerhalb 30 Tagen netto bis 04.04.2018, 3% Skonto innerhalb 10 Tagen bis 15.03.2018
+
+
+ 473.00
+ 0.00
+ 0.00
+ 473.00
+ 56.87
+ 529.87
+ 0.00
+ 529.87
+
+
+
+
\ No newline at end of file
diff --git a/tests/samples/zugferd_2p3_EN16931_Einfach_TaxPointDate.xml b/tests/samples/zugferd_2p3_EN16931_Einfach_TaxPointDate.xml
new file mode 100644
index 0000000..7c47a17
--- /dev/null
+++ b/tests/samples/zugferd_2p3_EN16931_Einfach_TaxPointDate.xml
@@ -0,0 +1,247 @@
+
+
+
+
+
+
+
+
+
+ urn:cen.eu:en16931:2017
+
+
+
+ 471102
+ 380
+
+ 20241115
+
+
+ Rechnung gemäß Bestellung vom 01.11.2024.
+
+
+ Lieferant GmbH
+Lieferantenstraße 20
+80333 München
+Deutschland
+Geschäftsführer: Hans Muster
+Handelsregisternummer: H A 123
+
+ REG
+
+
+
+
+
+ 1
+
+
+ 4012345001235
+ TB100A4
+ Trennblätter A4
+
+
+
+ 9.9000
+
+
+ 9.9000
+
+
+
+ 20.0000
+
+
+
+ VAT
+ S
+ 19.00
+
+
+ 198.00
+
+
+
+
+
+ 2
+
+
+ 4000050986428
+ ARNR2
+ Joghurt Banane
+
+
+
+ 5.5000
+
+
+ 5.5000
+
+
+
+ 50.0000
+
+
+
+ VAT
+ S
+ 7.00
+
+
+ 275.00
+
+
+
+
+
+ 549910
+ 4000001123452
+ Lieferant GmbH
+
+ 80333
+ Lieferantenstraße 20
+ München
+ DE
+
+
+ 201/113/40209
+
+
+ DE123456789
+
+
+
+ GE2020211
+ Kunden AG Mitte
+
+ 69876
+ Kundenstraße 15
+ Frankfurt
+ DE
+
+
+
+
+
+
+ 20241114
+
+
+
+
+ EUR
+
+ 19.25
+ VAT
+ 275.00
+ S
+
+ 20241114
+
+ 7.00
+
+
+ 37.62
+ VAT
+ 198.00
+ S
+ 19.00
+
+
+ Zahlbar innerhalb 30 Tagen netto bis 15.12.2024, 3% Skonto innerhalb 10 Tagen bis 25.11.2024
+
+
+ 473.00
+ 0.00
+ 0.00
+ 473.00
+ 56.87
+ 529.87
+ 0.00
+ 529.87
+
+
+
+
\ No newline at end of file