Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 50 additions & 30 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,85 +49,105 @@ Parsing::

``Document.parse()`` taskes a boolean parameter ``strict`` which defaults to ``True``. This means that the parser will raise an error if it encounters any unknown element. If you set it to ``False``, the parser will not raise an error and parse whatever it can.

.. [[[cog
# Re-run this with `cog -r README.rst`

from pathlib import Path
from textwrap import indent

import cog

cog.outl("Generating::\n")
cog.outl(indent(Path("example.py").read_text(encoding="UTF-8"), " "), dedent=False)
.. ]]]
Generating::

from datetime import date, datetime, timezone
from datetime import date, datetime, timedelta, timezone
from decimal import Decimal

from drafthorse.models.accounting import ApplicableTradeTax
from drafthorse.models.document import Document
from drafthorse.models.note import IncludedNote
from drafthorse.models.party import TaxRegistration
from drafthorse.models.payment import PaymentMeans, PaymentTerms
from drafthorse.models.trade import AdvancePayment, IncludedTradeTax
from drafthorse.models.tradelines import LineItem
from drafthorse.pdf import attach_xml

# Build data structure
doc = Document()
doc.context.guideline_parameter.id = "urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended"
doc.context.guideline_parameter.id = "urn:cen.eu:en16931:2017"
doc.header.id = "RE1337"
doc.header.type_code = "380"
doc.header.name = "RECHNUNG"
doc.header.issue_date_time = date.today()
doc.header.language = "ger"

doc.header.notes.add(IncludedNote(content="Test Note 1"))

doc.trade.agreement.seller.name = "Lieferant GmbH"
doc.trade.settlement.payee.name = "Lieferant GmbH"

doc.trade.agreement.buyer.name = "Kunde GmbH"
doc.trade.settlement.invoicee.name = "Kunde GmbH"
doc.trade.agreement.buyer.address.country_id = "DE"

doc.trade.settlement.currency_code = "EUR"
doc.trade.settlement.payment_means.type_code = "ZZZ"
doc.trade.settlement.payment_means.add(PaymentMeans(type_code="ZZZ"))

doc.trade.agreement.seller.name = "Lieferant GmbH"
doc.trade.agreement.seller.address.country_id = "DE"
doc.trade.agreement.seller.address.country_subdivision = "Bayern"
doc.trade.agreement.seller.tax_registrations.add(
TaxRegistration(
id=("VA", "DE000000000")
)
TaxRegistration(id=("VA", "DE000000000"))
)

doc.trade.agreement.seller_order.issue_date_time = datetime.now(timezone.utc)
doc.trade.agreement.buyer_order.issue_date_time = datetime.now(timezone.utc)
doc.trade.settlement.advance_payment.received_date = datetime.now(timezone.utc)
doc.trade.agreement.customer_order.issue_date_time = datetime.now(timezone.utc)
advance = AdvancePayment(
received_date=datetime.now(timezone.utc), paid_amount=Decimal(42)
)
advance.included_trade_tax.add(
IncludedTradeTax(
calculated_amount=Decimal(0),
type_code="VAT",
category_code="E",
rate_applicable_percent=Decimal(0),
)
)
doc.trade.settlement.advance_payment.add(advance)

li = LineItem()
li.document.line_id = "1"
li.product.name = "Rainbow"
li.agreement.gross.amount = Decimal("999.00")
li.agreement.gross.basis_quantity = (Decimal("1.0000"), "H87") # H87 == pieces
li.agreement.net.amount = Decimal("999.00")
li.agreement.net.basis_quantity = (Decimal("999.00"), "EUR")
li.delivery.billed_quantity = (Decimal("1.0000"), "H87") # H87 == pieces
li.agreement.gross.amount = Decimal("1198.8")
li.agreement.gross.basis_quantity = (Decimal("1.0000"), "C62") # C62 == unit
li.agreement.net.amount = Decimal("999")
li.agreement.net.basis_quantity = (Decimal("1.0000"), "C62") # C62 == unit
li.delivery.billed_quantity = (Decimal("1.0000"), "C62") # C62 == unit
li.settlement.trade_tax.type_code = "VAT"
li.settlement.trade_tax.category_code = "E"
li.settlement.trade_tax.rate_applicable_percent = Decimal("0.00")
li.settlement.trade_tax.category_code = "S"
li.settlement.trade_tax.rate_applicable_percent = Decimal("20.00")
li.settlement.monetary_summation.total_amount = Decimal("999.00")
doc.trade.items.add(li)

