← Back to team overview

clearcorp team mailing list archive

lp:~dr.clearcorp/openerp-costa-rica/6.1-l10n_cr_account_banking_cr_bncr_lafise into lp:openerp-costa-rica/6.1

 

Diana Rodríguez Martínez has proposed merging lp:~dr.clearcorp/openerp-costa-rica/6.1-l10n_cr_account_banking_cr_bncr_lafise into lp:openerp-costa-rica/6.1.

Requested reviews:
  CLEARCORP drivers (clearcorp-drivers)

For more details, see:
https://code.launchpad.net/~dr.clearcorp/openerp-costa-rica/6.1-l10n_cr_account_banking_cr_bncr_lafise/+merge/153401

[ADD] Add two new modules to parser files for the BN and Lafise Bank
-- 
https://code.launchpad.net/~dr.clearcorp/openerp-costa-rica/6.1-l10n_cr_account_banking_cr_bncr_lafise/+merge/153401
Your team CLEARCORP development team is subscribed to branch lp:openerp-costa-rica/6.1.
=== modified file 'l10n_cr_account_banking_cr_bac/bac_mt940.py'
--- l10n_cr_account_banking_cr_bac/bac_mt940.py	2013-02-22 22:35:48 +0000
+++ l10n_cr_account_banking_cr_bac/bac_mt940.py	2013-03-14 16:05:24 +0000
@@ -22,12 +22,13 @@
 #
 
 from account_banking.parsers import models
-from tools.translate import _
 from mt940_parser import BACParser
 import re
-import osv
+from osv import osv, fields
 import logging
 import datetime
+from tools.translate import _
+import base64
 
 bt = models.mem_bank_transaction
 logger = logging.getLogger('bac_mt940')
@@ -155,8 +156,8 @@
             This format is available through
             the BAC web interface.
             ''')
-
-    def parse(self, cr, data,**kwargs):
+    
+    def parse(self, cr, statements_file,**kwargs):
         '''
             ** Kwargs parameter is used for a dynamic list of parameters. 
             The wizard imported extracts used in all parsers and not all parsers have all the necessary information in your file, 
@@ -171,91 +172,112 @@
         list_record = []
         inversion_colocada = 0
         
+        """
+            **kwargs have all the parameters that have the wizard and 
+            has all the parameters passed from the wizard before calling 
+            the method that parses the file.            
+        """        
+        #pass to encoding with the correct type of file.        
+        data = base64.decodestring(statements_file)
+    
         # Split into statements
         statements = [st for st in re.split('[\r\n]*(?=:20:)', data)]
         # Split by records
         statement_list = [re.split('[\r\n ]*(?=:\d\d[\w]?:)', st) for st in statements]
-
-        for statement_lines in statement_list:
-            stmnt = statement()
-            
-            """EXTRACCION DE DATOS """
-            for record in statement_lines:               
-                records = parser.parse_record(record)
-
-                if records is not None:
-                    ############START PAGO CAPITAL INVERSION
-                    if records['recordid'] == '60F':
-                        start_balance = float(records['startingbalance'])
-                    if records['recordid'] == '61':
-                        amount = float(records['amount'])
-                    if records['recordid'] == '86' and records['infoline1'] == 'PAGO CAPITAL INVERSION':
-                        start_amount = amount
-                        start_balance += amount #con la suma ya realizada.
-                    ############END PAGO CAPITAL INVERSION
-                    
-                    ############START INVERSION COLOCADA
-                    if records['recordid'] == '86':
-                        cad = records['infoline1']
-                        if cad.find('INVERSION COLOCADA') > 0:
-                            inversion_colocada = amount
-                            
-                    if records['recordid'] == '62F':                                         
-                        ending_balance = (inversion_colocada + float(records['endingbalance']))
-
-            if records is not None:            
-                """ACTUALIZACION DE DATOS """
-                for record in statement_lines:   
-                    if record is not None:             
-                        records = parser.parse_record(record)    
+        
+        '''
+            In the first position of the statement_list is the account number.
+            If the account number that pass in the **kwargs dictionary.                
+        '''
+        account_number_wizard = kwargs['account_number']
+        #statement_list is a list, extract the first position 
+        accnum = statement_list[1][1]    
+        
+        #find the number in the account string.
+        if accnum.find(account_number_wizard) > -1:
+            for statement_lines in statement_list:
+                stmnt = statement()
                 
-                        if (records['recordid'] == '60F'):
-                            dic = {'startingbalance':start_balance}
-                            records.update(dic)
+                """EXTRACCION DE DATOS """
+                for record in statement_lines:               
+                    records = parser.parse_record(record,**kwargs)
+    
+                    if records is not None:
+                        ############START PAGO CAPITAL INVERSION
+                        if records['recordid'] == '60F':
+                            start_balance = float(records['startingbalance'])
+                        if records['recordid'] == '61':
+                            amount = float(records['amount'])
+                        if records['recordid'] == '86' and records['infoline1'] == 'PAGO CAPITAL INVERSION':
+                            start_amount = amount
+                            start_balance += amount #con la suma ya realizada.
+                        ############END PAGO CAPITAL INVERSION
                         
-                        if (records['recordid'] == '62F'):
-                            dic = {'endingbalance': ending_balance}
-                            records.update(dic)
-
-                        if (records['recordid'] == '64'):
-                            dic = {'endingbalance': ending_balance}
-                            records.update(dic)
-                            
-                        #SI LA LINEA NO ES INVERSION COLOCADA O PAGO CAPITAL INVERSION, SE AGREGA A LA LISTA
-                        #PAGO_CAPITAL
-                        if (records['recordid'] == '86'):
+                        ############START INVERSION COLOCADA
+                        if records['recordid'] == '86':
                             cad = records['infoline1']
-                            
-                            if (cad != "PAGO CAPITAL INVERSION") and (cad.find("INVERSION COLOCADA") < 0): 
-                                list_record.append(records)
-                                
-                        if (records['recordid'] == '61'):
-                            try:
-                                if float(records['amount']) != start_amount and float(records['amount']) != inversion_colocada:
-                                    list_record.append(records)
-                            except:
-                                list_record.append(records)
-                        #####################################################################
-                        
-                        if (records['recordid'] != '61' and records['recordid'] != '86' ):
-                            list_record.append(records)                
-                
-                [stmnt.import_record(r) for r in list_record if r is not None]
-                
-                if stmnt.is_valid():
-                    result.append(stmnt)
-                    list_record = []
-                    inversion_colocada = 0
-                    start_balance = 0
-                else:
-                    logger.info("Invalid Statement:")
-                    logger.info(records[0])
-                    logger.info(records[1])
-                    logger.info(records[2])
-                    logger.info(records[3])
-                    logger.info(records[4])
-                    list_record = []
-
-        return result
-
+                            if cad.find('INVERSION COLOCADA') > 0:
+                                inversion_colocada = amount
+                                
+                        if records['recordid'] == '62F':                                         
+                            ending_balance = (inversion_colocada + float(records['endingbalance']))
+    
+                if records is not None:            
+                    """ACTUALIZACION DE DATOS """
+                    for record in statement_lines:   
+                        if record is not None:             
+                            records = parser.parse_record(record)    
+                    
+                            if (records['recordid'] == '60F'):
+                                dic = {'startingbalance':start_balance}
+                                records.update(dic)
+                            
+                            if (records['recordid'] == '62F'):
+                                dic = {'endingbalance': ending_balance}
+                                records.update(dic)
+    
+                            if (records['recordid'] == '64'):
+                                dic = {'endingbalance': ending_balance}
+                                records.update(dic)
+                                
+                            #SI LA LINEA NO ES INVERSION COLOCADA O PAGO CAPITAL INVERSION, SE AGREGA A LA LISTA
+                            #PAGO_CAPITAL
+                            if (records['recordid'] == '86'):
+                                cad = records['infoline1']
+                                
+                                if (cad != "PAGO CAPITAL INVERSION") and (cad.find("INVERSION COLOCADA") < 0): 
+                                    list_record.append(records)
+                                    
+                            if (records['recordid'] == '61'):
+                                try:
+                                    if float(records['amount']) != start_amount and float(records['amount']) != inversion_colocada:
+                                        list_record.append(records)
+                                except:
+                                    list_record.append(records)
+                            #####################################################################
+                            
+                            if (records['recordid'] != '61' and records['recordid'] != '86' ):
+                                list_record.append(records)                
+                    
+                    [stmnt.import_record(r) for r in list_record if r is not None]
+                    
+                    if stmnt.is_valid():
+                        result.append(stmnt)
+                        list_record = []
+                        inversion_colocada = 0
+                        start_balance = 0
+                    else:
+                        logger.info("Invalid Statement:")
+                        logger.info(records[0])
+                        logger.info(records[1])
+                        logger.info(records[2])
+                        logger.info(records[3])
+                        logger.info(records[4])
+                        list_record = []
+            return result
+        
+        else:
+            raise osv.except_osv(_('Error'),
+                        _('Error en la importación! La cuenta especificada en el archivo no coincide con la seleccionada en el asistente de importacion'))
+        
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== modified file 'l10n_cr_account_banking_cr_bcr/__init__.py' (properties changed: +x to -x)
=== modified file 'l10n_cr_account_banking_cr_bcr/__openerp__.py' (properties changed: +x to -x)
=== modified file 'l10n_cr_account_banking_cr_bcr/bcr_format.py' (properties changed: +x to -x)
--- l10n_cr_account_banking_cr_bcr/bcr_format.py	2013-02-22 22:35:48 +0000
+++ l10n_cr_account_banking_cr_bcr/bcr_format.py	2013-03-14 16:05:24 +0000
@@ -24,10 +24,11 @@
 from tools.translate import _
 from bcr_parser import BCRParser
 import re
