Merge pull request #83 from Noviat/17.0

Syncing from upstream Noviat/account_ebics (17.0)
This commit is contained in:
braintec
2026-04-18 01:12:34 +02:00
committed by GitHub
15 changed files with 263 additions and 155 deletions

View File

@@ -15,12 +15,12 @@ Available addons
----------------
addon | version | maintainers | summary
--- | --- | --- | ---
[account_ebics](account_ebics/) | 17.0.1.2.2 | | EBICS banking protocol
[account_ebics](account_ebics/) | 17.0.1.3.0 | | EBICS banking protocol
[account_ebics_batch](account_ebics_batch/) | 17.0.1.0.1 | | EBICS Files automated import and processing
[account_ebics_batch_payment](account_ebics_batch_payment/) | 17.0.1.0.3 | | Upload Batch Payment via EBICS
[account_ebics_batch_payment](account_ebics_batch_payment/) | 17.0.1.1.0 | | Upload Batch Payment via EBICS
[account_ebics_oca_statement_import](account_ebics_oca_statement_import/) | 17.0.1.0.1 | | Use OCA Bank Statement Import with account_ebics
[account_ebics_oe](account_ebics_oe/) | 17.0.1.0.0 | | Deploy account_ebics module on Odoo Enterprise
[account_ebics_payment_order](account_ebics_payment_order/) | 17.0.1.1.0 | | Upload Payment Order via EBICS
[account_ebics_payment_order](account_ebics_payment_order/) | 17.0.1.2.0 | | Upload Payment Order via EBICS
[//]: # (end addons)

View File

@@ -1,9 +1,9 @@
# Copyright 2009-2025 Noviat.
# Copyright 2015 Noviat.
# License LGPL-3 or later (https://www.gnu.org/licenses/lgpl).
{
"name": "EBICS banking protocol",
"version": "17.0.1.2.2",
"version": "17.0.1.3.0",
"license": "LGPL-3",
"author": "Noviat",
"website": "https://www.noviat.com/",

View File

@@ -1,5 +1,6 @@
from . import fintech_ebics_register
from . import account_bank_statement
from . import account_journal
from . import ebics_config
from . import ebics_file
from . import ebics_file_format

View File

@@ -0,0 +1,26 @@
# Copyright 2026 Noviat.
# License LGPL-3 or later (https://www.gnu.org/licenses/lgpl).
from odoo import api, fields, models
class AccountJournal(models.Model):
_inherit = "account.journal"
ebics_config_ids = fields.Many2many(
comodel_name="ebics.config",
relation="account_journal_ebics_config_rel",
readonly=True,
)
ebics_config_id = fields.Many2one(
comodel_name="ebics.config",
compute="_compute_ebics_config_id",
compute_sudo=True,
)
@api.depends("ebics_config_ids")
def _compute_ebics_config_id(self):
for rec in self:
rec.ebics_config_id = rec.ebics_config_ids.filtered(
lambda r: r.state == "confirm"
)[:1]

View File

@@ -120,7 +120,8 @@ class EbicsConfig(models.Model):
comodel_name="res.company",
relation="ebics_config_res_company_rel",
string="Companies",
readonly=True,
compute="_compute_company_ids",
store=True,
help="Companies sharing this EBICS contract.",
)
@@ -154,26 +155,10 @@ class EbicsConfig(models.Model):
)
)
def write(self, vals):
"""
Due to the multi-company nature of the EBICS config we
need to adapt the company_ids in the write method.
"""
if "journal_ids" not in vals:
return super().write(vals)
@api.depends("journal_ids.company_id")
def _compute_company_ids(self):
for rec in self:
old_company_ids = rec.journal_ids.mapped("company_id").ids
super(EbicsConfig, rec).write(vals)
new_company_ids = rec.journal_ids.mapped("company_id").ids
updates = []
for cid in new_company_ids:
if cid in old_company_ids:
old_company_ids.remove(cid)
else:
updates += [(4, cid)]
updates += [(3, x) for x in old_company_ids]
super(EbicsConfig, rec).write({"company_ids": updates})
return True
rec.company_ids = rec.journal_ids.mapped("company_id")
def unlink(self):
for ebics_config in self:

View File

