[IMP] account_bank_statement_import_online: black, isort, prettier

This commit is contained in:
Alexey Pelykh
2020-04-25 11:13:55 +02:00
parent 58c1fad0cf
commit 4fd518dcfe
13 changed files with 645 additions and 719 deletions

View File

@@ -3,29 +3,26 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
'name': 'Online Bank Statements',
'version': '12.0.1.4.1',
'author':
'Brainbean Apps, '
'Dataplug, '
'Odoo Community Association (OCA)',
'maintainers': ['alexey-pelykh'],
'website': 'https://github.com/OCA/bank-statement-import/',
'license': 'AGPL-3',
'category': 'Accounting',
'summary': 'Online bank statements update',
'depends': [
'account',
'account_bank_statement_import',
'web_widget_dropdown_dynamic',
"name": "Online Bank Statements",
"version": "12.0.1.4.1",
"author": "Brainbean Apps, Dataplug, Odoo Community Association (OCA)",
"maintainers": ["alexey-pelykh"],
"website": "https://github.com/OCA/bank-statement-import/",
"license": "AGPL-3",
"category": "Accounting",
"summary": "Online bank statements update",
"depends": [
"account",
"account_bank_statement_import",
"web_widget_dropdown_dynamic",
],
'data': [
'data/account_bank_statement_import_online.xml',
'security/ir.model.access.csv',
'security/online_bank_statement_provider.xml',
'views/account_journal.xml',
'views/online_bank_statement_provider.xml',
'wizards/online_bank_statement_pull_wizard.xml',
"data": [
"data/account_bank_statement_import_online.xml",
"security/ir.model.access.csv",
"security/online_bank_statement_provider.xml",
"views/account_journal.xml",
"views/online_bank_statement_provider.xml",
"wizards/online_bank_statement_pull_wizard.xml",
],
'installable': True,
"installable": True,
}

View File

@@ -5,7 +5,6 @@
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
-->
<odoo noupdate="1">
<record model="ir.cron" id="ir_cron_account_pull_online_bank_statements">
<field name="name">Pull Online Bank Statements</field>
<field name="interval_number">1</field>
@@ -14,8 +13,10 @@
<field name="state">code</field>
<field name="nextcall">2019-01-01 00:10:00</field>
<field name="doall" eval="False" />
<field name="model_id" ref="account_bank_statement_import_online.model_online_bank_statement_provider"/>
<field
name="model_id"
ref="account_bank_statement_import_online.model_online_bank_statement_provider"
/>
<field name="code">model._scheduled_pull()</field>
</record>
</odoo>

View File

@@ -4,54 +4,50 @@
import logging
from odoo import models, fields, api, _
from odoo import _, api, fields, models
_logger = logging.getLogger(__name__)
class AccountJournal(models.Model):
_inherit = 'account.journal'
_inherit = "account.journal"
online_bank_statement_provider = fields.Selection(
selection=lambda self: self.env[
'account.journal'
"account.journal"
]._selection_online_bank_statement_provider(),
)
online_bank_statement_provider_id = fields.Many2one(
string='Statement Provider',
comodel_name='online.bank.statement.provider',
ondelete='restrict',
string="Statement Provider",
comodel_name="online.bank.statement.provider",
ondelete="restrict",
copy=False,
)
def __get_bank_statements_available_sources(self):
result = super().__get_bank_statements_available_sources()
result.append(('online', _('Online (OCA)')))
result.append(("online", _("Online (OCA)")))
return result
@api.model
def _selection_online_bank_statement_provider(self):
return self.env[
'online.bank.statement.provider'
]._get_available_services() + [('dummy', 'Dummy')]
return self.env["online.bank.statement.provider"]._get_available_services() + [
("dummy", "Dummy")
]
@api.model
def values_online_bank_statement_provider(self):
res = self.env[
'online.bank.statement.provider'
]._get_available_services()
if self.user_has_groups('base.group_no_one'):
res += [('dummy', 'Dummy')]
res = self.env["online.bank.statement.provider"]._get_available_services()
if self.user_has_groups("base.group_no_one"):
res += [("dummy", "Dummy")]
return res
@api.multi
def _update_online_bank_statement_provider_id(self):
OnlineBankStatementProvider = (
self.env['online.bank.statement.provider']
)
for journal in self.filtered('id'):
OnlineBankStatementProvider = self.env["online.bank.statement.provider"]
for journal in self.filtered("id"):
provider_id = journal.online_bank_statement_provider_id
if journal.bank_statements_source != 'online':
if journal.bank_statements_source != "online":
journal.online_bank_statement_provider_id = False
if provider_id:
provider_id.unlink()
@@ -61,40 +57,39 @@ class AccountJournal(models.Model):
journal.online_bank_statement_provider_id = False
if provider_id:
provider_id.unlink()
journal.online_bank_statement_provider_id = (
# fmt: off
journal.online_bank_statement_provider_id = \
OnlineBankStatementProvider.create({
'journal_id': journal.id,
'service': journal.online_bank_statement_provider,
"journal_id": journal.id,
"service": journal.online_bank_statement_provider,
})
)
# fmt: on
@api.model
def create(self, vals):
rec = super().create(vals)
if 'bank_statements_source' in vals \
or 'online_bank_statement_provider' in vals:
if "bank_statements_source" in vals or "online_bank_statement_provider" in vals:
rec._update_online_bank_statement_provider_id()
return rec
@api.multi
def write(self, vals):
res = super().write(vals)
if 'bank_statements_source' in vals \
or 'online_bank_statement_provider' in vals:
if "bank_statements_source" in vals or "online_bank_statement_provider" in vals:
self._update_online_bank_statement_provider_id()
return res
@api.multi
def action_online_bank_statements_pull_wizard(self):
provider_ids = self.mapped('online_bank_statement_provider_id').ids
provider_ids = self.mapped("online_bank_statement_provider_id").ids
return {
'name': _('Online Bank Statement Pull Wizard'),
'type': 'ir.actions.act_window',
'res_model': 'online.bank.statement.pull.wizard',
'views': [[False, 'form']],
'target': 'new',
'context': {
'default_provider_ids': [(6, False, provider_ids)],
'active_test': False,
"name": _("Online Bank Statement Pull Wizard"),
"type": "ir.actions.act_window",
"res_model": "online.bank.statement.pull.wizard",
"views": [[False, "form"]],
"target": "new",
"context": {
"default_provider_ids": [(6, False, provider_ids)],
"active_test": False,
},
}

View File

@@ -2,15 +2,16 @@
# Copyright 2019-2020 Dataplug (https://dataplug.io)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
import logging
from datetime import datetime
from dateutil.relativedelta import relativedelta, MO
from decimal import Decimal
from html import escape
import logging
from pytz import timezone, utc
from sys import exc_info
from odoo import models, fields, api, _
from dateutil.relativedelta import MO, relativedelta
from pytz import timezone, utc
from odoo import _, api, fields, models
from odoo.addons.base.models.res_bank import sanitize_account_number
from odoo.addons.base.models.res_partner import _tz_get
@@ -18,83 +19,63 @@ _logger = logging.getLogger(__name__)
class OnlineBankStatementProvider(models.Model):
_name = 'online.bank.statement.provider'
_inherit = ['mail.thread']
_description = 'Online Bank Statement Provider'
_name = "online.bank.statement.provider"
_inherit = ["mail.thread"]
_description = "Online Bank Statement Provider"
company_id = fields.Many2one(
related='journal_id.company_id',
store=True,
)
company_id = fields.Many2one(related="journal_id.company_id", store=True)
active = fields.Boolean()
name = fields.Char(
string='Name',
compute='_compute_name',
store=True,
)
name = fields.Char(string="Name", compute="_compute_name", store=True)
journal_id = fields.Many2one(
comodel_name='account.journal',
comodel_name="account.journal",
required=True,
readonly=True,
ondelete='cascade',
domain=[
('type', '=', 'bank'),
],
)
currency_id = fields.Many2one(
related='journal_id.currency_id',
ondelete="cascade",
domain=[("type", "=", "bank")],
)
currency_id = fields.Many2one(related="journal_id.currency_id")
account_number = fields.Char(
related='journal_id.bank_account_id.sanitized_acc_number'
related="journal_id.bank_account_id.sanitized_acc_number"
)
tz = fields.Selection(
selection=_tz_get,
string='Timezone',
default=lambda self: self.env.context.get('tz'),
string="Timezone",
default=lambda self: self.env.context.get("tz"),
help=(
'Timezone to convert transaction timestamps to prior being'
' saved into a statement.'
"Timezone to convert transaction timestamps to prior being"
" saved into a statement."
),
)
service = fields.Selection(
selection=lambda self: self._selection_service(),
required=True,
readonly=True,
selection=lambda self: self._selection_service(), required=True, readonly=True,
)
interval_type = fields.Selection(
selection=[
('minutes', 'Minute(s)'),
('hours', 'Hour(s)'),
('days', 'Day(s)'),
('weeks', 'Week(s)'),
("minutes", "Minute(s)"),
("hours", "Hour(s)"),
("days", "Day(s)"),
("weeks", "Week(s)"),
],
default='hours',
default="hours",
required=True,
)
interval_number = fields.Integer(
string='Scheduled update interval',
default=1,
required=True,
string="Scheduled update interval", default=1, required=True,
)
update_schedule = fields.Char(
string='Update Schedule',
compute='_compute_update_schedule',
)
last_successful_run = fields.Datetime(
string='Last successful pull',
string="Update Schedule", compute="_compute_update_schedule",
)
last_successful_run = fields.Datetime(string="Last successful pull")
next_run = fields.Datetime(
string='Next scheduled pull',
default=fields.Datetime.now,
required=True,
string="Next scheduled pull", default=fields.Datetime.now, required=True,
)
statement_creation_mode = fields.Selection(
selection=[
('daily', 'Daily statements'),
('weekly', 'Weekly statements'),
('monthly', 'Monthly statements'),
("daily", "Daily statements"),
("weekly", "Weekly statements"),
("monthly", "Monthly statements"),
],
default='daily',
default="daily",
required=True,
)
api_base = fields.Char()
@@ -110,15 +91,15 @@ class OnlineBankStatementProvider(models.Model):
_sql_constraints = [
(
'journal_id_uniq',
'UNIQUE(journal_id)',
'Only one online banking statement provider per journal!'
"journal_id_uniq",
"UNIQUE(journal_id)",
"Only one online banking statement provider per journal!",
),
(
'valid_interval_number',
'CHECK(interval_number > 0)',
'Scheduled update interval must be greater than zero!'
)
"valid_interval_number",
"CHECK(interval_number > 0)",
"Scheduled update interval must be greater than zero!",
),
]
@api.model
@@ -128,65 +109,64 @@ class OnlineBankStatementProvider(models.Model):
@api.model
def _selection_service(self):
return self._get_available_services() + [('dummy', 'Dummy')]
return self._get_available_services() + [("dummy", "Dummy")]
@api.model
def values_service(self):
return self._get_available_services()
@api.multi
@api.depends('service')
@api.depends("service")
def _compute_name(self):
for provider in self:
provider.name = list(filter(
lambda x: x[0] == provider.service,
self._selection_service()
))[0][1]
provider.name = list(
filter(lambda x: x[0] == provider.service, self._selection_service())
)[0][1]
@api.multi
@api.depends('active', 'interval_type', 'interval_number')
@api.depends("active", "interval_type", "interval_number")
def _compute_update_schedule(self):
for provider in self:
if not provider.active:
provider.update_schedule = _('Inactive')
provider.update_schedule = _("Inactive")
continue
provider.update_schedule = _('%(number)s %(type)s') % {
'number': provider.interval_number,
'type': list(filter(
provider.update_schedule = _("%(number)s %(type)s") % {
"number": provider.interval_number,
"type": list(
filter(
lambda x: x[0] == provider.interval_type,
self._fields['interval_type'].selection
))[0][1],
self._fields["interval_type"].selection,
)
)[0][1],
}
@api.multi
@api.multi # noqa: C901
def _pull(self, date_since, date_until):
AccountBankStatement = self.env['account.bank.statement']
is_scheduled = self.env.context.get('scheduled')
AccountBankStatement = self.env["account.bank.statement"]
is_scheduled = self.env.context.get("scheduled")
if is_scheduled:
AccountBankStatement = AccountBankStatement.with_context(
tracking_disable=True,
)
AccountBankStatementLine = self.env['account.bank.statement.line']
AccountBankStatementLine = self.env["account.bank.statement.line"]
for provider in self:
provider_tz = timezone(provider.tz) if provider.tz else utc
statement_date_since = provider._get_statement_date_since(
date_since
)
statement_date_since = provider._get_statement_date_since(date_since)
while statement_date_since < date_until:
statement_date_until = (
statement_date_since + provider._get_statement_date_step()
)
try:
data = provider._obtain_statement_data(
statement_date_since,
statement_date_until
statement_date_since, statement_date_until
)
except:
except BaseException as e:
if is_scheduled:
_logger.warning(
'Online Bank Statement Provider "%s" failed to'
' obtain statement data since %s until %s' % (
" obtain statement data since %s until %s"
% (
provider.name,
statement_date_since,
statement_date_until,
@@ -195,23 +175,21 @@ class OnlineBankStatementProvider(models.Model):
)
provider.message_post(
body=_(
'Failed to obtain statement data for period '
'since %s until %s: %s. See server logs for '
'more details.'
) % (
"Failed to obtain statement data for period "
"since %s until %s: %s. See server logs for "
"more details."
)
% (
statement_date_since,
statement_date_until,
escape(str(exc_info()[1])) or _('N/A')
),
subject=_(
'Issue with Online Bank Statement Provider'
escape(str(e)) or _("N/A"),
),
subject=_("Issue with Online Bank Statement Provider"),
)
break
raise
statement_date = provider._get_statement_date(
statement_date_since,
statement_date_until,
statement_date_since, statement_date_until,
)
if not data:
data = ([], {})
@@ -220,19 +198,24 @@ class OnlineBankStatementProvider(models.Model):
lines_data = []
if not statement_values:
statement_values = {}
statement = AccountBankStatement.search([
('journal_id', '=', provider.journal_id.id),
('state', '=', 'open'),
('date', '=', statement_date),
], limit=1)
statement = AccountBankStatement.search(
[
("journal_id", "=", provider.journal_id.id),
("state", "=", "open"),
("date", "=", statement_date),
],
limit=1,
)
if not statement:
statement_values.update({
'name': provider.journal_id.sequence_id.with_context(
statement_values.update(
{
"name": provider.journal_id.sequence_id.with_context(
ir_sequence_date=statement_date,
).next_by_id(),
'journal_id': provider.journal_id.id,
'date': statement_date,
})
"journal_id": provider.journal_id.id,
"date": statement_date,
}
)
statement = AccountBankStatement.with_context(
journal_id=provider.journal_id.id,
).create(
@@ -241,7 +224,7 @@ class OnlineBankStatementProvider(models.Model):
)
filtered_lines = []
for line_values in lines_data:
date = line_values['date']
date = line_values["date"]
if not isinstance(date, datetime):
date = fields.Datetime.from_string(date)
@@ -250,64 +233,56 @@ class OnlineBankStatementProvider(models.Model):
date = date.astimezone(utc).replace(tzinfo=None)
if date < statement_date_since:
if 'balance_start' in statement_values:
statement_values['balance_start'] = (
Decimal(
statement_values['balance_start']
) + Decimal(
line_values['amount']
)
)
if "balance_start" in statement_values:
statement_values["balance_start"] = Decimal(
statement_values["balance_start"]
) + Decimal(line_values["amount"])
continue
elif date >= statement_date_until:
if 'balance_end_real' in statement_values:
statement_values['balance_end_real'] = (
Decimal(
statement_values['balance_end_real']
) - Decimal(
line_values['amount']
)
)
if "balance_end_real" in statement_values:
statement_values["balance_end_real"] = Decimal(
statement_values["balance_end_real"]
) - Decimal(line_values["amount"])
continue
date = date.replace(tzinfo=utc)
date = date.astimezone(provider_tz).replace(tzinfo=None)
line_values['date'] = date
line_values["date"] = date
unique_import_id = line_values.get('unique_import_id')
unique_import_id = line_values.get("unique_import_id")
if unique_import_id:
unique_import_id = provider._generate_unique_import_id(
unique_import_id
)
line_values.update({
'unique_import_id': unique_import_id,
})
line_values.update({"unique_import_id": unique_import_id})
if AccountBankStatementLine.sudo().search(
[('unique_import_id', '=', unique_import_id)],
limit=1):
[("unique_import_id", "=", unique_import_id)], limit=1
):
continue
bank_account_number = line_values.get('account_number')
bank_account_number = line_values.get("account_number")
if bank_account_number:
line_values.update({
'account_number': (
line_values.update(
{
"account_number": (
self._sanitize_bank_account_number(
bank_account_number
)
),
})
}
)
filtered_lines.append(line_values)
statement_values.update({
'line_ids': [[0, False, line] for line in filtered_lines],
})
if 'balance_start' in statement_values:
statement_values['balance_start'] = float(
statement_values['balance_start']
statement_values.update(
{"line_ids": [[0, False, line] for line in filtered_lines]}
)
if 'balance_end_real' in statement_values:
statement_values['balance_end_real'] = float(
statement_values['balance_end_real']
if "balance_start" in statement_values:
statement_values["balance_start"] = float(
statement_values["balance_start"]
)
if "balance_end_real" in statement_values:
statement_values["balance_end_real"] = float(
statement_values["balance_end_real"]
)
statement.write(statement_values)
statement_date_since = statement_date_until
@@ -323,49 +298,26 @@ class OnlineBankStatementProvider(models.Model):
@api.multi
def _get_statement_date_since(self, date):
self.ensure_one()
date = date.replace(
hour=0,
minute=0,
second=0,
microsecond=0,
)
if self.statement_creation_mode == 'daily':
date = date.replace(hour=0, minute=0, second=0, microsecond=0)
if self.statement_creation_mode == "daily":
return date
elif self.statement_creation_mode == 'weekly':
elif self.statement_creation_mode == "weekly":
return date + relativedelta(weekday=MO(-1))
elif self.statement_creation_mode == 'monthly':
return date.replace(
day=1,
)
elif self.statement_creation_mode == "monthly":
return date.replace(day=1)
@api.multi
def _get_statement_date_step(self):
self.ensure_one()
if self.statement_creation_mode == 'daily':
if self.statement_creation_mode == "daily":
return relativedelta(days=1, hour=0, minute=0, second=0, microsecond=0)
elif self.statement_creation_mode == "weekly":
return relativedelta(
days=1,
hour=0,
minute=0,
second=0,
microsecond=0,
weeks=1, weekday=MO, hour=0, minute=0, second=0, microsecond=0,
)
elif self.statement_creation_mode == 'weekly':
elif self.statement_creation_mode == "monthly":
return relativedelta(
weeks=1,
weekday=MO,
hour=0,
minute=0,
second=0,
microsecond=0,
)
elif self.statement_creation_mode == 'monthly':
return relativedelta(
months=1,
day=1,
hour=0,
minute=0,
second=0,
microsecond=0,
months=1, day=1, hour=0, minute=0, second=0, microsecond=0,
)
@api.multi
@@ -382,8 +334,11 @@ class OnlineBankStatementProvider(models.Model):
def _generate_unique_import_id(self, unique_import_id):
self.ensure_one()
return (
self.account_number and self.account_number + '-' or ''
) + str(self.journal_id.id) + '-' + unique_import_id
(self.account_number and self.account_number + "-" or "")
+ str(self.journal_id.id)
+ "-"
+ unique_import_id
)
@api.multi
def _sanitize_bank_account_number(self, bank_account_number):
@@ -394,42 +349,40 @@ class OnlineBankStatementProvider(models.Model):
@api.multi
def _get_next_run_period(self):
self.ensure_one()
if self.interval_type == 'minutes':
if self.interval_type == "minutes":
return relativedelta(minutes=self.interval_number)
elif self.interval_type == 'hours':
elif self.interval_type == "hours":
return relativedelta(hours=self.interval_number)
elif self.interval_type == 'days':
elif self.interval_type == "days":
return relativedelta(days=self.interval_number)
elif self.interval_type == 'weeks':
elif self.interval_type == "weeks":
return relativedelta(weeks=self.interval_number)
@api.model
def _scheduled_pull(self):
_logger.info('Scheduled pull of online bank statements...')
_logger.info("Scheduled pull of online bank statements...")
providers = self.search([
('active', '=', True),
('next_run', '<=', fields.Datetime.now()),
])
providers = self.search(
[("active", "=", True), ("next_run", "<=", fields.Datetime.now())]
)
if providers:
_logger.info('Pulling online bank statements of: %s' % ', '.join(
providers.mapped('journal_id.name')
))
for provider in providers.with_context({'scheduled': True}):
_logger.info(
"Pulling online bank statements of: %s"
% ", ".join(providers.mapped("journal_id.name"))
)
for provider in providers.with_context({"scheduled": True}):
date_since = (
provider.last_successful_run
) if provider.last_successful_run else (
provider.next_run - provider._get_next_run_period()
(provider.last_successful_run)
if provider.last_successful_run
else (provider.next_run - provider._get_next_run_period())
)
date_until = provider.next_run
provider._pull(date_since, date_until)
_logger.info('Scheduled pull of online bank statements complete.')
_logger.info("Scheduled pull of online bank statements complete.")
@api.multi
def _obtain_statement_data(
self, date_since, date_until
):
def _obtain_statement_data(self, date_since, date_until):
"""Hook for extension"""
# Check tests/online_bank_statement_provider_dummy.py for reference
self.ensure_one()

View File

@@ -5,12 +5,12 @@
Copyright 2019 Dataplug (https://dataplug.io)
-->
<odoo noupdate="1">
<record id="online_bank_statement_provider_multicompany" model="ir.rule">
<field name="name">Online Bank Statement Provider multi-company</field>
<field name="model_id" ref="model_online_bank_statement_provider" />
<field eval="True" name="global" />
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
<field
name="domain_force"
>['|', ('company_id', '=', False), ('company_id', 'child_of', [user.company_id.id])]</field>
</record>
</odoo>

View File

@@ -3,83 +3,75 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from datetime import datetime, timedelta
from random import randrange
from dateutil.relativedelta import relativedelta
from pytz import timezone
from random import randrange
from odoo import api, fields, models
class OnlineBankStatementProviderDummy(models.Model):
_inherit = 'online.bank.statement.provider'
_inherit = "online.bank.statement.provider"
@api.multi
def _obtain_statement_data(self, date_since, date_until):
self.ensure_one()
if self.service != 'dummy':
if self.service != "dummy":
return super()._obtain_statement_data(
date_since,
date_until,
date_since, date_until,
) # pragma: no cover
if self.env.context.get('crash', False):
exception = self.env.context.get(
'exception',
Exception('Expected')
)
if self.env.context.get("crash", False):
exception = self.env.context.get("exception", Exception("Expected"))
raise exception
line_step_options = self.env.context.get('step', {
'minutes': 5,
})
line_step_options = self.env.context.get("step", {"minutes": 5})
line_step = relativedelta(**line_step_options)
expand_by = self.env.context.get('expand_by', 0)
data_since = self.env.context.get('data_since', date_since)
data_until = self.env.context.get('data_until', date_until)
expand_by = self.env.context.get("expand_by", 0)
data_since = self.env.context.get("data_since", date_since)
data_until = self.env.context.get("data_until", date_until)
data_since -= expand_by * line_step
data_until += expand_by * line_step
balance_start = self.env.context.get(
'balance_start',
randrange(-10000, 10000, 1) * 0.1
"balance_start", randrange(-10000, 10000, 1) * 0.1
)
balance = balance_start
tz = self.env.context.get('tz')
tz = self.env.context.get("tz")
if tz:
tz = timezone(tz)
timestamp_mode = self.env.context.get('timestamp_mode')
timestamp_mode = self.env.context.get("timestamp_mode")
lines = []
date = data_since
while date < data_until:
amount = self.env.context.get(
'amount',
randrange(-100, 100, 1) * 0.1
)
amount = self.env.context.get("amount", randrange(-100, 100, 1) * 0.1)
transaction_date = date.replace(tzinfo=tz)
if timestamp_mode == 'date':
if timestamp_mode == "date":
transaction_date = transaction_date.date()
elif timestamp_mode == 'str':
elif timestamp_mode == "str":
transaction_date = fields.Datetime.to_string(transaction_date)
lines.append({
'name': 'payment',
'amount': amount,
'date': transaction_date,
'unique_import_id': str(int(
(date - datetime(1970, 1, 1)) / timedelta(seconds=1)
)),
'partner_name': 'John Doe',
'account_number': 'XX00 0000 0000 0000',
})
lines.append(
{
"name": "payment",
"amount": amount,
"date": transaction_date,
"unique_import_id": str(
int((date - datetime(1970, 1, 1)) / timedelta(seconds=1))
),
"partner_name": "John Doe",
"account_number": "XX00 0000 0000 0000",
}
)
balance += amount
date += line_step
balance_end = balance
statement = {}
if self.env.context.get('balance', True):
statement.update({
'balance_start': balance_start,
'balance_end_real': balance_end,
})
if self.env.context.get("balance", True):
statement.update(
{"balance_start": balance_start, "balance_end_real": balance_end}
)
return lines, statement

View File

@@ -3,54 +3,48 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from datetime import date, datetime
from dateutil.relativedelta import relativedelta
from psycopg2 import IntegrityError
from urllib.error import HTTPError
from dateutil.relativedelta import relativedelta
from psycopg2 import IntegrityError
from odoo import fields
from odoo.tests import common
from odoo.tools import mute_logger
from odoo import fields
class TestAccountBankAccountStatementImportOnline(common.TransactionCase):
def setUp(self):
super().setUp()
self.now = fields.Datetime.now()
self.AccountJournal = self.env['account.journal']
self.OnlineBankStatementProvider = self.env[
'online.bank.statement.provider'
]
self.AccountJournal = self.env["account.journal"]
self.OnlineBankStatementProvider = self.env["online.bank.statement.provider"]
self.OnlineBankStatementPullWizard = self.env[
'online.bank.statement.pull.wizard'
"online.bank.statement.pull.wizard"
]
self.AccountBankStatement = self.env['account.bank.statement']
self.AccountBankStatementLine = self.env['account.bank.statement.line']
self.AccountBankStatement = self.env["account.bank.statement"]
self.AccountBankStatementLine = self.env["account.bank.statement.line"]
def test_provider_unlink_restricted(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
})
journal = self.AccountJournal.create(
{"name": "Bank", "type": "bank", "code": "BANK"}
)
with common.Form(journal) as journal_form:
journal_form.bank_statements_source = 'online'
journal_form.online_bank_statement_provider = 'dummy'
journal_form.bank_statements_source = "online"
journal_form.online_bank_statement_provider = "dummy"
journal_form.save()
with self.assertRaises(IntegrityError), mute_logger('odoo.sql_db'):
with self.assertRaises(IntegrityError), mute_logger("odoo.sql_db"):
journal.online_bank_statement_provider_id.unlink()
def test_cascade_unlink(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
})
journal = self.AccountJournal.create(
{"name": "Bank", "type": "bank", "code": "BANK"}
)
with common.Form(journal) as journal_form:
journal_form.bank_statements_source = 'online'
journal_form.online_bank_statement_provider = 'dummy'
journal_form.bank_statements_source = "online"
journal_form.online_bank_statement_provider = "dummy"
journal_form.save()
self.assertTrue(journal.online_bank_statement_provider_id)
@@ -58,329 +52,320 @@ class TestAccountBankAccountStatementImportOnline(common.TransactionCase):
self.assertFalse(self.OnlineBankStatementProvider.search([]))
def test_source_change_cleanup(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
})
journal = self.AccountJournal.create(
{"name": "Bank", "type": "bank", "code": "BANK"}
)
with common.Form(journal) as journal_form:
journal_form.bank_statements_source = 'online'
journal_form.online_bank_statement_provider = 'dummy'
journal_form.bank_statements_source = "online"
journal_form.online_bank_statement_provider = "dummy"
journal_form.save()
self.assertTrue(journal.online_bank_statement_provider_id)
with common.Form(journal) as journal_form:
journal_form.bank_statements_source = 'undefined'
journal_form.bank_statements_source = "undefined"
journal_form.save()
self.assertFalse(journal.online_bank_statement_provider_id)
self.assertFalse(self.OnlineBankStatementProvider.search([]))
def test_pull_mode_daily(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
'bank_statements_source': 'online',
'online_bank_statement_provider': 'dummy',
})
journal = self.AccountJournal.create(
{
"name": "Bank",
"type": "bank",
"code": "BANK",
"bank_statements_source": "online",
"online_bank_statement_provider": "dummy",
}
)
provider = journal.online_bank_statement_provider_id
provider.active = True
provider.statement_creation_mode = 'daily'
provider.statement_creation_mode = "daily"
provider.with_context(step={'hours': 2})._pull(
self.now - relativedelta(days=1),
self.now,
provider.with_context(step={"hours": 2})._pull(
self.now - relativedelta(days=1), self.now,
)
self.assertEqual(
len(self.AccountBankStatement.search(
[('journal_id', '=', journal.id)]
)),
2
len(self.AccountBankStatement.search([("journal_id", "=", journal.id)])), 2
)
def test_pull_mode_weekly(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
'bank_statements_source': 'online',
'online_bank_statement_provider': 'dummy',
})
journal = self.AccountJournal.create(
{
"name": "Bank",
"type": "bank",
"code": "BANK",
"bank_statements_source": "online",
"online_bank_statement_provider": "dummy",
}
)
provider = journal.online_bank_statement_provider_id
provider.active = True
provider.statement_creation_mode = 'weekly'
provider.statement_creation_mode = "weekly"
provider.with_context(step={'hours': 8})._pull(
self.now - relativedelta(weeks=1),
self.now,
provider.with_context(step={"hours": 8})._pull(
self.now - relativedelta(weeks=1), self.now,
)
self.assertEqual(
len(self.AccountBankStatement.search(
[('journal_id', '=', journal.id)]
)),
2
len(self.AccountBankStatement.search([("journal_id", "=", journal.id)])), 2
)
def test_pull_mode_monthly(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
'bank_statements_source': 'online',
'online_bank_statement_provider': 'dummy',
})
journal = self.AccountJournal.create(
{
"name": "Bank",
"type": "bank",
"code": "BANK",
"bank_statements_source": "online",
"online_bank_statement_provider": "dummy",
}
)
provider = journal.online_bank_statement_provider_id
provider.active = True
provider.statement_creation_mode = 'monthly'
provider.statement_creation_mode = "monthly"
provider.with_context(step={'hours': 8})._pull(
self.now - relativedelta(months=1),
self.now,
provider.with_context(step={"hours": 8})._pull(
self.now - relativedelta(months=1), self.now,
)
self.assertEqual(
len(self.AccountBankStatement.search(
[('journal_id', '=', journal.id)]
)),
2
len(self.AccountBankStatement.search([("journal_id", "=", journal.id)])), 2
)
def test_pull_scheduled(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
'bank_statements_source': 'online',
'online_bank_statement_provider': 'dummy',
})
journal = self.AccountJournal.create(
{
"name": "Bank",
"type": "bank",
"code": "BANK",
"bank_statements_source": "online",
"online_bank_statement_provider": "dummy",
}
)
provider = journal.online_bank_statement_provider_id
provider.active = True
provider.next_run = (
self.now - relativedelta(days=15)
provider.next_run = self.now - relativedelta(days=15)
self.assertFalse(
self.AccountBankStatement.search([("journal_id", "=", journal.id)])
)
self.assertFalse(self.AccountBankStatement.search(
[('journal_id', '=', journal.id)],
))
provider.with_context(step={"hours": 8})._scheduled_pull()
provider.with_context(step={'hours': 8})._scheduled_pull()
statement = self.AccountBankStatement.search(
[('journal_id', '=', journal.id)],
)
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id)])
self.assertEqual(len(statement), 1)
def test_pull_skip_duplicates_by_unique_import_id(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
'bank_statements_source': 'online',
'online_bank_statement_provider': 'dummy',
})
journal = self.AccountJournal.create(
{
"name": "Bank",
"type": "bank",
"code": "BANK",
"bank_statements_source": "online",
"online_bank_statement_provider": "dummy",
}
)
provider = journal.online_bank_statement_provider_id
provider.active = True
provider.statement_creation_mode = 'weekly'
provider.statement_creation_mode = "weekly"
provider.with_context(
step={'hours': 8},
step={"hours": 8},
data_since=self.now - relativedelta(weeks=2),
data_until=self.now,
)._pull(
self.now - relativedelta(weeks=2),
self.now,
self.now - relativedelta(weeks=2), self.now,
)
self.assertEqual(
len(self.AccountBankStatementLine.search(
[('journal_id', '=', journal.id)]
)),
14 * (24 / 8)
len(
self.AccountBankStatementLine.search([("journal_id", "=", journal.id)])
),
14 * (24 / 8),
)
provider.with_context(
step={'hours': 8},
step={"hours": 8},
data_since=self.now - relativedelta(weeks=3),
data_until=self.now - relativedelta(weeks=1),
)._pull(
self.now - relativedelta(weeks=3),
self.now - relativedelta(weeks=1),
self.now - relativedelta(weeks=3), self.now - relativedelta(weeks=1),
)
self.assertEqual(
len(self.AccountBankStatementLine.search(
[('journal_id', '=', journal.id)]
)),
21 * (24 / 8)
len(
self.AccountBankStatementLine.search([("journal_id", "=", journal.id)])
),
21 * (24 / 8),
)
provider.with_context(
step={'hours': 8},
step={"hours": 8},
data_since=self.now - relativedelta(weeks=1),
data_until=self.now,
)._pull(
self.now - relativedelta(weeks=1),
self.now,
self.now - relativedelta(weeks=1), self.now,
)
self.assertEqual(
len(self.AccountBankStatementLine.search(
[('journal_id', '=', journal.id)]
)),
21 * (24 / 8)
len(
self.AccountBankStatementLine.search([("journal_id", "=", journal.id)])
),
21 * (24 / 8),
)
def test_interval_type_minutes(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
'bank_statements_source': 'online',
'online_bank_statement_provider': 'dummy',
})
journal = self.AccountJournal.create(
{
"name": "Bank",
"type": "bank",
"code": "BANK",
"bank_statements_source": "online",
"online_bank_statement_provider": "dummy",
}
)
provider = journal.online_bank_statement_provider_id
provider.active = True
provider.interval_type = 'minutes'
provider.interval_type = "minutes"
provider._compute_update_schedule()
def test_interval_type_hours(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
'bank_statements_source': 'online',
'online_bank_statement_provider': 'dummy',
})
journal = self.AccountJournal.create(
{
"name": "Bank",
"type": "bank",
"code": "BANK",
"bank_statements_source": "online",
"online_bank_statement_provider": "dummy",
}
)
provider = journal.online_bank_statement_provider_id
provider.active = True
provider.interval_type = 'hours'
provider.interval_type = "hours"
provider._compute_update_schedule()
def test_interval_type_days(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
'bank_statements_source': 'online',
'online_bank_statement_provider': 'dummy',
})
journal = self.AccountJournal.create(
{
"name": "Bank",
"type": "bank",
"code": "BANK",
"bank_statements_source": "online",
"online_bank_statement_provider": "dummy",
}
)
provider = journal.online_bank_statement_provider_id
provider.active = True
provider.interval_type = 'days'
provider.interval_type = "days"
provider._compute_update_schedule()
def test_interval_type_weeks(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
'bank_statements_source': 'online',
'online_bank_statement_provider': 'dummy',
})
journal = self.AccountJournal.create(
{
"name": "Bank",
"type": "bank",
"code": "BANK",
"bank_statements_source": "online",
"online_bank_statement_provider": "dummy",
}
)
provider = journal.online_bank_statement_provider_id
provider.active = True
provider.interval_type = 'weeks'
provider.interval_type = "weeks"
provider._compute_update_schedule()
def test_pull_no_crash(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
'bank_statements_source': 'online',
'online_bank_statement_provider': 'dummy',
})
journal = self.AccountJournal.create(
{
"name": "Bank",
"type": "bank",
"code": "BANK",
"bank_statements_source": "online",
"online_bank_statement_provider": "dummy",
}
)
provider = journal.online_bank_statement_provider_id
provider.active = True
provider.statement_creation_mode = 'weekly'
provider.statement_creation_mode = "weekly"
provider.with_context(
crash=True,
scheduled=True,
)._pull(
self.now - relativedelta(hours=1),
self.now,
provider.with_context(crash=True, scheduled=True)._pull(
self.now - relativedelta(hours=1), self.now,
)
self.assertFalse(
self.AccountBankStatement.search([("journal_id", "=", journal.id)])
)
self.assertFalse(self.AccountBankStatement.search(
[('journal_id', '=', journal.id)],
))
def test_pull_crash(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
'bank_statements_source': 'online',
'online_bank_statement_provider': 'dummy',
})
journal = self.AccountJournal.create(
{
"name": "Bank",
"type": "bank",
"code": "BANK",
"bank_statements_source": "online",
"online_bank_statement_provider": "dummy",
}
)
provider = journal.online_bank_statement_provider_id
provider.active = True
provider.statement_creation_mode = 'weekly'
provider.statement_creation_mode = "weekly"
with self.assertRaises(Exception):
provider.with_context(
crash=True,
)._pull(
self.now - relativedelta(hours=1),
self.now,
provider.with_context(crash=True)._pull(
self.now - relativedelta(hours=1), self.now,
)
def test_pull_httperror(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
'bank_statements_source': 'online',
'online_bank_statement_provider': 'dummy',
})
journal = self.AccountJournal.create(
{
"name": "Bank",
"type": "bank",
"code": "BANK",
"bank_statements_source": "online",
"online_bank_statement_provider": "dummy",
}
)
provider = journal.online_bank_statement_provider_id
provider.active = True
provider.statement_creation_mode = 'weekly'
provider.statement_creation_mode = "weekly"
with self.assertRaises(HTTPError):
provider.with_context(
crash=True,
exception=HTTPError(None, 500, 'Error', None, None),
crash=True, exception=HTTPError(None, 500, "Error", None, None),
)._pull(
self.now - relativedelta(hours=1),
self.now,
self.now - relativedelta(hours=1), self.now,
)
def test_pull_no_balance(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
'bank_statements_source': 'online',
'online_bank_statement_provider': 'dummy',
})
journal = self.AccountJournal.create(
{
"name": "Bank",
"type": "bank",
"code": "BANK",
"bank_statements_source": "online",
"online_bank_statement_provider": "dummy",
}
)
provider = journal.online_bank_statement_provider_id
provider.active = True
provider.statement_creation_mode = 'daily'
provider.statement_creation_mode = "daily"
provider.with_context(
step={'hours': 2},
balance_start=0,
amount=100.0,
balance=False,
step={"hours": 2}, balance_start=0, amount=100.0, balance=False,
)._pull(
self.now - relativedelta(days=1),
self.now,
self.now - relativedelta(days=1), self.now,
)
statements = self.AccountBankStatement.search(
[('journal_id', '=', journal.id)],
order='date asc',
[("journal_id", "=", journal.id)], order="date asc",
)
self.assertFalse(statements[0].balance_start)
self.assertFalse(statements[0].balance_end_real)
@@ -389,74 +374,71 @@ class TestAccountBankAccountStatementImportOnline(common.TransactionCase):
self.assertFalse(statements[1].balance_end_real)
def test_wizard(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
'bank_statements_source': 'online',
'online_bank_statement_provider': 'dummy',
})
journal = self.AccountJournal.create(
{
"name": "Bank",
"type": "bank",
"code": "BANK",
"bank_statements_source": "online",
"online_bank_statement_provider": "dummy",
}
)
action = journal.action_online_bank_statements_pull_wizard()
self.assertTrue(action['context']['default_provider_ids'][0][2])
self.assertTrue(action["context"]["default_provider_ids"][0][2])
wizard = self.OnlineBankStatementPullWizard.with_context(
action['context']
).create({
'date_since': self.now - relativedelta(hours=1),
'date_until': self.now,
})
action["context"]
).create(
{"date_since": self.now - relativedelta(hours=1), "date_until": self.now}
)
self.assertTrue(wizard.provider_ids)
wizard.action_pull()
self.assertTrue(self.AccountBankStatement.search(
[('journal_id', '=', journal.id)],
))
self.assertTrue(
self.AccountBankStatement.search([("journal_id", "=", journal.id)])
)
def test_pull_statement_partially(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
'bank_statements_source': 'online',
'online_bank_statement_provider': 'dummy',
})
journal = self.AccountJournal.create(
{
"name": "Bank",
"type": "bank",
"code": "BANK",
"bank_statements_source": "online",
"online_bank_statement_provider": "dummy",
}
)
provider = journal.online_bank_statement_provider_id
provider.active = True
provider.statement_creation_mode = 'monthly'
provider.statement_creation_mode = "monthly"
provider_context = {
'step': {'hours': 24},
'data_since': datetime(2020, 1, 1),
'amount': 1.0,
'balance_start': 0,
"step": {"hours": 24},
"data_since": datetime(2020, 1, 1),
"amount": 1.0,
"balance_start": 0,
}
provider.with_context(
**provider_context,
data_until=datetime(2020, 1, 31),
**provider_context, data_until=datetime(2020, 1, 31),
)._pull(
datetime(2020, 1, 1),
datetime(2020, 1, 31),
datetime(2020, 1, 1), datetime(2020, 1, 31),
)
statements = self.AccountBankStatement.search(
[('journal_id', '=', journal.id)],
order='date asc',
[("journal_id", "=", journal.id)], order="date asc",
)
self.assertEqual(len(statements), 1)
self.assertEqual(statements[0].balance_start, 0.0)
self.assertEqual(statements[0].balance_end_real, 30.0)
provider.with_context(
**provider_context,
data_until=datetime(2020, 2, 15),
**provider_context, data_until=datetime(2020, 2, 15),
)._pull(
datetime(2020, 1, 1),
datetime(2020, 2, 29),
datetime(2020, 1, 1), datetime(2020, 2, 29),
)
statements = self.AccountBankStatement.search(
[('journal_id', '=', journal.id)],
order='date asc',
[("journal_id", "=", journal.id)], order="date asc",
)
self.assertEqual(len(statements), 2)
self.assertEqual(statements[0].balance_start, 0.0)
@@ -465,15 +447,12 @@ class TestAccountBankAccountStatementImportOnline(common.TransactionCase):
self.assertEqual(statements[1].balance_end_real, 45.0)
provider.with_context(
**provider_context,
data_until=datetime(2020, 2, 29),
**provider_context, data_until=datetime(2020, 2, 29),
)._pull(
datetime(2020, 1, 1),
datetime(2020, 2, 29),
datetime(2020, 1, 1), datetime(2020, 2, 29),
)
statements = self.AccountBankStatement.search(
[('journal_id', '=', journal.id)],
order='date asc',
[("journal_id", "=", journal.id)], order="date asc",
)
self.assertEqual(len(statements), 2)
self.assertEqual(statements[0].balance_start, 0.0)
@@ -482,33 +461,32 @@ class TestAccountBankAccountStatementImportOnline(common.TransactionCase):
self.assertEqual(statements[1].balance_end_real, 59.0)
def test_tz_utc(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
'bank_statements_source': 'online',
'online_bank_statement_provider': 'dummy',
})
journal = self.AccountJournal.create(
{
"name": "Bank",
"type": "bank",
"code": "BANK",
"bank_statements_source": "online",
"online_bank_statement_provider": "dummy",
}
)
provider = journal.online_bank_statement_provider_id
provider.active = True
provider.tz = 'UTC'
provider.tz = "UTC"
provider.with_context(
step={'hours': 1},
step={"hours": 1},
data_since=datetime(2020, 4, 17, 22, 0),
data_until=datetime(2020, 4, 18, 2, 0),
tz='UTC',
tz="UTC",
)._pull(
datetime(2020, 4, 17, 22, 0),
datetime(2020, 4, 18, 2, 0),
datetime(2020, 4, 17, 22, 0), datetime(2020, 4, 18, 2, 0),
)
statement = self.AccountBankStatement.search(
[('journal_id', '=', journal.id)],
)
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id)])
self.assertEqual(len(statement), 2)
lines = statement.mapped('line_ids').sorted()
lines = statement.mapped("line_ids").sorted()
self.assertEqual(len(lines), 4)
self.assertEqual(lines[0].date, date(2020, 4, 17))
self.assertEqual(lines[1].date, date(2020, 4, 17))
@@ -516,33 +494,32 @@ class TestAccountBankAccountStatementImportOnline(common.TransactionCase):
self.assertEqual(lines[3].date, date(2020, 4, 18))
def test_tz_non_utc(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
'bank_statements_source': 'online',
'online_bank_statement_provider': 'dummy',
})
journal = self.AccountJournal.create(
{
"name": "Bank",
"type": "bank",
"code": "BANK",
"bank_statements_source": "online",
"online_bank_statement_provider": "dummy",
}
)
provider = journal.online_bank_statement_provider_id
provider.active = True
provider.tz = 'Etc/GMT-2'
provider.tz = "Etc/GMT-2"
provider.with_context(
step={'hours': 1},
step={"hours": 1},
data_since=datetime(2020, 4, 17, 22, 0),
data_until=datetime(2020, 4, 18, 2, 0),
tz='UTC',
tz="UTC",
)._pull(
datetime(2020, 4, 17, 22, 0),
datetime(2020, 4, 18, 2, 0),
datetime(2020, 4, 17, 22, 0), datetime(2020, 4, 18, 2, 0),
)
statement = self.AccountBankStatement.search(
[('journal_id', '=', journal.id)],
)
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id)])
self.assertEqual(len(statement), 2)
lines = statement.mapped('line_ids').sorted()
lines = statement.mapped("line_ids").sorted()
self.assertEqual(len(lines), 4)
self.assertEqual(lines[0].date, date(2020, 4, 18))
self.assertEqual(lines[1].date, date(2020, 4, 18))
@@ -550,32 +527,31 @@ class TestAccountBankAccountStatementImportOnline(common.TransactionCase):
self.assertEqual(lines[3].date, date(2020, 4, 18))
def test_other_tz_to_utc(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
'bank_statements_source': 'online',
'online_bank_statement_provider': 'dummy',
})
journal = self.AccountJournal.create(
{
"name": "Bank",
"type": "bank",
"code": "BANK",
"bank_statements_source": "online",
"online_bank_statement_provider": "dummy",
}
)
provider = journal.online_bank_statement_provider_id
provider.active = True
provider.with_context(
step={'hours': 1},
tz='Etc/GMT-2',
step={"hours": 1},
tz="Etc/GMT-2",
data_since=datetime(2020, 4, 18, 0, 0),
data_until=datetime(2020, 4, 18, 4, 0),
)._pull(
datetime(2020, 4, 17, 22, 0),
datetime(2020, 4, 18, 2, 0),
datetime(2020, 4, 17, 22, 0), datetime(2020, 4, 18, 2, 0),
)
statement = self.AccountBankStatement.search(
[('journal_id', '=', journal.id)],
)
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id)])
self.assertEqual(len(statement), 2)
lines = statement.mapped('line_ids').sorted()
lines = statement.mapped("line_ids").sorted()
self.assertEqual(len(lines), 4)
self.assertEqual(lines[0].date, date(2020, 4, 17))
self.assertEqual(lines[1].date, date(2020, 4, 17))
@@ -583,27 +559,23 @@ class TestAccountBankAccountStatementImportOnline(common.TransactionCase):
self.assertEqual(lines[3].date, date(2020, 4, 18))
def test_timestamp_date_only_date(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
'bank_statements_source': 'online',
'online_bank_statement_provider': 'dummy',
})
journal = self.AccountJournal.create(
{
"name": "Bank",
"type": "bank",
"code": "BANK",
"bank_statements_source": "online",
"online_bank_statement_provider": "dummy",
}
)
provider = journal.online_bank_statement_provider_id
provider.active = True
provider.with_context(
step={'hours': 1},
timestamp_mode='date',
)._pull(
datetime(2020, 4, 18, 0, 0),
datetime(2020, 4, 18, 4, 0),
provider.with_context(step={"hours": 1}, timestamp_mode="date")._pull(
datetime(2020, 4, 18, 0, 0), datetime(2020, 4, 18, 4, 0),
)
statement = self.AccountBankStatement.search(
[('journal_id', '=', journal.id)],
)
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id)])
self.assertEqual(len(statement), 1)
lines = statement.line_ids
@@ -612,29 +584,28 @@ class TestAccountBankAccountStatementImportOnline(common.TransactionCase):
self.assertEqual(line.date, date(2020, 4, 18))
def test_timestamp_date_only_str(self):
journal = self.AccountJournal.create({
'name': 'Bank',
'type': 'bank',
'code': 'BANK',
'bank_statements_source': 'online',
'online_bank_statement_provider': 'dummy',
})
journal = self.AccountJournal.create(
{
"name": "Bank",
"type": "bank",
"code": "BANK",
"bank_statements_source": "online",
"online_bank_statement_provider": "dummy",
}
)
provider = journal.online_bank_statement_provider_id
provider.active = True
provider.with_context(
step={'hours': 1},
step={"hours": 1},
data_since=datetime(2020, 4, 18, 0, 0),
data_until=datetime(2020, 4, 18, 4, 0),
timestamp_mode='str',
timestamp_mode="str",
)._pull(
datetime(2020, 4, 18, 0, 0),
datetime(2020, 4, 18, 4, 0),
datetime(2020, 4, 18, 0, 0), datetime(2020, 4, 18, 4, 0),
)
statement = self.AccountBankStatement.search(
[('journal_id', '=', journal.id)],
)
statement = self.AccountBankStatement.search([("journal_id", "=", journal.id)])
self.assertEqual(len(statement), 1)
lines = statement.line_ids