-import osv
+from osv import osv, fields
 import logging
 import pprint
 from datetime import datetime
+import base64
 
 bt = models.mem_bank_transaction
 logger = logging.getLogger( 'bcr_mt940' )
@@ -138,8 +139,8 @@
             This format is available through
             the BCR  web interface.
             ''')
-
-    def parse(self, cr, data, **kwargs):
+    
+    def parse(self, cr, statements_file, **kwargs):
         
         '''
             ** Kwargs parameter is used for a dynamic list of parameters. 
@@ -155,7 +156,16 @@
         parser = BCRParser()
         stmnt = statement()
         
-        records = parser.parse_stamenent_record(data)        
+        """
+            **kwargs have all the parameters that have the wizard and 
+            has all the parameters passed from the wizard before calling 
+            the method that parses the file.            
+        """        
+
+        #pass to encoding with the correct type of file.
+        data = base64.decodestring(statements_file)
+    
+        records = parser.parse_stamenent_record(data,**kwargs)        
         
         stmnt._transmission_number(records)
         stmnt._account_number(records)
@@ -168,7 +178,7 @@
                   
         if stmnt.is_valid():
             result.append(stmnt)
-                      
+            
         return result
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== modified file 'l10n_cr_account_banking_cr_bcr/bcr_parser.py'
--- l10n_cr_account_banking_cr_bcr/bcr_parser.py	2013-02-22 22:35:48 +0000
+++ l10n_cr_account_banking_cr_bcr/bcr_parser.py	2013-03-14 16:05:24 +0000
@@ -27,6 +27,8 @@
 from dateutil import parser
 from pprint import PrettyPrinter
 from copy import copy
