line: import taxes, notes
This commit is contained in:
parent
18103d8e80
commit
174887f87e
4 changed files with 103 additions and 25 deletions
95
document.py
95
document.py
|
@ -6,15 +6,18 @@
|
||||||
# https://portal3.gefeg.com/projectdata/invoice/deliverables/installed/publishingproject/xrechnung%20%28german%20cius%29/xrechnung_crossindustryinvoice%3B%202017-10-18.scm/html/021.htm?https://portal3.gefeg.com/projectdata/invoice/deliverables/installed/publishingproject/xrechnung%20%28german%20cius%29/xrechnung_crossindustryinvoice%3B%202017-10-18.scm/html/025.htm
|
# https://portal3.gefeg.com/projectdata/invoice/deliverables/installed/publishingproject/xrechnung%20%28german%20cius%29/xrechnung_crossindustryinvoice%3B%202017-10-18.scm/html/021.htm?https://portal3.gefeg.com/projectdata/invoice/deliverables/installed/publishingproject/xrechnung%20%28german%20cius%29/xrechnung_crossindustryinvoice%3B%202017-10-18.scm/html/025.htm
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
|
import json
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from datetime import datetime, date
|
from datetime import datetime, date
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from trytond.pool import PoolMeta, Pool
|
from trytond.pool import PoolMeta, Pool
|
||||||
|
from trytond.report import Report
|
||||||
from trytond.transaction import Transaction
|
from trytond.transaction import Transaction
|
||||||
from trytond.exceptions import UserError
|
from trytond.exceptions import UserError
|
||||||
from trytond.i18n import gettext
|
from trytond.i18n import gettext
|
||||||
from trytond.model import fields
|
from trytond.model import fields
|
||||||
from trytond.pyson import Eval
|
from trytond.pyson import Eval
|
||||||
|
from trytond.protocols.jsonrpc import JSONEncoder
|
||||||
|
|
||||||
|
|
||||||
xml_types = [
|
xml_types = [
|
||||||
|
@ -410,21 +413,18 @@ class Incoming(metaclass=PoolMeta):
|
||||||
# get number of invoice-lines
|
# get number of invoice-lines
|
||||||
num_lines = len(xmltree.xpath(
|
num_lines = len(xmltree.xpath(
|
||||||
self._readxml_xpath(xpath_line_item), namespaces=xmltree.nsmap))
|
self._readxml_xpath(xpath_line_item), namespaces=xmltree.nsmap))
|
||||||
print('\n## num_lines:', num_lines)
|
|
||||||
lines_data = []
|
lines_data = []
|
||||||
for x in range(1, num_lines + 1):
|
for x in range(1, num_lines + 1):
|
||||||
lines_data.append(
|
lines_data.append(
|
||||||
self._readxml_invoice_line(xmltree, xpath_line_item, x))
|
self._readxml_invoice_line(xmltree, xpath_line_item, x))
|
||||||
print('\n## lines_data:', lines_data)
|
|
||||||
lines = [
|
lines = [
|
||||||
self._readxml_getinvoiceline(invoice, x)
|
self._readxml_getinvoiceline(invoice, x)
|
||||||
for x in lines_data]
|
for x in lines_data]
|
||||||
|
for x in range(len(lines)):
|
||||||
|
lines[x].sequence = x + 1
|
||||||
invoice.lines = lines
|
invoice.lines = lines
|
||||||
for pos in range(len(lines)):
|
|
||||||
invoice.lines[pos].on_change_account()
|
|
||||||
invoice.on_change_lines()
|
|
||||||
|
|
||||||
raise ValueError('stop')
|
invoice.on_change_lines()
|
||||||
return invoice
|
return invoice
|
||||||
|
|
||||||
def _readxml_getinvoiceline(self, invoice, line_data):
|
def _readxml_getinvoiceline(self, invoice, line_data):
|
||||||
|
@ -437,10 +437,11 @@ class Incoming(metaclass=PoolMeta):
|
||||||
pool = Pool()
|
pool = Pool()
|
||||||
Line = pool.get('account.invoice.line')
|
Line = pool.get('account.invoice.line')
|
||||||
Tax = pool.get('account.tax')
|
Tax = pool.get('account.tax')
|
||||||
|
Uom = pool.get('product.uom')
|
||||||
Configuration = pool.get('document.incoming.configuration')
|
Configuration = pool.get('document.incoming.configuration')
|
||||||
|
ModelData = pool.get('ir.model.data')
|
||||||
|
|
||||||
cfg1 = Configuration.get_singleton()
|
cfg1 = Configuration.get_singleton()
|
||||||
print('\n## line_data-vor:', line_data)
|
|
||||||
|
|
||||||
def get_tax_by_percent(percent):
|
def get_tax_by_percent(percent):
|
||||||
""" search for tax by percent of supplier tax
|
""" search for tax by percent of supplier tax
|
||||||
|
@ -453,7 +454,7 @@ class Incoming(metaclass=PoolMeta):
|
||||||
no matching tax was found
|
no matching tax was found
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
record: model 'account.tax
|
tuple: (model 'account.tax, model 'product.category')
|
||||||
"""
|
"""
|
||||||
if not (cfg1 and cfg1.product_category):
|
if not (cfg1 and cfg1.product_category):
|
||||||
raise UserError(gettext(
|
raise UserError(gettext(
|
||||||
|
@ -466,23 +467,34 @@ class Incoming(metaclass=PoolMeta):
|
||||||
current_taxes = Tax.compute(
|
current_taxes = Tax.compute(
|
||||||
[s_tax], Decimal('1'), 1.0, invoice.invoice_date)
|
[s_tax], Decimal('1'), 1.0, invoice.invoice_date)
|
||||||
|
|
||||||
# deny result of multiple or none taxes
|
# skip result of multiple or none taxes
|
||||||
if len(current_taxes) != 1:
|
if len(current_taxes) != 1:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if (current_taxes[0]['tax'].rate == percent) and (
|
if (current_taxes[0]['tax'].rate == percent) and (
|
||||||
current_taxes[0]['tax'].type == 'percentage'):
|
current_taxes[0]['tax'].type == 'percentage'):
|
||||||
# found it
|
# found it
|
||||||
return s_tax
|
return (s_tax, pcat)
|
||||||
|
|
||||||
# no product category found
|
# no product category found
|
||||||
raise UserError(gettext(
|
raise UserError(gettext(
|
||||||
'document_incoming_invoice_xml.msg_no_prodcat_found',
|
'document_incoming_invoice_xml.msg_no_prodcat_found',
|
||||||
percent=percent * Decimal('100.0')))
|
percent=percent * Decimal('100.0')))
|
||||||
|
|
||||||
|
# uom
|
||||||
|
xml_uom = Uom(ModelData.get_id('product', 'uom_unit'))
|
||||||
|
for x_attr in line_data.get('attributes', []):
|
||||||
|
x_uom = x_attr.get('uom', None)
|
||||||
|
if not x_uom:
|
||||||
|
continue
|
||||||
|
units = Uom.search([('symbol', '=', x_uom)])
|
||||||
|
if units:
|
||||||
|
xml_uom = units[0]
|
||||||
|
|
||||||
line = Line(
|
line = Line(
|
||||||
invoice=invoice,
|
invoice=invoice,
|
||||||
type='line',
|
type='line',
|
||||||
|
unit=xml_uom,
|
||||||
quantity=line_data.get('quantity', {}).pop('billed', None),
|
quantity=line_data.get('quantity', {}).pop('billed', None),
|
||||||
unit_price=line_data.get('unit_net_price', {}).pop('amount', None))
|
unit_price=line_data.get('unit_net_price', {}).pop('amount', None))
|
||||||
line_no = line_data.pop('line_no', None)
|
line_no = line_data.pop('line_no', None)
|
||||||
|
@ -494,40 +506,73 @@ class Incoming(metaclass=PoolMeta):
|
||||||
line_data.pop('description', None)]
|
line_data.pop('description', None)]
|
||||||
line.description = '; '.join([x for x in descr if x])
|
line.description = '; '.join([x for x in descr if x])
|
||||||
|
|
||||||
# taxes
|
# get taxes and product-category from settings
|
||||||
taxes = []
|
tax_and_category = []
|
||||||
line_taxes = line_data.get('taxes', [])
|
line_taxes = line_data.pop('taxes', [])
|
||||||
for x in line_taxes:
|
for x in line_taxes:
|
||||||
percent = x.get('percent', None)
|
percent = x.get('percent', None)
|
||||||
if (x.get('type', '') == 'VAT') and (percent is not None):
|
if (x.get('type', '') == 'VAT') and (percent is not None):
|
||||||
percent = percent / Decimal('100')
|
percent = percent / Decimal('100')
|
||||||
taxes.append(get_tax_by_percent(percent))
|
tax_and_category.append(get_tax_by_percent(percent))
|
||||||
# remove not-found-taxes
|
|
||||||
taxes = [x for x in taxes if x]
|
|
||||||
# check result
|
# check result
|
||||||
if len(line_taxes) != len(taxes):
|
if len(line_taxes) != len(tax_and_category):
|
||||||
raise UserError(gettext(
|
raise UserError(gettext(
|
||||||
'document_incoming_invoice_xml.msg_numtaxes_invalid',
|
'document_incoming_invoice_xml.msg_numtaxes_invalid',
|
||||||
descr=line.description,
|
descr=line.description,
|
||||||
taxin='|'.join([
|
taxin='|'.join([
|
||||||
str(x.get('percent', '-')) for x in line_taxes]),
|
str(x.get('percent', '-')) for x in line_taxes]),
|
||||||
taxout='|'.join([
|
taxout='|'.join([
|
||||||
str(x.rate * Decimal('100.0')) for x in taxes])))
|
str(x[0].rate * Decimal('100.0'))
|
||||||
line.taxes = taxes
|
for x in tax_and_category])))
|
||||||
|
|
||||||
#line.account =
|
# set taxes and account for product
|
||||||
|
line.taxes = [x[0] for x in tax_and_category]
|
||||||
|
expense_accounts = [
|
||||||
|
x[1].account_expense
|
||||||
|
for x in tax_and_category if x[1].account_expense]
|
||||||
|
if expense_accounts:
|
||||||
|
line.account = expense_accounts[0]
|
||||||
|
|
||||||
|
# check if calculated 'amount' matches with amount from xml-data
|
||||||
|
xml_amount = line_data.get('total', {}).pop('amount', None)
|
||||||
|
if xml_amount is not None:
|
||||||
|
if xml_amount != line.get_amount(None):
|
||||||
|
raise UserError(gettext(
|
||||||
|
'document_incoming_invoice_xml.msg_line_amount_invalid',
|
||||||
|
linetxt=line.description,
|
||||||
|
calcsum=Report.format_currency(
|
||||||
|
line.get_amount(None), None, invoice.currency),
|
||||||
|
xmlsum=Report.format_currency(
|
||||||
|
xml_amount, None, invoice.currency)))
|
||||||
|
|
||||||
# cleanup used values
|
# cleanup used values
|
||||||
for x in ['quantity', 'unit_net_price']:
|
for x in ['quantity', 'unit_net_price', 'total']:
|
||||||
if not line_data.get(x, {}):
|
if not line_data.get(x, {}):
|
||||||
del line_data[x]
|
del line_data[x]
|
||||||
|
|
||||||
|
# note of line
|
||||||
|
notes = [line_data.pop('line_note', None)]
|
||||||
|
# skipped xml-data
|
||||||
|
convert_notes = line_data.pop('convert_note', None)
|
||||||
|
if convert_notes:
|
||||||
|
notes.extend(
|
||||||
|
[' '] +
|
||||||
|
[gettext('document_incoming_invoice_xml.msg_convert_note')] +
|
||||||
|
convert_notes
|
||||||
|
if isinstance(convert_notes, list) else [str(convert_notes)])
|
||||||
|
# values not used to create invoice-line
|
||||||
|
if line_data:
|
||||||
|
notes.extend([
|
||||||
|
' ',
|
||||||
|
gettext(
|
||||||
|
'document_incoming_invoice_xml.msg_unused_linevalues'),
|
||||||
|
json.dumps(line_data, cls=JSONEncoder, indent=3)])
|
||||||
|
line.note = '\n'.join(x for x in notes if x)
|
||||||
|
|
||||||
line.on_change_invoice()
|
line.on_change_invoice()
|
||||||
|
|
||||||
print('-- line_data-nach:', line_data, (line,))
|
|
||||||
return line
|
return line
|
||||||
|
|
||||||
|
|
||||||
def _readxml_invoice_line(self, xmldata, xpth, pos):
|
def _readxml_invoice_line(self, xmldata, xpth, pos):
|
||||||
""" read invoice-line from xml
|
""" read invoice-line from xml
|
||||||
|
|
||||||
|
@ -712,7 +757,7 @@ class Incoming(metaclass=PoolMeta):
|
||||||
('ram:TaxTotalAmount', 'tax', Decimal),
|
('ram:TaxTotalAmount', 'tax', Decimal),
|
||||||
('ram:GrandTotalAmount', 'grand', Decimal),
|
('ram:GrandTotalAmount', 'grand', Decimal),
|
||||||
('ram:TotalAllowanceChargeAmount', 'feecharge', Decimal),
|
('ram:TotalAllowanceChargeAmount', 'feecharge', Decimal),
|
||||||
])
|
])[0]
|
||||||
|
|
||||||
# notice ignored fields
|
# notice ignored fields
|
||||||
for x in [
|
for x in [
|
||||||
|
|
12
locale/de.po
12
locale/de.po
|
@ -34,6 +34,18 @@ msgctxt "model:ir.message,text:msg_numtaxes_invalid"
|
||||||
msgid "Invalid number of taxes in line %(descr)s: wanted='%(taxin)s', found='%(taxout)s'."
|
msgid "Invalid number of taxes in line %(descr)s: wanted='%(taxin)s', found='%(taxout)s'."
|
||||||
msgstr "Ungültige Anzahl Steuern in Zeile %(descr)s: gesucht='%(taxin)s', gefunden='%(taxout)s'."
|
msgstr "Ungültige Anzahl Steuern in Zeile %(descr)s: gesucht='%(taxin)s', gefunden='%(taxout)s'."
|
||||||
|
|
||||||
|
msgctxt "model:ir.message,text:msg_line_amount_invalid"
|
||||||
|
msgid "The calculated sum '%(calcsum)s' of the line '%(linetxt)s' differs from the value '%(xmlsum)s' from the XML data."
|
||||||
|
msgstr "Die berechnete Summe '%(calcsum)s' der Zeile '%(linetxt)s' weicht vom Wert '%(xmlsum)s' aus den XML-Daten ab."
|
||||||
|
|
||||||
|
msgctxt "model:ir.message,text:msg_convert_note"
|
||||||
|
msgid "The following XML data has not been imported:"
|
||||||
|
msgstr "Folgende XML-Daten wurden nicht importiert:"
|
||||||
|
|
||||||
|
msgctxt "model:ir.message,text:msg_unused_linevalues"
|
||||||
|
msgid "The following data was not used to generate the invoice line:"
|
||||||
|
msgstr "Die folgenden Daten wurden für die Erzeugung der Rechnungszeile nicht verwendet:"
|
||||||
|
|
||||||
|
|
||||||
###################################
|
###################################
|
||||||
# document.incoming.configuration #
|
# document.incoming.configuration #
|
||||||
|
|
12
locale/en.po
12
locale/en.po
|
@ -30,6 +30,18 @@ msgctxt "model:ir.message,text:msg_numtaxes_invalid"
|
||||||
msgid "Invalid number of taxes in line %(descr)s: wanted='%(taxin)s', found='%(taxout)s'."
|
msgid "Invalid number of taxes in line %(descr)s: wanted='%(taxin)s', found='%(taxout)s'."
|
||||||
msgstr "Invalid number of taxes in line %(descr)s: wanted='%(taxin)s', found='%(taxout)s'."
|
msgstr "Invalid number of taxes in line %(descr)s: wanted='%(taxin)s', found='%(taxout)s'."
|
||||||
|
|
||||||
|
msgctxt "model:ir.message,text:msg_line_amount_invalid"
|
||||||
|
msgid "The calculated sum '%(calcsum)s' of the line '%(linetxt)s' differs from the value '%(xmlsum)s' from the XML data."
|
||||||
|
msgstr "The calculated sum '%(calcsum)s' of the line '%(linetxt)s' differs from the value '%(xmlsum)s' from the XML data."
|
||||||
|
|
||||||
|
msgctxt "model:ir.message,text:msg_convert_note"
|
||||||
|
msgid "The following XML data has not been imported:"
|
||||||
|
msgstr "The following XML data has not been imported:"
|
||||||
|
|
||||||
|
msgctxt "model:ir.message,text:msg_unused_linevalues"
|
||||||
|
msgid "The following data was not used to generate the invoice line:"
|
||||||
|
msgstr "The following data was not used to generate the invoice line:"
|
||||||
|
|
||||||
msgctxt "field:document.incoming.configuration,create_supplier:"
|
msgctxt "field:document.incoming.configuration,create_supplier:"
|
||||||
msgid "Create Supplier Party"
|
msgid "Create Supplier Party"
|
||||||
msgstr "Create Supplier Party"
|
msgstr "Create Supplier Party"
|
||||||
|
|
|
@ -26,6 +26,15 @@
|
||||||
<record model="ir.message" id="msg_numtaxes_invalid">
|
<record model="ir.message" id="msg_numtaxes_invalid">
|
||||||
<field name="text">Invalid number of taxes in line %(descr)s: wanted='%(taxin)s', found='%(taxout)s'.</field>
|
<field name="text">Invalid number of taxes in line %(descr)s: wanted='%(taxin)s', found='%(taxout)s'.</field>
|
||||||
</record>
|
</record>
|
||||||
|
<record model="ir.message" id="msg_line_amount_invalid">
|
||||||
|
<field name="text">The calculated sum '%(calcsum)s' of the line '%(linetxt)s' differs from the value '%(xmlsum)s' from the XML data.</field>
|
||||||
|
</record>
|
||||||
|
<record model="ir.message" id="msg_convert_note">
|
||||||
|
<field name="text">The following XML data was not used:</field>
|
||||||
|
</record>
|
||||||
|
<record model="ir.message" id="msg_unused_linevalues">
|
||||||
|
<field name="text">The following data was not used to generate the invoice line:</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
</tryton>
|
</tryton>
|
||||||
|
|
Loading…
Reference in a new issue