From 68a91a1d71cdbcb95f81450ebdbfe7a9e47f8e7c Mon Sep 17 00:00:00 2001 From: Akim Juillerat Date: Wed, 10 Jul 2019 09:48:13 +0200 Subject: [PATCH] [MIG] account_move_base_import: Migration to 11.0 --- account_move_base_import/__init__.py | 2 - account_move_base_import/__manifest__.py | 18 +- account_move_base_import/data/statement.csv | 4 - account_move_base_import/demo/statement.csv | 4 + .../{data => demo}/statement.xls | Bin account_move_base_import/models/__init__.py | 2 - .../models/account_journal.py | 16 +- .../models/account_move.py | 71 +++-- account_move_base_import/models/partner.py | 9 +- account_move_base_import/parser/__init__.py | 9 +- .../parser/file_parser.py | 31 +-- .../parser/generic_file_parser.py | 18 +- account_move_base_import/parser/parser.py | 15 +- .../readme/CONTRIBUTORS.rst | 7 + .../readme/DESCRIPTION.rst | 42 +++ account_move_base_import/readme/ROADMAP.rst | 1 + .../static/description/icon.png | Bin 9455 -> 0 bytes .../test/completion_test.yml | 108 -------- account_move_base_import/test/invoice.yml | 43 --- account_move_base_import/test/partner.yml | 5 - account_move_base_import/test/refund.yml | 43 --- .../test/supplier_invoice.yml | 41 --- account_move_base_import/tests/__init__.py | 10 +- .../tests/test_base_completion.py | 21 +- .../tests/test_base_import.py | 34 +-- .../tests/test_invoice.py | 256 ++++++++++++++++++ .../views/account_move_view.xml | 2 +- account_move_base_import/wizard/__init__.py | 2 - .../wizard/import_statement.py | 13 +- 29 files changed, 443 insertions(+), 384 deletions(-) delete mode 100644 account_move_base_import/data/statement.csv create mode 100644 account_move_base_import/demo/statement.csv rename account_move_base_import/{data => demo}/statement.xls (100%) create mode 100644 account_move_base_import/readme/CONTRIBUTORS.rst create mode 100644 account_move_base_import/readme/DESCRIPTION.rst create mode 100644 account_move_base_import/readme/ROADMAP.rst delete mode 100644 account_move_base_import/static/description/icon.png delete mode 100644 account_move_base_import/test/completion_test.yml delete mode 100644 account_move_base_import/test/invoice.yml delete mode 100644 account_move_base_import/test/partner.yml delete mode 100644 account_move_base_import/test/refund.yml delete mode 100644 account_move_base_import/test/supplier_invoice.yml create mode 100644 account_move_base_import/tests/test_invoice.py diff --git a/account_move_base_import/__init__.py b/account_move_base_import/__init__.py index 3f3a2791..9de55afe 100644 --- a/account_move_base_import/__init__.py +++ b/account_move_base_import/__init__.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from . import parser from . import wizard from . import models diff --git a/account_move_base_import/__manifest__.py b/account_move_base_import/__manifest__.py index a65c214c..893f4fb7 100644 --- a/account_move_base_import/__manifest__.py +++ b/account_move_base_import/__manifest__.py @@ -1,12 +1,11 @@ -# -*- coding: utf-8 -*- -# © 2011-2016 Akretion -# © 2011-2016 Camptocamp SA -# © 2013 Savoir-faire Linux -# © 2014 ACSONE SA/NV +# Copyright 2011-2016 Akretion +# Copyright 2011-2019 Camptocamp SA +# Copyright 2013 Savoir-faire Linux +# Copyright 2014 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) { 'name': "Journal Entry base import", - 'version': '10.0.1.1.0', + 'version': '11.0.1.0.0', 'author': "Akretion,Camptocamp,Odoo Community Association (OCA)", 'category': 'Finance', 'depends': ['account'], @@ -19,13 +18,6 @@ "views/journal_view.xml", "views/partner_view.xml", ], - 'test': [ - 'test/partner.yml', - 'test/invoice.yml', - 'test/supplier_invoice.yml', - 'test/refund.yml', - 'test/completion_test.yml' - ], 'installable': True, 'license': 'AGPL-3', } diff --git a/account_move_base_import/data/statement.csv b/account_move_base_import/data/statement.csv deleted file mode 100644 index 21dead31..00000000 --- a/account_move_base_import/data/statement.csv +++ /dev/null @@ -1,4 +0,0 @@ -"date";"amount";"commission_amount";"label" -2011-03-07 13:45:14;118.4;-11.84;"label a" -2011-03-02 13:45:14;189;-15.12;"label b" -2011-03-02 17:45:14;189;-15.12;"label c" diff --git a/account_move_base_import/demo/statement.csv b/account_move_base_import/demo/statement.csv new file mode 100644 index 00000000..333ee62d --- /dev/null +++ b/account_move_base_import/demo/statement.csv @@ -0,0 +1,4 @@ +date;amount;commission_amount;label +2011-03-07 13:45:14;118.4;-11.84;label a +2011-03-02 13:45:14;189;-15.12;label b +2011-03-02 17:45:14;189;-15.12;label c diff --git a/account_move_base_import/data/statement.xls b/account_move_base_import/demo/statement.xls similarity index 100% rename from account_move_base_import/data/statement.xls rename to account_move_base_import/demo/statement.xls diff --git a/account_move_base_import/models/__init__.py b/account_move_base_import/models/__init__.py index bfd56a48..2835820b 100644 --- a/account_move_base_import/models/__init__.py +++ b/account_move_base_import/models/__init__.py @@ -1,5 +1,3 @@ -# -*- coding: utf-8 -*- - from . import account_journal from . import account_move from . import partner diff --git a/account_move_base_import/models/account_journal.py b/account_move_base_import/models/account_journal.py index 5fe8b2aa..0040dcb3 100644 --- a/account_move_base_import/models/account_journal.py +++ b/account_move_base_import/models/account_journal.py @@ -1,8 +1,7 @@ -# -*- coding: utf-8 -*- -# © 2011-2016 Akretion -# © 2011-2019 Camptocamp SA -# © 2013 Savoir-faire Linux -# © 2014 ACSONE SA/NV +# Copyright 2011-2016 Akretion +# Copyright 2011-2019 Camptocamp SA +# Copyright 2013 Savoir-faire Linux +# Copyright 2014 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) import sys import traceback @@ -330,7 +329,9 @@ class AccountJournal(models.Model): if not result_row_list: raise UserError(_("Nothing to import: " "The file is empty")) - parsed_cols = parser.get_move_line_vals(result_row_list[0]).keys() + 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( @@ -345,9 +346,10 @@ class AccountJournal(models.Model): parser_vals = parser.get_move_line_vals(line) values = self.prepare_move_line_vals(parser_vals, move) move_store.append(values) + # TODO Check if this is still needed # Hack to bypass ORM poor perfomance. Sob... move_line_obj._insert_lines(move_store) - self.env.invalidate_all() + self.invalidate_cache() self._write_extra_move_lines(parser, move) if self.create_counterpart: self._create_counterpart(parser, move) diff --git a/account_move_base_import/models/account_move.py b/account_move_base_import/models/account_move.py index ef83d892..c1238b98 100644 --- a/account_move_base_import/models/account_move.py +++ b/account_move_base_import/models/account_move.py @@ -1,8 +1,7 @@ -# -*- coding: utf-8 -*- -# © 2011-2016 Akretion -# © 2011-2016 Camptocamp SA -# © 2013 Savoir-faire Linux -# © 2014 ACSONE SA/NV +# Copyright 2011-2016 Akretion +# Copyright 2011-2019 Camptocamp SA +# Copyright 2013 Savoir-faire Linux +# Copyright 2014 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) import traceback import sys @@ -10,8 +9,9 @@ import logging import psycopg2 -from odoo import _, api, fields, models +from odoo import _, api, fields, models, registry from odoo.exceptions import ValidationError +from odoo.tools import float_repr _logger = logging.getLogger(__name__) @@ -62,7 +62,8 @@ class AccountMoveCompletionRule(models.Model): 'From line name (based on partner field)'), ('get_from_name_and_partner_name', 'From line name (based on partner name)') - ], string='Method') + ], string='Method' + ) def _find_invoice(self, line, inv_type): """Find invoice related to statement line""" @@ -262,9 +263,9 @@ class AccountMoveLine(models.Model): """Return writeable by SQL columns""" model_cols = self._fields avail = [ - k for k, col in model_cols.iteritems() if not hasattr(col, '_fnct') + k for k, col in model_cols.items() if not hasattr(col, '_fnct') ] - keys = [k for k in move_store[0].keys() if k in avail] + keys = [k for k in list(move_store[0].keys()) if k in avail] keys.sort() return keys @@ -273,9 +274,34 @@ class AccountMoveLine(models.Model): Return a copy of statement """ move_copy = move - for k, col in move_copy.iteritems(): + for k, col in move_copy.items(): if k in cols: - move_copy[k] = self._fields[k].convert_to_column(col, None) + # In v11, the record is needed to call convert_to_column on a + # Monetary field because it must find the currency to apply the + # proper rounding. So we mimic the call here as best as we can. + if isinstance(self._fields[k], fields.Monetary): + currency_field = move_copy.get( + self._fields[k].currency_field + ) + if currency_field: + currency_id = ( + move_copy.get(currency_field) + or move.get('company_currency_id') + ) + if currency_id: + currency = self.env['res.currency'].browse( + currency_id + ) + move_copy[k] = float_repr( + currency.round(col), currency.decimal_places + ) + continue + # If no currency was found, set what convert_to_column + # would do and used to do in v10 + move_copy[k] = float(col or 0.0) + continue + else: + move_copy[k] = self._fields[k].convert_to_column(col, None) return move_copy def _prepare_manyinsert(self, move_store, cols): @@ -333,19 +359,16 @@ class AccountMove(models.Model): related='journal_id.used_for_completion', readonly=True) completion_logs = fields.Text(string='Completion Log', readonly=True) - # partner_id is a native field of the account module - # (related='line_ids.partner_id', store=True, readonly=True) - partner_id = fields.Many2one(related=False, compute='_compute_partner_id') import_partner_id = fields.Many2one('res.partner', string="Partner from import") - @api.one @api.depends('line_ids.partner_id', 'import_partner_id') def _compute_partner_id(self): - if self.import_partner_id: - self.partner_id = self.import_partner_id - elif self.line_ids: - self.partner_id = self.line_ids[0].partner_id + for move in self: + if move.import_partner_id: + move.partner_id = move.import_partner_id + else: + super(AccountMove, move)._compute_partner_id() def write_completion_log(self, error_msg, number_imported): """Write the log in the completion_logs field of the bank statement to @@ -392,9 +415,9 @@ class AccountMove(models.Model): res = line._get_line_values_from_rules(rules) if res: compl_lines += 1 - except ErrorTooManyPartner, exc: + except ErrorTooManyPartner as exc: msg_lines.append(repr(exc)) - except Exception, exc: + except Exception as exc: msg_lines.append(repr(exc)) error_type, error_value, trbk = sys.exc_info() st = "Error: %s\nDescription: %s\nTraceback:" % ( @@ -411,10 +434,6 @@ class AccountMove(models.Model): error_type.__name__, error_value) st += ''.join(traceback.format_tb(trbk, 30)) _logger.error(st) - # we can commit as it is not needed to be atomic - # commiting here adds a nice perfo boost - if not compl_lines % 500: - self.env.cr.commit() - msg = u'\n'.join(msg_lines) + msg = '\n'.join(msg_lines) self.write_completion_log(msg, compl_lines) return True diff --git a/account_move_base_import/models/partner.py b/account_move_base_import/models/partner.py index 7391479b..416a2c0b 100644 --- a/account_move_base_import/models/partner.py +++ b/account_move_base_import/models/partner.py @@ -1,8 +1,7 @@ -# -*- coding: utf-8 -*- -# © 2011-2016 Akretion -# © 2011-2016 Camptocamp SA -# © 2013 Savoir-faire Linux -# © 2014 ACSONE SA/NV +# Copyright 2011-2016 Akretion +# Copyright 2011-2019 Camptocamp SA +# Copyright 2013 Savoir-faire Linux +# Copyright 2014 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) from odoo import fields, models diff --git a/account_move_base_import/parser/__init__.py b/account_move_base_import/parser/__init__.py index 1233bf9d..527dfdb2 100644 --- a/account_move_base_import/parser/__init__.py +++ b/account_move_base_import/parser/__init__.py @@ -1,8 +1,7 @@ -# -*- coding: utf-8 -*- -# © 2011 Akretion -# © 2011-2016 Camptocamp SA -# © 2013 Savoir-faire Linux -# © 2014 ACSONE SA/NV +# Copyright 2011 Akretion +# Copyright 2011-2019 Camptocamp SA +# Copyright 2013 Savoir-faire Linux +# Copyright 2014 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) from .parser import new_move_parser from .parser import AccountMoveImportParser diff --git a/account_move_base_import/parser/file_parser.py b/account_move_base_import/parser/file_parser.py index 6b3f48fb..5700ede7 100644 --- a/account_move_base_import/parser/file_parser.py +++ b/account_move_base_import/parser/file_parser.py @@ -1,18 +1,17 @@ -# -*- coding: utf-8 -*- -# © 2011 Akretion -# © 2011-2016 Camptocamp SA -# © 2013 Savoir-faire Linux -# © 2014 ACSONE SA/NV +# Copyright 2011 Akretion +# Copyright 2011-2019 Camptocamp SA +# Copyright 2013 Savoir-faire Linux +# Copyright 2014 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) -from openerp.tools.translate import _ -from openerp.exceptions import UserError -import tempfile import datetime +import tempfile +import xlrd + +from odoo import _ +from odoo.exceptions import UserError + + from .parser import AccountMoveImportParser, UnicodeDictReader -try: - import xlrd -except: - raise Exception(_('Please install python lib xlrd')) def float_or_zero(val): @@ -37,14 +36,14 @@ class FileParser(AccountMoveImportParser): :param list: header : specify header fields if the csv file has no header """ - super(FileParser, self).__init__(journal, **kwargs) + super().__init__(journal, **kwargs) if ftype in ('csv', 'xls', 'xlsx'): self.ftype = ftype[0:3] else: raise UserError( _('Invalid file type %s. Please use csv, xls or xlsx') % ftype) self.conversion_dict = extra_fields - self.keys_to_validate = self.conversion_dict.keys() + self.keys_to_validate = list(self.conversion_dict.keys()) self.fieldnames = header self._datemode = 0 # used only for xls documents, # 0 means Windows mode (1900 based dates). @@ -79,7 +78,7 @@ class FileParser(AccountMoveImportParser): separately (in the field: fieldnames). """ if self.fieldnames is None: - parsed_cols = self.result_row_list[0].keys() + 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) @@ -113,7 +112,7 @@ class FileParser(AccountMoveImportParser): header = sheet.row_values(0) res = [] for rownum in range(1, sheet.nrows): - res.append(dict(zip(header, sheet.row_values(rownum)))) + res.append(dict(list(zip(header, sheet.row_values(rownum))))) return res def _from_csv(self, result_set, conversion_rules): diff --git a/account_move_base_import/parser/generic_file_parser.py b/account_move_base_import/parser/generic_file_parser.py index d6f466b1..34cc1687 100644 --- a/account_move_base_import/parser/generic_file_parser.py +++ b/account_move_base_import/parser/generic_file_parser.py @@ -1,15 +1,11 @@ -# -*- coding: utf-8 -*- -# © 2011 Akretion -# © 2011-2016 Camptocamp SA -# © 2013 Savoir-faire Linux -# © 2014 ACSONE SA/NV +# Copyright 2011 Akretion +# Copyright 2011-2019 Camptocamp SA +# Copyright 2013 Savoir-faire Linux +# Copyright 2014 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) import datetime -from .file_parser import FileParser -from openerp.addons.account_move_base_import.parser.file_parser import ( - float_or_zero -) -from openerp.tools import ustr +from .file_parser import FileParser, float_or_zero +from odoo.tools import ustr class GenericFileParser(FileParser): @@ -27,7 +23,7 @@ class GenericFileParser(FileParser): } # set self.env for later ORM searches self.env = journal.env - super(GenericFileParser, self).__init__( + super().__init__( journal, ftype=ftype, extra_fields=conversion_dict, **kwargs) diff --git a/account_move_base_import/parser/parser.py b/account_move_base_import/parser/parser.py index e20d5613..2cc7584d 100644 --- a/account_move_base_import/parser/parser.py +++ b/account_move_base_import/parser/parser.py @@ -1,8 +1,7 @@ -# -*- coding: utf-8 -*- -# © 2011 Akretion -# © 2011-2016 Camptocamp SA -# © 2013 Savoir-faire Linux -# © 2014 ACSONE SA/NV +# Copyright 2011 Akretion +# Copyright 2011-2019 Camptocamp SA +# Copyright 2013 Savoir-faire Linux +# Copyright 2014 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) import base64 import csv @@ -21,9 +20,9 @@ def UnicodeDictReader(utf8_data, **kwargs): dialect = kwargs.pop('dialect') csv_reader = csv.DictReader(utf8_data, dialect=dialect, **kwargs) for row in csv_reader: - yield dict([(unicode(key or '', 'utf-8'), - unicode(value or '', 'utf-8')) - for key, value in row.iteritems()]) + yield dict([(str(key or ''), + str(value or '')) + for key, value in row.items()]) class AccountMoveImportParser(object): diff --git a/account_move_base_import/readme/CONTRIBUTORS.rst b/account_move_base_import/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000..ef9233ac --- /dev/null +++ b/account_move_base_import/readme/CONTRIBUTORS.rst @@ -0,0 +1,7 @@ +* Joël Grand-Guillaume +* Nicolas Bessi +* Laurent Mignon +* Sébastien Beau +* Matthieu Dietrich +* Alexandre Fayolle +* Akim Juillerat diff --git a/account_move_base_import/readme/DESCRIPTION.rst b/account_move_base_import/readme/DESCRIPTION.rst new file mode 100644 index 00000000..7e23ab29 --- /dev/null +++ b/account_move_base_import/readme/DESCRIPTION.rst @@ -0,0 +1,42 @@ +This module is a grouping of 7.0/8.0 modules, used to import accounting files +and completing them automatically: + +* account_statement_base_completion +* account_statement_base_import +* account_statement_commission +* account_statement_ext + +The main change is that, in order to import financial data, this information +is now imported directly as a Journal Entry. + +Most of the information present in the "statement profile" is now located in +the account journal (with 2 boolean parameters which allows to use +this journal for importation and/or auto-completion). + +Financial data can be imported using a standard .csv or .xls file (you'll find +it in the 'data' folder). It respects the journal to pass the entries. + +This module can handle a commission taken by the payment office and has the +following format: +* __date__: date of the payment +* __amount__: amount paid in the currency of the journal used in the +importation +* __label__: the comunication given by the payment office, used as +communication in the generated entries. + +Another column which can be used is __commission_amount__, representing +the amount for the commission taken by line. + +Afterwards, the goal is to populate the journal items with information that +the bank or office gave you. For this, completion rules can be specified by +journal. + +Some basic rules are provided in this module: + +1) Match from statement line label (based on partner field 'Bank Statement +Label') +2) Match from statement line label (based on partner name) +3) Match from statement line label (based on Invoice reference) + +Feel free to extend either the importation method, the completion method, or +both. diff --git a/account_move_base_import/readme/ROADMAP.rst b/account_move_base_import/readme/ROADMAP.rst new file mode 100644 index 00000000..39566aa6 --- /dev/null +++ b/account_move_base_import/readme/ROADMAP.rst @@ -0,0 +1 @@ +* As for now, the module does not handle multicurrency imports. diff --git a/account_move_base_import/static/description/icon.png b/account_move_base_import/static/description/icon.png deleted file mode 100644 index 3a0328b516c4980e8e44cdb63fd945757ddd132d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I diff --git a/account_move_base_import/test/completion_test.yml b/account_move_base_import/test/completion_test.yml deleted file mode 100644 index 12e13a07..00000000 --- a/account_move_base_import/test/completion_test.yml +++ /dev/null @@ -1,108 +0,0 @@ -- - In order to test the banking framework, I first need to create a journal -- - !record {model: account.journal, id: account.bank_journal}: - used_for_completion: True - rule_ids: - - bank_statement_completion_rule_4 - - bank_statement_completion_rule_2 - - bank_statement_completion_rule_3 - - bank_statement_completion_rule_5 -- - Now I create a statement. I create statment lines separately because I need - to find each one by XML id -- - !record {model: account.move, id: move_test1}: - name: Move 2 - journal_id: account.bank_journal - company_id: base.main_company -- - I create a move line for a CI -- - !record {model: account.move.line, id: move_line_ci}: - name: \ - account_id: account.a_sale - move_id: move_test1 - date_maturity: '2013-12-20' - credit: 0.0 -- - I create a move line for a SI -- - !record {model: account.move.line, id: move_line_si}: - name: \ - account_id: account.a_expense - move_id: move_test1 - date_maturity: '2013-12-19' - debit: 0.0 -- - I create a move line for a CR -- - !record {model: account.move.line, id: move_line_cr}: - name: \ - account_id: account.a_expense - move_id: move_test1 - date_maturity: '2013-12-19' - debit: 0.0 -- - I create a move line for the Partner Name -- - !record {model: account.move.line, id: move_line_partner_name}: - name: Test autocompletion based on Partner Name Camptocamp - account_id: account.a_sale - move_id: move_test1 - date_maturity: '2013-12-17' - credit: 0.0 -- - I create a move line for the Partner Label -- - !record {model: account.move.line, id: move_line_partner_label}: - name: XXX66Z - account_id: account.a_sale - move_id: move_test1 - date_maturity: '2013-12-24' - debit: 0.0 -- - and add the correct name -- - !python {model: account.move.line}: | - import datetime as dt - model.browse(ref('move_line_ci')).with_context(check_move_validity=False).write({'name': dt.date.today().strftime('TBNK/%Y/0001'),'credit': 210.0}) - model.browse(ref('move_line_si')).with_context(check_move_validity=False).write({'name': 'T2S12345','debit': 65.0}) - model.browse(ref('move_line_cr')).with_context(check_move_validity=False).write({'name': dt.date.today().strftime('RTEXJ/%Y/0001'),'debit': 210.0}) - model.browse(ref('move_line_partner_name')).with_context(check_move_validity=False).write({'credit': 600.0}) - model.browse(ref('move_line_partner_label')).with_context(check_move_validity=False).write({'debit': 932.4}) -- - I run the auto complete -- - !python {model: account.move, ref: move_test1}: | - result = model.browse(ref('move_test1')).button_auto_completion() -- - Now I can check that all is nice and shiny, line 1. I expect the Customer - Invoice Number to be recognised. - I Use _ref, because ref conflicts with the field ref of the statement line -- - !assert {model: account.move.line, id: move_line_ci, string: Check completion by CI number}: - - partner_id.id == _ref("base.res_partner_12") -- - Line 2. I expect the Supplier invoice number to be recognised. The supplier - invoice was created by the account module demo data, and we confirmed it - here. -- - !assert {model: account.move.line, id: move_line_si, string: Check completion by SI number}: - - partner_id.id == _ref("base.res_partner_12") -- - Line 3. I expect the Customer refund number to be recognised. It should be - the commercial partner, and not the regular partner. -- - !assert {model: account.move.line, id: move_line_cr, string: Check completion by CR number and commercial partner}: - - partner_id.id == _ref("base.res_partner_12") -- - Line 4. I check that the partner name has been recognised. -- - !assert {model: account.move.line, id: move_line_partner_name, string: Check completion by partner name}: - - partner_id.name == 'Camptocamp' -- - Line 5. I check that the partner special label has been recognised. -- - !assert {model: account.move.line, id: move_line_partner_label, string: Check completion by partner label}: - - partner_id.id == _ref("base.res_partner_4") diff --git a/account_move_base_import/test/invoice.yml b/account_move_base_import/test/invoice.yml deleted file mode 100644 index 14cb6351..00000000 --- a/account_move_base_import/test/invoice.yml +++ /dev/null @@ -1,43 +0,0 @@ -- - I import account minimal data -- - !python {model: account.invoice}: | - openerp.tools.convert_file(cr, - 'account', - openerp.modules.get_module_resource( - 'account', - 'test', - 'account_minimal_test.xml'), - {}, 'init', False, 'test') -- - I create a customer Invoice to be found by the completion. -- - !record {model: account.invoice, id: invoice_for_completion_1}: - company_id: base.main_company - currency_id: base.EUR - invoice_line_ids: - - name: '[PCSC234] PC Assemble SC234' - price_unit: 210.0 - quantity: 1.0 - product_id: product.product_product_3 - uom_id: product.product_uom_unit - journal_id: account.bank_journal - partner_id: base.res_partner_12 - reference_type: none -- - I confirm the Invoice -- - !python {model: account.invoice, id: invoice_for_completion_1}: - self.action_invoice_open() -- - I check that the invoice state is "Open" -- - !assert {model: account.invoice, id: invoice_for_completion_1}: - - state == 'open' -- - I check that it is given the number "TBNK/%Y/0001" -- - !python {model: account.invoice}: | - import datetime as dt - invoice = model.browse(ref('invoice_for_completion_1')) - assert invoice.number == dt.date.today().strftime('TBNK/%Y/0001') diff --git a/account_move_base_import/test/partner.yml b/account_move_base_import/test/partner.yml deleted file mode 100644 index 5e207100..00000000 --- a/account_move_base_import/test/partner.yml +++ /dev/null @@ -1,5 +0,0 @@ -- - I fill in the field Bank Statement Label in a Partner -- - !record {model: res.partner, id: base.res_partner_4}: - bank_statement_label: XXX66Z diff --git a/account_move_base_import/test/refund.yml b/account_move_base_import/test/refund.yml deleted file mode 100644 index ec97bb04..00000000 --- a/account_move_base_import/test/refund.yml +++ /dev/null @@ -1,43 +0,0 @@ -- - I create a "child" partner, to use in the invoice - (and have a different commercial_partner_id than itself) -- - !record {model: res.partner, id: res_partner_12_child}: - name: Child Partner - supplier: False - customer: True - is_company: False - parent_id: base.res_partner_12 -- - I create a customer refund to be found by the completion. -- - !record {model: account.invoice, id: refund_for_completion_1}: - company_id: base.main_company - currency_id: base.EUR - invoice_line_ids: - - name: '[PCSC234] PC Assemble SC234' - price_unit: 210.0 - quantity: 1.0 - product_id: product.product_product_3 - uom_id: product.product_uom_unit - journal_id: account.expenses_journal - partner_id: res_partner_12_child - type: 'out_refund' - reference_type: none -- - I confirm the refund -- - !python {model: account.invoice, ref: invoice_for_completion_1}: | - model.browse(ref('refund_for_completion_1')).action_invoice_open() -- - I check that the refund state is "Open" -- - !assert {model: account.invoice, id: refund_for_completion_1}: - - state == 'open' -- - I check that it is given the number "RTEXJ/%Y/0001" -- - !python {model: account.invoice}: | - import datetime as dt - invoice = model.browse(ref('refund_for_completion_1')) - assert invoice.number == dt.date.today().strftime('RTEXJ/%Y/0001') diff --git a/account_move_base_import/test/supplier_invoice.yml b/account_move_base_import/test/supplier_invoice.yml deleted file mode 100644 index e3e90050..00000000 --- a/account_move_base_import/test/supplier_invoice.yml +++ /dev/null @@ -1,41 +0,0 @@ -- - I import account minimal data -- - !python {model: account.invoice}: | - openerp.tools.convert_file(cr, - 'account', - openerp.modules.get_module_resource( - 'account', - 'demo', - 'account_invoice_demo.yml'), - {}, 'init', False, 'test') -- - I check that my invoice is a supplier invoice -- - !assert {model: account.invoice, id: account.demo_invoice_0, string: Check invoice type}: - - type == 'in_invoice' -- - I add a reference to an existing supplier invoce -- - !python {model: account.invoice, id: account.demo_invoice_0}: | - self.write({'reference': 'T2S12345'}) -- - I check a second time that my invoice is still a supplier invoice -- - !assert {model: account.invoice, id: account.demo_invoice_0, string: Check invoice type 2}: - - type == 'in_invoice' -- - Now I confirm it -- - !python {model: account.invoice, ref: account.demo_invoice_0}: | - self.action_invoice_open() -- - I check that the supplier number is there -- - !assert {model: account.invoice, id: account.demo_invoice_0, string: Check supplier number}: - - reference == 'T2S12345' -- - I check a third time that my invoice is still a supplier invoice -- - !assert {model: account.invoice, id: account.demo_invoice_0, string: Check invoice type 3}: - - type == 'in_invoice' diff --git a/account_move_base_import/tests/__init__.py b/account_move_base_import/tests/__init__.py index 2a150908..0e6efa7d 100644 --- a/account_move_base_import/tests/__init__.py +++ b/account_move_base_import/tests/__init__.py @@ -1,8 +1,8 @@ -# -*- coding: utf-8 -*- -# © 2011 Akretion -# © 2011-2016 Camptocamp SA -# © 2013 Savoir-faire Linux -# © 2014 ACSONE SA/NV +# Copyright 2011 Akretion +# Copyright 2011-2019 Camptocamp SA +# Copyright 2013 Savoir-faire Linux +# Copyright 2014 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) from . import test_base_completion from . import test_base_import +from . import test_invoice diff --git a/account_move_base_import/tests/test_base_completion.py b/account_move_base_import/tests/test_base_completion.py index 15c48934..f619e958 100644 --- a/account_move_base_import/tests/test_base_completion.py +++ b/account_move_base_import/tests/test_base_completion.py @@ -1,11 +1,10 @@ -# -*- coding: utf-8 -*- -# © 2011-2016 Akretion -# © 2011-2016 Camptocamp SA -# © 2013 Savoir-faire Linux -# © 2014 ACSONE SA/NV +# Copyright 2011-2016 Akretion +# Copyright 2011-2019 Camptocamp SA +# Copyright 2013 Savoir-faire Linux +# Copyright 2014 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) from odoo import fields, tools -from odoo.modules import get_module_resource +from odoo.modules import get_resource_path from odoo.tests import common from collections import namedtuple @@ -36,10 +35,10 @@ NAMES_COMPLETION_CASES = [ class BaseCompletion(common.TransactionCase): def setUp(self): - super(BaseCompletion, self).setUp() + super().setUp() tools.convert_file(self.cr, 'account', - get_module_resource('account', 'test', - 'account_minimal_test.xml'), + get_resource_path('account', 'test', + 'account_minimal_test.xml'), {}, 'init', False, 'test') self.account_move_obj = self.env["account.move"] self.account_move_line_obj = \ @@ -82,13 +81,13 @@ class BaseCompletion(common.TransactionCase): "Partner_id must be blank before completion") self.move.button_auto_completion() if case.should_match: - self.assertEquals( + 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)) else: - self.assertNotEquals( + self.assertNotEqual( self.partner, self.move_line.partner_id, "Partner id should be empty after completion " "(partner_name: %s, line_name: %s)" diff --git a/account_move_base_import/tests/test_base_import.py b/account_move_base_import/tests/test_base_import.py index 0c036091..bb041b18 100644 --- a/account_move_base_import/tests/test_base_import.py +++ b/account_move_base_import/tests/test_base_import.py @@ -1,26 +1,24 @@ -# -*- coding: utf-8 -*- -# © 2011-2016 Akretion -# © 2011-2016 Camptocamp SA -# © 2013 Savoir-faire Linux -# © 2014 ACSONE SA/NV +# Copyright 2011-2016 Akretion +# Copyright 2011-2019 Camptocamp SA +# Copyright 2013 Savoir-faire Linux +# Copyright 2014 ACSONE SA/NV # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) import base64 -import inspect import os from operator import attrgetter from odoo.tests import common from odoo import tools -from odoo.modules import get_module_resource +from odoo.modules import get_resource_path class TestCodaImport(common.TransactionCase): def setUp(self): - super(TestCodaImport, self).setUp() + super().setUp() self.company_a = self.browse_ref('base.main_company') tools.convert_file(self.cr, 'account', - get_module_resource('account', 'test', - 'account_minimal_test.xml'), + get_resource_path('account', 'test', + 'account_minimal_test.xml'), {}, 'init', False, 'test') self.account_move_obj = self.env["account.move"] self.account_move_line_obj = self.env["account.move.line"] @@ -37,15 +35,11 @@ class TestCodaImport(common.TransactionCase): 'create_counterpart': True, }) - def _filename_to_abs_filename(self, file_name): - dir_name = os.path.dirname(inspect.getfile(self.__class__)) - return os.path.join(dir_name, file_name) - def _import_file(self, file_name): """ import a file using the wizard return the create account.bank.statement object """ - with open(file_name) as f: + with open(file_name, 'rb') as f: content = f.read() self.wizard = self.import_wizard_obj.create({ "journal_id": self.journal.id, @@ -58,16 +52,18 @@ class TestCodaImport(common.TransactionCase): def test_simple_xls(self): """Test import from xls """ - file_name = self._filename_to_abs_filename( - os.path.join("..", "data", "statement.xls")) + file_name = get_resource_path( + 'account_move_base_import', 'demo', 'statement.xls' + ) move = self._import_file(file_name) self._validate_imported_move(move) def test_simple_csv(self): """Test import from csv """ - file_name = self._filename_to_abs_filename( - os.path.join("..", "data", "statement.csv")) + file_name = get_resource_path( + 'account_move_base_import', 'demo', '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 new file mode 100644 index 00000000..c2910e13 --- /dev/null +++ b/account_move_base_import/tests/test_invoice.py @@ -0,0 +1,256 @@ +# Copyright 2019 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) +import datetime as dt + +from odoo.modules import get_resource_path +from odoo.tests import SingleTransactionCase +from odoo.tools import convert_file + + +class TestInvoice(SingleTransactionCase): + + def setUp(self): + super().setUp() + self.account_move_obj = self.env["account.move"] + self.account_move_line_obj = \ + self.env["account.move.line"] + self.company_a = self.env.ref('base.main_company') + self.partner = self.env.ref("base.res_partner_12") + + def test_01_partner(self): + # I fill in the field Bank Statement Label in a Partner + self.partner_4 = self.env.ref('base.res_partner_4') + self.partner_4.bank_statement_label = 'XXX66Z' + self.assertEqual(self.partner_4.bank_statement_label, 'XXX66Z') + + def test_02_invoice(self): + convert_file( + self.cr, 'account', get_resource_path( + 'account', 'test', 'account_minimal_test.xml' + ), {}, 'init', False, 'test' + ) + self.journal = self.env.ref("account.bank_journal") + self.account_id = self.env.ref("account.a_recv") + # I create a customer Invoice to be found by the completion. + product_3 = self.env.ref('product.product_product_3') + self.invoice_for_completion_1 = self.env['account.invoice'].create({ + 'currency_id': self.env.ref('base.EUR').id, + 'invoice_line_ids': [(0, 0, { + 'name': '[PCSC234] PC Assemble SC234', + 'product_id': product_3.id, + 'price_unit': 210.0, + 'quantity': 1.0, + 'uom_id': self.env.ref('product.product_uom_unit').id, + 'account_id': self.env.ref('account.a_sale').id, + })], + 'journal_id': self.journal.id, + 'partner_id': self.partner.id, + 'reference_type': 'none', + 'account_id': self.env.ref('account.a_recv').id, + }) + # I confirm the Invoice + self.invoice_for_completion_1.action_invoice_open() + # I check that the invoice state is "Open" + self.assertEqual(self.invoice_for_completion_1.state, 'open') + # I check that it is given the number "TBNK/%Y/0001" + self.assertEqual( + self.invoice_for_completion_1.number, + dt.date.today().strftime('TBNK/%Y/0001') + ) + + def test_03_supplier_invoice(self): + # I import account minimal data + convert_file( + self.cr, 'account', get_resource_path( + 'account', 'demo', 'account_invoice_demo.yml' + ), {}, 'init', False, 'test' + ) + + # I check that my invoice is a supplier invoice + demo_invoice_0 = self.env.ref('account.demo_invoice_0') + self.assertEqual( + demo_invoice_0.type, 'in_invoice', msg="Check invoice type" + ) + # I add a reference to an existing supplier invoice + demo_invoice_0.write({'reference': 'T2S12345'}) + # I check a second time that my invoice is still a supplier invoice + self.assertEqual( + demo_invoice_0.type, 'in_invoice', msg="Check invoice type 2" + ) + # Now I confirm it + demo_invoice_0.action_invoice_open() + # I check that the supplier number is there + self.assertEqual( + demo_invoice_0.reference, 'T2S12345', msg="Check supplier number" + ) + # I check a third time that my invoice is still a supplier invoice + self.assertEqual( + demo_invoice_0.type, 'in_invoice', msg="Check invoice type 3" + ) + + def test_04_refund(self): + # I create a "child" partner, to use in the invoice + # (and have a different commercial_partner_id than itself) + res_partner_12_child = self.env['res.partner'].create({ + 'name': 'Child Partner', + 'supplier': False, + 'customer': True, + 'is_company': False, + 'parent_id': self.partner.id, + }) + # I create a customer refund to be found by the completion. + product_3 = self.env.ref('product.product_product_3') + self.refund_for_completion_1 = self.env['account.invoice'].create({ + 'currency_id': self.env.ref('base.EUR').id, + 'invoice_line_ids': [(0, 0, { + 'name': '[PCSC234] PC Assemble SC234', + 'product_id': product_3.id, + 'price_unit': 210.0, + 'quantity': 1.0, + 'uom_id': self.env.ref('product.product_uom_unit').id, + 'account_id': self.env.ref('account.a_sale').id, + })], + 'journal_id': self.env.ref('account.expenses_journal').id, + 'partner_id': res_partner_12_child.id, + 'type': 'out_refund', + 'reference_type': 'none', + 'account_id': self.env.ref('account.a_recv').id, + }) + # I confirm the refund + self.refund_for_completion_1.action_invoice_open() + + # I check that the refund state is "Open" + self.assertEqual(self.refund_for_completion_1.state, 'open') + # I check that it is given the number "RTEXJ/%Y/0001" + self.assertEqual( + self.refund_for_completion_1.number, + dt.date.today().strftime('RTEXJ/%Y/0001') + ) + + def test_05_completion(self): + + # In order to test the banking framework, I first need to create a + # journal + self.journal = self.env.ref("account.bank_journal") + completion_rule_4 = self.env.ref( + 'account_move_base_import.bank_statement_completion_rule_4' + ) + completion_rule_2 = self.env.ref( + 'account_move_base_import.bank_statement_completion_rule_2' + ) + completion_rule_3 = self.env.ref( + 'account_move_base_import.bank_statement_completion_rule_3' + ) + completion_rule_5 = self.env.ref( + 'account_move_base_import.bank_statement_completion_rule_5' + ) + completion_rules = ( + completion_rule_2 | completion_rule_3 | completion_rule_4 + | completion_rule_5 + ) + self.journal.write({ + 'used_for_completion': True, + 'rule_ids': [ + (4, comp_rule.id, False) for comp_rule in completion_rules + ] + }) + # Now I create a statement. I create statment lines separately because + # I need to find each one by XML id + move_test1 = self.env['account.move'].create({ + 'name': 'Move 2', + 'journal_id': self.journal.id, + }) + # I create a move line for a CI + move_line_ci = self.env['account.move.line'].create({ + 'name': '\\', + 'account_id': self.env.ref('account.a_sale').id, + 'move_id': move_test1.id, + 'date_maturity': '2013-12-20', + 'credit': 0.0, + }) + # I create a move line for a SI + move_line_si = self.env['account.move.line'].create({ + 'name': '\\', + 'account_id': self.env.ref('account.a_expense').id, + 'move_id': move_test1.id, + 'date_maturity': '2013-12-19', + 'debit': 0.0, + }) + # I create a move line for a CR + move_line_cr = self.env['account.move.line'].create({ + 'name': '\\', + 'account_id': self.env.ref('account.a_expense').id, + 'move_id': move_test1.id, + 'date_maturity': '2013-12-19', + 'debit': 0.0, + }) + # I create a move line for the Partner Name + move_line_partner_name = self.env['account.move.line'].create({ + 'name': 'Test autocompletion based on Partner Name Camptocamp', + 'account_id': self.env.ref('account.a_sale').id, + 'move_id': move_test1.id, + 'date_maturity': '2013-12-17', + 'credit': 0.0, + }) + # I create a move line for the Partner Label + move_line_partner_label = self.env['account.move.line'].create({ + 'name': 'XXX66Z', + 'account_id': self.env.ref('account.a_sale').id, + 'move_id': move_test1.id, + 'date_maturity': '2013-12-24', + 'debit': 0.0, + }) + # and add the correct name + move_line_ci.with_context(check_move_validity=False).write({ + 'name': dt.date.today().strftime('TBNK/%Y/0001'), + 'credit': 210.0, + }) + move_line_si.with_context(check_move_validity=False).write({ + 'name': 'T2S12345', + 'debit': 65.0, + }) + move_line_cr.with_context(check_move_validity=False).write({ + 'name': dt.date.today().strftime('RTEXJ/%Y/0001'), + 'debit': 210.0, + }) + move_line_partner_name.with_context(check_move_validity=False).write({ + 'credit': 600.0, + }) + move_line_partner_label.with_context(check_move_validity=False).write({ + 'debit': 932.4, + }) + # I run the auto complete + move_test1.button_auto_completion() + # Now I can check that all is nice and shiny, line 1. I expect the + # Customer Invoice Number to be recognised. + # I Use _ref, because ref conflicts with the field ref of the + # statement line + self.assertEqual( + move_line_ci.partner_id, self.partner, + msg="Check completion by CI number" + ) + # Line 2. I expect the Supplier invoice number to be recognised. The + # supplier invoice was created by the account module demo data, and we + # confirmed it here. + self.assertEqual( + move_line_si.partner_id, self.partner, + msg="Check completion by SI number" + ) + # Line 3. I expect the Customer refund number to be recognised. It + # should be the commercial partner, and not the regular partner. + self.assertEqual( + move_line_cr.partner_id, self.partner, + msg="Check completion by CR number and commercial partner" + ) + # Line 4. I check that the partner name has been recognised. + self.assertEqual( + move_line_partner_name.partner_id.name, 'Camptocamp', + msg="Check completion by partner name" + ) + # Line 5. I check that the partner special label has been recognised. + self.partner_4 = self.env.ref('base.res_partner_4') + self.assertEqual( + move_line_partner_label.partner_id, + self.partner_4, + msg="Check completion by partner label" + ) diff --git a/account_move_base_import/views/account_move_view.xml b/account_move_base_import/views/account_move_view.xml index 68c81535..05108438 100644 --- a/account_move_base_import/views/account_move_view.xml +++ b/account_move_base_import/views/account_move_view.xml @@ -8,7 +8,7 @@ -