trade_tax = ApplicableTradeTax()
trade_tax.calculated_amount = Decimal("0.00")
trade_tax.calculated_amount = Decimal("199.80")
trade_tax.basis_amount = Decimal("999.00")
trade_tax.type_code = "VAT"
trade_tax.category_code = "AE"
trade_tax.exemption_reason_code = 'VATEX-EU-AE'
trade_tax.rate_applicable_percent = Decimal("0.00")
trade_tax.category_code = "S"
trade_tax.rate_applicable_percent = Decimal("20.00")
doc.trade.settlement.trade_tax.add(trade_tax)

doc.trade.settlement.monetary_summation.line_total = Decimal("999.00")
doc.trade.settlement.monetary_summation.charge_total = Decimal("0.00")
doc.trade.settlement.monetary_summation.allowance_total = Decimal("0.00")
doc.trade.settlement.monetary_summation.tax_basis_total = Decimal("999.00")
doc.trade.settlement.monetary_summation.tax_total = Decimal("0.00")
doc.trade.settlement.monetary_summation.grand_total = Decimal("999.00")
doc.trade.settlement.monetary_summation.due_amount = Decimal("999.00")
doc.trade.settlement.monetary_summation.tax_total = (Decimal("199.80"), "EUR")
doc.trade.settlement.monetary_summation.grand_total = Decimal("1198.8")
doc.trade.settlement.monetary_summation.due_amount = Decimal("1198.8")

terms = PaymentTerms()
terms.due = datetime.now(timezone.utc) + timedelta(days=30)
doc.trade.settlement.terms.add(terms)

# Generate XML file
xml = doc.serialize(schema="FACTUR-X_EXTENDED")

.. [[[end]]]

# Attach XML to an existing PDF.
# Note that the existing PDF should be compliant to PDF/A-3!
# You can validate this here: https://www.pdf-online.com/osa/validate.aspx
Expand Down
83 changes: 83 additions & 0 deletions example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
from datetime import date, datetime, timedelta, timezone
from decimal import Decimal

from drafthorse.models.accounting import ApplicableTradeTax
from drafthorse.models.document import Document
from drafthorse.models.note import IncludedNote
from drafthorse.models.party import TaxRegistration
from drafthorse.models.payment import PaymentMeans, PaymentTerms
from drafthorse.models.trade import AdvancePayment, IncludedTradeTax
from drafthorse.models.tradelines import LineItem
from drafthorse.pdf import attach_xml

# Build data structure
doc = Document()
doc.context.guideline_parameter.id = "urn:cen.eu:en16931:2017"
doc.header.id = "RE1337"
doc.header.type_code = "380"
doc.header.issue_date_time = date.today()

doc.header.notes.add(IncludedNote(content="Test Note 1"))

doc.trade.agreement.buyer.name = "Kunde GmbH"
doc.trade.agreement.buyer.address.country_id = "DE"

doc.trade.settlement.currency_code = "EUR"
doc.trade.settlement.payment_means.add(PaymentMeans(type_code="ZZZ"))

doc.trade.agreement.seller.name = "Lieferant GmbH"
doc.trade.agreement.seller.address.country_id = "DE"
doc.trade.agreement.seller.address.country_subdivision = "Bayern"
doc.trade.agreement.seller.tax_registrations.add(
TaxRegistration(id=("VA", "DE000000000"))
)

advance = AdvancePayment(
received_date=datetime.now(timezone.utc), paid_amount=Decimal(42)
)
advance.included_trade_tax.add(
IncludedTradeTax(
calculated_amount=Decimal(0),
type_code="VAT",
category_code="E",
rate_applicable_percent=Decimal(0),
)
)
doc.trade.settlement.advance_payment.add(advance)

li = LineItem()
li.document.line_id = "1"
li.product.name = "Rainbow"
li.agreement.gross.amount = Decimal("1198.8")
li.agreement.gross.basis_quantity = (Decimal("1.0000"), "C62") # C62 == unit
li.agreement.net.amount = Decimal("999")
li.agreement.net.basis_quantity = (Decimal("1.0000"), "C62") # C62 == unit
li.delivery.billed_quantity = (Decimal("1.0000"), "C62") # C62 == unit
li.settlement.trade_tax.type_code = "VAT"
li.settlement.trade_tax.category_code = "S"
li.settlement.trade_tax.rate_applicable_percent = Decimal("20.00")
li.settlement.monetary_summation.total_amount = Decimal("999.00")
doc.trade.items.add(li)

trade_tax = ApplicableTradeTax()
trade_tax.calculated_amount = Decimal("199.80")
trade_tax.basis_amount = Decimal("999.00")
trade_tax.type_code = "VAT"
trade_tax.category_code = "S"
trade_tax.rate_applicable_percent = Decimal("20.00")
doc.trade.settlement.trade_tax.add(trade_tax)

