29
29
class external_osv(osv.osv):
31
def read_w_order(self, cr, user, ids, fields_to_read=None, context=None, load='_classic_read'):
32
res = self.read(cr, user, ids, fields_to_read, context, load)
35
resultat += [x for x in res if x['id'] == id]
38
def browse_w_order(self, cr, uid, ids, context=None, list_class=None, fields_process={}):
39
res = self.browse(cr, uid, ids, context, list_class, fields_process)
42
resultat += [x for x in res if x.id == id]
45
def prefixed_id(self, id):
46
"""The reason why we don't just use the external id and put the model as the prefix is to avoid unique ir_model_data#name per module constraint violation."""
47
return self._name.replace('.', '_') + '/' + str(id)
49
def id_from_prefixed_id(self, prefixed_id):
50
return prefixed_id.split(self._name.replace('.', '_') + '/')[1]
52
def get_last_imported_external_id(self, cr, object_name, referential_id, where_clause):
53
table_name = object_name.replace('.', '_')
55
SELECT %(table_name)s.id, ir_model_data.name from %(table_name)s inner join ir_model_data
56
ON %(table_name)s.id = ir_model_data.res_id
57
WHERE ir_model_data.model=%%s %(where_clause)s
58
AND ir_model_data.external_referential_id = %%s
59
ORDER BY %(table_name)s.create_date DESC
61
""" % { 'table_name' : table_name, 'where_clause' : where_clause and ("and " + where_clause) or ""}
62
, (object_name, referential_id,))
63
results = cr.fetchone()
64
if results and len(results) > 0:
65
return [results[0], results[1].split(object_name.replace('.', '_') +'/')[1]]
69
def get_modified_ids(self, cr, uid, date=False, context=None):
70
""" This function will return the ids of the modified or created items of self object since the date
72
@return: a table of this format : [[id1, last modified date], [id2, last modified date] ...] """
74
sql_request = "SELECT id, create_date, write_date FROM %s " % (self._name.replace('.', '_'),)
75
sql_request += "WHERE create_date > %s OR write_date > %s;"
76
cr.execute(sql_request, (date, date))
78
sql_request = "SELECT id, create_date, write_date FROM %s " % (self._name.replace('.', '_'),)
79
cr.execute(sql_request)
87
return sorted(res, key=lambda date: date[1])
89
def external_connection(self, cr, uid, DEBUG=False):
90
"""Should be overridden to provide valid external referential connection"""
93
def oeid_to_extid(self, cr, uid, id, external_referential_id, context=None):
94
"""Returns the external id of a resource by its OpenERP id.
95
Returns False if the resource id does not exists."""
96
model_data_ids = self.pool.get('ir.model.data').search(cr, uid, [('model', '=', self._name), ('res_id', '=', id), ('external_referential_id', '=', external_referential_id)])
97
if model_data_ids and len(model_data_ids) > 0:
98
prefixed_id = self.pool.get('ir.model.data').read(cr, uid, model_data_ids[0], ['name'])['name']
99
ext_id = int(self.id_from_prefixed_id(prefixed_id))
103
def extid_to_existing_oeid(self, cr, uid, id, external_referential_id, context=None):
104
"""Returns the OpenERP id of a resource by its external id.
105
Returns False if the resource does not exist."""
107
model_data_ids = self.pool.get('ir.model.data').search(cr, uid, [('name', '=', self.prefixed_id(id)), ('model', '=', self._name), ('external_referential_id', '=', external_referential_id)])
109
claimed_oe_id = self.pool.get('ir.model.data').read(cr, uid, model_data_ids[0], ['res_id'])['res_id']
111
#because OpenERP might keep ir_model_data (is it a bug?) for deleted records, we check if record exists:
112
ids = self.search(cr, uid, [('id', '=', claimed_oe_id)])
117
def extid_to_oeid(self, cr, uid, id, external_referential_id, context=None):
118
"""Returns the OpenERP ID of a resource by its external id.
119
Creates the resource from the external connection if the resource does not exist."""
120
#First get the external key field name
121
#conversion external id -> OpenERP object using Object mapping_column_name key!
123
existing_id = self.extid_to_existing_oeid(cr, uid, id, external_referential_id, context)
127
if context and context.get('alternative_key', False): #FIXME dirty fix for Magento product.info id/sku mix bug: https://bugs.launchpad.net/magentoerpconnect/+bug/688225
128
id = context.get('alternative_key', False)
129
result = self.get_external_data(cr, uid, self.external_connection(cr, uid, self.pool.get('external.referential').browse(cr, uid, external_referential_id)), external_referential_id, {}, {'id':id})
130
if len(result['create_ids']) == 1:
131
return result['create_ids'][0]
132
except Exception, error: #external system might return error because no such record exists
136
def oevals_from_extdata(self, cr, uid, external_referential_id, data_record, key_field, mapping_lines, defaults, context):
139
vals = {} #Dictionary for create record
140
for each_mapping_line in mapping_lines:
141
#Type cast if the expression exists
142
if each_mapping_line['external_field'] in data_record.keys():
144
if each_mapping_line['external_type'] and type(data_record.get(each_mapping_line['external_field'], False)) != unicode:
145
type_casted_field = eval(each_mapping_line['external_type'])(data_record.get(each_mapping_line['external_field'], False))
30
pass #FIXME remove! only here for compatibility purpose for now
32
def read_w_order(self, cr, user, ids, fields_to_read=None, context=None, load='_classic_read'):
33
res = self.read(cr, user, ids, fields_to_read, context, load)
36
resultat += [x for x in res if x['id'] == id]
39
def browse_w_order(self, cr, uid, ids, context=None, list_class=None, fields_process={}):
40
res = self.browse(cr, uid, ids, context, list_class, fields_process)
43
resultat += [x for x in res if x.id == id]
46
def prefixed_id(self, id):
47
"""The reason why we don't just use the external id and put the model as the prefix is to avoid unique ir_model_data#name per module constraint violation."""
48
return self._name.replace('.', '_') + '/' + str(id)
50
def id_from_prefixed_id(self, prefixed_id):
51
return prefixed_id.split(self._name.replace('.', '_') + '/')[1]
53
def get_last_imported_external_id(self, cr, object_name, referential_id, where_clause):
54
table_name = object_name.replace('.', '_')
56
SELECT %(table_name)s.id, ir_model_data.name from %(table_name)s inner join ir_model_data
57
ON %(table_name)s.id = ir_model_data.res_id
58
WHERE ir_model_data.model=%%s %(where_clause)s
59
AND ir_model_data.external_referential_id = %%s
60
ORDER BY %(table_name)s.create_date DESC
62
""" % { 'table_name' : table_name, 'where_clause' : where_clause and ("and " + where_clause) or ""}
63
, (object_name, referential_id,))
64
results = cr.fetchone()
65
if results and len(results) > 0:
66
return [results[0], results[1].split(object_name.replace('.', '_') +'/')[1]]
70
def get_modified_ids(self, cr, uid, date=False, context=None):
71
""" This function will return the ids of the modified or created items of self object since the date
73
@return: a table of this format : [[id1, last modified date], [id2, last modified date] ...] """
75
sql_request = "SELECT id, create_date, write_date FROM %s " % (self._name.replace('.', '_'),)
76
sql_request += "WHERE create_date > %s OR write_date > %s;"
77
cr.execute(sql_request, (date, date))
79
sql_request = "SELECT id, create_date, write_date FROM %s " % (self._name.replace('.', '_'),)
80
cr.execute(sql_request)
88
return sorted(res, key=lambda date: date[1])
90
def external_connection(self, cr, uid, DEBUG=False):
91
"""Should be overridden to provide valid external referential connection"""
94
def oeid_to_extid(self, cr, uid, id, external_referential_id, context=None):
95
"""Returns the external id of a resource by its OpenERP id.
96
Returns False if the resource id does not exists."""
97
model_data_ids = self.pool.get('ir.model.data').search(cr, uid, [('model', '=', self._name), ('res_id', '=', id), ('external_referential_id', '=', external_referential_id)])
98
if model_data_ids and len(model_data_ids) > 0:
99
prefixed_id = self.pool.get('ir.model.data').read(cr, uid, model_data_ids[0], ['name'])['name']
100
ext_id = int(self.id_from_prefixed_id(prefixed_id))
104
def extid_to_existing_oeid(self, cr, uid, id, external_referential_id, context=None):
105
"""Returns the OpenERP id of a resource by its external id.
106
Returns False if the resource does not exist."""
108
model_data_ids = self.pool.get('ir.model.data').search(cr, uid, [('name', '=', self.prefixed_id(id)), ('model', '=', self._name), ('external_referential_id', '=', external_referential_id)])
110
claimed_oe_id = self.pool.get('ir.model.data').read(cr, uid, model_data_ids[0], ['res_id'])['res_id']
112
#because OpenERP might keep ir_model_data (is it a bug?) for deleted records, we check if record exists:
113
ids = self.search(cr, uid, [('id', '=', claimed_oe_id)])
118
def extid_to_oeid(self, cr, uid, id, external_referential_id, context=None):
119
"""Returns the OpenERP ID of a resource by its external id.
120
Creates the resource from the external connection if the resource does not exist."""
121
#First get the external key field name
122
#conversion external id -> OpenERP object using Object mapping_column_name key!
124
existing_id = self.extid_to_existing_oeid(cr, uid, id, external_referential_id, context)
128
if context and context.get('alternative_key', False): #FIXME dirty fix for Magento product.info id/sku mix bug: https://bugs.launchpad.net/magentoerpconnect/+bug/688225
129
id = context.get('alternative_key', False)
130
result = self.get_external_data(cr, uid, self.external_connection(cr, uid, self.pool.get('external.referential').browse(cr, uid, external_referential_id)), external_referential_id, {}, {'id':id})
131
if len(result['create_ids']) == 1:
132
return result['create_ids'][0]
133
except Exception, error: #external system might return error because no such record exists
137
def oevals_from_extdata(self, cr, uid, external_referential_id, data_record, key_field, mapping_lines, defaults, context):
140
vals = {} #Dictionary for create record
141
for each_mapping_line in mapping_lines:
142
#Type cast if the expression exists
143
if each_mapping_line['external_field'] in data_record.keys():
145
if each_mapping_line['external_type'] and type(data_record.get(each_mapping_line['external_field'], False)) != unicode:
146
type_casted_field = eval(each_mapping_line['external_type'])(data_record.get(each_mapping_line['external_field'], False))
148
type_casted_field = data_record.get(each_mapping_line['external_field'], False)
149
if type_casted_field in ['None', 'False']:
150
type_casted_field = False
152
type_casted_field = False
153
#Build the space for expr
159
'external_referential_id':external_referential_id,
162
'ifield':type_casted_field,
163
'conn':context.get('conn_obj', False),
167
#The expression should return value in list of tuple format
168
#eg[('name','Sharoon'),('age',20)] -> vals = {'name':'Sharoon', 'age':20}
170
exec each_mapping_line['in_function'] in space
172
logger = netsvc.Logger()
173
logger.notifyChannel('extdata_from_oevals', netsvc.LOG_DEBUG, "Error in import mapping: %r" % (each_mapping_line['in_function'],))
174
del(space['__builtins__'])
175
logger.notifyChannel('extdata_from_oevals', netsvc.LOG_DEBUG, "Mapping Context: %r" % (space,))
176
logger.notifyChannel('extdata_from_oevals', netsvc.LOG_DEBUG, "Exception: %r" % (e,))
177
result = space.get('result', False)
178
#If result exists and is of type list
179
if result and type(result) == list:
180
for each_tuple in result:
181
if type(each_tuple) == tuple and len(each_tuple) == 2:
182
vals[each_tuple[0]] = each_tuple[1]
183
#Every mapping line has now been translated into vals dictionary, now set defaults if any
184
for each_default_entry in defaults.keys():
185
vals[each_default_entry] = defaults[each_default_entry]
190
def get_external_data(self, cr, uid, conn, external_referential_id, defaults=None, context=None):
191
"""Constructs data using WS or other synch protocols and then call ext_import on it"""
192
return {'create_ids': [], 'write_ids': []}
194
def add_external_reference(self, cr, uid, id, external_id, external_referential_id, context=None):
195
'''Add an external id on an existing object'''
198
ir_model_data_vals = {
199
'name': self.prefixed_id(external_id),
202
'external_referential_id': external_referential_id,
203
'module': 'extref/' + self.pool.get('external.referential').read(cr, uid, external_referential_id, ['name'])['name']
205
self.pool.get('ir.model.data').create(cr, uid, ir_model_data_vals, context=context)
208
def ext_import(self, cr, uid, data, external_referential_id, defaults=None, context=None):
214
#Inward data has to be list of dictionary
215
#This function will import a given set of data as list of dictionary into Open ERP
216
write_ids = [] #Will record ids of records modified, not sure if will be used
217
create_ids = [] #Will record ids of newly created records, not sure if will be used
218
logger = netsvc.Logger()
220
mapping_id = self.pool.get('external.mapping').search(cr, uid, [('model', '=', self._name), ('referential_id', '=', external_referential_id)])
222
#If a mapping exists for current model, search for mapping lines
223
mapping_line_ids = self.pool.get('external.mapping.line').search(cr, uid, [('mapping_id', '=', mapping_id), ('type', 'in', ['in_out', 'in'])])
224
mapping_lines = self.pool.get('external.mapping.line').read(cr, uid, mapping_line_ids, ['external_field', 'external_type', 'in_function'])
226
#if mapping lines exist find the data conversion for each row in inward data
227
for_key_field = self.pool.get('external.mapping').read(cr, uid, mapping_id[0], ['external_key_name'])['external_key_name']
228
for each_row in data:
229
vals = self.oevals_from_extdata(cr, uid, external_referential_id, each_row, for_key_field, mapping_lines, defaults, context)
230
#perform a record check, for that we need foreign field
231
external_id = vals.get(for_key_field, False) or each_row.get(for_key_field, False) or each_row.get('external_id', False)
232
#del vals[for_key_field] looks like it is affecting the import :(
233
#Check if record exists
234
existing_ir_model_data_id = self.pool.get('ir.model.data').search(cr, uid, [('model', '=', self._name), ('name', '=', self.prefixed_id(external_id)), ('external_referential_id', '=', external_referential_id)])
235
record_test_id = False
236
if existing_ir_model_data_id:
237
existing_rec_id = self.pool.get('ir.model.data').read(cr, uid, existing_ir_model_data_id, ['res_id'])[0]['res_id']
239
#Note: OpenERP cleans up ir_model_data which res_id records have been deleted only at server update because that would be a perf penalty,
240
#so we take care of it here:
241
record_test_id = self.search(cr, uid, [('id', '=', existing_rec_id)])
242
if not record_test_id:
243
self.pool.get('ir.model.data').unlink(cr, uid, existing_ir_model_data_id)
246
if vals.get(for_key_field, False):
247
del vals[for_key_field]
248
if self.oe_update(cr, uid, existing_rec_id, vals, each_row, external_referential_id, defaults, context):
249
write_ids.append(existing_rec_id)
250
self.pool.get('ir.model.data').write(cr, uid, existing_ir_model_data_id, {'res_id':existing_rec_id})
251
logger.notifyChannel('ext synchro', netsvc.LOG_INFO, "Updated in OpenERP %s from External Ref with external_id %s and OpenERP id %s successfully" %(self._name, external_id, existing_rec_id))
147
type_casted_field = data_record.get(each_mapping_line['external_field'], False)
148
if type_casted_field in ['None', 'False']:
149
type_casted_field = False
151
type_casted_field = False
152
#Build the space for expr
158
'external_referential_id':external_referential_id,
161
'ifield':type_casted_field,
162
'conn':context.get('conn_obj', False),
254
crid = self.oe_create(cr, uid, vals, each_row, external_referential_id, defaults, context)
255
create_ids.append(crid)
256
ir_model_data_vals = {
257
'name': self.prefixed_id(external_id),
260
'external_referential_id': external_referential_id,
261
'module': 'extref/' + self.pool.get('external.referential').read(cr, uid, external_referential_id, ['name'])['name']
166
#The expression should return value in list of tuple format
167
#eg[('name','Sharoon'),('age',20)] -> vals = {'name':'Sharoon', 'age':20}
169
exec each_mapping_line['in_function'] in space
171
logger = netsvc.Logger()
172
logger.notifyChannel('extdata_from_oevals', netsvc.LOG_DEBUG, "Error in import mapping: %r" % (each_mapping_line['in_function'],))
173
del(space['__builtins__'])
174
logger.notifyChannel('extdata_from_oevals', netsvc.LOG_DEBUG, "Mapping Context: %r" % (space,))
175
logger.notifyChannel('extdata_from_oevals', netsvc.LOG_DEBUG, "Exception: %r" % (e,))
176
result = space.get('result', False)
177
#If result exists and is of type list
178
if result and type(result) == list:
179
for each_tuple in result:
180
if type(each_tuple) == tuple and len(each_tuple) == 2:
181
vals[each_tuple[0]] = each_tuple[1]
182
#Every mapping line has now been translated into vals dictionary, now set defaults if any
183
for each_default_entry in defaults.keys():
184
vals[each_default_entry] = defaults[each_default_entry]
189
def get_external_data(self, cr, uid, conn, external_referential_id, defaults=None, context=None):
190
"""Constructs data using WS or other synch protocols and then call ext_import on it"""
191
return {'create_ids': [], 'write_ids': []}
193
def ext_import(self, cr, uid, data, external_referential_id, defaults=None, context=None):
199
#Inward data has to be list of dictionary
200
#This function will import a given set of data as list of dictionary into Open ERP
201
write_ids = [] #Will record ids of records modified, not sure if will be used
202
create_ids = [] #Will record ids of newly created records, not sure if will be used
203
logger = netsvc.Logger()
205
mapping_id = self.pool.get('external.mapping').search(cr, uid, [('model', '=', self._name), ('referential_id', '=', external_referential_id)])
263
self.pool.get('ir.model.data').create(cr, uid, ir_model_data_vals)
264
logger.notifyChannel('ext synchro', netsvc.LOG_INFO, "Created in OpenERP %s from External Ref with external_id %s and OpenERP id %s successfully" %(self._name, external_id, crid))
267
return {'create_ids': create_ids, 'write_ids': write_ids}
270
def retry_import(self, cr, uid, id, external_referential_id, defaults=None, context=None):
271
""" When we import again a previously failed import
273
raise osv.except_osv(_("Not Implemented"), _("Not Implemented in abstract base module!"))
275
def oe_update(self, cr, uid, existing_rec_id, vals, data, external_referential_id, defaults, context):
276
return self.write(cr, uid, existing_rec_id, vals, context)
279
def oe_create(self, cr, uid, vals, data, external_referential_id, defaults, context):
280
return self.create(cr, uid, vals, context)
283
def extdata_from_oevals(self, cr, uid, external_referential_id, data_record, mapping_lines, defaults, context=None):
286
vals = {} #Dictionary for record
287
for each_mapping_line in mapping_lines:
288
#Build the space for expr
293
'external_referential_id':external_referential_id,
296
'record':data_record,
297
'conn':context.get('conn_obj', False),
300
#The expression should return value in list of tuple format
301
#eg[('name','Sharoon'),('age',20)] -> vals = {'name':'Sharoon', 'age':20}
302
if each_mapping_line['out_function']:
304
exec each_mapping_line['out_function'] in space
306
logger = netsvc.Logger()
307
logger.notifyChannel('extdata_from_oevals', netsvc.LOG_DEBUG, "Error in import mapping: %r" % (each_mapping_line['out_function'],))
308
del(space['__builtins__'])
309
logger.notifyChannel('extdata_from_oevals', netsvc.LOG_DEBUG, "Mapping Context: %r" % (space,))
310
logger.notifyChannel('extdata_from_oevals', netsvc.LOG_DEBUG, "Exception: %r" % (e,))
312
result = space.get('result', False)
313
#If result exists and is of type list
314
if result and type(result) == list:
315
for each_tuple in result:
316
if type(each_tuple) == tuple and len(each_tuple) == 2:
317
vals[each_tuple[0]] = each_tuple[1]
318
#Every mapping line has now been translated into vals dictionary, now set defaults if any
319
for each_default_entry in defaults.keys():
320
vals[each_default_entry] = defaults[each_default_entry]
325
def ext_export(self, cr, uid, ids, external_referential_ids=[], defaults={}, context=None):
328
#external_referential_ids has to be a list
329
logger = netsvc.Logger()
330
report_line_obj = self.pool.get('external.report.line')
331
write_ids = [] #Will record ids of records modified, not sure if will be used
332
create_ids = [] #Will record ids of newly created records, not sure if will be used
333
for record_data in self.read_w_order(cr, uid, ids, [], context):
334
#If no external_ref_ids are mentioned, then take all ext_ref_this item has
335
if not external_referential_ids:
336
ir_model_data_recids = self.pool.get('ir.model.data').search(cr, uid, [('model', '=', self._name), ('res_id', '=', id), ('module', 'ilike', 'extref')])
337
if ir_model_data_recids:
338
for each_model_rec in self.pool.get('ir.model.data').read(cr, uid, ir_model_data_recids, ['external_referential_id']):
339
if each_model_rec['external_referential_id']:
340
external_referential_ids.append(each_model_rec['external_referential_id'][0])
341
#if still there no external_referential_ids then export to all referentials
342
if not external_referential_ids:
343
external_referential_ids = self.pool.get('external.referential').search(cr, uid, [])
344
#Do an export for each external ID
345
for ext_ref_id in external_referential_ids:
346
#Find the mapping record now
347
mapping_id = self.pool.get('external.mapping').search(cr, uid, [('model', '=', self._name), ('referential_id', '=', ext_ref_id)])
207
349
#If a mapping exists for current model, search for mapping lines
208
mapping_line_ids = self.pool.get('external.mapping.line').search(cr, uid, [('mapping_id', '=', mapping_id), ('type', 'in', ['in_out', 'in'])])
209
mapping_lines = self.pool.get('external.mapping.line').read(cr, uid, mapping_line_ids, ['external_field', 'external_type', 'in_function'])
350
mapping_line_ids = self.pool.get('external.mapping.line').search(cr, uid, [('mapping_id', '=', mapping_id), ('type', 'in', ['in_out', 'out'])])
351
mapping_lines = self.pool.get('external.mapping.line').read(cr, uid, mapping_line_ids, ['external_field', 'out_function'])
210
352
if mapping_lines:
211
353
#if mapping lines exist find the data conversion for each row in inward data
212
for_key_field = self.pool.get('external.mapping').read(cr, uid, mapping_id[0], ['external_key_name'])['external_key_name']
213
for each_row in data:
214
vals = self.oevals_from_extdata(cr, uid, external_referential_id, each_row, for_key_field, mapping_lines, defaults, context)
215
#perform a record check, for that we need foreign field
216
external_id = vals.get(for_key_field, False) or each_row.get(for_key_field, False) or each_row.get('external_id', False)
217
#del vals[for_key_field] looks like it is affecting the import :(
218
#Check if record exists
219
existing_ir_model_data_id = self.pool.get('ir.model.data').search(cr, uid, [('model', '=', self._name), ('name', '=', self.prefixed_id(external_id)), ('external_referential_id', '=', external_referential_id)])
220
record_test_id = False
221
if existing_ir_model_data_id:
222
existing_rec_id = self.pool.get('ir.model.data').read(cr, uid, existing_ir_model_data_id, ['res_id'])[0]['res_id']
224
#Note: OpenERP cleans up ir_model_data which res_id records have been deleted only at server update because that would be a perf penalty,
225
#so we take care of it here:
226
record_test_id = self.search(cr, uid, [('id', '=', existing_rec_id)])
227
if not record_test_id:
228
self.pool.get('ir.model.data').unlink(cr, uid, existing_ir_model_data_id)
231
if vals.get(for_key_field, False):
232
del vals[for_key_field]
233
if self.oe_update(cr, uid, existing_rec_id, vals, each_row, external_referential_id, defaults, context):
234
write_ids.append(existing_rec_id)
235
self.pool.get('ir.model.data').write(cr, uid, existing_ir_model_data_id, {'res_id':existing_rec_id})
236
logger.notifyChannel('ext synchro', netsvc.LOG_INFO, "Updated in OpenERP %s from External Ref with external_id %s and OpenERP id %s successfully" %(self._name, external_id, existing_rec_id))
239
crid = self.oe_create(cr, uid, vals, each_row, external_referential_id, defaults, context)
240
create_ids.append(crid)
241
ir_model_data_vals = {
242
'name': self.prefixed_id(external_id),
245
'external_referential_id': external_referential_id,
246
'module': 'extref/' + self.pool.get('external.referential').read(cr, uid, external_referential_id, ['name'])['name']
248
self.pool.get('ir.model.data').create(cr, uid, ir_model_data_vals)
249
logger.notifyChannel('ext synchro', netsvc.LOG_INFO, "Created in OpenERP %s from External Ref with external_id %s and OpenERP id %s successfully" %(self._name, external_id, crid))
252
return {'create_ids': create_ids, 'write_ids': write_ids}
254
def oe_update(self, cr, uid, existing_rec_id, vals, data, external_referential_id, defaults, context):
255
return self.write(cr, uid, existing_rec_id, vals, context)
258
def oe_create(self, cr, uid, vals, data, external_referential_id, defaults, context):
259
return self.create(cr, uid, vals, context)
262
def extdata_from_oevals(self, cr, uid, external_referential_id, data_record, mapping_lines, defaults, context=None):
265
vals = {} #Dictionary for record
266
for each_mapping_line in mapping_lines:
267
#Build the space for expr
272
'external_referential_id':external_referential_id,
275
'record':data_record,
276
'conn':context.get('conn_obj', False),
279
#The expression should return value in list of tuple format
280
#eg[('name','Sharoon'),('age',20)] -> vals = {'name':'Sharoon', 'age':20}
281
if each_mapping_line['out_function']:
283
exec each_mapping_line['out_function'] in space
285
logger = netsvc.Logger()
286
logger.notifyChannel('extdata_from_oevals', netsvc.LOG_DEBUG, "Error in import mapping: %r" % (each_mapping_line['out_function'],))
287
del(space['__builtins__'])
288
logger.notifyChannel('extdata_from_oevals', netsvc.LOG_DEBUG, "Mapping Context: %r" % (space,))
289
logger.notifyChannel('extdata_from_oevals', netsvc.LOG_DEBUG, "Exception: %r" % (e,))
291
result = space.get('result', False)
292
#If result exists and is of type list
293
if result and type(result) == list:
294
for each_tuple in result:
295
if type(each_tuple) == tuple and len(each_tuple) == 2:
296
vals[each_tuple[0]] = each_tuple[1]
297
#Every mapping line has now been translated into vals dictionary, now set defaults if any
298
for each_default_entry in defaults.keys():
299
vals[each_default_entry] = defaults[each_default_entry]
304
def ext_export(self, cr, uid, ids, external_referential_ids=[], defaults={}, context=None):
307
#external_referential_ids has to be a list
308
logger = netsvc.Logger()
309
write_ids = [] #Will record ids of records modified, not sure if will be used
310
create_ids = [] #Will record ids of newly created records, not sure if will be used
311
for record_data in self.read_w_order(cr, uid, ids, [], context):
312
#If no external_ref_ids are mentioned, then take all ext_ref_this item has
313
if not external_referential_ids:
314
ir_model_data_recids = self.pool.get('ir.model.data').search(cr, uid, [('model', '=', self._name), ('res_id', '=', id), ('module', 'ilike', 'extref')])
315
if ir_model_data_recids:
316
for each_model_rec in self.pool.get('ir.model.data').read(cr, uid, ir_model_data_recids, ['external_referential_id']):
317
if each_model_rec['external_referential_id']:
318
external_referential_ids.append(each_model_rec['external_referential_id'][0])
319
#if still there no external_referential_ids then export to all referentials
320
if not external_referential_ids:
321
external_referential_ids = self.pool.get('external.referential').search(cr, uid, [])
322
#Do an export for each external ID
323
for ext_ref_id in external_referential_ids:
324
#Find the mapping record now
325
mapping_id = self.pool.get('external.mapping').search(cr, uid, [('model', '=', self._name), ('referential_id', '=', ext_ref_id)])
327
#If a mapping exists for current model, search for mapping lines
328
mapping_line_ids = self.pool.get('external.mapping.line').search(cr, uid, [('mapping_id', '=', mapping_id), ('type', 'in', ['in_out', 'out'])])
329
mapping_lines = self.pool.get('external.mapping.line').read(cr, uid, mapping_line_ids, ['external_field', 'out_function'])
331
#if mapping lines exist find the data conversion for each row in inward data
332
exp_data = self.extdata_from_oevals(cr, uid, ext_ref_id, record_data, mapping_lines, defaults, context)
333
#Check if export for this referential demands a create or update
334
rec_check_ids = self.pool.get('ir.model.data').search(cr, uid, [('model', '=', self._name), ('res_id', '=', record_data['id']), ('module', 'ilike', 'extref'), ('external_referential_id', '=', ext_ref_id)])
335
#rec_check_ids will indicate if the product already has a mapping record with ext system
336
mapping_id = self.pool.get('external.mapping').search(cr, uid, [('model', '=', self._name), ('referential_id', '=', ext_ref_id)])
337
if mapping_id and len(mapping_id) == 1:
338
mapping_rec = self.pool.get('external.mapping').read(cr, uid, mapping_id[0], ['external_update_method', 'external_create_method'])
339
conn = context.get('conn_obj', False)
340
if rec_check_ids and mapping_rec and len(rec_check_ids) == 1:
341
ext_id = self.oeid_to_extid(cr, uid, record_data['id'], ext_ref_id, context)
343
if not context.get('force', False):#TODO rename this context's key in 'no_date_check' or something like that
344
#Record exists, check if update is required, for that collect last update times from ir.data & record
345
last_exported_times = self.pool.get('ir.model.data').read(cr, uid, rec_check_ids[0], ['write_date', 'create_date'])
346
last_exported_time = last_exported_times.get('write_date', False) or last_exported_times.get('create_date', False)
347
this_record_times = self.read(cr, uid, record_data['id'], ['write_date', 'create_date'])
348
last_updated_time = this_record_times.get('write_date', False) or this_record_times.get('create_date', False)
350
if not last_updated_time: #strangely seems that on inherits structure, write_date/create_date are False for children
351
cr.execute("select write_date, create_date from %s where id=%s;" % (self._name.replace('.', '_'), record_data['id']))
353
last_updated_time = read[0] and read[0].split('.')[0] or read[1] and read[1].split('.')[0] or False
355
if last_updated_time and last_exported_time:
356
last_exported_time = datetime.datetime.fromtimestamp(time.mktime(time.strptime(last_exported_time, '%Y-%m-%d %H:%M:%S')))
357
last_updated_time = datetime.datetime.fromtimestamp(time.mktime(time.strptime(last_updated_time, '%Y-%m-%d %H:%M:%S')))
358
if last_exported_time + datetime.timedelta(seconds=1) > last_updated_time:
361
if conn and mapping_rec['external_update_method']:
354
exp_data = self.extdata_from_oevals(cr, uid, ext_ref_id, record_data, mapping_lines, defaults, context)
355
#Check if export for this referential demands a create or update
356
rec_check_ids = self.pool.get('ir.model.data').search(cr, uid, [('model', '=', self._name), ('res_id', '=', record_data['id']), ('module', 'ilike', 'extref'), ('external_referential_id', '=', ext_ref_id)])
357
#rec_check_ids will indicate if the product already has a mapping record with ext system
358
mapping_id = self.pool.get('external.mapping').search(cr, uid, [('model', '=', self._name), ('referential_id', '=', ext_ref_id)])
359
if mapping_id and len(mapping_id) == 1:
360
mapping_rec = self.pool.get('external.mapping').read(cr, uid, mapping_id[0], ['external_update_method', 'external_create_method'])
361
conn = context.get('conn_obj', False)
362
if rec_check_ids and mapping_rec and len(rec_check_ids) == 1:
363
ext_id = self.oeid_to_extid(cr, uid, record_data['id'], ext_ref_id, context)
365
if not context.get('force', False):#TODO rename this context's key in 'no_date_check' or something like that
366
#Record exists, check if update is required, for that collect last update times from ir.data & record
367
last_exported_times = self.pool.get('ir.model.data').read(cr, uid, rec_check_ids[0], ['write_date', 'create_date'])
368
last_exported_time = last_exported_times.get('write_date', False) or last_exported_times.get('create_date', False)
369
this_record_times = self.read(cr, uid, record_data['id'], ['write_date', 'create_date'])
370
last_updated_time = this_record_times.get('write_date', False) or this_record_times.get('create_date', False)
372
if not last_updated_time: #strangely seems that on inherits structure, write_date/create_date are False for children
373
cr.execute("select write_date, create_date from %s where id=%s;" % (self._name.replace('.', '_'), record_data['id']))
375
last_updated_time = read[0] and read[0].split('.')[0] or read[1] and read[1].split('.')[0] or False
377
if last_updated_time and last_exported_time:
378
last_exported_time = datetime.datetime.fromtimestamp(time.mktime(time.strptime(last_exported_time, '%Y-%m-%d %H:%M:%S')))
379
last_updated_time = datetime.datetime.fromtimestamp(time.mktime(time.strptime(last_updated_time, '%Y-%m-%d %H:%M:%S')))
380
if last_exported_time + datetime.timedelta(seconds=1) > last_updated_time:
383
if conn and mapping_rec['external_update_method']:
362
385
self.ext_update(cr, uid, exp_data, conn, mapping_rec['external_update_method'], record_data['id'], ext_id, rec_check_ids[0], mapping_rec['external_create_method'], context)
363
386
write_ids.append(record_data['id'])
364
387
#Just simply write to ir.model.data to update the updated time