View File

@@ -5,7 +5,6 @@
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
-->
<odoo>
<record model="ir.ui.view" id="view_account_journal_form">
<field name="name">account.journal.form</field>
<field name="model">account.journal</field>
@@ -50,7 +49,6 @@
</page>
</field>
</record>
<record model="ir.ui.view" id="view_account_bank_journal_form">
<field name="name">account.journal.form</field>
<field name="model">account.journal</field>
@@ -95,24 +93,31 @@
</group>
</field>
</record>
<record id="journal_dashboard_view_inherit" model="ir.ui.view">
<field name="name">account.journal.dashboard.kanban</field>
<field name="model">account.journal</field>
<field name="inherit_id" ref="account_bank_statement_import.journal_dashboard_view_inherit"/>
<field
name="inherit_id"
ref="account_bank_statement_import.journal_dashboard_view_inherit"
/>
<field name="arch" type="xml">
<div name="bank_statement_create_button" position="attributes">
<attribute name="t-if">dashboard.bank_statements_source != 'online_sync' and dashboard.bank_statements_source != 'online'</attribute>
<attribute
name="t-if"
>dashboard.bank_statements_source != 'online_sync' and dashboard.bank_statements_source != 'online'</attribute>
</div>
<xpath expr="//a[@name='create_bank_statement']" position="attributes">
<attribute name="t-if">dashboard.bank_statements_source != 'online_sync' and dashboard.bank_statements_source != 'online'</attribute>
<attribute
name="t-if"
>dashboard.bank_statements_source != 'online_sync' and dashboard.bank_statements_source != 'online'</attribute>
</xpath>
<xpath expr="//a[@name='import_statement']" position="attributes">
<attribute name="t-if">dashboard.bank_statements_source != 'online_sync' and dashboard.bank_statements_source != 'online'</attribute>
<attribute
name="t-if"
>dashboard.bank_statements_source != 'online_sync' and dashboard.bank_statements_source != 'online'</attribute>
</xpath>
</field>
</record>
<record id="action_online_bank_statements_pull_wizard" model="ir.actions.server">
<field name="name">Online Bank Statements Pull Wizard</field>
<field name="type">ir.actions.server</field>
@@ -124,5 +129,4 @@
action = records.action_online_bank_statements_pull_wizard()
</field>
</record>
</odoo>

