Merge pull request #22 from Noviat/16.0

Syncing from upstream Noviat/account_ebics (16.0)
This commit is contained in:
braintec 2023-12-10 01:13:07 +01:00 committed by GitHub
commit 5bb253935e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 91 additions and 46 deletions

View File

@ -174,6 +174,16 @@ Go to **Accounting > Bank and Cash > EBICS Processing**
| |
Diagnostics
===========
Add the following to your Odoo config file in order to diagnose
issues with the EBICS connection with your bank:
log_handler = fintech.ebics:DEBUG
|
EBICS Return Codes EBICS Return Codes
------------------ ------------------
@ -192,13 +202,14 @@ Electronic Distributed Signature (EDS)
This is supported via external signing apps, e.g. BankingVEU: This is supported via external signing apps, e.g. BankingVEU:
https://play.google.com/store/apps/details?id=subsembly.bankingveu - https://play.google.com/store/apps/details?id=subsembly.bankingveu
https://apps.apple.com/de/app/bankingveu/id1578694190 - https://apps.apple.com/de/app/bankingveu/id1578694190
Known Issues / Roadmap Known Issues / Roadmap
====================== ======================
- The end user is currently not able to change his passphrases (only the users with 'EBICS Manager' rights can do so).
- Add support to import externally generated keys & certificates (currently only 3SKey signature certificate). - Add support to import externally generated keys & certificates (currently only 3SKey signature certificate).
- Add support for SWIFT 3SKey signing javascript lib (SConnect, cf https://www2.swift.com/3skey/help/sconnect.html). - Add support for SWIFT 3SKey signing javascript lib (SConnect, cf https://www2.swift.com/3skey/help/sconnect.html).

View File

@ -3,7 +3,7 @@
{ {
"name": "EBICS banking protocol", "name": "EBICS banking protocol",
"version": "16.0.1.7.1", "version": "16.0.1.8.0",
"license": "LGPL-3", "license": "LGPL-3",
"author": "Noviat", "author": "Noviat",
"website": "https://www.noviat.com/", "website": "https://www.noviat.com/",

View File

@ -13,10 +13,6 @@ from odoo.exceptions import UserError
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
# logging.basicConfig(
# level=logging.DEBUG,
# format='[%(asctime)s] %(levelname)s - %(name)s: %(message)s')
try: try:
import fintech import fintech
from fintech.ebics import ( from fintech.ebics import (
@ -117,7 +113,6 @@ class EbicsUserID(models.Model):
) )
ebics_sig_passphrase = fields.Char( ebics_sig_passphrase = fields.Char(
string="EBICS Signature Passphrase", string="EBICS Signature Passphrase",
store=False,
help="You can set here a different passphrase for the EBICS " help="You can set here a different passphrase for the EBICS "
"signing key. This passphrase will never be stored hence " "signing key. This passphrase will never be stored hence "
"you'll need to specify your passphrase for each transaction that " "you'll need to specify your passphrase for each transaction that "
@ -228,10 +223,12 @@ class EbicsUserID(models.Model):
@api.depends("state", "ebics_passphrase") @api.depends("state", "ebics_passphrase")
def _compute_ebics_passphrase_view_modifiers(self): def _compute_ebics_passphrase_view_modifiers(self):
for rec in self: for rec in self:
rec.ebics_passphrase_invisible = False
if rec.state == "draft": if rec.state == "draft":
rec.ebics_passphrase_required = True rec.ebics_passphrase_required = True
rec.ebics_passphrase_invisible = False elif rec.state == "init":
elif rec.state == "get_bank_keys": rec.ebics_passphrase_invisible = True
elif rec.state in ("get_bank_keys", "to_verify"):
rec.ebics_passphrase_required = not rec.ebics_passphrase rec.ebics_passphrase_required = not rec.ebics_passphrase
rec.ebics_passphrase_invisible = rec.ebics_passphrase rec.ebics_passphrase_invisible = rec.ebics_passphrase
else: else:
@ -253,11 +250,19 @@ class EbicsUserID(models.Model):
if cfg.ebics_version == "H005" and not cfg.ebics_key_x509: if cfg.ebics_version == "H005" and not cfg.ebics_key_x509:
raise UserError(_("X.509 certificates must be used with EBICS 3.0.")) raise UserError(_("X.509 certificates must be used with EBICS 3.0."))
@api.constrains("ebics_passphrase", "ebics_sig_passphrase") @api.constrains("ebics_passphrase")
def _check_ebics_passphrase(self): def _check_ebics_passphrase(self):
for rec in self: for rec in self:
if rec.ebics_passphrase and len(rec.ebics_passphrase) < 8: if rec.ebics_passphrase and len(rec.ebics_passphrase) < 8:
raise UserError(_("The passphrase must be at least 8 characters long")) raise UserError(_("The Passphrase must be at least 8 characters long"))
@api.constrains("ebics_sig_passphrase")
def _check_ebics_sig_passphrase(self):
for rec in self:
if rec.ebics_sig_passphrase and len(rec.ebics_sig_passphrase) < 8:
raise UserError(
_("The Signature Passphrase must be at least 8 characters long")
)
@api.onchange("ebics_version") @api.onchange("ebics_version")
def _onchange_ebics_version(self): def _onchange_ebics_version(self):
@ -271,7 +276,7 @@ class EbicsUserID(models.Model):
@api.onchange("ebics_passphrase_store") @api.onchange("ebics_passphrase_store")
def _onchange_ebics_passphrase_store(self): def _onchange_ebics_passphrase_store(self):
if not self.ebics_passphrase_store: if not self.ebics_passphrase_store and self.state == "active_keys":
self.ebics_passphrase = False self.ebics_passphrase = False
@api.onchange("swift_3skey") @api.onchange("swift_3skey")
@ -320,7 +325,7 @@ class EbicsUserID(models.Model):
"passphrase": self.ebics_passphrase, "passphrase": self.ebics_passphrase,
} }
if self.ebics_sig_passphrase: if self.ebics_sig_passphrase:
keyring_params["ebics_sig_passphrase"] = self.ebics_sig_passphrase keyring_params["sig_passphrase"] = self.ebics_sig_passphrase
keyring = EbicsKeyRing(**keyring_params) keyring = EbicsKeyRing(**keyring_params)
bank = EbicsBank( bank = EbicsBank(
keyring=keyring, keyring=keyring,
@ -457,24 +462,35 @@ class EbicsUserID(models.Model):
fn_date = fields.Date.today().isoformat() fn_date = fields.Date.today().isoformat()
fn = "_".join([self.ebics_config_id.ebics_host, "ini_letter", fn_date]) + ".pdf" fn = "_".join([self.ebics_config_id.ebics_host, "ini_letter", fn_date]) + ".pdf"
letter = user.create_ini_letter(bankname=ebics_config_bank.name, lang=lang) letter = user.create_ini_letter(bankname=ebics_config_bank.name, lang=lang)
self.write( vals = {
{
"ebics_ini_letter": base64.encodebytes(letter), "ebics_ini_letter": base64.encodebytes(letter),
"ebics_ini_letter_fn": fn, "ebics_ini_letter_fn": fn,
"state": "init",
} }
) # remove non-stored passphrases from db after successfull init_1
if not self.ebics_passphrase_store:
return self.write({"state": "init"}) vals.update["ebics_passphrase"] = False
if self.ebics_sig_passphrase:
vals.update["ebics_sig_passphrase"] = False
return self.write(vals)
def ebics_init_2(self): def ebics_init_2(self):
""" """
Initialization of bank keys - Step 2: Initialization of bank keys - Step 2:
Activation of the account by the bank. Activation of the account by the bank.
""" """
self.ensure_one()
if self.state != "init": if self.state != "init":
raise UserError(_("Set state to 'Initialisation'.")) raise UserError(_("Set state to 'Initialisation'."))
self.ensure_one() vals = {"state": "get_bank_keys"}
return self.write({"state": "get_bank_keys"}) # remove non-stored passphrases from db
# remark: this code is here for extra safety but shouldn't
# have any effect since passphrases are invisible in state "init"
if not self.ebics_passphrase_store:
vals.update["ebics_passphrase"] = False
if self.ebics_sig_passphrase:
vals.update["ebics_sig_passphrase"] = False
return self.write(vals)
def ebics_init_3(self): def ebics_init_3(self):
""" """
@ -527,21 +543,23 @@ class EbicsUserID(models.Model):
"_".join([self.ebics_config_id.ebics_host, "public_bank_keys", fn_date]) "_".join([self.ebics_config_id.ebics_host, "public_bank_keys", fn_date])
+ ".txt" + ".txt"
) )
self.write( vals = {
{
"ebics_public_bank_keys": base64.encodebytes(public_bank_keys), "ebics_public_bank_keys": base64.encodebytes(public_bank_keys),
"ebics_public_bank_keys_fn": fn, "ebics_public_bank_keys_fn": fn,
"state": "to_verify", "state": "to_verify",
} }
) # remove non-stored passphrases from db
if not self.ebics_passphrase_store:
return True vals.update["ebics_passphrase"] = False
if self.ebics_sig_passphrase:
vals.update["ebics_sig_passphrase"] = False
return self.write(vals)
def ebics_init_4(self): def ebics_init_4(self):
""" """
Initialization of bank keys - Step 2: Initialization of bank keys - Step 2:
Confirm Verification of the public bank keys Confirm Verification of the public bank keys
and activate the bank keyu. and activate the bank keys.
""" """
self.ensure_one() self.ensure_one()
if self.state != "to_verify": if self.state != "to_verify":
@ -556,7 +574,13 @@ class EbicsUserID(models.Model):
url=self.ebics_config_id.ebics_url, url=self.ebics_config_id.ebics_url,
) )
bank.activate_keys() bank.activate_keys()
return self.write({"state": "active_keys"}) vals = {"state": "active_keys"}
# remove non-stored passphrases from db
if not self.ebics_passphrase_store:
vals.update["ebics_passphrase"] = False
if self.ebics_sig_passphrase:
vals.update["ebics_sig_passphrase"] = False
return self.write(vals)
def change_passphrase(self): def change_passphrase(self):
self.ensure_one() self.ensure_one()

View File

@ -527,6 +527,15 @@ fintech_register_keycode = AB1CD-E2FG-3H-IJ4K-5L
<div class="line-block"> <div class="line-block">
<div class="line"><br /></div> <div class="line"><br /></div>
</div> </div>
</div>
<div class="section" id="diagnostics">
<h2>Diagnostics</h2>
<p>Add the following to your Odoo config file in order to diagnose
issues with the EBICS connection with your bank:</p>
<p>log_handler = fintech.ebics:DEBUG</p>
<div class="line-block">
<div class="line"><br /></div>
</div>
<div class="section" id="ebics-return-codes"> <div class="section" id="ebics-return-codes">
<h3>EBICS Return Codes</h3> <h3>EBICS Return Codes</h3>
<p>During the processing of your EBICS upload/download, your bank may return an Error Code, e.g.</p> <p>During the processing of your EBICS upload/download, your bank may return an Error Code, e.g.</p>
@ -541,14 +550,16 @@ You can also find this information in the doc folder of this module (file EBICS_
<div class="section" id="electronic-distributed-signature-eds"> <div class="section" id="electronic-distributed-signature-eds">
<h3>Electronic Distributed Signature (EDS)</h3> <h3>Electronic Distributed Signature (EDS)</h3>
<p>This is supported via external signing apps, e.g. BankingVEU:</p> <p>This is supported via external signing apps, e.g. BankingVEU:</p>
<blockquote> <ul class="simple">
<a class="reference external" href="https://play.google.com/store/apps/details?id=subsembly.bankingveu">https://play.google.com/store/apps/details?id=subsembly.bankingveu</a> <li><a class="reference external" href="https://play.google.com/store/apps/details?id=subsembly.bankingveu">https://play.google.com/store/apps/details?id=subsembly.bankingveu</a></li>
<a class="reference external" href="https://apps.apple.com/de/app/bankingveu/id1578694190">https://apps.apple.com/de/app/bankingveu/id1578694190</a></blockquote> <li><a class="reference external" href="https://apps.apple.com/de/app/bankingveu/id1578694190">https://apps.apple.com/de/app/bankingveu/id1578694190</a></li>
</ul>
</div> </div>
</div> </div>
<div class="section" id="known-issues-roadmap"> <div class="section" id="known-issues-roadmap">
<h2>Known Issues / Roadmap</h2> <h2>Known Issues / Roadmap</h2>
<ul class="simple"> <ul class="simple">
<li>The end user is currently not able to change his passphrases (only the users with 'EBICS Manager' rights can do so).</li>
<li>Add support to import externally generated keys &amp; certificates (currently only 3SKey signature certificate).</li> <li>Add support to import externally generated keys &amp; certificates (currently only 3SKey signature certificate).</li>
<li>Add support for SWIFT 3SKey signing javascript lib (SConnect, cf <a class="reference external" href="https://www2.swift.com/3skey/help/sconnect.html">https://www2.swift.com/3skey/help/sconnect.html</a>).</li> <li>Add support for SWIFT 3SKey signing javascript lib (SConnect, cf <a class="reference external" href="https://www2.swift.com/3skey/help/sconnect.html">https://www2.swift.com/3skey/help/sconnect.html</a>).</li>
</ul> </ul>

View File

@ -89,9 +89,15 @@ class EbicsChangePassphrase(models.TransientModel):
raise UserError(str(err)) from err raise UserError(str(err)) from err
if self.new_pass: if self.new_pass:
self.ebics_userid_id.ebics_passphrase = self.new_pass self.ebics_userid_id.ebics_passphrase = (
self.ebics_userid_id.ebics_passphrase_store and self.new_pass
)
self.note += "The EBICS Passphrase has been changed." self.note += "The EBICS Passphrase has been changed."
if self.new_sig_pass: if self.new_sig_pass:
# removing ebics_sig_passphrase from db should not be required
# but we do it for double safety
if self.ebics_userid_id.ebics_sig_passphrase:
self.ebics_userid_id.ebics_sig_passphrase = False
self.note += "The EBICS Signature Passphrase has been changed." self.note += "The EBICS Signature Passphrase has been changed."
module = __name__.split("addons.")[1].split(".")[0] module = __name__.split("addons.")[1].split(".")[0]

View File

@ -1,13 +1,6 @@
# Copyright 2009-2023 Noviat. # Copyright 2009-2023 Noviat.
# License LGPL-3 or later (http://www.gnu.org/licenses/lgpl). # License LGPL-3 or later (http://www.gnu.org/licenses/lgpl).
"""
import logging
logging.basicConfig(
level=logging.DEBUG,
format='[%(asctime)s] %(levelname)s - %(name)s: %(message)s')
"""
import base64 import base64
import logging import logging
from sys import exc_info from sys import exc_info