]> git.ipfire.org Git - thirdparty/python-drafthorse.git/commitdiff
Add all models
authorRaphael Michel <mail@raphaelmichel.de>
Mon, 15 Oct 2018 18:22:12 +0000 (20:22 +0200)
committerRaphael Michel <mail@raphaelmichel.de>
Mon, 15 Oct 2018 18:22:12 +0000 (20:22 +0200)
14 files changed:
demo.py
drafthorse/models/__init__.py
drafthorse/models/accounting.py [new file with mode: 0644]
drafthorse/models/delivery.py [new file with mode: 0644]
drafthorse/models/document.py
drafthorse/models/elements.py
drafthorse/models/fields.py
drafthorse/models/note.py
drafthorse/models/party.py [new file with mode: 0644]
drafthorse/models/payment.py [new file with mode: 0644]
drafthorse/models/product.py [new file with mode: 0644]
drafthorse/models/references.py [new file with mode: 0644]
drafthorse/models/trade.py
drafthorse/models/tradelines.py [new file with mode: 0644]

diff --git a/demo.py b/demo.py
index 0c69a372ed23bba7acf5bf68f6034f23e9804032..44c172c97c7c8c5a4faf47fb9aef18b0055ddb25 100644 (file)
--- a/demo.py
+++ b/demo.py
@@ -4,7 +4,7 @@ from drafthorse.models.document import Document, IncludedNote
 from drafthorse.utils import prettify
 
 doc = Document()
-doc.context.parameter.id = "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort"
+doc.context.guideline_parameter.id = "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort"
 doc.header.id = "RE1337"
 doc.header.name = "RECHNUNG"
 doc.header.type_code = "380"
index 08f88e5ef7ff74371591244f174fae36428c38a1..e41f4345bc881c49033fd38befa56ef1dfd84c21 100644 (file)
@@ -1,3 +1,6 @@
 NS_FERD_1p0 = "urn:ferd:CrossIndustryDocument:invoice:1p0"
 NS_UDT = "urn:un:unece:uncefact:data:standard:UnqualifiedDataType:15"
 NS_RAM = "urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:12"
+BASIC = "BASIC"
+COMFORT = "COMFORT"
+EXTENDED = "EXTENDED"
diff --git a/drafthorse/models/accounting.py b/drafthorse/models/accounting.py
new file mode 100644 (file)
index 0000000..253941b
--- /dev/null
@@ -0,0 +1,110 @@
+from . import NS_FERD_1p0, COMFORT, EXTENDED, BASIC
+from .elements import Element
+from .fields import DateTimeField, StringField, CurrencyField, DecimalField, MultiField, IndicatorField
+
+
+class LineApplicableTradeTax(Element):
+    calculated_amount = CurrencyField(NS_FERD_1p0, "CalculatedAmount", required=True,
+                                      profile=BASIC, _d="Steuerbetrag")
+    type_code = StringField(NS_FERD_1p0, "TypeCode", required=True, profile=BASIC,
+                            _d="Steuerart (Code)")
+    exemption_reason = StringField(NS_FERD_1p0, "ExemptionReason", required=False,
+                                   profile=COMFORT, _d="Grund der Steuerbefreiung (Freitext)")
+    category_code = StringField(NS_FERD_1p0, "CategoryCode", required=False,
+                                profile=COMFORT, _d="Steuerkategorie (Wert)")
+    applicable_percent = DecimalField(NS_FERD_1p0, "ApplicablePercent",
+                                      required=True, profile=BASIC)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "ApplicableTradeTax"
+
+
+class ApplicableTradeTax(LineApplicableTradeTax):
+    basis_amount = CurrencyField(NS_FERD_1p0, "BasisAmount", required=True,
+                                 profile=BASIC, _d="Basisbetrag der Steuerberechnung")
+    line_total_basis_amount = CurrencyField(NS_FERD_1p0, "LineTotalBasisAmount",
+                                            required=False, profile=EXTENDED,
+                                            _d="Warenbetrag des Steuersatzes")
+    allowance_charge_basis_amount = CurrencyField(NS_FERD_1p0, "AllowanceChargeBasisAmount",
+                                                  required=False, profile=EXTENDED,
+                                                  _d="Gesamtbetrag Zu- und Abschläge des Steuersatzes")
+
+
+class AccountingAccount(Element):
+    id = StringField(NS_FERD_1p0, "ID", required=True, profile=EXTENDED, _d="Buchungsreferenz")
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "ReceivableSpecifiedTradeAccount"
+
+
+class MonetarySummation(Element):
+    line_total = CurrencyField(NS_FERD_1p0, "LineTotalAmount", required=True,
+                               profile=BASIC, _d="Gesamtbetrag der Positionen")
+    charge_total = CurrencyField(NS_FERD_1p0, "ChargeTotalAmount", required=True,
+                                 profile=BASIC, _d="Gesamtbetrag der Zuschläge")
+    allowance_total = CurrencyField(NS_FERD_1p0, "AllowanceTotalAmount", required=True,
+                                    profile=BASIC, _d="Gesamtbetrag der Abschläge")
+    tax_basis_total = CurrencyField(NS_FERD_1p0, "TaxBasisTotalAmount", required=True,
+                                    profile=BASIC, _d="Steuerbasisbetrag")
+    tax_total = CurrencyField(NS_FERD_1p0, "TaxTotalAmount", required=True,
+                              profile=BASIC, _d="Steuergesamtbetrag")
+    grand_total = CurrencyField(NS_FERD_1p0, "GrandTotalAmount", required=True,
+                                profile=BASIC, _d="Bruttosumme")
+    prepaid_total = CurrencyField(NS_FERD_1p0, "TotalPrepaidAmount", required=False,
+                                  profile=COMFORT, _d="Anzahlungsbetrag")
+    due_amount = CurrencyField(NS_FERD_1p0, "DuePayableAmount", required=False,
+                               profile=COMFORT, _d="Zahlbetrag")
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "SpecifiedTradeSettlementMonetarySummation"
+
+
+class BillingSpecifiedPeriod(Element):
+    start = DateTimeField(NS_FERD_1p0, "StartDateTime", required=True, profile=COMFORT)
+    end = DateTimeField(NS_FERD_1p0, "EndDateTime", required=True, profile=COMFORT)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "BillingSpecifiedPeriod"
+
+
+class AppliedTradeTax(Element):
+    type_code = StringField(NS_FERD_1p0, "TypeCode", required=True, profile=COMFORT)
+    category_code = StringField(NS_FERD_1p0, "CategoryCode", required=True, profile=COMFORT)
+    applicable_percent = StringField(NS_FERD_1p0, "ApplicablePercent", required=True, profile=COMFORT)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "AppliedTradeTax"
+
+
+class CategoryTradeTax(AppliedTradeTax):
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "CategoryTradeTax"
+
+
+class TradeAllowanceCharge(Element):
+    indicator = IndicatorField(NS_FERD_1p0, "ChargeIndicator", required=False, profile=COMFORT,
+                               _d="Schalter für Zu-/Abschlag")
+    sequence_numeric = DecimalField(NS_FERD_1p0, "SequenceNumeric", required=False, profile=EXTENDED,
+                                    _d="Berechnungsreihenfolge")
+    calculation_percent = DecimalField(NS_FERD_1p0, "CalculationPercent",
+                                       required=False, profile=EXTENDED,
+                                       _d="Rabatt in Prozent")
+    basis_amount = CurrencyField(NS_FERD_1p0, "BasisAmount", required=False,
+                                 profile=EXTENDED, _d="Basisbetrag des Rabatts")
+    basis_quantity = CurrencyField(NS_FERD_1p0, "BasisQuantity", required=False,
+                                   profile=EXTENDED, _d="Basismenge des Rabatts")
+    actual_amount = CurrencyField(NS_FERD_1p0, "ActualAmount", required=True,
+                                  profile=COMFORT, _d="Betrag des Zu-/Abschlags")
+    reason_code = StringField(NS_FERD_1p0, "ReasonCode", required=False, profile=EXTENDED)
+    reason = StringField(NS_FERD_1p0, "Reason", required=False, profile=COMFORT)
+    trade_tax = MultiField(CategoryTradeTax, required=False, profile=COMFORT)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "SpecifiedTradeAllowanceCharge"
diff --git a/drafthorse/models/delivery.py b/drafthorse/models/delivery.py
new file mode 100644 (file)
index 0000000..83d6214
--- /dev/null
@@ -0,0 +1,49 @@
+from . import NS_FERD_1p0, BASIC, EXTENDED
+from .elements import Element
+from .fields import DateTimeField, StringField, IDField, Field
+from .party import ShipToTradeParty, ShipFromTradeParty, UltimateShipToTradeParty
+from .references import DespatchAdviceReferencedDocument, DeliveryNoteReferencedDocument
+
+
+class SupplyChainEvent(Element):
+    occurrence = DateTimeField(NS_FERD_1p0, "OccurenceDateTime",
+                               required=False, profile=BASIC,
+                               _d="Tatsächlicher Lieferungszeitpunkt")
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "ActualDeliverySupplyChainEvent"
+
+
+class LogisticsTransportMovement(Element):
+    mode_code = StringField(NS_FERD_1p0, "ModeCode", required=False, profile=EXTENDED)
+    id = IDField(NS_FERD_1p0, "ID", required=False, profile=EXTENDED)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "SpecifiedLogisticsTransportMovement"
+
+
+class SupplyChainConsignment(Element):
+    movement = Field(LogisticsTransportMovement, required=False, profile=EXTENDED)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "RelatedSupplyChainConsignment"
+
+
+class TradeDelivery(Element):
+    consignment = Field(SupplyChainConsignment, default=False, required=False,
+                        _d="Detailinformationen zur Konsignation oder Sendung")
+    ship_to = Field(ShipToTradeParty, required=False, profile=EXTENDED)
+    ultimate_ship_to = Field(UltimateShipToTradeParty, required=False, profile=EXTENDED)
+    ship_from = Field(ShipFromTradeParty, required=False, profile=EXTENDED)
+    event = Field(SupplyChainEvent, required=False, profile=BASIC)
+    despatch_advice = Field(DespatchAdviceReferencedDocument, required=False,
+                            profile=EXTENDED)
+    delivery_note = Field(DeliveryNoteReferencedDocument, required=False,
+                          profile=EXTENDED)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "ApplicableSupplyChainTradeDelivery"
index 74cca532287c3dfb86846b2b7519f240b69858c2..a81fb664ec342a26b79563955301c92ed2f3ba59 100644 (file)
@@ -1,13 +1,13 @@
 import xml.etree.cElementTree as ET
 
 from drafthorse.models.note import IncludedNote
