[IMP] : black, isort, prettier

This commit is contained in:
Ronald Portier
2021-02-17 16:26:15 +01:00
committed by Ronald Portier (Therp BV)
parent 10d9639646
commit fc8b6db62d
11 changed files with 161 additions and 129 deletions

View File

@@ -8,8 +8,6 @@
"category": "Banking addons",
"website": "https://opener.am",
"license": "AGPL-3",
"depends": [
"account_cancel",
],
"depends": ["account_cancel",],
"installable": True,
}

View File

@@ -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

View File

@@ -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,
}

View File

@@ -1,16 +1,17 @@
# © 2017 Opener BV (<https://opener.amsterdam>)
# 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

View File

@@ -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

View File

@@ -3,24 +3,27 @@
# © 2015 Therp BV (<http://therp.nl>)
# 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

View File

@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="view_account_journal_form" model="ir.ui.view">
<field name="name">Add Adyen merchant account</field>
<field name="model">account.journal</field>
<field name="inherit_id" ref="account.view_account_journal_form"/>
<field name="inherit_id" ref="account.view_account_journal_form" />
<field name="arch" type="xml">
<field name="currency_id" position="after">
<field name="adyen_merchant_account"/>
<field name="adyen_merchant_account" />
</field>
</field>
</record>

View File

@@ -0,0 +1 @@
../../../../account_bank_statement_clearing_account

View File

@@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)

View File

@@ -0,0 +1 @@
../../../../account_bank_statement_import_adyen

View File

@@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)