Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[9.0][MIG] account_invoice_import_invoice2data and dependencies: Migration to 9.0 #11

Closed
Closed
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
4 changes: 1 addition & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ addons:
# Search your packages here:
# https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise
- wkhtmltopdf # only add if needed and check the before_install section below
- poppler-utils # for invoice2data
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexis-via I was doubting my sanity because for the life of me, I couldn't get the tests work. Then I got the suspicion that pdftotext parses the test invoice incorrectly, and that;s the case, see https://travis-ci.org/OCA/edi/jobs/230782037 - check the install phase, there I first print the output of standard pdftotext on travis, then the version you install. As you see, the total line is botched in the second version. I guess you needed the private version because back then travis had an ancient version only? Any objections to do it the way I propose? And I guess that's also the reason why this still runs on the sudo infrastructure, any objections to change this to the current OCA standard?


# set up an X server to run wkhtmltopdf.
before_install:
Expand All @@ -50,9 +51,6 @@ install:
- export PATH=${HOME}/maintainer-quality-tools/travis:${PATH}
- travis_install_nightly
- pip install invoice2data
- wget -P /tmp http://public.akretion.com/pdftotext-3.04
- sudo mv /tmp/pdftotext-3.04 /usr/local/bin/pdftotext
- sudo chmod 755 /usr/local/bin/pdftotext
- pip install PyPDF2 # needed for account_invoice*zugferd
- pip install phonenumbers

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
EDI Modules

[//]: # (addons)

Unported addons
---------------
addon | version | summary
Expand Down
2 changes: 1 addition & 1 deletion account_invoice_import/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Go to the form view of the suppliers and configure it with the following paramet
Usage
=====

To use this module, go to the menu *Accounting > Suppliers > Import Invoices* and upload a PDF or XML invoice of your supplier.
To use this module, go to the menu *Accounting > Purchases > Import Invoices* and upload a PDF or XML invoice of your supplier.

.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
Expand Down
7 changes: 2 additions & 5 deletions account_invoice_import/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
# -*- coding: utf-8 -*-

from . import partner
from . import account_invoice_import_config
from . import account_invoice
from . import wizard
from . import models
from . import wizards
10 changes: 5 additions & 5 deletions account_invoice_import/__openerp__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

{
'name': 'Account Invoice Import',
'version': '8.0.1.0.0',
'version': '9.0.1.0.0',
'category': 'Accounting & Finance',
'license': 'AGPL-3',
'summary': 'Import supplier invoices/refunds as PDF or XML files',
Expand All @@ -14,11 +14,11 @@
'data': [
'security/ir.model.access.csv',
'security/rule.xml',
'account_invoice_import_config_view.xml',
'wizard/account_invoice_import_view.xml',
'views/account_invoice_import_config_view.xml',
'wizards/account_invoice_import_view.xml',
'views/account_invoice.xml',
'partner_view.xml',
'views/partner_view.xml',
],
'images': ['images/sshot-wizard1.png'],
'installable': False,
'installable': True,
}
4 changes: 4 additions & 0 deletions account_invoice_import/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import partner
from . import account_invoice_import_config
from . import account_invoice
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class AccountInvoiceImportConfig(models.Model):
'account.invoice.import.config'))
account_id = fields.Many2one(
'account.account', string='Expense Account',
domain=[('type', 'not in', ('view', 'closed'))])
domain=[('deprecated', '=', False)])
account_analytic_id = fields.Many2one(
'account.analytic.account', string='Analytic Account',
domain=[('type', '!=', 'view')])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
</record>

<menuitem id="account_invoice_import_config_menu"
parent="account.menu_configuration_misc"
parent="account.menu_finance_configuration"
action="account_invoice_import_config_action" sequence="100"/>

</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def fallback_parse_pdf_invoice(self, file_data):
# 'note': 'Note embedded in the document',
# 'lines': [{
# 'product': {
# 'ean13': '4123456000021',
# 'barcode': '4123456000021',
# 'code': 'GZ250',
# },
# 'name': 'Gelierzucker Extra 250g',
Expand All @@ -117,7 +117,6 @@ def fallback_parse_pdf_invoice(self, file_data):
@api.model
def _prepare_create_invoice_vals(self, parsed_inv):
aio = self.env['account.invoice']
ailo = self.env['account.invoice.line']
bdio = self.env['business.document.import']
rpo = self.env['res.partner']
company = self.env.user.company_id
Expand All @@ -132,16 +131,22 @@ def _prepare_create_invoice_vals(self, parsed_inv):
'currency_id': currency.id,
'type': parsed_inv['type'],
'company_id': company.id,
'supplier_invoice_number':
parsed_inv.get('invoice_number'),
'reference': parsed_inv.get('invoice_number'),
'date_invoice': parsed_inv.get('date'),
'journal_id':
aio.with_context(type='in_invoice')._default_journal().id,
'invoice_line': [],
'check_total': parsed_inv.get('amount_total'),
}
vals.update(aio.onchange_partner_id(
'in_invoice', partner.id, company_id=company.id)['value'])
'invoice_line_ids': [],
}
new_invoice = aio.new(vals)
new_invoice._onchange_partner_id()
vals.update({
f: aio._fields[f].convert_to_write(v)
if not isinstance(new_invoice._fields[f],
fields._RelationalMulti)
else v.ids
for f, v in new_invoice._cache.iteritems()
})

