Merge lp:~openerp-dev/openobject-server/trunk-improve-export-ref-mat into lp:openobject-server
- trunk-improve-export-ref-mat
- Merge into trunk
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
OpenERP Core Team | Pending | ||
Review via email: mp+216035@code.launchpad.net |
Commit message
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 | 50 | def test_0(self): | 50 | def test_0(self): |
6 | 51 | self.assertEqual( | 51 | self.assertEqual( |
7 | 52 | self.export(0), | 52 | self.export(0), |
9 | 53 | [[False]]) | 53 | [['0']]) |
10 | 54 | 54 | ||
11 | 55 | def test_basic_value(self): | 55 | def test_basic_value(self): |
12 | 56 | self.assertEqual( | 56 | self.assertEqual( |
13 | @@ -73,7 +73,7 @@ | |||
14 | 73 | def test_0(self): | 73 | def test_0(self): |
15 | 74 | self.assertEqual( | 74 | self.assertEqual( |
16 | 75 | self.export(0.0), | 75 | self.export(0.0), |
18 | 76 | [[False]]) | 76 | [['0.0']]) |
19 | 77 | 77 | ||
20 | 78 | def test_epsilon(self): | 78 | def test_epsilon(self): |
21 | 79 | self.assertEqual( | 79 | self.assertEqual( |
22 | @@ -101,14 +101,14 @@ | |||
23 | 101 | def test_0(self): | 101 | def test_0(self): |
24 | 102 | self.assertEqual( | 102 | self.assertEqual( |
25 | 103 | self.export(0.0), | 103 | self.export(0.0), |
27 | 104 | [[False]]) | 104 | [['0.0']]) |
28 | 105 | 105 | ||
29 | 106 | def test_epsilon(self): | 106 | def test_epsilon(self): |
30 | 107 | """ epsilon gets sliced to 0 due to precision | 107 | """ epsilon gets sliced to 0 due to precision |
31 | 108 | """ | 108 | """ |
32 | 109 | self.assertEqual( | 109 | self.assertEqual( |
33 | 110 | self.export(0.000000000027), | 110 | self.export(0.000000000027), |
35 | 111 | [[False]]) | 111 | [['0.0']]) |
36 | 112 | 112 | ||
37 | 113 | def test_negative(self): | 113 | def test_negative(self): |
38 | 114 | self.assertEqual( | 114 | self.assertEqual( |
39 | @@ -130,7 +130,7 @@ | |||
40 | 130 | def test_empty(self): | 130 | def test_empty(self): |
41 | 131 | self.assertEqual( | 131 | self.assertEqual( |
42 | 132 | self.export(""), | 132 | self.export(""), |
44 | 133 | [[False]]) | 133 | [[""]]) |
45 | 134 | def test_within_bounds(self): | 134 | def test_within_bounds(self): |
46 | 135 | self.assertEqual( | 135 | self.assertEqual( |
47 | 136 | self.export("foobar"), | 136 | self.export("foobar"), |
48 | @@ -149,7 +149,7 @@ | |||
49 | 149 | def test_empty(self): | 149 | def test_empty(self): |
50 | 150 | self.assertEqual( | 150 | self.assertEqual( |
51 | 151 | self.export(""), | 151 | self.export(""), |
53 | 152 | [[False]]) | 152 | [[""]]) |
54 | 153 | def test_small(self): | 153 | def test_small(self): |
55 | 154 | self.assertEqual( | 154 | self.assertEqual( |
56 | 155 | self.export("foobar"), | 155 | self.export("foobar"), |
57 | @@ -171,7 +171,7 @@ | |||
58 | 171 | def test_empty(self): | 171 | def test_empty(self): |
59 | 172 | self.assertEqual( | 172 | self.assertEqual( |
60 | 173 | self.export(""), | 173 | self.export(""), |
62 | 174 | [[False]]) | 174 | [[""]]) |
63 | 175 | def test_small(self): | 175 | def test_small(self): |
64 | 176 | self.assertEqual( | 176 | self.assertEqual( |
65 | 177 | self.export("foobar"), | 177 | self.export("foobar"), |
66 | @@ -191,7 +191,7 @@ | |||
67 | 191 | def test_empty(self): | 191 | def test_empty(self): |
68 | 192 | self.assertEqual( | 192 | self.assertEqual( |
69 | 193 | self.export(False), | 193 | self.export(False), |
71 | 194 | [[False]]) | 194 | [['']]) |
72 | 195 | def test_basic(self): | 195 | def test_basic(self): |
73 | 196 | self.assertEqual( | 196 | self.assertEqual( |
74 | 197 | self.export('2011-11-07'), | 197 | self.export('2011-11-07'), |
75 | @@ -203,7 +203,7 @@ | |||
76 | 203 | def test_empty(self): | 203 | def test_empty(self): |
77 | 204 | self.assertEqual( | 204 | self.assertEqual( |
78 | 205 | self.export(False), | 205 | self.export(False), |
80 | 206 | [[False]]) | 206 | [['']]) |
81 | 207 | def test_basic(self): | 207 | def test_basic(self): |
82 | 208 | self.assertEqual( | 208 | self.assertEqual( |
83 | 209 | self.export('2011-11-07 21:05:48'), | 209 | self.export('2011-11-07 21:05:48'), |
84 | @@ -229,7 +229,7 @@ | |||
85 | 229 | def test_empty(self): | 229 | def test_empty(self): |
86 | 230 | self.assertEqual( | 230 | self.assertEqual( |
87 | 231 | self.export(False), | 231 | self.export(False), |
89 | 232 | [[False]]) | 232 | [['']]) |
90 | 233 | 233 | ||
91 | 234 | def test_value(self): | 234 | def test_value(self): |
92 | 235 | """ selections export the *label* for their value | 235 | """ selections export the *label* for their value |
93 | @@ -266,7 +266,7 @@ | |||
94 | 266 | def test_empty(self): | 266 | def test_empty(self): |
95 | 267 | self.assertEqual( | 267 | self.assertEqual( |
96 | 268 | self.export(False), | 268 | self.export(False), |
98 | 269 | [[False]]) | 269 | [['']]) |
99 | 270 | 270 | ||
100 | 271 | def test_value(self): | 271 | def test_value(self): |
101 | 272 | # FIXME: selection functions export the *value* itself | 272 | # FIXME: selection functions export the *value* itself |
102 | @@ -279,7 +279,7 @@ | |||
103 | 279 | # fucking hell | 279 | # fucking hell |
104 | 280 | self.assertEqual( | 280 | self.assertEqual( |
105 | 281 | self.export(0), | 281 | self.export(0), |
107 | 282 | [[False]]) | 282 | [['']]) |
108 | 283 | 283 | ||
109 | 284 | class test_m2o(CreatorCase): | 284 | class test_m2o(CreatorCase): |
110 | 285 | model_name = 'export.many2one' | 285 | model_name = 'export.many2one' |
111 | @@ -287,7 +287,7 @@ | |||
112 | 287 | def test_empty(self): | 287 | def test_empty(self): |
113 | 288 | self.assertEqual( | 288 | self.assertEqual( |
114 | 289 | self.export(False), | 289 | self.export(False), |
116 | 290 | [[False]]) | 290 | [['']]) |
117 | 291 | def test_basic(self): | 291 | def test_basic(self): |
118 | 292 | """ Exported value is the name_get of the related object | 292 | """ Exported value is the name_get of the related object |
119 | 293 | """ | 293 | """ |
120 | @@ -333,7 +333,7 @@ | |||
121 | 333 | def test_empty(self): | 333 | def test_empty(self): |
122 | 334 | self.assertEqual( | 334 | self.assertEqual( |
123 | 335 | self.export(False), | 335 | self.export(False), |
125 | 336 | [[False]]) | 336 | [['']]) |
126 | 337 | 337 | ||
127 | 338 | def test_single(self): | 338 | def test_single(self): |
128 | 339 | self.assertEqual( | 339 | self.assertEqual( |
129 | @@ -443,16 +443,16 @@ | |||
130 | 443 | def test_empty(self): | 443 | def test_empty(self): |
131 | 444 | self.assertEqual( | 444 | self.assertEqual( |
132 | 445 | self.export(child1=False, child2=False), | 445 | self.export(child1=False, child2=False), |
134 | 446 | [[False, False]]) | 446 | [['', '']]) |
135 | 447 | 447 | ||
136 | 448 | def test_single_per_side(self): | 448 | def test_single_per_side(self): |
137 | 449 | self.assertEqual( | 449 | self.assertEqual( |
138 | 450 | self.export(child1=False, child2=[(0, False, {'value': 42})]), | 450 | self.export(child1=False, child2=[(0, False, {'value': 42})]), |
140 | 451 | [[False, u'export.one2many.child.2:42']]) | 451 | [['', u'export.one2many.child.2:42']]) |
141 | 452 | 452 | ||
142 | 453 | self.assertEqual( | 453 | self.assertEqual( |
143 | 454 | self.export(child1=[(0, False, {'value': 43})], child2=False), | 454 | self.export(child1=[(0, False, {'value': 43})], child2=False), |
145 | 455 | [[u'export.one2many.child.1:43', False]]) | 455 | [[u'export.one2many.child.1:43', '']]) |
146 | 456 | 456 | ||
147 | 457 | self.assertEqual( | 457 | self.assertEqual( |
148 | 458 | self.export(child1=[(0, False, {'value': 43})], | 458 | self.export(child1=[(0, False, {'value': 43})], |
149 | @@ -464,12 +464,12 @@ | |||
150 | 464 | self.assertEqual( | 464 | self.assertEqual( |
151 | 465 | self.export(child1=False, child2=[(0, False, {'value': 42})], | 465 | self.export(child1=False, child2=[(0, False, {'value': 42})], |
152 | 466 | fields=fields), | 466 | fields=fields), |
154 | 467 | [[u'36', False, u'42']]) | 467 | [[u'36', '', u'42']]) |
155 | 468 | 468 | ||
156 | 469 | self.assertEqual( | 469 | self.assertEqual( |
157 | 470 | self.export(child1=[(0, False, {'value': 43})], child2=False, | 470 | self.export(child1=[(0, False, {'value': 43})], child2=False, |
158 | 471 | fields=fields), | 471 | fields=fields), |
160 | 472 | [[u'36', u'43', False]]) | 472 | [[u'36', u'43', '']]) |
161 | 473 | 473 | ||
162 | 474 | self.assertEqual( | 474 | self.assertEqual( |
163 | 475 | self.export(child1=[(0, False, {'value': 43})], | 475 | self.export(child1=[(0, False, {'value': 43})], |
164 | @@ -490,7 +490,7 @@ | |||
165 | 490 | self.assertEqual( | 490 | self.assertEqual( |
166 | 491 | self.export(child1=child1, child2=False, fields=fields), | 491 | self.export(child1=child1, child2=False, fields=fields), |
167 | 492 | [ | 492 | [ |
169 | 493 | [u'36', u'4', False], | 493 | [u'36', u'4', ''], |
170 | 494 | ['', u'42', ''], | 494 | ['', u'42', ''], |
171 | 495 | ['', u'36', ''], | 495 | ['', u'36', ''], |
172 | 496 | ['', u'4', ''], | 496 | ['', u'4', ''], |
173 | @@ -499,7 +499,7 @@ | |||
174 | 499 | self.assertEqual( | 499 | self.assertEqual( |
175 | 500 | self.export(child1=False, child2=child2, fields=fields), | 500 | self.export(child1=False, child2=child2, fields=fields), |
176 | 501 | [ | 501 | [ |
178 | 502 | [u'36', False, u'8'], | 502 | [u'36', '', u'8'], |
179 | 503 | ['', '', u'12'], | 503 | ['', '', u'12'], |
180 | 504 | ['', '', u'8'], | 504 | ['', '', u'8'], |
181 | 505 | ['', '', u'55'], | 505 | ['', '', u'55'], |
182 | @@ -538,7 +538,7 @@ | |||
183 | 538 | def test_empty(self): | 538 | def test_empty(self): |
184 | 539 | self.assertEqual( | 539 | self.assertEqual( |
185 | 540 | self.export(False), | 540 | self.export(False), |
187 | 541 | [[False]]) | 541 | [['']]) |
188 | 542 | 542 | ||
189 | 543 | def test_single(self): | 543 | def test_single(self): |
190 | 544 | self.assertEqual( | 544 | self.assertEqual( |
191 | 545 | 545 | ||
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 | 1115 | elif field_type == 'integer': | 1115 | elif field_type == 'integer': |
197 | 1116 | return 0 | 1116 | return 0 |
198 | 1117 | elif field_type == 'boolean': | 1117 | elif field_type == 'boolean': |
200 | 1118 | return 'False' | 1118 | return False |
201 | 1119 | return '' | 1119 | return '' |
202 | 1120 | 1120 | ||
203 | 1121 | def selection_field(in_field): | ||
204 | 1122 | col_obj = self.pool[in_field.keys()[0]] | ||
205 | 1123 | if f[i] in col_obj._columns.keys(): | ||
206 | 1124 | return col_obj._columns[f[i]] | ||
207 | 1125 | elif f[i] in col_obj._inherits.keys(): | ||
208 | 1126 | selection_field(col_obj._inherits) | ||
209 | 1127 | else: | ||
210 | 1128 | return False | ||
211 | 1129 | |||
212 | 1130 | def _get_xml_id(self, cr, uid, r): | 1121 | def _get_xml_id(self, cr, uid, r): |
213 | 1131 | model_data = self.pool.get('ir.model.data') | 1122 | model_data = self.pool.get('ir.model.data') |
214 | 1132 | data_ids = model_data.search(cr, uid, [('model', '=', r._model._name), ('res_id', '=', r['id'])]) | 1123 | data_ids = model_data.search(cr, uid, [('model', '=', r._model._name), ('res_id', '=', r['id'])]) |
215 | @@ -1155,57 +1146,64 @@ | |||
216 | 1155 | lines = [] | 1146 | lines = [] |
217 | 1156 | data = map(lambda x: '', range(len(fields))) | 1147 | data = map(lambda x: '', range(len(fields))) |
218 | 1157 | done = [] | 1148 | done = [] |
219 | 1149 | init_row = row | ||
220 | 1158 | for fpos in range(len(fields)): | 1150 | for fpos in range(len(fields)): |
224 | 1159 | f = fields[fpos] | 1151 | # list of fields to get through |
225 | 1160 | if f: | 1152 | fpath = fields[fpos] |
226 | 1161 | r = row | 1153 | if fpath: |
227 | 1154 | result = False | ||
228 | 1162 | i = 0 | 1155 | i = 0 |
230 | 1163 | while i < len(f): | 1156 | row = init_row |
231 | 1157 | while i < len(fpath): | ||
232 | 1164 | cols = False | 1158 | cols = False |
237 | 1165 | if f[i] == '.id': | 1159 | col_type = False |
238 | 1166 | r = r['id'] | 1160 | row_model = row._model |
239 | 1167 | elif f[i] == 'id': | 1161 | row_columns = row_model._all_columns |
240 | 1168 | r = _get_xml_id(self, cr, uid, r) | 1162 | |
241 | 1163 | if fpath[i] == '.id': | ||
242 | 1164 | result = row['id'] | ||
243 | 1165 | col_type = 'integer' | ||
244 | 1166 | elif fpath[i] == 'id': | ||
245 | 1167 | result = _get_xml_id(self, cr, uid, row) | ||
246 | 1168 | col_type = 'char' | ||
247 | 1169 | else: | 1169 | else: |
249 | 1170 | r = r[f[i]] | 1170 | result = row[fpath[i]] |
250 | 1171 | # To display external name of selection field when its exported | 1171 | # To display external name of selection field when its exported |
255 | 1172 | if f[i] in self._columns.keys(): | 1172 | if fpath[i] in row_columns.keys(): |
256 | 1173 | cols = self._columns[f[i]] | 1173 | cols = row_columns[fpath[i]].column |
253 | 1174 | elif f[i] in self._inherit_fields.keys(): | ||
254 | 1175 | cols = selection_field(self._inherits) | ||
257 | 1176 | if cols and cols._type == 'selection': | 1174 | if cols and cols._type == 'selection': |
258 | 1177 | sel_list = cols.selection | 1175 | sel_list = cols.selection |
270 | 1178 | if r and type(sel_list) == type([]): | 1176 | if result and type(sel_list) == list: |
271 | 1179 | r = [x[1] for x in sel_list if r==x[0]] | 1177 | result = [x[1] for x in sel_list if result==x[0]] |
272 | 1180 | r = r and r[0] or False | 1178 | result = result and result[0] or False |
273 | 1181 | if not r: | 1179 | col_type = cols and cols._type or False |
274 | 1182 | if f[i] in self._columns: | 1180 | |
275 | 1183 | r = check_type(self._columns[f[i]]._type) | 1181 | if col_type == 'many2one': |
276 | 1184 | elif f[i] in self._inherit_fields: | 1182 | # next iteration should use field model |
277 | 1185 | r = check_type(self._inherit_fields[f[i]][2]._type) | 1183 | row = result |
278 | 1186 | data[fpos] = r or False | 1184 | |
279 | 1187 | break | 1185 | elif col_type in ['many2many', 'one2many']: |
280 | 1188 | if isinstance(r, (browse_record_list, list)): | 1186 | # list of browse records |
281 | 1189 | first = True | 1187 | first = True |
283 | 1190 | fields2 = map(lambda x: (x[:i+1]==f[:i+1] and x[i+1:]) \ | 1188 | fields2 = map(lambda x: (x[:i+1]==fpath[:i+1] and x[i+1:]) \ |
284 | 1191 | or [], fields) | 1189 | or [], fields) |
285 | 1192 | if fields2 in done: | 1190 | if fields2 in done: |
286 | 1193 | if [x for x in fields2 if x]: | 1191 | if [x for x in fields2 if x]: |
287 | 1194 | break | 1192 | break |
288 | 1195 | done.append(fields2) | 1193 | done.append(fields2) |
291 | 1196 | if cols and cols._type=='many2many' and len(fields[fpos])>(i+1) and (fields[fpos][i+1]=='id'): | 1194 | if col_type == 'many2many' and len(fields[fpos])>(i+1) and (fields[fpos][i+1]=='id'): |
292 | 1197 | data[fpos] = ','.join([_get_xml_id(self, cr, uid, x) for x in r]) | 1195 | data[fpos] = ','.join([_get_xml_id(self, cr, uid, x) for x in result]) |
293 | 1198 | break | 1196 | break |
294 | 1199 | 1197 | ||
297 | 1200 | for row2 in r: | 1198 | for row2 in result: |
298 | 1201 | lines2 = row2._model.__export_row(cr, uid, row2, fields2, context=context) | 1199 | lines2 = row2._model.__export_row(cr, uid, row2, fields2, raw_data=raw_data, context=context) |
299 | 1202 | if first: | 1200 | if first: |
300 | 1203 | for fpos2 in range(len(fields)): | 1201 | for fpos2 in range(len(fields)): |
301 | 1204 | if lines2 and lines2[0][fpos2]: | 1202 | if lines2 and lines2[0][fpos2]: |
302 | 1205 | data[fpos2] = lines2[0][fpos2] | 1203 | data[fpos2] = lines2[0][fpos2] |
303 | 1206 | if not data[fpos]: | 1204 | if not data[fpos]: |
304 | 1207 | dt = '' | 1205 | dt = '' |
306 | 1208 | for rr in r: | 1206 | for rr in result: |
307 | 1209 | name_relation = self.pool[rr._table_name]._rec_name | 1207 | name_relation = self.pool[rr._table_name]._rec_name |
308 | 1210 | if isinstance(rr[name_relation], browse_record): | 1208 | if isinstance(rr[name_relation], browse_record): |
309 | 1211 | rr = rr[name_relation] | 1209 | rr = rr[name_relation] |
310 | @@ -1218,21 +1216,33 @@ | |||
311 | 1218 | first = False | 1216 | first = False |
312 | 1219 | else: | 1217 | else: |
313 | 1220 | lines += lines2 | 1218 | lines += lines2 |
314 | 1219 | # data already in | ||
315 | 1221 | break | 1220 | break |
316 | 1222 | i += 1 | 1221 | i += 1 |
317 | 1223 | 1222 | ||
328 | 1224 | if i == len(f): | 1223 | # skip in case of *2m where data is already set |
329 | 1225 | if isinstance(r, browse_record): | 1224 | if i == len(fpath): |
330 | 1226 | r = self.pool[r._table_name].name_get(cr, uid, [r.id], context=context) | 1225 | if isinstance(result, browse_record): |
331 | 1227 | r = r and r[0] and r[0][1] or '' | 1226 | result = self.pool[result._table_name].name_get(cr, uid, [result.id], context=context) |
332 | 1228 | if raw_data and cols and cols._type in ('integer', 'boolean', 'float'): | 1227 | result = result and result[0] and result[0][1] or '' |
333 | 1229 | data[fpos] = r | 1228 | if raw_data and col_type in ('integer', 'boolean', 'float'): |
334 | 1230 | elif raw_data and cols and cols._type == 'date': | 1229 | data[fpos] = result |
335 | 1231 | data[fpos] = datetime.datetime.strptime(r, tools.DEFAULT_SERVER_DATE_FORMAT).date() | 1230 | elif raw_data and col_type == 'date': |
336 | 1232 | elif raw_data and cols and cols._type == 'datetime': | 1231 | data[fpos] = datetime.datetime.strptime(result, tools.DEFAULT_SERVER_DATE_FORMAT).date() |
337 | 1233 | data[fpos] = datetime.datetime.strptime(r, tools.DEFAULT_SERVER_DATETIME_FORMAT) | 1232 | elif raw_data and col_type == 'datetime': |
338 | 1233 | data[fpos] = datetime.datetime.strptime(result, tools.DEFAULT_SERVER_DATETIME_FORMAT) | ||
339 | 1234 | elif not result: | ||
340 | 1235 | if col_type == 'float': | ||
341 | 1236 | data[fpos] = '0.0' | ||
342 | 1237 | elif col_type == 'integer': | ||
343 | 1238 | data[fpos] = '0' | ||
344 | 1239 | elif col_type == 'boolean': | ||
345 | 1240 | data[fpos] = 'False' | ||
346 | 1241 | else: | ||
347 | 1242 | data[fpos] = '' | ||
348 | 1234 | else: | 1243 | else: |
350 | 1235 | data[fpos] = tools.ustr(r or '') | 1244 | data[fpos] = tools.ustr(result) |
351 | 1245 | |||
352 | 1236 | return [data] + lines | 1246 | return [data] + lines |
353 | 1237 | 1247 | ||
354 | 1238 | def export_data(self, cr, uid, ids, fields_to_export, raw_data=False, context=None): | 1248 | def export_data(self, cr, uid, ids, fields_to_export, raw_data=False, context=None): |