~ss-dtic/openerp-costa-rica/6.1-purchase-import

« back to all changes in this revision

Viewing changes to l10n_cr_account_banking_cr_bac/bac_mt940.py

  • Committer: Armando Soto
  • Date: 2012-07-02 19:59:23 UTC
  • mto: This revision was merged to the branch mainline in revision 115.
  • Revision ID: armando.soto@clearcorp.co.cr-20120702195923-pa9s9d5fuszsoh61
[ADD] Added l10n_cr_account_banking_cr_bac

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- encoding: utf-8 -*-
 
2
##############################################################################
 
3
#
 
4
#    Copyright (C) 2011 credativ Ltd (<http://www.credativ.co.uk>).
 
5
#    All Rights Reserved
 
6
#
 
7
#    This program is free software: you can redistribute it and/or modify
 
8
#    it under the terms of the GNU Affero General Public License as
 
9
#    published by the Free Software Foundation, either version 3 of the
 
10
#    License, or (at your option) any later version.
 
11
#
 
12
#    This program is distributed in the hope that it will be useful,
 
13
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
#    GNU Affero General Public License for more details.
 
16
#
 
17
#    You should have received a copy of the GNU Affero General Public License
 
18
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
19
#
 
20
##############################################################################
 
21
# Import of BAC data in Swift MT940 format
 
22
#
 
23
 
 
24
from account_banking.parsers import models
 
25
from tools.translate import _
 
26
from mt940_parser import BACParser
 
27
import re
 
28
import osv
 
29
import logging
 
30
 
 
31
bt = models.mem_bank_transaction
 
32
logger = logging.getLogger('bac_mt940')
 
33
 
 
34
def record2float(record, value):
 
35
    if record['creditmarker'][-1] == 'C':
 
36
        return float(record[value])
 
37
    return -float(record[value])
 
38
 
 
39
class transaction(models.mem_bank_transaction):
 
40
 
 
41
    mapping = {
 
42
        'execution_date' : 'valuedate',
 
43
        'effective_date' : 'valuedate',
 
44
        'local_currency' : 'currency',
 
45
        'transfer_type' : 'bookingcode',
 
46
        'reference' : 'custrefno',
 
47
        'message' : 'furtherinfo',
 
48
        'name' : 'infoline1'
 
49
    }
 
50
 
 
51
    type_map = {
 
52
        'NTRF': bt.ORDER,
 
53
        'NMSC': bt.ORDER,
 
54
        'NPAY': bt.PAYMENT_BATCH,
 
55
        'NCHK': bt.CHECK,
 
56
        'NCLR': bt.ORDER,
 
57
    }
 
58
 
 
59
    def __init__(self, record, *args, **kwargs):
 
60
        '''
 
61
        Transaction creation
 
62
        '''
 
63
        super(transaction, self).__init__(*args, **kwargs)
 
64
        for key, value in self.mapping.iteritems():
 
65
            if record.has_key(value):
 
66
                setattr(self, key, record[value])
 
67
 
 
68
        self.transferred_amount = record2float(record, 'amount')
 
69
 
 
70
        # Set the transfer type based on the bookingcode
 
71
        if record.get('bookingcode','ignore') in self.type_map:
 
72
            self.transfer_type = self.type_map[record['bookingcode']]
 
73
        else:
 
74
            # Default to the generic order, so it will be eligible for matching
 
75
            self.transfer_type = bt.ORDER
 
76
 
 
77
        if not self.is_valid():
 
78
            logger.info("Invalid: %s", record)
 
79
    def is_valid(self):
 
80
        '''
 
81
        We don't have remote_account so override base
 
82
        '''
 
83
        return (self.execution_date
 
84
                and self.transferred_amount and True) or False
 
85
 
 
86
class statement(models.mem_bank_statement):
 
87
    '''
 
88
    Bank statement imported data
 
89
    '''
 
90
 
 
91
    def import_record(self, record):
 
92
        def _transmission_number():
 
93
            self.id = record['transref']
 
94
        def _account_number():
 
95
            # The wizard doesn't check for sort code
 
96
            self.local_account = record['sortcode'] + record['accnum']
 
97
        def _statement_number():
 
98
            self.id = '-'.join([self.id, self.local_account, record['statementnr']])
 
99
        def _opening_balance():
 
100
            self.start_balance = record2float(record,'startingbalance')
 
101
            self.local_currency = record['currencycode']
 
102
        def _closing_balance():
 
103
            self.end_balance = record2float(record, 'endingbalance')
 
104
            self.date = record['bookingdate']
 
105
        def _transaction_new():
 
106
            self.transactions.append(transaction(record))
 
107
        def _transaction_info():
 
108
            self.transaction_info(record)
 
109
        def _not_used():
 
110
            logger.info("Didn't use record: %s", record)
 
111
        def _forward_available():
 
112
            self.end_balance = record2float(record, 'endingbalance')
 
113
            self.date = record['bookingdate']
 
114
 
 
115
        rectypes = {
 
116
            '20' : _transmission_number,
 
117
            '25' : _account_number,
 
118
            '28' : _statement_number,
 
119
            '28C': _statement_number,
 
120
            '60F': _opening_balance,
 
121
            '62F': _closing_balance,
 
122
            '64' : _forward_available,
 
123
           #'62M': _interim_balance,
 
124
            '61' : _transaction_new,
 
125
            '86' : _transaction_info,
 
126
            }
 
127
 
 
128
        rectypes.get(record['recordid'], _not_used)()
 
129
 
 
130
    def transaction_info(self, record):
 
131
        '''
 
132
        Add extra information to transaction
 
133
        '''
 
134
        # Additional information for previous transaction
 
135
        if len(self.transactions) < 1:
 
136
            logger.info("Received additional information for non existent transaction:")
 
137
            logger.info(record)
 
138
        else:
 
139
            transaction = self.transactions[-1]
 
140
            transaction.id = ','.join([record[k] for k in ['infoline{0}'.format(i) for i in range(2,5)] if record.has_key(k)])
 
141
 
 
142
    
 
143
 
 
144
def raise_error(message, line):
 
145
    raise osv.osv.except_osv(_('Import error'),
 
146
        'Error in import:%s\n\n%s' % (message, line))
 
147
 
 
148
class parser_bac_mt940(models.parser):
 
149
    code = 'BAC-MT940'
 
150
    name = _('BAC Swift MT940 statement export')
 
151
    country_code = 'CR'
 
152
    doc = _('''\
 
153
            This format is available through
 
154
            the BAC web interface.
 
155
            ''')
 
156
 
 
157
    def parse(self, cr, data):
 
158
        result = []
 
159
        parser = BACParser()
 
160
        # Split into statements
 
161
        statements = [st for st in re.split('[\r\n]*(?=:20:)', data)]
 
162
        # Split by records
 
163
        statement_list = [re.split('[\r\n ]*(?=:\d\d[\w]?:)', st) for st in statements]
 
164
 
 
165
        for statement_lines in statement_list:
 
166
            stmnt = statement()
 
167
            records = [parser.parse_record(record) for record in statement_lines]
 
168
            [stmnt.import_record(r) for r in records if r is not None]
 
169
 
 
170
 
 
171
            if stmnt.is_valid():
 
172
                result.append(stmnt)
 
173
            else:
 
174
                logger.info("Invalid Statement:")
 
175
                logger.info(records[0])
 
176
                logger.info(records[1])
 
177
                logger.info(records[2])
 
178
                logger.info(records[3])
 
179
                logger.info(records[4])
 
180
 
 
181
        return result
 
182
 
 
183
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: