From: Ben Dangelmayr Date: Tue, 31 May 2022 09:41:48 +0000 (+0200) Subject: Added new fields, added XRECHNUNG samples X-Git-Tag: 2.2.0~1^2~19 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4283d152ca2fb3eb950bee00e7047ae25a046f16;p=thirdparty%2Fpython-drafthorse.git Added new fields, added XRECHNUNG samples --- diff --git a/drafthorse/models/elements.py b/drafthorse/models/elements.py index 2c95b18..9b523a4 100644 --- a/drafthorse/models/elements.py +++ b/drafthorse/models/elements.py @@ -4,7 +4,8 @@ import xml.etree.cElementTree as ET from collections import OrderedDict from datetime import datetime from decimal import Decimal - +#TODO: implement mimeElement and container +import mimetypes from drafthorse.utils import validate_xml from . import NS_UDT @@ -202,6 +203,25 @@ class ClassificationElement(StringElement): def __str__(self): return "{} ({} {})".format(self.text, self.list_id, self.list_version_id) +class BinaryObjectElement(StringElement): + def __init__(self, namespace, tag, text="", mime_code=""): + super().__init__(namespace, tag) + self.text = text + self.mime_code = mime_code + + def to_etree(self): + node = self._etree_node() + node.text = self.text + node.attrib['mimeCode'] = self.mime_code + return node + + def from_etree(self, root): + self.text = root.text + self.mime_code = root.attrib['mimeCode'] + return self + + def __str__(self): + return "{} ({} {})".format(self.text, self.mime_code) class AgencyIDElement(StringElement): def __init__(self, namespace, tag, text="", scheme_id=""): diff --git a/drafthorse/models/fields.py b/drafthorse/models/fields.py index ca733f2..4ad8d9e 100644 --- a/drafthorse/models/fields.py +++ b/drafthorse/models/fields.py @@ -143,6 +143,24 @@ class QuantityField(Field): def initialize(self): return self.cls(self.namespace, self.tag) +class BinaryObjectField(Field): + def __init__(self, namespace, tag, default=False, required=False, profile=BASIC, _d=None): + from .elements import BinaryObjectElement + super().__init__(BinaryObjectElement, default, required, profile, _d) + self.namespace = namespace + self.tag = 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 including amount and unit code.") + instance._data[self.name].text = value[1] + instance._data[self.name].mime_code = value[0] + + def initialize(self): + return self.cls(self.namespace, self.tag) class CurrencyField(Field): def __init__(self, namespace, tag, default=False, required=False, profile=BASIC, _d=None): diff --git a/drafthorse/models/party.py b/drafthorse/models/party.py index 19fdbbf..7a3aee3 100644 --- a/drafthorse/models/party.py +++ b/drafthorse/models/party.py @@ -75,14 +75,14 @@ class TradeParty(Element): global_id = MultiIDField(NS_RAM, "GlobalID", required=False, profile=COMFORT, _d="Globaler Identifier des Verkäufers") name = StringField(NS_RAM, "Name", required=False, profile=BASIC) + description = StringField(NS_RAM, "Description", required=True, profile=COMFORT, + _d="Freitext der Zahlungsbedingungen") 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) electronic_adress = MultiField(URIUniversalCommunication, required=False, profile=BASIC) - description = StringField(NS_RAM, "Description", required=True, profile=COMFORT, - _d="Freitext der Zahlungsbedingungen") + tax_registrations = MultiField(TaxRegistration, required=False, profile=BASIC) class SellerTaxRepresentativeTradeParty(TradeParty): class Meta: diff --git a/drafthorse/models/payment.py b/drafthorse/models/payment.py index 9d1f695..103859c 100644 --- a/drafthorse/models/payment.py +++ b/drafthorse/models/payment.py @@ -1,8 +1,8 @@ from . import BASIC, COMFORT, EXTENDED, NS_RAM from .elements import Element from .fields import ( - AgencyIDField, DecimalField, DateTimeField, DecimalField, Field, - MultiDecimalField, MultiStringField, QuantityField, StringField, + AgencyIDField, DateTimeField, DecimalField, Field, + MultiDecimalField, MultiStringField, QuantityField, StringField, DirectDateTimeField ) @@ -87,6 +87,15 @@ class PaymentDiscountTerms(Element): namespace = NS_RAM tag = "ApplicableTradePaymentDiscountTerms" +class TaxApplicableTradeCurrencyExchange(Element): + source_currency = StringField(NS_RAM, "SourceCurrencyCode", required=False, profile=EXTENDED) + target_currency = StringField(NS_RAM, "TargetCurrencyCode", required=False, profile=EXTENDED) + conversion_rate = DecimalField(NS_RAM, "ConversionRate", required=False, profile=EXTENDED) + date_time_string = DirectDateTimeField(NS_RAM, "ConversionRateDateTime", required=True, + profile=EXTENDED) + class Meta: + namespace = NS_RAM + tag = "TaxApplicableTradeCurrencyExchange" class PaymentTerms(Element): description = StringField(NS_RAM, "Description", required=True, profile=COMFORT, diff --git a/drafthorse/models/references.py b/drafthorse/models/references.py index 6e3ca2b..09fde8a 100644 --- a/drafthorse/models/references.py +++ b/drafthorse/models/references.py @@ -1,13 +1,13 @@ -from . import COMFORT, EXTENDED, NS_RAM +from . import COMFORT, EXTENDED, NS_RAM, NS_RSM from .elements import Element -from .fields import DirectDateTimeField, StringField, Field +from .fields import DirectDateTimeField, StringField, Field, BinaryObjectField class ProcuringProjectType(Element): id = StringField(NS_RAM, "ID") name = StringField(NS_RAM, "Name") class Meta: namespace = NS_RAM - tag = "ProcuringProjectType" + tag = "SpecifiedProcuringProject" class ReferencedDocument(Element): date_time_string = DirectDateTimeField(NS_RAM, "DateTimeString", required=False, @@ -15,7 +15,8 @@ class ReferencedDocument(Element): issuer_assigned_id = StringField(NS_RAM, "IssuerAssignedID", required=False, profile=COMFORT) class AttachmentBinaryObject(Element): - name = StringField(NS_RAM, "filename", profile=EXTENDED) + name = StringField(NS_RAM, "filename", required=False, profile=COMFORT) + #mime_code = BinaryObjectField(NS_RAM,"mime_code", profile=COMFORT) class Meta: namespace = NS_RAM tag = "AttachmentBinaryObject" @@ -41,7 +42,7 @@ class AdditionalReferencedDocument(Element): profile=COMFORT) type_code = StringField(NS_RAM, "TypeCode", profile=EXTENDED, required=True) name = StringField(NS_RAM, "Name", profile=COMFORT, required=False) - attached_object = Field(AttachmentBinaryObject, required=False, profile=EXTENDED) + attached_object = BinaryObjectField(NS_RAM, "AttachmentBinaryObject", required=False, profile=EXTENDED) class Meta: namespace = NS_RAM tag = "AdditionalReferencedDocument" diff --git a/drafthorse/models/trade.py b/drafthorse/models/trade.py index ef30cef..c6e122e 100644 --- a/drafthorse/models/trade.py +++ b/drafthorse/models/trade.py @@ -10,7 +10,7 @@ from .party import ( BuyerTradeParty, EndUserTradeParty, InvoiceeTradeParty, PayeeTradeParty, SellerTradeParty, SellerTaxRepresentativeTradeParty, ) -from .payment import PaymentMeans, PaymentTerms +from .payment import PaymentMeans, PaymentTerms, TaxApplicableTradeCurrencyExchange from .references import ( AdditionalReferencedDocument, BuyerOrderReferencedDocument, ContractReferencedDocument, UltimateCustomerOrderReferencedDocument, ProcuringProjectType, InvoiceReferencedDocument @@ -68,7 +68,9 @@ class TradeSettlement(Element): payee = Field(PayeeTradeParty, required=False, profile=COMFORT, _d="Zahlungsempfänger") payment_means = Field(PaymentMeans) + invoice_currency = Field(TaxApplicableTradeCurrencyExchange) trade_tax = MultiField(ApplicableTradeTax) + period = Field(BillingSpecifiedPeriod, required=False, profile=BASIC) allowance_charge = MultiField(TradeAllowanceCharge, required=False, profile=COMFORT, _d="Schalter für Zu-/Abschlag") service_charge = MultiField(LogisticsServiceCharge, required=False, profile=COMFORT) @@ -78,7 +80,6 @@ class TradeSettlement(Element): accounting_account = Field(ReceivableAccountingAccount, required=False, profile=EXTENDED, _d="Detailinformationen zur Buchungsreferenz") creditor_reference_ID = IDField(NS_RAM, "CreditorReferenceID") - period = Field(BillingSpecifiedPeriod, required=False, profile=BASIC) tax_currency_code = StringField(NS_RAM, "TaxCurrencyCode", required=False, profile=COMFORT) invoice_referenced_document = Field(InvoiceReferencedDocument, required=False, profile=BASIC) class Meta: diff --git a/drafthorse/models/tradelines.py b/drafthorse/models/tradelines.py index dfda603..05e4e61 100644 --- a/drafthorse/models/tradelines.py +++ b/drafthorse/models/tradelines.py @@ -108,8 +108,8 @@ class LineSettlement(Element): trade_tax = Field(ApplicableTradeTax, required=False, profile=COMFORT) accounting_account = Field(AccountingAccount, required=False, profile=EXTENDED, _d="Kostenstelle") - monetary_summation = Field(LineSummation, required=False, profile=COMFORT) period = Field(BillingSpecifiedPeriod, required=False, profile=COMFORT) + monetary_summation = Field(LineSummation, required=False, profile=COMFORT) allowance_charge = MultiField(TradeAllowanceCharge, required=False, profile=COMFORT, _d="Schalter für Zu-/Abschlag") invoice_referenced_document = Field(InvoiceReferencedDocument, required=False, profile=EXTENDED) diff --git a/tests/test_roundtrip.py b/tests/test_roundtrip.py index 22691c0..9acaca1 100644 --- a/tests/test_roundtrip.py +++ b/tests/test_roundtrip.py @@ -22,7 +22,10 @@ def test_sample_roundtrip(filename): open(os.path.join(os.path.dirname(__file__), 'samples', filename), 'rb').read(), remove_comments=True ) - schema = 'FACTUR-X_' + filename.split('_')[2] + if filename.split('_')[2] != "XRECHNUNG": + schema = 'FACTUR-X_' + filename.split('_')[2] + else: + schema = 'FACTUR-X_EN16931' # Validate that the sample file is valid, otherwise the test is moot validate_xml(xmlout=origxml, schema=schema)