Browse Source

Add module for imports of Romanian BRD bank in MT940.

pull/69/head
Fekete Mihai 9 years ago
parent
commit
cb0cff591e
  1. 65
      account_bank_statement_import_mt940_ro_brd/README.rst
  2. 5
      account_bank_statement_import_mt940_ro_brd/__init__.py
  3. 20
      account_bank_statement_import_mt940_ro_brd/__openerp__.py
  4. 28
      account_bank_statement_import_mt940_ro_brd/account_bank_statement_import.py
  5. 26
      account_bank_statement_import_mt940_ro_brd/demo/demo_data.xml
  6. 143
      account_bank_statement_import_mt940_ro_brd/mt940.py
  7. 17
      account_bank_statement_import_mt940_ro_brd/test_files/test-brd.940
  8. 5
      account_bank_statement_import_mt940_ro_brd/tests/__init__.py
  9. 18
      account_bank_statement_import_mt940_ro_brd/tests/test_import_bank_statement.py

65
account_bank_statement_import_mt940_ro_brd/README.rst

@ -0,0 +1,65 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:alt: License: AGPL-3
Import MT940 ROMANIAN BRD Bank Statements
=========================================
This module allows you to import the MT940 files from the Romanian BRD bank
in Odoo as bank statements.
Installation
============
To install this module, you need to:
* clone the branch 8.0 of the repository https://github.com/OCA/bank-statement-import
* add the path to this repository in your configuration (addons-path)
* update the module list
* search for "MT940 BRD Format Bank Statements Import" in your addons
* install the module
Known issues / Roadmap
======================
* None
Usage
=====
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/174/8.0
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/bank-statement-import/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed feedback
`here <https://github.com/OCA/bank-statement-import/issues/new?body=module:%20account_bank_statement_import_mt940_ro_brd%0Aversion:%208.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Credits
=======
Contributors
------------
* Fekete Mihai <feketemihai@gmail.com>
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit http://odoo-community.org.
This module should make it easy to migrate bank statement import
modules written for earlies versions of Odoo/OpenERP.

5
account_bank_statement_import_mt940_ro_brd/__init__.py

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# © 2016 Forest and Biomass Services Romania
# See README.rst file on addons root folder for license details
from . import account_bank_statement_import

20
account_bank_statement_import_mt940_ro_brd/__openerp__.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# © 2016 Forest and Biomass Services Romania
# See README.rst file on addons root folder for license details
{
'name': 'MT940 BRD Format Bank Statements Import',
'version': '8.0.0.1.0',
'license': 'AGPL-3',
'author': 'Forest and Biomass Services Romania, '
'Odoo Community Association (OCA)',
'website': 'https://www.forbiom.eu',
'website': 'www.forbiom.eu',
'category': 'Banking addons',
'depends': [
'account_bank_statement_import_mt940_base'
],
'demo': [
'demo/demo_data.xml',
],
'installable': True,
}

28
account_bank_statement_import_mt940_ro_brd/account_bank_statement_import.py

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# © 2016 Forest and Biomass Services Romania
# See README.rst file on addons root folder for license details
import logging
from openerp import models, api
from .mt940 import MT940Parser as Parser
_logger = logging.getLogger(__name__)
class AccountBankStatementImport(models.TransientModel):
"""Add parsing of mt940 files to bank statement import."""
_inherit = 'account.bank.statement.import'
def _parse_file(self, cr, uid, data_file, context=None):
"""Parse a MT940 IBAN BRD file."""
parser = Parser()
try:
_logger.debug("Try parsing with MT940 IBAN BRD.")
return parser.parse(data_file)
except ValueError:
# Returning super will call next candidate:
_logger.debug("Statement file was not a MT940 IBAN BRD file.",
exc_info=True)
return super(AccountBankStatementImport, self)._parse_file(
cr, uid, data_file, context=context)

26
account_bank_statement_import_mt940_ro_brd/demo/demo_data.xml

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="mt940_brd_bank_journal" model="account.journal">
<field name="name">Bank Journal - (test mt940 BRD)</field>
<field name="code">TBNKMT940BRD</field>
<field name="type">bank</field>
<field name="sequence_id" ref="account.sequence_bank_journal"/>
<field name="default_debit_account_id" ref="account.bnk"/>
<field name="default_credit_account_id" ref="account.bnk"/>
<field name="user_id" ref="base.user_root"/>
</record>
<record id="mt940_brd_company_bank" model="res.partner.bank">
<field name="owner_name">Your Company</field>
<field name="acc_number">RO56BRDE360SV52474653600</field>
<field name="partner_id" ref="base.partner_root"></field>
<field name="company_id" ref="base.main_company"></field>
<field name="journal_id" ref="mt940_brd_bank_journal"></field>
<field name="state">bank</field>
<field name="bank" ref="base.res_bank_1"/>
</record>
</data>
</openerp>

143
account_bank_statement_import_mt940_ro_brd/mt940.py

@ -0,0 +1,143 @@
# -*- coding: utf-8 -*-
# © 2016 Forest and Biomass Services Romania
# See README.rst file on addons root folder for license details
import re
from datetime import datetime
from openerp.addons.account_bank_statement_import_mt940_base.mt940 import (
MT940, str2amount)
def get_counterpart(transaction, subfield):
"""Get counterpart from transaction.
Counterpart is often stored in subfield of tag 86. The subfield
can be 31, 32, 33"""
if not subfield:
return # subfield is empty
if len(subfield) >= 1 and subfield[0]:
transaction.remote_account = subfield[0]
if len(subfield) >= 2 and subfield[1]:
transaction.remote_owner = subfield[1]
if len(subfield) >= 3 and subfield[2]:
transaction.remote_owner_tin = subfield[2]
def get_subfields(data, codewords):
"""Return dictionary with value array for each codeword in data.
For instance:
data =
000+20TRANSACTIONTYPE+30BANKTRANSACTIONNUMBER+31PARTNERBANKACCOUNT
+32PARTNER+33CUI/CNPTIN
+23TRANSACTIONMESSAGE1+24TRANSACTIONMESSAGE2
+25TRANSACTIONMESSAGE3+26TRANSACTIONMESSAGE4
+27TRANSACTIONMESSAGE5
+61PARTNERADDRESS1+62PARTNERADDRESS2
codewords = ['20', '23', '24', '25', '26', '27',
'30', '31', '32', '33', '61', '62']
!!! NOT ALL CODEWORDS ARE PRESENT !!!
Then return subfields = {
'20': [TRANSACTIONTYPE],
'30': [BANKTRANSACTIONNUMBER],
'31': [PARTNERBANKACCOUNT],
'32': [PARTNER],
'33': [TIN],
'23': [TRANSACTIONMESSAGE1],
'24': [TRANSACTIONMESSAGE2],
'25': [TRANSACTIONMESSAGE3],
'26': [TRANSACTIONMESSAGE4],
'27': [TRANSACTIONMESSAGE5],
'61': [PARTNERADDRESS1],
'62': [PARTNERADDRESS2],
}
"""
subfields = {}
current_codeword = None
for word in data.split('+'):
if not word and not current_codeword:
continue
if word[:2] in codewords:
current_codeword = word[:2]
subfields[current_codeword] = [word[2:]]
continue
if current_codeword in subfields:
subfields[current_codeword].append(word[2:])
return subfields
def handle_common_subfields(transaction, subfields):
"""Deal with common functionality for tag 86 subfields."""
# Get counterpart from 31, 32 or 33 subfields:
counterpart_fields = []
for counterpart_field in ['31', '32', '33']:
if counterpart_field in subfields:
new_value = subfields[counterpart_field][0].replace('CUI/CNP', '')
counterpart_fields.append(new_value)
else:
counterpart_fields.append('')
if counterpart_fields:
get_counterpart(transaction, counterpart_fields)
# REMI: Remitter information (text entered by other party on trans.):
transaction.message = ''
for counterpart_field in ['23', '24', '25', '26', '27']:
if counterpart_field in subfields:
transaction.message += (
'/'.join(x for x in subfields[counterpart_field] if x))
# Get transaction reference subfield (might vary):
if transaction.eref in subfields:
transaction.eref = ''.join(
subfields[transaction.eref])
class MT940Parser(MT940):
"""Parser for ing MT940 bank statement import files."""
tag_61_regex = re.compile(
r'^(?P<date>\d{6})(?P<line_date>\d{0,4})'
r'(?P<sign>[CD])(?P<amount>\d+,\d{2})N(?P<type>.{3})'
r'(?P<reference>\w{1,50})'
)
def __init__(self):
"""Initialize parser - override at least header_regex."""
super(MT940Parser, self).__init__()
self.mt940_type = 'BRD'
self.header_lines = 1 # Number of lines to skip
# Do not user $ for end of string below: line contains much
# more data than just the first line.
self.header_regex = '^:20:' # Start of relevant data
def handle_tag_25(self, data):
"""Local bank account information."""
data = data.replace('.', '').strip()
self.current_statement.local_account = data
def handle_tag_28(self, data):
"""Number of BRD bank statement."""
stmt = self.current_statement
stmt.statement_id = data.replace('.', '').strip()
def handle_tag_61(self, data):
"""get transaction values"""
super(MT940Parser, self).handle_tag_61(data)
re_61 = self.tag_61_regex.match(data)
if not re_61:
raise ValueError("Cannot parse %s" % data)
parsed_data = re_61.groupdict()
self.current_transaction.transferred_amount = (
str2amount(parsed_data['sign'], parsed_data['amount']))
self.current_transaction.eref = parsed_data['reference']
def handle_tag_86(self, data):
"""Parse 86 tag containing reference data."""
if not self.current_transaction:
return
codewords = ['20', '23', '24', '25', '26', '27',
'30', '31', '32', '33', '61', '62']
subfields = get_subfields(data, codewords)
transaction = self.current_transaction
# If we have no subfields, set message to whole of data passed:
if not subfields:
transaction.message = data
else:
handle_common_subfields(transaction, subfields)
# Prevent handling tag 86 later for non transaction details:
self.current_transaction = None

17
account_bank_statement_import_mt940_ro_brd/test_files/test-brd.940

@ -0,0 +1,17 @@
:20:6450374100
:25:RO56BRDE360SV52474653600
:28:00138/1
:60F:C160517EUR3885,24
:61:1605170517D210,60NTRFOPH478
PLATA FACT 4603309
:86:000+20Plata +30302410000+31RO89RZBR0000060003480121
+32RUSSMEDIA PRESS SRL+33/
+23PLATA FACT 4603309
:61:1605170517D2,76NCOMOPH478
25-Comision MULTIX
:86:000+20Comision
+2325-Comision MULTIX
:62F:C160517EUR3671,88
:64:C160517EUR3671,88
:86:Credit neutilizat la 17/05/2016: 0,00 \
Sume blocate la 17/05/2016: 0,00

5
account_bank_statement_import_mt940_ro_brd/tests/__init__.py

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# © 2016 Forest and Biomass Services Romania
# See README.rst file on addons root folder for license details
from . import test_import_bank_statement

18
account_bank_statement_import_mt940_ro_brd/tests/test_import_bank_statement.py

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
# © 2016 Forest and Biomass Services Romania
# See README.rst file on addons root folder for license details
from openerp.addons.account_bank_statement_import.tests import (
TestStatementFile)
class TestImport(TestStatementFile):
"""Run test to import MT940 ING import."""
def test_statement_import(self):
"""Test correct creation of single statement."""
self._test_statement_import(
'account_bank_statement_import_mt940_ro_brd', 'test-brd.940',
'00138/1',
start_balance=3885.24, end_balance=3671.88
)
Loading…
Cancel
Save