@@ -82,4 +82,13 @@
sequence="30"
/>
<menuitem
id="ebics_xfer_menu_mark_as_downloaded"
name="Mark files as Downloaded"
parent="ebics_menu"
action="account_ebics.ebics_xfer_action_mark_as_downloaded"
groups="account_ebics.group_ebics_manager"
sequence="40"
/>
</odoo>

View File

@@ -237,8 +237,8 @@ class EbicsXfer(models.TransientModel):
date_from = self.date_from and self.date_from.isoformat() or None
date_to = self.date_to and self.date_to.isoformat() or None
for df in download_formats:
success = False
try:
success = False
if df.order_type == "BTD":
btf = BusinessTransactionFormat(
df.btf_service,
@@ -263,7 +263,8 @@ class EbicsXfer(models.TransientModel):
}
}
data = client.download(df.order_type, params=params)
ebics_files += self._handle_download_data(data, df)
if not self.env.context.get("ebics_mark_as_downloaded"):
ebics_files += self._handle_download_data(data, df)
success = True
except EbicsFunctionalError:
err_cnt += 1
@@ -321,8 +322,8 @@ class EbicsXfer(models.TransientModel):
order_type=df.order_type,
)
tb = "".join(format_exception(*exc_info()))
self.note += "\n%s" % tb
else:
self.note += f"\n{tb}"
finally:
# mark received data so that it is not included in further
# downloads
trans_id = client.last_trans_id

View File