-from . import NS_RAM, NS_UDT, NS_FERD_1p0
+from . import NS_RAM, NS_UDT, NS_FERD_1p0, EXTENDED, BASIC
 from .elements import Element
-from .fields import DateTimeField, Field, MultiField, StringField
+from .fields import DateTimeField, Field, MultiField, StringField, IndicatorField
 from .trade import TradeTransaction
 
 
-class DocumentContextParameter(Element):
+class GuidelineDocumentContextParameter(Element):
     id = StringField(NS_FERD_1p0, "ID")
 
     class Meta:
@@ -15,21 +15,52 @@ class DocumentContextParameter(Element):
         tag = "GuidelineSpecifiedDocumentContextParameter"
 
 
+class BusinessDocumentContextParameter(Element):
+    id = StringField(NS_FERD_1p0, "ID")
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "BusinessSpecifiedDocumentContextParameter"
+
+
 class DocumentContext(Element):
-    parameter = Field(DocumentContextParameter)
+    test_indicator = IndicatorField(NS_FERD_1p0, "TestIndicator", required=False,
+                                    profile=BASIC, _d="Testkennzeichen")
+    guideline_parameter = Field(GuidelineDocumentContextParameter, required=True,
+                                profile=BASIC, _d="Anwendungsempfehlung")
+    business_parameter = Field(BusinessDocumentContextParameter, required=False,
+                               profile=EXTENDED, _d="Geschäftsprozess, Wert")
 
     class Meta:
         namespace = NS_FERD_1p0
         tag = "SpecifiedExchangedDocumentContext"
 
 
+class EffectivePeriod(Element):
+    complete = DateTimeField(NS_FERD_1p0, "CompleteDateTime")
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "EffectiveSpecifiedPeriod"
+
+
 class Header(Element):
-    id = StringField(NS_FERD_1p0, "ID")
-    name = StringField(NS_FERD_1p0, "Name")
-    type_code = StringField(NS_FERD_1p0, "TypeCode")
-    issue_date_time = DateTimeField(NS_FERD_1p0, "IssueDateTime")
+    id = StringField(NS_FERD_1p0, "ID", required=True, profile=BASIC,
+                     _d="Rechnungsnummer")
+    name = StringField(NS_FERD_1p0, "Name", required=True, profile=BASIC,
+                       _d="Dokumentenart (Freitext)")
+    type_code = StringField(NS_FERD_1p0, "TypeCode", required=True, profile=BASIC,
+                            _d="Dokumentenart (Code)")
+    issue_date_time = DateTimeField(NS_FERD_1p0, "IssueDateTime", required=True,
+                                    profile=BASIC, _d="Rechnungsdatum")
+    copy_indicator = IndicatorField(NS_FERD_1p0, "CopyIndicator", required=False,
+                                    profile=EXTENDED, _d="Indikator Original/Kopie")
+    effective_period = Field(EffectivePeriod, required=False, profile=EXTENDED,
+                             _d="Vertragliches Fälligkeitsdatum der Rechnung")
     notes = MultiField(IncludedNote)
 
+    # TODO: LanguageID
+
     class Meta:
         namespace = NS_FERD_1p0
         tag = "HeaderExchangedDocument"
@@ -37,8 +68,8 @@ class Header(Element):
 
 class Document(Element):
     context = Field(DocumentContext, required=True)
