Merge lp:~therp-nl/banking-addons/6.1-abnamro_process_sepa_feedback_string into lp:banking-addons/6.1

Proposed by Stefan Rijnhart (Opener)
Status: Merged
Merged at revision: 147
Proposed branch: lp:~therp-nl/banking-addons/6.1-abnamro_process_sepa_feedback_string
Merge into: lp:banking-addons/6.1
Diff against target: 165 lines (+77/-15)
3 files modified
account_banking/banking_import_transaction.py (+2/-1)
account_banking/wizard/banktools.py (+1/-2)
account_banking_nl_abnamro/abnamro.py (+74/-12)
To merge this branch: bzr merge lp:~therp-nl/banking-addons/6.1-abnamro_process_sepa_feedback_string
Reviewer Review Type Date Requested Status
Guewen Baconnier @ Camptocamp Approve
Review via email: mp+128696@code.launchpad.net
To post a comment you must log in.
142. By Stefan Rijnhart (Opener)

[RFR] SEPA message string parts is known to contain its own separator

143. By Stefan Rijnhart (Opener)

[RFR] Improve parsing of GIRO transactions feedback string

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

Looks good to me

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'account_banking/banking_import_transaction.py'
2--- account_banking/banking_import_transaction.py 2012-05-07 11:38:26 +0000
3+++ account_banking/banking_import_transaction.py 2012-10-27 19:56:21 +0000
4@@ -1319,7 +1319,8 @@
5 transaction.remote_owner,
6 transaction.remote_owner_address,
7 transaction.remote_owner_city,
8- country_code, results['log']
9+ country_code, results['log'],
10+ bic=transaction.remote_bank_bic
11 )
12 partner_banks = partner_bank_obj.browse(
13 cr, uid, [partner_bank_id]
14
15=== modified file 'account_banking/wizard/banktools.py'
16--- account_banking/wizard/banktools.py 2012-06-26 11:17:32 +0000
17+++ account_banking/wizard/banktools.py 2012-10-27 19:56:21 +0000
18@@ -318,7 +318,7 @@
19
20 def create_bank_account(pool, cursor, uid, partner_id,
21 account_number, holder_name, address, city,
22- country_code, log
23+ country_code, log, bic=False,
24 ):
25 '''
26 Create a matching bank account with this holder for this partner.
27@@ -328,7 +328,6 @@
28 owner_name = holder_name,
29 )
30 bankcode = None
31- bic = None
32 country_obj = pool.get('res.country')
33
34 # Are we dealing with IBAN?
35
36=== modified file 'account_banking_nl_abnamro/abnamro.py'
37--- account_banking_nl_abnamro/abnamro.py 2012-01-17 08:48:10 +0000
38+++ account_banking_nl_abnamro/abnamro.py 2012-10-27 19:56:21 +0000
39@@ -88,6 +88,7 @@
40 'GIRO': bt.ORDER,
41 'INTL': bt.ORDER, # international order
42 'UNKN': bt.ORDER, # everything else
43+ 'SEPA': bt.ORDER,
44 }
45
46 def __init__(self, line, *args, **kwargs):
47@@ -134,24 +135,70 @@
48 size = 33
49 res = []
50 while(len(line) > col * size):
51- if line[col * size : (col + 1) * size - 1].strip():
52- res.append(line[col * size : (col + 1) * size - 1])
53+ separation = (col + 1) * size - 1
54+ if line[col * size : separation].strip():
55+ part = line[col * size : separation]
56+ # If the separation character is not a space, add it anyway
57+ # presumably for sepa feedback strings only
58+ if (len(line) > separation
59+ and line[separation] != ' '):
60+ part += line[separation]
61+ res.append(part)
62 col += 1
63 return res
64
65+ def get_sepa_dict(field):
66+ """
67+ Parses a subset of SEPA feedback strings as occur
68+ in this non-SEPA csv format.
69+
70+ The string consists of slash separated KEY/VALUE pairs,
71+ but the slash is allowed to and known to occur in VALUE as well!
72+ """
73+ items = field[1:].split('/') # skip leading slash
74+ sepa_dict = {}
75+ prev_key = False
76+ known_keys = ['TRTP', 'IBAN', 'BIC', 'NAME', 'RTRN', 'EREF',
77+ 'SWOC', 'REMI', ]
78+ while items:
79+ if len(items) == 1:
80+ raise osv.except_osv(
81+ _('Error !'),
82+ _("unable to parse SEPA string: %s") % field)
83+ key = items.pop(0)
84+ if key not in known_keys:
85+ # either an unknown key or a value containing a slash
86+ if prev_key:
87+ sepa_dict[prev_key] = sepa_dict[prev_key] + '/' + key
88+ else:
89+ raise osv.except_osv(
90+ _('Error !'),
91+ _("unable to parse SEPA string: %s") % field)
92+ else:
93+ sepa_dict[key] = items.pop(0).strip()
94+ prev_key = key
95+ return sepa_dict
96+
97 def parse_type(field):
98 # here we process the first field, which identifies the statement type
99 # and in case of certain types contains additional information
100 transfer_type = 'UNKN'
101 remote_account = False
102 remote_owner = False
103- if field.startswith('GIRO '):
104+ if field.startswith('/TRTP/'):
105+ transfer_type = 'SEPA'
106+ elif field.startswith('GIRO '):
107 transfer_type = 'GIRO'
108- # columns 6 to 14 contain the left or right aligned account number
109- remote_account = field[:15].strip().zfill(10)
110- # column 15 contains a space
111- # columns 16 to 31 contain remote owner
112- remote_owner = field[16:32].strip() or False
113+ # field has markup 'GIRO ACCOUNT OWNER'
114+ # separated by clusters of space of varying size
115+ account_match = re.match('\s*([0-9]+)\s(.*)$', field[5:])
116+ if account_match:
117+ remote_account = account_match.group(1).zfill(10)
118+ remote_owner = account_match.group(2).strip() or ''
119+ else:
120+ raise osv.except_osv(
121+ _('Error !'),
122+ _('unable to parse GIRO string: %s') % field)
123 elif field.startswith('BEA '):
124 transfer_type = 'BEA'
125 # columns 6 to 16 contain the terminal identifier
126@@ -176,8 +223,22 @@
127 fields = split_blob(self.blob)
128 (self.transfer_type, self.remote_account, self.remote_owner) = parse_type(fields[0])
129
130+ if self.transfer_type == 'SEPA':
131+ sepa_dict = get_sepa_dict(''.join(fields))
132+ sepa_type = sepa_dict.get('TRTP')
133+ if sepa_type != 'SEPA OVERBOEKING':
134+ raise ValueError,_('Sepa transaction type %s not handled yet')
135+ self.remote_account = sepa_dict.get('IBAN',False)
136+ self.remote_bank_bic = sepa_dict.get('BIC', False)
137+ self.remote_owner = sepa_dict.get('NAME', False)
138+ self.reference = sepa_dict.get('REMI', '')
139+
140 # extract other information depending on type
141- if self.transfer_type == 'GIRO':
142+ elif self.transfer_type == 'GIRO':
143+ if not self.remote_owner and len(fields) > 1:
144+ # OWNER is listed in the second field if not in the first
145+ self.remote_owner = fields[1].strip() or False
146+ fields = [fields[0]] + fields[2:]
147 self.message = ' '.join(field.strip() for field in fields[1:])
148
149 elif self.transfer_type == 'BEA':
150@@ -219,11 +280,12 @@
151 if not self.reference:
152 # the reference is sometimes flagged by the prefix "BETALINGSKENM."
153 # but can be any numeric line really
154- refexpr = re.compile("^\s*(BETALINGSKENM\.)?\s*([0-9]+ ?)+\s*$")
155 for field in fields[1:]:
156- m = refexpr.match(field)
157+ m = re.match(
158+ "^\s*((BETALINGSKENM\.)|(ACCEPTGIRO))?\s*([0-9]+([ /][0-9]+)*)\s*$",
159+ field)
160 if m:
161- self.reference = m.group(2)
162+ self.reference = m.group(4)
163 break
164
165 class statement(models.mem_bank_statement):

Subscribers

People subscribed via source and target branches