@@ -1,136 +1,139 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="ebics_xfer_view_form_download" model="ir.ui.view">
<field name="name">EBICS File Download</field>
<field name="model">ebics.xfer</field>
<field name="priority">1</field>
<field name="arch" type="xml">
<form string="EBICS File Download">
<group>
<separator string="Select your bank :" colspan="2" />
<field
<record id="ebics_xfer_view_form_download" model="ir.ui.view">
<field name="name">EBICS File Download</field>
<field name="model">ebics.xfer</field>
<field name="priority">1</field>
<field name="arch" type="xml">
<form string="EBICS File Download">
<group>
<separator string="Select your bank :" colspan="2" />
<field
name="ebics_config_id"
required="1"
options="{'no_create': True, 'no_open': True}"
/>
<field
<field
name="ebics_userid_id"
domain="[('ebics_config_id', '=', ebics_config_id), ('user_ids.id', '=', uid), ('transaction_rights', 'in', ['both', 'down'])]"
required="1"
options="{'no_create': True, 'no_open': True}"
/>
<field
<field
name="ebics_passphrase"
password="True"
invisible="ebics_passphrase_store"
required="not ebics_passphrase_store"
/>
<field name="ebics_passphrase_store" invisible="1" />
<field name="date_from" />
<field name="date_to" />
<field
<field name="ebics_passphrase_store" invisible="1" />
<field name="date_from" />
<field name="date_to" />
<field
name="format_id"
domain="[('type', '=', 'down'), ('id', 'in', allowed_format_ids)]"
/>
<field name="order_type" />
<field name="allowed_format_ids" invisible="1" />
</group>
<footer>
<button
<field name="order_type" />
<field name="allowed_format_ids" invisible="1" />
</group>
<footer>
<button
name="ebics_download"
string="Download Files"
type="object"
class="btn-primary"
data-hotkey="q"
/>
<button
<button
string="Cancel"
class="btn-secondary"
special="cancel"
data-hotkey="z"
/>
</footer>
</form>
</field>
</record>
</footer>
</form>
</field>
</record>
<record id="ebics_xfer_view_form_upload" model="ir.ui.view">
<field name="name">EBICS File Upload</field>
<field name="model">ebics.xfer</field>
<field name="priority">1</field>
<field name="arch" type="xml">
<form string="EBICS File Upload">
<group>
<separator string="Select your bank :" colspan="2" />
<field
<record id="ebics_xfer_view_form_upload" model="ir.ui.view">
<field name="name">EBICS File Upload</field>
<field name="model">ebics.xfer</field>
<field name="priority">1</field>
<field name="arch" type="xml">
<form string="EBICS File Upload">
<group>
<separator string="Select your bank :" colspan="2" />
<field
name="ebics_config_id"
required="1"
options="{'no_create': True, 'no_open': True}"
/>
<field
<field
name="ebics_userid_id"
domain="[('ebics_config_id', '=', ebics_config_id), ('user_ids.id', '=', uid), ('transaction_rights', 'in', ['both', 'up'])]"
required="1"
options="{'no_create': True, 'no_open': True}"
/>
<field
<field
name="ebics_passphrase"
password="True"
invisible="ebics_passphrase_store"
required="not ebics_passphrase_store"
/>
<field
<field
name="ebics_sig_passphrase"
password="True"
invisible="ebics_sig_passphrase_invisible"
/>
<field name="ebics_passphrase_store" invisible="1" />
<field name="ebics_sig_passphrase_invisible" invisible="1" />
<separator string="Select your file :" colspan="2" />
<field name="upload_data" filename="upload_fname" required="1" />
<field name="upload_fname" invisible="1" />
<field name="upload_fname_dummy" string="Upload Filename" />
<field name="upload_format_ids" invisible="1" />
<field
<field name="ebics_passphrase_store" invisible="1" />
<field name="ebics_sig_passphrase_invisible" invisible="1" />
<separator string="Select your file :" colspan="2" />
<field name="upload_data" filename="upload_fname" required="1" />
<field name="upload_fname" invisible="1" />
<field name="upload_fname_dummy" string="Upload Filename" />
<field name="upload_format_ids" invisible="1" />
<field
name="format_id"
required="1"
domain="[('type', '=', 'up'), ('id', 'in', allowed_format_ids)]"
readonly="context.get('active_model') == 'account.payment.order'"
/>
<field name="order_type" />
<field name="test_mode" invisible="order_type not in ('FUL', 'BTU')" />
<field name="allowed_format_ids" invisible="1" />
</group>
<footer>
<button
<field name="order_type" />
<field
name="test_mode"
invisible="order_type not in ('FUL', 'BTU')"
/>
<field name="allowed_format_ids" invisible="1" />
</group>
<footer>
<button
name="ebics_upload"
string="Upload File"
type="object"
class="btn-primary"
data-hotkey="q"
/>
<button
<button
string="Cancel"
class="btn-secondary"
special="cancel"
data-hotkey="z"
/>
</footer>
</form>
</field>
</record>
</footer>
</form>
</field>
</record>
<record id="ebics_xfer_view_form_result" model="ir.ui.view">
<field name="name">EBICS File Transfer</field>
<field name="model">ebics.xfer</field>
<field name="priority">2</field>
<field name="arch" type="xml">
<form string="EBICS File Transfer">
<separator colspan="4" string="Results :" />
<field name="note" colspan="4" nolabel="1" width="850" height="400" />
<footer>
<button
<record id="ebics_xfer_view_form_result" model="ir.ui.view">
<field name="name">EBICS File Transfer</field>
<field name="model">ebics.xfer</field>
<field name="priority">2</field>
<field name="arch" type="xml">
<form string="EBICS File Transfer">
<separator colspan="4" string="Results :" />
<field name="note" colspan="4" nolabel="1" width="850" height="400" />
<footer>
<button
name="view_ebics_file"
type="object"
string="View EBICS File(s)"
@@ -138,35 +141,108 @@
invisible="not context.get('ebics_file_ids')"
data-hotkey="q"
/>
<button
<button
string="Close"
class="btn-secondary"
special="cancel"
data-hotkey="z"
/>
</footer>
</form>
</field>
</record>
</footer>
</form>
</field>
</record>
<record id="ebics_xfer_action_download" model="ir.actions.act_window">
<field name="name">EBICS File Transfer - Download</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ebics.xfer</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="context">{'ebics_download': 1}</field>
<field name="view_id" ref="ebics_xfer_view_form_download" />
</record>
<record id="ebics_xfer_action_download" model="ir.actions.act_window">
<field name="name">EBICS File Transfer - Download</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ebics.xfer</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="context">{'ebics_download': 1}</field>
<field name="view_id" ref="ebics_xfer_view_form_download" />
</record>
<record id="ebics_xfer_action_upload" model="ir.actions.act_window">
<field name="name">EBICS File Transfer - Upload</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ebics.xfer</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="context">{'ebics_upload': 1}</field>
<field name="view_id" ref="ebics_xfer_view_form_upload" />
</record>
<record id="ebics_xfer_action_upload" model="ir.actions.act_window">
<field name="name">EBICS File Transfer - Upload</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ebics.xfer</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="context">{'ebics_upload': 1}</field>
<field name="view_id" ref="ebics_xfer_view_form_upload" />
</record>
<record id="ebics_xfer_view_form_mark_as_downloaded" model="ir.ui.view">
<field name="name">Mark EBICS files as Downloaded</field>
<field name="model">ebics.xfer</field>
<field name="priority">1</field>
<field name="arch" type="xml">
<form string="EBICS Mark as Downloaded">
<div class="alert alert-warning" role="alert">
The EBICS Files (Bank Statements) selected via this screen will not become available in Odoo as
EBICS files but will be marked by your bank as downloaded.
<br />
As a consequence, these Bank Statements will not be retrieved by the next 'EBICS Batch Import'
scheduled action.
</div>
<group>
<separator string="Select your bank :" colspan="2" />
<field
name="ebics_config_id"
required="1"
options="{'no_create': True, 'no_open': True}"
/>
<field
name="ebics_userid_id"
domain="[('ebics_config_id', '=', ebics_config_id), ('user_ids.id', '=', uid), ('transaction_rights', 'in', ['both', 'down'])]"
required="1"
options="{'no_create': True, 'no_open': True}"
/>
<field
name="ebics_passphrase"
password="True"
invisible="ebics_passphrase_store"
required="not ebics_passphrase_store"
/>
<field name="ebics_passphrase_store" invisible="1" />
<field name="date_from" required="1" />
<field name="date_to" required="1" />
<field
name="format_id"
required="1"
domain="[('type', '=', 'down'), ('id', 'in', allowed_format_ids)]"
/>
<field name="allowed_format_ids" invisible="1" />
</group>
<footer>
<button
name="ebics_download"
string="Mark as Downloaded"
type="object"
class="btn-primary"
data-hotkey="q"
/>
<button
string="Cancel"
class="btn-secondary"
special="cancel"
data-hotkey="z"
/>
</footer>
</form>
</field>
</record>
<record id="ebics_xfer_action_mark_as_downloaded" model="ir.actions.act_window">
<field name="name">Mark files as Downloaded</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ebics.xfer</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field
name="context"
>{'ebics_download': 1, 'ebics_mark_as_downloaded': 1}</field>
<field name="view_id" ref="ebics_xfer_view_form_mark_as_downloaded" />
</record>
</odoo>

