export xrechnung 2.1 ok + test
This commit is contained in:
parent
7e35688043
commit
1306f2a339
6 changed files with 152 additions and 60 deletions
69
edocument.py
69
edocument.py
|
@ -15,25 +15,88 @@ class Invoice(Invoice):
|
||||||
'EDocument XRechnung'
|
'EDocument XRechnung'
|
||||||
__name__ = 'edocument.xrechnung.invoice'
|
__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):
|
def prepaid_amount(self, invoice):
|
||||||
""" compute already paid amount
|
""" compute already paid amount
|
||||||
"""
|
"""
|
||||||
return invoice.total_amount - invoice.amount_to_pay
|
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):
|
def tax_rate(self, tax):
|
||||||
""" get tax-rate in procent
|
""" 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):
|
def tax_category_code(self, tax):
|
||||||
""" read tax-category, fire exception if missing
|
""" 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(
|
raise UserError(gettext(
|
||||||
'edocument_xrechnung.mds_tax_category_missing',
|
'edocument_xrechnung.mds_tax_category_missing',
|
||||||
taxname = tax.rec_name,
|
taxname = tax.rec_name,
|
||||||
))
|
))
|
||||||
return tax.tax.unece_category_code
|
return tax.unece_category_code
|
||||||
|
|
||||||
def quote_text(self, text):
|
def quote_text(self, text):
|
||||||
""" replace critical chars
|
""" replace critical chars
|
||||||
|
|
12
locale/de.po
12
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'."
|
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."
|
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 #
|
# party.configuration #
|
||||||
|
|
|
@ -11,6 +11,15 @@ full copyright notices and license terms. -->
|
||||||
<record model="ir.message" id="mds_tax_category_missing">
|
<record model="ir.message" id="mds_tax_category_missing">
|
||||||
<field name="text">The UNECE tax category is not configured for tax '%(taxname)s'.</field>
|
<field name="text">The UNECE tax category is not configured for tax '%(taxname)s'.</field>
|
||||||
</record>
|
</record>
|
||||||
|
<record model="ir.message" id="msg_uom_code_missing">
|
||||||
|
<field name="text">The UNECE uom code is not configured for unit '%(uomname)s'.</field>
|
||||||
|
</record>
|
||||||
|
<record model="ir.message" id="msg_linetax_invalid_number">
|
||||||
|
<field name="text">The invoice line '%(linename)s' must have exactly one tax (number of taxes currently: %(numtax)d).</field>
|
||||||
|
</record>
|
||||||
|
<record model="ir.message" id="msg_linetax_invalid_catcode">
|
||||||
|
<field name="text">Invalid category code at tax '%(taxname)s' (allowed: %(allowed)s).</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
</tryton>
|
</tryton>
|
||||||
|
|
|
@ -17,56 +17,88 @@
|
||||||
<cbc:IdentificationCode>${getattr(getattr(value, 'country', None), 'code', None)}</cbc:IdentificationCode>
|
<cbc:IdentificationCode>${getattr(getattr(value, 'country', None), 'code', None)}</cbc:IdentificationCode>
|
||||||
</cac:Country>
|
</cac:Country>
|
||||||
</py:def>
|
</py:def>
|
||||||
|
|
||||||
<py:def function="PartyTaxScheme(value)">
|
<py:def function="PartyTaxScheme(value)">
|
||||||
<cbc:CompanyID>${getattr(value, 'code', None)}</cbc:CompanyID>
|
<cbc:CompanyID>${this.taxident_data(value)['code']}</cbc:CompanyID>
|
||||||
<cac:TaxScheme>
|
<cac:TaxScheme>
|
||||||
<cbc:ID>VAT</cbc:ID>
|
<cbc:ID>${this.taxident_data(value)['id']}</cbc:ID>
|
||||||
</cac:TaxScheme>
|
</cac:TaxScheme>
|
||||||
</py:def>
|
</py:def>
|
||||||
|
|
||||||
<py:def function="Contact(value)">
|
<py:def function="Contact(value)">
|
||||||
<cbc:Name>${value.name}</cbc:Name>
|
<cbc:Name>${value.name}</cbc:Name>
|
||||||
<cbc:Telephone>${value.phone}</cbc:Telephone>
|
<cbc:Telephone>${value.phone}</cbc:Telephone>
|
||||||
<cbc:ElectronicMail>${value.email}</cbc:ElectronicMail>
|
<cbc:ElectronicMail>${value.email}</cbc:ElectronicMail>
|
||||||
</py:def>
|
</py:def>
|
||||||
|
|
||||||
<py:def function="PartyLegalEntity(value, company_id=True)">
|
<py:def function="PartyLegalEntity(value, company_id=True)">
|
||||||
<cbc:RegistrationName>${value.name}</cbc:RegistrationName>
|
<cbc:RegistrationName>${value.name}</cbc:RegistrationName>
|
||||||
<cbc:CompanyID py:if="company_id">${getattr(this.seller_trade_tax_identifier, 'code', None)}</cbc:CompanyID>
|
<cbc:CompanyID py:if="company_id">${this.taxident_data(this.seller_trade_tax_identifier)['code']}</cbc:CompanyID>
|
||||||
</py:def>
|
</py:def>
|
||||||
|
|
||||||
<py:def function="PayeeFinancialAccount(value)">
|
<py:def function="PayeeFinancialAccount(value)">
|
||||||
<py:if test="len(value.bank_accounts)>0">
|
<py:if test="len(value.bank_accounts)>0">
|
||||||
<cbc:ID>${value.bank_accounts[0].numbers[0].number_compact}</cbc:ID>
|
<cbc:ID>${value.bank_accounts[0].numbers[0].number_compact}</cbc:ID>
|
||||||
<cbc:Name>${value.name}</cbc:Name>
|
<cbc:Name>${value.name}</cbc:Name>
|
||||||
</py:if>
|
</py:if>
|
||||||
</py:def>
|
</py:def>
|
||||||
|
|
||||||
|
<py:def function="TaxCategory(value, incl_reason=False)">
|
||||||
|
<cbc:ID>${this.tax_category_code(value)}</cbc:ID>
|
||||||
|
<cbc:Percent>${this.tax_rate(value)}</cbc:Percent>
|
||||||
|
<cbc:TaxExemptionReason
|
||||||
|
py:if="(this.tax_category_code(value) in ['E']) and (incl_reason==True)">${value.legal_notice or '-'}</cbc:TaxExemptionReason>
|
||||||
|
<cac:TaxScheme>
|
||||||
|
<cbc:ID>VAT</cbc:ID>
|
||||||
|
</cac:TaxScheme>
|
||||||
|
</py:def>
|
||||||
|
|
||||||
<py:def function="TaxSubTotal(value)">
|
<py:def function="TaxSubTotal(value)">
|
||||||
<cac:TaxSubtotal>
|
<cac:TaxSubtotal>
|
||||||
<cbc:TaxableAmount py:attrs="{'currencyID': value.currency.code}">${value.base}</cbc:TaxableAmount>
|
<cbc:TaxableAmount py:attrs="{'currencyID': value.currency.code}">${value.base}</cbc:TaxableAmount>
|
||||||
<cbc:TaxAmount py:attrs="{'currencyID': value.currency.code}">${value.amount}</cbc:TaxAmount>
|
<cbc:TaxAmount py:attrs="{'currencyID': value.currency.code}">${value.amount}</cbc:TaxAmount>
|
||||||
<cac:TaxCategory>
|
<cac:TaxCategory>
|
||||||
<cbc:ID>${this.tax_category_code(value)}</cbc:ID>
|
${TaxCategory(value.tax, True)}
|
||||||
<cbc:Percent>${this.tax_rate(value)}</cbc:Percent>
|
|
||||||
<cac:TaxScheme>
|
|
||||||
<cbc:ID>VAT</cbc:ID>
|
|
||||||
</cac:TaxScheme>
|
|
||||||
</cac:TaxCategory>
|
</cac:TaxCategory>
|
||||||
</cac:TaxSubtotal>
|
</cac:TaxSubtotal>
|
||||||
</py:def>
|
</py:def>
|
||||||
|
|
||||||
|
<py:def function="InvoiceLine(value)">
|
||||||
|
<cac:InvoiceLine>
|
||||||
|
<cbc:ID>${value.id}</cbc:ID>
|
||||||
|
<cbc:InvoicedQuantity py:attrs="{'unitCode': this.uom_unece_code(value)}">${value.quantity}</cbc:InvoicedQuantity>
|
||||||
|
<cbc:LineExtensionAmount py:attrs="{'currencyID': value.currency.code}">${value.amount}</cbc:LineExtensionAmount>
|
||||||
|
<cac:Item>
|
||||||
|
<cbc:Name>${value.description or getattr(value.product, 'name', None)}</cbc:Name>
|
||||||
|
<cac:SellersItemIdentification py:if="getattr(value.product, 'code', None)">
|
||||||
|
<cbc:ID>${value.product.code}</cbc:ID>
|
||||||
|
</cac:SellersItemIdentification>
|
||||||
|
<cac:ClassifiedTaxCategory>
|
||||||
|
${TaxCategory(this.invoice_line_tax(value))}
|
||||||
|
</cac:ClassifiedTaxCategory>
|
||||||
|
</cac:Item>
|
||||||
|
<cac:Price>
|
||||||
|
<cbc:PriceAmount py:attrs="{'currencyID': value.currency.code}">${value.unit_price}</cbc:PriceAmount>
|
||||||
|
</cac:Price>
|
||||||
|
</cac:InvoiceLine>
|
||||||
|
</py:def>
|
||||||
|
|
||||||
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.1</cbc:CustomizationID>
|
<cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.1</cbc:CustomizationID>
|
||||||
<cbc:ID>${this.invoice.number}</cbc:ID>
|
<cbc:ID>${this.invoice.number}</cbc:ID>
|
||||||
<cbc:IssueDate>${this.invoice.invoice_date.isoformat()}</cbc:IssueDate>
|
<cbc:IssueDate>${this.invoice.invoice_date.isoformat()}</cbc:IssueDate>
|
||||||
<cbc:DueDate>${(getattr(this.invoice, 'payment_term_date', None) or this.invoice.invoice_date).isoformat()}</cbc:DueDate>
|
<cbc:DueDate>${(getattr(this.invoice, 'payment_term_date', None) or this.invoice.invoice_date).isoformat()}</cbc:DueDate>
|
||||||
<cbc:InvoiceTypeCode>${this.type_code}</cbc:InvoiceTypeCode>
|
<cbc:InvoiceTypeCode>${this.type_code}</cbc:InvoiceTypeCode>
|
||||||
|
<cbc:Note py:if="this.invoice_note()">${this.invoice_note()}</cbc:Note>
|
||||||
<cbc:DocumentCurrencyCode>${this.invoice.currency.code}</cbc:DocumentCurrencyCode>
|
<cbc:DocumentCurrencyCode>${this.invoice.currency.code}</cbc:DocumentCurrencyCode>
|
||||||
<cbc:BuyerReference>${this.invoice.party.get_xrechnung_route_id()}</cbc:BuyerReference>
|
<cbc:BuyerReference>${this.invoice.party.get_xrechnung_route_id()}</cbc:BuyerReference>
|
||||||
<cac:OrderReference>
|
<cac:OrderReference py:if="this.invoice.reference">
|
||||||
<cbc:ID>bestell-nr</cbc:ID>
|
<cbc:ID>${this.invoice.reference}</cbc:ID>
|
||||||
<cbc:SalesOrderID>auftrags-nr</cbc:SalesOrderID>
|
<cbc:SalesOrderID py:if="this.sales_order_nums()">${this.sales_order_nums()}</cbc:SalesOrderID>
|
||||||
</cac:OrderReference>
|
</cac:OrderReference>
|
||||||
<cac:ContractDocumentReference>
|
<cac:ContractDocumentReference py:if="False">
|
||||||
<cbc:ID>vertrags-nr</cbc:ID>
|
<cbc:ID>vertrags-nr</cbc:ID>
|
||||||
</cac:ContractDocumentReference>
|
</cac:ContractDocumentReference>
|
||||||
<cac:ProjectReference>
|
<cac:ProjectReference py:if="False">
|
||||||
<cbc:ID>proj-referenz</cbc:ID>
|
<cbc:ID>proj-referenz</cbc:ID>
|
||||||
</cac:ProjectReference>
|
</cac:ProjectReference>
|
||||||
<cac:AccountingSupplierParty>
|
<cac:AccountingSupplierParty>
|
||||||
|
@ -137,50 +169,11 @@
|
||||||
<cbc:TaxExclusiveAmount py:attrs="{'currencyID': this.invoice.currency.code}">${this.invoice.untaxed_amount}</cbc:TaxExclusiveAmount>
|
<cbc:TaxExclusiveAmount py:attrs="{'currencyID': this.invoice.currency.code}">${this.invoice.untaxed_amount}</cbc:TaxExclusiveAmount>
|
||||||
<cbc:TaxInclusiveAmount py:attrs="{'currencyID': this.invoice.currency.code}">${this.invoice.total_amount}</cbc:TaxInclusiveAmount>
|
<cbc:TaxInclusiveAmount py:attrs="{'currencyID': this.invoice.currency.code}">${this.invoice.total_amount}</cbc:TaxInclusiveAmount>
|
||||||
<cbc:AllowanceTotalAmount py:if="False" py:attrs="{'currencyID': this.invoice.currency.code}">0.00</cbc:AllowanceTotalAmount>
|
<cbc:AllowanceTotalAmount py:if="False" py:attrs="{'currencyID': this.invoice.currency.code}">0.00</cbc:AllowanceTotalAmount>
|
||||||
<cbc:ChargeTotalAmount py:attrs="{'currencyID': this.invoice.currency.code}">0.00</cbc:ChargeTotalAmount>
|
<cbc:ChargeTotalAmount py:if="False" py:attrs="{'currencyID': this.invoice.currency.code}">0.00</cbc:ChargeTotalAmount>
|
||||||
<cbc:PrepaidAmount py:attrs="{'currencyID': this.invoice.currency.code}">${this.prepaid_amount(this.invoice)}</cbc:PrepaidAmount>
|
<cbc:PrepaidAmount py:attrs="{'currencyID': this.invoice.currency.code}">${this.prepaid_amount(this.invoice)}</cbc:PrepaidAmount>
|
||||||
<cbc:PayableAmount py:attrs="{'currencyID': this.invoice.currency.code}">${this.invoice.amount_to_pay}</cbc:PayableAmount>
|
<cbc:PayableAmount py:attrs="{'currencyID': this.invoice.currency.code}">${this.invoice.amount_to_pay}</cbc:PayableAmount>
|
||||||
</cac:LegalMonetaryTotal>
|
</cac:LegalMonetaryTotal>
|
||||||
<cac:InvoiceLine>
|
<py:for each="line in this.lines">
|
||||||
<cbc:ID>1</cbc:ID>
|
${InvoiceLine(line)}
|
||||||
<cbc:InvoicedQuantity unitCode="C62">0.5</cbc:InvoicedQuantity>
|
</py:for>
|
||||||
<cbc:LineExtensionAmount currencyID="EUR">35.00</cbc:LineExtensionAmount>
|
|
||||||
<cac:Item>
|
|
||||||
<cbc:Name>Reparaturdienstleistung in Stunden</cbc:Name>
|
|
||||||
<cac:SellersItemIdentification>
|
|
||||||
<cbc:ID>REP-012</cbc:ID>
|
|
||||||
</cac:SellersItemIdentification>
|
|
||||||
<cac:ClassifiedTaxCategory>
|
|
||||||
<cbc:ID>S</cbc:ID>
|
|
||||||
<cbc:Percent>19.00</cbc:Percent>
|
|
||||||
<cac:TaxScheme>
|
|
||||||
<cbc:ID>VAT</cbc:ID>
|
|
||||||
</cac:TaxScheme>
|
|
||||||
</cac:ClassifiedTaxCategory>
|
|
||||||
</cac:Item>
|
|
||||||
<cac:Price>
|
|
||||||
<cbc:PriceAmount currencyID="EUR">70.00</cbc:PriceAmount>
|
|
||||||
</cac:Price>
|
|
||||||
</cac:InvoiceLine>
|
|
||||||
<cac:InvoiceLine>
|
|
||||||
<cbc:ID>2</cbc:ID>
|
|
||||||
<cbc:InvoicedQuantity unitCode="C62">3</cbc:InvoicedQuantity>
|
|
||||||
<cbc:LineExtensionAmount currencyID="EUR">5.25</cbc:LineExtensionAmount>
|
|
||||||
<cac:Item>
|
|
||||||
<cbc:Name>Material</cbc:Name>
|
|
||||||
<cac:SellersItemIdentification>
|
|
||||||
<cbc:ID>MAT-987</cbc:ID>
|
|
||||||
</cac:SellersItemIdentification>
|
|
||||||
<cac:ClassifiedTaxCategory>
|
|
||||||
<cbc:ID>S</cbc:ID>
|
|
||||||
<cbc:Percent>19.00</cbc:Percent>
|
|
||||||
<cac:TaxScheme>
|
|
||||||
<cbc:ID>VAT</cbc:ID>
|
|
||||||
</cac:TaxScheme>
|
|
||||||
</cac:ClassifiedTaxCategory>
|
|
||||||
</cac:Item>
|
|
||||||
<cac:Price>
|
|
||||||
<cbc:PriceAmount currencyID="EUR">1.75</cbc:PriceAmount>
|
|
||||||
</cac:Price>
|
|
||||||
</cac:InvoiceLine>
|
|
||||||
</ubl:Invoice>
|
</ubl:Invoice>
|
||||||
|
|
|
@ -7,6 +7,7 @@ from trytond.tests.test_tryton import ModuleTestCase, with_transaction
|
||||||
from trytond.pool import Pool
|
from trytond.pool import Pool
|
||||||
from trytond.modules.edocument_uncefact.tests.test_edocument_uncefact import get_invoice
|
from trytond.modules.edocument_uncefact.tests.test_edocument_uncefact import get_invoice
|
||||||
from unittest.mock import Mock, MagicMock
|
from unittest.mock import Mock, MagicMock
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
|
|
||||||
class EdocTestCase(ModuleTestCase):
|
class EdocTestCase(ModuleTestCase):
|
||||||
|
@ -21,9 +22,23 @@ class EdocTestCase(ModuleTestCase):
|
||||||
Template = pool.get('edocument.xrechnung.invoice')
|
Template = pool.get('edocument.xrechnung.invoice')
|
||||||
Address = pool.get('party.address')
|
Address = pool.get('party.address')
|
||||||
Identifier = pool.get('party.identifier')
|
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 = get_invoice()
|
||||||
invoice.party.get_xrechnung_route_id = Mock(return_value='xrechn-route-id-123')
|
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 = [
|
invoice.identifiers = [
|
||||||
Mock(spec=Identifier,
|
Mock(spec=Identifier,
|
||||||
type='edoc_route_id',
|
type='edoc_route_id',
|
||||||
|
|
|
@ -3,7 +3,7 @@ version=6.0.0
|
||||||
depends:
|
depends:
|
||||||
edocument_uncefact
|
edocument_uncefact
|
||||||
party
|
party
|
||||||
#extras_depend:
|
bank
|
||||||
account_invoice
|
account_invoice
|
||||||
xml:
|
xml:
|
||||||
message.xml
|
message.xml
|
||||||
|
|
Loading…
Reference in a new issue