Merge lp:~openerp-dev/openobject-server/trunk-improve-export-ref-mat into lp:openobject-server

Proposed by Martin Trigaux (OpenERP)
Status: Work in progress
Proposed branch: lp:~openerp-dev/openobject-server/trunk-improve-export-ref-mat
Merge into: lp:openobject-server
Diff against target: 354 lines (+83/-73)
2 files modified
openerp/addons/test_impex/tests/test_export.py (+22/-22)
openerp/osv/orm.py (+61/-51)
To merge this branch: bzr merge lp:~openerp-dev/openobject-server/trunk-improve-export-ref-mat
Reviewer Review Type Date Requested Status
OpenERP Core Team Pending
Review via email: mp+216035@code.launchpad.net

Description of the change

refactoring export for better excel

To post a comment you must log in.
5164. By Martin Trigaux (OpenERP)

improving tests and export

5165. By Martin Trigaux (OpenERP)

[FIX] initialise value

Unmerged revisions

5165. By Martin Trigaux (OpenERP)

[FIX] initialise value

5164. By Martin Trigaux (OpenERP)

improving tests and export

5163. By Martin Trigaux (OpenERP)

sync with trunk

5162. By Martin Trigaux (OpenERP)

[FIX] export: when exporting make sure use correct model, improve raw data export, clean code

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openerp/addons/test_impex/tests/test_export.py'
2--- openerp/addons/test_impex/tests/test_export.py 2013-10-24 21:47:35 +0000
3+++ openerp/addons/test_impex/tests/test_export.py 2014-04-16 13:23:35 +0000
4@@ -50,7 +50,7 @@
5 def test_0(self):
6 self.assertEqual(
7 self.export(0),
8- [[False]])
9+ [['0']])
10
11 def test_basic_value(self):
12 self.assertEqual(
13@@ -73,7 +73,7 @@
14 def test_0(self):
15 self.assertEqual(
16 self.export(0.0),
17- [[False]])
18+ [['0.0']])
19
20 def test_epsilon(self):
21 self.assertEqual(
22@@ -101,14 +101,14 @@
23 def test_0(self):
24 self.assertEqual(
25 self.export(0.0),
26- [[False]])
27+ [['0.0']])
28
29 def test_epsilon(self):
30 """ epsilon gets sliced to 0 due to precision
31 """
32 self.assertEqual(
33 self.export(0.000000000027),
34- [[False]])
35+ [['0.0']])
36
37 def test_negative(self):
38 self.assertEqual(
39@@ -130,7 +130,7 @@
40 def test_empty(self):
41 self.assertEqual(
42 self.export(""),
43- [[False]])
44+ [[""]])
45 def test_within_bounds(self):
46 self.assertEqual(
47 self.export("foobar"),
48@@ -149,7 +149,7 @@
49 def test_empty(self):
50 self.assertEqual(
51 self.export(""),
52- [[False]])
53+ [[""]])
54 def test_small(self):
55 self.assertEqual(
56 self.export("foobar"),
57@@ -171,7 +171,7 @@
58 def test_empty(self):
59 self.assertEqual(
60 self.export(""),
61- [[False]])
62+ [[""]])
63 def test_small(self):
64 self.assertEqual(
65 self.export("foobar"),
66@@ -191,7 +191,7 @@
67 def test_empty(self):
68 self.assertEqual(
69 self.export(False),
70- [[False]])
71+ [['']])
72 def test_basic(self):
73 self.assertEqual(
74 self.export('2011-11-07'),
75@@ -203,7 +203,7 @@
76 def test_empty(self):
77 self.assertEqual(
78 self.export(False),
79- [[False]])
80+ [['']])
81 def test_basic(self):
82 self.assertEqual(
83 self.export('2011-11-07 21:05:48'),
84@@ -229,7 +229,7 @@
85 def test_empty(self):
86 self.assertEqual(
87 self.export(False),
88- [[False]])
89+ [['']])
90
91 def test_value(self):
92 """ selections export the *label* for their value
93@@ -266,7 +266,7 @@
94 def test_empty(self):
95 self.assertEqual(
96 self.export(False),
97- [[False]])
98+ [['']])
99
100 def test_value(self):
101 # FIXME: selection functions export the *value* itself
102@@ -279,7 +279,7 @@
103 # fucking hell
104 self.assertEqual(
105 self.export(0),
106- [[False]])
107+ [['']])
108
109 class test_m2o(CreatorCase):
110 model_name = 'export.many2one'
111@@ -287,7 +287,7 @@
112 def test_empty(self):
113 self.assertEqual(
114 self.export(False),
115- [[False]])
116+ [['']])
117 def test_basic(self):
118 """ Exported value is the name_get of the related object
119 """
120@@ -333,7 +333,7 @@
121 def test_empty(self):
122 self.assertEqual(
123 self.export(False),
124- [[False]])
125+ [['']])
126
127 def test_single(self):
128 self.assertEqual(
129@@ -443,16 +443,16 @@
130 def test_empty(self):
131 self.assertEqual(
132 self.export(child1=False, child2=False),
133- [[False, False]])
134+ [['', '']])
135
136 def test_single_per_side(self):
137 self.assertEqual(
138 self.export(child1=False, child2=[(0, False, {'value': 42})]),
139- [[False, u'export.one2many.child.2:42']])
140+ [['', u'export.one2many.child.2:42']])
141
142 self.assertEqual(
143 self.export(child1=[(0, False, {'value': 43})], child2=False),
144- [[u'export.one2many.child.1:43', False]])
145+ [[u'export.one2many.child.1:43', '']])
146
147 self.assertEqual(
148 self.export(child1=[(0, False, {'value': 43})],
149@@ -464,12 +464,12 @@
150 self.assertEqual(
151 self.export(child1=False, child2=[(0, False, {'value': 42})],
152 fields=fields),
153- [[u'36', False, u'42']])
154+ [[u'36', '', u'42']])
155
156 self.assertEqual(
157 self.export(child1=[(0, False, {'value': 43})], child2=False,
158 fields=fields),
159- [[u'36', u'43', False]])
160+ [[u'36', u'43', '']])
161
162 self.assertEqual(
163 self.export(child1=[(0, False, {'value': 43})],
164@@ -490,7 +490,7 @@
165 self.assertEqual(
166 self.export(child1=child1, child2=False, fields=fields),
167 [
168- [u'36', u'4', False],
169+ [u'36', u'4', ''],
170 ['', u'42', ''],
171 ['', u'36', ''],
172 ['', u'4', ''],
173@@ -499,7 +499,7 @@
174 self.assertEqual(
175 self.export(child1=False, child2=child2, fields=fields),
176 [
177- [u'36', False, u'8'],
178+ [u'36', '', u'8'],
179 ['', '', u'12'],
180 ['', '', u'8'],
181 ['', '', u'55'],
182@@ -538,7 +538,7 @@
183 def test_empty(self):
184 self.assertEqual(
185 self.export(False),
186- [[False]])
187+ [['']])
188
189 def test_single(self):
190 self.assertEqual(
191
192=== modified file 'openerp/osv/orm.py'
193--- openerp/osv/orm.py 2014-04-11 07:55:56 +0000
194+++ openerp/osv/orm.py 2014-04-16 13:23:35 +0000
195@@ -1115,18 +1115,9 @@
196 elif field_type == 'integer':
197 return 0
198 elif field_type == 'boolean':
199- return 'False'
200+ return False
201 return ''
202
203- def selection_field(in_field):
204- col_obj = self.pool[in_field.keys()[0]]
205- if f[i] in col_obj._columns.keys():
206- return col_obj._columns[f[i]]
207- elif f[i] in col_obj._inherits.keys():
208- selection_field(col_obj._inherits)
209- else:
210- return False
211-
212 def _get_xml_id(self, cr, uid, r):
213 model_data = self.pool.get('ir.model.data')
214 data_ids = model_data.search(cr, uid, [('model', '=', r._model._name), ('res_id', '=', r['id'])])
215@@ -1155,57 +1146,64 @@
216 lines = []
217 data = map(lambda x: '', range(len(fields)))
218 done = []
219+ init_row = row
220 for fpos in range(len(fields)):
221- f = fields[fpos]
222- if f:
223- r = row
224+ # list of fields to get through
225+ fpath = fields[fpos]
226+ if fpath:
227+ result = False
228 i = 0
229- while i < len(f):
230+ row = init_row
231+ while i < len(fpath):
232 cols = False
233- if f[i] == '.id':
234- r = r['id']
235- elif f[i] == 'id':
236- r = _get_xml_id(self, cr, uid, r)
237+ col_type = False
238+ row_model = row._model
239+ row_columns = row_model._all_columns
240+
241+ if fpath[i] == '.id':
242+ result = row['id']
243+ col_type = 'integer'
244+ elif fpath[i] == 'id':
245+ result = _get_xml_id(self, cr, uid, row)
246+ col_type = 'char'
247 else:
248- r = r[f[i]]
249+ result = row[fpath[i]]
250 # To display external name of selection field when its exported
251- if f[i] in self._columns.keys():
252- cols = self._columns[f[i]]
253- elif f[i] in self._inherit_fields.keys():
254- cols = selection_field(self._inherits)
255+ if fpath[i] in row_columns.keys():
256+ cols = row_columns[fpath[i]].column
257 if cols and cols._type == 'selection':
258 sel_list = cols.selection
259- if r and type(sel_list) == type([]):
260- r = [x[1] for x in sel_list if r==x[0]]
261- r = r and r[0] or False
262- if not r:
263- if f[i] in self._columns:
264- r = check_type(self._columns[f[i]]._type)
265- elif f[i] in self._inherit_fields:
266- r = check_type(self._inherit_fields[f[i]][2]._type)
267- data[fpos] = r or False
268- break
269- if isinstance(r, (browse_record_list, list)):
270+ if result and type(sel_list) == list:
271+ result = [x[1] for x in sel_list if result==x[0]]
272+ result = result and result[0] or False
273+ col_type = cols and cols._type or False
274+
275+ if col_type == 'many2one':
276+ # next iteration should use field model
277+ row = result
278+
279+ elif col_type in ['many2many', 'one2many']:
280+ # list of browse records
281 first = True
282- fields2 = map(lambda x: (x[:i+1]==f[:i+1] and x[i+1:]) \
283+ fields2 = map(lambda x: (x[:i+1]==fpath[:i+1] and x[i+1:]) \
284 or [], fields)
285 if fields2 in done:
286 if [x for x in fields2 if x]:
287 break
288 done.append(fields2)
289- if cols and cols._type=='many2many' and len(fields[fpos])>(i+1) and (fields[fpos][i+1]=='id'):
290- data[fpos] = ','.join([_get_xml_id(self, cr, uid, x) for x in r])
291+ if col_type == 'many2many' and len(fields[fpos])>(i+1) and (fields[fpos][i+1]=='id'):
292+ data[fpos] = ','.join([_get_xml_id(self, cr, uid, x) for x in result])
293 break
294
295- for row2 in r:
296- lines2 = row2._model.__export_row(cr, uid, row2, fields2, context=context)
297+ for row2 in result:
298+ lines2 = row2._model.__export_row(cr, uid, row2, fields2, raw_data=raw_data, context=context)
299 if first:
300 for fpos2 in range(len(fields)):
301 if lines2 and lines2[0][fpos2]:
302 data[fpos2] = lines2[0][fpos2]
303 if not data[fpos]:
304 dt = ''
305- for rr in r:
306+ for rr in result:
307 name_relation = self.pool[rr._table_name]._rec_name
308 if isinstance(rr[name_relation], browse_record):
309 rr = rr[name_relation]
310@@ -1218,21 +1216,33 @@
311 first = False
312 else:
313 lines += lines2
314+ # data already in
315 break
316 i += 1
317
318- if i == len(f):
319- if isinstance(r, browse_record):
320- r = self.pool[r._table_name].name_get(cr, uid, [r.id], context=context)
321- r = r and r[0] and r[0][1] or ''
322- if raw_data and cols and cols._type in ('integer', 'boolean', 'float'):
323- data[fpos] = r
324- elif raw_data and cols and cols._type == 'date':
325- data[fpos] = datetime.datetime.strptime(r, tools.DEFAULT_SERVER_DATE_FORMAT).date()
326- elif raw_data and cols and cols._type == 'datetime':
327- data[fpos] = datetime.datetime.strptime(r, tools.DEFAULT_SERVER_DATETIME_FORMAT)
328+ # skip in case of *2m where data is already set
329+ if i == len(fpath):
330+ if isinstance(result, browse_record):
331+ result = self.pool[result._table_name].name_get(cr, uid, [result.id], context=context)
332+ result = result and result[0] and result[0][1] or ''
333+ if raw_data and col_type in ('integer', 'boolean', 'float'):
334+ data[fpos] = result
335+ elif raw_data and col_type == 'date':
336+ data[fpos] = datetime.datetime.strptime(result, tools.DEFAULT_SERVER_DATE_FORMAT).date()
337+ elif raw_data and col_type == 'datetime':
338+ data[fpos] = datetime.datetime.strptime(result, tools.DEFAULT_SERVER_DATETIME_FORMAT)
339+ elif not result:
340+ if col_type == 'float':
341+ data[fpos] = '0.0'
342+ elif col_type == 'integer':
343+ data[fpos] = '0'
344+ elif col_type == 'boolean':
345+ data[fpos] = 'False'
346+ else:
347+ data[fpos] = ''
348 else:
349- data[fpos] = tools.ustr(r or '')
350+ data[fpos] = tools.ustr(result)
351+
352 return [data] + lines
353
354 def export_data(self, cr, uid, ids, fields_to_export, raw_data=False, context=None):