+from tools.translate import _
+from osv import osv, fields
 
 class BCRParser( object ):
     """
@@ -72,75 +74,83 @@
 
         cad = ''
         list_split = rec.split('\r\n')
-
-        for l in list_split:
-            
-            # _transmission_number -> FIRST REVISION
-            if (l.find('Movimiento realizado el periodo', 0, len('Movimiento realizado el periodo')) > -1):
-                line_dict['statementnr'] = self.extract_number(l)
-            # _transmission_number -> SECOND REVISION
-            elif (l.find('MOVIMIENTO REALIZADO', 0, len('MOVIMIENTO REALIZADO')) > -1):
-                line_dict['statementnr'] = self.extract_number(l)   
-                           
-            #_account_number -> FIRST REVISION
-            if l.find('Movimiento de Cuenta Corriente', 0, len('Movimiento de Cuenta Corriente')) > -1:
-                line_dict['account_number'] = self.extract_number(l)                
-                if (l.find('D',0,len(l)) > -1):
-                    line_dict['currencycode'] = 'USD'
-                else:
-                    line_dict['currencycode'] = 'CRC'
-            #_account_number -> SECOND REVISION        
-            elif (l.find('MOVIMIENTO DE LA CUENTA  CORRIENTE No.', 0, len('MOVIMIENTO DE LA CUENTA  CORRIENTE No.')) > -1):
-                account_str = self.extract_number(l)   
-                #001-0246447-0
-                account_1 = account_str[2:3] #1
-                account_2 = account_str[4:]  #246447-0
-                account_complete = account_1+self.extract_number(account_2)#12464470
-                line_dict['account_number'] = self.extract_number(account_complete)
-                if (l.find('DOLARES',0,len(l)) > -1):
-                    line_dict['currencycode'] = 'USD'
-                else:
-                    line_dict['currencycode'] = 'CRC'                      
-             
-            #FECHA Y HORA -> FIRST REVISION 
-            if (l.find('Solicitado el', 0, len('Solicitado el'))  > -1):
-                date =  hour = cad = ''
-                date = self.extract_date_regular_expresion(l)
-                if len(date) > 0:                   
-                    hour = self.extract_hour_regular_expresion(l)
-                cad = date + ' ' + hour                
-                line_dict['transref'] = cad
-                line_dict['bookingdate'] = cad
-            #FECHA Y HORA -> SECOND REVISION 
-            elif (l.find('SOLICITADO EL', 0, len('SOLICITADO EL'))  > -1):
-                date =  hour = cad = ''
-                date = self.extract_date_regular_expresion(l)
-                if len(date) > 0:                   
-                    hour = self.extract_hour_regular_expresion(l)
-                cad = date + ' ' + hour                
-                line_dict['transref'] = cad
-                line_dict['bookingdate'] = cad        
-                               
-            #_opening_balance -> FIRST REVISION
-            if l.find('Saldo Inicial', 0, len('Saldo Inicial'))  > -1:
-                line_dict['startingbalance'] = self.extract_float(l)
-            #_opening_balance -> SECOND REVISION   
-            elif l.find('INICIAL', 0, len('INICIAL'))  > -1:
-                line_dict['startingbalance'] = self.extract_float(l)
-                    
-            #_closing_balance -> FIRST REVISION
-            if l.find('FINAL', 0, len('FINAL'))  > -1:
-                line_dict['endingbalance'] = self.extract_float(l)
-            #_closing_balance -> SECOND REVISION    
-            elif l.find('Saldo Final', 0, len('Saldo Final'))  > -1:
-                line_dict['endingbalance'] = self.extract_float(l)
-                    
-        line_dict['ammount'] = float( line_dict['startingbalance'] ) + float( line_dict['endingbalance'] )
-        line_dict['id'] = line_dict['bookingdate'] + ' - ' + line_dict['account_number']
-        self.line_dict = line_dict
-      
-        return line_dict
-            
+        account_number_wizard = kwargs['account_number']
+        
+        #If return True, the account are the same.
+        if self.match_account(list_split, account_number_wizard):        
+            for l in list_split:            
+                 #_account_number -> FIRST REVISION
+                if l.find('Movimiento de Cuenta Corriente', 0, len('Movimiento de Cuenta Corriente')) > -1:
+                    line_dict['account_number'] = self.extract_number(l)                
+                    
+                    if (l.find('D',0,len(l)) > -1):
+                        line_dict['currencycode'] = 'USD'
+                    else:
+                        line_dict['currencycode'] = 'CRC'
+                        
+                #_account_number -> SECOND REVISION        
+                elif (l.find('MOVIMIENTO DE LA CUENTA  CORRIENTE No.', 0, len('MOVIMIENTO DE LA CUENTA  CORRIENTE No.')) > -1):
+                    account_str = self.extract_number(l)   
+                    #001-0246447-0
+                    account_1 = account_str[2:3] #1
+                    account_2 = account_str[4:]  #246447-0
+                    account_complete = account_1+self.extract_number(account_2)#12464470
+                    line_dict['account_number'] = self.extract_number(account_complete)
+                    if (l.find('DOLARES',0,len(l)) > -1):
+                        line_dict['currencycode'] = 'USD'
+                    else:
+                        line_dict['currencycode'] = 'CRC'
+                
+                # _transmission_number -> FIRST REVISION
+                if (l.find('Movimiento realizado el periodo', 0, len('Movimiento realizado el periodo')) > -1):
+                    line_dict['statementnr'] = self.extract_number(l)
+                # _transmission_number -> SECOND REVISION
+                elif (l.find('MOVIMIENTO REALIZADO', 0, len('MOVIMIENTO REALIZADO')) > -1):
+                    line_dict['statementnr'] = self.extract_number(l)                          
+                                     
+                #FECHA Y HORA -> FIRST REVISION 
+                if (l.find('Solicitado el', 0, len('Solicitado el'))  > -1):
+                    date =  hour = cad = ''
+                    date = self.extract_date_regular_expresion(l)
+                    if len(date) > 0:                   
+                        hour = self.extract_hour_regular_expresion(l)
+                    cad = date + ' ' + hour                
+                    line_dict['transref'] = cad
+                    line_dict['bookingdate'] = cad
+                #FECHA Y HORA -> SECOND REVISION 
+                elif (l.find('SOLICITADO EL', 0, len('SOLICITADO EL'))  > -1):
+                    date =  hour = cad = ''
+                    date = self.extract_date_regular_expresion(l)
+                    if len(date) > 0:                   
+                        hour = self.extract_hour_regular_expresion(l)
+                    cad = date + ' ' + hour                
+                    line_dict['transref'] = cad
+                    line_dict['bookingdate'] = cad        
+                                   
+                #_opening_balance -> FIRST REVISION
+                if l.find('Saldo Inicial', 0, len('Saldo Inicial'))  > -1:
+                    line_dict['startingbalance'] = self.extract_float(l)
+                #_opening_balance -> SECOND REVISION   
+                elif l.find('INICIAL', 0, len('INICIAL'))  > -1:
+                    line_dict['startingbalance'] = self.extract_float(l)
+                        
+                #_closing_balance -> FIRST REVISION
+                if l.find('FINAL', 0, len('FINAL'))  > -1:
+                    line_dict['endingbalance'] = self.extract_float(l)
+                #_closing_balance -> SECOND REVISION    
+                elif l.find('Saldo Final', 0, len('Saldo Final'))  > -1:
+                    line_dict['endingbalance'] = self.extract_float(l)
+                        
+            line_dict['ammount'] = float( line_dict['startingbalance'] ) + float( line_dict['endingbalance'] )
+            line_dict['id'] = line_dict['bookingdate'] + ' - ' + line_dict['account_number']
+            self.line_dict = line_dict
+          
+            return line_dict
+        
+        else:
+            raise osv.except_osv(_('Error'),
+                        _('Error en la importación! La cuenta especificada en el archivo no coincide con la seleccionada en el asistente de importacion'))
+        
     def statement_lines ( self, rec ):
         parser = BCRParser()
         mapping = {
@@ -349,10 +359,36 @@
             output.append( self.parse_stamenent_record( rec ) )
                 
         return output
+    
+    #check if the account_number in the file match with the selected in the wizard.
+    def match_account(self, list_split, account_number_wizard):
+        accnumber = ''
+        for l in list_split:            
+             #_account_number -> FIRST REVISION
+            if l.find('Movimiento de Cuenta Corriente', 0, len('Movimiento de Cuenta Corriente')) > -1:
+                accnumber = self.extract_number(l)                
+                break
+            
+             #_account_number -> SECOND REVISION        
+            elif (l.find('MOVIMIENTO DE LA CUENTA  CORRIENTE No.', 0, len('MOVIMIENTO DE LA CUENTA  CORRIENTE No.')) > -1):
+                account_str = self.extract_number(l)   
+                #001-0246447-0
+                account_1 = account_str[2:3] #1
+                account_2 = account_str[4:]  #246447-0
+                account_complete = account_1+self.extract_number(account_2)#12464470
+                accnumber = self.extract_number(account_complete)         
+                break
+        
+        #If return True, the account_number in the wizard and the account in the file are the same.
+        if accnumber.find(account_number_wizard) > -1:
+            return True
+        else:
+            return False
+    
 
 def parse_file( filename ):
     bacfile = open( filename, "r" )
-    p = BCRParser().parse( bacfile.readlines() )
+    p = BCRParser().parse(bacfile.readlines())
 
 def main():
     """The main function, currently just calls a dummy filename

=== added directory 'l10n_cr_account_banking_cr_bncr'
=== added file 'l10n_cr_account_banking_cr_bncr/__init__.py'
--- l10n_cr_account_banking_cr_bncr/__init__.py	1970-01-01 00:00:00 +0000
+++ l10n_cr_account_banking_cr_bncr/__init__.py	2013-03-14 16:05:24 +0000
@@ -0,0 +1,24 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+#    Copyright (C) 2011 credativ Ltd (<http://www.credativ.co.uk>).
+#    All Rights Reserved
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import bncr_format
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== added file 'l10n_cr_account_banking_cr_bncr/__openerp__.py'
--- l10n_cr_account_banking_cr_bncr/__openerp__.py	1970-01-01 00:00:00 +0000
+++ l10n_cr_account_banking_cr_bncr/__openerp__.py	2013-03-14 16:05:24 +0000
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Addons modules by CLEARCORP S.A.
+#    Copyright (C) 2009-TODAY CLEARCORP S.A. (<http://clearcorp.co.cr>).
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+{
+    'name': 'National Bank Account Banking',
+    'version': '0.5',
+    'license': 'AGPL-3',
+    'author': 'CLEARCORP S.A.',
+    'website': 'http://www.clearcorp.co.cr',
+    'category': 'Account Banking',
+    'depends': ['account_banking'],
+    'init_xml': [],
+    'update_xml': [],
+    'demo_xml': [],
+    'description': '',
+    'active': False,
+    'installable': True,
+}

