Merge lp:~camptocamp/banking-addons/bank-statement-reconcile-70-improve-import-usability into lp:banking-addons/bank-statement-reconcile-70

Proposed by Nicolas Bessi - Camptocamp
Status: Superseded
Proposed branch: lp:~camptocamp/banking-addons/bank-statement-reconcile-70-improve-import-usability
Merge into: lp:banking-addons/bank-statement-reconcile-70
Diff against target: 216 lines (+77/-33)
3 files modified
account_statement_base_import/parser/file_parser.py (+65/-27)
account_statement_base_import/parser/generic_file_parser.py (+9/-4)
account_statement_transactionid_import/parser/transactionid_file_parser.py (+3/-2)
To merge this branch: bzr merge lp:~camptocamp/banking-addons/bank-statement-reconcile-70-improve-import-usability
Reviewer Review Type Date Requested Status
Nicolas Bessi - Camptocamp (community) Needs Resubmitting
Alexandre Fayolle - camptocamp code review, no test Needs Fixing
Review via email: mp+148665@code.launchpad.net

This proposal has been superseded by a proposal from 2013-03-01.

Description of the change

Improve statement import global usability by retuning usable error message while parsing files.

Allows empty value for float in parsed CSV.

Minor code improvements.

To post a comment you must log in.
Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

Nitpickings

l.30
s/Invalide/invalid/
s/please/Please/
remove extraneous parenthesis around `ftype`

l.40
remove extraneous parenthesis around `col`

l.80,93,113,128
I would recommend the new syntax python3-like for the exceptions as it is more readable
    except Exception as err:
BTW, I don't have the context here, but don't we have a more precise exception to catch?

l.147
s/convertion/conversion/

l.149
    return float(val) if val else 0.0

Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote :

l19: do not use a mutable value as a default value. Please replace with an empty tuple.

review: Needs Fixing (code review, no test)
Revision history for this message
Nicolas Bessi - Camptocamp (nbessi-c2c-deactivatedaccount) wrote :

Fixes applied.
convertion/conversion typo also fixed in other files.