-    header = Field(Header)
-    trade = Field(TradeTransaction)
+    header = Field(Header, required=True)
+    trade = Field(TradeTransaction, required=True)
 
     def __init__(self):
         super().__init__()
index 588a0af220ade3c2593270a17068bef467b90efb..564986c6a5db004771dfb12812e5a18f401024a2 100644 (file)
@@ -101,9 +101,37 @@ class CurrencyElement(StringElement):
         return node
 
 
-class IDElement(Element):
-    def __init__(self, text="", scheme_id=""):
-        super().__init__()
+class ClassificationElement(StringElement):
+    def __init__(self, namespace, tag, text="", list_id="", list_version_id=""):
+        super().__init__(namespace, tag)
+        self.text = text
+        self.list_id = list_id
+        self.list_version_id = list_version_id
+
+    def to_etree(self):
+        node = self._etree_node()
+        node.text = self.text
+        node.attrib['listID'] = self.list_id
+        node.attrib['listVersionID'] = self.list_version_id
+        return node
+
+
+class AgencyIDElement(StringElement):
+    def __init__(self, namespace, tag, text="", scheme_id=""):
+        super().__init__(namespace, tag)
+        self.text = text
+        self.scheme_id = scheme_id
+
+    def to_etree(self):
+        node = self._etree_node()
+        node.text = self.text
+        node.attrib['schemeAgencyID'] = self.scheme_id
+        return node
+
+
+class IDElement(StringElement):
+    def __init__(self, namespace, tag, text="", scheme_id=""):
+        super().__init__(namespace, tag)
         self.text = text
         self.scheme_id = scheme_id
 
index 7d974aa652410cff537ec5b182981c9b98d20920..32c45becf750b59bffcd2c8a80258b4ca8aced40 100644 (file)
@@ -1,9 +1,13 @@
+from . import BASIC
+
+
 class Field:
-    def __init__(self, cls, default=False, required=False, _d=None):
+    def __init__(self, cls, default=False, required=False, profile=BASIC, _d=None):
         self.cls = cls
         self.required = required
         self.default = default
         self.__doc__ = _d
+        self.profile = profile
         super().__init__()
 
     def initialize(self):
@@ -25,9 +29,9 @@ class Field:
 
 
 class StringField(Field):
-    def __init__(self, namespace, tag, default=False, required=False, _d=None):
+    def __init__(self, namespace, tag, default=False, required=False, profile=BASIC, _d=None):
         from .elements import StringElement
-        super().__init__(StringElement, default, required, _d)
+        super().__init__(StringElement, default, required, profile, _d)
         self.namespace = namespace
         self.tag = tag
 
@@ -40,10 +44,56 @@ class StringField(Field):
         instance._data[self.name].text = value
 
 
+class AgencyIDField(Field):
+    def __init__(self, namespace, tag, default=False, required=False, profile=BASIC, _d=None):
+        from .elements import AgencyIDElement
+        super().__init__(AgencyIDElement, default, required, profile, _d)
+        self.namespace = namespace
+        self.tag = tag
+
+    def initialize(self):
+        return self.cls(self.namespace, self.tag)
+
+    def __set__(self, instance, value):
+        if instance._data.get(self.name, None) is None:
+            instance._data[self.name] = self.initialize()
+
+        if not isinstance(value, (tuple, list)):
+            raise TypeError("Please pass a 2-tuple of scheme agency ID and ID.")
+        instance._data[self.name].text = value[1]
+        instance._data[self.name].scheme_id = value[0]
+
+
+class ClassificationField(Field):
+    def __init__(self, namespace, tag, default=False, required=False, profile=BASIC, _d=None):
+        from .elements import ClassificationElement
+        super().__init__(ClassificationElement, default, required, profile, _d)
+        self.namespace = namespace
+        self.tag = tag
+
+    def initialize(self):
+        return self.cls(self.namespace, self.tag)
+
+    def __set__(self, instance, value):
+        if instance._data.get(self.name, None) is None:
+            instance._data[self.name] = self.initialize()
+
+        if not isinstance(value, (tuple, list)):
+            raise TypeError("Please pass a 3-tuple of list ID, list version and ID.")
+        instance._data[self.name].text = value[2]
+        instance._data[self.name].list_id = value[0]
+        instance._data[self.name].list_version_id = value[1]
+
+
 class IDField(Field):
-    def __init__(self, default=False, required=False, _d=None):
+    def __init__(self, namespace, tag, default=False, required=False, profile=BASIC, _d=None):
         from .elements import IDElement
-        super().__init__(IDElement, default, required, _d)
+        super().__init__(IDElement, default, required, profile, _d)
+        self.namespace = namespace
+        self.tag = tag
+
+    def initialize(self):
+        return self.cls(self.namespace, self.tag)
 
     def __set__(self, instance, value):
         if instance._data.get(self.name, None) is None:
@@ -56,9 +106,9 @@ class IDField(Field):
 
 
 class DecimalField(Field):
-    def __init__(self, namespace, tag, default=False, required=False, _d=None):
+    def __init__(self, namespace, tag, default=False, required=False, profile=BASIC, _d=None):
         from .elements import DecimalElement
-        super().__init__(DecimalElement, default, required, _d)
+        super().__init__(DecimalElement, default, required, profile, _d)
         self.namespace = namespace
         self.tag = tag
 
@@ -67,9 +117,9 @@ class DecimalField(Field):
 
 
 class QuantityField(Field):
-    def __init__(self, namespace, tag, default=False, required=False, _d=None):
+    def __init__(self, namespace, tag, default=False, required=False, profile=BASIC, _d=None):
         from .elements import QuantityElement
-        super().__init__(QuantityElement, default, required, _d)
+        super().__init__(QuantityElement, default, required, profile, _d)
         self.namespace = namespace
         self.tag = tag
 
@@ -87,9 +137,9 @@ class QuantityField(Field):
 
 
 class CurrencyField(Field):
-    def __init__(self, namespace, tag, default=False, required=False, _d=None):
+    def __init__(self, namespace, tag, default=False, required=False, profile=BASIC, _d=None):
         from .elements import CurrencyElement
-        super().__init__(CurrencyElement, default, required, _d)
+        super().__init__(CurrencyElement, default, required, profile, _d)
         self.namespace = namespace
         self.tag = tag
 
@@ -107,9 +157,9 @@ class CurrencyField(Field):
 
 
 class IndicatorField(Field):
-    def __init__(self, namespace, tag, default=False, required=False, _d=None):
+    def __init__(self, namespace, tag, default=False, required=False, profile=BASIC, _d=None):
         from .elements import IndicatorElement
-        super().__init__(IndicatorElement, default, required, _d)
+        super().__init__(IndicatorElement, default, required, profile, _d)
         self.namespace = namespace
         self.tag = tag
 
@@ -123,9 +173,9 @@ class IndicatorField(Field):
 
 
 class DateTimeField(Field):
-    def __init__(self, namespace, tag, default=False, required=False, _d=None):
+    def __init__(self, namespace, tag, default=False, required=False, profile=BASIC, _d=None):
         from .elements import DateTimeElement
-        super().__init__(DateTimeElement, default, required, _d)
+        super().__init__(DateTimeElement, default, required, profile, _d)
         self.namespace = namespace
         self.tag = tag
 
@@ -138,7 +188,7 @@ class DateTimeField(Field):
         return self.cls(self.namespace, self.tag)
 
 
-class Container():
+class Container:
     def __init__(self, child_type):
         super().__init__()
         self.children = []
@@ -155,8 +205,8 @@ class Container():
 
 
 class MultiField(Field):
-    def __init__(self, inner_type, default=False, required=False, _d=None):
-        super().__init__(Container, default, required, _d)
+    def __init__(self, inner_type, default=False, required=False, profile=BASIC, _d=None):
+        super().__init__(Container, default, required, profile, _d)
         self.inner_type = inner_type
 
     def initialize(self):
index 811d80f473c383d0eef23c6556576d9fc4da4cdb..2dec5b23b24ae66bb81aa79771c258523eb632b7 100644 (file)
@@ -1,11 +1,15 @@
-from drafthorse.models import NS_FERD_1p0
-from drafthorse.models.elements import Element
-from drafthorse.models.fields import StringField
+from . import NS_FERD_1p0, BASIC, COMFORT, EXTENDED
+from .elements import Element
+from .fields import StringField
 
 
 class IncludedNote(Element):
-    content = StringField(NS_FERD_1p0, "Content")
-    subject_code = StringField(NS_FERD_1p0, "SubjectCode")
+    content = StringField(NS_FERD_1p0, "Content", required=False,
+                          profile=BASIC)  # TODO: Can appear multiple times
+    content_code = StringField(NS_FERD_1p0, "ContentCode", required=False,
+                               profile=EXTENDED)
+    subject_code = StringField(NS_FERD_1p0, "SubjectCode", required=False,
+                               profile=COMFORT)
 
     class Meta:
         namespace = NS_FERD_1p0
