Merge pull request #24 from Noviat/12-generic-order_type

[12.0] generic order type + CH File Formats
This commit is contained in:
Luc De Meyer 2020-12-11 12:50:50 +01:00 committed by GitHub
commit 7cf360c880
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 533 additions and 188 deletions

View File

@ -22,6 +22,58 @@ Remark:
The EBICS 'Test Mode' for uploading orders requires Fintech 4.3.4 or higher. The EBICS 'Test Mode' for uploading orders requires Fintech 4.3.4 or higher.
|
We also recommend to consider the installation of the following modules:
|
- account_ebics_oe
Required if you are running Odoo Enterprise
|
- account_ebics_batch_payment
Recommended if you are using the Odoo Enterprise account_batch_payment module
|
- account_ebics_payment_order
Recommended if you are using the OCA account_payment_order module.
Cf. https://github.com/OCA/bank-payment
|
- account_bank_statement_import_fr_cfonb
Required to handle french CFONB files.
Cf. https://github.com/OCA/l10n_fr
|
- account_bank_statement_import_camt_oca
Required to handle camt.052 and camt.054 files.
Cf. https://github.com/OCA/bank_statement_import
|
- account_bank_statement_import_helper
Required if you are processing bank statements with local bank account numbers (e.g. french CFONB files).
The import helper will match the local bank account number with the IBAN number specified on the Odoo Financial journal.
Cf. https://github.com/noviat-apps
|
Fintech license Fintech license
--------------- ---------------
@ -50,6 +102,33 @@ Go to **Settings > Users**
Add the users that are authorised to maintain the EBICS configuration to the 'EBICS Manager' Group. Add the users that are authorised to maintain the EBICS configuration to the 'EBICS Manager' Group.
|
Go to **Accounting > Configuration > Miscellaneous > EBICS > EBICS File Formats**
Check if the EBICS File formats that you want to process in Odoo are defined.
Most commonly used formats for which support is available in Odoo should be there already.
Please open an issue on https://github.com/Noviat/account_ebics to report missing EBICS File Formats.
For File Formats of type 'Downloads' you can also specifiy a 'Download Process Method'.
This is the method that will be executed when hitting the 'Process' button on the downloaded file.
The following methods are currently available:
- cfonb120
- camt.053
- camt.052
- camt.054
All these methods require complimentary modules to be installed (cf. Installation section supra).
You'll get an error message when the required module is not installed on your Odoo instance.
|
Go to **Accounting > Configuration > Miscellaneous > EBICS > EBICS Configuration** Go to **Accounting > Configuration > Miscellaneous > EBICS > EBICS Configuration**
Configure your EBICS configuration according to the contract with your bank. Configure your EBICS configuration according to the contract with your bank.

View File