View File

@@ -1,9 +1,9 @@
# Copyright 2009-2024 Noviat.
# Copyright 2020 Noviat.
# License LGPL-3 or later (http://www.gnu.org/licenses/lgpl).
{
"name": "Upload Batch Payment via EBICS",
"version": "17.0.1.0.3",
"version": "17.0.1.1.0",
"license": "LGPL-3",
"author": "Noviat",
"website": "https://www.noviat.com/",

View File

@@ -1,32 +1,38 @@
# Copyright 2009-2023 Noviat.
# Copyright 2020 Noviat.
# License LGPL-3 or later (http://www.gnu.org/licenses/lgpl).
from odoo import _, models
from odoo import _, api, fields, models
from odoo.exceptions import UserError
class AccountBatchPayment(models.Model):
_inherit = "account.batch.payment"
hide_ebics_upload = fields.Boolean(
compute="_compute_hide_ebics_upload", default=True
)
@api.depends("journal_id.ebics_config_id", "file_generation_enabled", "state")
def _compute_hide_ebics_upload(self):
for rec in self:
rec.hide_ebics_upload = (
not rec.journal_id.ebics_config_id
or not rec.file_generation_enabled
or rec.state != "sent"
)
def ebics_upload(self):
self.ensure_one()
ctx = self.env.context.copy()
origin = _("Batch Payment") + ": " + self.name
ebics_config = self.env["ebics.config"].search(
[
("journal_ids", "=", self.journal_id.id),
("state", "=", "confirm"),
]
)
if not ebics_config:
if not self.journal_id.ebics_config_id:
raise UserError(
_("No active EBICS configuration available " "for the selected bank.")
_("No active EBICS configuration available for the selected bank.")
)
if len(ebics_config) == 1:
ctx["default_ebics_config_id"] = ebics_config.id
ctx.update(
{
"default_ebics_config_id": self.journal_id.ebics_config_id.id,
"default_upload_data": self.export_file,
"default_upload_fname": self.export_filename,
"origin": origin,
@@ -44,7 +50,6 @@ class AccountBatchPayment(models.Model):
view = self.env.ref("account_ebics.ebics_xfer_view_form_upload")
act = {
"name": _("EBICS Upload"),
"view_type": "form",
"view_mode": "form",
"res_model": "ebics.xfer",
"view_id": view.id,

View File

@@ -7,10 +7,11 @@
<field name="inherit_id" ref="account_batch_payment.view_batch_payment_form" />
<field name="arch" type="xml">
<button name="validate_batch_button" position="after">
<field name="hide_ebics_upload" invisible="1" />
<button
name="ebics_upload"
type="object"
invisible="not file_generation_enabled or state != 'sent'"
invisible="hide_ebics_upload"
string="EBICS Upload"
/>
</button>

View File

@@ -1,9 +1,9 @@
# Copyright 2009-2024 Noviat.
# License LGPL-3 or later (http://www.gnu.org/licenses/lgpl).
# Copyright 2015 Noviat.
# License LGPL-3 or later (https://www.gnu.org/licenses/lgpl).
{
"name": "Upload Payment Order via EBICS",
"version": "17.0.1.1.0",
"version": "17.0.1.2.0",
"license": "LGPL-3",
"author": "Noviat",
"website": "https://www.noviat.com/",

View File

@@ -1,5 +1,5 @@
# Copyright 2009-2024 Noviat.
# License LGPL-3 or later (http://www.gnu.org/licenses/lpgl).
# Copyright 2015 Noviat.
# License LGPL-3 or later (https://www.gnu.org/licenses/lgpl).
from odoo import fields, models

View File

@@ -1,13 +1,24 @@
# Copyright 2009-2024 Noviat.
# License LGPL-3 or later (http://www.gnu.org/licenses/lgpl).
# Copyright 2015 Noviat.
# License LGPL-3 or later (https://www.gnu.org/licenses/lgpl).
from odoo import _, models
from odoo import _, api, fields, models
from odoo.exceptions import UserError
class AccountPaymentOrder(models.Model):
_inherit = "account.payment.order"
hide_ebics_upload = fields.Boolean(
compute="_compute_hide_ebics_upload", default=True
)
@api.depends("journal_id.ebics_config_id", "state")
def _compute_hide_ebics_upload(self):
for rec in self:
rec.hide_ebics_upload = (
not rec.journal_id.ebics_config_id or rec.state != "generated"
)
def ebics_upload(self):
self.ensure_one()
ctx = self.env.context.copy()
@@ -28,8 +39,8 @@ class AccountPaymentOrder(models.Model):
if not attach:
raise UserError(
_(
"This payment order doesn't contains attachements."
"\nPlease generate first the Payment Order file first."
"This payment order doesn't contains attachments."
"\nPlease generate first the Payment Order file."
)
)
elif len(attach) > 1:
@@ -43,23 +54,16 @@ class AccountPaymentOrder(models.Model):
)
else:
origin = _("Payment Order") + ": " + self.name
ebics_config = self.env["ebics.config"].search(
[
("journal_ids", "=", self.journal_id.id),
("state", "=", "confirm"),
]
)
if not ebics_config:
if not self.journal_id.ebics_config_id:
raise UserError(
_(
"No active EBICS configuration available "
"for the selected bank."
)
)
if len(ebics_config) == 1:
ctx["default_ebics_config_id"] = ebics_config.id
ctx.update(
{
"default_ebics_config_id": self.journal_id.ebics_config_id.id,
"default_upload_data": attach.datas,
"default_upload_fname": attach.name,
"origin": origin,
@@ -76,7 +80,6 @@ class AccountPaymentOrder(models.Model):
view = self.env.ref("account_ebics.ebics_xfer_view_form_upload")
act = {
"name": _("EBICS Upload"),
"view_type": "form",
"view_mode": "form",
"res_model": "ebics.xfer",
"view_id": view.id,

View File

@@ -7,10 +7,11 @@
<field name="inherit_id" ref="account_payment_order.account_payment_order_form" />
<field name="arch" type="xml">
<button name="open2generated" position="after">
<field name="hide_ebics_upload" invisible="1" />
<button
name="ebics_upload"
type="object"
invisible="state != 'generated'"
invisible="hide_ebics_upload"
string="EBICS Upload"
class="oe_highlight"
/>