=== added file 'l10n_cr_account_banking_cr_bncr/bncr_format.py'
--- l10n_cr_account_banking_cr_bncr/bncr_format.py	1970-01-01 00:00:00 +0000
+++ l10n_cr_account_banking_cr_bncr/bncr_format.py	2013-03-14 16:05:24 +0000
@@ -0,0 +1,188 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Addons modules by CLEARCORP S.A.
+#    Copyright (C) 2009-TODAY CLEARCORP S.A. (<http://clearcorp.co.cr>).
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from account_banking.parsers import models
+from tools.translate import _
+from bncr_parser import BNCRParser
+import re
+from osv import osv, fields
+import logging
+import pprint
+from datetime import datetime
+import base64
+
+bt = models.mem_bank_transaction
+logger = logging.getLogger( 'bncr_logger' )
+
+class transaction(models.mem_bank_transaction):
+
+    mapping = {
+        'execution_date' : '',
+        'effective_date' : '',
+        'local_currency' : '',
+        'transfer_type' : '',
+        'reference' : '',
+        'message' : '',
+        'name' : '',
+        'amount': '',
+        'creditmarker': '',
+    }
+
+    def __init__(self, record, *args, **kwargs):
+        
+        '''
+        Transaction creation
+        '''
+        #record is a dictionary, that is the reason to use iteritems().
+        super(transaction, self).__init__(*args, **kwargs)
+        for key, value in record.iteritems():
+            if record.has_key(key):
+                setattr(self, key, record[key])
+
+        if not self.is_valid():
+            logger.info("Invalid: %s", record)
+    
+    def is_valid(self):
+        '''
+        We don't have remote_account so override base
+        '''
+        return (self.execution_date
+                and self.transferred_amount and True) or False
+
+class statement(models.mem_bank_statement):
+    '''
+    Bank statement imported data    '''
+      
+    def _transmission_number(self, record):
+        self.id = record['transref']
+    
+    def _account_number(self, record):
+        self.local_account = record['account_number']
+
+    def _statement_number(self, record):
+        self.id = record['id']
+        
+    def _opening_balance(self, record):
+        self.start_balance = float(record['startingbalance'])
+    
+    def _closing_balance(self, record):
+        self.end_balance = float(record['endingbalance'])
+        self.date = record['bookingdate']
+     
+    def _transaction_new(self, record):
+        parser = BNCRParser()
+        sub_record = parser.statement_lines(record) #dictionary
+        for sub in sub_record:
+            self.transactions.append(transaction(sub))
+
+    def _not_used():
+        logger.info("Didn't use record: %s", record)
+        
+    def _forward_available(self, record):
+        self.end_balance =  float(record['endingbalance'])
+        self.date = record['bookingdate'] 
+    
+    def _execution_date_transferred_amount (self, record):        
+        self.execution_date = record['bookingdate']       
+        self.transferred_amount = float(record['ammount'])
+
+    def transaction_info(self, record):
+        '''
+        Add extra information to transaction
+        '''
+        # Additional information for previous transaction
+        if len(self.transactions) < 1:
+            logger.info("Received additional information for non existent transaction:")
+            logger.info(record)
+        else:
+            transaction = self.transactions[-1]
+            transaction.id = ','.join([record[k] for k in ['infoline{0}'.format(i) for i in range(2,5)] if record.has_key(k)])
+
+def raise_error(message, line):
+    raise osv.osv.except_osv(_('Import error'),
+        'Error in import:%s\n\n%s' % (message, line))
+
+class parser_bncr( models.parser ):
+    
+    '''
+        This adds a new parser in the selection options. 
+        When the account is associated to a parser, the following code makes it appear as an option
+    '''
+    code = 'BNCR-Parser'
+    name = _( 'BNCR Bank statement import' )
+    country_code = 'CR'
+    doc = _('''\
+            This format is available through
+            the National Bank  web interface.
+            ''')
+    
+    '''
+        ** Kwargs parameter is used for a dynamic list of parameters. 
+        The wizard imported extracts used in all parsers and not all parsers have all the necessary information in your file, 
+        so get information from the wizard and passed by the ** kwargs. 
+        Then in the parses that are needed, are extracted from the ** kwargs and if needed, 
+        the parser still works the same way without this parameter.
+        
+        The rest of the methods must receive this parameter. (As the method that parse the header and the lines). 
+        
+        If you need a new parameter, you specify its name and value, using the ** kwargs is a dictionary, 
+        extract its value, with the respective key
+    '''
+
+    def parse(self, cr, statements_file, **kwargs):
+        result = []
+        parser = BNCRParser()
+        stmnt = statement()
+        
+        """
+            **kwargs have all the parameters that have the wizard and 
+            has all the parameters passed from the wizard before calling 
+            the method that parses the file.            
+        """        
+        #try:            
+        #pass to encoding with the correct type of file.
+        data = base64.decodestring(statements_file)        
+    
+        records = parser.parse_stamenent_record(data,**kwargs)
+        
+        stmnt._transmission_number(records)
+        stmnt._account_number(records)
+        stmnt._statement_number(records)
+        stmnt._opening_balance(records)
+        stmnt._closing_balance(records)
+        stmnt._forward_available(records)
+        stmnt._execution_date_transferred_amount (records)
+        stmnt._transaction_new(data)#call the method statement_lines in parser to parse all the lines in file and add to stament.
+                  
+        '''
+        A stament must have a header and transacctions. The method parse_stamenent_record parse the header and the 
+        method _transaction_new parse all the line (transactions) in the file. 
+        '''
+        if stmnt.is_valid():
+            result.append(stmnt)
+                  
+        return result
+        '''
+        except:
+            raise osv.except_osv(_('Error'), _('The file have a invalid extension for this parser.\nThe valid extension are .txt or .csv'))
+        '''
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== added file 'l10n_cr_account_banking_cr_bncr/bncr_parser.py'
--- l10n_cr_account_banking_cr_bncr/bncr_parser.py	1970-01-01 00:00:00 +0000
+++ l10n_cr_account_banking_cr_bncr/bncr_parser.py	2013-03-14 16:05:24 +0000
@@ -0,0 +1,259 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Addons modules by CLEARCORP S.A.
+#    Copyright (C) 2009-TODAY CLEARCORP S.A. (<http://clearcorp.co.cr>).
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+"""
+Parser for Davivienda format files
+"""
+import re
+from datetime import datetime
+from dateutil import parser
+from pprint import PrettyPrinter
+from copy import copy
+
+class BNCRParser( object ):
+    
+    #Define the header for the extract to import.
+    '''
+     ** Kwargs parameter is used for a dynamic list of parameters. 
+        The wizard imported extracts used in all parsers and not all parsers have all the necessary information in your file, 
+        so get information from the wizard and passed by the ** kwargs. 
+        Then in the parses that are needed, are extracted from the ** kwargs and if needed, 
+        the parser still works the same way without this parameter.
+        
+        The rest of the methods must receive this parameter. (As the method that parse the header and the lines). 
+        
+        If you need a new parameter, you specify its name and value, using the ** kwargs is a dictionary, 
+        extract its value, with the respective key
+    '''
+    def statement_record ( self, rec, **kwargs):
+        lines = []
+        line_dict = {}
+        startingbalance = 0.0
+
+        line_dict = {
+            'transref': '', # _transmission_number
+            'account_number': '', #_account_number
+            'statementnr':'', # statement_number
+            'startingbalance': 0.0, #_opening_balance
+            'currencycode': '', #currencycode
+            'endingbalance': 0.0, #_closing_balance
+            'bookingdate': '', #moving_date
+            'ammount': 0.0,
+            'id': '',
+        }
+        #Split the file in statements
+        list_split = rec.split('\n')        
+       
+        #currency_code (local_currency in the stament) extracted from account_number object from the wizard.
+        #account_number (local_account) extracted from account_number object from the wizard.
+        #date_to_str and date_from_str are the dates in wizard, both are strings
+        
+        line_dict['account_number'] = kwargs['account_number']
+        
+        line_dict['currencycode'] = kwargs['local_currency']
+        
+        line_dict['statementnr'] = kwargs['date_from_str'] + ' - '+ kwargs['date_to_str'] + ' Extracto BNCR ' + line_dict['account_number'] #Interval time of the file.
+        
+        #transmission_number (Date when done the import)
+        date_obj= datetime.now()
+        line_dict['transref'] = date_obj.strftime("%d-%m-%Y %H:%M:%S")
+        #bookingdate
+        line_dict['bookingdate'] = date_obj.strftime("%d-%m-%Y %H:%M:%S")
+        
+        '''
+            For the BNCR parser, the ending_balance comes from wizard. With total of debit and credit and the ending_balance
+            compute the initial_balance.
+        '''
+        #extract the total of debit and credit from the file. The last statements and compute the startingbalance
+        last_position = (len(list_split) - 1)
+        last_line = list_split[last_position] 
+        #last line can be blanck, find the last line with data.
+        if last_line == "":
+            while True:
+                last_position -= 1
+                last_line = list_split[last_position]
+                if last_line is not "":
+                    break       
+        
+        last_line_split = last_line.split(';')
+        if last_line_split[3] != '':
+            debit = float(last_line_split[3].replace(",",""))
+        else:
+            debit = 0.0
+        if last_line_split[4] != '':
+            credit = float(last_line_split[4].replace(",",""))
+        else:
+            credit = 0.0
+        
+        startingbalance = float(kwargs['ending_balance']) + debit - credit 
+        line_dict['startingbalance'] =  str(startingbalance)
+        
+        #the ending_balance extracted from **kwargs (comes from wizard)
+        endingbalance = float(kwargs['ending_balance'])
+        line_dict['endingbalance'] =  str(kwargs['ending_balance'])
+        
+        line_dict['ammount'] = startingbalance + endingbalance
+        line_dict['id'] = kwargs['date_from_str'] + ' - '+ kwargs['date_to_str'] + ' Extracto BNCR ' + line_dict['account_number']
+        
+        return line_dict
+        
+    '''
+    Parse all the lines in the file. Once the header is parser, the next step are the lines.
+    '''     
+    def statement_lines ( self, rec ):
+        parser = BNCRParser()
+        mapping = {
+            'execution_date' : '',
+            'effective_date' : '',
+            'transfer_type' : '',
+            'reference' : '',
+            'message' : '',
+            'name' : '',
+            'transferred_amount': '',
+            'creditmarker': '',
+        }
+        
+        lines = []
+        line_dict = {}
+        currencycode = ''
+        
+        list_split = rec.split('\n')
+        entrada = False
+            
+        start = 1
+        end = (len(list_split) - 1)
+        last_line = list_split[end]
+        #last line can be blanck, find the last line with data.
+        if last_line == "":
+            while True:
+                end -= 1
+                last_line = list_split[end]
+                if last_line is not "":
+                    break
+                    
+        sub_list = list_split [start:end] #The end line is amount totals of credit and debit
+        for sub in sub_list:
+            line = sub.split(';')
+            #effective_date
+            date_str = line[1].replace("/","-")
+            date= datetime.strptime(date_str, "%Y-%m-%d")               
+            mapping['effective_date'] = date #fecha_contable.                        
+            #execution_date
+            mapping['execution_date'] = date #fecha_movimiento
+                                   
+            mapping['transfer_type'] = 'NTRF'
+            mapping['reference'] = line[2] #NumDocumento
+            mapping['message'] = line[2]+' '+line[5] #NumDocumento + Description         
+            mapping['name'] = line[2]+' '+line[5] #NumDocumento + Description       
+            mapping['id'] = line[2]+' '+line[5] #NumDocumento + Description     
+            
+            #the field in position 3 is debit, the position 4 is credit
+            if line[4] != '':
+                credit = float(line[4].replace(",",""))
+                mapping['transferred_amount'] = credit    
+                mapping['creditmarker'] = 'C'
+            
+            elif line[3] != '':
+                #In this case, the debit is negative.
+                debit = float(line[3].replace(",",""))
+                mapping['transferred_amount'] =  -1 * debit
+           
+            lines.append(copy(mapping))
+                            
+        return lines    
+     
+    """
+    ** Kwargs parameter is used for a dynamic list of parameters. 
+        The wizard imported extracts used in all parsers and not all parsers have all the necessary information in your file, 
+        so get information from the wizard and passed by the ** kwargs. 
+        Then in the parses that are needed, are extracted from the ** kwargs and if needed, 
+        the parser still works the same way without this parameter.
+        
+        The rest of the methods must receive this parameter. (As the method that parse the header and the lines). 
+        
+        If you need a new parameter, you specify its name and value, using the ** kwargs is a dictionary, 
+        extract its value, with the respective key
+    """
+    def parse_stamenent_record( self, rec, **kwargs):
+
+        matchdict = dict()
+        
+        #Set the header for the stament.
+        matchdict = self.statement_record(rec, **kwargs);
+
+        # Remove members set to None
+        matchdict = dict( [( k, v ) for k, v in matchdict.iteritems() if v] )
+
+        matchkeys = set( matchdict.keys() )
+        needstrip = set( [ 'transref', 'account_number', 'statementnr', 'currencycode', 'endingbalance', 'bookingdate'] )
+
+        for field in matchkeys & needstrip:
+            matchdict[field] = matchdict[field].strip()
+
+        # Convert to float. Comma is decimal separator
+        needsfloat = set( ["startingbalance", "endingbalance", "amount"] )
+        for field in matchkeys & needsfloat:
+            matchdict[field] = float( matchdict[field].replace( ',', '.' ) )
+
+        # Convert date fields
+        needdate = set( ["bookingdate"] )
+                
+        for field in matchkeys & needdate:            
+            datestring = matchdict[field]
+            date_obj= datetime.strptime(datestring, "%d-%m-%Y %H:%M:%S")
+            matchdict[field] = date_obj
+        
+        return matchdict
+        
+    def parse( self, cr, data ):
+        records = []
+        # Some records are multiline
+        for line in data:
+            if len(line) <= 1:
+                continue
+            if line[0] == ':' and len(line) > 1:
+                records.append(line)
+            else:
+                records[-1] = '\n'.join([records[-1], line])
+                
+        output = []
+
+        for rec in records:
+            #parse_stament_record call the method that parse the header and the stament of the file.
+            output.append(self.parse_stamenent_record( rec ))
+                
+        return output
+
+def parse_file( filename ):
+    bncrfile = open( filename, "r" )
+    p = BNCRParser().parse( bncrfile.readlines() )
+
+
+def main():
+    """The main function, currently just calls a dummy filename
+
+    :returns: description
+    """
+    parse_file("testfile")
+
+if __name__ == '__main__':
+    main()
+

