From fc8b6db62d09cc9f2d49e7ca9e93fa1a0c0ca198 Mon Sep 17 00:00:00 2001 From: Ronald Portier Date: Wed, 17 Feb 2021 16:26:15 +0100 Subject: [PATCH] [IMP] : black, isort, prettier --- .../__manifest__.py | 4 +- .../models/account_bank_statement.py | 24 ++-- .../__manifest__.py | 10 +- .../models/account_bank_statement_import.py | 97 +++++++------- .../models/account_journal.py | 14 +- .../tests/test_import_adyen.py | 121 ++++++++++-------- .../views/account_journal.xml | 6 +- .../account_bank_statement_clearing_account | 1 + .../setup.py | 6 + .../account_bank_statement_import_adyen | 1 + .../setup.py | 6 + 11 files changed, 161 insertions(+), 129 deletions(-) create mode 120000 setup/account_bank_statement_clearing_account/odoo/addons/account_bank_statement_clearing_account create mode 100644 setup/account_bank_statement_clearing_account/setup.py create mode 120000 setup/account_bank_statement_import_adyen/odoo/addons/account_bank_statement_import_adyen create mode 100644 setup/account_bank_statement_import_adyen/setup.py diff --git a/account_bank_statement_clearing_account/__manifest__.py b/account_bank_statement_clearing_account/__manifest__.py index 04d914fc..5f6e364f 100644 --- a/account_bank_statement_clearing_account/__manifest__.py +++ b/account_bank_statement_clearing_account/__manifest__.py @@ -8,8 +8,6 @@ "category": "Banking addons", "website": "https://opener.am", "license": "AGPL-3", - "depends": [ - "account_cancel", - ], + "depends": ["account_cancel",], "installable": True, } diff --git a/account_bank_statement_clearing_account/models/account_bank_statement.py b/account_bank_statement_clearing_account/models/account_bank_statement.py index eb30d373..cf5ebadb 100644 --- a/account_bank_statement_clearing_account/models/account_bank_statement.py +++ b/account_bank_statement_clearing_account/models/account_bank_statement.py @@ -5,7 +5,7 @@ from odoo import api, models class BankStatement(models.Model): - _inherit = 'account.bank.statement' + _inherit = "account.bank.statement" @api.multi def get_reconcile_clearing_account_lines(self): @@ -16,23 +16,25 @@ class BankStatement(models.Model): the counterpart lines is zero. """ self.ensure_one() - if (self.journal_id.default_debit_account_id != - self.journal_id.default_credit_account_id or - not self.journal_id.default_debit_account_id.reconcile): + if ( + self.journal_id.default_debit_account_id + != self.journal_id.default_credit_account_id + or not self.journal_id.default_debit_account_id.reconcile + ): return False account = self.journal_id.default_debit_account_id currency = self.journal_id.currency_id or self.company_id.currency_id def get_bank_line(st_line): for line in st_line.journal_entry_ids: - field = 'debit' if st_line.amount > 0 else 'credit' - if (line.account_id == account and - not currency.compare_amounts( - line[field], abs(st_line.amount))): + field = "debit" if st_line.amount > 0 else "credit" + if line.account_id == account and not currency.compare_amounts( + line[field], abs(st_line.amount) + ): return line return False - move_lines = self.env['account.move.line'] + move_lines = self.env["account.move.line"] for st_line in self.line_ids: bank_line = get_bank_line(st_line) if not bank_line: @@ -50,8 +52,8 @@ class BankStatement(models.Model): self.ensure_one() lines = self.get_reconcile_clearing_account_lines() if not lines or any( - li.matched_debit_ids or li.matched_credit_ids - for li in lines): + li.matched_debit_ids or li.matched_credit_ids for li in lines + ): return False lines.reconcile() return True diff --git a/account_bank_statement_import_adyen/__manifest__.py b/account_bank_statement_import_adyen/__manifest__.py index 4be97c2e..de271032 100644 --- a/account_bank_statement_import_adyen/__manifest__.py +++ b/account_bank_statement_import_adyen/__manifest__.py @@ -12,13 +12,7 @@ "account_bank_statement_import", "account_bank_statement_clearing_account", ], - "external_dependencies": { - "python": [ - "openpyxl", - ], - }, - "data": [ - "views/account_journal.xml", - ], + "external_dependencies": {"python": ["openpyxl",],}, + "data": ["views/account_journal.xml",], "installable": True, } diff --git a/account_bank_statement_import_adyen/models/account_bank_statement_import.py b/account_bank_statement_import_adyen/models/account_bank_statement_import.py index a8d17f60..45e062de 100644 --- a/account_bank_statement_import_adyen/models/account_bank_statement_import.py +++ b/account_bank_statement_import_adyen/models/account_bank_statement_import.py @@ -1,16 +1,17 @@ # © 2017 Opener BV () # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from io import BytesIO -from openpyxl import load_workbook from zipfile import BadZipfile -from odoo import api, models, fields +from openpyxl import load_workbook + +from odoo import api, fields, models from odoo.exceptions import UserError from odoo.tools.translate import _ class AccountBankStatementImport(models.TransientModel): - _inherit = 'account.bank.statement.import' + _inherit = "account.bank.statement.import" @api.model def _parse_file(self, data_file): @@ -19,41 +20,46 @@ class AccountBankStatementImport(models.TransientModel): try: return self.import_adyen_xlsx(data_file) except ValueError: - return super(AccountBankStatementImport, self)._parse_file( - data_file) + return super(AccountBankStatementImport, self)._parse_file(data_file) def _find_additional_data(self, currency_code, account_number): """ Try to find journal by Adyen merchant account """ if account_number: - journal = self.env['account.journal'].search([ - ('adyen_merchant_account', '=', account_number)], limit=1) + journal = self.env["account.journal"].search( + [("adyen_merchant_account", "=", account_number)], limit=1 + ) if journal: - if self._context.get('journal_id', journal.id) != journal.id: + if self._context.get("journal_id", journal.id) != journal.id: raise UserError( - _('Selected journal Merchant Account does not match ' - 'the import file Merchant Account ' - 'column: %s') % account_number) + _( + "Selected journal Merchant Account does not match " + "the import file Merchant Account " + "column: %s" + ) + % account_number + ) self = self.with_context(journal_id=journal.id) return super(AccountBankStatementImport, self)._find_additional_data( - currency_code, account_number) + currency_code, account_number + ) @api.model def balance(self, row): return -(row[15] or 0) + sum( - row[i] if row[i] else 0.0 - for i in (16, 17, 18, 19, 20)) + row[i] if row[i] else 0.0 for i in (16, 17, 18, 19, 20) + ) @api.model def import_adyen_transaction(self, statement, statement_id, row): - transaction_id = str(len(statement['transactions'])).zfill(4) + transaction_id = str(len(statement["transactions"])).zfill(4) transaction = dict( unique_import_id=statement_id + transaction_id, date=fields.Date.from_string(row[6]), amount=self.balance(row), - note='%s %s %s %s' % (row[2], row[3], row[4], row[21]), + note="{} {} {} {}".format(row[2], row[3], row[4], row[21]), name="%s" % (row[3] or row[4] or row[9]), ) - statement['transactions'].append(transaction) + statement["transactions"].append(transaction) @api.model def import_adyen_xlsx(self, data_file): @@ -75,61 +81,62 @@ class AccountBankStatementImport(models.TransientModel): row = [cell.value for cell in row] if len(row) != 31: raise ValueError( - 'Not an Adyen statement. Unexpected row length %s ' - 'instead of 31' % len(row)) + "Not an Adyen statement. Unexpected row length %s " + "instead of 31" % len(row) + ) if not row[1]: continue if not headers: - if row[1] != 'Company Account': + if row[1] != "Company Account": raise ValueError( 'Not an Adyen statement. Unexpected header "%s" ' - 'instead of "Company Account"', row[1]) + 'instead of "Company Account"', + row[1], + ) headers = True continue if not statement: - statement = {'transactions': []} + statement = {"transactions": []} statements.append(statement) - statement_id = '%s %s/%s' % ( - row[2], row[6].strftime('%Y'), int(row[23])) + statement_id = "{} {}/{}".format( + row[2], + row[6].strftime("%Y"), + int(row[23]), + ) currency_code = row[14] merchant_id = row[2] - statement['name'] = '%s %s/%s' % ( - row[2], row[6].year, row[23]) + statement["name"] = "{} {}/{}".format(row[2], row[6].year, row[23]) date = fields.Date.from_string(row[6]) - if not statement.get('date') or statement.get('date') > date: - statement['date'] = date + if not statement.get("date") or statement.get("date") > date: + statement["date"] = date row[8] = row[8].strip() - if row[8] == 'MerchantPayout': + if row[8] == "MerchantPayout": payout -= self.balance(row) else: balance += self.balance(row) self.import_adyen_transaction(statement, statement_id, row) - fees += sum( - row[i] if row[i] else 0.0 - for i in (17, 18, 19, 20)) + fees += sum(row[i] if row[i] else 0.0 for i in (17, 18, 19, 20)) if not headers: - raise ValueError( - 'Not an Adyen statement. Did not encounter header row.') + raise ValueError("Not an Adyen statement. Did not encounter header row.") if fees: - transaction_id = str(len(statement['transactions'])).zfill(4) + transaction_id = str(len(statement["transactions"])).zfill(4) transaction = dict( unique_import_id=statement_id + transaction_id, - date=max(t['date'] for t in statement['transactions']), + date=max(t["date"] for t in statement["transactions"]), amount=-fees, - name='Commission, markup etc. batch %s' % (int(row[23])), + name="Commission, markup etc. batch %s" % (int(row[23])), ) balance -= fees - statement['transactions'].append(transaction) + statement["transactions"].append(transaction) - if statement['transactions'] and not payout: + if statement["transactions"] and not payout: + raise UserError(_("No payout detected in Adyen statement.")) + if self.env.user.company_id.currency_id.compare_amounts(balance, payout) != 0: raise UserError( - _('No payout detected in Adyen statement.')) - if self.env.user.company_id.currency_id.compare_amounts( - balance, payout) != 0: - raise UserError( - _('Parse error. Balance %s not equal to merchant ' - 'payout %s') % (balance, payout)) + _("Parse error. Balance %s not equal to merchant " "payout %s") + % (balance, payout) + ) return currency_code, merchant_id, statements diff --git a/account_bank_statement_import_adyen/models/account_journal.py b/account_bank_statement_import_adyen/models/account_journal.py index 44a3e7f8..32c213dd 100644 --- a/account_bank_statement_import_adyen/models/account_journal.py +++ b/account_bank_statement_import_adyen/models/account_journal.py @@ -5,14 +5,16 @@ from odoo import fields, models class Journal(models.Model): - _inherit = 'account.journal' + _inherit = "account.journal" adyen_merchant_account = fields.Char( - help=('Fill in the exact merchant account string to select this ' - 'journal when importing Adyen statements')) + help=( + "Fill in the exact merchant account string to select this " + "journal when importing Adyen statements" + ) + ) def _get_bank_statements_available_import_formats(self): - res = super( - Journal, self)._get_bank_statements_available_import_formats() - res.append('adyen') + res = super(Journal, self)._get_bank_statements_available_import_formats() + res.append("adyen") return res diff --git a/account_bank_statement_import_adyen/tests/test_import_adyen.py b/account_bank_statement_import_adyen/tests/test_import_adyen.py index acbadfdf..10e61e92 100644 --- a/account_bank_statement_import_adyen/tests/test_import_adyen.py +++ b/account_bank_statement_import_adyen/tests/test_import_adyen.py @@ -3,24 +3,27 @@ # © 2015 Therp BV () # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). import base64 + from odoo.exceptions import UserError -from odoo.tests.common import SavepointCase from odoo.modules.module import get_module_resource +from odoo.tests.common import SavepointCase class TestImportAdyen(SavepointCase): @classmethod def setUpClass(cls): super(TestImportAdyen, cls).setUpClass() - cls.journal = cls.env['account.journal'].create({ - 'company_id': cls.env.user.company_id.id, - 'name': 'Adyen test', - 'code': 'ADY', - 'type': 'bank', - 'adyen_merchant_account': 'YOURCOMPANY_ACCOUNT', - 'update_posted': True, - 'currency_id': cls.env.ref('base.USD').id, - }) + cls.journal = cls.env["account.journal"].create( + { + "company_id": cls.env.user.company_id.id, + "name": "Adyen test", + "code": "ADY", + "type": "bank", + "adyen_merchant_account": "YOURCOMPANY_ACCOUNT", + "update_posted": True, + "currency_id": cls.env.ref("base.USD").id, + } + ) # Enable reconcilation on the default journal account to trigger # the functionality from account_bank_statement_clearing_account cls.journal.default_debit_account_id.reconcile = True @@ -30,79 +33,91 @@ class TestImportAdyen(SavepointCase): lines on the default journal (clearing) account are fully reconciled with each other """ self._test_statement_import( - 'account_bank_statement_import_adyen', 'adyen_test.xlsx', - 'YOURCOMPANY_ACCOUNT 2016/48') - statement = self.env['account.bank.statement'].search( - [], order='create_date desc', limit=1) + "account_bank_statement_import_adyen", + "adyen_test.xlsx", + "YOURCOMPANY_ACCOUNT 2016/48", + ) + statement = self.env["account.bank.statement"].search( + [], order="create_date desc", limit=1 + ) self.assertEqual(statement.journal_id, self.journal) self.assertEqual(len(statement.line_ids), 22) self.assertTrue( self.env.user.company_id.currency_id.is_zero( - sum(line.amount for line in statement.line_ids))) + sum(line.amount for line in statement.line_ids) + ) + ) - account = self.env['account.account'].search([( - 'internal_type', '=', 'receivable')], limit=1) + account = self.env["account.account"].search( + [("internal_type", "=", "receivable")], limit=1 + ) for line in statement.line_ids: - line.process_reconciliation(new_aml_dicts=[{ - 'debit': -line.amount if line.amount < 0 else 0, - 'credit': line.amount if line.amount > 0 else 0, - 'account_id': account.id}]) + line.process_reconciliation( + new_aml_dicts=[ + { + "debit": -line.amount if line.amount < 0 else 0, + "credit": line.amount if line.amount > 0 else 0, + "account_id": account.id, + } + ] + ) statement.button_confirm_bank() - self.assertEqual(statement.state, 'confirm') - lines = self.env['account.move.line'].search([ - ('account_id', '=', self.journal.default_debit_account_id.id), - ('statement_id', '=', statement.id)]) - reconcile = lines.mapped('full_reconcile_id') + self.assertEqual(statement.state, "confirm") + lines = self.env["account.move.line"].search( + [ + ("account_id", "=", self.journal.default_debit_account_id.id), + ("statement_id", "=", statement.id), + ] + ) + reconcile = lines.mapped("full_reconcile_id") self.assertEqual(len(reconcile), 1) self.assertEqual(lines, reconcile.reconciled_line_ids) # Reset the bank statement to see the counterpart lines being # unreconciled statement.button_draft() - self.assertEqual(statement.state, 'open') - self.assertFalse(lines.mapped('matched_debit_ids')) - self.assertFalse(lines.mapped('matched_credit_ids')) - self.assertFalse(lines.mapped('full_reconcile_id')) + self.assertEqual(statement.state, "open") + self.assertFalse(lines.mapped("matched_debit_ids")) + self.assertFalse(lines.mapped("matched_credit_ids")) + self.assertFalse(lines.mapped("full_reconcile_id")) # Confirm the statement without the correct clearing account settings self.journal.default_debit_account_id.reconcile = False statement.button_confirm_bank() - self.assertEqual(statement.state, 'confirm') - self.assertFalse(lines.mapped('matched_debit_ids')) - self.assertFalse(lines.mapped('matched_credit_ids')) - self.assertFalse(lines.mapped('full_reconcile_id')) + self.assertEqual(statement.state, "confirm") + self.assertFalse(lines.mapped("matched_debit_ids")) + self.assertFalse(lines.mapped("matched_credit_ids")) + self.assertFalse(lines.mapped("full_reconcile_id")) def test_02_import_adyen_credit_fees(self): """ Import an Adyen statement with credit fees """ self._test_statement_import( - 'account_bank_statement_import_adyen', - 'adyen_test_credit_fees.xlsx', - 'YOURCOMPANY_ACCOUNT 2016/8') + "account_bank_statement_import_adyen", + "adyen_test_credit_fees.xlsx", + "YOURCOMPANY_ACCOUNT 2016/8", + ) def test_03_import_adyen_invalid(self): """ Trying to hit that coverall target """ - with self.assertRaisesRegex(UserError, 'Could not make sense'): + with self.assertRaisesRegex(UserError, "Could not make sense"): self._test_statement_import( - 'account_bank_statement_import_adyen', - 'adyen_test_invalid.xls', - 'invalid') + "account_bank_statement_import_adyen", + "adyen_test_invalid.xls", + "invalid", + ) - def _test_statement_import( - self, module_name, file_name, statement_name): + def _test_statement_import(self, module_name, file_name, statement_name): """Test correct creation of single statement.""" - statement_path = get_module_resource( - module_name, - 'test_files', - file_name + statement_path = get_module_resource(module_name, "test_files", file_name) + statement_file = open(statement_path, "rb").read() + import_wizard = self.env["account.bank.statement.import"].create( + {"data_file": base64.b64encode(statement_file), "filename": file_name} ) - statement_file = open(statement_path, 'rb').read() - import_wizard = self.env['account.bank.statement.import'].create({ - 'data_file': base64.b64encode(statement_file), - 'filename': file_name}) import_wizard.import_file() # statement name is account number + '-' + date of last line: - statements = self.env['account.bank.statement'].search( - [('name', '=', statement_name)]) + statements = self.env["account.bank.statement"].search( + [("name", "=", statement_name)] + ) self.assertTrue(statements) return statements diff --git a/account_bank_statement_import_adyen/views/account_journal.xml b/account_bank_statement_import_adyen/views/account_journal.xml index 02f36f05..bf845158 100644 --- a/account_bank_statement_import_adyen/views/account_journal.xml +++ b/account_bank_statement_import_adyen/views/account_journal.xml @@ -1,12 +1,12 @@ - + Add Adyen merchant account account.journal - + - + diff --git a/setup/account_bank_statement_clearing_account/odoo/addons/account_bank_statement_clearing_account b/setup/account_bank_statement_clearing_account/odoo/addons/account_bank_statement_clearing_account new file mode 120000 index 00000000..4ae7bb48 --- /dev/null +++ b/setup/account_bank_statement_clearing_account/odoo/addons/account_bank_statement_clearing_account @@ -0,0 +1 @@ +../../../../account_bank_statement_clearing_account \ No newline at end of file diff --git a/setup/account_bank_statement_clearing_account/setup.py b/setup/account_bank_statement_clearing_account/setup.py new file mode 100644 index 00000000..28c57bb6 --- /dev/null +++ b/setup/account_bank_statement_clearing_account/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/account_bank_statement_import_adyen/odoo/addons/account_bank_statement_import_adyen b/setup/account_bank_statement_import_adyen/odoo/addons/account_bank_statement_import_adyen new file mode 120000 index 00000000..2e39464e --- /dev/null +++ b/setup/account_bank_statement_import_adyen/odoo/addons/account_bank_statement_import_adyen @@ -0,0 +1 @@ +../../../../account_bank_statement_import_adyen \ No newline at end of file diff --git a/setup/account_bank_statement_import_adyen/setup.py b/setup/account_bank_statement_import_adyen/setup.py new file mode 100644 index 00000000..28c57bb6 --- /dev/null +++ b/setup/account_bank_statement_import_adyen/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)