From 56d0ca5f812947a9fa3701535bffc775a0b0affa Mon Sep 17 00:00:00 2001 From: Jordi Ballester Alomar Date: Tue, 1 Oct 2019 05:43:11 +0200 Subject: [PATCH 01/15] [12.0][add] account_bank_statement_import_txt --- account_bank_statement_import_txt/__init__.py | 2 + .../__manifest__.py | 25 +++ .../data/txt_map_data.xml | 53 +++++ .../models/__init__.py | 2 + .../account_bank_statement_import_txt_map.py | 106 +++++++++ .../models/account_journal.py | 19 ++ .../readme/CONFIGURE.rst | 12 + .../readme/CONTRIBUTORS.rst | 7 + .../readme/DESCRIPTION.rst | 2 + .../readme/USAGE.rst | 3 + .../security/ir.model.access.csv | 3 + .../tests/__init__.py | 1 + .../tests/sample_statement_en.csv | 3 + .../tests/test_txt_statement_import.py | 67 ++++++ .../views/account_journal_views.xml | 16 ++ .../views/txt_map_views.xml | 67 ++++++ .../wizards/__init__.py | 2 + .../account_bank_statement_import_txt.py | 208 ++++++++++++++++++ .../account_bank_statement_import_view.xml | 14 ++ .../wizards/create_map_lines_from_file.py | 40 ++++ .../create_map_lines_from_file_views.xml | 29 +++ 21 files changed, 681 insertions(+) create mode 100644 account_bank_statement_import_txt/__init__.py create mode 100644 account_bank_statement_import_txt/__manifest__.py create mode 100644 account_bank_statement_import_txt/data/txt_map_data.xml create mode 100644 account_bank_statement_import_txt/models/__init__.py create mode 100644 account_bank_statement_import_txt/models/account_bank_statement_import_txt_map.py create mode 100644 account_bank_statement_import_txt/models/account_journal.py create mode 100644 account_bank_statement_import_txt/readme/CONFIGURE.rst create mode 100644 account_bank_statement_import_txt/readme/CONTRIBUTORS.rst create mode 100644 account_bank_statement_import_txt/readme/DESCRIPTION.rst create mode 100644 account_bank_statement_import_txt/readme/USAGE.rst create mode 100644 account_bank_statement_import_txt/security/ir.model.access.csv create mode 100644 account_bank_statement_import_txt/tests/__init__.py create mode 100644 account_bank_statement_import_txt/tests/sample_statement_en.csv create mode 100644 account_bank_statement_import_txt/tests/test_txt_statement_import.py create mode 100644 account_bank_statement_import_txt/views/account_journal_views.xml create mode 100644 account_bank_statement_import_txt/views/txt_map_views.xml create mode 100644 account_bank_statement_import_txt/wizards/__init__.py create mode 100644 account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py create mode 100644 account_bank_statement_import_txt/wizards/account_bank_statement_import_view.xml create mode 100644 account_bank_statement_import_txt/wizards/create_map_lines_from_file.py create mode 100644 account_bank_statement_import_txt/wizards/create_map_lines_from_file_views.xml diff --git a/account_bank_statement_import_txt/__init__.py b/account_bank_statement_import_txt/__init__.py new file mode 100644 index 0000000000..aee8895e7a --- /dev/null +++ b/account_bank_statement_import_txt/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import wizards diff --git a/account_bank_statement_import_txt/__manifest__.py b/account_bank_statement_import_txt/__manifest__.py new file mode 100644 index 0000000000..f52c0524f5 --- /dev/null +++ b/account_bank_statement_import_txt/__manifest__.py @@ -0,0 +1,25 @@ +# Copyright 2014-2017 Akretion (http://www.akretion.com). +# @author Alexis de Lattre +# @author Sébastien BEAU +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +{ + "name": "Import Text Bank Statements", + 'summary': 'Import TXT/CSV files as Bank Statements in Odoo', + "version": "12.0.1.0.1", + "category": "Accounting", + "website": "https://github.com/OCA/bank-statement-import", + "author": " Eficent, Odoo Community Association (OCA)", + "license": "AGPL-3", + "installable": True, + "depends": [ + "account_bank_statement_import", + ], + "data": [ + "security/ir.model.access.csv", + "data/txt_map_data.xml", + "wizards/create_map_lines_from_file_views.xml", + "wizards/account_bank_statement_import_view.xml", + "views/account_journal_views.xml", + "views/txt_map_views.xml", + ] +} diff --git a/account_bank_statement_import_txt/data/txt_map_data.xml b/account_bank_statement_import_txt/data/txt_map_data.xml new file mode 100644 index 0000000000..c18c4f0a36 --- /dev/null +++ b/account_bank_statement_import_txt/data/txt_map_data.xml @@ -0,0 +1,53 @@ + + + + + Sample Statement + comma + dot + + + + Date + 0 + + date + %m/%d/%Y + + + Label + 1 + + name + + + Currency + 2 + + currency + + + Amount + 3 + + amount + + + Amount Currency + 4 + + amount_currency + + + Partner Name + 5 + + partner_name + + + Bank Account + 6 + + account_number + + diff --git a/account_bank_statement_import_txt/models/__init__.py b/account_bank_statement_import_txt/models/__init__.py new file mode 100644 index 0000000000..ff680f4cb0 --- /dev/null +++ b/account_bank_statement_import_txt/models/__init__.py @@ -0,0 +1,2 @@ +from . import account_bank_statement_import_txt_map +from . import account_journal diff --git a/account_bank_statement_import_txt/models/account_bank_statement_import_txt_map.py b/account_bank_statement_import_txt/models/account_bank_statement_import_txt_map.py new file mode 100644 index 0000000000..289fc6f219 --- /dev/null +++ b/account_bank_statement_import_txt/models/account_bank_statement_import_txt_map.py @@ -0,0 +1,106 @@ +# Copyright 2019 Tecnativa - Vicent Cubells +# Copyright 2019 Eficent Business and IT Consulting Services, S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models, api + + +class AccountBankStatementImportTxtMap(models.Model): + _name = 'account.bank.statement.import.txt.map' + _description = 'Account Bank Statement Import Txt Map' + + name = fields.Char( + required=True, + ) + map_line_ids = fields.One2many( + comodel_name='account.bank.statement.import.txt.map.line', + inverse_name='map_parent_id', + string="Map lines", + required=True, + copy=True, + ) + float_thousands_sep = fields.Selection( + [('dot', 'dot (.)'), + ('comma', 'comma (,)'), + ('none', 'none'), + ], + string='Thousands separator', + # forward compatibility: this was the value assumed + # before the field was added. + default='dot', + required=True + ) + float_decimal_sep = fields.Selection( + [('dot', 'dot (.)'), + ('comma', 'comma (,)'), + ('none', 'none'), + ], + string='Decimals separator', + # forward compatibility: this was the value assumed + # before the field was added. + default='comma', + required=True + ) + + @api.onchange('float_thousands_sep') + def onchange_thousands_separator(self): + if 'dot' == self.float_thousands_sep == self.float_decimal_sep: + self.float_decimal_sep = 'comma' + elif 'comma' == self.float_thousands_sep == self.float_decimal_sep: + self.float_decimal_sep = 'dot' + + @api.onchange('float_decimal_sep') + def onchange_decimal_separator(self): + if 'dot' == self.float_thousands_sep == self.float_decimal_sep: + self.float_thousands_sep = 'comma' + elif 'comma' == self.float_thousands_sep == self.float_decimal_sep: + self.float_thousands_sep = 'dot' + + def _get_separators(self): + separators = {'dot': '.', + 'comma': ',', + 'none': '', + } + return (separators[self.float_thousands_sep], + separators[self.float_decimal_sep]) + + +class AccountBankStatementImportTxtMapLine(models.Model): + _name = 'account.bank.statement.import.txt.map.line' + _description = 'Account Bank Statement Import Txt Map Line' + _order = "sequence asc, id asc" + + sequence = fields.Integer( + string="Field number", + required=True, + ) + name = fields.Char( + string="Header Name", + required=True, + ) + map_parent_id = fields.Many2one( + comodel_name='account.bank.statement.import.txt.map', + required=True, + ondelete='cascade', + ) + field_to_assign = fields.Selection( + selection=[ + ('date', 'Date'), + ('name', 'Label'), + ('currency', 'Currency'), + ('amount', 'Amount in the journal currency'), + ('amount_currency', 'Amount in foreign currency'), + ('ref', 'Reference'), + ('note', 'Notes'), + ('partner_name', 'Name'), + ('account_number', 'Bank Account Number'), + ], + string="Statement Field to Assign", + ) + date_format = fields.Selection( + selection=[ + ('%d/%m/%Y', 'i.e. 15/12/2019'), + ('%m/%d/%Y', 'i.e. 12/15/2019'), + ], + string="Date Format", + ) diff --git a/account_bank_statement_import_txt/models/account_journal.py b/account_bank_statement_import_txt/models/account_journal.py new file mode 100644 index 0000000000..105ecce1be --- /dev/null +++ b/account_bank_statement_import_txt/models/account_journal.py @@ -0,0 +1,19 @@ +# Copyright 2019 Tecnativa - Vicent Cubells +# Copyright 2019 Eficent Business and IT Consulting Services, S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class AccountJournal(models.Model): + _inherit = "account.journal" + + statement_import_txt_map_id = fields.Many2one( + comodel_name='account.bank.statement.import.txt.map', + string='Statement Import Txt Map', + ) + + def _get_bank_statements_available_import_formats(self): + res = super()._get_bank_statements_available_import_formats() + res.append('Txt') + return res diff --git a/account_bank_statement_import_txt/readme/CONFIGURE.rst b/account_bank_statement_import_txt/readme/CONFIGURE.rst new file mode 100644 index 0000000000..97c4cc4f59 --- /dev/null +++ b/account_bank_statement_import_txt/readme/CONFIGURE.rst @@ -0,0 +1,12 @@ +* Create or go to a bank journal where you want to import the txt statement. +* Edit that journal and set a Txt map in **Statement Import Txt Map** section in **Advanced + Settings** tab. + +* Now you can import Text based statements in that journal. + +Note: if existent Txt Map does not fit to your file to import, you can +create another map in **Invoicing > Configuration > Accounting > +Statement Import Txt Mapping**. + +You can import headers from any Txt file in **Action > Create Txt Map +Lines** and set every line with which field of statement have to match. diff --git a/account_bank_statement_import_txt/readme/CONTRIBUTORS.rst b/account_bank_statement_import_txt/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..0e58309108 --- /dev/null +++ b/account_bank_statement_import_txt/readme/CONTRIBUTORS.rst @@ -0,0 +1,7 @@ +* Alexis de Lattre +* Sebastien BEAU +* Tecnativa (https://www.tecnativa.com) + * Vicent Cubells + * Victor M.M. Torres +* Eficent (https://www.eficent.com) + * Jordi Ballester Alomar diff --git a/account_bank_statement_import_txt/readme/DESCRIPTION.rst b/account_bank_statement_import_txt/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..3994412c5e --- /dev/null +++ b/account_bank_statement_import_txt/readme/DESCRIPTION.rst @@ -0,0 +1,2 @@ +This module allows you to import the any TXT file in Odoo as bank +statements. diff --git a/account_bank_statement_import_txt/readme/USAGE.rst b/account_bank_statement_import_txt/readme/USAGE.rst new file mode 100644 index 0000000000..539be0fa51 --- /dev/null +++ b/account_bank_statement_import_txt/readme/USAGE.rst @@ -0,0 +1,3 @@ +To use this module, you need to: + +#. Go to your bank online and download your Bank Statement in TXT/CSV format. diff --git a/account_bank_statement_import_txt/security/ir.model.access.csv b/account_bank_statement_import_txt/security/ir.model.access.csv new file mode 100644 index 0000000000..9cfe3a2a7e --- /dev/null +++ b/account_bank_statement_import_txt/security/ir.model.access.csv @@ -0,0 +1,3 @@ +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" +access_account_bank_statement_import_txt_map,txt map manager,model_account_bank_statement_import_txt_map,account.group_account_manager,1,1,1,1 +access_account_bank_statement_import_txt_map_line,txt map line manager,model_account_bank_statement_import_txt_map_line,account.group_account_manager,1,1,1,1 diff --git a/account_bank_statement_import_txt/tests/__init__.py b/account_bank_statement_import_txt/tests/__init__.py new file mode 100644 index 0000000000..3260f75378 --- /dev/null +++ b/account_bank_statement_import_txt/tests/__init__.py @@ -0,0 +1 @@ +from . import test_txt_statement_import diff --git a/account_bank_statement_import_txt/tests/sample_statement_en.csv b/account_bank_statement_import_txt/tests/sample_statement_en.csv new file mode 100644 index 0000000000..c50bfc83c8 --- /dev/null +++ b/account_bank_statement_import_txt/tests/sample_statement_en.csv @@ -0,0 +1,3 @@ +"Date","Label","Currency","Amount","Amount Currency","Partner Name","Bank Account" +"12/15/2018","Your best supplier","USD","-33.50","0.0","John Doe","123456789" +"12/15/2018","Your payment","EUR","1,525.00","1,000.00","Azure Interior","" diff --git a/account_bank_statement_import_txt/tests/test_txt_statement_import.py b/account_bank_statement_import_txt/tests/test_txt_statement_import.py new file mode 100644 index 0000000000..17b78912d2 --- /dev/null +++ b/account_bank_statement_import_txt/tests/test_txt_statement_import.py @@ -0,0 +1,67 @@ +# Copyright 2019 Tecnativa - Vicent Cubells +# Copyright 2019 Eficent Business and IT Consulting Services, S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import os +import base64 +from odoo.tests import common + + +class TestTxtFile(common.TransactionCase): + + def setUp(self): + super(TestTxtFile, self).setUp() + + self.map = self.env['account.bank.statement.import.txt.map'].create({ + 'name': 'Txt Map Test', + }) + usd = self.env.ref('base.USD') + self.journal = self.env['account.journal'].create({ + 'name': 'Txt Bank', + 'type': 'bank', + 'code': 'TXT', + 'currency_id': ( + usd.id if self.env.user.company_id.currency_id != usd + else False + ), + }) + + def _do_import(self, file_name): + file_name = os.path.join(os.path.dirname(__file__), file_name) + return open(file_name).read() + + def test_import_header(self): + file = self._do_import('sample_statement_en.csv') + file = base64.b64encode(file.encode("utf-8")) + wizard = self.env['wizard.txt.map.create'].with_context({ + 'journal_id': self.journal.id, + 'active_ids': [self.map.id], + }).create({'data_file': file}) + wizard.create_map_lines() + self.assertEqual(len(self.map.map_line_ids.ids), 7) + + def test_import_txt_file(self): + # Current statements before to run the wizard + old_statements = self.env['account.bank.statement'].search([]) + # This journal is for Txt statements + txt_map = self.env.ref( + 'account_bank_statement_import_txt.txt_map' + ) + self.journal.statement_import_txt_map_id = txt_map.id + file = self._do_import('sample_statement_en.csv') + file = base64.b64encode(file.encode("utf-8")) + wizard = self.env['account.bank.statement.import'].with_context({ + 'journal_id': self.journal.id, + }).create({'data_file': file}) + wizard.import_file() + staments_now = self.env['account.bank.statement'].search([]) + statement = staments_now - old_statements + self.assertEqual(len(statement.line_ids), 2) + self.assertEqual(len(statement.mapped('line_ids').filtered( + lambda x: x.partner_id)), 1) + self.assertAlmostEqual( + sum(statement.mapped('line_ids.amount')), 1491.50 + ) + self.assertAlmostEqual( + sum(statement.mapped('line_ids.amount_currency')), 1000.00 + ) diff --git a/account_bank_statement_import_txt/views/account_journal_views.xml b/account_bank_statement_import_txt/views/account_journal_views.xml new file mode 100644 index 0000000000..b7be6cd234 --- /dev/null +++ b/account_bank_statement_import_txt/views/account_journal_views.xml @@ -0,0 +1,16 @@ + + + + + account.journal + + + + + + + + + + + diff --git a/account_bank_statement_import_txt/views/txt_map_views.xml b/account_bank_statement_import_txt/views/txt_map_views.xml new file mode 100644 index 0000000000..3cac91a47d --- /dev/null +++ b/account_bank_statement_import_txt/views/txt_map_views.xml @@ -0,0 +1,67 @@ + + + + + account.bank.statement.import.txt.map + + + + + + + + + account.bank.statement.import.txt.map + +
+ + + + + + + + + +
+ + + account.bank.statement.import.txt.map.line + + + + + + + + + + + + account.bank.statement.import.txt.map.line + +
+ + + + + + + +
+
+
+ + + TXT Statement Import Mapping + account.bank.statement.import.txt.map + form + tree,form + + + + +
diff --git a/account_bank_statement_import_txt/wizards/__init__.py b/account_bank_statement_import_txt/wizards/__init__.py new file mode 100644 index 0000000000..ec27082d37 --- /dev/null +++ b/account_bank_statement_import_txt/wizards/__init__.py @@ -0,0 +1,2 @@ +from . import create_map_lines_from_file +from . import account_bank_statement_import_txt diff --git a/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py b/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py new file mode 100644 index 0000000000..70c5f6c4f5 --- /dev/null +++ b/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py @@ -0,0 +1,208 @@ +# Copyright 2014-2017 Akretion (http://www.akretion.com). +# @author Alexis de Lattre +# @author Sébastien BEAU +# Copyright 2019 Eficent Business and IT Consulting Services, S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import logging +from datetime import datetime +from odoo import _, api, fields, models +from odoo.exceptions import UserError +import re +from io import StringIO +_logger = logging.getLogger(__name__) + +try: + import csv +except (ImportError, IOError) as err: + _logger.debug(err) + + +class AccountBankStatementImport(models.TransientModel): + _inherit = 'account.bank.statement.import' + + txt_map_id = fields.Many2one( + comodel_name='account.bank.statement.import.txt.map', + string='Txt map', + readonly=True, + ) + + @api.model + def _get_txt_encoding(self): + return 'utf-8-sig' + + @api.model + def _get_txt_str_data(self, data_file): + if not isinstance(data_file, str): + data_file = data_file.decode(self._get_txt_encoding()) + return data_file.strip() + + @api.model + def _txt_convert_amount(self, amount_str): + if not amount_str: + return 0.0 + if self.txt_map_id: + thousands, decimal = self.txt_map_id._get_separators() + else: + thousands, decimal = ',', '.' + valstr = re.sub(r'[^\d%s%s.-]' % (thousands, decimal), '', amount_str) + valstrdot = valstr.replace(thousands, '') + valstrdot = valstrdot.replace(decimal, '.') + return float(valstrdot) + + @api.model + def _check_txt(self, data_file): + data_file = self._get_txt_str_data(data_file) + if not self.txt_map_id: + return False + headers = self.mapped('txt_map_id.map_line_ids.name') + file_headers = data_file.split('\n', 1)[0] + if any(item not in file_headers for item in headers): + raise UserError( + _("Headers of file to import and Txt map lines does not " + "match.")) + return True + + def _get_currency_fields(self): + return ['amount', 'amount_currency'] + + def _convert_txt_line_to_dict(self, idx, line): + rline = dict() + for item in range(len(line)): + txt_map = self.mapped('txt_map_id.map_line_ids')[item] + value = line[item] + if not txt_map.field_to_assign: + continue + if txt_map.date_format: + try: + value = fields.Date.to_string( + datetime.strptime(value, txt_map.date_format)) + except Exception: + raise UserError( + _("Date format of map file and Txt date does " + "not match.")) + rline[txt_map.field_to_assign] = value + for field in self._get_currency_fields(): + _logger.debug('Trying to convert %s to float' % rline[field]) + try: + rline[field] = self._txt_convert_amount(rline[field]) + except Exception: + raise UserError( + _("Value '%s' for the field '%s' on line %d, " + "cannot be converted to float") + % (rline[field], field, idx)) + return rline + + def _parse_txt_file(self, data_file): + data_file = self._get_txt_str_data(data_file) + f = StringIO(data_file) + f.seek(0) + raw_lines = [] + reader = csv.reader(f) + next(reader) # Drop header + for idx, line in enumerate(reader): + _logger.debug("Line %d: %s" % (idx, line)) + raw_lines.append(self._convert_txt_line_to_dict(idx, line)) + return raw_lines + + def _post_process_statement_line(self, raw_lines): + """ Enter your additional logic here. """ + return raw_lines + + def _get_journal(self): + journal_id = self.env.context.get('journal_id') + if not journal_id: + raise UserError(_('You must run this wizard from the journal')) + return self.env['account.journal'].browse(journal_id) + + def _get_currency_id(self, fline): + journal = self._get_journal() + line_currency_name = fline.get('currency', False) + currency = journal.currency_id or journal.company_id.currency_id + if line_currency_name and line_currency_name != currency.name: + currency = self.env['res.currency'].search( + [('name', '=', fline['currency'])], limit=1) + return currency.id + return False + + @api.model + def _get_partner_id(self, fline): + partner_name = fline.get('partner_name', False) + if partner_name: + partner = self.env['res.partner'].search([ + ('name', '=ilike', partner_name)]) + if partner and len(partner) == 1: + return partner.commercial_partner_id.id + return None + + def _prepare_txt_statement_line(self, fline): + currency_id = self._get_currency_id(fline) + return { + 'date': fline.get('date', False), + 'name': fline.get('name', ''), + 'ref': fline.get('ref', False), + 'note': fline.get('Notes', False), + 'amount': fline.get('amount', 0.0), + 'currency_id': self._get_currency_id(fline), + 'amount_currency': currency_id and fline.get( + 'amount_currency', 0.0) or 0.0, + 'partner_id': self._get_partner_id(fline), + 'account_number': fline.get('account_number', False), + } + + def _prepare_txt_statement(self, lines): + balance_end_real = 0.0 + for line in lines: + if 'amount' in line and line['amount']: + balance_end_real += line['amount'] + + return { + 'name': + _('%s Import %s > %s') + % (self.txt_map_id.name, + lines[0]['date'], lines[-1]['date']), + 'date': lines[-1]['date'], + 'balance_start': 0.0, + 'balance_end_real': balance_end_real, + } + + @api.model + def _parse_file(self, data_file): + """ Import a file in Txt CSV format """ + txt = self._check_txt(data_file) + if not txt: + return super(AccountBankStatementImport, self)._parse_file( + data_file) + + raw_lines = self._parse_txt_file(data_file) + final_lines = self._post_process_statement_line(raw_lines) + vals_bank_statement = self._prepare_txt_statement(final_lines) + transactions = [] + for fline in final_lines: + vals_line = self._prepare_txt_statement_line(fline) + _logger.debug("vals_line = %s" % vals_line) + transactions.append(vals_line) + vals_bank_statement['transactions'] = transactions + return None, None, [vals_bank_statement] + + @api.model + def _complete_txt_statement_line(self, line): + """ Enter additional logic here. """ + return None + + @api.model + def _complete_stmts_vals(self, stmts_vals, journal_id, account_number): + stmts_vals = super(AccountBankStatementImport, self). \ + _complete_stmts_vals(stmts_vals, journal_id, account_number) + for line in stmts_vals[0]['transactions']: + vals = self._complete_txt_statement_line(line) + if vals: + line.update(vals) + return stmts_vals + + @api.model + def default_get(self, fields): + res = super(AccountBankStatementImport, self).default_get(fields) + journal = self._get_journal() + res['txt_map_id'] = journal.statement_import_txt_map_id.id + return res diff --git a/account_bank_statement_import_txt/wizards/account_bank_statement_import_view.xml b/account_bank_statement_import_txt/wizards/account_bank_statement_import_view.xml new file mode 100644 index 0000000000..318216222d --- /dev/null +++ b/account_bank_statement_import_txt/wizards/account_bank_statement_import_view.xml @@ -0,0 +1,14 @@ + + + + + account.bank.statement.import + + + +
  • Txt file with Template:
  • +
    +
    +
    + +
    diff --git a/account_bank_statement_import_txt/wizards/create_map_lines_from_file.py b/account_bank_statement_import_txt/wizards/create_map_lines_from_file.py new file mode 100644 index 0000000000..46aa027693 --- /dev/null +++ b/account_bank_statement_import_txt/wizards/create_map_lines_from_file.py @@ -0,0 +1,40 @@ +# Copyright 2019 Tecnativa - Vicent Cubells +# Copyright 2019 Eficent Business and IT Consulting Services, S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import csv +import base64 +from odoo import api, fields, models +from io import StringIO + + +class WizardTxtMapCreate(models.TransientModel): + _name = 'wizard.txt.map.create' + _description = 'Wizard Txt Map Create' + + data_file = fields.Binary( + string='Bank Statement File', + required=True, + ) + filename = fields.Char() + + @api.multi + def create_map_lines(self): + statement_obj = self.env['account.bank.statement.import.txt.map'] + data_file = base64.b64decode(self.data_file) + if not isinstance(data_file, str): + data_file = data_file.decode('utf-8-sig').strip() + file = StringIO(data_file) + file.seek(0) + reader = csv.reader(file) + headers = [] + for row in reader: + headers = row + break + lines = [] + for idx, title in enumerate(headers): + lines.append((0, 0, {'sequence': idx, 'name': title})) + if lines: + for statement in statement_obj.browse( + self.env.context.get('active_ids')): + statement.map_line_ids = lines diff --git a/account_bank_statement_import_txt/wizards/create_map_lines_from_file_views.xml b/account_bank_statement_import_txt/wizards/create_map_lines_from_file_views.xml new file mode 100644 index 0000000000..5dd023be93 --- /dev/null +++ b/account_bank_statement_import_txt/wizards/create_map_lines_from_file_views.xml @@ -0,0 +1,29 @@ + + + + + Create Txt Map Lines + wizard.txt.map.create + +
    +

    Select a TXT/CSV bank statement file to create all the map lines from headers file.

    +

    Download a bank statement from your bank and import it here.

    +

    All the txt map lines will be created automatically.

    + + +
    +
    + +
    +
    + + +
    From 1dbaee362e14b4fe4125afbe5306de417d1049bd Mon Sep 17 00:00:00 2001 From: Joan Sisquella Date: Mon, 9 Dec 2019 16:25:53 +0100 Subject: [PATCH 02/15] [12.0][IMP] account_bank_statement_import_txt: * add string delimiter, encoding and encoding separator selection --- .../account_bank_statement_import_txt_map.py | 30 +++++++++++++++++++ .../views/txt_map_views.xml | 3 ++ .../account_bank_statement_import_txt.py | 5 +++- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/account_bank_statement_import_txt/models/account_bank_statement_import_txt_map.py b/account_bank_statement_import_txt/models/account_bank_statement_import_txt_map.py index 289fc6f219..8a05bf31c2 100644 --- a/account_bank_statement_import_txt/models/account_bank_statement_import_txt_map.py +++ b/account_bank_statement_import_txt/models/account_bank_statement_import_txt_map.py @@ -41,6 +41,36 @@ class AccountBankStatementImportTxtMap(models.Model): default='comma', required=True ) + file_encoding = fields.Selection( + string='Encoding', + selection=[ + ('utf-8', 'UTF-8'), + ('utf-16 ', 'UTF-18'), + ('windows-1252', 'Windows-1252'), + ('latin1', 'latin1'), + ('latin2', 'latin2'), + ('big5', 'big5'), + ('gb18030', 'gb18030'), + ('shift_jis', 'shift_jis'), + ('windows-1251', 'windows-1251'), + ('koir8_r', 'koir9_r'), + ], + default='utf-8', + required=True + ) + delimiter = fields.Selection( + string='Separated by', + selection=[ + ('dot', 'dot (.)'), + ('comma', 'comma (,)'), + ('none', 'none'), + ('\t', 'Tab'), + (' ', 'Space'), + ], + default='comma', + required=True + ) + quotechar = fields.Char(string='String delimiter', size=1) @api.onchange('float_thousands_sep') def onchange_thousands_separator(self): diff --git a/account_bank_statement_import_txt/views/txt_map_views.xml b/account_bank_statement_import_txt/views/txt_map_views.xml index 3cac91a47d..5a7047e6df 100644 --- a/account_bank_statement_import_txt/views/txt_map_views.xml +++ b/account_bank_statement_import_txt/views/txt_map_views.xml @@ -18,6 +18,9 @@ + + + diff --git a/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py b/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py index 70c5f6c4f5..e5ab26a916 100644 --- a/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py +++ b/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py @@ -29,6 +29,8 @@ class AccountBankStatementImport(models.TransientModel): @api.model def _get_txt_encoding(self): + if self.txt_map_id.file_encoding: + return self.txt_map_id.file_encoding return 'utf-8-sig' @api.model @@ -98,7 +100,8 @@ def _parse_txt_file(self, data_file): f = StringIO(data_file) f.seek(0) raw_lines = [] - reader = csv.reader(f) + reader = csv.reader(f, quotechar=self.txt_map_id.quotechar, + delimiter=self.txt_map_id.delimiter or False) next(reader) # Drop header for idx, line in enumerate(reader): _logger.debug("Line %d: %s" % (idx, line)) From 801cb45dfe4eff9696ae21635aaee9402aeb3f63 Mon Sep 17 00:00:00 2001 From: Joan Sisquella Date: Wed, 11 Dec 2019 12:15:49 +0100 Subject: [PATCH 03/15] [12.0][IMP] account_bank_statement_import_txt: * add semicolon ";" as a encoding separator --- .../models/account_bank_statement_import_txt_map.py | 13 ++++++------- .../wizards/account_bank_statement_import_txt.py | 9 +++++++-- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/account_bank_statement_import_txt/models/account_bank_statement_import_txt_map.py b/account_bank_statement_import_txt/models/account_bank_statement_import_txt_map.py index 8a05bf31c2..60d6d8ee95 100644 --- a/account_bank_statement_import_txt/models/account_bank_statement_import_txt_map.py +++ b/account_bank_statement_import_txt/models/account_bank_statement_import_txt_map.py @@ -56,19 +56,18 @@ class AccountBankStatementImportTxtMap(models.Model): ('koir8_r', 'koir9_r'), ], default='utf-8', - required=True ) delimiter = fields.Selection( string='Separated by', selection=[ - ('dot', 'dot (.)'), - ('comma', 'comma (,)'), - ('none', 'none'), + ('.', 'dot (.)'), + (',', 'comma (,)'), + (';', 'semicolon (;)'), + ('', 'none'), ('\t', 'Tab'), (' ', 'Space'), - ], - default='comma', - required=True + ], + default=',', ) quotechar = fields.Char(string='String delimiter', size=1) diff --git a/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py b/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py index e5ab26a916..ad15d8430e 100644 --- a/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py +++ b/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py @@ -100,8 +100,13 @@ def _parse_txt_file(self, data_file): f = StringIO(data_file) f.seek(0) raw_lines = [] - reader = csv.reader(f, quotechar=self.txt_map_id.quotechar, - delimiter=self.txt_map_id.delimiter or False) + if not self.txt_map_id.quotechar: + reader = csv.reader(f, + delimiter=self.txt_map_id.delimiter or False) + else: + reader = csv.reader(f, + quotechar=self.txt_map_id.quotechar, + delimiter=self.txt_map_id.delimiter or False) next(reader) # Drop header for idx, line in enumerate(reader): _logger.debug("Line %d: %s" % (idx, line)) From 59bae151de8015dc0e0cdd1f347edcbd030e23dd Mon Sep 17 00:00:00 2001 From: Jordi Ballester Alomar Date: Tue, 17 Dec 2019 12:31:27 +0100 Subject: [PATCH 04/15] introduce xls import --- .../account_bank_statement_import_txt.py | 86 +++++++++++++++++-- 1 file changed, 81 insertions(+), 5 deletions(-) diff --git a/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py b/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py index ad15d8430e..8db6fd0e98 100644 --- a/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py +++ b/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py @@ -3,7 +3,8 @@ # @author Sébastien BEAU # Copyright 2019 Eficent Business and IT Consulting Services, S.L. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - +import xlrd +from xlrd.sheet import ctype_text import logging from datetime import datetime from odoo import _, api, fields, models @@ -52,6 +53,31 @@ def _txt_convert_amount(self, amount_str): valstrdot = valstrdot.replace(decimal, '.') return float(valstrdot) + @api.model + def _check_xls(self, data_file): + # Try if it is an Excel file + headers = self.mapped('txt_map_id.map_line_ids.name') + try: + file_headers = [] + book = xlrd.open_workbook(file_contents=data_file) + xl_sheet = book.sheet_by_index(0) + row = xl_sheet.row(0) # 1st row + for idx, cell_obj in enumerate(row): + cell_type_str = ctype_text.get(cell_obj.ctype, False) + if cell_type_str: + file_headers.append(cell_obj.value) + else: + return False + if any(item not in file_headers for item in headers): + raise UserError( + _("Headers of file to import and Txt map lines does not " + "match.")) + except xlrd.XLRDError: + return False + except Exception as e: + return False + return True + @api.model def _check_txt(self, data_file): data_file = self._get_txt_str_data(data_file) @@ -113,6 +139,51 @@ def _parse_txt_file(self, data_file): raw_lines.append(self._convert_txt_line_to_dict(idx, line)) return raw_lines + def _convert_xls_line_to_dict(self, row_idx, xl_sheet): + rline = dict() + for col_idx in range(0, xl_sheet.ncols): # Iterate through columns + txt_map = self.mapped('txt_map_id.map_line_ids')[col_idx] + cell_obj = xl_sheet.cell(row_idx, col_idx) # Get cell + value = cell_obj.value + if not txt_map.field_to_assign: + continue + if txt_map.date_format: + # dt = datetime.datetime( + # *xlrd.xldate.xldate_as_tuple(value, xl_sheet.datemode)) + try: + value = fields.Date.to_string( + datetime.strptime(value, txt_map.date_format)) + except Exception: + raise UserError( + _("Date format of map file and Txt date does " + "not match.")) + rline[txt_map.field_to_assign] = value + for field in self._get_currency_fields(): + _logger.debug('Trying to convert %s to float' % rline[field]) + try: + rline[field] = self._txt_convert_amount(rline[field]) + except Exception: + raise UserError( + _("Value '%s' for the field '%s' on line %d, " + "cannot be converted to float") + % (rline[field], field, col_idx)) + return rline + + def _parse_xls_file(self, data_file): + try: + raw_lines = [] + book = xlrd.open_workbook(file_contents=data_file) + xl_sheet = book.sheet_by_index(0) + for row_idx in range(1, xl_sheet.nrows): + _logger.debug("Line %d" % row_idx) + raw_lines.append(self._convert_xls_line_to_dict( + row_idx, xl_sheet)) + except xlrd.XLRDError: + return False + except Exception as e: + return False + return True + def _post_process_statement_line(self, raw_lines): """ Enter your additional logic here. """ return raw_lines @@ -177,12 +248,17 @@ def _prepare_txt_statement(self, lines): @api.model def _parse_file(self, data_file): """ Import a file in Txt CSV format """ - txt = self._check_txt(data_file) - if not txt: + is_txt = False + is_xls = self._check_xls(data_file) + if not is_xls: + is_txt = self._check_txt(data_file) + if not is_txt and not is_xls: return super(AccountBankStatementImport, self)._parse_file( data_file) - - raw_lines = self._parse_txt_file(data_file) + if is_txt: + raw_lines = self._parse_txt_file(data_file) + elif is_xls: + raw_lines = self._parse_xls_file(data_file) final_lines = self._post_process_statement_line(raw_lines) vals_bank_statement = self._prepare_txt_statement(final_lines) transactions = [] From 131f11edd2877f6ac99e6bcefed7b8d78c0eb768 Mon Sep 17 00:00:00 2001 From: Joan Sisquella Date: Tue, 17 Dec 2019 15:57:37 +0100 Subject: [PATCH 05/15] introduce xls import --- .../account_bank_statement_import_txt_map.py | 2 +- .../account_bank_statement_import_txt.py | 30 ++++++------------- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/account_bank_statement_import_txt/models/account_bank_statement_import_txt_map.py b/account_bank_statement_import_txt/models/account_bank_statement_import_txt_map.py index 60d6d8ee95..911b1098f6 100644 --- a/account_bank_statement_import_txt/models/account_bank_statement_import_txt_map.py +++ b/account_bank_statement_import_txt/models/account_bank_statement_import_txt_map.py @@ -45,7 +45,7 @@ class AccountBankStatementImportTxtMap(models.Model): string='Encoding', selection=[ ('utf-8', 'UTF-8'), - ('utf-16 ', 'UTF-18'), + ('utf-16 ', 'UTF-16'), ('windows-1252', 'Windows-1252'), ('latin1', 'latin1'), ('latin2', 'latin2'), diff --git a/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py b/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py index 8db6fd0e98..29f0577344 100644 --- a/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py +++ b/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py @@ -3,10 +3,11 @@ # @author Sébastien BEAU # Copyright 2019 Eficent Business and IT Consulting Services, S.L. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + import xlrd from xlrd.sheet import ctype_text import logging -from datetime import datetime +import datetime from odoo import _, api, fields, models from odoo.exceptions import UserError import re @@ -144,29 +145,16 @@ def _convert_xls_line_to_dict(self, row_idx, xl_sheet): for col_idx in range(0, xl_sheet.ncols): # Iterate through columns txt_map = self.mapped('txt_map_id.map_line_ids')[col_idx] cell_obj = xl_sheet.cell(row_idx, col_idx) # Get cell + ctype = xl_sheet.cell(row_idx, col_idx).ctype value = cell_obj.value if not txt_map.field_to_assign: continue - if txt_map.date_format: - # dt = datetime.datetime( - # *xlrd.xldate.xldate_as_tuple(value, xl_sheet.datemode)) - try: - value = fields.Date.to_string( - datetime.strptime(value, txt_map.date_format)) - except Exception: - raise UserError( - _("Date format of map file and Txt date does " - "not match.")) + if ctype == 3: + ms_date_number = xl_sheet.cell(row_idx, col_idx).value + year, month, day, hour, minute, second = xlrd.xldate_as_tuple( + ms_date_number, 0) + value = datetime.date(year, month, day) rline[txt_map.field_to_assign] = value - for field in self._get_currency_fields(): - _logger.debug('Trying to convert %s to float' % rline[field]) - try: - rline[field] = self._txt_convert_amount(rline[field]) - except Exception: - raise UserError( - _("Value '%s' for the field '%s' on line %d, " - "cannot be converted to float") - % (rline[field], field, col_idx)) return rline def _parse_xls_file(self, data_file): @@ -182,7 +170,7 @@ def _parse_xls_file(self, data_file): return False except Exception as e: return False - return True + return raw_lines def _post_process_statement_line(self, raw_lines): """ Enter your additional logic here. """ From b9f1ebf5f17de635919286dce54e748034c1321b Mon Sep 17 00:00:00 2001 From: Joan Sisquella Date: Tue, 17 Dec 2019 16:52:12 +0100 Subject: [PATCH 06/15] code fixup --- .../wizards/account_bank_statement_import_txt.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py b/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py index 29f0577344..1385c1f02a 100644 --- a/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py +++ b/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py @@ -7,7 +7,8 @@ import xlrd from xlrd.sheet import ctype_text import logging -import datetime +import datetime as dtm +from datetime import datetime from odoo import _, api, fields, models from odoo.exceptions import UserError import re @@ -153,7 +154,7 @@ def _convert_xls_line_to_dict(self, row_idx, xl_sheet): ms_date_number = xl_sheet.cell(row_idx, col_idx).value year, month, day, hour, minute, second = xlrd.xldate_as_tuple( ms_date_number, 0) - value = datetime.date(year, month, day) + value = dtm.date(year, month, day) rline[txt_map.field_to_assign] = value return rline From 9a844c557e9389d5fb14c42d2defcf24460de61a Mon Sep 17 00:00:00 2001 From: Jordi Ballester Alomar Date: Tue, 17 Dec 2019 19:06:33 +0100 Subject: [PATCH 07/15] change module name --- account_bank_statement_import_txt/readme/DESCRIPTION.rst | 2 -- .../__init__.py | 0 .../__manifest__.py | 4 ++-- .../data/txt_map_data.xml | 0 .../models/__init__.py | 0 .../models/account_bank_statement_import_txt_map.py | 0 .../models/account_journal.py | 0 .../readme/CONFIGURE.rst | 0 .../readme/CONTRIBUTORS.rst | 0 account_bank_statement_import_txt_xlsx/readme/DESCRIPTION.rst | 2 ++ .../readme/USAGE.rst | 2 +- .../security/ir.model.access.csv | 0 .../tests/__init__.py | 0 .../tests/sample_statement_en.csv | 0 .../tests/test_txt_statement_import.py | 0 .../views/account_journal_views.xml | 0 .../views/txt_map_views.xml | 0 .../wizards/__init__.py | 0 .../wizards/account_bank_statement_import_txt.py | 0 .../wizards/account_bank_statement_import_view.xml | 0 .../wizards/create_map_lines_from_file.py | 0 .../wizards/create_map_lines_from_file_views.xml | 0 22 files changed, 5 insertions(+), 5 deletions(-) delete mode 100644 account_bank_statement_import_txt/readme/DESCRIPTION.rst rename {account_bank_statement_import_txt => account_bank_statement_import_txt_xlsx}/__init__.py (100%) rename {account_bank_statement_import_txt => account_bank_statement_import_txt_xlsx}/__manifest__.py (86%) rename {account_bank_statement_import_txt => account_bank_statement_import_txt_xlsx}/data/txt_map_data.xml (100%) rename {account_bank_statement_import_txt => account_bank_statement_import_txt_xlsx}/models/__init__.py (100%) rename {account_bank_statement_import_txt => account_bank_statement_import_txt_xlsx}/models/account_bank_statement_import_txt_map.py (100%) rename {account_bank_statement_import_txt => account_bank_statement_import_txt_xlsx}/models/account_journal.py (100%) rename {account_bank_statement_import_txt => account_bank_statement_import_txt_xlsx}/readme/CONFIGURE.rst (100%) rename {account_bank_statement_import_txt => account_bank_statement_import_txt_xlsx}/readme/CONTRIBUTORS.rst (100%) create mode 100644 account_bank_statement_import_txt_xlsx/readme/DESCRIPTION.rst rename {account_bank_statement_import_txt => account_bank_statement_import_txt_xlsx}/readme/USAGE.rst (81%) rename {account_bank_statement_import_txt => account_bank_statement_import_txt_xlsx}/security/ir.model.access.csv (100%) rename {account_bank_statement_import_txt => account_bank_statement_import_txt_xlsx}/tests/__init__.py (100%) rename {account_bank_statement_import_txt => account_bank_statement_import_txt_xlsx}/tests/sample_statement_en.csv (100%) rename {account_bank_statement_import_txt => account_bank_statement_import_txt_xlsx}/tests/test_txt_statement_import.py (100%) rename {account_bank_statement_import_txt => account_bank_statement_import_txt_xlsx}/views/account_journal_views.xml (100%) rename {account_bank_statement_import_txt => account_bank_statement_import_txt_xlsx}/views/txt_map_views.xml (100%) rename {account_bank_statement_import_txt => account_bank_statement_import_txt_xlsx}/wizards/__init__.py (100%) rename {account_bank_statement_import_txt => account_bank_statement_import_txt_xlsx}/wizards/account_bank_statement_import_txt.py (100%) rename {account_bank_statement_import_txt => account_bank_statement_import_txt_xlsx}/wizards/account_bank_statement_import_view.xml (100%) rename {account_bank_statement_import_txt => account_bank_statement_import_txt_xlsx}/wizards/create_map_lines_from_file.py (100%) rename {account_bank_statement_import_txt => account_bank_statement_import_txt_xlsx}/wizards/create_map_lines_from_file_views.xml (100%) diff --git a/account_bank_statement_import_txt/readme/DESCRIPTION.rst b/account_bank_statement_import_txt/readme/DESCRIPTION.rst deleted file mode 100644 index 3994412c5e..0000000000 --- a/account_bank_statement_import_txt/readme/DESCRIPTION.rst +++ /dev/null @@ -1,2 +0,0 @@ -This module allows you to import the any TXT file in Odoo as bank -statements. diff --git a/account_bank_statement_import_txt/__init__.py b/account_bank_statement_import_txt_xlsx/__init__.py similarity index 100% rename from account_bank_statement_import_txt/__init__.py rename to account_bank_statement_import_txt_xlsx/__init__.py diff --git a/account_bank_statement_import_txt/__manifest__.py b/account_bank_statement_import_txt_xlsx/__manifest__.py similarity index 86% rename from account_bank_statement_import_txt/__manifest__.py rename to account_bank_statement_import_txt_xlsx/__manifest__.py index f52c0524f5..667e44c8a4 100644 --- a/account_bank_statement_import_txt/__manifest__.py +++ b/account_bank_statement_import_txt_xlsx/__manifest__.py @@ -3,8 +3,8 @@ # @author Sébastien BEAU # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { - "name": "Import Text Bank Statements", - 'summary': 'Import TXT/CSV files as Bank Statements in Odoo', + "name": "Account Bank Statement Import TXT XLSX", + 'summary': 'Import TXT/CSV or XLSX files as Bank Statements in Odoo', "version": "12.0.1.0.1", "category": "Accounting", "website": "https://github.com/OCA/bank-statement-import", diff --git a/account_bank_statement_import_txt/data/txt_map_data.xml b/account_bank_statement_import_txt_xlsx/data/txt_map_data.xml similarity index 100% rename from account_bank_statement_import_txt/data/txt_map_data.xml rename to account_bank_statement_import_txt_xlsx/data/txt_map_data.xml diff --git a/account_bank_statement_import_txt/models/__init__.py b/account_bank_statement_import_txt_xlsx/models/__init__.py similarity index 100% rename from account_bank_statement_import_txt/models/__init__.py rename to account_bank_statement_import_txt_xlsx/models/__init__.py diff --git a/account_bank_statement_import_txt/models/account_bank_statement_import_txt_map.py b/account_bank_statement_import_txt_xlsx/models/account_bank_statement_import_txt_map.py similarity index 100% rename from account_bank_statement_import_txt/models/account_bank_statement_import_txt_map.py rename to account_bank_statement_import_txt_xlsx/models/account_bank_statement_import_txt_map.py diff --git a/account_bank_statement_import_txt/models/account_journal.py b/account_bank_statement_import_txt_xlsx/models/account_journal.py similarity index 100% rename from account_bank_statement_import_txt/models/account_journal.py rename to account_bank_statement_import_txt_xlsx/models/account_journal.py diff --git a/account_bank_statement_import_txt/readme/CONFIGURE.rst b/account_bank_statement_import_txt_xlsx/readme/CONFIGURE.rst similarity index 100% rename from account_bank_statement_import_txt/readme/CONFIGURE.rst rename to account_bank_statement_import_txt_xlsx/readme/CONFIGURE.rst diff --git a/account_bank_statement_import_txt/readme/CONTRIBUTORS.rst b/account_bank_statement_import_txt_xlsx/readme/CONTRIBUTORS.rst similarity index 100% rename from account_bank_statement_import_txt/readme/CONTRIBUTORS.rst rename to account_bank_statement_import_txt_xlsx/readme/CONTRIBUTORS.rst diff --git a/account_bank_statement_import_txt_xlsx/readme/DESCRIPTION.rst b/account_bank_statement_import_txt_xlsx/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..2564840495 --- /dev/null +++ b/account_bank_statement_import_txt_xlsx/readme/DESCRIPTION.rst @@ -0,0 +1,2 @@ +This module allows you to import the any TXT/CSV or XLSX file in Odoo as bank +statements. diff --git a/account_bank_statement_import_txt/readme/USAGE.rst b/account_bank_statement_import_txt_xlsx/readme/USAGE.rst similarity index 81% rename from account_bank_statement_import_txt/readme/USAGE.rst rename to account_bank_statement_import_txt_xlsx/readme/USAGE.rst index 539be0fa51..2a8fb28a67 100644 --- a/account_bank_statement_import_txt/readme/USAGE.rst +++ b/account_bank_statement_import_txt_xlsx/readme/USAGE.rst @@ -1,3 +1,3 @@ To use this module, you need to: -#. Go to your bank online and download your Bank Statement in TXT/CSV format. +#. Go to your bank online and download your Bank Statement in TXT/CSV or XLSX format. diff --git a/account_bank_statement_import_txt/security/ir.model.access.csv b/account_bank_statement_import_txt_xlsx/security/ir.model.access.csv similarity index 100% rename from account_bank_statement_import_txt/security/ir.model.access.csv rename to account_bank_statement_import_txt_xlsx/security/ir.model.access.csv diff --git a/account_bank_statement_import_txt/tests/__init__.py b/account_bank_statement_import_txt_xlsx/tests/__init__.py similarity index 100% rename from account_bank_statement_import_txt/tests/__init__.py rename to account_bank_statement_import_txt_xlsx/tests/__init__.py diff --git a/account_bank_statement_import_txt/tests/sample_statement_en.csv b/account_bank_statement_import_txt_xlsx/tests/sample_statement_en.csv similarity index 100% rename from account_bank_statement_import_txt/tests/sample_statement_en.csv rename to account_bank_statement_import_txt_xlsx/tests/sample_statement_en.csv diff --git a/account_bank_statement_import_txt/tests/test_txt_statement_import.py b/account_bank_statement_import_txt_xlsx/tests/test_txt_statement_import.py similarity index 100% rename from account_bank_statement_import_txt/tests/test_txt_statement_import.py rename to account_bank_statement_import_txt_xlsx/tests/test_txt_statement_import.py diff --git a/account_bank_statement_import_txt/views/account_journal_views.xml b/account_bank_statement_import_txt_xlsx/views/account_journal_views.xml similarity index 100% rename from account_bank_statement_import_txt/views/account_journal_views.xml rename to account_bank_statement_import_txt_xlsx/views/account_journal_views.xml diff --git a/account_bank_statement_import_txt/views/txt_map_views.xml b/account_bank_statement_import_txt_xlsx/views/txt_map_views.xml similarity index 100% rename from account_bank_statement_import_txt/views/txt_map_views.xml rename to account_bank_statement_import_txt_xlsx/views/txt_map_views.xml diff --git a/account_bank_statement_import_txt/wizards/__init__.py b/account_bank_statement_import_txt_xlsx/wizards/__init__.py similarity index 100% rename from account_bank_statement_import_txt/wizards/__init__.py rename to account_bank_statement_import_txt_xlsx/wizards/__init__.py diff --git a/account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py b/account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_txt.py similarity index 100% rename from account_bank_statement_import_txt/wizards/account_bank_statement_import_txt.py rename to account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_txt.py diff --git a/account_bank_statement_import_txt/wizards/account_bank_statement_import_view.xml b/account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_view.xml similarity index 100% rename from account_bank_statement_import_txt/wizards/account_bank_statement_import_view.xml rename to account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_view.xml diff --git a/account_bank_statement_import_txt/wizards/create_map_lines_from_file.py b/account_bank_statement_import_txt_xlsx/wizards/create_map_lines_from_file.py similarity index 100% rename from account_bank_statement_import_txt/wizards/create_map_lines_from_file.py rename to account_bank_statement_import_txt_xlsx/wizards/create_map_lines_from_file.py diff --git a/account_bank_statement_import_txt/wizards/create_map_lines_from_file_views.xml b/account_bank_statement_import_txt_xlsx/wizards/create_map_lines_from_file_views.xml similarity index 100% rename from account_bank_statement_import_txt/wizards/create_map_lines_from_file_views.xml rename to account_bank_statement_import_txt_xlsx/wizards/create_map_lines_from_file_views.xml From 1cdb1ab44cc4479d4956955b930c5def969a3e6b Mon Sep 17 00:00:00 2001 From: Jordi Ballester Alomar Date: Tue, 17 Dec 2019 19:23:21 +0100 Subject: [PATCH 08/15] fixup! --- .../wizards/account_bank_statement_import_txt.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_txt.py b/account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_txt.py index 1385c1f02a..8cc0b1c3d3 100644 --- a/account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_txt.py +++ b/account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_txt.py @@ -150,10 +150,16 @@ def _convert_xls_line_to_dict(self, row_idx, xl_sheet): value = cell_obj.value if not txt_map.field_to_assign: continue - if ctype == 3: + if ctype == xlrd.XL_CELL_DATE: ms_date_number = xl_sheet.cell(row_idx, col_idx).value - year, month, day, hour, minute, second = xlrd.xldate_as_tuple( - ms_date_number, 0) + try: + year, month, day, hour, minute, \ + second = xlrd.xldate_as_tuple( + ms_date_number, 0) + except xlrd.XLDateError as e: + raise UserError( + _('An error was found translating a date ' + 'field from the file: %s') % e) value = dtm.date(year, month, day) rline[txt_map.field_to_assign] = value return rline From 118ef5a8ce974845f8cc34f44ec00cf921a1a5e0 Mon Sep 17 00:00:00 2001 From: Jordi Ballester Alomar Date: Wed, 18 Dec 2019 06:35:27 +0100 Subject: [PATCH 09/15] add tests for xlsx --- .../readme/CONFIGURE.rst | 6 ++-- .../tests/sample statement_en.xlsx | Bin 0 -> 4991 bytes .../tests/test_txt_statement_import.py | 28 +++++++++++++++++- .../views/txt_map_views.xml | 4 +-- .../account_bank_statement_import_view.xml | 2 +- .../create_map_lines_from_file_views.xml | 6 ++-- 6 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 account_bank_statement_import_txt_xlsx/tests/sample statement_en.xlsx diff --git a/account_bank_statement_import_txt_xlsx/readme/CONFIGURE.rst b/account_bank_statement_import_txt_xlsx/readme/CONFIGURE.rst index 97c4cc4f59..5c81f99c39 100644 --- a/account_bank_statement_import_txt_xlsx/readme/CONFIGURE.rst +++ b/account_bank_statement_import_txt_xlsx/readme/CONFIGURE.rst @@ -1,12 +1,12 @@ * Create or go to a bank journal where you want to import the txt statement. -* Edit that journal and set a Txt map in **Statement Import Txt Map** section in **Advanced +* Edit that journal and set a Txt map in **Statement Import Map** section in **Advanced Settings** tab. * Now you can import Text based statements in that journal. Note: if existent Txt Map does not fit to your file to import, you can create another map in **Invoicing > Configuration > Accounting > -Statement Import Txt Mapping**. +Statement Import Map**. -You can import headers from any Txt file in **Action > Create Txt Map +You can import headers from any Txt file in **Action > Create Map Lines** and set every line with which field of statement have to match. diff --git a/account_bank_statement_import_txt_xlsx/tests/sample statement_en.xlsx b/account_bank_statement_import_txt_xlsx/tests/sample statement_en.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..6be79fe3901f206aa5fea3b54a781c2c33e6d506 GIT binary patch literal 4991 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 literal 0 HcmV?d00001 diff --git a/account_bank_statement_import_txt_xlsx/tests/test_txt_statement_import.py b/account_bank_statement_import_txt_xlsx/tests/test_txt_statement_import.py index 17b78912d2..22d09b9b71 100644 --- a/account_bank_statement_import_txt_xlsx/tests/test_txt_statement_import.py +++ b/account_bank_statement_import_txt_xlsx/tests/test_txt_statement_import.py @@ -45,7 +45,7 @@ def test_import_txt_file(self): old_statements = self.env['account.bank.statement'].search([]) # This journal is for Txt statements txt_map = self.env.ref( - 'account_bank_statement_import_txt.txt_map' + 'account_bank_statement_import_txt_xlsx.txt_map' ) self.journal.statement_import_txt_map_id = txt_map.id file = self._do_import('sample_statement_en.csv') @@ -65,3 +65,29 @@ def test_import_txt_file(self): self.assertAlmostEqual( sum(statement.mapped('line_ids.amount_currency')), 1000.00 ) + + def test_import_xlsx_file(self): + # Current statements before to run the wizard + old_statements = self.env['account.bank.statement'].search([]) + # This journal is for Txt statements + txt_map = self.env.ref( + 'account_bank_statement_import_txt_xlsx.txt_map' + ) + self.journal.statement_import_txt_map_id = txt_map.id + file = self._do_import('sample_statement_en.xlsx') + file = base64.b64encode(file.encode("utf-8")) + wizard = self.env['account.bank.statement.import'].with_context({ + 'journal_id': self.journal.id, + }).create({'data_file': file}) + wizard.import_file() + staments_now = self.env['account.bank.statement'].search([]) + statement = staments_now - old_statements + self.assertEqual(len(statement.line_ids), 2) + self.assertEqual(len(statement.mapped('line_ids').filtered( + lambda x: x.partner_id)), 1) + self.assertAlmostEqual( + sum(statement.mapped('line_ids.amount')), 1491.50 + ) + self.assertAlmostEqual( + sum(statement.mapped('line_ids.amount_currency')), 1000.00 + ) diff --git a/account_bank_statement_import_txt_xlsx/views/txt_map_views.xml b/account_bank_statement_import_txt_xlsx/views/txt_map_views.xml index 5a7047e6df..c0de3e6730 100644 --- a/account_bank_statement_import_txt_xlsx/views/txt_map_views.xml +++ b/account_bank_statement_import_txt_xlsx/views/txt_map_views.xml @@ -56,7 +56,7 @@ - TXT Statement Import Mapping + Statement Import Mapping account.bank.statement.import.txt.map form tree,form @@ -65,6 +65,6 @@ + name="Statement Import Map"/> diff --git a/account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_view.xml b/account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_view.xml index 318216222d..14e682d090 100644 --- a/account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_view.xml +++ b/account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_view.xml @@ -6,7 +6,7 @@ -
  • Txt file with Template:
  • +
  • Txt/XLSX file with Template:
  • diff --git a/account_bank_statement_import_txt_xlsx/wizards/create_map_lines_from_file_views.xml b/account_bank_statement_import_txt_xlsx/wizards/create_map_lines_from_file_views.xml index 5dd023be93..35f31c71d7 100644 --- a/account_bank_statement_import_txt_xlsx/wizards/create_map_lines_from_file_views.xml +++ b/account_bank_statement_import_txt_xlsx/wizards/create_map_lines_from_file_views.xml @@ -2,11 +2,11 @@ - Create Txt Map Lines + Create Statement Map Lines wizard.txt.map.create
    -

    Select a TXT/CSV bank statement file to create all the map lines from headers file.

    +

    Select a TXT/CSV or XLSX bank statement file to create all the map lines from headers file.

    Download a bank statement from your bank and import it here.

    All the txt map lines will be created automatically.

    @@ -18,7 +18,7 @@
    - Date: Wed, 18 Dec 2019 07:05:47 +0100 Subject: [PATCH 10/15] fixup! --- .../__manifest__.py | 3 +++ ...e statement_en.xlsx => sample_statement_en.xlsx} | Bin .../wizards/account_bank_statement_import_txt.py | 3 +-- 3 files changed, 4 insertions(+), 2 deletions(-) rename account_bank_statement_import_txt_xlsx/tests/{sample statement_en.xlsx => sample_statement_en.xlsx} (100%) diff --git a/account_bank_statement_import_txt_xlsx/__manifest__.py b/account_bank_statement_import_txt_xlsx/__manifest__.py index 667e44c8a4..08b8fba33d 100644 --- a/account_bank_statement_import_txt_xlsx/__manifest__.py +++ b/account_bank_statement_import_txt_xlsx/__manifest__.py @@ -14,6 +14,9 @@ "depends": [ "account_bank_statement_import", ], + "external_dependencies": { + "python": ["xlrd"], + }, "data": [ "security/ir.model.access.csv", "data/txt_map_data.xml", diff --git a/account_bank_statement_import_txt_xlsx/tests/sample statement_en.xlsx b/account_bank_statement_import_txt_xlsx/tests/sample_statement_en.xlsx similarity index 100% rename from account_bank_statement_import_txt_xlsx/tests/sample statement_en.xlsx rename to account_bank_statement_import_txt_xlsx/tests/sample_statement_en.xlsx diff --git a/account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_txt.py b/account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_txt.py index 8cc0b1c3d3..d95134f45b 100644 --- a/account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_txt.py +++ b/account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_txt.py @@ -5,7 +5,6 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). import xlrd -from xlrd.sheet import ctype_text import logging import datetime as dtm from datetime import datetime @@ -65,7 +64,7 @@ def _check_xls(self, data_file): xl_sheet = book.sheet_by_index(0) row = xl_sheet.row(0) # 1st row for idx, cell_obj in enumerate(row): - cell_type_str = ctype_text.get(cell_obj.ctype, False) + cell_type_str = xlrd.sheet.ctype_text.get(cell_obj.ctype, False) if cell_type_str: file_headers.append(cell_obj.value) else: From da25c8b071fe3b906988f0d04a9c0dc23d691e72 Mon Sep 17 00:00:00 2001 From: Jordi Ballester Alomar Date: Wed, 18 Dec 2019 07:33:39 +0100 Subject: [PATCH 11/15] fixup! --- .../tests/test_txt_statement_import.py | 1 - 1 file changed, 1 deletion(-) diff --git a/account_bank_statement_import_txt_xlsx/tests/test_txt_statement_import.py b/account_bank_statement_import_txt_xlsx/tests/test_txt_statement_import.py index 22d09b9b71..d9c526bbc3 100644 --- a/account_bank_statement_import_txt_xlsx/tests/test_txt_statement_import.py +++ b/account_bank_statement_import_txt_xlsx/tests/test_txt_statement_import.py @@ -49,7 +49,6 @@ def test_import_txt_file(self): ) self.journal.statement_import_txt_map_id = txt_map.id file = self._do_import('sample_statement_en.csv') - file = base64.b64encode(file.encode("utf-8")) wizard = self.env['account.bank.statement.import'].with_context({ 'journal_id': self.journal.id, }).create({'data_file': file}) From f83102308c53607a93ba2df975b9a0c581c660fb Mon Sep 17 00:00:00 2001 From: Joan Sisquella Date: Wed, 18 Dec 2019 09:21:37 +0100 Subject: [PATCH 12/15] fixup! --- .../models/account_bank_statement_import_txt_map.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/account_bank_statement_import_txt_xlsx/models/account_bank_statement_import_txt_map.py b/account_bank_statement_import_txt_xlsx/models/account_bank_statement_import_txt_map.py index 911b1098f6..de76a31c26 100644 --- a/account_bank_statement_import_txt_xlsx/models/account_bank_statement_import_txt_map.py +++ b/account_bank_statement_import_txt_xlsx/models/account_bank_statement_import_txt_map.py @@ -69,7 +69,8 @@ class AccountBankStatementImportTxtMap(models.Model): ], default=',', ) - quotechar = fields.Char(string='String delimiter', size=1) + quotechar = fields.Char(string='String delimiter', size=1, + default='"') @api.onchange('float_thousands_sep') def onchange_thousands_separator(self): From 8a11f4dc39af0d31eb5c643e660685c6dd128be2 Mon Sep 17 00:00:00 2001 From: Joan Sisquella Date: Wed, 18 Dec 2019 12:31:41 +0100 Subject: [PATCH 13/15] fixup! --- .../__manifest__.py | 2 +- .../data/txt_map_data.xml | 16 +++--- .../account_bank_statement_import_txt_map.py | 8 +-- .../models/account_journal.py | 2 +- .../security/ir.model.access.csv | 4 +- .../tests/sample_statement_en.xlsx | Bin 4991 -> 4982 bytes .../tests/test_txt_statement_import.py | 54 +++++++++--------- .../views/txt_map_views.xml | 10 ++-- .../account_bank_statement_import_txt.py | 2 +- .../wizards/create_map_lines_from_file.py | 2 +- .../create_map_lines_from_file_views.xml | 2 +- 11 files changed, 52 insertions(+), 50 deletions(-) diff --git a/account_bank_statement_import_txt_xlsx/__manifest__.py b/account_bank_statement_import_txt_xlsx/__manifest__.py index 08b8fba33d..02b458f521 100644 --- a/account_bank_statement_import_txt_xlsx/__manifest__.py +++ b/account_bank_statement_import_txt_xlsx/__manifest__.py @@ -15,7 +15,7 @@ "account_bank_statement_import", ], "external_dependencies": { - "python": ["xlrd"], + "python": ["xlrd",], }, "data": [ "security/ir.model.access.csv", diff --git a/account_bank_statement_import_txt_xlsx/data/txt_map_data.xml b/account_bank_statement_import_txt_xlsx/data/txt_map_data.xml index c18c4f0a36..fb4c899afa 100644 --- a/account_bank_statement_import_txt_xlsx/data/txt_map_data.xml +++ b/account_bank_statement_import_txt_xlsx/data/txt_map_data.xml @@ -1,50 +1,50 @@ - + Sample Statement comma dot - + Date 0 date %m/%d/%Y - + Label 1 name - + Currency 2 currency - + Amount 3 amount - + Amount Currency 4 amount_currency - + Partner Name 5 partner_name - + Bank Account 6 diff --git a/account_bank_statement_import_txt_xlsx/models/account_bank_statement_import_txt_map.py b/account_bank_statement_import_txt_xlsx/models/account_bank_statement_import_txt_map.py index de76a31c26..9a6bc07f65 100644 --- a/account_bank_statement_import_txt_xlsx/models/account_bank_statement_import_txt_map.py +++ b/account_bank_statement_import_txt_xlsx/models/account_bank_statement_import_txt_map.py @@ -6,14 +6,14 @@ class AccountBankStatementImportTxtMap(models.Model): - _name = 'account.bank.statement.import.txt.map' + _name = 'account.bank.statement.import.map' _description = 'Account Bank Statement Import Txt Map' name = fields.Char( required=True, ) map_line_ids = fields.One2many( - comodel_name='account.bank.statement.import.txt.map.line', + comodel_name='account.bank.statement.import.map.line', inverse_name='map_parent_id', string="Map lines", required=True, @@ -96,7 +96,7 @@ def _get_separators(self): class AccountBankStatementImportTxtMapLine(models.Model): - _name = 'account.bank.statement.import.txt.map.line' + _name = 'account.bank.statement.import.map.line' _description = 'Account Bank Statement Import Txt Map Line' _order = "sequence asc, id asc" @@ -109,7 +109,7 @@ class AccountBankStatementImportTxtMapLine(models.Model): required=True, ) map_parent_id = fields.Many2one( - comodel_name='account.bank.statement.import.txt.map', + comodel_name='account.bank.statement.import.map', required=True, ondelete='cascade', ) diff --git a/account_bank_statement_import_txt_xlsx/models/account_journal.py b/account_bank_statement_import_txt_xlsx/models/account_journal.py index 105ecce1be..261df272ad 100644 --- a/account_bank_statement_import_txt_xlsx/models/account_journal.py +++ b/account_bank_statement_import_txt_xlsx/models/account_journal.py @@ -9,7 +9,7 @@ class AccountJournal(models.Model): _inherit = "account.journal" statement_import_txt_map_id = fields.Many2one( - comodel_name='account.bank.statement.import.txt.map', + comodel_name='account.bank.statement.import.map', string='Statement Import Txt Map', ) diff --git a/account_bank_statement_import_txt_xlsx/security/ir.model.access.csv b/account_bank_statement_import_txt_xlsx/security/ir.model.access.csv index 9cfe3a2a7e..b282f31ba8 100644 --- a/account_bank_statement_import_txt_xlsx/security/ir.model.access.csv +++ b/account_bank_statement_import_txt_xlsx/security/ir.model.access.csv @@ -1,3 +1,3 @@ "id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" -access_account_bank_statement_import_txt_map,txt map manager,model_account_bank_statement_import_txt_map,account.group_account_manager,1,1,1,1 -access_account_bank_statement_import_txt_map_line,txt map line manager,model_account_bank_statement_import_txt_map_line,account.group_account_manager,1,1,1,1 +access_account_bank_statement_import_map,map manager,model_account_bank_statement_import_map,account.group_account_manager,1,1,1,1 +access_account_bank_statement_import_map_line,map line manager,model_account_bank_statement_import_map_line,account.group_account_manager,1,1,1,1 diff --git a/account_bank_statement_import_txt_xlsx/tests/sample_statement_en.xlsx b/account_bank_statement_import_txt_xlsx/tests/sample_statement_en.xlsx index 6be79fe3901f206aa5fea3b54a781c2c33e6d506..123dae639f1d52893503185766a3f54836622be3 100644 GIT binary patch delta 4271 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 delta 4278 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 diff --git a/account_bank_statement_import_txt_xlsx/tests/test_txt_statement_import.py b/account_bank_statement_import_txt_xlsx/tests/test_txt_statement_import.py index d9c526bbc3..14b2e8f89e 100644 --- a/account_bank_statement_import_txt_xlsx/tests/test_txt_statement_import.py +++ b/account_bank_statement_import_txt_xlsx/tests/test_txt_statement_import.py @@ -5,6 +5,7 @@ import os import base64 from odoo.tests import common +import codecs class TestTxtFile(common.TransactionCase): @@ -12,7 +13,7 @@ class TestTxtFile(common.TransactionCase): def setUp(self): super(TestTxtFile, self).setUp() - self.map = self.env['account.bank.statement.import.txt.map'].create({ + self.map = self.env['account.bank.statement.import.map'].create({ 'name': 'Txt Map Test', }) usd = self.env.ref('base.USD') @@ -49,31 +50,6 @@ def test_import_txt_file(self): ) self.journal.statement_import_txt_map_id = txt_map.id file = self._do_import('sample_statement_en.csv') - wizard = self.env['account.bank.statement.import'].with_context({ - 'journal_id': self.journal.id, - }).create({'data_file': file}) - wizard.import_file() - staments_now = self.env['account.bank.statement'].search([]) - statement = staments_now - old_statements - self.assertEqual(len(statement.line_ids), 2) - self.assertEqual(len(statement.mapped('line_ids').filtered( - lambda x: x.partner_id)), 1) - self.assertAlmostEqual( - sum(statement.mapped('line_ids.amount')), 1491.50 - ) - self.assertAlmostEqual( - sum(statement.mapped('line_ids.amount_currency')), 1000.00 - ) - - def test_import_xlsx_file(self): - # Current statements before to run the wizard - old_statements = self.env['account.bank.statement'].search([]) - # This journal is for Txt statements - txt_map = self.env.ref( - 'account_bank_statement_import_txt_xlsx.txt_map' - ) - self.journal.statement_import_txt_map_id = txt_map.id - file = self._do_import('sample_statement_en.xlsx') file = base64.b64encode(file.encode("utf-8")) wizard = self.env['account.bank.statement.import'].with_context({ 'journal_id': self.journal.id, @@ -90,3 +66,29 @@ def test_import_xlsx_file(self): self.assertAlmostEqual( sum(statement.mapped('line_ids.amount_currency')), 1000.00 ) + + # def test_import_xlsx_file(self): + # # Current statements before to run the wizard + # old_statements = self.env['account.bank.statement'].search([]) + # # This journal is for Txt statements + # txt_map = self.env.ref( + # 'account_bank_statement_import_txt_xlsx.txt_map' + # ) + # self.journal.statement_import_txt_map_id = txt_map.id + # file = self._do_import_xlsx('sample_statement_en.xlsx') + # file = base64.b64encode(file.encode("utf-8")) + # wizard = self.env['account.bank.statement.import'].with_context({ + # 'journal_id': self.journal.id, + # }).create({'data_file': file}) + # wizard.import_file() + # staments_now = self.env['account.bank.statement'].search([]) + # statement = staments_now - old_statements + # self.assertEqual(len(statement.line_ids), 2) + # self.assertEqual(len(statement.mapped('line_ids').filtered( + # lambda x: x.partner_id)), 1) + # self.assertAlmostEqual( + # sum(statement.mapped('line_ids.amount')), 1491.50 + # ) + # self.assertAlmostEqual( + # sum(statement.mapped('line_ids.amount_currency')), 1000.00 + # ) diff --git a/account_bank_statement_import_txt_xlsx/views/txt_map_views.xml b/account_bank_statement_import_txt_xlsx/views/txt_map_views.xml index c0de3e6730..c7ab75506d 100644 --- a/account_bank_statement_import_txt_xlsx/views/txt_map_views.xml +++ b/account_bank_statement_import_txt_xlsx/views/txt_map_views.xml @@ -2,7 +2,7 @@ - account.bank.statement.import.txt.map + account.bank.statement.import.map @@ -11,7 +11,7 @@ - account.bank.statement.import.txt.map + account.bank.statement.import.map
    @@ -29,7 +29,7 @@ - account.bank.statement.import.txt.map.line + account.bank.statement.import.map.line @@ -41,7 +41,7 @@ - account.bank.statement.import.txt.map.line + account.bank.statement.import.map.line @@ -57,7 +57,7 @@ Statement Import Mapping - account.bank.statement.import.txt.map + account.bank.statement.import.map form tree,form diff --git a/account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_txt.py b/account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_txt.py index d95134f45b..8b33ef5e33 100644 --- a/account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_txt.py +++ b/account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_txt.py @@ -24,7 +24,7 @@ class AccountBankStatementImport(models.TransientModel): _inherit = 'account.bank.statement.import' txt_map_id = fields.Many2one( - comodel_name='account.bank.statement.import.txt.map', + comodel_name='account.bank.statement.import.map', string='Txt map', readonly=True, ) diff --git a/account_bank_statement_import_txt_xlsx/wizards/create_map_lines_from_file.py b/account_bank_statement_import_txt_xlsx/wizards/create_map_lines_from_file.py index 46aa027693..65d279ed81 100644 --- a/account_bank_statement_import_txt_xlsx/wizards/create_map_lines_from_file.py +++ b/account_bank_statement_import_txt_xlsx/wizards/create_map_lines_from_file.py @@ -20,7 +20,7 @@ class WizardTxtMapCreate(models.TransientModel): @api.multi def create_map_lines(self): - statement_obj = self.env['account.bank.statement.import.txt.map'] + statement_obj = self.env['account.bank.statement.import.map'] data_file = base64.b64decode(self.data_file) if not isinstance(data_file, str): data_file = data_file.decode('utf-8-sig').strip() diff --git a/account_bank_statement_import_txt_xlsx/wizards/create_map_lines_from_file_views.xml b/account_bank_statement_import_txt_xlsx/wizards/create_map_lines_from_file_views.xml index 35f31c71d7..d94d868c0f 100644 --- a/account_bank_statement_import_txt_xlsx/wizards/create_map_lines_from_file_views.xml +++ b/account_bank_statement_import_txt_xlsx/wizards/create_map_lines_from_file_views.xml @@ -20,7 +20,7 @@ Date: Wed, 18 Dec 2019 12:39:26 +0100 Subject: [PATCH 14/15] fixup! --- account_bank_statement_import_txt_xlsx/__manifest__.py | 2 +- .../tests/test_txt_statement_import.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/account_bank_statement_import_txt_xlsx/__manifest__.py b/account_bank_statement_import_txt_xlsx/__manifest__.py index 02b458f521..08b8fba33d 100644 --- a/account_bank_statement_import_txt_xlsx/__manifest__.py +++ b/account_bank_statement_import_txt_xlsx/__manifest__.py @@ -15,7 +15,7 @@ "account_bank_statement_import", ], "external_dependencies": { - "python": ["xlrd",], + "python": ["xlrd"], }, "data": [ "security/ir.model.access.csv", diff --git a/account_bank_statement_import_txt_xlsx/tests/test_txt_statement_import.py b/account_bank_statement_import_txt_xlsx/tests/test_txt_statement_import.py index 14b2e8f89e..a93ce45662 100644 --- a/account_bank_statement_import_txt_xlsx/tests/test_txt_statement_import.py +++ b/account_bank_statement_import_txt_xlsx/tests/test_txt_statement_import.py @@ -5,7 +5,6 @@ import os import base64 from odoo.tests import common -import codecs class TestTxtFile(common.TransactionCase): From 76e8434dd8293452df1080137b051439734e01ed Mon Sep 17 00:00:00 2001 From: Joan Sisquella Date: Wed, 18 Dec 2019 14:11:10 +0100 Subject: [PATCH 15/15] code and test fixup! --- .../tests/sample_statement_en.xlsx | Bin 4982 -> 5092 bytes .../tests/test_txt_statement_import.py | 59 ++++++++++-------- .../account_bank_statement_import_txt.py | 7 ++- 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/account_bank_statement_import_txt_xlsx/tests/sample_statement_en.xlsx b/account_bank_statement_import_txt_xlsx/tests/sample_statement_en.xlsx index 123dae639f1d52893503185766a3f54836622be3..b3365b205d4ff97fe88181c5654983dcfec100d2 100644 GIT binary patch delta 3988 zcmZ8kcRbbm|38ksa_n`E?2&Oqwj$Z{n8(N_^CV@D4n<^#D`Xy7hwR-s#VMj3$Id!d z5)P34}pe!)zlNWU-Ya$gl#J%{)NF=t9LHhSwE@XbX%@2>wb9&>QZ zUg{bG8lveB&bfPq%aClUV{)-AoAmVASRNbrN?TVbP5B)82c2LGS?VW-PmHGH7rz(= zj>S%>-{F(RVpN(`p9>+_BZ0)b)FA)*zBfxqD?0=%sZWQ&AVg3{`#ZDiUZgp@KYCfu zW5`L#KrPs{1k#V5B%@!zaSv-p~-`7T_zvw@ALCYz$&A}>$ew? zY~#~z0<>P1N?bqd9@^n7af+4)q)*GIc_jUK+az(Xu#Ic(>-P&znYTN_GFAHC$5I%Z z5^q-T;=X%iegYx~$e@=W{*{spl;~jRHOm2(jjLP1pg&F<;rzIp&z7_>qSOSr%tgr} zE6Q8%MVWI2DL;QG$Q~{1eYE7H%w0;C3{{VBlGhe_)XIX`p{uDcw}Ypj@BxoK12`i0 z-ZU$VbeC8MQVdmm^}G|v>JvwHVzOh}RtL%ZP6Te$if1B^gG9rG^dpS89#yeeL!uU6 zs#F$hGJ;-VcbGUZv@}fvr8tLzYSD5n5_^TRxiUhdy_StKbK+j(YKuX}GK00%I!jDi za�uyP0E!XL&~E(|oryi3voPDXOtp;CI-XDzt#JhQb^qv2!|kS{RPuowz%X@^a#~ z+pxyMCy@mj>ls5Nl0cqJ3r1x07+r@825GlX*~njP-`*-qJGo5-^uuF0r0$ zwAPxy$9*rYE<>x?cBfFt_;Jo$Q5|{Yy*p~bwm-~Fo0hg)X$t*RPe-$;$e2jZ8C!$t zSmXXU_C8{q$aRBPz;?8mSvGzH1Ztx*uV6LFRLv%R9Ukk%zcAMz{O zEp|jNOs6 z7`k!T^b+htov6#~DrVTp(f8c|zl{NA&E_Md*V@2^u&%o=udL1D#NuxX@phfC=SnTe z_TV0TERppaHhK+XJVx4DO2oSrxmQfa5#~!#C$dV#+ppj^qr)hUp@nJ<`%DY*$>>`KAj;3*v8_`V?LYXZI(9WXlC=~hn^n^XK9jsHdYhiAU|pY&)_002FV z|HCtNR6@vs+q1GD?13c3JVM&Zmp6wTo|XY1f+`2{GIcrplGysc<)D7gGkcax%-mp7 zRH0wMab3kxS8I~S$Eak%LG9<tv=TZU+W$m#*+Q;p%jj>HXaJ(v6|XZ^DZn$afB70`opXPAyt8?VTeQ zeMkoUl6`6-s{c3pblby-mAtLOFJ7f|(MjAd)^=C#-~H%i?xI6qkap|Sd?>XW+;#BQ zlDZq;?q(^(YEYEys$_iQT9PuGX(2dvqm@Hp<@I|1R;|X>&r};ukEE?tx9QQFK@Zqe z=_KV0Qt(=^?m5mUH#S|Xhy|-q5W{D&qY`AI*3?}&*!@w;>$S97JV?i(iTN09Q{jZ` zptgoPed!#;aO=$Rpx;I&79Lcpr^*tSw_UUc?_-K}$2=5MsYX=6jJTZ;xu3E;W>o8l z{L#fs6FDb01ypIk3fcRuc$>(t!fhehQSUc?LF8Y<-)?aJ0Y-9|Jp0zc znF8JZUj_O?!;iEj-hL*_g7J5wL*r+(#kl$m;%w@70RgHG{`QIjVsO>A5uqd}Ld zL+~rmmM2FAi^RZ905hxpR7FHm8yF0!y%6eM9 zWB%=`kCEjwvBOtazK%H^bjixF8mc|590r=h1j`#-?hyed(dK_ewB_Cxkv4%GJXR7o=U5B4MZgpXU6@q2((Htqx!rPz5353wFZI+3o*(Q@H{L&gST24;(VN=U?*trf!b?S{m?lu+$Ta?~_Qn?%Sjy6F{7 z>V06?DO-(;9+1~?b=000u;eAmn>hSTKRPCN@RzGno-B88bmT)C`|5J)bc6ff@k%%Hi7dDFk_z;abOX@#k|}8? zT#;qP7Y<0gSU)&kXvoG;n92P;di<^b5B|*CWKF!XQ#Z|Vwoa1ABgKhBEy@+?VMy|R$JV6kG<}Oli z4*cyk3^GoLKE!JD;#e`%oG-LN1y1j;m9$_3`Dd)xi`kKhBRnFF+JYgg@;x86FU%;` zb_V1m7k(R4kE)$5b+m?)-#A>NXS3)7JE)uXZA1*LE2NDX-C5@S^Zds!-?h!N=SQCr z;(0s%f5^zej+6&c*UzarWv#LDBJq$NehF z04Brly3Z3S1a>tWDi%@3BdX3n}kegyxwy2}PlD$-N)lWER z&?Bj>ub;~u-v+aU*v2=kRG2F$aG+U?-oNsuRi=9*QP(q!e87`bSPIqC3u=;@@|Fli zZ!pk3Dt*8cHNj=n44n#aanX zh<9Ko&laiFb*qTs5m)yE9ek!*4c`5k4TW*Uugr@*F{@DNOn+ks*4?K4wKvbbA6O>$ zt|&H@e%Lq=>9ffgxvPg;PD;A##aR@)^RdQMu3}C?5{)0_i+)oYrfi=s*;!h4lzmLl zZ!VbYdLp{itN-vi+^(nS&`+uF03_W-b*MeJB(a=d6Y+6Ltv5!B=E|egJKU zqW7({3f=H$6`pXC~@gh|^}-v+&yeIr)6~obkuG zxXb`JPbU9+gY&=xom&O~7&2xJvG85|v-|nvF#l^(P!>Ha|DR424xwsicqEh GJ>@^_^9bYs delta 3848 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 diff --git a/account_bank_statement_import_txt_xlsx/tests/test_txt_statement_import.py b/account_bank_statement_import_txt_xlsx/tests/test_txt_statement_import.py index a93ce45662..88b559790c 100644 --- a/account_bank_statement_import_txt_xlsx/tests/test_txt_statement_import.py +++ b/account_bank_statement_import_txt_xlsx/tests/test_txt_statement_import.py @@ -3,6 +3,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). import os +from io import StringIO import base64 from odoo.tests import common @@ -26,7 +27,13 @@ def setUp(self): ), }) - def _do_import(self, file_name): + def _do_import_xlsx(self, file_name ): + file_name = os.path.join(os.path.dirname(__file__), file_name) + with open(file_name, 'rb') as fin: + data = fin.read() + return data + + def _do_import(self, file_name ): file_name = os.path.join(os.path.dirname(__file__), file_name) return open(file_name).read() @@ -66,28 +73,28 @@ def test_import_txt_file(self): sum(statement.mapped('line_ids.amount_currency')), 1000.00 ) - # def test_import_xlsx_file(self): - # # Current statements before to run the wizard - # old_statements = self.env['account.bank.statement'].search([]) - # # This journal is for Txt statements - # txt_map = self.env.ref( - # 'account_bank_statement_import_txt_xlsx.txt_map' - # ) - # self.journal.statement_import_txt_map_id = txt_map.id - # file = self._do_import_xlsx('sample_statement_en.xlsx') - # file = base64.b64encode(file.encode("utf-8")) - # wizard = self.env['account.bank.statement.import'].with_context({ - # 'journal_id': self.journal.id, - # }).create({'data_file': file}) - # wizard.import_file() - # staments_now = self.env['account.bank.statement'].search([]) - # statement = staments_now - old_statements - # self.assertEqual(len(statement.line_ids), 2) - # self.assertEqual(len(statement.mapped('line_ids').filtered( - # lambda x: x.partner_id)), 1) - # self.assertAlmostEqual( - # sum(statement.mapped('line_ids.amount')), 1491.50 - # ) - # self.assertAlmostEqual( - # sum(statement.mapped('line_ids.amount_currency')), 1000.00 - # ) + def test_import_xlsx_file(self): + # Current statements before to run the wizard + old_statements = self.env['account.bank.statement'].search([]) + # This journal is for Txt statements + txt_map = self.env.ref( + 'account_bank_statement_import_txt_xlsx.txt_map' + ) + self.journal.statement_import_txt_map_id = txt_map.id + file = self._do_import_xlsx('sample_statement_en.xlsx') + file = base64.b64encode(file) + wizard = self.env['account.bank.statement.import'].with_context({ + 'journal_id': self.journal.id, + }).create({'data_file': file}) + wizard.import_file() + staments_now = self.env['account.bank.statement'].search([]) + statement = staments_now - old_statements + self.assertEqual(len(statement.line_ids), 2) + self.assertEqual(len(statement.mapped('line_ids').filtered( + lambda x: x.partner_id)), 1) + self.assertAlmostEqual( + sum(statement.mapped('line_ids.amount')), 1491.50 + ) + self.assertAlmostEqual( + sum(statement.mapped('line_ids.amount_currency')), 1000.00 + ) diff --git a/account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_txt.py b/account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_txt.py index 8b33ef5e33..5ba300c296 100644 --- a/account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_txt.py +++ b/account_bank_statement_import_txt_xlsx/wizards/account_bank_statement_import_txt.py @@ -6,6 +6,7 @@ import xlrd import logging +import time import datetime as dtm from datetime import datetime from odoo import _, api, fields, models @@ -73,7 +74,7 @@ def _check_xls(self, data_file): raise UserError( _("Headers of file to import and Txt map lines does not " "match.")) - except xlrd.XLRDError: + except xlrd.XLRDError as e: return False except Exception as e: return False @@ -160,7 +161,9 @@ def _convert_xls_line_to_dict(self, row_idx, xl_sheet): _('An error was found translating a date ' 'field from the file: %s') % e) value = dtm.date(year, month, day) + value = value.strftime('%Y-%m-%d') rline[txt_map.field_to_assign] = value + return rline def _parse_xls_file(self, data_file): @@ -251,7 +254,7 @@ def _parse_file(self, data_file): data_file) if is_txt: raw_lines = self._parse_txt_file(data_file) - elif is_xls: + else: raw_lines = self._parse_xls_file(data_file) final_lines = self._post_process_statement_line(raw_lines) vals_bank_statement = self._prepare_txt_statement(final_lines)