diff --git a/drafthorse/models/party.py b/drafthorse/models/party.py
new file mode 100644 (file)
index 0000000..156e6ed
--- /dev/null
@@ -0,0 +1,125 @@
+from . import NS_FERD_1p0, COMFORT, BASIC, EXTENDED
+from .elements import Element
+from .fields import StringField, Field, IDField, MultiField
+
+
+class PostalTradeAddress(Element):
+    postcode = StringField(NS_FERD_1p0, "PostcodeCode", required=False, profile=BASIC)
+    line_one = StringField(NS_FERD_1p0, "LineOne", required=False, profile=BASIC)
+    line_two = StringField(NS_FERD_1p0, "LineTwo", required=False, profile=BASIC)
+    city_name = StringField(NS_FERD_1p0, "CityName", required=False, profile=BASIC)
+    country_id = StringField(NS_FERD_1p0, "CountryID", required=False, profile=BASIC)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "PostalTradeAddress"
+
+
+class TaxRegistration(Element):
+    id = IDField(NS_FERD_1p0, "ID")
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "SpecifiedTaxRegistration"
+
+
+class PhoneNumber(Element):
+    number = StringField(NS_FERD_1p0, "CompleteNumber", required=False,
+                         profile=EXTENDED)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "TelephoneUniversalCommunication"
+
+
+class FaxNumber(Element):
+    number = StringField(NS_FERD_1p0, "CompleteNumber", required=False,
+                         profile=EXTENDED)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "FaxUniversalCommunication"
+
+
+class EmailURI(Element):
+    address = StringField(NS_FERD_1p0, "URIID", required=False,
+                          profile=EXTENDED)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "EmailURICommunication"
+
+
+class TradeContact(Element):
+    person_name = StringField(NS_FERD_1p0, "PersonName", required=False,
+                              profile=EXTENDED)
+    department_name = StringField(NS_FERD_1p0, "DepartmentName", required=False,
+                                  profile=EXTENDED)
+    telephone = Field(PhoneNumber, required=False, profile=EXTENDED)
+    fax = Field(FaxNumber, required=False, profile=EXTENDED)
+    email = Field(EmailURI, required=False, profile=EXTENDED)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "DefinedTradeContact"
+
+
+class TradeParty(Element):
+    id = StringField(NS_FERD_1p0, "ID", required=False, profile=COMFORT,
+                     _d="Identifier des Verkäufers")
+    global_id = IDField(NS_FERD_1p0, "GlobalID", required=False, profile=COMFORT,
+                        _d="Globaler Identifier des Verkäufers")  # TODO: Support multiple
+    name = StringField(NS_FERD_1p0, "Name", required=False, profile=BASIC)
+    contact = Field(TradeContact, required=False, profile=EXTENDED,
+                    _d="Ansprechpartner des Käufers")
+    address = Field(PostalTradeAddress, required=False, profile=BASIC,
+                    _d="Anschrift des Käufers")
+    tax_registrations = MultiField(TaxRegistration, required=False, profile=BASIC)
+
+
+class PayeeTradeParty(TradeParty):
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "PayeeTradeParty"
+
+
+class InvoiceeTradeParty(TradeParty):
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "InvoiceeTradeParty"
+
+
+class BuyerTradeParty(TradeParty):
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "BuyerTradeParty"
+
+
+class SellerTradeParty(TradeParty):
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "SellerTradeParty"
+
+
+class EndUserTradeParty(TradeParty):
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "ProductEndUserTradeParty"
+
+
+class ShipToTradeParty(TradeParty):
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "ShipToTradeParty"
+
+
+class ShipFromTradeParty(TradeParty):
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "ShipFromTradeParty"
+
+
+class UltimateShipToTradeParty(TradeParty):
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "UltimateShipToTradeParty"
diff --git a/drafthorse/models/payment.py b/drafthorse/models/payment.py
new file mode 100644 (file)
index 0000000..8471787
--- /dev/null
@@ -0,0 +1,99 @@
+from . import NS_FERD_1p0, COMFORT, BASIC, EXTENDED
+from .elements import Element
+from .fields import Field, StringField, IDField, DateTimeField, DecimalField, CurrencyField
+
+
+class PayerFinancialAccount(Element):
+    iban = StringField(NS_FERD_1p0, "IBANID")
+    proprietary_id = StringField(NS_FERD_1p0, "ProprietaryID")
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "PayerPartyDebtorFinancialAccount"
+
+
+class PayerFinancialInstitution(Element):
+    bic = StringField(NS_FERD_1p0, "BICID")
+    german_blz = StringField(NS_FERD_1p0, "GermanBankleitzahlID")
+    name = StringField(NS_FERD_1p0, "Name")
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "PayerSpecifiedDebtorFinancialInstitution"
+
+
+class PayeeFinancialAccount(Element):
+    iban = StringField(NS_FERD_1p0, "IBANID")
+    account_name = StringField(NS_FERD_1p0, "AccountName")
+    proprietary_id = StringField(NS_FERD_1p0, "ProprietaryID")
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "PayeePartyCreditorFinancialAccount"
+
+
+class PayeeFinancialInstitution(Element):
+    bic = StringField(NS_FERD_1p0, "BICID")
+    german_blz = StringField(NS_FERD_1p0, "GermanBankleitzahlID")
+    name = StringField(NS_FERD_1p0, "Name")
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "PayeeSpecifiedCreditorFinancialInstitution"
+
+
+class PaymentMeans(Element):
+    type_code = StringField(NS_FERD_1p0, "TypeCode", required=False, profile=COMFORT)
+    information = StringField(NS_FERD_1p0, "Information", required=False, profile=COMFORT)  # TODO: Allow multiple
+    id = IDField(NS_FERD_1p0, "ID", required=False, profile=BASIC)
+    payer_account = Field(PayerFinancialAccount)
+    payer_institution = Field(PayerFinancialInstitution)
+    payee_account = Field(PayeeFinancialAccount)
+    payee_institution = Field(PayeeFinancialInstitution)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "SpecifiedTradeSettlementPaymentMeans"
+
+
+class PaymentPenaltyTerms(Element):
+    basis_date_time = DateTimeField(NS_FERD_1p0, "BasisDateTime", required=False,
+                                    profile=EXTENDED, _d="Bezugsdatum der Fälligkeit")
+    basis_period_measure = StringField(NS_FERD_1p0, "BasisPeriodMeasure", required=False,
+                                       profile=EXTENDED, _d="Fälligkeitszeitraum")
+    basis_amount = CurrencyField(NS_FERD_1p0, "BasisAmount", required=False,
+                                 profile=EXTENDED, _d="Basisbetrag des Zahlungszuschlags")
+    calculation_percent = DecimalField(NS_FERD_1p0, "CalculationPercent", required=False,
+                                       profile=EXTENDED, _d="Prozentwert des Zahlungszuschlags")
+    actual_amount = CurrencyField(NS_FERD_1p0, "ActualPenaltyAmount", required=False,
+                                  profile=EXTENDED, _d="Betrag des Zahlungszuschlags")
+
+
+class PaymentDiscountTerms(Element):
+    basis_date_time = DateTimeField(NS_FERD_1p0, "BasisDateTime", required=False,
+                                    profile=EXTENDED, _d="Bezugsdatum der Fälligkeit")
+    basis_period_measure = StringField(NS_FERD_1p0, "BasisPeriodMeasure", required=False,
+                                       profile=EXTENDED, _d="Fälligkeitszeitraum")
+    basis_amount = CurrencyField(NS_FERD_1p0, "BasisAmount", required=False,
+                                 profile=EXTENDED, _d="Basisbetrag des Zahlungsabschlags")
+    calculation_percent = DecimalField(NS_FERD_1p0, "CalculationPercent", required=False,
+                                       profile=EXTENDED, _d="Prozentwert des Zahlungsabschlags")
+    actual_amount = CurrencyField(NS_FERD_1p0, "ActualDiscountAmount", required=False,
+                                  profile=EXTENDED, _d="Betrag des Zahlungsabschlags")
+
+
+class PaymentTerms(Element):
+    description = StringField(NS_FERD_1p0, "Description", required=True, profile=COMFORT,
+                              _d="Freitext der Zahlungsbedingungen")
+    due = DateTimeField(NS_FERD_1p0, "DueDateDateTime", required=False, profile=COMFORT,
+                        _d="Fälligkeitsdatum")
+    partial_amount = CurrencyField(NS_FERD_1p0, "PartialPaymentAmount", profile=EXTENDED,
+                                   required=False, _d="Betrag der Teilzahlung")  # TODO: Allow multiple times
+    penalty_terms = Field(PaymentPenaltyTerms, required=False, profile=EXTENDED,
+                          _d="Detailinformationen zu Zahlungszuschlägen")
+    discount_terms = Field(PaymentDiscountTerms, required=False, profile=EXTENDED,
+                           _d="Detailinformationen zu Zahlungsabschlägen")
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "SpecifiedTradePaymentTerms"
diff --git a/drafthorse/models/product.py b/drafthorse/models/product.py
new file mode 100644 (file)
index 0000000..1ba1171
--- /dev/null
@@ -0,0 +1,49 @@
+from . import NS_FERD_1p0, EXTENDED, COMFORT
+from .elements import Element
+from .fields import StringField, QuantityField, IDField, MultiField, ClassificationField
+
+
+class ProductCharacteristic(Element):
+    type_code = StringField(NS_FERD_1p0, "TypeCode", required=True, profile=EXTENDED,
+                            _d="Art der Produkteigenschaft")
+    description = StringField(NS_FERD_1p0, "Description", required=True, profile=EXTENDED)
+    value_measure = QuantityField(NS_FERD_1p0, "ValueMeasure", required=False,
+                                  profile=EXTENDED, _d="Numerische Messgröße")
+    value = StringField(NS_FERD_1p0, "Value", required=False, profile=EXTENDED)
+
+
+class ProductClassification(Element):
+    class_code = ClassificationField(NS_FERD_1p0, "ClassCode", required=True,
+                                     profile=EXTENDED)
+    value = StringField(NS_FERD_1p0, "ClassName", required=True, profile=EXTENDED)
+
+
+class OriginCountry(Element):
+    id = StringField(NS_FERD_1p0, "ID", required=True, profile=EXTENDED,
+                     _d="Land der Produktherkunft")
+
+
+class ReferencedProduct(Element):
+    name = StringField(NS_FERD_1p0, "Name", required=False, profile=EXTENDED)
+    description = StringField(NS_FERD_1p0, "Description", required=False, profile=EXTENDED)
+    global_id = IDField(NS_FERD_1p0, "GlobalID", required=False, profile=EXTENDED)
+    seller_assigned_id = StringField(NS_FERD_1p0, "SellerAssignedID", required=False,
+                                     profile=EXTENDED)
+    buyer_assigned_id = StringField(NS_FERD_1p0, "BuyerAssignedID", required=False,
+                                    profile=EXTENDED)
+    unit_quantity = QuantityField(NS_FERD_1p0, "UnitQuantity", required=False,
+                                  profile=EXTENDED)
+
+
+class TradeProduct(Element):
+    name = StringField(NS_FERD_1p0, "Name", required=False, profile=COMFORT)
+    description = StringField(NS_FERD_1p0, "Description", required=False, profile=COMFORT)
+    global_id = IDField(NS_FERD_1p0, "GlobalID", required=False, profile=COMFORT)
+    seller_assigned_id = StringField(NS_FERD_1p0, "SellerAssignedID", required=False,
+                                     profile=COMFORT)
+    buyer_assigned_id = StringField(NS_FERD_1p0, "BuyerAssignedID", required=False,
+                                    profile=COMFORT)
+    characteristics = MultiField(ProductCharacteristic, required=False, profile=EXTENDED)
+    classifications = MultiField(ProductClassification, required=False, profile=EXTENDED)
+    origins = MultiField(OriginCountry, required=False, profile=EXTENDED)
+    included_products = MultiField(ReferencedProduct, required=False, profile=EXTENDED)
diff --git a/drafthorse/models/references.py b/drafthorse/models/references.py
new file mode 100644 (file)
index 0000000..02e1110
--- /dev/null
@@ -0,0 +1,103 @@
+from . import COMFORT, EXTENDED, NS_FERD_1p0
+from .elements import Element
+from .fields import DateTimeField, StringField
+
+
+class ReferencedDocument(Element):
+    issue_date_time = DateTimeField(NS_FERD_1p0, "IssueDateTime", required=False,
+                                    profile=COMFORT)
+    id = StringField(NS_FERD_1p0, "ID", required=False,
+                     profile=COMFORT)
+
+
+class BuyerOrderReferencedDocument(ReferencedDocument):
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "BuyerOrderReferencedDocument"
+
+
+class ContractReferencedDocument(ReferencedDocument):
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "ContractReferencedDocument"
+
+
+class AdditionalReferencedDocument(ReferencedDocument):
+    type_code = StringField(NS_FERD_1p0, "ReferenceTypeCode", profile=EXTENDED, required=True)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "AdditionalReferencedDocument"
+
+
+class CustomerOrderReferencedDocument(ReferencedDocument):
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "CustomerOrderReferencedDocument"
+
+
+class DespatchAdviceReferencedDocument(ReferencedDocument):
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "DespatchAdviceReferencedDocument"
+
+
+class LineCustomerOrderReferencedDocument(ReferencedDocument):
+    line_id = StringField(NS_FERD_1p0, "LineID", required=False, profile=EXTENDED)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "CustomerOrderReferencedDocument"
+
+
+class LineBuyerOrderReferencedDocument(ReferencedDocument):
+    line_id = StringField(NS_FERD_1p0, "LineID", required=False, profile=EXTENDED)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "BuyerOrderReferencedDocument"
+
+
+class LineContractReferencedDocument(ReferencedDocument):
+    line_id = StringField(NS_FERD_1p0, "LineID", required=False, profile=EXTENDED)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "ContractReferencedDocument"
+
+
+class LineDespatchAdviceReferencedDocument(ReferencedDocument):
+    line_id = StringField(NS_FERD_1p0, "LineID", required=False, profile=EXTENDED)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "DespatchAdviceReferencedDocument"
+
+
+class LineReceivingAdviceReferencedDocument(ReferencedDocument):
+    line_id = StringField(NS_FERD_1p0, "LineID", required=False, profile=EXTENDED)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "ReceivingAdviceReferencedDocument"
+
+
+class LineAdditionalReferencedDocument(ReferencedDocument):
+    line_id = StringField(NS_FERD_1p0, "LineID", required=False, profile=EXTENDED)
+    type_code = StringField(NS_FERD_1p0, "ReferenceTypeCode", profile=EXTENDED, required=True)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "AdditionalReferencedDocument"
+
+
+class DeliveryNoteReferencedDocument(ReferencedDocument):
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "DeliveryNoteReferencedDocument"
+
+
+class LineDeliveryNoteReferencedDocument(ReferencedDocument):
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "LineDeliveryNoteReferencedDocument"
index 4ccc309577743a0d277e499442d413c3f94d8e0c..d4287d40f3d1cfec98ba7560c9b73beea395d565 100644 (file)
-from drafthorse.models.note import IncludedNote
-from . import NS_RAM, NS_UDT, NS_FERD_1p0
+from . import NS_FERD_1p0, COMFORT, EXTENDED, BASIC
+from .accounting import ApplicableTradeTax, BillingSpecifiedPeriod, MonetarySummation, \
+    AccountingAccount
+from .accounting import TradeAllowanceCharge
+from .delivery import TradeDelivery
 from .elements import Element