Revision history for this message
Nicolas Bessi - Camptocamp (nbessi-c2c-deactivatedaccount) :
review: Needs Resubmitting

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'account_statement_base_import/parser/file_parser.py'
--- account_statement_base_import/parser/file_parser.py 2012-12-20 13:37:01 +0000
+++ account_statement_base_import/parser/file_parser.py 2013-02-26 08:28:21 +0000
@@ -17,8 +17,8 @@
17# along with this program. If not, see <http://www.gnu.org/licenses/>.17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#18#
19##############################################################################19##############################################################################
20
21from openerp.tools.translate import _20from openerp.tools.translate import _
21from openerp.osv.osv import except_osv
22import tempfile22import tempfile
23import datetime23import datetime
24from parser import BankStatementImportParser24from parser import BankStatementImportParser
@@ -34,12 +34,13 @@
34 Generic abstract class for defining parser for .csv or .xls file format.34 Generic abstract class for defining parser for .csv or .xls file format.
35 """35 """
3636
37 def __init__(self, parse_name, keys_to_validate=[], ftype='csv', convertion_dict=None, header=None, *args, **kwargs):37 def __init__(self, parse_name, keys_to_validate=None, ftype='csv', conversion_dict=None,
38 header=None, *args, **kwargs):
38 """39 """
39 :param char: parse_name : The name of the parser40 :param char: parse_name : The name of the parser
40 :param list: keys_to_validate : contain the key that need to be present in the file41 :param list: keys_to_validate : contain the key that need to be present in the file
41 :param char ftype: extension of the file (could be csv or xls)42 :param char ftype: extension of the file (could be csv or xls)
42 :param: convertion_dict : keys and type to convert of every column in the file like43 :param: conversion_dict : keys and type to convert of every column in the file like
43 {44 {
44 'ref': unicode,45 'ref': unicode,
45 'label': unicode,46 'label': unicode,
@@ -54,9 +55,10 @@
54 if ftype in ('csv', 'xls'):55 if ftype in ('csv', 'xls'):
55 self.ftype = ftype56 self.ftype = ftype
56 else:57 else:
57 raise Exception(_('Invalide file type %s. please use csv or xls') % (ftype))58 raise except_osv(_('User Error'),
58 self.keys_to_validate = keys_to_validate59 _('Invalid file type %s. Please use csv or xls') % ftype)
59 self.convertion_dict = convertion_dict60 self.keys_to_validate = keys_to_validate if keys_to_validate is not None else []
61 self.conversion_dict = conversion_dict
60 self.fieldnames = header62 self.fieldnames = header
61 self._datemode = 0 # used only for xls documents,63 self._datemode = 0 # used only for xls documents,
62 # 0 means Windows mode (1900 based dates).64 # 0 means Windows mode (1900 based dates).
@@ -99,7 +101,8 @@
99 parsed_cols = self.result_row_list[0].keys()101 parsed_cols = self.result_row_list[0].keys()
100 for col in self.keys_to_validate:102 for col in self.keys_to_validate:
101 if col not in parsed_cols:103 if col not in parsed_cols:
102 raise Exception(_('Column %s not present in file') % (col))104 raise except_osv(_('Invalid data'),
105 _('Column %s not present in file') % col)
103 return True106 return True
104107
105 def _post(self, *args, **kwargs):108 def _post(self, *args, **kwargs):
@@ -128,17 +131,13 @@
128 wb_file.write(self.filebuffer)131 wb_file.write(self.filebuffer)
129 # We ensure that cursor is at beginig of file132 # We ensure that cursor is at beginig of file
130 wb_file.seek(0)133 wb_file.seek(0)
131 wb = xlrd.open_workbook(wb_file.name)134 with xlrd.open_workbook(wb_file.name) as wb:
132 self._datemode = wb.datemode135 self._datemode = wb.datemode
133 sheet = wb.sheet_by_index(0)136 sheet = wb.sheet_by_index(0)
134 header = sheet.row_values(0)137 header = sheet.row_values(0)
135 res = []138 res = []
136 for rownum in range(1, sheet.nrows):139 for rownum in range(1, sheet.nrows):
137 res.append(dict(zip(header, sheet.row_values(rownum))))140 res.append(dict(zip(header, sheet.row_values(rownum))))
138 try:
139 wb_file.close()
140 except Exception, e:
141 pass # file is already closed
142 return res141 return res
143142
144 def _from_csv(self, result_set, conversion_rules):143 def _from_csv(self, result_set, conversion_rules):
@@ -149,11 +148,30 @@
149 for line in result_set:148 for line in result_set:
150 for rule in conversion_rules:149 for rule in conversion_rules:
151 if conversion_rules[rule] == datetime.datetime:150 if conversion_rules[rule] == datetime.datetime:
152 date_string = line[rule].split(' ')[0]151 try:
153 line[rule] = datetime.datetime.strptime(date_string,152 date_string = line[rule].split(' ')[0]
154 '%Y-%m-%d')153 line[rule] = datetime.datetime.strptime(date_string,
154 '%Y-%m-%d')
155 except ValueError as err:
156 raise except_osv(_("Date format is not valid."),
157 _(" It should be YYYY-MM-DD for column: %s"
158 " value: %s \n \n"
159 " \n Please check the line with ref: %s"
160 " \n \n Detail: %s") % (rule,
161 line.get(rule, _('Missing')),
162 line.get('ref', line),
163 repr(err)))
155 else:164 else:
156 line[rule] = conversion_rules[rule](line[rule])165 try:
166 line[rule] = conversion_rules[rule](line[rule])
167 except Exception as err:
168 raise except_osv(_('Invalid data'),
169 _("Value %s of column %s is not valid."
170 "\n Please check the line with ref %s:"
171 "\n \n Detail: %s") % (line.get(rule, _('Missing')),
172 rule,
173 line.get('ref', line),
174 repr(err)))
157 return result_set175 return result_set
158176
159 def _from_xls(self, result_set, conversion_rules):177 def _from_xls(self, result_set, conversion_rules):
@@ -164,17 +182,37 @@
164 for line in result_set:182 for line in result_set:
165 for rule in conversion_rules:183 for rule in conversion_rules:
166 if conversion_rules[rule] == datetime.datetime:184 if conversion_rules[rule] == datetime.datetime:
167 t_tuple = xlrd.xldate_as_tuple(line[rule], self._datemode)185 try:
168 line[rule] = datetime.datetime(*t_tuple)186 t_tuple = xlrd.xldate_as_tuple(line[rule], self._datemode)
187 line[rule] = datetime.datetime(*t_tuple)
188 except Exception as err:
189 raise except_osv(_("Date format is not valid"),
190 _("Please modify the cell formatting to date format"
191 " for column: %s"
192 " value: %s"
193 "\n Please check the line with ref: %s"
194 "\n \n Detail: %s") % (rule,
195 line.get(rule, _('Missing')),
196 line.get('ref', line),
197 repr(err)))
169 else:198 else:
170 line[rule] = conversion_rules[rule](line[rule])199 try:
200 line[rule] = conversion_rules[rule](line[rule])
201 except Exception as err:
202 raise except_osv(_('Invalid data'),
203 _("Value %s of column %s is not valid."
204 "\n Please check the line with ref %s:"
205 "\n \n Detail: %s") % (line.get(rule, _('Missing')),
206 rule,
207 line.get('ref', line),
208 repr(err)))
171 return result_set209 return result_set
172210
173 def _cast_rows(self, *args, **kwargs):211 def _cast_rows(self, *args, **kwargs):
174 """212 """
175 Convert the self.result_row_list using the self.convertion_dict providen.213 Convert the self.result_row_list using the self.conversion_dict providen.
176 We call here _from_xls or _from_csv depending on the self.ftype variable.214 We call here _from_xls or _from_csv depending on the self.ftype variable.
177 """215 """
178 func = getattr(self, '_from_%s' % self.ftype)216 func = getattr(self, '_from_%s' % self.ftype)
179 res = func(self.result_row_list, self.convertion_dict)217 res = func(self.result_row_list, self.conversion_dict)
180 return res218 return res
181219
=== modified file 'account_statement_base_import/parser/generic_file_parser.py'
--- account_statement_base_import/parser/generic_file_parser.py 2012-12-20 13:37:01 +0000
+++ account_statement_base_import/parser/generic_file_parser.py 2013-02-26 08:28:21 +0000
@@ -29,6 +29,11 @@
29except:29except:
30 raise Exception(_('Please install python lib xlrd'))30 raise Exception(_('Please install python lib xlrd'))
3131
32def float_or_zero(val):
33 """ Conversion function used to manage
34 empty string into float usecase"""
35 return float(val) if val else 0.0
36
3237
33class GenericFileParser(FileParser):38class GenericFileParser(FileParser):
34 """39 """
@@ -38,16 +43,16 @@
38 """43 """
3944
40 def __init__(self, parse_name, ftype='csv'):45 def __init__(self, parse_name, ftype='csv'):
41 convertion_dict = {46 conversion_dict = {
42 'ref': unicode,47 'ref': unicode,
43 'label': unicode,48 'label': unicode,
44 'date': datetime.datetime,49 'date': datetime.datetime,
45 'amount': float,50 'amount': float_or_zero,
46 'commission_amount': float51 'commission_amount': float_or_zero
47 }52 }
48 # Order of cols does not matter but first row of the file has to be header53 # Order of cols does not matter but first row of the file has to be header
49 keys_to_validate = ['ref', 'label', 'date', 'amount', 'commission_amount']54 keys_to_validate = ['ref', 'label', 'date', 'amount', 'commission_amount']
50 super(GenericFileParser, self).__init__(parse_name, keys_to_validate=keys_to_validate, ftype=ftype, convertion_dict=convertion_dict)55 super(GenericFileParser, self).__init__(parse_name, keys_to_validate=keys_to_validate, ftype=ftype, conversion_dict=conversion_dict)
5156
52 @classmethod57 @classmethod
53 def parser_for(cls, parser_name):58 def parser_for(cls, parser_name):
5459
=== modified file 'account_statement_transactionid_import/parser/transactionid_file_parser.py'
--- account_statement_transactionid_import/parser/transactionid_file_parser.py 2012-12-20 13:37:01 +0000
+++ account_statement_transactionid_import/parser/transactionid_file_parser.py 2013-02-26 08:28:21 +0000
@@ -30,7 +30,7 @@
30 """30 """
3131
32 def __init__(self, parse_name, ftype='csv'):32 def __init__(self, parse_name, ftype='csv'):
33 convertion_dict = {33 conversion_dict = {
34 'transaction_id': unicode,34 'transaction_id': unicode,
35 'label': unicode,35 'label': unicode,
36 'date': datetime.datetime,36 'date': datetime.datetime,
@@ -39,7 +39,8 @@
39 }39 }
40 # Order of cols does not matter but first row of the file has to be header40 # Order of cols does not matter but first row of the file has to be header
41 keys_to_validate = ['transaction_id', 'label', 'date', 'amount', 'commission_amount']41 keys_to_validate = ['transaction_id', 'label', 'date', 'amount', 'commission_amount']
42 super(TransactionIDFileParser, self).__init__(parse_name, keys_to_validate=keys_to_validate, ftype=ftype, convertion_dict=convertion_dict)42 super(TransactionIDFileParser, self).__init__(parse_name, keys_to_validate=keys_to_validate,
43 ftype=ftype, conversion_dict=conversion_dict)
4344
44 @classmethod45 @classmethod
45 def parser_for(cls, parser_name):46 def parser_for(cls, parser_name):

Subscribers

People subscribed via source and target branches