@ -3,7 +3,7 @@
{ {
'name': 'EBICS banking protocol', 'name': 'EBICS banking protocol',
'version': '12.0.1.0.4', 'version': '12.0.1.1.0',
'license': 'LGPL-3', 'license': 'LGPL-3',
'author': 'Noviat', 'author': 'Noviat',
'category': 'Accounting & Finance', 'category': 'Accounting & Finance',

View File

@ -2,104 +2,152 @@
<odoo> <odoo>
<data noupdate="1"> <data noupdate="1">
<!-- <!-- Download formats -->
File format tested with the following banks:
- GLS Gemeinschaftsbank (Germany)
-->
<record id="ebics_ff_camt_053_001_02_stm" model="ebics.file.format">
<field name="name">camt.053.001.02.stm</field>
<field name="type">down</field>
<field name="order_type">C53</field>
<field name="description">Bank Statement in Format camt.053</field>
<field name="suffix">c53.xml</field>
</record>
<!-- <record id="ebics_ff_C52" model="ebics.file.format">
File format tested with the following banks: <field name="name">camt.052</field>
- Kreissparkasse Göppingen (Germany)
-->
<record id="ebics_ff_camt_052_001_02_stm" model="ebics.file.format">
<field name="name">camt.052.001.02.stm</field>
<field name="type">down</field> <field name="type">down</field>
<field name="order_type">C52</field> <field name="order_type">C52</field>
<field name="description">Bank Statement in Format camt.052</field> <field name="download_process_method">camt.052</field>
<field name="description">bank to customer account report in format camt.052</field>
<field name="suffix">c52.xml</field> <field name="suffix">c52.xml</field>
</record> </record>
<!-- <record id="ebics_ff_Z52" model="ebics.file.format">
File format tested with the following banks: <field name="name">camt.052</field>
- GLS Gemeinschaftsbank (Germany) <field name="type">down</field>
--> <field name="order_type">Z52</field>
<record id="ebics_ff_pain_001_001_03_sct" model="ebics.file.format"> <field name="download_process_method">camt.052</field>
<field name="name">pain.001.001.03.sct</field> <field name="description">bank to customer account report in format camt.052</field>
<field name="type">up</field> <field name="suffix">c52.xml</field>
<field name="order_type">CCT</field>
<field name="description">Payment Order in Format pain.001.001.03</field>
<field name="suffix">xml</field>
</record> </record>
<record id="ebics_ff_pain_008_001_02_sdd" model="ebics.file.format"> <record id="ebics_ff_C53" model="ebics.file.format">
<field name="name">pain.008.001.02.sdd</field> <field name="name">camt.053</field>
<field name="type">up</field> <field name="type">down</field>
<field name="order_type">CDD</field> <field name="order_type">C53</field>
<field name="description">Sepa Core Direct Debit Order in Format pain.008.001.02</field> <field name="download_process_method">camt.053</field>
<field name="suffix">xml</field> <field name="description">Bank to customer statement report in format camt.053</field>
<field name="suffix">c53.xml</field>
</record> </record>
<record id="ebics_ff_pain_008_001_02_sbb" model="ebics.file.format"> <record id="ebics_ff_Z53" model="ebics.file.format">
<field name="name">pain.008.001.02.sbb</field> <field name="name">camt.053</field>
<field name="type">up</field> <field name="type">down</field>
<field name="order_type">CDB</field> <field name="order_type">Z53</field>
<field name="description">Sepa Direct Debit (B2B) Order in Format pain.008.001.02</field> <field name="download_process_method">camt.053</field>
<field name="suffix">xml</field> <field name="description">Bank to customer statement report in format camt.053</field>
<field name="suffix">c53.xml</field>
</record> </record>
<!-- <record id="ebics_ff_C54" model="ebics.file.format">
File format tested with the following banks: <field name="name">camt.054</field>
- Credit Suisse (Switzerland) <field name="type">down</field>
--> <field name="order_type">C54</field>
<record id="ebics_ff_pain_001" model="ebics.file.format"> <field name="download_process_method">camt.054</field>
<field name="name">pain.001</field> <field name="description">Bank to customer debit credit notification in format camt.054</field>
<field name="type">up</field> <field name="suffix">c52.xml</field>
<field name="order_type">XE2</field>
<field name="description">Payment Order in Format pain.001.001.03</field>
<field name="suffix">xml</field>
</record> </record>
<!-- <record id="ebics_ff_Z54" model="ebics.file.format">
File format tested with the following banks: <field name="name">camt.054</field>
- Credit Suisse (Switzerland) <field name="type">down</field>
--> <field name="order_type">Z54</field>
<record id="ebics_ff_pain_008" model="ebics.file.format"> <field name="download_process_method">camt.054</field>
<field name="name">pain.008</field> <field name="description">Bank to customer debit credit notification in format camt.054</field>
<field name="type">up</field> <field name="suffix">c52.xml</field>
<field name="order_type">XE3</field>
<field name="description">Direct Debit Order in Format pain.008.001.02</field>
<field name="suffix">xml</field>
</record> </record>
<!-- <record id="ebics_ff_FDL_camt_xxx_cfonb120_stm" model="ebics.file.format">
File format tested with the following banks:
- CIC (France)
-->
<record id="ebics_ff_camt_xxx_cfonb120_stm" model="ebics.file.format">
<field name="name">camt.xxx.cfonb120.stm</field> <field name="name">camt.xxx.cfonb120.stm</field>
<field name="type">down</field> <field name="type">down</field>
<field name="order_type">FDL</field> <field name="order_type">FDL</field>
<field name="description">Bank Statement in Format cfonb120</field> <field name="download_process_method">cfonb120</field>
<field name="description">Bank to customer statement report in format cfonb120</field>
<field name="suffix">cfonb120.dat</field> <field name="suffix">cfonb120.dat</field>
</record> </record>
<!-- <record id="ebics_ff_CDZ" model="ebics.file.format">
File format tested with the following banks: <field name="name">pain.002</field>
- CIC (France) <field name="type">down</field>
--> <field name="order_type">CDZ</field>
<record id="ebics_ff_pain_001_001_02_sct" model="ebics.file.format"> <field name="description">Payment status report for direct debit in format pain.002</field>
<field name="suffix">psr.xml</field>
</record>
<record id="ebics_ff_Z01" model="ebics.file.format">
<field name="name">pain.002</field>
<field name="type">down</field>
<field name="order_type">Z01</field>
<field name="download_process_method">pain.002</field>
<field name="description">Payment status report for direct debit in format pain.002</field>
<field name="suffix">psr.xml</field>
</record>
<!-- Upload formats -->
<record id="ebics_ff_CCT" model="ebics.file.format">
<field name="name">pain.001.001.03</field>
<field name="type">up</field>
<field name="order_type">CCT</field>
<field name="description">Payment Order in format pain.001.001.03</field>
<field name="suffix">cct.xml</field>
</record>
<record id="ebics_ff_XE2" model="ebics.file.format">
<field name="name">pain.001.001.03</field>
<field name="type">up</field>
<field name="order_type">XE2</field>
<field name="description">Payment Order in format pain.001.001.03</field>
<field name="suffix">cct.xml</field>
</record>
<record id="ebics_ff_CDD" model="ebics.file.format">
<field name="name">pain.008.001.02.sdd</field>
<field name="type">up</field>
<field name="order_type">CDD</field>
<field name="description">Sepa Core Direct Debit Order in format pain.008.001.02</field>
<field name="suffix">sdd.xml</field>
</record>
<record id="ebics_ff_CDD" model="ebics.file.format">
<field name="name">pain.008.001.02.sdd</field>
<field name="type">up</field>
<field name="order_type">CDD</field>
<field name="description">Sepa Core Direct Debit Order in format pain.008.001.02</field>
<field name="suffix">sdd.xml</field>
</record>
<record id="ebics_ff_XE3" model="ebics.file.format">
<field name="name">pain.008.001.02.sdd</field>
<field name="type">up</field>
<field name="order_type">XE3</field>
<field name="description">Sepa Core Direct Debit Order in format pain.008.001.02</field>
<field name="suffix">sdd.xml</field>
</record>
<record id="ebics_ff_CDB" model="ebics.file.format">
<field name="name">pain.008.001.02.sbb</field>
<field name="type">up</field>
<field name="order_type">CDB</field>
<field name="description">Sepa Direct Debit (B2B) Order in format pain.008.001.02</field>
<field name="suffix">sbb.xml</field>
</record>
<record id="ebics_ff_XE4" model="ebics.file.format">
<field name="name">pain.008.001.02.sbb</field>
<field name="type">up</field>
<field name="order_type">XE4</field>
<field name="description">Sepa Direct Debit (B2B) Order in format pain.008.001.02</field>
<field name="suffix">sbb.xml</field>
</record>
<record id="ebics_ff_FUL_pain_001_001_02_sct" model="ebics.file.format">
<field name="name">pain.001.001.02.sct</field> <field name="name">pain.001.001.02.sct</field>
<field name="type">up</field> <field name="type">up</field>
<field name="order_type">FUL</field> <field name="order_type">FUL</field>
<field name="description">Payment Order in Format pain.001.001.02</field> <field name="description">Payment Order in format pain.001.001.02</field>
<field name="suffix">xml</field> <field name="suffix">cct.xml</field>
</record> </record>
</data> </data>

View File

@ -0,0 +1,41 @@
# Copyright 2009-2020 Noviat.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
_FILE_FORMATS = [
{'xml_id_name': 'ebics_ff_C52',
'download_process_method': 'camt.052',
},
{'xml_id_name': 'ebics_ff_C53',
'download_process_method': 'camt.053',
},
{'xml_id_name': 'ebics_ff_FDL_camt_xxx_cfonb120_stm',
'download_process_method': 'cfonb120',
},
]
def migrate(cr, version):
for ff in _FILE_FORMATS:
_update_file_format(cr, ff)
def _update_file_format(cr, ff):
cr.execute(
"""
SELECT res_id FROM ir_model_data
WHERE module='account_ebics' AND name='{}'
""".format(ff['xml_id_name'])
)
res = cr.fetchone()
if res:
cr.execute(
"""
UPDATE ebics_file_format
SET download_process_method='{download_process_method}'
WHERE id={ff_id};
""".format(
download_process_method=ff['download_process_method'],
ff_id=res[0]
)
)

View File

@ -0,0 +1,70 @@
# Copyright 2009-2020 Noviat.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
_FILE_FORMATS = [
{'old_xml_id_name': 'ebics_ff_camt_052_001_02_stm',
'new_xml_id_name': 'ebics_ff_C52',
'new_name': 'camt.052',
},
{'old_xml_id_name': 'ebics_ff_camt_053_001_02_stm',
'new_xml_id_name': 'ebics_ff_C53',
'new_name': 'camt.053',
},
{'old_xml_id_name': 'ebics_ff_camt_xxx_cfonb120_stm',
'new_xml_id_name': 'ebics_ff_FDL_camt_xxx_cfonb120_stm',
},
{'old_xml_id_name': 'ebics_ff_pain_001_001_03_sct',
'new_xml_id_name': 'ebics_ff_CCT',
},
{'old_xml_id_name': 'ebics_ff_pain_001',
'new_xml_id_name': 'ebics_ff_XE2',
'new_name': 'pain.001.001.03',
},
{'old_xml_id_name': 'ebics_ff_pain_008_001_02_sdd',
'new_xml_id_name': 'ebics_ff_CDD',
},
{'old_xml_id_name': 'ebics_ff_pain_008',
'new_xml_id_name': 'ebics_ff_XE3',
},
{'old_xml_id_name': 'ebics_ff_pain_008_001_02_sbb',
'new_xml_id_name': 'ebics_ff_CDB',
},
{'old_xml_id_name': 'ebics_ff_pain_001_001_02_sct',
'new_xml_id_name': 'ebics_ff_FUL_pain_001_001_02_sct',
},
]
def migrate(cr, version):
if not version:
return
for ff in _FILE_FORMATS:
_update_file_format(cr, ff)
def _update_file_format(cr, ff):
cr.execute(
"""
SELECT id, res_id FROM ir_model_data
WHERE module='account_ebics' AND name='{}'
""".format(ff['old_xml_id_name'])
)
res = cr.fetchone()
if res:
query = """
UPDATE ir_model_data
SET name='{new_xml_id_name}'
WHERE id={xml_id};
""".format(
new_xml_id_name=ff["new_xml_id_name"], xml_id=res[0]
)
if ff.get('new_name'):
query += """
UPDATE ebics_file_format
SET name='{new_name}'
WHERE id={ff_id};
""".format(
new_name=ff["new_name"], ff_id=res[1]
)
cr.execute(query)

View File

@ -74,7 +74,7 @@ class EbicsFile(models.Model):
raise UserError(_( raise UserError(_(
"You can only remove EBICS files in state 'Draft'.")) "You can only remove EBICS files in state 'Draft'."))
# execute format specific actions # execute format specific actions
ff = ebics_file.format_id.name ff = ebics_file.format_id.download_process_method
if ff in ff_methods: if ff in ff_methods:
if ff_methods[ff].get('unlink'): if ff_methods[ff].get('unlink'):
ff_methods[ff]['unlink'](ebics_file) ff_methods[ff]['unlink'](ebics_file)
@ -95,7 +95,7 @@ class EbicsFile(models.Model):
self.ensure_one() self.ensure_one()
self.note_process = '' self.note_process = ''
ff_methods = self._file_format_methods() ff_methods = self._file_format_methods()
ff = self.format_id.name ff = self.format_id.download_process_method
if ff in ff_methods: if ff in ff_methods:
if ff_methods[ff].get('process'): if ff_methods[ff].get('process'):
res = ff_methods[ff]['process'](self) res = ff_methods[ff]['process'](self)
@ -125,15 +125,21 @@ class EbicsFile(models.Model):
for extra file formats. for extra file formats.
""" """
res = { res = {
'camt.xxx.cfonb120.stm': 'cfonb120':
{'process': self._process_cfonb120, {'process': self._process_cfonb120,
'unlink': self._unlink_cfonb120}, 'unlink': self._unlink_cfonb120},
'camt.052.001.02.stm': 'camt.052':
{'process': self._process_camt052, {'process': self._process_camt052,
'unlink': self._unlink_camt052}, 'unlink': self._unlink_camt052},
'camt.053.001.02.stm': 'camt.053':
{'process': self._process_camt053, {'process': self._process_camt053,
'unlink': self._unlink_camt053}, 'unlink': self._unlink_camt053},
'camt.054':
{'process': self._process_camt054,
'unlink': self._unlink_camt054},
'pain.002':
{'process': self._process_pain002,
'unlink': self._unlink_pain002},
} }
return res return res
@ -222,6 +228,20 @@ class EbicsFile(models.Model):
""" """
pass pass
@staticmethod
def _process_camt054(self):
import_module = 'account_bank_statement_import_camt_oca'
self._check_import_module(import_module)
return self._process_camt053(self)
@staticmethod
def _unlink_camt054(self):
"""
Placeholder for camt054 specific actions before removing the
EBICS data file and its related bank statements.
"""
pass
@staticmethod @staticmethod
def _process_camt053(self): def _process_camt053(self):
import_module = 'account_bank_statement_import_camt%' import_module = 'account_bank_statement_import_camt%'
@ -272,6 +292,23 @@ class EbicsFile(models.Model):
""" """
pass pass
@staticmethod
def _process_pain002(self):
"""
Placeholder for processing pain.002 files.
TODO:
add import logic based upon OCA 'account_payment_return_import'
"""
pass
@staticmethod
def _unlink_pain002(self):
"""
Placeholder for pain.002 specific actions before removing the
EBICS data file.
"""
raise NotImplementedError
def _process_undefined_format(self): def _process_undefined_format(self):
raise UserError(_( raise UserError(_(
"The current version of the 'account_ebics' module " "The current version of the 'account_ebics' module "

View File

@ -7,21 +7,35 @@ from odoo import api, fields, models
class EbicsFileFormat(models.Model): class EbicsFileFormat(models.Model):
_name = 'ebics.file.format' _name = 'ebics.file.format'
_description = 'EBICS File Formats' _description = 'EBICS File Formats'
_order = 'type,name' _order = 'type,name,order_type'
name = fields.Selection( name = fields.Char(
selection=lambda self: self._selection_name(), string='Request Type',
string='Request Type', required=True) required=True,
help="E.g. camt.xxx.cfonb120.stm, pain.001.001.03.sct.\n"
"Specify camt.052, camt.053, camt.054 for camt "
"Order Types such as C53, Z53, C54, Z54.\n"
"This name has to match the 'Request Type' in your "
"EBICS contract for Order Type 'FDL' or 'FUL'.\n")
type = fields.Selection( type = fields.Selection(
selection=[('down', 'Download'), selection=[('down', 'Download'),
('up', 'Upload')], ('up', 'Upload')],
required=True) required=True)
order_type = fields.Selection( order_type = fields.Char(
selection=lambda self: self._selection_order_type(),
string='Order Type', string='Order Type',
help="For most banks is France you should use the " required=True,
help="E.g. C53 (check your EBICS contract).\n"
"For most banks in France you should use the "
"format neutral Order Types 'FUL' for upload " "format neutral Order Types 'FUL' for upload "
"and 'FDL' for download.") "and 'FDL' for download.")
download_process_method = fields.Selection(
selection='_selection_download_process_method',
help="Enable processing within Odoo of the downloaded file "
"via the 'Process' button."
"E.g. specify camt.053 to import a camt.053 file and create "
"a bank statement.")
# TODO:
# move signature_class parameter so that it can be set per EBICS config
signature_class = fields.Selection( signature_class = fields.Selection(
selection=[('E', 'Single signature'), selection=[('E', 'Single signature'),
('T', 'Transport signature')], ('T', 'Transport signature')],
@ -30,51 +44,19 @@ class EbicsFileFormat(models.Model):
"ERP system when using class 'E' to prevent unauthorised " "ERP system when using class 'E' to prevent unauthorised "
"users to make supplier payments." "users to make supplier payments."
"\nLeave this field empty to use the default " "\nLeave this field empty to use the default "
"defined for your bank connection.") "defined for your EBICS Configuration.")
description = fields.Char() description = fields.Char()
suffix = fields.Char( suffix = fields.Char(
required=True, required=True,
help="Specify the filename suffix for this File Format." help="Specify the filename suffix for this File Format."
"\nE.g. camt.053.xml") "\nE.g. c53.xml")
@api.model @api.model
def _selection_order_type(self): def _selection_download_process_method(self):
up = self._supported_upload_order_types() methods = self.env['ebics.file']._file_format_methods().keys()
down = self._supported_download_order_types() return [(x, x) for x in methods]
selection = [(x, x) for x in up + down]
return selection
def _supported_upload_order_types(self): @api.onchange('type')
return ['FUL', 'CCT', 'CDD', 'CDB', 'XE2', 'XE3'] def _onchange_type(self):
if self.type == 'up':
def _supported_download_order_types(self): self.download_process_method = False
return ['FDL', 'C52', 'C53', 'C54']
@api.model
def _selection_name(self):
"""
List of supported EBICS Request Types.
Extend this method via a custom module when testing
a new Request Type and make a PR for the
account_ebics module when this new Request Type
is working correctly.
This PR should include at least updates to
- 'data/ebics_file_format.xml'
- 'models/ebics_file_format.py'
An overview of the EBICS Request Types can be found in
the doc folder of this module (EBICS_Annex2).
"""
request_types = [
'camt.052.001.02.stm',
'camt.053.001.02.stm',
'pain.001.001.03.sct',
'pain.008.001.02.sdd',
'pain.008.001.02.sbb',
'camt.xxx.cfonb120.stm',
'pain.001.001.02.sct',
'camt.053',
'pain.001',
'pain.008',
]
selection = [(x, x) for x in request_types]
return selection

View File

@ -32,10 +32,10 @@ try:
keycode=fintech_register_keycode, keycode=fintech_register_keycode,
users=fintech_register_users) users=fintech_register_users)
except RuntimeError as e: except RuntimeError as e:
if e.message == "'register' can be called only once": if str(e) == "'register' can be called only once":
pass pass
else: else:
_logger.error(e.message) _logger.error(str(e))
fintech.register() fintech.register()
except Exception: except Exception:
msg = "fintech.register error" msg = "fintech.register error"

View File

@ -355,6 +355,66 @@ ul.auto-toc {
</ul> </ul>
<p>Remark:</p> <p>Remark:</p>
<p>The EBICS 'Test Mode' for uploading orders requires Fintech 4.3.4 or higher.</p> <p>The EBICS 'Test Mode' for uploading orders requires Fintech 4.3.4 or higher.</p>
<div class="line-block">
<div class="line"><br /></div>
</div>
<p>We also recommend to consider the installation of the following modules:</p>
<div class="line-block">
<div class="line"><br /></div>
</div>
<ul>
<li><p class="first">account_ebics_oe</p>
<p>Required if you are running Odoo Enterprise</p>
</li>
</ul>
<div class="line-block">
<div class="line"><br /></div>
</div>
<ul>
<li><p class="first">account_ebics_batch_payment</p>
<p>Recommended if you are using the Odoo Enterprise account_batch_payment module</p>
</li>
</ul>
<div class="line-block">
<div class="line"><br /></div>
</div>
<ul>
<li><p class="first">account_ebics_payment_order</p>
<p>Recommended if you are using the OCA account_payment_order module.</p>
<p>Cf. <a class="reference external" href="https://github.com/OCA/bank-payment">https://github.com/OCA/bank-payment</a></p>
</li>
</ul>
<div class="line-block">
<div class="line"><br /></div>
</div>
<ul>
<li><p class="first">account_bank_statement_import_fr_cfonb</p>
<p>Required to handle french CFONB files.</p>
<p>Cf. <a class="reference external" href="https://github.com/OCA/l10n_fr">https://github.com/OCA/l10n_fr</a></p>
</li>
</ul>
<div class="line-block">
<div class="line"><br /></div>
</div>
<ul>
<li><p class="first">account_bank_statement_import_camt_oca</p>
<p>Required to handle camt.052 and camt.054 files.</p>
<p>Cf. <a class="reference external" href="https://github.com/OCA/bank_statement_import">https://github.com/OCA/bank_statement_import</a></p>
</li>
</ul>
<div class="line-block">
<div class="line"><br /></div>
</div>
<ul>
<li><p class="first">account_bank_statement_import_helper</p>
<p>Required if you are processing bank statements with local bank account numbers (e.g. french CFONB files).</p>
<p>The import helper will match the local bank account number with the IBAN number specified on the Odoo Financial journal.</p>
<p>Cf. <a class="reference external" href="https://github.com/noviat-apps">https://github.com/noviat-apps</a></p>
</li>
</ul>
<div class="line-block">
<div class="line"><br /></div>
</div>
<div class="section" id="fintech-license"> <div class="section" id="fintech-license">
<h3>Fintech license</h3> <h3>Fintech license</h3>
<p>If you have a valid Fintech.ebics license, you should add the following <p>If you have a valid Fintech.ebics license, you should add the following
@ -379,6 +439,27 @@ based (with monthly recurring billing).</p>
<h2>Configuration</h2> <h2>Configuration</h2>
<p>Go to <strong>Settings &gt; Users</strong></p> <p>Go to <strong>Settings &gt; Users</strong></p>
<p>Add the users that are authorised to maintain the EBICS configuration to the 'EBICS Manager' Group.</p> <p>Add the users that are authorised to maintain the EBICS configuration to the 'EBICS Manager' Group.</p>
<div class="line-block">
<div class="line"><br /></div>
</div>
<p>Go to <strong>Accounting &gt; Configuration &gt; Miscellaneous &gt; EBICS &gt; EBICS File Formats</strong></p>
<p>Check if the EBICS File formats that you want to process in Odoo are defined.</p>
<p>Most commonly used formats for which support is available in Odoo should be there already.</p>
<p>Please open an issue on <a class="reference external" href="https://github.com/Noviat/account_ebics">https://github.com/Noviat/account_ebics</a> to report missing EBICS File Formats.</p>
<p>For File Formats of type 'Downloads' you can also specifiy a 'Download Process Method'.</p>
<p>This is the method that will be executed when hitting the 'Process' button on the downloaded file.</p>
<p>The following methods are currently available:</p>
<ul class="simple">
<li>cfonb120</li>
<li>camt.053</li>
<li>camt.052</li>
<li>camt.054</li>
</ul>
<p>All these methods require complimentary modules to be installed (cf. Installation section supra).</p>
<p>You'll get an error message when the required module is not installed on your Odoo instance.</p>
<div class="line-block">
<div class="line"><br /></div>
</div>
<p>Go to <strong>Accounting &gt; Configuration &gt; Miscellaneous &gt; EBICS &gt; EBICS Configuration</strong></p> <p>Go to <strong>Accounting &gt; Configuration &gt; Miscellaneous &gt; EBICS &gt; EBICS Configuration</strong></p>
<p>Configure your EBICS configuration according to the contract with your bank.</p> <p>Configure your EBICS configuration according to the contract with your bank.</p>
</div> </div>

View File

@ -20,13 +20,21 @@
<field name="model">ebics.file.format</field> <field name="model">ebics.file.format</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="EBICS File Format"> <form string="EBICS File Format">
<group col="4"> <group name="main">
<group name="main-left">
<field name="type"/> <field name="type"/>
<field name="suffix"/>
<field name="download_process_method"
attrs="{'invisible': [('type', '=', 'up')]}"
force_save="1"/>
<field name="signature_class"/>
</group>
<group name="main-right">
<field name="order_type"/> <field name="order_type"/>
<field name="name"/> <field name="name"/>
<field name="signature_class"/> </group>
<field name="suffix"/> </group>
<newline/> <group name="description">
<field name="description"/> <field name="description"/>
</group> </group>
</form> </form>

View File

@ -63,10 +63,10 @@ class EbicsXfer(models.TransientModel):
string='EBICS File Format', string='EBICS File Format',
help="Select EBICS File Format to upload/download." help="Select EBICS File Format to upload/download."
"\nLeave blank to download all available files.") "\nLeave blank to download all available files.")
order_type = fields.Selection( order_type = fields.Char(
selection=lambda self: self._selection_order_type(), related='format_id.order_type',
string='Order Type', string='Order Type',
help="For most banks is France you should use the " help="For most banks in France you should use the "
"format neutral Order Types 'FUL' for upload " "format neutral Order Types 'FUL' for upload "
"and 'FDL' for download.") "and 'FDL' for download.")
test_mode = fields.Boolean( test_mode = fields.Boolean(
@ -88,10 +88,6 @@ class EbicsXfer(models.TransientModel):
else: else:
return cfg_mod return cfg_mod
@api.model
def _selection_order_type(self):
return self.env['ebics.file.format']._selection_order_type()
@api.onchange('ebics_config_id') @api.onchange('ebics_config_id')
def _onchange_ebics_config_id(self): def _onchange_ebics_config_id(self):
domain = {} domain = {}
@ -155,56 +151,66 @@ class EbicsXfer(models.TransientModel):
self.note = '' self.note = ''
client = self._setup_client() client = self._setup_client()
if client: if client:
download_formats = self.format_id \ download_formats = (
self.format_id
or self.ebics_config_id.ebics_file_format_ids.filtered( or self.ebics_config_id.ebics_file_format_ids.filtered(
lambda r: r.type == 'down') lambda r: r.type == 'down'
)
)
ebics_files = self.env['ebics.file'] ebics_files = self.env['ebics.file']
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: for df in download_formats:
success = False
order_type = df.order_type or 'FDL'
params = {}
if order_type == 'FDL':
params['filetype'] = df.name
if order_type in ['FDL', 'C52', 'C53', 'C54']:
params.update({
'start':
self.date_from and self.date_from.isoformat()
or None,
'end':
self.date_to and self.date_to.isoformat()
or None,
})
kwargs = {k: v for k, v in params.items() if v}
try: try:
method = getattr(client, order_type) success = False
data = method(**kwargs) if df.order_type == 'FDL':
data = client.FDL(df.name, date_from, date_to)
else:
params = None
if date_from and date_to:
params = {'DateRange': {
'Start': date_from,
'End': date_to,
}}
data = client.download(df.order_type, params=params)
ebics_files += self._handle_download_data(data, df) ebics_files += self._handle_download_data(data, df)
success = True success = True
except EbicsFunctionalError: except EbicsFunctionalError:
e = exc_info() e = exc_info()
self.note += '\n' self.note += '\n'
self.note += _("EBICS Functional Error:") self.note += _(
"EBICS Functional Error during download of File Format %s (%s):"
) % (df.name, df.order_type)
self.note += '\n' self.note += '\n'
self.note += '%s (code: %s)' % (e[1].message, e[1].code) self.note += '%s (code: %s)' % (e[1].message, e[1].code)
except EbicsTechnicalError: except EbicsTechnicalError:
e = exc_info() e = exc_info()
self.note += '\n' self.note += '\n'
self.note += _("EBICS Technical Error:") self.note += _(
"EBICS Technical Error during download of File Format %s (%s):"
) % (df.name, df.order_type)
self.note += '\n' self.note += '\n'
self.note += '%s (code: %s)' % (e[1].message, e[1].code) self.note += '%s (code: %s)' % (e[1].message, e[1].code)
except EbicsVerificationError: except EbicsVerificationError:
self.note += '\n' self.note += '\n'
self.note += _("EBICS Verification Error:") self.note += _(
"EBICS Verification Error during download of "
"File Format %s (%s):"
) % (df.name, df.order_type)
self.note += '\n' self.note += '\n'
self.note += _("The EBICS response could not be verified.") self.note += _("The EBICS response could not be verified.")
except UserError as e: except UserError as e:
self.note += '\n' self.note += '\n'
self.note += _("Warning:") self.note += _(
"Warning during download of File Format %s (%s):"
) % (df.name, df.order_type)
self.note += '\n' self.note += '\n'
self.note += e.name self.note += e.name
except Exception: except Exception:
self.note += '\n' self.note += '\n'
self.note += _("Unknown Error") self.note += _(
"Unknown Error during download of File Format %s (%s):"
) % (df.name, df.order_type)
tb = ''.join(format_exception(*exc_info())) tb = ''.join(format_exception(*exc_info()))
self.note += '\n%s' % tb self.note += '\n%s' % tb
else: else:
@ -262,9 +268,7 @@ class EbicsXfer(models.TransientModel):
ef_format = self.format_id ef_format = self.format_id
OrderID = False OrderID = False
try: try:
order_type = ef_format.order_type or 'FUL' order_type = self.order_type
method = hasattr(client, order_type) \
and getattr(client, order_type)
if order_type == 'FUL': if order_type == 'FUL':
kwargs = {} kwargs = {}
# bank = self.ebics_config_id.bank_id.bank v8.0 # bank = self.ebics_config_id.bank_id.bank v8.0
@ -273,15 +277,9 @@ class EbicsXfer(models.TransientModel):
kwargs['country'] = bank.country.code kwargs['country'] = bank.country.code
if self.test_mode: if self.test_mode:
kwargs['TEST'] = 'TRUE' kwargs['TEST'] = 'TRUE'
OrderID = method(ef_format.name, upload_data, **kwargs) OrderID = client.FUL(ef_format.name, upload_data, **kwargs)
elif order_type in ['CCT', 'CDD', 'CDB']:
OrderID = method(upload_data)
elif order_type in ['XE2', 'XE3']:
OrderID = client.upload(order_type, upload_data)
else: else:
# TODO: investigate if it makes sense to support OrderID = client.upload(order_type, upload_data)
# a generic upload for a non-predefined order_type
pass
if OrderID: if OrderID:
self.note += '\n' self.note += '\n'
self.note += _( self.note += _(
@ -516,17 +514,17 @@ class EbicsXfer(models.TransientModel):
else: else:
o_list[-i] = chr(ord(c) + 1) o_list[-i] = chr(ord(c) + 1)
break break
next = ''.join(o_list) next_nr = ''.join(o_list)
if next == 'ZZZZ': if next_nr == 'ZZZZ':
next = 'A000' next_nr = 'A000'
self.ebics_config_id.order_number = next self.ebics_config_id.order_number = next_nr
def _insert_line_terminator(self, data_in, line_len): def _insert_line_terminator(self, data_in, line_len):
data_in = data_in.replace(b'\n', b'').replace(b'\r', b'') data_in = data_in.replace(b'\n', b'').replace(b'\r', b'')
data_out = b'' data_out = b''
max = len(data_in) max_len = len(data_in)
i = 0 i = 0
while i + line_len <= max: while i + line_len <= max_len:
data_out += data_in[i:i + line_len] + b'\n' data_out += data_in[i:i + line_len] + b'\n'
i += line_len i += line_len
return data_out return data_out

View File

@ -13,6 +13,7 @@
<field name="date_from"/> <field name="date_from"/>
<field name="date_to"/> <field name="date_to"/>
<field name="format_id"/> <field name="format_id"/>
<field name="order_type"/>
</group> </group>
<footer> <footer>
<button name="ebics_download" string="Download Files" type="object" class="oe_highlight"/> <button name="ebics_download" string="Download Files" type="object" class="oe_highlight"/>