=== modified file 'l10n_cr_account_banking_cr_davivienda/__init__.py' (properties changed: +x to -x)
=== modified file 'l10n_cr_account_banking_cr_davivienda/__openerp__.py' (properties changed: +x to -x)
=== modified file 'l10n_cr_account_banking_cr_davivienda/davivienda_format.py' (properties changed: +x to -x)
--- l10n_cr_account_banking_cr_davivienda/davivienda_format.py	2013-02-22 22:35:48 +0000
+++ l10n_cr_account_banking_cr_davivienda/davivienda_format.py	2013-03-14 16:05:24 +0000
@@ -24,10 +24,11 @@
 from tools.translate import _
 from davivienda_parser import DaviviendaParser
 import re
-import osv
+from osv import osv, fields
 import logging
 import pprint
 from datetime import datetime
+import base64
 
 bt = models.mem_bank_transaction
 logger = logging.getLogger( 'davivienda_logger' )
@@ -76,6 +77,7 @@
     
     def _account_number(self, record):
         self.local_account = record['account_number']
+        self.local_currency = record['currencycode']
 
     def _statement_number(self, record):
         self.id = record['id']
@@ -133,7 +135,8 @@
             This format is available through
             the Davivienda  web interface.
             ''')
-    '''
+    
+    '''    
         ** Kwargs parameter is used for a dynamic list of parameters. 
         The wizard imported extracts used in all parsers and not all parsers have all the necessary information in your file, 
         so get information from the wizard and passed by the ** kwargs. 
@@ -146,10 +149,17 @@
         extract its value, with the respective key
     '''
 
-    def parse(self, cr, data, **kwargs):
+    def parse(self, cr, statements_file, **kwargs):
         result = []
         parser = DaviviendaParser()
         stmnt = statement()
+        """
+            **kwargs have all the parameters that have the wizard and 
+            has all the parameters passed from the wizard before calling 
+            the method that parses the file.            
+        """        
+        #pass to encoding with the correct type of file.
+        data = base64.decodestring(statements_file)
         
         #parse the data for the header of the stament.
         records = parser.parse_stamenent_record(data, **kwargs)        
@@ -171,5 +181,5 @@
             result.append(stmnt)
                       
         return result
-
+      
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== modified file 'l10n_cr_account_banking_cr_davivienda/davivienda_parser.py'
--- l10n_cr_account_banking_cr_davivienda/davivienda_parser.py	2013-02-22 22:35:48 +0000
+++ l10n_cr_account_banking_cr_davivienda/davivienda_parser.py	2013-03-14 16:05:24 +0000
@@ -27,6 +27,8 @@
 from dateutil import parser
 from pprint import PrettyPrinter
 from copy import copy
+from osv import osv, fields
+from tools.translate import _
 
 class DaviviendaParser( object ):
     
@@ -59,49 +61,63 @@
             'id': '',
         }
         