View File

@@ -5,17 +5,19 @@
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
-->
<odoo>
<record model="ir.ui.view" id="online_bank_statement_provider_filter">
<field name="name">online.bank.statement.provider.filter</field>
<field name="model">online.bank.statement.provider</field>
<field name="arch" type="xml">
<search string="Online Bank Statement Providers">
<filter name="active" string="Inactive" domain="[('active', '=', False)]"/>
<filter
name="active"
string="Inactive"
domain="[('active', '=', False)]"
/>
</search>
</field>
</record>
<record model="ir.ui.view" id="online_bank_statement_provider_tree">
<field name="name">online.bank.statement.provider.tree</field>
<field name="model">online.bank.statement.provider</field>
@@ -30,7 +32,6 @@
</tree>
</field>
</record>
<record model="ir.ui.view" id="online_bank_statement_provider_form">
<field name="name">online.bank.statement.provider.form</field>
<field name="model">online.bank.statement.provider</field>
@@ -38,8 +39,17 @@
<form string="Online Bank Statement Provider">
<sheet>
<div class="oe_button_box" name="button_box">
<button class="oe_stat_button" type="object" name="toggle_active" icon="fa-archive">
<field name="active" widget="boolean_button" options='{"terminology": "active"}'/>
<button
class="oe_stat_button"
type="object"
name="toggle_active"
icon="fa-archive"
>
<field
name="active"
widget="boolean_button"
options='{"terminology": "active"}'
/>
</button>
</div>
<notebook>
@@ -93,5 +103,4 @@
</form>
</field>
</record>
</odoo>

