Skip to content

Commit

Permalink
fixes Invoice line object identifier (BT-128) among others (contains PR
Browse files Browse the repository at this point in the history
  • Loading branch information
MAKOMO committed Jan 26, 2024
1 parent 68494e8 commit beb6c41
Show file tree
Hide file tree
Showing 12 changed files with 136 additions and 113 deletions.
41 changes: 22 additions & 19 deletions EN16931_Einfach.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,25 @@


def test_EN16931_Einfach_example():

doc = Document()
doc.context.guideline_parameter.id = (
"urn:cen.eu:en16931:2017"
)
doc.context.guideline_parameter.id = "urn:cen.eu:en16931:2017"
doc.header.id = "471102"
doc.header.type_code = "380"
doc.header.issue_date_time = date.fromisoformat('20180305')
doc.header.issue_date_time = date.fromisoformat("20180305")

note = IncludedNote()
note.content.add("Rechnung gemäß Bestellung vom 01.03.2018.")
doc.header.notes.add(note)

note = IncludedNote()
# BT-21
note.subject_code = "REG" # REG=Regulatory information; code list: UNTDID 4451 "Text subject code qualifier"
# BT-21
note.subject_code = "REG" # REG=Regulatory information; code list: UNTDID 4451 "Text subject code qualifier"
# BT-22 Kommentarfeld
note.content.add("Lieferant GmbH\nLieferantenstraße 20\n80333 München\nDeutschland\nGeschäftsführer: Hans Muster\nHandelsregisternummer: H A 123")
note.content.add(
"Lieferant GmbH\nLieferantenstraße 20\n80333 München\nDeutschland\nGeschäftsführer: Hans Muster\nHandelsregisternummer: H A 123"
)
doc.header.notes.add(note)

li = LineItem()
li.document.line_id = "1"
li.product.global_id = ("0160", "4012345001235")
Expand Down Expand Up @@ -59,7 +58,7 @@ def test_EN16931_Einfach_example():
li.settlement.trade_tax.rate_applicable_percent = Decimal("7.00")
li.settlement.monetary_summation.total_amount = Decimal("275.00")
doc.trade.items.add(li)

doc.trade.agreement.seller.id = "549910"
doc.trade.agreement.seller.global_id.add(("0088", "4000001123452"))
doc.trade.agreement.seller.name = "Lieferant GmbH"
Expand All @@ -73,16 +72,16 @@ def test_EN16931_Einfach_example():
seller_tr_va = TaxRegistration()
seller_tr_va.id = ("VA", "DE123456789")
doc.trade.agreement.seller.tax_registrations.add(seller_tr_va)

doc.trade.agreement.buyer.id = "GE2020211"
doc.trade.agreement.buyer.name = "Kunden AG Mitte"
doc.trade.agreement.buyer.address.postcode = "69876"
doc.trade.agreement.buyer.address.line_one = "Kundenstraße 15"
doc.trade.agreement.buyer.address.city_name = "Frankfurt"
doc.trade.agreement.buyer.address.country_id = "DE"
doc.trade.delivery.event.occurrence = date.fromisoformat('20180305')

doc.trade.delivery.event.occurrence = date.fromisoformat("20180305")

doc.trade.settlement.currency_code = "EUR"
trade_tax = ApplicableTradeTax()
trade_tax.calculated_amount = Decimal("19.25")
Expand Down Expand Up @@ -112,17 +111,21 @@ def test_EN16931_Einfach_example():
doc.trade.settlement.monetary_summation.prepaid_total = Decimal("0.00")
doc.trade.settlement.monetary_summation.due_amount = Decimal("529.87")

### Serialization and PDF Generation
### Serialization and PDF Generation

xml = doc.serialize(schema="FACTUR-X_EN16931")
with open('factur-x.xml', 'wb') as f:
with open("factur-x.xml", "wb") as f:
f.write(xml)
with open(
os.path.join(os.path.dirname(__file__), "tests", "samples", "invoice_pdf17.pdf"), "rb"
os.path.join(
os.path.dirname(__file__), "tests", "samples", "invoice_pdf17.pdf"
),
"rb",
) as original_file:
new_pdf_bytes = attach_xml(original_file.read(), xml, "EN 16931")

with open("EN16931_Einfach.pdf", "wb") as f:
f.write(new_pdf_bytes)


test_EN16931_Einfach_example()
37 changes: 4 additions & 33 deletions drafthorse/models/accounting.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
StringField,
)