-from .fields import DateTimeField, Field, MultiField, StringField, IDField, CurrencyField, DecimalField, IndicatorField, \
-    QuantityField
-
-
-class PostalTradeAddress(Element):
-    postcode = StringField(NS_FERD_1p0, "PostcodeCode")
-    line_one = StringField(NS_FERD_1p0, "LineOne")
-    city_name = StringField(NS_FERD_1p0, "CityName")
-    country_id = StringField(NS_FERD_1p0, "CountryID")
-
-    class Meta:
-        namespace = NS_FERD_1p0
-        tag = "PostalTradeAddress"
-
-
-class TaxRegistration(Element):
-    id = IDField()
-
-    class Meta:
-        namespace = NS_FERD_1p0
-        tag = "SpecifiedTaxRegistration"
-
-
-class BuyerTradeParty(Element):
-    name = StringField(NS_FERD_1p0, "Name")
-    address = Field(PostalTradeAddress)
-    tax_registrations = MultiField(TaxRegistration)
-
-    class Meta:
-        namespace = NS_FERD_1p0
-        tag = "BuyerTradeParty"
-
-
-class SellerTradeParty(Element):
-    name = StringField(NS_FERD_1p0, "Name")
-    address = Field(PostalTradeAddress)
-    tax_registrations = MultiField(TaxRegistration)
-
-    class Meta:
-        namespace = NS_FERD_1p0
-        tag = "SellerTradeParty"
+from .fields import Field, MultiField, StringField, CurrencyField
+from .party import PayeeTradeParty, SellerTradeParty, BuyerTradeParty, \
+    EndUserTradeParty, InvoiceeTradeParty
+from .payment import PaymentMeans, PaymentTerms
+from .references import CustomerOrderReferencedDocument, ContractReferencedDocument, BuyerOrderReferencedDocument, \
+    AdditionalReferencedDocument
+from .tradelines import LineItem
 
 
 class TradeAgreement(Element):
-    seller = Field(SellerTradeParty)
-    buyer = Field(BuyerTradeParty)
+    buyer_reference = StringField(NS_FERD_1p0, "BuyerReference", required=False,
+                                  profile=COMFORT, _d="Referenz des Käufers")
+    seller = Field(SellerTradeParty, required=True, _d="Detailinformationen zum Verkäufer")
+    buyer = Field(BuyerTradeParty, required=True)
+    end_user = Field(EndUserTradeParty, required=False, _d="Abweichender Endverbraucher")
+    delivery_type_code = StringField(NS_FERD_1p0, "DeliveryTypeCode", required=False,
+                                     profile=EXTENDED, _d="Lieferbedingung (Code)")
+    buyer_order = BuyerOrderReferencedDocument(required=False, profile=COMFORT)
+    customer_order = CustomerOrderReferencedDocument(required=False, profile=COMFORT)
+    contract = ContractReferencedDocument(required=False, profile=COMFORT)
+    additional_references = MultiField(AdditionalReferencedDocument, required=False,
+                                       profile=COMFORT)
 
     class Meta:
         namespace = NS_FERD_1p0
         tag = "ApplicableSupplyChainTradeAgreement"
 
 