View File

@@ -2,38 +2,31 @@
# Copyright 2019-2020 Dataplug (https://dataplug.io)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import fields, models, api
from odoo import api, fields, models
class OnlineBankStatementPullWizard(models.TransientModel):
_name = 'online.bank.statement.pull.wizard'
_description = 'Online Bank Statement Pull Wizard'
_name = "online.bank.statement.pull.wizard"
_description = "Online Bank Statement Pull Wizard"
date_since = fields.Datetime(
string='Since',
required=True,
default=fields.Datetime.now,
string="Since", required=True, default=fields.Datetime.now,
)
date_until = fields.Datetime(
string='Until',
required=True,
default=fields.Datetime.now,
string="Until", required=True, default=fields.Datetime.now,
)
provider_ids = fields.Many2many(
string='Providers',
comodel_name='online.bank.statement.provider',
column1='wizard_id',
column2='provider_id',
relation='online_bank_statement_provider_pull_wizard_rel',
string="Providers",
comodel_name="online.bank.statement.provider",
column1="wizard_id",
column2="provider_id",
relation="online_bank_statement_provider_pull_wizard_rel",
)
@api.multi
def action_pull(self):
self.ensure_one()
self.with_context(
active_test=False,
).provider_ids._pull(
self.date_since,
self.date_until
self.with_context(active_test=False,).provider_ids._pull(
self.date_since, self.date_until
)
return {'type': 'ir.actions.act_window_close'}
return {"type": "ir.actions.act_window_close"}

View File

@@ -5,7 +5,6 @@
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="online_bank_statement_pull_wizard_form" model="ir.ui.view">
<field name="name">online.bank.statement.pull.wizard.form</field>
<field name="model">online.bank.statement.pull.wizard</field>
@@ -23,11 +22,16 @@
</group>
</group>
<footer>
<button name="action_pull" string="Pull" type="object" default_focus="1" class="oe_highlight"/>
<button
name="action_pull"
string="Pull"
type="object"
default_focus="1"
class="oe_highlight"
/>
<button string="Cancel" class="oe_link" special="cancel" />
</footer>
</form>
</field>
</record>
</odoo>

View File

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

View File

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