Merge lp:~gs.clearcorp/openerp-costa-rica/7.0_l10n_cr_account_banking into lp:openerp-costa-rica
- 7.0_l10n_cr_account_banking
- Merge into 7.0
Proposed by
Glen Sojo
Status: | Merged |
---|---|
Merged at revision: | 252 |
Proposed branch: | lp:~gs.clearcorp/openerp-costa-rica/7.0_l10n_cr_account_banking |
Merge into: | lp:openerp-costa-rica |
Diff against target: |
823 lines (+803/-0) 4 files modified
l10n_cr_account_banking_cr_bcr/__init__.py (+24/-0) l10n_cr_account_banking_cr_bcr/__openerp__.py (+39/-0) l10n_cr_account_banking_cr_bcr/bcr_format.py (+181/-0) l10n_cr_account_banking_cr_bcr/bcr_parser.py (+559/-0) |
To merge this branch: | bzr merge lp:~gs.clearcorp/openerp-costa-rica/7.0_l10n_cr_account_banking |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
ClearCorp drivers | Pending | ||
Review via email: mp+197215@code.launchpad.net |
Commit message
Description of the change
[ADD] New module l10n_cr_
To post a comment you must log in.
- 252. By Ronald Rubi
-
[MRG] New module l10n_cr_
account_ banking_ cr_bcr intended to read and parse bank statements files for a the module account_ banking_ ccorp from openerp- ccorp-addons
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added directory 'l10n_cr_account_banking_cr_bcr' |
2 | === added file 'l10n_cr_account_banking_cr_bcr/__init__.py' |
3 | --- l10n_cr_account_banking_cr_bcr/__init__.py 1970-01-01 00:00:00 +0000 |
4 | +++ l10n_cr_account_banking_cr_bcr/__init__.py 2013-11-29 14:49:44 +0000 |
5 | @@ -0,0 +1,24 @@ |
6 | +# -*- encoding: utf-8 -*- |
7 | +############################################################################## |
8 | +# |
9 | +# Copyright (C) 2011 credativ Ltd (<http://www.credativ.co.uk>). |
10 | +# All Rights Reserved |
11 | +# |
12 | +# This program is free software: you can redistribute it and/or modify |
13 | +# it under the terms of the GNU Affero General Public License as |
14 | +# published by the Free Software Foundation, either version 3 of the |
15 | +# License, or (at your option) any later version. |
16 | +# |
17 | +# This program is distributed in the hope that it will be useful, |
18 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
20 | +# GNU Affero General Public License for more details. |
21 | +# |
22 | +# You should have received a copy of the GNU Affero General Public License |
23 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
24 | +# |
25 | +############################################################################## |
26 | + |
27 | +import bcr_format |
28 | + |
29 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
30 | |
31 | === added file 'l10n_cr_account_banking_cr_bcr/__openerp__.py' |
32 | --- l10n_cr_account_banking_cr_bcr/__openerp__.py 1970-01-01 00:00:00 +0000 |
33 | +++ l10n_cr_account_banking_cr_bcr/__openerp__.py 2013-11-29 14:49:44 +0000 |
34 | @@ -0,0 +1,39 @@ |
35 | +# -*- coding: utf-8 -*- |
36 | +############################################################################## |
37 | +# |
38 | +# OpenERP, Open Source Management Solution |
39 | +# Addons modules by CLEARCORP S.A. |
40 | +# Copyright (C) 2009-TODAY CLEARCORP S.A. (<http://clearcorp.co.cr>). |
41 | +# |
42 | +# This program is free software: you can redistribute it and/or modify |
43 | +# it under the terms of the GNU Affero General Public License as |
44 | +# published by the Free Software Foundation, either version 3 of the |
45 | +# License, or (at your option) any later version. |
46 | +# |
47 | +# This program is distributed in the hope that it will be useful, |
48 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
49 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
50 | +# GNU Affero General Public License for more details. |
51 | +# |
52 | +# You should have received a copy of the GNU Affero General Public License |
53 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
54 | +# |
55 | +############################################################################## |
56 | + |
57 | +{ |
58 | + 'name': 'BCR Account Banking', |
59 | + 'version': '0.1', |
60 | + 'license': 'AGPL-3', |
61 | + 'author': 'CLEARCORP S.A.', |
62 | + 'website': 'http://www.clearcorp.co.cr', |
63 | + 'category': 'Accounting & Finance', |
64 | + 'depends': [ |
65 | + 'account_banking_ccorp', |
66 | + ], |
67 | + 'init_xml': [], |
68 | + 'update_xml': [], |
69 | + 'demo_xml': [], |
70 | + 'description': '', |
71 | + 'active': False, |
72 | + 'installable': True, |
73 | +} |
74 | |
75 | === added file 'l10n_cr_account_banking_cr_bcr/bcr_format.py' |
76 | --- l10n_cr_account_banking_cr_bcr/bcr_format.py 1970-01-01 00:00:00 +0000 |
77 | +++ l10n_cr_account_banking_cr_bcr/bcr_format.py 2013-11-29 14:49:44 +0000 |
78 | @@ -0,0 +1,181 @@ |
79 | +# -*- coding: utf-8 -*- |
80 | +############################################################################## |
81 | +# |
82 | +# OpenERP, Open Source Management Solution |
83 | +# Addons modules by CLEARCORP S.A. |
84 | +# Copyright (C) 2009-TODAY CLEARCORP S.A. (<http://clearcorp.co.cr>). |
85 | +# |
86 | +# This program is free software: you can redistribute it and/or modify |
87 | +# it under the terms of the GNU Affero General Public License as |
88 | +# published by the Free Software Foundation, either version 3 of the |
89 | +# License, or (at your option) any later version. |
90 | +# |
91 | +# This program is distributed in the hope that it will be useful, |
92 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
93 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
94 | +# GNU Affero General Public License for more details. |
95 | +# |
96 | +# You should have received a copy of the GNU Affero General Public License |
97 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
98 | +# |
99 | +############################################################################## |
100 | + |
101 | +from account_banking_ccorp.parsers import models |
102 | +from openerp.tools.translate import _ |
103 | +from bcr_parser import BCRParser |
104 | +import re |
105 | +from openerp.osv import osv, fields |
106 | +import logging |
107 | +import pprint |
108 | +from datetime import datetime |
109 | +import base64 |
110 | + |
111 | +bt = models.mem_bank_transaction |
112 | +logger = logging.getLogger( 'bcr_mt940' ) |
113 | + |
114 | +def record2float(record, value): |
115 | + if record == 'C': |
116 | + return float (value) |
117 | + else: |
118 | + return -float(value) |
119 | + |
120 | +class transaction(models.mem_bank_transaction): |
121 | + |
122 | + mapping = { |
123 | + 'execution_date' : '', |
124 | + 'effective_date' : '', |
125 | + 'local_currency' : '', |
126 | + 'transfer_type' : '', |
127 | + 'reference' : '', |
128 | + 'message' : '', |
129 | + 'name' : '', |
130 | + 'amount': '', |
131 | + 'creditmarker': '', |
132 | + } |
133 | + |
134 | + def __init__(self, record, *args, **kwargs): |
135 | + |
136 | + ''' |
137 | + Transaction creation |
138 | + ''' |
139 | + super(transaction, self).__init__(*args, **kwargs) |
140 | + #for r in record: |
141 | + for key, value in record.iteritems(): |
142 | + if record.has_key(key): |
143 | + setattr(self, key, record[key]) |
144 | + |
145 | + if not self.is_valid(): |
146 | + logger.info("Invalid: %s", record) |
147 | + |
148 | + def is_valid(self): |
149 | + ''' |
150 | + We don't have remote_account so override base |
151 | + ''' |
152 | + return (self.execution_date |
153 | + and self.transferred_amount and True) or False |
154 | + |
155 | +class statement(models.mem_bank_statement): |
156 | + ''' |
157 | + Bank statement imported data ''' |
158 | + |
159 | + def _transmission_number(self, record): |
160 | + self.id = record['transref'] |
161 | + |
162 | + def _account_number(self, record): |
163 | + self.local_account = record['account_number'] |
164 | + |
165 | + def _statement_number(self, record): |
166 | + self.id = record['id'] |
167 | + |
168 | + def _opening_balance(self, record): |
169 | + self.start_balance = float(record['startingbalance']) |
170 | + self.local_currency = record['currencycode'] |
171 | + |
172 | + def _closing_balance(self, record): |
173 | + self.end_balance = float(record['endingbalance']) |
174 | + self.date = record['bookingdate'] |
175 | + |
176 | + def _transaction_new(self, record): |
177 | + parser = BCRParser() |
178 | + sub_record = parser.statement_lines(record) #dictionary |
179 | + for sub in sub_record: |
180 | + self.transactions.append(transaction(sub)) |
181 | + |
182 | + def _not_used(): |
183 | + logger.info("Didn't use record: %s", record) |
184 | + |
185 | + def _forward_available(self, record): |
186 | + self.end_balance = float(record['endingbalance']) |
187 | + self.date = record['bookingdate'] |
188 | + |
189 | + def _execution_date_transferred_amount (self, record): |
190 | + self.execution_date = record['bookingdate'] |
191 | + self.transferred_amount = float(record['ammount']) |
192 | + |
193 | + def transaction_info(self, record): |
194 | + ''' |
195 | + Add extra information to transaction |
196 | + ''' |
197 | + # Additional information for previous transaction |
198 | + if len(self.transactions) < 1: |
199 | + logger.info("Received additional information for non existent transaction:") |
200 | + logger.info(record) |
201 | + else: |
202 | + transaction = self.transactions[-1] |
203 | + transaction.id = ','.join([record[k] for k in ['infoline{0}'.format(i) for i in range(2,5)] if record.has_key(k)]) |
204 | + |
205 | +def raise_error(message, line): |
206 | + raise osv.osv.except_osv(_('Import error'), |
207 | + 'Error in import:%s\n\n%s' % (message, line)) |
208 | + |
209 | +class parser_bcr_mt940( models.parser ): |
210 | + code = 'BCR-MT940' |
211 | + name = _( 'BCR statement import' ) |
212 | + country_code = 'CR' |
213 | + doc = _('''\ |
214 | + This format is available through |
215 | + the BCR web interface. |
216 | + ''') |
217 | + |
218 | + def parse(self, cr, statements_file, **kwargs): |
219 | + |
220 | + ''' |
221 | + ** Kwargs parameter is used for a dynamic list of parameters. |
222 | + The wizard imported extracts used in all parsers and not all parsers have all the necessary information in your file, |
223 | + so get information from the wizard and passed by the ** kwargs. |
224 | + Then in the parses that are needed, are extracted from the ** kwargs and if needed, |
225 | + the parser still works the same way without this parameter. |
226 | + |
227 | + The rest of the methods must receive this parameter. (As the method that parse the header and the lines). |
228 | + ''' |
229 | + |
230 | + result = [] |
231 | + parser = BCRParser() |
232 | + stmnt = statement() |
233 | + |
234 | + """ |
235 | + **kwargs have all the parameters that have the wizard and |
236 | + has all the parameters passed from the wizard before calling |
237 | + the method that parses the file. |
238 | + """ |
239 | + |
240 | + #pass to encoding with the correct type of file. |
241 | + data = base64.decodestring(statements_file) |
242 | + |
243 | + records = parser.parse_stamenent_record(data,**kwargs) |
244 | + |
245 | + stmnt._transmission_number(records) |
246 | + stmnt._account_number(records) |
247 | + stmnt._statement_number(records) |
248 | + stmnt._opening_balance(records) |
249 | + stmnt._closing_balance(records) |
250 | + stmnt._forward_available(records) |
251 | + stmnt._execution_date_transferred_amount (records) |
252 | + stmnt._transaction_new(data) |
253 | + |
254 | + if stmnt.is_valid(): |
255 | + result.append(stmnt) |
256 | + |
257 | + return result |
258 | + |
259 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
260 | |
261 | === added file 'l10n_cr_account_banking_cr_bcr/bcr_parser.py' |
262 | --- l10n_cr_account_banking_cr_bcr/bcr_parser.py 1970-01-01 00:00:00 +0000 |
263 | +++ l10n_cr_account_banking_cr_bcr/bcr_parser.py 2013-11-29 14:49:44 +0000 |
264 | @@ -0,0 +1,559 @@ |
265 | +# -*- coding: utf-8 -*- |
266 | +############################################################################## |
267 | +# |
268 | +# OpenERP, Open Source Management Solution |
269 | +# Addons modules by CLEARCORP S.A. |
270 | +# Copyright (C) 2009-TODAY CLEARCORP S.A. (<http://clearcorp.co.cr>). |
271 | +# |
272 | +# This program is free software: you can redistribute it and/or modify |
273 | +# it under the terms of the GNU Affero General Public License as |
274 | +# published by the Free Software Foundation, either version 3 of the |
275 | +# License, or (at your option) any later version. |
276 | +# |
277 | +# This program is distributed in the hope that it will be useful, |
278 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
279 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
280 | +# GNU Affero General Public License for more details. |
281 | +# |
282 | +# You should have received a copy of the GNU Affero General Public License |
283 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
284 | +# |
285 | +############################################################################## |
286 | +""" |
287 | +Parser for BCR format files |
288 | +""" |
289 | +import re |
290 | +from datetime import datetime |
291 | +from dateutil import parser |
292 | +from pprint import PrettyPrinter |
293 | +from copy import copy |
294 | +from openerp.tools.translate import _ |
295 | +from openerp.osv import osv, fields |
296 | + |
297 | +class BCRParser( object ): |
298 | + """ |
299 | + Para noviembre de 2012 se cambia el formato del archivo del BCR. Se cambia el encabezado del archivo |
300 | + así como el final del mismo. Además en la parte de abajo cambia el formato y visualización de los |
301 | + saldos finales. |
302 | + |
303 | + El cambio más evidente es el formato de la cuenta de banco, pasa de 1-246447-0 a 001-0246447-0 |
304 | + Revisión # 1 Revisión#2 |
305 | + Encabezado anterior: Encabezado nuevo |
306 | + BANCO DE COSTA RICA BANCO DE COSTA RICA |
307 | + Movimiento de Cuenta Corriente 1-246447-0 Colones (puede ser Dólares o Dolares) MOVIMIENTO DE LA CUENTA CORRIENTE No. 001-0246447-0 COLONES (DOLARES) |
308 | + Dueño: COMPA IA INMOBILIARIA CENTROA DUENO: COMPA IA INMOBILIARIA CENTROAMERICANA CICCR S |
309 | + Movimiento realizado el periodo del 01-10-2012 al 31-10-2012 MOVIMIENTO REALIZADO DEL 01-11-2012 AL 30-11-2012 |
310 | + |
311 | + Final de archivo |
312 | + Revisión # 1 Revisión #2 |
313 | + TOTALES DEL MOVIMIENTO CONTABILIZADO TOTALES DEL MOVIMIENTO CONTABILIZADO |
314 | + Cantidad -------Monto-------- CANTIDAD -------MONTO-------- |
315 | + Débitos 239 81,876,681.22 DEBITOS 209 67,553,414.30 |
316 | + Créditos 27 92,636,599.01 CREDITOS 8 66,086,326.53 |
317 | + |
318 | + Saldo Inicial 21,682,799.04 -------- SALDOS -------- |
319 | + Saldo Final 33,992,829.43 INICIAL 33,992,829.43 |
320 | + FINAL 32,525,741.66 |
321 | + Solicitado el 01/11/2012 20:03:34 SOLICITADO EL 01-12-2012 A LAS 15:36:15:17 |
322 | + """ |
323 | + def statement_record ( self, rec, **kwargs): |
324 | + lines = [] |
325 | + line_dict = {} |
326 | + |
327 | + line_dict = { |
328 | + 'transref': 0.0, # _transmission_number |
329 | + 'account_number': '', #_account_number |
330 | + 'statementnr':'', # statement_number |
331 | + 'startingbalance': 0.0, #_opening_balance |
332 | + 'currencycode': 'CRC', #currencycode |
333 | + 'endingbalance': 0.0, #_closing_balance |
334 | + 'bookingdate': '', #moving_date |
335 | + 'ammount': 0.0, |
336 | + 'id': '', |
337 | + } |
338 | + |
339 | + cad = '' |
340 | + list_split = rec.split('\r\n') |
341 | + account_number_wizard = kwargs['account_number'] |
342 | + |
343 | + #If return True, the account are the same. |
344 | + if self.match_account(list_split, account_number_wizard): |
345 | + for l in list_split: |
346 | + #_account_number -> FIRST REVISION |
347 | + if l.find('Movimiento de Cuenta Corriente', 0, len('Movimiento de Cuenta Corriente')) > -1: |
348 | + line_dict['account_number'] = self.extract_number(l) |
349 | + |
350 | + if (l.find('D',0,len(l)) > -1): |
351 | + line_dict['currencycode'] = 'USD' |
352 | + else: |
353 | + line_dict['currencycode'] = 'CRC' |
354 | + |
355 | + #_account_number -> SECOND REVISION |
356 | + elif (l.find('MOVIMIENTO DE LA CUENTA CORRIENTE No.', 0, len('MOVIMIENTO DE LA CUENTA CORRIENTE No.')) > -1): |
357 | + account_str = self.extract_number(l) |
358 | + #001-0246447-0 |
359 | + account_1 = account_str[2:3] #1 |
360 | + account_2 = account_str[4:] #246447-0 |
361 | + account_complete = account_1+self.extract_number(account_2)#12464470 |
362 | + line_dict['account_number'] = self.extract_number(account_complete) |
363 | + if (l.find('DOLARES',0,len(l)) > -1): |
364 | + line_dict['currencycode'] = 'USD' |
365 | + else: |
366 | + line_dict['currencycode'] = 'CRC' |
367 | + |
368 | + # _transmission_number -> FIRST REVISION |
369 | + if (l.find('Movimiento realizado el periodo', 0, len('Movimiento realizado el periodo')) > -1): |
370 | + line_dict['statementnr'] = self.extract_number(l) |
371 | + date_1 = self.extract_date_regular_expresion_line_format_2(l,0) |
372 | + date_2 = self.extract_date_regular_expresion_line_format_2(l,1) |
373 | + |
374 | + # _transmission_number -> SECOND REVISION |
375 | + elif (l.find('MOVIMIENTO REALIZADO', 0, len('MOVIMIENTO REALIZADO')) > -1): |
376 | + line_dict['statementnr'] = self.extract_number(l) |
377 | + date_1 = self.extract_date_regular_expresion_line_format_2(l,0) |
378 | + date_2 = self.extract_date_regular_expresion_line_format_2(l,1) |
379 | + |
380 | + #date and hour -> FIRST REVISION |
381 | + if (l.find('Solicitado el', 0, len('Solicitado el')) > -1): |
382 | + date = hour = cad = '' |
383 | + date = self.extract_date_regular_expresion(l) |
384 | + if len(date) > 0: |
385 | + hour = self.extract_hour_regular_expresion(l) |
386 | + cad = date + ' ' + hour |
387 | + line_dict['transref'] = cad |
388 | + line_dict['bookingdate'] = cad |
389 | + |
390 | + #date and hour -> SECOND REVISION |
391 | + elif (l.find('SOLICITADO EL', 0, len('SOLICITADO EL')) > -1): |
392 | + date = hour = cad = '' |
393 | + date = self.extract_date_regular_expresion(l) |
394 | + if len(date) > 0: |
395 | + hour = self.extract_hour_regular_expresion(l) |
396 | + cad = date + ' ' + hour |
397 | + line_dict['transref'] = cad |
398 | + line_dict['bookingdate'] = cad |
399 | + |
400 | + #_opening_balance -> FIRST REVISION |
401 | + if l.find('Saldo Inicial', 0, len('Saldo Inicial')) > -1: |
402 | + line_dict['startingbalance'] = self.extract_float(l) |
403 | + #_opening_balance -> SECOND REVISION |
404 | + elif l.find('INICIAL', 0, len('INICIAL')) > -1: |
405 | + line_dict['startingbalance'] = self.extract_float(l) |
406 | + |
407 | + #_closing_balance -> FIRST REVISION |
408 | + if l.find('FINAL', 0, len('FINAL')) > -1: |
409 | + line_dict['endingbalance'] = self.extract_float(l) |
410 | + |
411 | + #_closing_balance -> SECOND REVISION |
412 | + elif l.find('Saldo Final', 0, len('Saldo Final')) > -1: |
413 | + line_dict['endingbalance'] = self.extract_float(l) |
414 | + |
415 | + line_dict['ammount'] = float( line_dict['startingbalance'] ) + float( line_dict['endingbalance'] ) |
416 | + line_dict['id'] = date_1 + ' - ' + date_2 + ' Extracto BCR ' + line_dict['account_number'] |
417 | + self.line_dict = line_dict |
418 | + |
419 | + return line_dict |
420 | + |
421 | + else: |
422 | + raise osv.except_osv(_('Error'), |
423 | + _('Error en la importación! La cuenta especificada en el archivo no coincide con la seleccionada en el asistente de importacion')) |
424 | + |
425 | + def statement_lines ( self, rec): |
426 | + parser = BCRParser() |
427 | + mapping = { |
428 | + 'execution_date' : '', |
429 | + 'effective_date' : '', |
430 | + 'local_currency' : '', |
431 | + 'transfer_type' : '', |
432 | + 'reference' : '', |
433 | + 'message' : '', |
434 | + 'name' : '', |
435 | + 'transferred_amount': '', |
436 | + 'creditmarker': '', |
437 | + } |
438 | + line_dict = {} |
439 | + currencycode = '' |
440 | + |
441 | + list_split = rec.split('\r\n') |
442 | + entrada = False |
443 | + start = 0 |
444 | + end = 0 |
445 | + version = 'none' |
446 | + |
447 | + #========= Start and end of lines ======# |
448 | + for l in list_split: |
449 | + if l.find('TOTALES DEL MOVIMIENTO CONTABILIZADO', 0, len('TOTALES DEL MOVIMIENTO CONTABILIZADO')) <= -1: |
450 | + end += 1 |
451 | + else: |
452 | + break |
453 | + end = end - 1 |
454 | + |
455 | + for l in list_split: |
456 | + if l.find('-CONTABLE-', 0, len('-CONTABLE-')) <= -1: |
457 | + start += 1 |
458 | + else: |
459 | + break |
460 | + start += 1 |
461 | + |
462 | + for l in list_split: |
463 | + if l.find('Movimiento de Cuenta Corriente', 0, len('Movimiento de Cuenta Corriente')) > -1: |
464 | + if (l.find('D',0,len(l)) > -1): |
465 | + currencycode = 'USD' |
466 | + else: |
467 | + currencycode = 'CRC' |
468 | + break |
469 | + |
470 | + elif l.find('MOVIMIENTO DE LA CUENTA CORRIENTE No.', 0, len('MOVIMIENTO DE LA CUENTA CORRIENTE No.')) > -1: |
471 | + if (l.find('DOLARES',0,len(l)) > -1): |
472 | + currencycode = 'USD' |
473 | + else: |
474 | + currencycode = 'CRC' |
475 | + break |
476 | + |
477 | + #========= VERSION OF THREE COLUMNS FOR DEBIT AND CREDIT =============# |
478 | + sub_list = list_split [start:end] |
479 | + |
480 | + if len(sub_list) > 0: |
481 | + sub_first = sub_list[0] #Based in first line, decide which version it is |
482 | + |
483 | + #1. Try separate by tab ('\t') (last version) (fields must have, at least, more than 1 of length) |
484 | + fields = sub_first.split('\t') |
485 | + |
486 | + if len(fields) > 1: |
487 | + version = 'third_version' |
488 | + |
489 | + #2. Find where start debit and credit columns |
490 | + else: |
491 | + amount = sub_first[106:] |
492 | + debit = amount[0:16] |
493 | + |
494 | + debit = debit.replace(',','') |
495 | + debit = debit.replace('.','') |
496 | + debit = re.sub(r'\s', '', debit) |
497 | + |
498 | + if re.match('^[0-9,.]*$', debit): |
499 | + version = 'first_version' |
500 | + |
501 | + else: |
502 | + amount = sub_first[120:] |
503 | + debit = amount[0:40] |
504 | + |
505 | + debit = debit.replace(',','') |
506 | + debit = debit.replace('.','') |
507 | + debit = re.sub(r'\s', '', debit) |
508 | + |
509 | + if re.match('^[0-9,.]*$', debit): |
510 | + version = 'second_version' |
511 | + |
512 | + #=====================================================================# |
513 | + |
514 | + if version != 'none': |
515 | + if version =='first_version': |
516 | + return self.first_version_file(sub_list,mapping,currencycode,parser) |
517 | + |
518 | + elif version == 'second_version': |
519 | + return self.second_version(sub_list,mapping,currencycode,parser) |
520 | + |
521 | + elif version == 'third_version': |
522 | + return self.third_version(sub_list,mapping,currencycode,parser) |
523 | + |
524 | + else: |
525 | + raise osv.except_osv(_('Error'), |
526 | + _('There is not format implementend for this file.')) |
527 | + |
528 | + else: |
529 | + return [] |
530 | + |
531 | + def parse_stamenent_record( self, rec, **kwargs): |
532 | + |
533 | + matchdict = dict() |
534 | + |
535 | + matchdict = self.statement_record( rec, **kwargs ); |
536 | + |
537 | + # Remove members set to None |
538 | + matchdict = dict( [( k, v ) for k, v in matchdict.iteritems() if v] ) |
539 | + |
540 | + matchkeys = set( matchdict.keys() ) |
541 | + needstrip = set( [ 'transref', 'account_number', 'statementnr', 'currencycode', 'endingbalance', 'bookingdate'] ) |
542 | + |
543 | + for field in matchkeys & needstrip: |
544 | + matchdict[field] = matchdict[field].strip() |
545 | + |
546 | + # Convert to float. Comma is decimal separator |
547 | + needsfloat = set( ["startingbalance", "endingbalance", "amount"] ) |
548 | + for field in matchkeys & needsfloat: |
549 | + matchdict[field] = float( matchdict[field].replace( ',', '.' ) ) |
550 | + |
551 | + # Convert date fields |
552 | + needdate = set( ["bookingdate"] ) |
553 | + |
554 | + for field in matchkeys & needdate: |
555 | + datestring = matchdict[field] |
556 | + date = self.extract_date_regular_expresion(datestring) |
557 | + hour = self.extract_hour_regular_expresion(datestring) |
558 | + |
559 | + date_complete = date + ' ' + hour |
560 | + try: |
561 | + #FORMAT DATE REVISION # 1 |
562 | + date_obj= datetime.strptime(date_complete, "%d/%m/%Y %H:%M:%S") |
563 | + except: |
564 | + #FORMAT DATE REVISION # 2 |
565 | + date_obj= datetime.strptime(date_complete, "%d-%m-%Y %H:%M:%S") |
566 | + matchdict[field] = date_obj |
567 | + |
568 | + return matchdict |
569 | + |
570 | + #=============================Auxiliary methods =============================# |
571 | + |
572 | + #=====================Versions of file |
573 | + |
574 | + def first_version_file(self, sub_list,mapping,currencycode,parser): |
575 | + lines = [] |
576 | + for sub in sub_list: |
577 | + #effective_date |
578 | + date_str = '' |
579 | + date_str = self.extract_date_regular_expresion_line(sub,0) |
580 | + date= datetime.strptime(date_str, "%d-%m-%y") |
581 | + mapping['effective_date'] = date #fecha_contable. |
582 | + |
583 | + #execution_date |
584 | + date_str = self.extract_date_regular_expresion_line(sub,1) |
585 | + date = datetime.strptime(date_str, "%d-%m-%y") |
586 | + mapping['execution_date'] = date #fecha_movimiento |
587 | + |
588 | + mapping['local_currency'] = currencycode |
589 | + mapping['transfer_type'] = 'NTRF' |
590 | + mapping['reference'] = parser.extract_number(sub[18:26]) |
591 | + mapping['message'] = sub[27:80] |
592 | + mapping['name'] = sub[27:80] |
593 | + mapping['id'] = sub[27:80] |
594 | + |
595 | + amount = sub[106:] |
596 | + amount.replace('\t',' ') |
597 | + debit = amount[0:16] |
598 | + credit = amount[16:] |
599 | + |
600 | + if (parser.extract_float(debit) is not ''): #debit |
601 | + cad = parser.extract_float(debit) |
602 | + mapping['transferred_amount'] = -float(cad) |
603 | + mapping['creditmarker'] = 'C' |
604 | + |
605 | + else: #credit |
606 | + cad = parser.extract_float (credit) |
607 | + mapping['transferred_amount'] = float(cad) |
608 | + |
609 | + lines.append(copy(mapping)) |
610 | + |
611 | + return lines |
612 | + |
613 | + def second_version (self, sub_list,mapping,currencycode,parser): |
614 | + lines = [] |
615 | + for sub in sub_list: |
616 | + #effective_date |
617 | + date_str = '' |
618 | + date_str = self.extract_date_regular_expresion_line(sub,0) |
619 | + date= datetime.strptime(date_str, "%d-%m-%y") |
620 | + mapping['effective_date'] = date #fecha_contable. |
621 | + |
622 | + #execution_date |
623 | + date_str = self.extract_date_regular_expresion_line(sub,1) |
624 | + date = datetime.strptime(date_str, "%d-%m-%y") |
625 | + mapping['execution_date'] = date #fecha_movimiento |
626 | + |
627 | + mapping['local_currency'] = currencycode |
628 | + mapping['transfer_type'] = 'NTRF' |
629 | + mapping['reference'] = parser.extract_number(sub[18:26]) |
630 | + mapping['message'] = sub[27:80] |
631 | + mapping['name'] = sub[27:80] |
632 | + mapping['id'] = sub[27:80] |
633 | + |
634 | + amount = sub[120:] |
635 | + amount.replace('\t',' ') |
636 | + debit = amount[0:40] |
637 | + credit = amount[40:] |
638 | + |
639 | + if (parser.extract_float(debit) is not ''): #debit |
640 | + cad = parser.extract_float(debit) |
641 | + mapping['transferred_amount'] = -float(cad) |
642 | + mapping['creditmarker'] = 'C' |
643 | + |
644 | + else: #credit |
645 | + cad = parser.extract_float (credit) |
646 | + mapping['transferred_amount'] = float(cad) |
647 | + |
648 | + lines.append(copy(mapping)) |
649 | + |
650 | + return lines |
651 | + |
652 | + def third_version(self, sub_list,mapping,currencycode,parser): |
653 | + lines = [] |
654 | + for l in sub_list: |
655 | + fields = l.split('\t') |
656 | + |
657 | + #effective_date |
658 | + date_str = fields[0] |
659 | + date= datetime.strptime(date_str, "%d-%m-%y") |
660 | + mapping['effective_date'] = date #fecha_contable. |
661 | + |
662 | + #execution_date |
663 | + date_str = fields[1] |
664 | + date = datetime.strptime(date_str, "%d-%m-%y") |
665 | + mapping['execution_date'] = date #fecha_movimiento |
666 | + |
667 | + mapping['local_currency'] = currencycode |
668 | + mapping['transfer_type'] = 'NTRF' |
669 | + mapping['reference'] = parser.extract_number(fields[2]) |
670 | + mapping['message'] = fields[3] |
671 | + mapping['name'] = fields[3] |
672 | + mapping['id'] = fields[3] |
673 | + |
674 | + #Extract debit and credit |
675 | + debit = fields[5] |
676 | + if (parser.extract_float(debit) is not ''): #debit |
677 | + cad = parser.extract_float(debit) |
678 | + mapping['transferred_amount'] = -float(cad) |
679 | + mapping['creditmarker'] = 'C' |
680 | + |
681 | + else: #credit |
682 | + credit = fields[6] |
683 | + cad = parser.extract_float(credit) |
684 | + mapping['transferred_amount'] = float(cad) |
685 | + |
686 | + lines.append(copy(mapping)) |
687 | + |
688 | + return lines |
689 | + |
690 | + #=============================================================== |
691 | + def extract_number( self, account_number ): |
692 | + cad = '' |
693 | + result = re.findall(r'[0-9]+', account_number) |
694 | + |
695 | + for character in result: |
696 | + cad = cad + character |
697 | + return cad |
698 | + |
699 | + def extract_float ( self, amount ): |
700 | + cad = '' |
701 | + result = re.findall(r"[-+]?\d*\.\d+|\d+",amount) |
702 | + |
703 | + for character in result: |
704 | + cad = cad + character |
705 | + return cad |
706 | + |
707 | + def extract_date_regular_expresion(self, date): |
708 | + cad = '' |
709 | + result = [] |
710 | + date_string = '' |
711 | + #re.findall('[0-9]{1,2}-[0-9]{1,2}-[0-9]{4}',str)[0]+' '+re.findall('[0-9]{2}:[0-9]{2}:[0-9]{2}',str)[0] |
712 | + #FORMAT DATE FIRST REVISION |
713 | + result = re.findall('[0-9]{1,2}/[0-9]{1,2}/[0-9]{4}', date) |
714 | + |
715 | + if len(result) == 0: |
716 | + #FORMAT DATE SECOND REVISION |
717 | + result = re.findall('[0-9]{1,2}-[0-9]{1,2}-[0-9]{4}',date) |
718 | + |
719 | + for character in result: |
720 | + cad = cad + character |
721 | + return cad |
722 | + |
723 | + #with the pos parameter is said which of the two dates must be brought |
724 | + #result brings a list of two elements, the post tells us to choose |
725 | + def extract_date_regular_expresion_line(self, date, pos): |
726 | + cad = '' |
727 | + result = [] |
728 | + date_string = '' |
729 | + result = re.findall('([0-9]{2}-[0-9]{2}-[0-9]{2})[\s]*',date) |
730 | + date_str = result[pos] |
731 | + |
732 | + for character in date_str: |
733 | + cad = cad + character |
734 | + return cad |
735 | + |
736 | + #with the pos parameter is said which of the two dates must be brought |
737 | + #result brings a list of two elements, the post tells us to choose |
738 | + def extract_date_regular_expresion_line_format_2(self, date, pos): |
739 | + cad = '' |
740 | + result = [] |
741 | + date_string = '' |
742 | + result = re.findall('([0-9]{2}-[0-9]{2}-[0-9]{4})[\s]*',date) |
743 | + date_str = result[pos] |
744 | + |
745 | + for character in date_str: |
746 | + cad = cad + character |
747 | + return cad |
748 | + |
749 | + def extract_hour_regular_expresion(self, date): |
750 | + cad = '' |
751 | + result = [] |
752 | + |
753 | + result = re.findall('[0-9]{2}:[0-9]{2}:[0-9]{2}',date) |
754 | + |
755 | + for character in result: |
756 | + cad = cad + character |
757 | + return cad |
758 | + |
759 | + def extract_currency_code_USD(self, currency): |
760 | + cad = '' |
761 | + result = re.findall('[D.lares]',currency) |
762 | + for character in result: |
763 | + cad = cad + character |
764 | + return cad |
765 | + |
766 | + def parse( self, cr, data ): |
767 | + records = [] |
768 | + # Some records are multiline |
769 | + for line in data: |
770 | + if len(line) <= 1: |
771 | + continue |
772 | + if line[0] == ':' and len(line) > 1: |
773 | + records.append(line) |
774 | + else: |
775 | + records[-1] = '\n'.join([records[-1], line]) |
776 | + |
777 | + output = [] |
778 | + |
779 | + for rec in records: |
780 | + output.append( self.parse_stamenent_record( rec ) ) |
781 | + |
782 | + return output |
783 | + |
784 | + #check if the account_number in the file match with the selected in the wizard. |
785 | + def match_account(self, list_split, account_number_wizard): |
786 | + accnumber = '' |
787 | + for l in list_split: |
788 | + #_account_number -> FIRST REVISION |
789 | + if l.find('Movimiento de Cuenta Corriente', 0, len('Movimiento de Cuenta Corriente')) > -1: |
790 | + accnumber = self.extract_number(l) |
791 | + break |
792 | + |
793 | + #_account_number -> SECOND REVISION |
794 | + elif (l.find('MOVIMIENTO DE LA CUENTA CORRIENTE No.', 0, len('MOVIMIENTO DE LA CUENTA CORRIENTE No.')) > -1): |
795 | + account_str = self.extract_number(l) |
796 | + #001-0246447-0 |
797 | + account_1 = account_str[2:3] #1 |
798 | + account_2 = account_str[4:] #246447-0 |
799 | + account_complete = account_1+self.extract_number(account_2)#12464470 |
800 | + accnumber = self.extract_number(account_complete) |
801 | + break |
802 | + |
803 | + #If return True, the account_number in the wizard and the account in the file are the same. |
804 | + if accnumber.find(account_number_wizard) > -1: |
805 | + return True |
806 | + else: |
807 | + return False |
808 | + |
809 | + |
810 | +def parse_file( filename ): |
811 | + bacfile = open( filename, "r" ) |
812 | + p = BCRParser().parse(bacfile.readlines()) |
813 | + |
814 | +def main(): |
815 | + """The main function, currently just calls a dummy filename |
816 | + |
817 | + :returns: description |
818 | + """ |
819 | + parse_file("testfile") |
820 | + |
821 | +if __name__ == '__main__': |
822 | + main() |
823 | + |