[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). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{ {
'name': 'Online Bank Statements', "name": "Online Bank Statements",
'version': '12.0.1.4.1', "version": "12.0.1.4.1",
'author': "author": "Brainbean Apps, Dataplug, Odoo Community Association (OCA)",
'Brainbean Apps, ' "maintainers": ["alexey-pelykh"],
'Dataplug, ' "website": "https://github.com/OCA/bank-statement-import/",
'Odoo Community Association (OCA)', "license": "AGPL-3",
'maintainers': ['alexey-pelykh'], "category": "Accounting",
'website': 'https://github.com/OCA/bank-statement-import/', "summary": "Online bank statements update",
'license': 'AGPL-3', "depends": [
'category': 'Accounting', "account",
'summary': 'Online bank statements update', "account_bank_statement_import",
'depends': [ "web_widget_dropdown_dynamic",
'account',
'account_bank_statement_import',
'web_widget_dropdown_dynamic',
], ],
'data': [ "data": [
'data/account_bank_statement_import_online.xml', "data/account_bank_statement_import_online.xml",
'security/ir.model.access.csv', "security/ir.model.access.csv",
'security/online_bank_statement_provider.xml', "security/online_bank_statement_provider.xml",
'views/account_journal.xml', "views/account_journal.xml",
'views/online_bank_statement_provider.xml', "views/online_bank_statement_provider.xml",
'wizards/online_bank_statement_pull_wizard.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). License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
--> -->
<odoo noupdate="1"> <odoo noupdate="1">
<record model="ir.cron" id="ir_cron_account_pull_online_bank_statements"> <record model="ir.cron" id="ir_cron_account_pull_online_bank_statements">
<field name="name">Pull Online Bank Statements</field> <field name="name">Pull Online Bank Statements</field>
<field name="interval_number">1</field> <field name="interval_number">1</field>
@@ -13,9 +12,11 @@
<field name="numbercall">-1</field> <field name="numbercall">-1</field>
<field name="state">code</field> <field name="state">code</field>
<field name="nextcall">2019-01-01 00:10:00</field> <field name="nextcall">2019-01-01 00:10:00</field>
<field name="doall" eval="False"/> <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> <field name="code">model._scheduled_pull()</field>
</record> </record>
</odoo> </odoo>

View File

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

View File

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

View File

@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- <!--
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
Copyright 2019 Brainbean Apps (https://brainbeanapps.com) Copyright 2019 Brainbean Apps (https://brainbeanapps.com)
Copyright 2019 Dataplug (https://dataplug.io) Copyright 2019 Dataplug (https://dataplug.io)
--> -->
<odoo noupdate="1"> <odoo noupdate="1">
<record id="online_bank_statement_provider_multicompany" model="ir.rule"> <record id="online_bank_statement_provider_multicompany" model="ir.rule">
<field name="name">Online Bank Statement Provider multi-company</field> <field name="name">Online Bank Statement Provider multi-company</field>
<field name="model_id" ref="model_online_bank_statement_provider"/> <field name="model_id" ref="model_online_bank_statement_provider" />
<field eval="True" name="global"/> <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> </record>
</odoo> </odoo>

View File

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

View File

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

View File

@@ -1,15 +1,14 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- <!--
Copyright 2019-2020 Brainbean Apps (https://brainbeanapps.com) Copyright 2019-2020 Brainbean Apps (https://brainbeanapps.com)
Copyright 2019-2020 Dataplug (https://dataplug.io) Copyright 2019-2020 Dataplug (https://dataplug.io)
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
--> -->
<odoo> <odoo>
<record model="ir.ui.view" id="view_account_journal_form"> <record model="ir.ui.view" id="view_account_journal_form">
<field name="name">account.journal.form</field> <field name="name">account.journal.form</field>
<field name="model">account.journal</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="arch" type="xml">
<page name="bank_account"> <page name="bank_account">
<group <group
@@ -50,11 +49,10 @@
</page> </page>
</field> </field>
</record> </record>
<record model="ir.ui.view" id="view_account_bank_journal_form"> <record model="ir.ui.view" id="view_account_bank_journal_form">
<field name="name">account.journal.form</field> <field name="name">account.journal.form</field>
<field name="model">account.journal</field> <field name="model">account.journal</field>
<field name="inherit_id" ref="account.view_account_bank_journal_form"/> <field name="inherit_id" ref="account.view_account_bank_journal_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<group name="bank_statement" position="after"> <group name="bank_statement" position="after">
<group <group
@@ -95,34 +93,40 @@
</group> </group>
</field> </field>
</record> </record>
<record id="journal_dashboard_view_inherit" model="ir.ui.view"> <record id="journal_dashboard_view_inherit" model="ir.ui.view">
<field name="name">account.journal.dashboard.kanban</field> <field name="name">account.journal.dashboard.kanban</field>
<field name="model">account.journal</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"> <field name="arch" type="xml">
<div name="bank_statement_create_button" position="attributes"> <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> </div>
<xpath expr="//a[@name='create_bank_statement']" position="attributes"> <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>
<xpath expr="//a[@name='import_statement']" position="attributes"> <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> </xpath>
</field> </field>
</record> </record>
<record id="action_online_bank_statements_pull_wizard" model="ir.actions.server"> <record id="action_online_bank_statements_pull_wizard" model="ir.actions.server">
<field name="name">Online Bank Statements Pull Wizard</field> <field name="name">Online Bank Statements Pull Wizard</field>
<field name="type">ir.actions.server</field> <field name="type">ir.actions.server</field>
<field name="model_id" ref="account.model_account_journal"/> <field name="model_id" ref="account.model_account_journal" />
<field name="binding_model_id" ref="account.model_account_journal"/> <field name="binding_model_id" ref="account.model_account_journal" />
<field name="state">code</field> <field name="state">code</field>
<field name="code"> <field name="code">
if records: if records:
action = records.action_online_bank_statements_pull_wizard() action = records.action_online_bank_statements_pull_wizard()
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -1,36 +1,37 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8" ?>
<!-- <!--
Copyright 2019 Brainbean Apps (https://brainbeanapps.com) Copyright 2019 Brainbean Apps (https://brainbeanapps.com)
Copyright 2019 Dataplug (https://dataplug.io) Copyright 2019 Dataplug (https://dataplug.io)
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
--> -->
<odoo> <odoo>
<record model="ir.ui.view" id="online_bank_statement_provider_filter"> <record model="ir.ui.view" id="online_bank_statement_provider_filter">
<field name="name">online.bank.statement.provider.filter</field> <field name="name">online.bank.statement.provider.filter</field>
<field name="model">online.bank.statement.provider</field> <field name="model">online.bank.statement.provider</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="Online Bank Statement Providers"> <search string="Online Bank Statement Providers">
<filter name="active" string="Inactive" domain="[('active', '=', False)]"/> <filter
name="active"
string="Inactive"
domain="[('active', '=', False)]"
/>
</search> </search>
</field> </field>
</record> </record>
<record model="ir.ui.view" id="online_bank_statement_provider_tree"> <record model="ir.ui.view" id="online_bank_statement_provider_tree">
<field name="name">online.bank.statement.provider.tree</field> <field name="name">online.bank.statement.provider.tree</field>
<field name="model">online.bank.statement.provider</field> <field name="model">online.bank.statement.provider</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree> <tree>
<field name="journal_id"/> <field name="journal_id" />
<field name="company_id" groups="base.group_multi_company"/> <field name="company_id" groups="base.group_multi_company" />
<field name="service"/> <field name="service" />
<field name="currency_id"/> <field name="currency_id" />
<field name="update_schedule"/> <field name="update_schedule" />
<field name="next_run"/> <field name="next_run" />
</tree> </tree>
</field> </field>
</record> </record>
<record model="ir.ui.view" id="online_bank_statement_provider_form"> <record model="ir.ui.view" id="online_bank_statement_provider_form">
<field name="name">online.bank.statement.provider.form</field> <field name="name">online.bank.statement.provider.form</field>
<field name="model">online.bank.statement.provider</field> <field name="model">online.bank.statement.provider</field>
@@ -38,20 +39,29 @@
<form string="Online Bank Statement Provider"> <form string="Online Bank Statement Provider">
<sheet> <sheet>
<div class="oe_button_box" name="button_box"> <div class="oe_button_box" name="button_box">
<button class="oe_stat_button" type="object" name="toggle_active" icon="fa-archive"> <button
<field name="active" widget="boolean_button" options='{"terminology": "active"}'/> class="oe_stat_button"
type="object"
name="toggle_active"
icon="fa-archive"
>
<field
name="active"
widget="boolean_button"
options='{"terminology": "active"}'
/>
</button> </button>
</div> </div>
<notebook> <notebook>
<page name="details" string="Details"> <page name="details" string="Details">
<group> <group>
<group groups="base.group_multi_company"> <group groups="base.group_multi_company">
<field name="company_id"/> <field name="company_id" />
</group> </group>
<group> <group>
<field name="journal_id"/> <field name="journal_id" />
<field name="currency_id"/> <field name="currency_id" />
<field name="account_number"/> <field name="account_number" />
</group> </group>
<group> <group>
<field <field
@@ -65,33 +75,32 @@
<page name="pull" string="Scheduled Pull"> <page name="pull" string="Scheduled Pull">
<group> <group>
<group> <group>
<label for="interval_number"/> <label for="interval_number" />
<div class="o_row"> <div class="o_row">
<field name="interval_number" class="ml8"/> <field name="interval_number" class="ml8" />
<field name="interval_type"/> <field name="interval_type" />
</div> </div>
</group> </group>
<group> <group>
<field name="next_run"/> <field name="next_run" />
</group> </group>
</group> </group>
</page> </page>
<page name="configuration" string="Configuration"> <page name="configuration" string="Configuration">
<group> <group>
<group> <group>
<field name="statement_creation_mode"/> <field name="statement_creation_mode" />
<field name="tz"/> <field name="tz" />
</group> </group>
</group> </group>
</page> </page>
</notebook> </notebook>
</sheet> </sheet>
<div class="oe_chatter"> <div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/> <field name="message_follower_ids" widget="mail_followers" />
<field name="message_ids" widget="mail_thread"/> <field name="message_ids" widget="mail_thread" />
</div> </div>
</form> </form>
</field> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -2,38 +2,31 @@
# Copyright 2019-2020 Dataplug (https://dataplug.io) # Copyright 2019-2020 Dataplug (https://dataplug.io)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). # 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): class OnlineBankStatementPullWizard(models.TransientModel):
_name = 'online.bank.statement.pull.wizard' _name = "online.bank.statement.pull.wizard"
_description = 'Online Bank Statement Pull Wizard' _description = "Online Bank Statement Pull Wizard"
date_since = fields.Datetime( date_since = fields.Datetime(
string='Since', string="Since", required=True, default=fields.Datetime.now,
required=True,
default=fields.Datetime.now,
) )
date_until = fields.Datetime( date_until = fields.Datetime(
string='Until', string="Until", required=True, default=fields.Datetime.now,
required=True,
default=fields.Datetime.now,
) )
provider_ids = fields.Many2many( provider_ids = fields.Many2many(
string='Providers', string="Providers",
comodel_name='online.bank.statement.provider', comodel_name="online.bank.statement.provider",
column1='wizard_id', column1="wizard_id",
column2='provider_id', column2="provider_id",
relation='online_bank_statement_provider_pull_wizard_rel', relation="online_bank_statement_provider_pull_wizard_rel",
) )
@api.multi @api.multi
def action_pull(self): def action_pull(self):
self.ensure_one() self.ensure_one()
self.with_context( self.with_context(active_test=False,).provider_ids._pull(
active_test=False, self.date_since, self.date_until
).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,29 +5,33 @@
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
--> -->
<odoo> <odoo>
<record id="online_bank_statement_pull_wizard_form" model="ir.ui.view"> <record id="online_bank_statement_pull_wizard_form" model="ir.ui.view">
<field name="name">online.bank.statement.pull.wizard.form</field> <field name="name">online.bank.statement.pull.wizard.form</field>
<field name="model">online.bank.statement.pull.wizard</field> <field name="model">online.bank.statement.pull.wizard</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form> <form>
<field name="provider_ids" invisible="1"/> <field name="provider_ids" invisible="1" />
<group name="filter"> <group name="filter">
<group name="date_range" colspan="2"> <group name="date_range" colspan="2">
<group> <group>
<field name="date_since" string="Since (at least)"/> <field name="date_since" string="Since (at least)" />
</group> </group>
<group> <group>
<field name="date_until" string="Until (at least)"/> <field name="date_until" string="Until (at least)" />
</group> </group>
</group> </group>
</group> </group>
<footer> <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" /> <button string="Cancel" class="oe_link" special="cancel" />
</footer> </footer>
</form> </form>
</field> </field>
</record> </record>
</odoo> </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,
)