-class SupplyChainEvent(Element):
-    occurrence = DateTimeField(NS_FERD_1p0, "OccurenceDateTime")
-
-    class Meta:
-        namespace = NS_FERD_1p0
-        tag = "ActualDeliverySupplyChainEvent"
-
-
-class TradeDelivery(Element):
-    events = MultiField(SupplyChainEvent)
-
-    class Meta:
-        namespace = NS_FERD_1p0
-        tag = "ApplicableSupplyChainTradeDelivery"
-
-
-class FinancialAccount(Element):
-    iban = StringField(NS_FERD_1p0, "IBANID")
-    account_name = StringField(NS_FERD_1p0, "AccountName")
-    proprietary_id = StringField(NS_FERD_1p0, "ProprietaryID")
-
-    class Meta:
-        namespace = NS_FERD_1p0
-        tag = "PayeePartyCreditorFinancialAccount"
-
-
-class FinancialInstitution(Element):
-    bic = StringField(NS_FERD_1p0, "BICID")
-    german_blz = StringField(NS_FERD_1p0, "GermanBankleitzahlID")
-    name = StringField(NS_FERD_1p0, "Name")
-
-    class Meta:
-        namespace = NS_FERD_1p0
-        tag = "PayeeSpecifiedCreditorFinancialInstitution"
-
-
-class PaymentMeans(Element):
-    type_code = StringField(NS_FERD_1p0, "TypeCode")
-    information = StringField(NS_FERD_1p0, "Information")
-    account = Field(FinancialAccount)
-    institution = Field(FinancialInstitution)
-
-    class Meta:
-        namespace = NS_FERD_1p0
-        tag = "SpecifiedTradeSettlementPaymentMeans"
-
-
-class TradeTax(Element):
-    calculated_amount = CurrencyField(NS_FERD_1p0, "CalculatedAmount", required=False)
-    type_code = StringField(NS_FERD_1p0, "TypeCode")
-    category_code = StringField(NS_FERD_1p0, "CategoryCode", required=False)
-    basis_amount = CurrencyField(NS_FERD_1p0, "BasisAmount", required=False)
-    applicable_percent = DecimalField(NS_FERD_1p0, "ApplicablePercent")
-
-    class Meta:
-        namespace = NS_FERD_1p0
-        tag = "ApplicableTradeTax"
-
-
-class PaymentTerms(Element):
-    description = StringField(NS_FERD_1p0, "Description")
-    due = DateTimeField(NS_FERD_1p0, "DueDateDateTime")
-
-    class Meta:
-        namespace = NS_FERD_1p0
-        tag = "SpecifiedTradePaymentTerms"
-
-
-class MonetarySummation(Element):
-    line_total = CurrencyField(NS_FERD_1p0, "LineTotalAmount")
-    charge_total = CurrencyField(NS_FERD_1p0, "ChargeTotalAmount")
-    allowance_total = CurrencyField(NS_FERD_1p0, "AllowanceTotalAmount")
-    tax_basis_total = CurrencyField(NS_FERD_1p0, "TaxBasisTotalAmount")
-    tax_total = CurrencyField(NS_FERD_1p0, "TaxTotalAmount")
-    grand_total = CurrencyField(NS_FERD_1p0, "GrandTotalAmount")
+class LogisticsServiceCharge(Element):
+    description = StringField(NS_FERD_1p0, "Description", required=True, profile=COMFORT,
+                              _d="Identifikation der Servicegebühr")
+    applied_amount = CurrencyField(NS_FERD_1p0, "AppliedAmount", required=True,
+                                   profile=COMFORT, _d="Betrag der Servicegebühr")
+    trade_tax = MultiField(ApplicableTradeTax, required=False, profile=COMFORT)
 
     class Meta:
         namespace = NS_FERD_1p0
-        tag = "SpecifiedTradeSettlementMonetarySummation"
+        tag = "SpecifiedLogisticsServiceCharge"
 
 
 class TradeSettlement(Element):
     payment_reference = StringField(NS_FERD_1p0, "PaymentReference")
     currency_code = StringField(NS_FERD_1p0, "InvoiceCurrencyCode")
+    invoicee = Field(InvoiceeTradeParty, required=False, profile=COMFORT,
+                     _d="Rechnungsempfänger")
+    payee = Field(PayeeTradeParty, required=False, profile=COMFORT,
+                  _d="Zahlungsempfänger")
     payment_means = Field(PaymentMeans)
-    trade_tax = MultiField(TradeTax)
-    terms = Field(PaymentTerms)
+    trade_tax = MultiField(ApplicableTradeTax)
+    period = Field(BillingSpecifiedPeriod, required=False, profile=COMFORT)
+    allowance_charge = MultiField(TradeAllowanceCharge, required=False, profile=COMFORT,
+                                  _d="Schalter für Zu-/Abschlag")
+    service_charge = MultiField(LogisticsServiceCharge, required=False, profile=COMFORT)
+    terms = MultiField(PaymentTerms, required=False, profile=COMFORT)
+    money_summation = Field(MonetarySummation, required=True, profile=BASIC,
+                            _d="Detailinformation zu Belegsummen")
+    accounting_account = Field(AccountingAccount, required=False, profile=EXTENDED,
+                               _d="Detailinformationen zur Buchungsreferenz")
 
     class Meta:
         namespace = NS_FERD_1p0
         tag = "ApplicableSupplyChainTradeSettlement"
 
 
-class AllowanceCharge(Element):
-    indicator = IndicatorField(NS_FERD_1p0, "ChargeIndicator")
-    actual_amount = CurrencyField(NS_FERD_1p0, "ActualAmount")
-
-    class Meta:
-        namespace = NS_FERD_1p0
-        tag = "AppliedTradeAllowanceCharge"
-
-
-class GrossPrice(Element):
-    amount = CurrencyField(NS_FERD_1p0, "ChargeAmount")
-    charge = Field(AllowanceCharge)
-
-    class Meta:
-        namespace = NS_FERD_1p0
-        tag = "GrossPriceProductTradePrice"
-
-
-class NetPrice(Element):
-    amount = CurrencyField(NS_FERD_1p0, "ChargeAmount")
-
-    class Meta:
-        namespace = NS_FERD_1p0
-        tag = "NetPriceProductTradePrice"
-
-
-class LineDocument(Element):
-    gross = Field(GrossPrice)
-    net = Field(NetPrice)
-
-    class Meta:
-        namespace = NS_FERD_1p0
-        tag = "AssociatedDocumentLineDocument"
-
-
-class LineAgreement(Element):
-    line_id = StringField(NS_FERD_1p0, "LineID")
-    note = Field(IncludedNote)
-
-    class Meta:
-        namespace = NS_FERD_1p0
-        tag = "SpecifiedSupplyChainTradeAgreement"
-
-
-class LineDelivery(Element):
-    billed_quantity = QuantityField(NS_FERD_1p0, "BilledQuantity")
-
-    class Meta:
-        namespace = NS_FERD_1p0
-        tag = "SpecifiedSupplyChainTradeDelivery"
-
-
-class LineSummation(Element):
-    total_amount = CurrencyField(NS_FERD_1p0, "LineTotalAmount")
-
-    class Meta:
-        namespace = NS_FERD_1p0
-        tag = "SpecifiedTradeSettlementMonetarySummation"
-
-
-class LineSettlement(Element):
-    trade_tax = Field(TradeTax)
-    monetary_summation = Field(LineSummation)
-
-    class Meta:
-        namespace = NS_FERD_1p0
-        tag = "SpecifiedSupplyChainTradeSettlement"
-
-
-class TradeProduct(Element):
-    seller_assigned_id = StringField(NS_FERD_1p0, "SellerAssignedID")
-    name = StringField(NS_FERD_1p0, "Name")
-
-
-class LineItem(Element):
-    document = Field(LineDocument)
-    agreement = Field(LineAgreement)
-    delivery = Field(LineDelivery)
-    settlement = Field(LineSettlement)
-    product = Field(TradeProduct)
-
-    class Meta:
-        namespace = NS_FERD_1p0
-        tag = "IncludedSupplyChainTradeItem"
-
-
 class TradeTransaction(Element):