# Force due date of the invoice
if parsed_inv.get('date_due'):
vals['date_due'] = parsed_inv.get('date_due')
Expand All @@ -158,16 +163,15 @@ def _prepare_create_invoice_vals(self, parsed_inv):
if config.invoice_line_method == '1line_no_product':
il_vals = {
'account_id': config.account_id.id,
'invoice_line_tax_id': config.tax_ids.ids or False,
'invoice_line_tax_ids': config.tax_ids.ids or False,
'price_unit': parsed_inv.get('amount_untaxed'),
}
elif config.invoice_line_method == '1line_static_product':
product = config.static_product_id
il_vals = ailo.product_id_change(
product.id, product.uom_id.id, type='in_invoice',
partner_id=partner.id,
fposition_id=partner.property_account_position.id,
company_id=company.id)['value']
il_vals = self._amend_create_invoice_line_vals(
product, 'in_invoice', partner,
partner.property_account_position_id, company
)
il_vals.update({
'product_id': product.id,
'price_unit': parsed_inv.get('amount_untaxed'),
Expand All @@ -180,7 +184,7 @@ def _prepare_create_invoice_vals(self, parsed_inv):
il_vals['name'] = _('MISSING DESCRIPTION')
self.set_1line_price_unit_and_quantity(il_vals, parsed_inv)
self.set_1line_start_end_dates(il_vals, parsed_inv)
vals['invoice_line'].append((0, 0, il_vals))
vals['invoice_line_ids'].append((0, 0, il_vals))
elif config.invoice_line_method.startswith('nline'):
if not parsed_inv.get('lines'):
raise UserError(_(
Expand All @@ -193,11 +197,10 @@ def _prepare_create_invoice_vals(self, parsed_inv):
}
elif config.invoice_line_method == 'nline_static_product':
sproduct = config.static_product_id
static_vals = ailo.product_id_change(
sproduct.id, sproduct.uom_id.id, type='in_invoice',
partner_id=partner.id,
fposition_id=partner.property_account_position.id,
company_id=company.id)['value']
static_vals = self._amend_create_invoice_line_vals(
sproduct, 'in_invoice', partner,
partner.property_account_position_id, company
)
static_vals['product_id'] = sproduct.id
else:
static_vals = {}
Expand All @@ -207,18 +210,17 @@ def _prepare_create_invoice_vals(self, parsed_inv):
product = bdio._match_product(
line['product'], parsed_inv['chatter_msg'],
seller=partner)
fposition_id = partner.property_account_position.id
il_vals.update(
ailo.product_id_change(
product.id, product.uom_id.id, type='in_invoice',
partner_id=partner.id,
fposition_id=fposition_id,
company_id=company.id)['value'])
self._amend_create_invoice_line_vals(
product, 'in_invoice', partner,
partner.property_account_position_id, company
)
)
il_vals['product_id'] = product.id
elif config.invoice_line_method == 'nline_no_product':
taxes = bdio._match_taxes(
line.get('taxes'), parsed_inv['chatter_msg'])
il_vals['invoice_line_tax_id'] = taxes.ids
il_vals['invoice_line_tax_ids'] = taxes.ids
if line.get('name'):
il_vals['name'] = line['name']
elif not il_vals.get('name'):
Expand All @@ -230,27 +232,53 @@ def _prepare_create_invoice_vals(self, parsed_inv):
'quantity': line['qty'],
'price_unit': line['price_unit'], # TODO fix for tax incl
})
vals['invoice_line'].append((0, 0, il_vals))
vals['invoice_line_ids'].append((0, 0, il_vals))
# Write analytic account + fix syntax for taxes
aacount_id = config.account_analytic_id.id or False
for line in vals['invoice_line']:
for line in vals['invoice_line_ids']:
line_dict = line[2]
if line_dict.get('invoice_line_tax_id'):
line_dict['invoice_line_tax_id'] = [
(6, 0, line_dict['invoice_line_tax_id'])]
if line_dict.get('invoice_line_tax_ids'):
line_dict['invoice_line_tax_ids'] = [
(6, 0, line_dict['invoice_line_tax_ids'])]
if aacount_id:
line_dict['account_analytic_id'] = aacount_id
return vals

@api.model
def _amend_create_invoice_line_vals(
self, product, invoice_type, partner, fposition, company
):
new_invoice = self.env['account.invoice'].new({
'type': invoice_type,
'partner_id': partner,
'fiscal_position_id': fposition,
'company_id': company,
})
new_invoice._onchange_partner_id()
new_invoice_line = self.env['account.invoice.line'].new({
'invoice_id': new_invoice,
'product_id': product,
'uom_id': product.uom_id
})
new_invoice_line._onchange_product_id()
return {
f: new_invoice_line._fields[f].convert_to_write(v)
if not isinstance(new_invoice_line._fields[f],
fields._RelationalMulti)
else v.ids
for f, v in new_invoice_line._cache.iteritems()
if f != 'invoice_id'
}

@api.model
def set_1line_price_unit_and_quantity(self, il_vals, parsed_inv):
"""For the moment, we only take into account the 'price_include'
option of the first tax"""
il_vals['quantity'] = 1
il_vals['price_unit'] = parsed_inv.get('amount_total')
if il_vals.get('invoice_line_tax_id'):
if il_vals.get('invoice_line_tax_ids'):
first_tax = self.env['account.tax'].browse(
il_vals['invoice_line_tax_id'][0])
il_vals['invoice_line_tax_ids'][0])
if not first_tax.price_include:
il_vals['price_unit'] = parsed_inv.get('amount_untaxed')

Expand Down Expand Up @@ -367,9 +395,8 @@ def import_invoice(self):
existing_invs = aio.search(
domain +
[(
'supplier_invoice_number',
'=ilike',
parsed_inv.get('invoice_number'))])
'reference', '=ilike', parsed_inv.get('invoice_number')
)])
if existing_invs:
raise UserError(_(
"This invoice already exists in Odoo. It's "
Expand Down Expand Up @@ -426,7 +453,7 @@ def _create_invoice(self, parsed_inv):

@api.model
def post_process_invoice(self, parsed_inv, invoice):
invoice.button_reset_taxes()
invoice.compute_taxes()
# Force tax amount if necessary
prec = self.env['decimal.precision'].precision_get('Account')
if (
Expand All @@ -436,14 +463,14 @@ def post_process_invoice(self, parsed_inv, invoice):
invoice.amount_total,
parsed_inv['amount_total'],
precision_digits=prec)):
if not invoice.tax_line:
if not invoice.tax_line_ids:
raise UserError(_(
"The total amount is different from the untaxed amount, "
"but no tax has been configured !"))
initial_tax_amount = invoice.tax_line[0].amount
initial_tax_amount = invoice.tax_line_ids[0].amount
tax_amount = parsed_inv['amount_total'] -\
parsed_inv['amount_untaxed']
invoice.tax_line[0].amount = tax_amount
invoice.tax_line_ids[0].amount = tax_amount
cur_symbol = invoice.currency_id.symbol
invoice.message_post(
'The total tax amount has been forced to %s %s '
Expand Down Expand Up @@ -518,13 +545,19 @@ def update_invoice_lines(self, parsed_inv, invoice, seller):

@api.model
def _prepare_create_invoice_line(self, product, uom, import_line, invoice):
ailo = self.env['account.invoice.line']
vals = ailo.product_id_change(
product.id, uom.id, qty=import_line['qty'], type='in_invoice',
partner_id=invoice.partner_id.id,
fposition_id=invoice.fiscal_position.id or False,
currency_id=invoice.currency_id.id,
company_id=invoice.company_id.id)['value']
new_line = self.env['account.invoice.line'].new({
'invoice_id': invoice,
'qty': import_line['qty'],
'product_id': product,
})
new_line._onchange_product_id()
vals = {
f: new_line._fields[f].convert_to_write(v)
if not isinstance(new_line._fields[f],
fields._RelationalMulti)
else v.ids
for f, v in new_line._cache.iteritems()
}
vals.update({
'product_id': product.id,
'price_unit': import_line.get('price_unit'),
Expand All @@ -537,10 +570,8 @@ def _prepare_create_invoice_line(self, product, uom, import_line, invoice):
def _prepare_update_invoice_vals(self, parsed_inv, partner):
bdio = self.env['business.document.import']
vals = {
'supplier_invoice_number':
parsed_inv.get('invoice_number'),
'reference': parsed_inv.get('invoice_number'),
'date_invoice': parsed_inv.get('date'),
'check_total': parsed_inv.get('amount_total'),
}
if parsed_inv.get('date_due'):
vals['date_due'] = parsed_inv['date_due']
Expand Down
2 changes: 1 addition & 1 deletion account_invoice_import_invoice2data/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ If you want to use only your custom invoice templates and ignore the templates p
invoice2data_templates_dir = /opt/invoice2data_local_templates
invoice2data_exclude_built_in_templates = True

French users should also install the module *l10n_fr_invoice_import* available in the `French localization <https://github.com/OCA/l10n-france/>`_, cf `this PR <https://github.com/OCA/l10n-france/pull/55>`_.
French users should also install the module *l10n_fr_invoice_import* available in the `French localization <https://github.com/OCA/l10n-france/>`_.

Configuration
=============
Expand Down
4 changes: 2 additions & 2 deletions account_invoice_import_invoice2data/__openerp__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

{
'name': 'Account Invoice Import Invoice2data',
'version': '8.0.1.0.0',
'version': '9.0.1.0.0',
'category': 'Accounting & Finance',
'license': 'AGPL-3',
'summary': 'Import supplier invoices using the invoice2data lib',
Expand All @@ -15,5 +15,5 @@
'data': [],
'demo': ['demo/demo_data.xml'],
'images': ['images/sshot-wizard1.png'],
'installable': False,
'installable': True,
}
Loading