diff --git a/edocument.py b/edocument.py
index a61ea94..44b4123 100644
--- a/edocument.py
+++ b/edocument.py
@@ -15,25 +15,88 @@ class Invoice(Invoice):
'EDocument XRechnung'
__name__ = 'edocument.xrechnung.invoice'
+ def sales_order_nums(self):
+ """ get string of sale-numbers
+ """
+ if getattr(self.invoice, 'sales', None) is not None:
+ return ', '.join([x.number for x in self.invoice.sales])
+
def prepaid_amount(self, invoice):
""" compute already paid amount
"""
return invoice.total_amount - invoice.amount_to_pay
+ def invoice_note(self):
+ """ get 'description' + 'comment'
+ """
+ notes = []
+ if self.invoice.description:
+ notes.append(self.invoice.description)
+
+ if self.invoice.comment:
+ notes.extend(self.invoice.comment.split('\n'))
+ if len(notes) > 0:
+ return '; '.join(notes)
+
+ def invoice_line_tax(self, line):
+ """ get tax of invoice-line,
+ fire exception if no/multiple taxes exists
+ """
+ if len(line.invoice_taxes) != 1:
+ raise UserError(gettext(
+ 'edocument_xrechnung.msg_linetax_invalid_number',
+ linename = line.rec_name,
+ numtax = len(line.invoice_taxes),
+ ))
+
+ allowed_cat = ['AE', 'L', 'M', 'E', 'S', 'Z', 'G', 'O', 'K', 'B']
+ if not line.invoice_taxes[0].tax.unece_category_code in allowed_cat:
+ raise UserError(gettext(
+ 'edocument_xrechnung.msg_linetax_invalid_catcode',
+ taxname = line.invoice_taxes[0].tax.rec_name,
+ allowed = ', '.join(allowed_cat),
+ ))
+
+ return line.invoice_taxes[0].tax
+
+ def taxident_data(self, tax_identifier):
+ """ get tax-scheme-id and codes
+ """
+ result = {
+ 'code': None,
+ 'id': None,
+ }
+
+ if tax_identifier:
+ if tax_identifier.type == 'de_vat':
+ result['code'] = 'DE%s' % tax_identifier.code
+ result['id'] = 'VAT'
+ return result
+
def tax_rate(self, tax):
""" get tax-rate in procent
"""
- return (tax.tax.rate * Decimal('100.0')).quantize(Decimal('0.01'))
+ return (tax.rate * Decimal('100.0')).quantize(Decimal('0.01'))
+
+ def uom_unece_code(self, line):
+ """ 'line': invoice.line
+ """
+ if len(line.unit.unece_code or '') == 0:
+ raise UserError(gettext(
+ 'edocument_xrechnung.msg_uom_code_missing',
+ uomname = line.unit.rec_name,
+ ))
+ return line.unit.unece_code
def tax_category_code(self, tax):
""" read tax-category, fire exception if missing
"""
- if len(tax.tax.unece_category_code or '') == 0:
+ if len(tax.unece_category_code or '') == 0:
raise UserError(gettext(
'edocument_xrechnung.mds_tax_category_missing',
taxname = tax.rec_name,
))
- return tax.tax.unece_category_code
+ return tax.unece_category_code
def quote_text(self, text):
""" replace critical chars
diff --git a/locale/de.po b/locale/de.po
index 691c523..8eed6b4 100644
--- a/locale/de.po
+++ b/locale/de.po
@@ -14,6 +14,18 @@ msgctxt "model:ir.message,text:mds_tax_category_missing"
msgid "The UNECE tax category is not configured for tax '%(taxname)s'."
msgstr "Für die Steuer '%(taxname)s' ist die UNECE-Steuerkategorie nicht konfiguriert."
+msgctxt "model:ir.message,text:msg_uom_code_missing"
+msgid "The UNECE uom code is not configured for unit '%(uomname)s'."
+msgstr "Für die Einheit '%(uomname)s' ist der UNECE-Einheitencode nicht konfiguriert."
+
+msgctxt "model:ir.message,text:msg_linetax_invalid_number"
+msgid "The invoice line '%(linename)s' must have exactly one tax (number of taxes currently: %(numtax)d)."
+msgstr "Die Rechnungszeile '%(linename)s' muß genau eine Steuer haben (Anzahl Steuern derzeit: %(numtax)d)."
+
+msgctxt "model:ir.message,text:msg_linetax_invalid_catcode"
+msgid "Invalid category code at tax '%(taxname)s' (allowed: %(allowed)s)."
+msgstr "Ungültiger Kategoriecode an der Steuer '%(taxname)s' (erlaubt: %(allowed)s)."
+
#######################
# party.configuration #
diff --git a/message.xml b/message.xml
index ec96f4c..4105e7c 100644
--- a/message.xml
+++ b/message.xml
@@ -11,6 +11,15 @@ full copyright notices and license terms. -->
The UNECE tax category is not configured for tax '%(taxname)s'.
+
+ The UNECE uom code is not configured for unit '%(uomname)s'.
+
+
+ The invoice line '%(linename)s' must have exactly one tax (number of taxes currently: %(numtax)d).
+
+
+ Invalid category code at tax '%(taxname)s' (allowed: %(allowed)s).
+
diff --git a/template/XRechnung-2.2/XRechnung.xml b/template/XRechnung-2.2/XRechnung.xml
index 6c6d5f8..b07ad43 100644
--- a/template/XRechnung-2.2/XRechnung.xml
+++ b/template/XRechnung-2.2/XRechnung.xml
@@ -17,56 +17,88 @@
${getattr(getattr(value, 'country', None), 'code', None)}
+
- ${getattr(value, 'code', None)}
+ ${this.taxident_data(value)['code']}
- VAT
+ ${this.taxident_data(value)['id']}
+
${value.name}
${value.phone}
${value.email}
+
${value.name}
- ${getattr(this.seller_trade_tax_identifier, 'code', None)}
+ ${this.taxident_data(this.seller_trade_tax_identifier)['code']}
+
${value.bank_accounts[0].numbers[0].number_compact}
${value.name}
+
+
+ ${this.tax_category_code(value)}
+ ${this.tax_rate(value)}
+ ${value.legal_notice or '-'}
+
+ VAT
+
+
+
${value.base}
${value.amount}
- ${this.tax_category_code(value)}
- ${this.tax_rate(value)}
-
- VAT
-
+ ${TaxCategory(value.tax, True)}
+
+
+ ${value.id}
+ ${value.quantity}
+ ${value.amount}
+
+ ${value.description or getattr(value.product, 'name', None)}
+
+ ${value.product.code}
+
+
+ ${TaxCategory(this.invoice_line_tax(value))}
+
+
+
+ ${value.unit_price}
+
+
+
+
urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.1
${this.invoice.number}
${this.invoice.invoice_date.isoformat()}
${(getattr(this.invoice, 'payment_term_date', None) or this.invoice.invoice_date).isoformat()}
${this.type_code}
+ ${this.invoice_note()}
${this.invoice.currency.code}
${this.invoice.party.get_xrechnung_route_id()}
-
- bestell-nr
- auftrags-nr
+
+ ${this.invoice.reference}
+ ${this.sales_order_nums()}
-
+
vertrags-nr
-
+
proj-referenz
@@ -137,50 +169,11 @@
${this.invoice.untaxed_amount}
${this.invoice.total_amount}
0.00
- 0.00
+ 0.00
${this.prepaid_amount(this.invoice)}
${this.invoice.amount_to_pay}
-
- 1
- 0.5
- 35.00
-
- Reparaturdienstleistung in Stunden
-
- REP-012
-
-
- S
- 19.00
-
- VAT
-
-
-
-
- 70.00
-
-
-
- 2
- 3
- 5.25
-
- Material
-
- MAT-987
-
-
- S
- 19.00
-
- VAT
-
-
-
-
- 1.75
-
-
+
+ ${InvoiceLine(line)}
+
diff --git a/tests/test_edocument.py b/tests/test_edocument.py
index fcae41f..c2cdad8 100644
--- a/tests/test_edocument.py
+++ b/tests/test_edocument.py
@@ -7,6 +7,7 @@ from trytond.tests.test_tryton import ModuleTestCase, with_transaction
from trytond.pool import Pool
from trytond.modules.edocument_uncefact.tests.test_edocument_uncefact import get_invoice
from unittest.mock import Mock, MagicMock
+from decimal import Decimal
class EdocTestCase(ModuleTestCase):
@@ -21,9 +22,23 @@ class EdocTestCase(ModuleTestCase):
Template = pool.get('edocument.xrechnung.invoice')
Address = pool.get('party.address')
Identifier = pool.get('party.identifier')
+ Party = pool.get('party.party')
+ Bank = pool.get('bank')
+ BankAccount = pool.get('bank.account')
+ BankNumber = pool.get('bank.account.number')
invoice = get_invoice()
invoice.party.get_xrechnung_route_id = Mock(return_value='xrechn-route-id-123')
+ invoice.company.party.bank_accounts = [
+ Mock(spec=BankAccount,
+ currency=invoice.currency,
+ bank=Mock(spec=Bank, party=Mock(spec=Party, name='Bank')),
+ owners = [invoice.company.party],
+ numbers = [Mock(spec=BankNumber, type='other', number='123456')],
+ )]
+ invoice.description = 'description of invoice'
+ invoice.comment = 'note line 1\nnote line 2'
+ invoice.taxes[0].tax.rate = Decimal('0.1')
invoice.identifiers = [
Mock(spec=Identifier,
type='edoc_route_id',
diff --git a/tryton.cfg b/tryton.cfg
index fec7d8f..5fc2311 100644
--- a/tryton.cfg
+++ b/tryton.cfg
@@ -3,7 +3,7 @@ version=6.0.0
depends:
edocument_uncefact
party
-#extras_depend:
+ bank
account_invoice
xml:
message.xml