diff --git a/account_move_base_import/__manifest__.py b/account_move_base_import/__manifest__.py index 7d6fcb6189..d23d93f0bd 100644 --- a/account_move_base_import/__manifest__.py +++ b/account_move_base_import/__manifest__.py @@ -5,7 +5,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) { "name": "Journal Entry base import", - "version": "16.0.1.0.1", + "version": "18.0.1.0.0", "author": "Akretion,Camptocamp,Odoo Community Association (OCA)", "category": "Finance", "depends": ["account"], diff --git a/account_move_base_import/models/account_journal.py b/account_move_base_import/models/account_journal.py index 838bc495e2..d6fe219b7a 100644 --- a/account_move_base_import/models/account_journal.py +++ b/account_move_base_import/models/account_journal.py @@ -7,7 +7,7 @@ import sys import traceback -from odoo import _, fields, models +from odoo import fields, models from odoo.exceptions import UserError, ValidationError from ..parser.parser import new_move_parser @@ -172,14 +172,17 @@ def _get_extra_move_line_vals_list(self, parser, move): partner_id = self.partner_id.id # Commission line if global_commission_amount > 0.0: - raise UserError(_("Commission amount should not be positive.")) + raise UserError(self.env._("Commission amount should not be positive.")) elif global_commission_amount < 0.0: if not self.commission_account_id: - raise UserError(_("No commission account is set on the journal.")) + error_no_comission = self.env._( + "No commission account is set on the journal." + ) + raise UserError(error_no_comission) else: commission_account_id = self.commission_account_id.id comm_values = { - "name": _("Commission line"), + "name": self.env._("Commission line"), "date_maturity": ( parser.get_move_vals().get("date") or fields.Date.today() ), @@ -217,7 +220,9 @@ def write_logs_after_import(self, move, num_lines): :return: True """ self.message_post( - body=_("Move %(move_name)s have been imported with %(num_lines)s " "lines.") + body=self.env._( + "Move %(move_name)s have been imported with %(num_lines)s " "lines." + ) % {"move_name": move.name, "num_lines": num_lines} ) return True @@ -340,12 +345,12 @@ def _move_import(self, parser, file_stream, result_row_list=None, ftype="csv"): result_row_list = parser.result_row_list # Check all key are present in account.bank.statement.line!! if not result_row_list: - raise UserError(_("Nothing to import: " "The file is empty")) + raise UserError(self.env._("Nothing to import: " "The file is empty")) parsed_cols = list(parser.get_move_line_vals(result_row_list[0]).keys()) for col in parsed_cols: if col not in move_line_obj._fields: raise UserError( - _( + self.env._( "Missing column! Column %s you try to import is not " "present in the move line!" ) @@ -391,6 +396,9 @@ def _move_import(self, parser, file_stream, result_row_list=None, ftype="csv"): st = f"Error: {error_type.__name__}\nDescription: {error_value}\nTraceback:" st += "".join(traceback.format_tb(trbk, 30)) raise ValidationError( - _("Statement import error " "The statement cannot be created: %s") % st + self.env._( + "Statement import error " "The statement cannot be created: %s" + ) + % st ) from None return move diff --git a/account_move_base_import/models/account_move.py b/account_move_base_import/models/account_move.py index 88766e5163..045a73f695 100644 --- a/account_move_base_import/models/account_move.py +++ b/account_move_base_import/models/account_move.py @@ -7,7 +7,7 @@ import sys import traceback -from odoo import _, api, fields, models +from odoo import api, fields, models from odoo.exceptions import ValidationError _logger = logging.getLogger(__name__) @@ -82,7 +82,7 @@ def _find_invoice(self, line, inv_type): number_field = "name" else: raise ValidationError( - _("Invalid invoice type for completion: %s") % inv_type + self.env._("Invalid invoice type for completion: %s") % inv_type ) invoices = inv_obj.search( @@ -93,7 +93,7 @@ def _find_invoice(self, line, inv_type): return invoices else: raise ErrorTooManyPartner( - _( + self.env._( 'Line named "%(line_name)s" was matched by more than one ' "partner while looking on %(inv_type)s invoices" ) @@ -105,7 +105,7 @@ def _from_invoice(self, line, inv_type): """Populate statement line values""" if inv_type not in ("supplier", "customer"): raise ValidationError( - _("Invalid invoice type for completion: %s") % inv_type + self.env._("Invalid invoice type for completion: %s") % inv_type ) res = {} invoice = self._find_invoice(line, inv_type) @@ -168,15 +168,15 @@ def get_from_name_and_partner_field(self, line): """ res = {} partner_obj = self.env["res.partner"] - or_regex = ".*;? *%s *;?.*" % line.name - self.env["res.partner"].flush(["bank_statement_label"]) + or_regex = f".*;? *{line.name} *;?.*" + self.env["res.partner"].flush_model(["bank_statement_label"]) sql = "SELECT id from res_partner" " WHERE bank_statement_label ~* %s" self.env.cr.execute(sql, (or_regex,)) partner_ids = self.env.cr.fetchall() partners = partner_obj.browse([x[0] for x in partner_ids]) if partners: if len(partners) > 1: - msg = _( + msg = self.env._( 'Line named "%(line_name)s" was matched by more than ' "one partner while looking on partner label: %(partner_labels)s" ) % { @@ -211,7 +211,7 @@ def get_from_name_and_partner_name(self, line): # to: # http://www.postgresql.org/docs/9.0/static/functions-matching.html # in chapter 9.7.3.6. Limits and Compatibility - self.env["res.partner"].flush(["name"]) + self.env["res.partner"].flush_model(["name"]) sql = r""" SELECT id FROM ( SELECT id, @@ -226,7 +226,7 @@ def get_from_name_and_partner_name(self, line): if result: if len(result) > 1: raise ErrorTooManyPartner( - _( + self.env._( 'Line named "%s" was matched by more than one ' "partner while looking on partner by name" ) @@ -335,7 +335,7 @@ def write_completion_log(self, error_msg, number_imported): number_line = len(self.line_ids) log = self.completion_logs or "" completion_date = fields.Datetime.now() - message = _( + message = self.env._( "%(completion_date)s Account Move %(move_name)s has %(num_imported)s/" "%(number_line)s lines completed by " "%(user_name)s \n%(error_msg)s\n%(log)s\n" @@ -352,7 +352,7 @@ def write_completion_log(self, error_msg, number_imported): body = ( ( - _( + self.env._( "Statement ID %(move_name)s auto-completed for %(num_imported)s/" "%(number_line)s lines completed" ) @@ -385,7 +385,8 @@ def button_auto_completion(self): except Exception as exc: msg_lines.append(repr(exc)) error_type, error_value, trbk = sys.exc_info() - st = f"Error: {error_type.__name__}\nDescription: {error_value}\nTraceback:" + st = f"Error: {error_type.__name__}\n\ + Description: {error_value}\nTraceback:" st += "".join(traceback.format_tb(trbk, 30)) _logger.error(st) if res: @@ -394,7 +395,8 @@ def button_auto_completion(self): except Exception as exc: msg_lines.append(repr(exc)) error_type, error_value, trbk = sys.exc_info() - st = f"Error: {error_type.__name__}\nDescription: {error_value}\nTraceback:" + st = f"Error: {error_type.__name__}\n\ + Description: {error_value}\nTraceback:" st += "".join(traceback.format_tb(trbk, 30)) _logger.error(st) msg = "\n".join(msg_lines) diff --git a/account_move_base_import/parser/file_parser.py b/account_move_base_import/parser/file_parser.py index f380a60ecd..a650db95b5 100644 --- a/account_move_base_import/parser/file_parser.py +++ b/account_move_base_import/parser/file_parser.py @@ -7,7 +7,6 @@ import logging import tempfile -from odoo import _ from odoo.exceptions import UserError from .parser import AccountMoveImportParser, UnicodeDictReader @@ -56,7 +55,7 @@ def __init__( self.ftype = ftype[0:3] else: raise UserError( - _("Invalid file type %s. Please use csv, xls or xlsx") % ftype + self.env._("Invalid file type %s. Please use csv, xls or xlsx") % ftype ) self.conversion_dict = extra_fields self.keys_to_validate = list(self.conversion_dict.keys()) @@ -109,7 +108,7 @@ def _validate(self, *args, **kwargs): parsed_cols = list(self.result_row_list[0].keys()) for col in self.keys_to_validate: if col not in parsed_cols: - raise UserError(_("Column %s not present in file") % col) + raise UserError(self.env._("Column %s not present in file") % col) return True def _post(self, *args, **kwargs): @@ -158,7 +157,7 @@ def _from_csv(self, result_set, conversion_rules): line[rule] = datetime.datetime.strptime(date_string, "%Y-%m-%d") except ValueError as err: raise UserError( - _( + self.env._( "Date format is not valid." " It should be YYYY-MM-DD for column: %(rule)s" " value: %(line_value)s \n \n \n Please check" @@ -167,7 +166,7 @@ def _from_csv(self, result_set, conversion_rules): ) % { "rule": rule, - "line_value": line.get(rule, _("Missing")), + "line_value": line.get(rule, self.env._("Missing")), "ref_value": line.get("ref", line), "error": repr(err), } @@ -177,13 +176,13 @@ def _from_csv(self, result_set, conversion_rules): line[rule] = conversion_rules[rule](line[rule]) except Exception as err: raise UserError( - _( + self.env._( "Value %(line_value)s of column %(rule)s is not valid." "\n Please check the line with ref %(value_ref)s:\n " "\n Detail: %(error)s" ) % { - "line_value": line.get(rule, _("Missing")), + "line_value": line.get(rule, self.env._("Missing")), "rule": rule, "value_ref": line.get("ref", line), "error": repr(err), @@ -203,7 +202,7 @@ def _from_xls(self, result_set, conversion_rules): line[rule] = datetime.datetime(*t_tuple) except Exception as err: raise UserError( - _( + self.env._( "Date format is not valid. " "Please modify the cell formatting to date " "format for column: %(rule)s value: %(line_value)s\n " @@ -212,7 +211,7 @@ def _from_xls(self, result_set, conversion_rules): ) % { "rule": rule, - "line_value": line.get(rule, _("Missing")), + "line_value": line.get(rule, self.env._("Missing")), "value_ref": line.get("ref", line), "error": repr(err), } @@ -222,13 +221,13 @@ def _from_xls(self, result_set, conversion_rules): line[rule] = conversion_rules[rule](line[rule]) except Exception as err: raise UserError( - _( + self.env._( "Value %(line_value)s of column %(rule)s is not valid." "\n Please check the line with ref %(value_ref)s:\n " "\n Detail: %(error)s" ) % { - "line_value": line.get(rule, _("Missing")), + "line_value": line.get(rule, self.env._("Missing")), "rule": rule, "value_ref": line.get("ref", line), "error": repr(err), @@ -241,6 +240,6 @@ def _cast_rows(self, *args, **kwargs): providen. We call here _from_xls or _from_csv depending on the self.ftype variable. """ - func = getattr(self, "_from_%s" % self.ftype) + func = getattr(self, f"_from_{self.ftype}") res = func(self.result_row_list, self.conversion_dict) return res diff --git a/account_move_base_import/parser/generic_file_parser.py b/account_move_base_import/parser/generic_file_parser.py index e4b4bef350..5d44c9a2b4 100644 --- a/account_move_base_import/parser/generic_file_parser.py +++ b/account_move_base_import/parser/generic_file_parser.py @@ -5,8 +5,6 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) import datetime -from odoo.tools import ustr - from .file_parser import FileParser, float_or_zero @@ -19,7 +17,7 @@ class GenericFileParser(FileParser): def __init__(self, journal, ftype="csv", **kwargs): conversion_dict = { - "label": ustr, + "label": str, "date": datetime.datetime, "amount": float_or_zero, } diff --git a/account_move_base_import/parser/parser.py b/account_move_base_import/parser/parser.py index 780b3175d2..a7e5304d3c 100644 --- a/account_move_base_import/parser/parser.py +++ b/account_move_base_import/parser/parser.py @@ -6,7 +6,7 @@ import base64 import csv -from odoo import _, fields +from odoo import fields def UnicodeDictReader(utf8_data, **kwargs): @@ -144,7 +144,7 @@ def parse(self, filebuffer, *args, **kwargs): if filebuffer: self.filebuffer = filebuffer else: - raise Exception(_("No buffer file given.")) + raise Exception(self.env._("No buffer file given.")) self._format(*args, **kwargs) self._pre(*args, **kwargs) if self.support_multi_moves: @@ -197,8 +197,7 @@ def itersubclasses(cls, _seen=None): if sub not in _seen: _seen.add(sub) yield sub - for sub in itersubclasses(sub, _seen): - yield sub + yield from itersubclasses(sub, _seen) def new_move_parser(journal, *args, **kwargs): diff --git a/account_move_base_import/tests/test_base_completion.py b/account_move_base_import/tests/test_base_completion.py index 8a8d4ecc82..07c40df5d2 100644 --- a/account_move_base_import/tests/test_base_completion.py +++ b/account_move_base_import/tests/test_base_completion.py @@ -43,8 +43,8 @@ @odoo.tests.tagged("post_install", "-at_install") class BaseCompletion(AccountTestInvoicingCommon): @classmethod - def setUpClass(cls, chart_template_ref=None): - super().setUpClass(chart_template_ref=chart_template_ref) + def setUpClass(cls): + super().setUpClass() cls.account_move_obj = cls.env["account.move"] cls.account_move_line_obj = cls.env["account.move.line"] cls.journal = cls.company_data["default_journal_bank"] @@ -88,18 +88,18 @@ def test_name_completion(self): ) self.move.with_context(check_move_validity=False).button_auto_completion() if case.should_match: + test_text = f"Missing expected partner id after completion \ + (partner_name: {case.partner_name}, line_name: {case.line_label})" self.assertEqual( self.partner, self.move_line.partner_id, - "Missing expected partner id after completion " - "(partner_name: %s, line_name: %s)" - % (case.partner_name, case.line_label), + test_text, ) else: + test_text = f"Partner id should be empty after completion \ + (partner_name: {case.partner_name}, line_name: {case.line_label})" self.assertNotEqual( self.partner, self.move_line.partner_id, - "Partner id should be empty after completion " - "(partner_name: %s, line_name: %s)" - % (case.partner_name, case.line_label), + test_text, ) diff --git a/account_move_base_import/tests/test_base_import.py b/account_move_base_import/tests/test_base_import.py index fee9a2e77b..b0656a24b9 100644 --- a/account_move_base_import/tests/test_base_import.py +++ b/account_move_base_import/tests/test_base_import.py @@ -7,9 +7,9 @@ import os from operator import attrgetter +import odoo import odoo.tests from odoo import fields -from odoo.modules import get_resource_path from odoo.addons.account.tests.common import AccountTestInvoicingCommon @@ -17,8 +17,8 @@ @odoo.tests.tagged("post_install", "-at_install") class TestCodaImport(AccountTestInvoicingCommon): @classmethod - def setUpClass(cls, chart_template_ref=None): - super().setUpClass(chart_template_ref=chart_template_ref) + def setUpClass(cls): + super().setUpClass() cls.account_move_obj = cls.env["account.move"] cls.account_move_line_obj = cls.env["account.move.line"] cls.journal = cls.company_data["default_journal_bank"] @@ -54,16 +54,16 @@ def _import_file(self, file_name): def test_simple_xls(self): """Test import from xls""" - file_name = get_resource_path( - "account_move_base_import", "tests", "data", "statement.xls" + file_name = odoo.tools.misc.file_path( + "account_move_base_import/tests/data/statement.xls" ) move = self._import_file(file_name) self._validate_imported_move(move) def test_simple_csv(self): """Test import from csv""" - file_name = get_resource_path( - "account_move_base_import", "tests", "data", "statement.csv" + file_name = odoo.tools.misc.file_path( + "account_move_base_import/tests/data/statement.csv" ) move = self._import_file(file_name) self._validate_imported_move(move) diff --git a/account_move_base_import/tests/test_invoice.py b/account_move_base_import/tests/test_invoice.py index 14c7c428f9..08c7ea2aef 100644 --- a/account_move_base_import/tests/test_invoice.py +++ b/account_move_base_import/tests/test_invoice.py @@ -1,20 +1,85 @@ # Copyright 2019 Camptocamp SA # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) +import time + import odoo.tests -from odoo import fields +from odoo import Command, fields -from odoo.addons.account.tests.common import TestAccountReconciliationCommon +from odoo.addons.account.tests.common import AccountTestInvoicingCommon @odoo.tests.tagged("post_install", "-at_install") -class TestInvoice(TestAccountReconciliationCommon): +class TestInvoice(AccountTestInvoicingCommon): @classmethod - def setUpClass(cls, chart_template_ref=None): - super().setUpClass(chart_template_ref=chart_template_ref) + def setUpClass(cls): + super().setUpClass() cls.account_move_obj = cls.env["account.move"] cls.account_move_line_obj = cls.env["account.move.line"] cls.journal = cls.company_data["default_journal_bank"] cls.account_id = cls.journal.default_account_id.id + cls.partner_agrolait = cls.env["res.partner"].create( + { + "name": "Deco Agrolait", + "is_company": True, + "country_id": cls.env.ref("base.us").id, + } + ) + cls.partner_agrolait_id = cls.partner_agrolait.id + + def _create_invoice( + self, + move_type="out_invoice", + invoice_amount=50, + currency_id=None, + partner_id=None, + date_invoice=None, + payment_term_id=False, + auto_validate=False, + taxes=None, + state=None, + ): + if move_type == "entry": + raise AssertionError("Unexpected move_type : 'entry'.") + + if not taxes: + taxes = self.env["account.tax"] + + date_invoice = date_invoice or time.strftime("%Y") + "-07-01" + + invoice_vals = { + "move_type": move_type, + "partner_id": partner_id or self.partner_agrolait.id, + "invoice_date": date_invoice, + "date": date_invoice, + "invoice_line_ids": [ + Command.create( + { + "name": f"product that cost {invoice_amount}", + "quantity": 1, + "price_unit": invoice_amount, + "tax_ids": [Command.set(taxes.ids)], + } + ) + ], + } + + if payment_term_id: + invoice_vals["invoice_payment_term_id"] = payment_term_id + + if currency_id: + invoice_vals["currency_id"] = currency_id + + invoice = ( + self.env["account.move"] + .with_context(default_move_type=move_type) + .create(invoice_vals) + ) + + if state == "cancel": + invoice.write({"state": "cancel"}) + elif auto_validate or state == "posted": + invoice.action_post() + return invoice def test_all_completion_rules(self): # I fill in the field Bank Statement Label in a Partner diff --git a/account_move_base_import/views/account_move_view.xml b/account_move_base_import/views/account_move_view.xml index b61cc74500..d161177de2 100644 --- a/account_move_base_import/views/account_move_view.xml +++ b/account_move_base_import/views/account_move_view.xml @@ -5,9 +5,6 @@ account.move - - - - + @@ -49,27 +43,27 @@ - + account.move.completion.rule.view account.move.completion.rule - + - + - + Move Completion Rules account.move.completion.rule - tree,form + list,form diff --git a/account_move_base_import/views/journal_view.xml b/account_move_base_import/views/journal_view.xml index eb93b70801..2219d406f8 100644 --- a/account_move_base_import/views/journal_view.xml +++ b/account_move_base_import/views/journal_view.xml @@ -10,39 +10,31 @@ - + - + @@ -56,7 +48,7 @@ diff --git a/account_move_base_import/wizard/import_statement.py b/account_move_base_import/wizard/import_statement.py index aefc079f79..e5a87f41c7 100644 --- a/account_move_base_import/wizard/import_statement.py +++ b/account_move_base_import/wizard/import_statement.py @@ -9,7 +9,7 @@ import os -from odoo import _, api, fields, models +from odoo import api, fields, models from odoo.exceptions import UserError @@ -52,7 +52,7 @@ def _check_extension(self): self.ensure_one() (__, ftype) = os.path.splitext(self.file_name) if not ftype: - raise UserError(_("Please use a file with an extension")) + raise UserError(self.env._("Please use a file with an extension")) return ftype def import_statement(self): diff --git a/account_move_base_import/wizard/import_statement_view.xml b/account_move_base_import/wizard/import_statement_view.xml index 39a58ea098..0d5220aa48 100644 --- a/account_move_base_import/wizard/import_statement_view.xml +++ b/account_move_base_import/wizard/import_statement_view.xml @@ -11,7 +11,6 @@ domain="[('used_for_import', '=', True)]" /> -