class BillingSpecifiedPeriod(Element):
description = StringField(
NS_RAM,
Expand All @@ -27,36 +28,6 @@ class Meta:
tag = "BillingSpecifiedPeriod"


class LineApplicableTradeTax(Element):
calculated_amount = DecimalField(
NS_RAM, "CalculatedAmount", required=True, profile=BASIC, _d="Steuerbetrag"
)
type_code = StringField(
NS_RAM, "TypeCode", required=True, profile=BASIC, _d="Steuerart (Code)"
)
exemption_reason = StringField(
NS_RAM,
"ExemptionReason",
required=False,
profile=COMFORT,
_d="Grund der Steuerbefreiung (Freitext)",
)
category_code = StringField(
NS_RAM,
"CategoryCode",
required=False,
profile=COMFORT,
_d="Steuerkategorie (Wert)",
)
rate_applicable_percent = DecimalField(
NS_RAM, "RateApplicablePercent", required=True, profile=BASIC
)

class Meta:
namespace = NS_RAM
tag = "ApplicableTradeTax"


class ApplicableTradeTax(Element):
calculated_amount = DecimalField(
NS_RAM, "CalculatedAmount", required=True, profile=BASIC, _d="Steuerbetrag"
Expand All @@ -68,7 +39,7 @@ class ApplicableTradeTax(Element):
NS_RAM,
"ExemptionReason",
required=False,
profile=COMFORT,
profile=BASIC,
_d="Grund der Steuerbefreiung (Freitext)",
)
basis_amount = DecimalField(
Expand Down Expand Up @@ -96,14 +67,14 @@ class ApplicableTradeTax(Element):
NS_RAM,
"CategoryCode",
required=False,
profile=COMFORT,
profile=BASIC,
_d="Steuerkategorie (Wert)",
)
exemption_reason_code = StringField(
NS_RAM,
"ExemptionReasonCode",
required=False,
profile=EXTENDED,
profile=BASIC,
_d="Grund der Steuerbefreiung (Code)",
)
tax_point_date = DateTimeField(
Expand Down
9 changes: 6 additions & 3 deletions drafthorse/models/elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from drafthorse.utils import validate_xml

from . import NS_UDT, NS_A
from . import NS_UDT
from .container import Container
from .fields import Field

Expand Down Expand Up @@ -302,7 +302,8 @@ def __init__(self, namespace, tag, text="", scheme_id=""):
def to_etree(self):
node = self._etree_node()
node.text = self._text
node.attrib["schemeID"] = self._scheme_id
if self._scheme_id != "":
node.attrib["schemeID"] = self._scheme_id
return node

def from_etree(self, root):
Expand All @@ -320,7 +321,9 @@ def __str__(self):


class DateTimeElement(StringElement):
def __init__(self, namespace, tag, value=None, format="102", date_time_namespace=NS_UDT):
def __init__(
self, namespace, tag, value=None, format="102", date_time_namespace=NS_UDT
):
super().__init__(namespace, tag)
self._value = value
self._format = format
Expand Down
31 changes: 24 additions & 7 deletions drafthorse/models/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,16 @@ 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 scheme ID and ID.")
instance._data[self.name]._text = value[1]
instance._data[self.name]._scheme_id = value[0]
if isinstance(value, (tuple, list)):
if len(value) == 2:
instance._data[self.name]._text = value[1]
instance._data[self.name]._scheme_id = value[0]
else:
raise TypeError(
"Please pass a 2-tuple of including scheme ID and ID, or just an ID."
)
else:
instance._data[self.name]._text = value


class CurrencyField(Field):
Expand Down Expand Up @@ -208,7 +214,9 @@ def __set__(self, instance, value):
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.")
raise TypeError(
"Please pass a 3-tuple of mimeCode, filename and base64-encoded binary."
)
instance._data[self.name]._text = value[2]
instance._data[self.name]._mime_code = value[0]
instance._data[self.name]._filename = value[1]
Expand Down Expand Up @@ -238,7 +246,14 @@ def initialize(self):

class DateTimeField(Field):
def __init__(
self, namespace, tag, default=False, required=False, profile=BASIC, _d=None, date_time_namespace=NS_UDT
self,
namespace,
tag,
default=False,
required=False,
profile=BASIC,
_d=None,
date_time_namespace=NS_UDT,
):
from .elements import DateTimeElement

Expand All @@ -253,7 +268,9 @@ def __set__(self, instance, value):
instance._data[self.name]._value = value

def initialize(self):
return self.cls(self.namespace, self.tag, date_time_namespace=self._date_time_namespace)
return self.cls(
self.namespace, self.tag, date_time_namespace=self._date_time_namespace
)


class DirectDateTimeField(Field):
Expand Down
23 changes: 17 additions & 6 deletions drafthorse/models/party.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,13 @@ class Meta:
class LegalOrganization(Element):
id = StringField(NS_RAM, "ID", required=False, profile=BASIC)
trade_name = StringField(
NS_RAM, "TradingBusinessName", required=False, profile=BASIC, _d="Name, unter dem der Käufers bekannt ist"
)
trade_address = Field(
PostalTradeAddress, required=False, profile=EXTENDED
NS_RAM,
"TradingBusinessName",
required=False,
profile=BASIC,
_d="Name, unter dem der Käufers bekannt ist",
)
trade_address = Field(PostalTradeAddress, required=False, profile=EXTENDED)

class Meta:
namespace = NS_RAM
Expand Down Expand Up @@ -99,8 +101,11 @@ class TradeParty(Element):
_d="Globaler Identifier des Verkäufers",
)
name = StringField(NS_RAM, "Name", required=False, profile=BASIC)
legal_organization = Field(
LegalOrganization, required=False, profile=BASIC, _d="Handelsinformationen des Käufers"
legal_organization = Field(
LegalOrganization,
required=False,
profile=BASIC,
_d="Handelsinformationen des Käufers",
)
description = StringField(
NS_RAM,
Expand Down Expand Up @@ -133,6 +138,12 @@ class Meta:
tag = "PayeeTradeParty"


class PayerTradeParty(TradeParty):
class Meta:
namespace = NS_RAM
tag = "PayerTradeParty"


class InvoicerTradeParty(TradeParty):
class Meta:
namespace = NS_RAM
Expand Down
37 changes: 23 additions & 14 deletions drafthorse/models/product.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ class ProductCharacteristic(Element):
type_code = StringField(
NS_RAM,
"TypeCode",
required=True,
required=False,
profile=EXTENDED,
_d="Art der Produkteigenschaft",
)
description = StringField(NS_RAM, "Description", required=True, profile=EXTENDED)
description = StringField(NS_RAM, "Description", required=True, profile=COMFORT)
value_measure = QuantityField(
NS_RAM,
"ValueMeasure",
required=False,
profile=EXTENDED,
_d="Numerische Messgröße",
)
value = StringField(NS_RAM, "Value", required=False, profile=EXTENDED)
value = StringField(NS_RAM, "Value", required=False, profile=COMFORT)

class Meta:
namespace = NS_RAM
Expand All @@ -34,15 +34,26 @@ class Meta:

class ProductClassification(Element):
class_code = ClassificationField(
NS_RAM, "ClassCode", required=True, profile=EXTENDED
NS_RAM, "ClassCode", required=False, profile=COMFORT
)
value = StringField(NS_RAM, "ClassName", required=True, profile=EXTENDED)
value = StringField(NS_RAM, "ClassName", required=False, profile=EXTENDED)

class Meta:
namespace = NS_RAM
tag = "DesignatedProductClassification"


class ProductInstance(Element):
batch_id = IDField(NS_RAM, "BatchID", required=False, profile=EXTENDED)
serial_id = StringField(
NS_RAM, "SupplierAssignedSerialID", required=False, profile=EXTENDED
)

class Meta:
namespace = NS_RAM
tag = "IndividualTradeProductInstance"


class OriginCountry(Element):
id = StringField(
NS_RAM, "ID", required=True, profile=EXTENDED, _d="Land der Produktherkunft"
Expand Down Expand Up @@ -73,22 +84,20 @@ class Meta:


class TradeProduct(Element):
global_id = IDField(NS_RAM, "GlobalID", required=False, profile=COMFORT)
id = IDField(NS_RAM, "ID", required=False, profile=EXTENDED)
global_id = IDField(NS_RAM, "GlobalID", required=False)
seller_assigned_id = StringField(
NS_RAM, "SellerAssignedID", required=False, profile=COMFORT
)
buyer_assigned_id = StringField(
NS_RAM, "BuyerAssignedID", required=False, profile=COMFORT
)
name = StringField(NS_RAM, "Name", required=False, profile=COMFORT)
name = StringField(NS_RAM, "Name", required=False)
description = StringField(NS_RAM, "Description", 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)
characteristics = MultiField(ProductCharacteristic, required=False, profile=COMFORT)
classifications = MultiField(ProductClassification, required=False, profile=COMFORT)
instance = MultiField(ProductInstance, required=False, profile=EXTENDED)
origins = MultiField(OriginCountry, required=False, profile=COMFORT)
included_products = MultiField(ReferencedProduct, required=False, profile=EXTENDED)

class Meta:
Expand Down
Loading

0 comments on commit beb6c41

Please sign in to comment.