-    agreement = Field(TradeAgreement)
-    delivery = Field(TradeDelivery)
-    settlement = Field(TradeSettlement)
-    items = MultiField(LineItem)
+    agreement = Field(TradeAgreement, required=True)
+    delivery = Field(TradeDelivery, required=True)
+    settlement = Field(TradeSettlement, required=True)
+    items = MultiField(LineItem, required=True)
 
     class Meta:
         namespace = NS_FERD_1p0
diff --git a/drafthorse/models/tradelines.py b/drafthorse/models/tradelines.py
new file mode 100644 (file)
index 0000000..b8e55f0
--- /dev/null
@@ -0,0 +1,120 @@
+from drafthorse.models.delivery import SupplyChainEvent
+from . import NS_FERD_1p0, BASIC, COMFORT, EXTENDED
+from .accounting import TradeAllowanceCharge, BillingSpecifiedPeriod, AccountingAccount
+from .elements import Element
+from .fields import CurrencyField, QuantityField, Field, MultiField, StringField
+from .note import IncludedNote
+from .party import UltimateShipToTradeParty, ShipToTradeParty
+from .product import TradeProduct
+from .references import LineReceivingAdviceReferencedDocument, LineDespatchAdviceReferencedDocument, \
+    LineDeliveryNoteReferencedDocument, LineCustomerOrderReferencedDocument, LineContractReferencedDocument, \
+    LineBuyerOrderReferencedDocument, LineAdditionalReferencedDocument
+
+
+class AllowanceCharge(TradeAllowanceCharge):
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "AppliedTradeAllowanceCharge"
+
+
+class GrossPrice(Element):
+    amount = CurrencyField(NS_FERD_1p0, "ChargeAmount", required=True, profile=COMFORT,
+                           _d="Bruttopreis")
+    basis_quantity = QuantityField(NS_FERD_1p0, "BasisQuantity", required=False,
+                                   profile=COMFORT, _d="Preisbasismenge")
+    charge = Field(AllowanceCharge, required=False, profile=COMFORT)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "GrossPriceProductTradePrice"
+
+
+class NetPrice(Element):
+    amount = CurrencyField(NS_FERD_1p0, "ChargeAmount", required=True, profile=COMFORT)
+    basis_quantity = QuantityField(NS_FERD_1p0, "BasisQuantity", required=False,
+                                   profile=COMFORT, _d="Preisbasismenge")
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "NetPriceProductTradePrice"
+
+
+class LineDocument(Element):
+    line_id = StringField(NS_FERD_1p0, "LineID")
+    notes = MultiField(IncludedNote)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "AssociatedDocumentLineDocument"
+
+
+class LineAgreement(Element):
+    buyer_order = Field(LineBuyerOrderReferencedDocument, required=False, profile=EXTENDED)
+    contract = Field(LineContractReferencedDocument, required=False, profile=EXTENDED)
+    customer_order = Field(LineCustomerOrderReferencedDocument, required=False, profile=EXTENDED)
+    additional_references = MultiField(LineAdditionalReferencedDocument, required=False,
+                                       profile=COMFORT)
+    gross = Field(GrossPrice, required=False, profile=COMFORT)
+    net = Field(NetPrice)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "SpecifiedSupplyChainTradeAgreement"
+
+
+class LineDelivery(Element):
+    billed_quantity = QuantityField(NS_FERD_1p0, "BilledQuantity", required=True,
+                                    profile=BASIC, _d="Menge, berechnet")
+    charge_free_quantity = QuantityField(NS_FERD_1p0, "ChargeFreeQuantity", required=False,
+                                         profile=EXTENDED, _d="Menge, ohne Berechnung")
+    package_quantity = QuantityField(NS_FERD_1p0, "ChargeFreeQuantity", required=False,
+                                     profile=EXTENDED, _d="Anzahl Packstücke")
+    ship_to = Field(ShipToTradeParty, required=False, profile=EXTENDED)
+    ultimate_ship_to = Field(UltimateShipToTradeParty, required=False, profile=EXTENDED)
+    event = Field(SupplyChainEvent, required=False, profile=EXTENDED,
+                  _d="Detailinformationen zur tatsächlichen Lieferung")
+    despatch_advice = Field(LineDespatchAdviceReferencedDocument, required=False,
+                            profile=EXTENDED)
+    receiving_advice = Field(LineReceivingAdviceReferencedDocument, required=False,
+                             profile=EXTENDED)
+    delivery_note = Field(LineDeliveryNoteReferencedDocument, required=False,
+                          profile=EXTENDED)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "SpecifiedSupplyChainTradeDelivery"
+
+
+class LineSummation(Element):
+    total_amount = CurrencyField(NS_FERD_1p0, "LineTotalAmount", required=True,
+                                 profile=COMFORT)
+    total_allowance_charge = CurrencyField(NS_FERD_1p0, "TotalAllowanceChargeAmount",
+                                           required=False, profile=EXTENDED, _d="Gesamtbetrag der Zu- und Abschläge")
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "SpecifiedTradeSettlementMonetarySummation"
+
+
+class LineSettlement(Element):
+    trade_tax = Field(LineAdditionalReferencedDocument, required=False, profile=COMFORT)
+    period = Field(BillingSpecifiedPeriod, required=False, profile=EXTENDED)
+    accounting_account = Field(AccountingAccount, required=False, profile=EXTENDED,
+                               _d="Kostenstelle")
+    monetary_summation = Field(LineSummation, required=False, profile=COMFORT)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "SpecifiedSupplyChainTradeSettlement"
+
+
+class LineItem(Element):
+    document = Field(LineDocument, required=True)
+    agreement = Field(LineAgreement)
+    delivery = Field(LineDelivery)
+    settlement = Field(LineSettlement)
+    product = Field(TradeProduct)
+
+    class Meta:
+        namespace = NS_FERD_1p0
+        tag = "IncludedSupplyChainTradeLineItem"