-        #currency_code (local_currency in the stament) extracted from account_number object from the wizard.
-        #account_number (local_account) extracted from account_number object from the wizard.
-        #date_to_str and date_from_str are the dates in wizard, both are strings
-        #the parameters come from davivienda_format in parser class.
-        line_dict['account_number'] = kwargs['account_number']
-        
-        line_dict['currencycode'] = kwargs['local_currency']
-        
-        line_dict['statementnr'] = kwargs['date_from_str'] + ' - '+ kwargs['date_to_str'] + 'Extracto Davivienda ' + line_dict['account_number'] #Interval time of the file.
-         
-        startingbalance = endingbalance = 0.0
+        #Separe the file in statements
         list_split = rec.split('\n')
-        
-        #transmission_number (Date when done the import)
-        date_obj= datetime.now()
-        line_dict['transref'] = date_obj.strftime("%d-%m-%Y %H:%M:%S")
-        #bookingdate
-        line_dict['bookingdate'] = date_obj.strftime("%d-%m-%Y %H:%M:%S")
-    
-        #with the first line compute the initial_balance
+        #Obtain the first line to know the account number
         fist_line = list_split[1]
         first_line_split = fist_line.split(';')
-        startingbalance = float(first_line_split[5].replace(",","")) + float(first_line_split[3].replace(",","")) - float(first_line_split[4].replace(",",""))
-        line_dict['startingbalance'] =  str(startingbalance)
-        
-        #the ending_balance is the balance of the last line.        
-        last_position = (len(list_split) - 1)
-        last_line = list_split[last_position] 
-        #last line can be blanck, find the last line with data.
-        if last_line == "":
-            while True:
-                last_position -= 1
-                last_line = list_split[last_position]
-                if last_line is not "":
-                    break       
-        last_line_split = last_line.split(';')
-        endingbalance += float(last_line_split[5].replace(",",""))      
-        line_dict['endingbalance'] =  str(endingbalance)
-        
-        line_dict['ammount'] = startingbalance + endingbalance
-        line_dict['id'] = kwargs['date_from_str'] + ' - '+ kwargs['date_to_str'] + ' Extracto Davivienda ' + line_dict['account_number']
-        
-        return line_dict
+        
+        account_number_wizard = kwargs['account_number']#from wizard
+        account_number_file = first_line_split[11]#from file.
+        
+        #if the account_number in the file match with the account selected in the wizard, return True
+        if account_number_file.find(account_number_wizard) > -1:
+            #currency_code (local_currency in the stament) extracted from account_number object from the wizard.
+            #account_number (local_account) extracted from account_number object from the wizard.
+            #date_to_str and date_from_str are the dates in wizard, both are strings
+            #the parameters come from davivienda_format in parser class.
+            line_dict['account_number'] = kwargs['account_number']
+            
+            line_dict['currencycode'] = kwargs['local_currency']
+            
+            line_dict['statementnr'] = kwargs['date_from_str'] + ' - '+ kwargs['date_to_str'] + 'Extracto Davivienda ' + line_dict['account_number'] #Interval time of the file.
+             
+            startingbalance = endingbalance = 0.0
+            
+            #transmission_number (Date when done the import)
+            date_obj= datetime.now()
+            line_dict['transref'] = date_obj.strftime("%d-%m-%Y %H:%M:%S")
+            #bookingdate
+            line_dict['bookingdate'] = date_obj.strftime("%d-%m-%Y %H:%M:%S")
+        
+            #with the first line compute the initial_balance
+            fist_line = list_split[1]
+            first_line_split = fist_line.split(';')
+            startingbalance = float(first_line_split[5].replace(",","")) + float(first_line_split[3].replace(",","")) - float(first_line_split[4].replace(",",""))
+            line_dict['startingbalance'] =  str(startingbalance)
+            
+            #the ending_balance is the balance of the last line.        
+            last_position = (len(list_split) - 1)
+            last_line = list_split[last_position] 
+            #last line can be blanck, find the last line with data.
+            if last_line == "":
+                while True:
+                    last_position -= 1
+                    last_line = list_split[last_position]
+                    if last_line is not "":
+                        break       
+            last_line_split = last_line.split(';')
+            endingbalance += float(last_line_split[5].replace(",",""))      
+            line_dict['endingbalance'] =  str(endingbalance)
+            
+            line_dict['ammount'] = startingbalance + endingbalance
+            line_dict['id'] = kwargs['date_from_str'] + ' - '+ kwargs['date_to_str'] + ' Extracto Davivienda ' + line_dict['account_number']
+            
+            return line_dict
+        
+        else:
+            raise osv.except_osv(_('Error'),
+                        _('Error en la importación! La cuenta especificada en el archivo no coincide con la seleccionada en el asistente de importacion'))
     
     '''
     Parse all the lines in the file. Once the header is parser, the next step are the lines.
@@ -179,7 +195,8 @@
         If you need a new parameter, you specify its name and value, using the ** kwargs is a dictionary, 
         extract its value, with the respective key
     """
-    def parse_stamenent_record( self, rec, **kwargs):
+    
+    def parse_stamenent_record( self, rec, **kwargs): #parse the header.
 
         matchdict = dict()
         
@@ -209,7 +226,8 @@
             matchdict[field] = date_obj
         
         return matchdict
-        
+    
+    #call the method that parse the header and the statements.    
     def parse( self, cr, data ):
         records = []
         # Some records are multiline
@@ -224,23 +242,9 @@
         output = []
 
         for rec in records:
+            #parse_stamenent_record parse the header and the statements
             output.append( self.parse_stamenent_record( rec ) )
                 
         return output
 
 
-def parse_file( filename ):
-    daviviendafile = open( filename, "r" )
-    p = DaviviendaParser().parse( daviviendafile.readlines() )
-
-
-def main():
-    """The main function, currently just calls a dummy filename
-
-    :returns: description
-    """
-    parse_file("testfile")
-
-if __name__ == '__main__':
-    main()
-

=== added directory 'l10n_cr_account_banking_cr_lafise'
=== added file 'l10n_cr_account_banking_cr_lafise/__init__.py'
--- l10n_cr_account_banking_cr_lafise/__init__.py	1970-01-01 00:00:00 +0000
+++ l10n_cr_account_banking_cr_lafise/__init__.py	2013-03-14 16:05:24 +0000
@@ -0,0 +1,24 @@
+# -*- encoding: utf-8 -*-
+##############################################################################
+#
+#    Copyright (C) 2011 credativ Ltd (<http://www.credativ.co.uk>).
+#    All Rights Reserved
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+import lafise_format
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== added file 'l10n_cr_account_banking_cr_lafise/__openerp__.py'
--- l10n_cr_account_banking_cr_lafise/__openerp__.py	1970-01-01 00:00:00 +0000
+++ l10n_cr_account_banking_cr_lafise/__openerp__.py	2013-03-14 16:05:24 +0000
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Addons modules by CLEARCORP S.A.
+#    Copyright (C) 2009-TODAY CLEARCORP S.A. (<http://clearcorp.co.cr>).
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+{
+    'name': 'Lafise Account Banking',
+    'version': '0.5',
+    'license': 'AGPL-3',
+    'author': 'CLEARCORP S.A.',
+    'website': 'http://www.clearcorp.co.cr',
+    'category': 'Account Banking',
+    'depends': ['account_banking'],
+    'init_xml': [],
+    'update_xml': [],
+    'demo_xml': [],
+    'description': 'Module to import Lafise CR format transation files.',
+    'active': False,
+    'installable': True,
+}

=== added file 'l10n_cr_account_banking_cr_lafise/lafise_format.py'
--- l10n_cr_account_banking_cr_lafise/lafise_format.py	1970-01-01 00:00:00 +0000
+++ l10n_cr_account_banking_cr_lafise/lafise_format.py	2013-03-14 16:05:24 +0000
@@ -0,0 +1,204 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Addons modules by CLEARCORP S.A.
+#    Copyright (C) 2009-TODAY CLEARCORP S.A. (<http://clearcorp.co.cr>).
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from account_banking.parsers import models
+from tools.translate import _
+from lafise_parser import LafiseParser
+import re
+from osv import osv, fields
+import logging
+import pprint
+from datetime import datetime
+import base64
+import StringIO
+from lxml import etree
+
+bt = models.mem_bank_transaction
+logger = logging.getLogger( 'lafise_logger' )
+
+class transaction(models.mem_bank_transaction):
+
+    mapping = {
+        'execution_date' : '',
+        'effective_date' : '',
+        'local_currency' : '',
+        'transfer_type' : '',
+        'reference' : '',
+        'message' : '',
+        'name' : '',
+        'amount': '',
+        'creditmarker': '',
+    }
+
+    def __init__(self, record, *args, **kwargs):
+        
+        '''
+        Transaction creation
+        '''
+        #record is a dictionary, that is the reason to use iteritems().
+        super(transaction, self).__init__(*args, **kwargs)
+        for key, value in record.iteritems():
+            if record.has_key(key):
+                setattr(self, key, record[key])
+
+        if not self.is_valid():
+            logger.info("Invalid: %s", record)
+    
+    def is_valid(self):
+        '''
+        We don't have remote_account so override base
+        '''
+        return (self.execution_date
+                and self.transferred_amount and True) or False
+
+class statement(models.mem_bank_statement):
+    '''
+    Bank statement imported data    '''
+      
+    def _transmission_number(self, record):
+        self.id = record['transref']
+    
+    def _account_number(self, record):
+        self.local_account = record['account_number']
+
+    def _statement_number(self, record):
+        self.id = record['id']
+        
+    def _opening_balance(self, record):
+        self.start_balance = float(record['startingbalance'])
+    
+    def _closing_balance(self, record):
+        self.end_balance = float(record['endingbalance'])
+        self.date = record['bookingdate']
+     
+    def _transaction_new(self, record, rows):
+        parser = LafiseParser()
+        #parse the lines in the file. 
+        
+        '''
+            Record is the header of the file
+            Rows is the lines when the parser to html read the file.
+        '''
+        sub_record = parser.statement_lines(record, rows) #dictionary
+        for sub in sub_record:
+            self.transactions.append(transaction(sub))
+
+    def _not_used():
+        logger.info("Didn't use record: %s", record)
+        
+    def _forward_available(self, record):
+        self.end_balance =  float(record['endingbalance'])
+        self.date = record['bookingdate'] 
+    
+    def _execution_date_transferred_amount (self, record):        
+        self.execution_date = record['bookingdate']       
+        self.transferred_amount = float(record['ammount'])
+
+    def transaction_info(self, record):
+        '''
+        Add extra information to transaction
+        '''
+        # Additional information for previous transaction
+        if len(self.transactions) < 1:
+            logger.info("Received additional information for non existent transaction:")
+            logger.info(record)
+        else:
+            transaction = self.transactions[-1]
+            transaction.id = ','.join([record[k] for k in ['infoline{0}'.format(i) for i in range(2,5)] if record.has_key(k)])
+
+def raise_error(message, line):
+    raise osv.osv.except_osv(_('Import error'),
+        'Error in import:%s\n\n%s' % (message, line))
+
+class parse_lafise( models.parser ):
+    
+    '''
+        This adds a new parser in the selection options. 
+        When the account is associated to a parser, the following code makes it appear as an option
+    '''
+    code = 'Lafise-Parser'
+    name = _( 'Lafise statement import' )
+    country_code = 'CR'
+    doc = _('''\
+            This format is available through
+            the Lafise  web interface.
+            ''')
+    '''
+        ** Kwargs parameter is used for a dynamic list of parameters. 
+        The wizard imported extracts used in all parsers and not all parsers have all the necessary information in your file, 
+        so get information from the wizard and passed by the ** kwargs. 
+        Then in the parses that are needed, are extracted from the ** kwargs and if needed, 
+        the parser still works the same way without this parameter.
+        
+        The rest of the methods must receive this parameter. (As the method that parse the header and the lines). 
+        
+        If you need a new parameter, you specify its name and value, using the ** kwargs is a dictionary, 
+        extract its value, with the respective key
+    '''
+ 
+    def parse(self, cr, statements_file, **kwargs):
+        list_result = []
+        stmnt = statement() 
+        parser_lafise = LafiseParser()
+        
+        #decode to string the binary file in the wizard
+        content = base64.decodestring(statements_file)
+        
+        '''
+            The lafise file when the content is decode to string return a html string.
+            The html format for the file is incorrect, so the function etree.HTMLParser()
+            With this function, the file have the correct tags and content for the file in html.
+        '''
+        parser = etree.HTMLParser() #parse to correct html format.
+        tree   = etree.parse(StringIO.StringIO(content), parser) #Create a root with tags and content with the html file.
+        result = etree.tostring(tree.getroot(),pretty_print=True, method="html") #parse to string.
+
+        table = etree.HTML(result) #pass a tags HTML
+        rows = table.iter() #extract all the rows in the file.
+        
+        #pass the rows to parse the headers
+        records = parser_lafise.parse_stamenent_record(rows, **kwargs)        
+        
+        stmnt._transmission_number(records)
+        stmnt._account_number(records)
+        stmnt._statement_number(records)
+        stmnt._opening_balance(records)
+        stmnt._closing_balance(records)
+        stmnt._forward_available(records)
+        stmnt._execution_date_transferred_amount (records)
+        
+        #call the method statement_lines in parser to parse all the lines in file and add to stament. Receive the rows.
+        #pass the records to extract the currency (the currency is in the header file)        
+        rows = table.iter() #extract all the rows in the file, when a iteration finish, must be reload the variable.
+        stmnt._transaction_new(records,rows)
+                  
+        '''
+            A stament must have a header and transacctions. The method parse_stamenent_record parse the header and the 
+            method _transaction_new parse all the line (transactions) in the file. 
+        '''
+        
+        if stmnt.is_valid():
+            list_result.append(stmnt)
+                      
+        return list_result
+       
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

=== added file 'l10n_cr_account_banking_cr_lafise/lafise_parser.py'
--- l10n_cr_account_banking_cr_lafise/lafise_parser.py	1970-01-01 00:00:00 +0000
+++ l10n_cr_account_banking_cr_lafise/lafise_parser.py	2013-03-14 16:05:24 +0000
@@ -0,0 +1,306 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Addons modules by CLEARCORP S.A.
+#    Copyright (C) 2009-TODAY CLEARCORP S.A. (<http://clearcorp.co.cr>).
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+"""
+Parser for Lafise html format files
+"""
+import re
+from datetime import datetime
+from dateutil import parser
+from pprint import PrettyPrinter
+from copy import copy
+from tools.translate import _
+from osv import osv, fields
+
+class LafiseParser(object):
+    
+    #Define the header for the extract to import.
+    '''
+     ** Kwargs parameter is used for a dynamic list of parameters. 
+        The wizard imported extracts used in all parsers and not all parsers have all the necessary information in your file, 
+        so get information from the wizard and passed by the ** kwargs. 
+        Then in the parses that are needed, are extracted from the ** kwargs and if needed, 
+        the parser still works the same way without this parameter.
+        
+        The rest of the methods must receive this parameter. (As the method that parse the header and the lines). 
+        
+        If you need a new parameter, you specify its name and value, using the ** kwargs is a dictionary, 
+        extract its value, with the respective key
+    '''
+    
+    """
+        As the lafise file comes in a html format, the parameter rows is the file parser, 
+        the values can be extracted with the property .text in the row.
+        For the header, extracted the account, currency, initial_balance, ending_balance. 
+        
+        It must iterate in the rows to obtain the values.
+    """    
+    
+    def statement_record ( self, rows, **kwargs):
+        lines = []
+        line_dict = {}
+        count = 1
+        
+        line_dict = {
+            'transref': '', # _transmission_number
+            'account_number': '', #_account_number
+            'statementnr':'', # statement_number
+            'startingbalance': 0.0, #_opening_balance
+            'currencycode': '', #currencycode
+            'endingbalance': 0.0, #_closing_balance
+            'bookingdate': '', #moving_date
+            'ammount': 0.0,
+            'id': '',
+        }        
+        #transmission_number and bookingdate -> Date when make the extract import.
+        date_obj= datetime.now()
+        line_dict['transref'] = date_obj.strftime("%d-%m-%Y %H:%M:%S")
+        
+        #delete blank rows
+        for row in rows:
+            values = [col.text for col in row]
+            if len(values) > 0:
+                lines.append(values)
+        
+        #search the row #16 (after delete blank rows) and extract account, currency and ending_balance.
+        #the line 23 contain the initial_balance (position 5)
+        #lines is a list of lists.
+        
+        #First, check if the account in the wizard match with the account in the file. 
+        if self.match_account(lines, kwargs['account_number']):        
+            for list in lines:
+                if count == 16:
+                    line_dict['account_number'] = self.extract_number(list[0])
+                    line_dict['currencycode'] = list[3]
+                    line_dict['endingbalance'] = self.extract_float(list[6]).replace(",","")
+                
+                elif count == 23:
+                    line_dict['startingbalance'] =  self.extract_float(str(list[5]).replace(",",""))
+                
+                #interrupted the cycle, because the information is complete for the header.
+                elif count >= 24:
+                    break               
+                count +=1        
+            
+            #statementnr
+            line_dict['statementnr'] = kwargs['date_from_str'] + ' - '+ kwargs['date_to_str'] + ' Extracto Lafise ' + line_dict['account_number'] #Interval time of the file.
+            
+            #amount
+            line_dict['ammount'] = float(line_dict['startingbalance']) + float(line_dict['endingbalance'])
+            
+            #bookingdate
+            line_dict['bookingdate'] = date_obj.strftime("%d-%m-%Y %H:%M:%S")
+            
+            #id
+            line_dict['id'] = kwargs['date_from_str'] + ' - '+ kwargs['date_to_str'] + ' Extracto Lafise ' + line_dict['account_number']
+            
+            return line_dict
+        else:
+             raise osv.except_osv(_('Error'),
+                        _('Error en la importación! La cuenta especificada en el archivo no coincide con la seleccionada en el asistente de importacion'))
+             
+    '''
+    Parse all the lines in the file. Once the header is parser, the next step are the lines.
+    '''     
+    def statement_lines (self, records, rows):
+        parser = LafiseParser()
+        mapping = {
+            'execution_date' : '',
+            'effective_date' : '',
+            'transfer_type' : '',
+            'reference' : '',
+            'message' : '',
+            'name' : '',
+            'transferred_amount': '',
+            'creditmarker': '',
+        }
+        
+        lines = []
+        statements = [] 
+        currencycode = records['currencycode']
+        count = 1 #in line 24 start the statements.
+        
+        #delete blank rows
+        for row in rows:
+            values = [col.text for col in row]
+            if len(values) > 0:
+                lines.append(values)
+
+        for line in lines:
+             #In line 24 start the statements (in movements format)
+             if (count >= 24): 
+                #The final line (**** SALDO FINAL ****) must be largest than 3 celds,
+                #because the expresion is in the celd 2 (0,1,2)
+                if len(line) >= 3: 
+                    #the function clean_special_characters remove '\r\n' and '\t'
+                    try:
+                        str_line = self.clean_special_characters(line[2])  
+                        #The string str_line don't have blank spaces, son instance **** SALDO FINAL **** find ****SALDOFINAL****
+                        if (str_line != "****SALDOFINAL****"):
+                            #effective_date                  
+                            date_str = self.extract_date_regular_expresion(self.clean_special_characters(line[0]))
+                            date = datetime.strptime(date_str, "%d/%m/%y")               
+                            mapping['effective_date'] = date #fecha_contable.
+                            
+                            #execution_date
+                            mapping['execution_date'] = date #fecha_movimiento                       
+                           
+                            mapping['local_currency'] = currencycode
+                            mapping['transfer_type'] = 'NTRF'
+                            mapping['reference'] = self.extract_number(self.clean_special_characters(line[1]))
+                            mapping['message'] = str_line               
+                            mapping['name'] = str_line
+                            mapping['id'] = str_line
+                            
+                            debit = float(self.extract_float(self.clean_special_characters(line[3])))
+                            credit = float(self.extract_float(self.clean_special_characters(line[4])))
+                                            
+                            if (credit > 0.0): #in this case, credit is a input of money
+                                mapping['transferred_amount'] = credit
+                                mapping['creditmarker'] = 'C'
+                                                  
+                            else: #debit is output
+                                mapping['transferred_amount'] =  -debit
+                            
+                            statements.append(copy(mapping))
+                    except:
+                        #end of the file.
+                        break
+             count +=1      
+
+        return statements    
+    
+    """
+    ** Kwargs parameter is used for a dynamic list of parameters. 
+        The wizard imported extracts used in all parsers and not all parsers have all the necessary information in your file, 
+        so get information from the wizard and passed by the ** kwargs. 
+        Then in the parses that are needed, are extracted from the ** kwargs and if needed, 
+        the parser still works the same way without this parameter.
+        
+        The rest of the methods must receive this parameter. (As the method that parse the header and the lines). 
+        
+        If you need a new parameter, you specify its name and value, using the ** kwargs is a dictionary, 
+        extract its value, with the respective key
+    """
+    def parse_stamenent_record( self, rec, **kwargs):
+
+        matchdict = dict()
+        
+        #Set the header for the stament.
+        matchdict = self.statement_record(rec, **kwargs);
+
+        # Remove members set to None
+        matchdict = dict( [( k, v ) for k, v in matchdict.iteritems() if v] )
+
+        matchkeys = set( matchdict.keys() )
+        needstrip = set( [ 'transref', 'account_number', 'statementnr', 'currencycode', 'endingbalance', 'bookingdate'] )
+
+        for field in matchkeys & needstrip:
+            matchdict[field] = matchdict[field].strip()
+
+        # Convert to float. Comma is decimal separator
+        needsfloat = set( ["startingbalance", "endingbalance", "amount"] )
+        for field in matchkeys & needsfloat:
+            matchdict[field] = float( matchdict[field].replace( ',', '.' ) )
+
+        # Convert date fields
+        needdate = set( ["bookingdate"] )
+                
+        for field in matchkeys & needdate:            
+            datestring = matchdict[field]
+            date_obj= datetime.strptime(datestring, "%d-%m-%Y %H:%M:%S")
+            matchdict[field] = date_obj
+        
+        return matchdict
+        
+    def parse( self, cr, data ):
+        records = []
+        # Some records are multiline
+        for line in data:
+            if len(line) <= 1:
+                continue
+            if line[0] == ':' and len(line) > 1:
+                records.append(line)
+            else:
+                records[-1] = '\n'.join([records[-1], line])
+                
+        output = []
+
+        for rec in records:
+            output.append( self.parse_stamenent_record( rec ) )
+                
+        return output
+    
+    ##################################<-AUXILIAR METHODS->####################################
+    def extract_number( self, account_number ):
+        cad = ''
+        result = re.findall(r'[0-9]+', account_number)
+               
+        for character in result:
+            cad = cad + character
+        return cad
+
+    def extract_float ( self, ammount ):
+        cad = ''
+        result = re.findall(r"[-+]?\d*\.\d+|\d+",ammount)
+        
+        for character in result:
+            cad = cad + character       
+        return cad
+    
+    def extract_date_regular_expresion(self, date):
+        cad = ''
+        result = []
+        date_string = ''
+        result = re.findall('[0-9]{1,2}/[0-9]{1,2}/[0-9]{2}', date)
+       
+        for character in result:
+            cad = cad + character       
+        return cad
+    
+    #clear special characters in a row. 
+    def clean_special_characters(self, text_celd):
+        special_characters = {'\r\n':'','\t':''," ":''}
+         
+        for i, j in special_characters.iteritems():
+            text = text_celd.replace(i, j)    
+            
+        #remove all the blank space.
+        return re.sub(r'\s', '', text)
+    
+    #Return true if the account selected in the wizard match with the account in the file.
+    def match_account(self, lines, account_wizard):
+        count = 1
+        acc_number = ''
+        for list in lines:
+            if count == 16:
+                acc_number= self.extract_number(list[0])
+                break
+            else:
+                count +=1
+        
+        if acc_number.find(account_wizard) > -1:
+            return True
+        
+        else:
+            return False
+    
+        
\ No newline at end of file


Follow ups