doc.trade.settlement.monetary_summation.line_total = Decimal("999.00")
doc.trade.settlement.monetary_summation.charge_total = Decimal("0.00")
doc.trade.settlement.monetary_summation.allowance_total = Decimal("0.00")
doc.trade.settlement.monetary_summation.tax_basis_total = Decimal("999.00")
doc.trade.settlement.monetary_summation.tax_total = (Decimal("199.80"), "EUR")
doc.trade.settlement.monetary_summation.grand_total = Decimal("1198.8")
doc.trade.settlement.monetary_summation.due_amount = Decimal("1198.8")

terms = PaymentTerms()
terms.due = datetime.now(timezone.utc) + timedelta(days=30)
doc.trade.settlement.terms.add(terms)

# Generate XML file
xml = doc.serialize(schema="FACTUR-X_EXTENDED")
1 change: 1 addition & 0 deletions requirements_dev.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
cogapp
lxml
pypdf
pytest
Expand Down
71 changes: 1 addition & 70 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,79 +1,10 @@
import os
import pytest
from datetime import date, datetime, timezone
from decimal import Decimal

from drafthorse.models.accounting import ApplicableTradeTax
from drafthorse.models.document import Document
from drafthorse.models.note import IncludedNote
from drafthorse.models.party import TaxRegistration
from drafthorse.models.tradelines import LineItem
from example import doc


@pytest.fixture
def invoice_document(request):
doc = Document()
doc.context.guideline_parameter.id = (
"urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended"
)
doc.header.id = "RE1337"
doc.header.type_code = request.param
doc.header.name = "RECHNUNG"
doc.header.issue_date_time = date.today()
doc.header.language = "ger"

doc.header.notes.add(IncludedNote(content="Test Note 1"))

doc.trade.agreement.seller.name = "Lieferant GmbH"
doc.trade.settlement.payee.name = "Lieferant GmbH"

doc.trade.agreement.buyer.name = "Kunde GmbH"
doc.trade.settlement.invoicee.name = "Kunde GmbH"

doc.trade.settlement.currency_code = "EUR"
doc.trade.settlement.payment_means.type_code = "ZZZ"

doc.trade.agreement.seller.address.country_id = "DE"
doc.trade.agreement.seller.address.country_subdivision = "Bayern"
doc.trade.agreement.seller.tax_registrations.add(
TaxRegistration(id=("VA", "DE000000000"))
)

doc.trade.agreement.seller_order.issue_date_time = datetime.now(timezone.utc)
doc.trade.agreement.buyer_order.issue_date_time = datetime.now(timezone.utc)
doc.trade.settlement.advance_payment.received_date = datetime.now(timezone.utc)
doc.trade.agreement.customer_order.issue_date_time = datetime.now(timezone.utc)

li = LineItem()
li.document.line_id = "1"
li.product.name = "Rainbow"
li.agreement.gross.amount = Decimal("999.00")
li.agreement.gross.basis_quantity = (Decimal("1.0000"), "C62") # C62 == pieces
li.agreement.net.amount = Decimal("999.00")
li.agreement.net.basis_quantity = (Decimal("999.00"), "C62")
li.delivery.billed_quantity = (Decimal("1.0000"), "C62") # C62 == pieces
li.settlement.trade_tax.type_code = "VAT"
li.settlement.trade_tax.category_code = "E"
li.settlement.trade_tax.rate_applicable_percent = Decimal("0.00")
li.settlement.monetary_summation.total_amount = Decimal("999.00")
doc.trade.items.add(li)

trade_tax = ApplicableTradeTax()
trade_tax.calculated_amount = Decimal("0.00")
trade_tax.basis_amount = Decimal("999.00")
trade_tax.type_code = "VAT"
trade_tax.category_code = "E"
trade_tax.rate_applicable_percent = Decimal("0.00")
doc.trade.settlement.trade_tax.add(trade_tax)

doc.trade.settlement.monetary_summation.line_total = Decimal("999.00")
doc.trade.settlement.monetary_summation.charge_total = Decimal("0.00")
doc.trade.settlement.monetary_summation.allowance_total = Decimal("0.00")
doc.trade.settlement.monetary_summation.tax_basis_total = Decimal("999.00")
doc.trade.settlement.monetary_summation.tax_total = (Decimal("0.00"), "EUR")
doc.trade.settlement.monetary_summation.grand_total = Decimal("999.00")
doc.trade.settlement.monetary_summation.due_amount = Decimal("999.00")

return doc


Expand Down