From 023ce68e841d91ae3610bf50774f61b2be7de090 Mon Sep 17 00:00:00 2001 From: "Amit Parmar (OpenERP)" Date: Mon, 6 Jun 2011 11:22:57 +0530 Subject: [PATCH 1/8] [EDI]: worked on the local time to UTC time conversion bzr revid: aar@tinyerp.com-20110606055257-d33gwzaidwxufn64 --- openerp/addons/base/ir/ir_edi.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/openerp/addons/base/ir/ir_edi.py b/openerp/addons/base/ir/ir_edi.py index 4ed7b0a4d3a..2cb40c4dfa7 100644 --- a/openerp/addons/base/ir/ir_edi.py +++ b/openerp/addons/base/ir/ir_edi.py @@ -26,6 +26,7 @@ import time import base64 import urllib2 import release +import datetime def safe_unique_id(model, database_id): """Generate a unique string to represent a (model,database id) pair @@ -216,14 +217,21 @@ class edi(object): 'content': base64.encodestring(attachment.datas), 'file_name': attachment.datas_fname, }) + ''' Here we are obtaining the release version ''' version = [] for ver in release.version.split('.'): version.append(int(ver)) + ''' Here we are converting local time into UTC time''' + UTC_OFFSET_TIMEDELTA = datetime.datetime.utcnow() - datetime.datetime.now() + local_datetime = datetime.datetime.strptime(record.write_date, "%Y-%m-%d %H:%M:%S") + result_utc_datetime = local_datetime - UTC_OFFSET_TIMEDELTA + write_date = result_utc_datetime.strftime("%Y-%m-%d %H:%M:%S") + edi_dict = { '__model' : record._name, '__module' : record._module, '__id': record.id, - '__last_update': record.write_date, #TODO: convert into UTC + '__last_update': write_date, #TODO: convert into UTC '__version': version, '__attachments': attachment_dict_list } From ab62f7b7802571f56a56fce7389b777d6fee2583 Mon Sep 17 00:00:00 2001 From: "Amit Parmar (OpenERP)" Date: Tue, 21 Jun 2011 18:46:32 +0530 Subject: [PATCH 2/8] [EDI] revised edi class bzr revid: aar@tinyerp.com-20110621131632-rdwn6in74q5t1wkj --- openerp/addons/base/__openerp__.py | 3 +- openerp/addons/base/ir/ir_edi.py | 316 +++++++++++++++++------------ 2 files changed, 191 insertions(+), 128 deletions(-) diff --git a/openerp/addons/base/__openerp__.py b/openerp/addons/base/__openerp__.py index 75e0a8c56d0..b0c437352f9 100644 --- a/openerp/addons/base/__openerp__.py +++ b/openerp/addons/base/__openerp__.py @@ -71,7 +71,7 @@ 'res/partner/wizard/partner_clear_ids_view.xml', 'res/partner/wizard/partner_wizard_ean_check_view.xml', 'res/partner/partner_data.xml', - + #'test/test_edi_document.yml', 'res/ir_property_view.xml', 'security/base_security.xml', 'publisher_warranty/publisher_warranty_view.xml', @@ -96,6 +96,7 @@ 'test/test_ir_rule.yml', # <-- These tests modify/add/delete ir_rules. 'test/test_config_users.yml', 'test/test_ir_values.yml', + ], 'installable': True, 'active': True, diff --git a/openerp/addons/base/ir/ir_edi.py b/openerp/addons/base/ir/ir_edi.py index 2cb40c4dfa7..fe8320491bf 100644 --- a/openerp/addons/base/ir/ir_edi.py +++ b/openerp/addons/base/ir/ir_edi.py @@ -20,14 +20,13 @@ ############################################################################## from osv import osv,fields -import json +import simplejson import hashlib import time import base64 import urllib2 -import release -import datetime - +import unicodedata +import openerp.release as release def safe_unique_id(model, database_id): """Generate a unique string to represent a (model,database id) pair without being too long, without revealing the database id, and @@ -58,7 +57,7 @@ def safe_unique_id(model, database_id): class ir_edi_document(osv.osv): _name = 'ir.edi.document' - _description = 'To represent the EDI export of any OpenERP record, it could be an invoice, a project task, etc.' + _description = 'To represent' _columns = { 'name': fields.char("EDI token", size = 128, help="EDI Token is a unique identifier for the EDI document."), 'document': fields.text("Document", help="hold the serialization of the EDI document.") @@ -83,7 +82,7 @@ class ir_edi_document(osv.osv): perform a JSON serialization of a list of dicts prepared by generate_edi() and return a UTF-8 encoded string that could be passed to deserialize() :param edi_dicts: it's list of edi_dict """ - serialized_list = json.dumps(edi_dicts) + serialized_list = simplejson.dumps(edi_documents) return serialized_list def generate_edi(self, cr, uid, records, context=None): @@ -95,7 +94,7 @@ class ir_edi_document(osv.osv): edi_list = [] for record in records: record_model_obj = self.pool.get(record._name) - edi_list += record_model_obj.edi_export(cr, uid, [record], context=context) + edi_list += record_model_obj.edi_export(cr, uid, [record],context=context) return self.serialize(edi_list) def get_document(self, cr, uid, edi_token, context=None): @@ -104,14 +103,12 @@ class ir_edi_document(osv.osv): returns the string serialization that is in the database (column: document) for the given edi_token or raise. """ - records = self.name_search(cr, uid, edi_token, context=context) + records = self.search(cr, uid, [('name','=',edi_token)]) if records: - edi = self.browse(cr, uid, records[0], context=context) - return edi.document - else: - raise osv.except_osv(_('Error !'), - _('Desired EDI Document does not Exist')) - + for edi in self.browse(cr, uid, records, context=context): + return edi.document + else: + pass def load_edi(self, cr, uid, edi_documents, context=None): @@ -135,10 +132,11 @@ class ir_edi_document(osv.osv): """ Deserialized the edi document string perform JSON deserialization from an edi document string, and returns a list of dicts """ - edi_document = json.loads(edi_document_string) + edi_document = simplejson.loads(edi_document_string) + return edi_document - def export(self, cr, uid, records, context=None): + def export_edi(self, cr, uid, records, context=None): """ The method handles the flow of the edi document generation and store it in the database and return the edi_token of the particular document @@ -161,7 +159,7 @@ class ir_edi_document(osv.osv): exported_ids.append(token) return exported_ids - def import(self, cr, uid, edi_document=None, edi_url=None, context=None): + def import_edi(self, cr, uid, edi_document=None, edi_url=None, context=None): """ The method handles the flow of importing particular edi document and updates the database values on the basis of the edi document using @@ -175,8 +173,10 @@ class ir_edi_document(osv.osv): if edi_url and not edi_document: edi_document = urllib2.urlopen(edi_url).read() - assert edi_document, _('EDI Document should be provided') - edi_documents = self.deserialize(edi_document) + #assert edi_document, _('EDI Document should be provided') + else: + + edi_documents = self.deserialize(edi_document) return self.load_edi(cr, uid, edi_documents, context=context) ir_edi_document() @@ -206,8 +206,11 @@ class edi(object): - __attachments': a list (possibly empty) of dicts describing the files attached to this record. """ # generic implementation! + model_data = self.pool.get('ir.model.data') + data_ids = [] attachment_object = self.pool.get('ir.attachment') edi_dict_list = [] + db_uuid = '' for record in records: attachment_ids = attachment_object.search(cr, uid, [('res_model','=', record._name), ('res_id', '=', record.id)]) attachment_dict_list = [] @@ -217,22 +220,24 @@ class edi(object): 'content': base64.encodestring(attachment.datas), 'file_name': attachment.datas_fname, }) - ''' Here we are obtaining the release version ''' version = [] - for ver in release.version.split('.'): - version.append(int(ver)) - ''' Here we are converting local time into UTC time''' - UTC_OFFSET_TIMEDELTA = datetime.datetime.utcnow() - datetime.datetime.now() - local_datetime = datetime.datetime.strptime(record.write_date, "%Y-%m-%d %H:%M:%S") - result_utc_datetime = local_datetime - UTC_OFFSET_TIMEDELTA - write_date = result_utc_datetime.strftime("%Y-%m-%d %H:%M:%S") + + for ver in release.major_version.split('.'): + version.append(ver) + data_ids = model_data.search(cr, uid, [('res_id','=',record.id)]) + + if len(data_ids): + xml_obj = model_data.browse(cr,uid,data_ids[0]) + uuid = safe_unique_id(record._name,record.id) + db_uuid = '%s:%s' % (uuid,xml_obj.name) + edi_dict = { '__model' : record._name, '__module' : record._module, - '__id': record.id, - '__last_update': write_date, #TODO: convert into UTC - '__version': version, + '__id': db_uuid, + '__last_update': False, #record.write_date, #TODO: convert into UTC + '__version': version, # ? '__attachments': attachment_dict_list } edi_dict_list.append(edi_dict) @@ -249,10 +254,15 @@ class edi(object): data_object = self.pool.get('ir.model.data') db_uuid = safe_unique_id(record._name, record.id) xml_ids = data_object.search(cr, uid, [('model','=',record._name),('res_id','=',record.id)]) + if xml_ids: xml_id = data_object.browse(cr, uid, xml_ids[0], context=context) xml_id = xml_id.name - db_uuid = '%s:%s' %(db_uuid, xml_id) + else: + xml_id = record._name + db_uuid = '%s:%s' %(db_uuid, xml_id) + + name = record.name return [db_uuid, name] @@ -271,9 +281,12 @@ class edi(object): """ # generic implementation! dict_list = [] + for record in records: + model_obj = self.pool.get(record._name) - dict_list += model_obj.edi_export(cr, uid, [record.id], context=context) + dict_list += model_obj.edi_export(cr, uid, [record], context=context) + return dict_list @@ -291,14 +304,15 @@ class edi(object): """ # generic implementation! dict_list = [] + for record in records: - dict_list.append(self.edi_o2m(cr, uid, record, context=None)) - + dict_list.append(self.edi_o2m(cr, uid, [record], context=None)) + return dict_list - def edi_export(self, cr, uid, ids, edi_struct=None, context=None): + def edi_export(self, cr, uid, records, edi_struct=None, context=None): """Returns a list of dicts representing an edi.document containing the browse_records with ``ids``, using the generic algorithm. :param edi_struct: if provided, edi_struct should be a dictionary @@ -318,32 +332,39 @@ class edi(object): be included in the exported data. """ # generic implementation! + if context is None: context = {} _fields = self.fields_get(cr, uid, context=context) - fields_to_export = edi_struct and edi_struct.keys() or _fields.key() - + fields_to_export = edi_struct and edi_struct.keys() or _fields.keys() edi_dict_list = [] - for row in self.browse(cr, uid, ids, fields_to_export, context): + value = None + for row in records: edi_dict = {} - edi_dict.update(self.edi_metadata(cr, uid, [row.id], context=context)[0]) + edi_dict.update(self.edi_metadata(cr, uid, [row], context=context)[0]) + for field in fields_to_export: - cols = self._fields[field] - if cols['type'] == 'many2one': - m2o_record = row.getattrs(field) - value = self.m2o(cr, uid, m2o_record, context=context) - elif cols['type'] == 'many2many': - m2m_records = row.getattrs(field) - value = self.m2m(cr, uid, m2m_records, context=context) - elif cols['type'] == 'one2many': - o2m_records = row.getattrs(field) - value = self.o2m(cr, uid, o2m_records, context=context) + cols = _fields[field] + if _fields[field].has_key('function') or _fields[field].has_key('related_columns'): + + pass else: - value = row.getattrs(field) + if cols['type'] == 'many2one': + m2o_record = getattr(row, field) + value = self.edi_m2o(cr, uid, m2o_record, context=context) + elif cols['type'] == 'many2many': + m2m_records = getattr(row, field) + value = self.edi_m2m(cr, uid, m2m_records, context=context) + elif cols['type'] == 'one2many': + o2m_records = getattr(row, field) + value = self.edi_o2m(cr, uid, o2m_records, context=context ) + else: + value = getattr(row, field) edi_dict[field] = value edi_dict_list.append(edi_dict) + return edi_dict_list @@ -395,6 +416,19 @@ class edi(object): connect it to the parent record via a write value like (4, db_id). """ # generic implementation! + + def convert(data): + if isinstance(data, unicode): + return str(data) + elif isinstance(data, dict): + return dict(map(convert, data.iteritems())) + elif isinstance(data, (list, tuple, set, frozenset)): + return type(data)(map(convert, data)) + else: + return data + #edi_document = convert(edi_document) + + fields = edi_document.keys() fields_to_import = [] data_line = [] @@ -403,87 +437,115 @@ class edi(object): current_module = 'edi_import' values = {} for field in edi_document.keys(): - if not field.startwith('__'): - field_to_import.append(field) + if field.startswith('__') and field == '__id': + db_uuid, xml_ids = tuple(edi_document[field].split(':')) + + elif not field.startswith('__'): + + + fields_to_import.append(field) edi_field_value = edi_document[field] - if _fields[field]['type'] in ('many2one', 'many2many'): - - if _fields[field]['type'] == 'many2one': - edi_parent_documents = [edi_field_value] - else: - edi_parent_documents = edi_field_value - - parent_lines = [] - - for edi_parent_document in edi_parent_documents: - #Look in ir.model.data for a record that matches the db_id. - #If found, replace the m2o value with the correct database ID and stop. - #If not found, continue to next step - - db_uuid, xml_id = tuple(edi_parent_document[0].split(':')) - data_ids = model_data.name_search(cr, uid, xml_id) - if data_ids: - d = model_data.browse(cr, uid, data_ids[0], context=context) - parent_lines.append(d.res_id) - - else: - #Perform name_search(name) to look for a record that matches the - #given m2o name. If only one record is found, create the missing - #ir.model.data record to link it to the db_id, and the replace the m2o - #value with the correct database ID, then stop. If zero result or - #multiple results are found, go to next step. - #Create the new record using the only field value that is known: the - #name, and create the ir.model.data entry to map to it. - - relation_object = self.get.pool(_fields[field]['relation']) - relation_ids = relation_object.name_search(cr, uid, edi_parent_document[1]) - if relation_ids and len(relation_ids) == 1: - relation_id = relation_ids[0] - else: - relation_id = relation_object.create(cr, uid, {'name': edi_parent_document[1]}, context=context) - model_data.create(cr, uid, { - 'name': xml_id, - 'model': relation_object._name, - #'module':relation_object._module, - 'res_id':relation_id, - },context=context) - - parent_lines.append(relation_id) - - if _fields[field]['type'] == 'many2one': - values[field] = parent_lines[0] - else: - many2many_ids = [] - for m2m_id in parent_lines: - many2many_ids.append((4,m2m_id)) - values[field] = many2many_ids - + if _fields[field].has_key('function') or _fields[field].has_key('related_columns'): - elif _fields[field]['type'] == 'one2many': - #Look for a record that matches the db_id provided in the __id field. If - #found, keep the corresponding database id, and connect it to the parent - #using a write value like (4,db_id). - #If not found via db_id, create a new entry using the same method that - #imports a full EDI record (recursive call!), grab the resulting db id, - #and use it to connect to the parent via a write value like (4, db_id). - - relations = [] - relation_object = self.get.pool(_fields[field]['relation']) - for edi_relation_document in edi_field_value: - db_uuid, xml_id = tuple(edi_relation_document.get('__id').split(':')) - data_ids = model_data.name_search(cr, uid, xml_id) - if data_ids: - d = model_data.browse(cr, uid, data_ids[0], context=context) - relations.append(d.res_id) + pass + else: + if _fields[field]['type'] in ('many2one', 'many2many'): + + if _fields[field]['type'] == 'many2one': + edi_parent_documents = [edi_field_value] + else: + edi_parent_documents = edi_field_value + + parent_lines = [] + + for edi_parent_document in edi_parent_documents: + #Look in ir.model.data for a record that matches the db_id. + #If found, replace the m2o value with the correct database ID and stop. + #If not found, continue to next step + if edi_parent_document[0].find(':') != -1 and edi_parent_document[1] != None: + db_uuid, xml_id = tuple(edi_parent_document[0].split(':')) + data_ids = model_data.name_search(cr, uid, xml_id) + if data_ids: + for data in model_data.browse(cr, uid, [data_ids[0][0]], context=context): + parent_lines.append(data.res_id) + print "..............................................",data.res_id + else: + #Perform name_search(name) to look for a record that matches the + #given m2o name. If only one record is found, create the missing + #ir.model.data record to link it to the db_id, and the replace the m2o + #value with the correct database ID, then stop. If zero result or + #multiple results are found, go to next step. + #Create the new record using the only field value that is known: the + #name, and create the ir.model.data entry to map to it. + + relation_object = self.pool.get(_fields[field]['relation']) + print "parent_document",edi_parent_document[1] + relation_ids = relation_object.search(cr, uid, [('name','=',edi_parent_document[1])]) + if relation_ids and len(relation_ids) == 1: + relation_id = relation_ids[0] + else: + relation_id = relation_object.create(cr, uid, {'name': edi_parent_document[1]}, context=context) + model_data.create(cr, uid, { + 'name': xml_id, + 'model': relation_object._name, + 'module':relation_object._module, + 'res_id':relation_id + }, context=context) + + parent_lines.append(relation_id) + + else: + pass + if len(parent_lines): + if _fields[field]['type'] == 'many2one': + values[field] = parent_lines[0] + + else: + many2many_ids = [] + for m2m_id in parent_lines: + many2many_ids.append((4,m2m_id)) + values[field] = many2many_ids + + + elif _fields[field]['type'] == 'one2many': + #Look for a record that matches the db_id provided in the __id field. If + #found, keep the corresponding database id, and connect it to the parent + #using a write value like (4,db_id). + #If not found via db_id, create a new entry using the same method that + #imports a full EDI record (recursive call!), grab the resulting db id, + #and use it to connect to the parent via a write value like (4, db_id). + + relations = [] + relation_object = self.pool.get(_fields[field]['relation']) + for edi_relation_document in edi_field_value: + '''print "pppppppppppppppppppppppppppppppppppppppppp" + print edi_field_value + print ":::::::::::::::::::::::::::::::::::::::::::::" + print edi_relation_document + print edi_parent_document + print "ppppppppppppppppppppppppppppppppppp" + if edi_relation_document['__id'].find(':') != -1: + db_uuid, xml_id = tuple(edi_relation_document['__id'].split(':')) + print xml_id + data_ids = model_data.name_search(cr, uid, xml_id) + print "dddddddddddddddddddddddddddddddddddddddddddddd",data_ids + if data_ids: + for data in model_data.browse(cr,uid,[data_ids[0][0]]): + relations.append(data.res_id) + else:''' r = relation_object.edi_import(cr, uid, edi_relation_document, context=context) relations.append(r) - one2many_ids = [] - for o2m_id in relations: - one2many_ids.append((4,o2m_id)) - values[field] = one2many_ids - else: - values[field] = edi_field_value + print "relation id ssssssssssssssssssss",relations + one2many_ids = [] + for o2m_id in relations: + one2many_ids.append((4,o2m_id)) + values[field] = one2many_ids + else: + values[field] = edi_field_value + for val in values.keys(): + print '::::::::::::::::::::::',val,'::::::::::;;;;;;;;;;;;;;;;;;;;;;' + print values[val] return model_data._update(cr, uid, self._name, current_module, values, context=context) - +# vim: ts=4 sts=4 sw=4 si et \ No newline at end of file From e60caf7d51b5f86f3597d610708a42ba3eeadbc6 Mon Sep 17 00:00:00 2001 From: "Amit Parmar (OpenERP)" Date: Tue, 21 Jun 2011 18:49:27 +0530 Subject: [PATCH 3/8] [EDI] revised edi class bzr revid: aar@tinyerp.com-20110621131927-872hkmor321f1gdf --- openerp/addons/base/__openerp__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/__openerp__.py b/openerp/addons/base/__openerp__.py index b0c437352f9..bccaf7f660b 100644 --- a/openerp/addons/base/__openerp__.py +++ b/openerp/addons/base/__openerp__.py @@ -71,7 +71,7 @@ 'res/partner/wizard/partner_clear_ids_view.xml', 'res/partner/wizard/partner_wizard_ean_check_view.xml', 'res/partner/partner_data.xml', - #'test/test_edi_document.yml', + 'test/test_edi_document.yml', 'res/ir_property_view.xml', 'security/base_security.xml', 'publisher_warranty/publisher_warranty_view.xml', From 395b953f47d1098732aab9999535a8e6bca88329 Mon Sep 17 00:00:00 2001 From: "Amit Parmar (OpenERP)" Date: Tue, 21 Jun 2011 18:51:33 +0530 Subject: [PATCH 4/8] [EDI] revised edi class bzr revid: aar@tinyerp.com-20110621132133-g24z7zi1ln16h06d --- openerp/addons/base/test/test_edi_documents.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 openerp/addons/base/test/test_edi_documents.yml diff --git a/openerp/addons/base/test/test_edi_documents.yml b/openerp/addons/base/test/test_edi_documents.yml new file mode 100644 index 00000000000..1b66caaf4dc --- /dev/null +++ b/openerp/addons/base/test/test_edi_documents.yml @@ -0,0 +1,16 @@ +- + Tesing of Export functionality +- + !python {model: ir.edi.document}: | + partner_obj = self.pool.get('res.partner') + partner_ids = partner_obj.search(cr, uid, []) + + if partner_ids: + partners = partner_obj.browse(cr, uid, partner_ids) + tokens = self.export_edi(cr, uid, partners) + print '>>>>>>>>>>',tokens + for token in tokens: + document = self.get_document(cr, uid, token, context=context) + a = self.import_edi(cr, uid, edi_document = document) + print '////////////',a + From 6d4b05e3d4840629fe04bffb75ef078174dfa65b Mon Sep 17 00:00:00 2001 From: "Amit Parmar (OpenERP)" Date: Wed, 22 Jun 2011 14:41:23 +0530 Subject: [PATCH 5/8] [EDI] refactored code of edi class bzr revid: aar@tinyerp.com-20110622091123-6zal2su3vy8nv1nm --- openerp/addons/base/__openerp__.py | 2 +- openerp/addons/base/ir/ir_edi.py | 79 +++---------------- .../addons/base/test/test_edi_documents.yml | 4 +- 3 files changed, 15 insertions(+), 70 deletions(-) diff --git a/openerp/addons/base/__openerp__.py b/openerp/addons/base/__openerp__.py index bccaf7f660b..6406ec7b716 100644 --- a/openerp/addons/base/__openerp__.py +++ b/openerp/addons/base/__openerp__.py @@ -71,7 +71,6 @@ 'res/partner/wizard/partner_clear_ids_view.xml', 'res/partner/wizard/partner_wizard_ean_check_view.xml', 'res/partner/partner_data.xml', - 'test/test_edi_document.yml', 'res/ir_property_view.xml', 'security/base_security.xml', 'publisher_warranty/publisher_warranty_view.xml', @@ -96,6 +95,7 @@ 'test/test_ir_rule.yml', # <-- These tests modify/add/delete ir_rules. 'test/test_config_users.yml', 'test/test_ir_values.yml', + 'test/test_edi_documents.yml', ], 'installable': True, diff --git a/openerp/addons/base/ir/ir_edi.py b/openerp/addons/base/ir/ir_edi.py index fe8320491bf..fa41da161cc 100644 --- a/openerp/addons/base/ir/ir_edi.py +++ b/openerp/addons/base/ir/ir_edi.py @@ -20,12 +20,11 @@ ############################################################################## from osv import osv,fields -import simplejson import hashlib +import json import time import base64 import urllib2 -import unicodedata import openerp.release as release def safe_unique_id(model, database_id): """Generate a unique string to represent a (model,database id) pair @@ -82,7 +81,7 @@ class ir_edi_document(osv.osv): perform a JSON serialization of a list of dicts prepared by generate_edi() and return a UTF-8 encoded string that could be passed to deserialize() :param edi_dicts: it's list of edi_dict """ - serialized_list = simplejson.dumps(edi_documents) + serialized_list = json.dumps(edi_documents) return serialized_list def generate_edi(self, cr, uid, records, context=None): @@ -94,7 +93,7 @@ class ir_edi_document(osv.osv): edi_list = [] for record in records: record_model_obj = self.pool.get(record._name) - edi_list += record_model_obj.edi_export(cr, uid, [record],context=context) + edi_list += record_model_obj.edi_export(cr, uid, [record], context=context) return self.serialize(edi_list) def get_document(self, cr, uid, edi_token, context=None): @@ -103,13 +102,12 @@ class ir_edi_document(osv.osv): returns the string serialization that is in the database (column: document) for the given edi_token or raise. """ - records = self.search(cr, uid, [('name','=',edi_token)]) + records = self.name_search(cr, uid, edi_token) if records: - for edi in self.browse(cr, uid, records, context=context): - return edi.document + edi = self.browse(cr, uid, records, context=context) + return edi.document else: pass - def load_edi(self, cr, uid, edi_documents, context=None): """ @@ -132,7 +130,7 @@ class ir_edi_document(osv.osv): """ Deserialized the edi document string perform JSON deserialization from an edi document string, and returns a list of dicts """ - edi_document = simplejson.loads(edi_document_string) + edi_document = json.loads(edi_document_string) return edi_document @@ -173,15 +171,13 @@ class ir_edi_document(osv.osv): if edi_url and not edi_document: edi_document = urllib2.urlopen(edi_url).read() - #assert edi_document, _('EDI Document should be provided') + assert edi_document, _('EDI Document should be provided') else: - edi_documents = self.deserialize(edi_document) return self.load_edi(cr, uid, edi_documents, context=context) ir_edi_document() - class edi(object): _name = 'edi' _description = 'edi document handler' @@ -191,7 +187,6 @@ class edi(object): ``edi_import()`` and ``edi_export()`` methods to implement their specific behavior, based on the primitives provided by this superclass.""" - def edi_metadata(self, cr, uid, records, context=None): """Return a list representing the boilerplate EDI structure for exporting the record in the given browse_rec_list, including @@ -221,11 +216,10 @@ class edi(object): 'file_name': attachment.datas_fname, }) version = [] - for ver in release.major_version.split('.'): version.append(ver) - data_ids = model_data.search(cr, uid, [('res_id','=',record.id)]) + data_ids = model_data.search(cr, uid, [('res_id','=',record.id),('model','=',record._name)]) if len(data_ids): xml_obj = model_data.browse(cr,uid,data_ids[0]) @@ -261,12 +255,9 @@ class edi(object): else: xml_id = record._name db_uuid = '%s:%s' %(db_uuid, xml_id) - - name = record.name return [db_uuid, name] - def edi_o2m(self, cr, uid, records, context=None): """Return a list representing a O2M EDI value for the browse_records from the given browse_record_list. @@ -289,7 +280,6 @@ class edi(object): return dict_list - def edi_m2m(self, cr, uid, records, context=None): """Return a list representing a M2M EDI value for the browse_records from the given browse_record_list. @@ -310,8 +300,6 @@ class edi(object): return dict_list - - def edi_export(self, cr, uid, records, edi_struct=None, context=None): """Returns a list of dicts representing an edi.document containing the browse_records with ``ids``, using the generic algorithm. @@ -336,19 +324,15 @@ class edi(object): if context is None: context = {} _fields = self.fields_get(cr, uid, context=context) - - fields_to_export = edi_struct and edi_struct.keys() or _fields.keys() edi_dict_list = [] value = None for row in records: edi_dict = {} edi_dict.update(self.edi_metadata(cr, uid, [row], context=context)[0]) - for field in fields_to_export: cols = _fields[field] if _fields[field].has_key('function') or _fields[field].has_key('related_columns'): - pass else: if cols['type'] == 'many2one': @@ -364,10 +348,8 @@ class edi(object): value = getattr(row, field) edi_dict[field] = value edi_dict_list.append(edi_dict) - return edi_dict_list - def edi_import(self, cr, uid, edi_document, context=None): """Imports a list of dicts representing an edi.document, using the @@ -417,18 +399,6 @@ class edi(object): """ # generic implementation! - def convert(data): - if isinstance(data, unicode): - return str(data) - elif isinstance(data, dict): - return dict(map(convert, data.iteritems())) - elif isinstance(data, (list, tuple, set, frozenset)): - return type(data)(map(convert, data)) - else: - return data - #edi_document = convert(edi_document) - - fields = edi_document.keys() fields_to_import = [] data_line = [] @@ -437,23 +407,15 @@ class edi(object): current_module = 'edi_import' values = {} for field in edi_document.keys(): - if field.startswith('__') and field == '__id': - db_uuid, xml_ids = tuple(edi_document[field].split(':')) - - elif not field.startswith('__'): - - + if not field.startswith('__'): fields_to_import.append(field) edi_field_value = edi_document[field] if _fields[field].has_key('function') or _fields[field].has_key('related_columns'): - pass else: if _fields[field]['type'] in ('many2one', 'many2many'): - if _fields[field]['type'] == 'many2one': edi_parent_documents = [edi_field_value] - else: edi_parent_documents = edi_field_value @@ -469,7 +431,6 @@ class edi(object): if data_ids: for data in model_data.browse(cr, uid, [data_ids[0][0]], context=context): parent_lines.append(data.res_id) - print "..............................................",data.res_id else: #Perform name_search(name) to look for a record that matches the #given m2o name. If only one record is found, create the missing @@ -506,8 +467,6 @@ class edi(object): for m2m_id in parent_lines: many2many_ids.append((4,m2m_id)) values[field] = many2many_ids - - elif _fields[field]['type'] == 'one2many': #Look for a record that matches the db_id provided in the __id field. If #found, keep the corresponding database id, and connect it to the parent @@ -519,24 +478,15 @@ class edi(object): relations = [] relation_object = self.pool.get(_fields[field]['relation']) for edi_relation_document in edi_field_value: - '''print "pppppppppppppppppppppppppppppppppppppppppp" - print edi_field_value - print ":::::::::::::::::::::::::::::::::::::::::::::" - print edi_relation_document - print edi_parent_document - print "ppppppppppppppppppppppppppppppppppp" if edi_relation_document['__id'].find(':') != -1: db_uuid, xml_id = tuple(edi_relation_document['__id'].split(':')) - print xml_id data_ids = model_data.name_search(cr, uid, xml_id) - print "dddddddddddddddddddddddddddddddddddddddddddddd",data_ids if data_ids: for data in model_data.browse(cr,uid,[data_ids[0][0]]): relations.append(data.res_id) - else:''' - r = relation_object.edi_import(cr, uid, edi_relation_document, context=context) - relations.append(r) - print "relation id ssssssssssssssssssss",relations + else: + r = relation_object.edi_import(cr, uid, edi_relation_document, context=context) + relations.append(r) one2many_ids = [] for o2m_id in relations: one2many_ids.append((4,o2m_id)) @@ -544,8 +494,5 @@ class edi(object): else: values[field] = edi_field_value - for val in values.keys(): - print '::::::::::::::::::::::',val,'::::::::::;;;;;;;;;;;;;;;;;;;;;;' - print values[val] return model_data._update(cr, uid, self._name, current_module, values, context=context) # vim: ts=4 sts=4 sw=4 si et \ No newline at end of file diff --git a/openerp/addons/base/test/test_edi_documents.yml b/openerp/addons/base/test/test_edi_documents.yml index 1b66caaf4dc..06656800d4f 100644 --- a/openerp/addons/base/test/test_edi_documents.yml +++ b/openerp/addons/base/test/test_edi_documents.yml @@ -4,13 +4,11 @@ !python {model: ir.edi.document}: | partner_obj = self.pool.get('res.partner') partner_ids = partner_obj.search(cr, uid, []) - if partner_ids: partners = partner_obj.browse(cr, uid, partner_ids) tokens = self.export_edi(cr, uid, partners) - print '>>>>>>>>>>',tokens for token in tokens: document = self.get_document(cr, uid, token, context=context) a = self.import_edi(cr, uid, edi_document = document) - print '////////////',a + From 5ac271fa1fa85fc24a34c76ca5258d45a422955f Mon Sep 17 00:00:00 2001 From: "Harry (OpenERP)" Date: Mon, 27 Jun 2011 13:59:45 +0530 Subject: [PATCH 6/8] [IMP] edi: improve metadata function to create xml record if does not found bzr revid: hmo@tinyerp.com-20110627082945-xtoibwmlsl8187yg --- openerp/addons/base/ir/ir_edi.py | 50 ++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/openerp/addons/base/ir/ir_edi.py b/openerp/addons/base/ir/ir_edi.py index ad9fd2a2adf..8db5b397116 100644 --- a/openerp/addons/base/ir/ir_edi.py +++ b/openerp/addons/base/ir/ir_edi.py @@ -26,6 +26,9 @@ import time import base64 import urllib2 import openerp.release as release + +edi_module = 'edi_import' + def safe_unique_id(model, database_id): """Generate a unique string to represent a (model,database id) pair without being too long, without revealing the database id, and @@ -201,8 +204,9 @@ class edi(object): - __version': a list of components for the version - __attachments': a list (possibly empty) of dicts describing the files attached to this record. """ - # generic implementation! - model_data = self.pool.get('ir.model.data') + if context is None: + context = {} + model_data_pool = self.pool.get('ir.model.data') data_ids = [] attachment_object = self.pool.get('ir.attachment') edi_dict_list = [] @@ -214,6 +218,7 @@ class edi(object): except: pass version.append(ver) + for record in records: attachment_ids = attachment_object.search(cr, uid, [('res_model','=', record._name), ('res_id', '=', record.id)]) attachment_dict_list = [] @@ -225,21 +230,32 @@ class edi(object): }) - data_ids = model_data.search(cr, uid, [('res_id','=',record.id),('model','=',record._name)]) - + data_ids = model_data_pool.search(cr, uid, [('res_id','=',record.id),('model','=',record._name)]) + uuid = safe_unique_id(record._name, record.id) + if len(data_ids): - xml_record = model_data.browse(cr, uid, data_ids[0]) - uuid = safe_unique_id(record._name, record.id) - db_uuid = '%s:%s.%s' % (uuid, xml_record.module, xml_record.name) - + xml_record_id = data_ids[0] + else: + xml_record_id = model_data_pool.create(cr, uid, { + 'name': uuid, + 'model': record._name, + 'module': edi_module, + 'res_id': record.id}, context=context) + + xml_record = model_data_pool.browse(cr, uid, xml_record_id, context=context) + db_uuid = '%s:%s.%s' % (uuid, xml_record.module, xml_record.name) + edi_dict = { - '__model' : record._name, - '__module' : record._module, '__id': db_uuid, '__last_update': False, #record.write_date, #TODO: convert into UTC - '__version': version, - '__attachments': attachment_dict_list } + if not context.get('o2m_export'): + edi_dict.update({ + '__model' : record._name, + '__module' : record._module, + '__version': version, + '__attachments': attachment_dict_list + }) edi_dict_list.append(edi_dict) return edi_dict_list @@ -278,11 +294,14 @@ class edi(object): """ # generic implementation! dict_list = [] - + if context is None: + context = {} + ctx = context.copy() + ctx.update({'o2m_export':True}) for record in records: model_obj = self.pool.get(record._name) - dict_list += model_obj.edi_export(cr, uid, [record], context=context) + dict_list += model_obj.edi_export(cr, uid, [record], context=ctx) return dict_list @@ -410,7 +429,6 @@ class edi(object): data_line = [] model_data = self.pool.get('ir.model.data') _fields = self.fields_get(cr, uid, context=context) - current_module = 'edi_import' values = {} for field in edi_document.keys(): if not field.startswith('__'): @@ -500,5 +518,5 @@ class edi(object): else: values[field] = edi_field_value - return model_data._update(cr, uid, self._name, current_module, values, context=context) + return model_data._update(cr, uid, self._name, edi_module, values, context=context) # vim: ts=4 sts=4 sw=4 si et From 25dcd09489096441f2588b06db2ad23bab0fd462 Mon Sep 17 00:00:00 2001 From: "Harry (OpenERP)" Date: Mon, 27 Jun 2011 17:51:45 +0530 Subject: [PATCH 7/8] [IMP] EDI: introduce new methods in edi class edi_import_relation: create record of relation object if does not match with relation value edi_xml_id: generate xml id with unique db id. create record of ir.model.data if xml id is not found for particular record. bzr revid: hmo@tinyerp.com-20110627122145-v2d2wtkjut68rcba --- openerp/addons/base/ir/ir_edi.py | 74 ++++++++++++++++---------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/openerp/addons/base/ir/ir_edi.py b/openerp/addons/base/ir/ir_edi.py index 8db5b397116..9672b9a2207 100644 --- a/openerp/addons/base/ir/ir_edi.py +++ b/openerp/addons/base/ir/ir_edi.py @@ -190,6 +190,22 @@ class edi(object): Classes that inherit from this mixin class should override the ``edi_import()`` and ``edi_export()`` methods to implement their specific behavior, based on the primitives provided by this superclass.""" + + def edi_xml_id(self, cr, uid, record, context=None): + model_data_pool = self.pool.get('ir.model.data') + uuid = safe_unique_id(record._name, record.id) + data_ids = model_data_pool.search(cr, uid, [('res_id','=',record.id),('model','=',record._name)]) + if len(data_ids): + xml_record_id = data_ids[0] + else: + xml_record_id = model_data_pool.create(cr, uid, { + 'name': uuid, + 'model': record._name, + 'module': edi_module, + 'res_id': record.id}, context=context) + xml_record = model_data_pool.browse(cr, uid, xml_record_id, context=context) + db_uuid = '%s:%s.%s' % (uuid, xml_record.module, xml_record.name) + return db_uuid def edi_metadata(self, cr, uid, records, context=None): """Return a list representing the boilerplate EDI structure for @@ -206,7 +222,6 @@ class edi(object): """ if context is None: context = {} - model_data_pool = self.pool.get('ir.model.data') data_ids = [] attachment_object = self.pool.get('ir.attachment') edi_dict_list = [] @@ -230,21 +245,7 @@ class edi(object): }) - data_ids = model_data_pool.search(cr, uid, [('res_id','=',record.id),('model','=',record._name)]) - uuid = safe_unique_id(record._name, record.id) - - if len(data_ids): - xml_record_id = data_ids[0] - else: - xml_record_id = model_data_pool.create(cr, uid, { - 'name': uuid, - 'model': record._name, - 'module': edi_module, - 'res_id': record.id}, context=context) - - xml_record = model_data_pool.browse(cr, uid, xml_record_id, context=context) - db_uuid = '%s:%s.%s' % (uuid, xml_record.module, xml_record.name) - + db_uuid = self.edi_xml_id(cr, uid, record, context=context) edi_dict = { '__id': db_uuid, '__last_update': False, #record.write_date, #TODO: convert into UTC @@ -267,20 +268,13 @@ class edi(object): Exmaple: ['db-uuid:xml-id', 'Partner Name'] """ # generic implementation! - data_object = self.pool.get('ir.model.data') - db_uuid = safe_unique_id(record._name, record.id) - xml_ids = data_object.search(cr, uid, [('model','=',record._name),('res_id','=',record.id)]) - - if xml_ids: - xml_id = data_object.browse(cr, uid, xml_ids[0], context=context) - xml_id = '%s.%s' %(xml_id.module, xml_id.name) - else: - xml_id = record._name - db_uuid = '%s:%s' %(db_uuid, xml_id) - name = record.name + db_uuid = self.edi_xml_id(cr, uid, record, context=context) + relation_model_pool = self.pool.get(record._name) + name = relation_model_pool.name_get(cr, uid, [record.id], context=context) + name = name and name[0][1] or False return [db_uuid, name] - def edi_o2m(self, cr, uid, records, context=None): + def edi_o2m(self, cr, uid, records, edi_struct=None, context=None): """Return a list representing a O2M EDI value for the browse_records from the given browse_record_list. @@ -301,7 +295,7 @@ class edi(object): for record in records: model_obj = self.pool.get(record._name) - dict_list += model_obj.edi_export(cr, uid, [record], context=ctx) + dict_list += model_obj.edi_export(cr, uid, [record], edi_struct=edi_struct, context=ctx) return dict_list @@ -368,12 +362,22 @@ class edi(object): elif cols['type'] == 'many2many': value = self.edi_m2m(cr, uid, record, context=context) elif cols['type'] == 'one2many': - value = self.edi_o2m(cr, uid, record, context=context ) + value = self.edi_o2m(cr, uid, record, edi_struct=edi_struct.get(field, {}), context=context ) else: value = record edi_dict[field] = value edi_dict_list.append(edi_dict) return edi_dict_list + + def edi_import_relation(self, cr, uid, relation_model, relation_value, values={}, context=None): + relation_object = self.pool.get(relation_model) + relation_ids = relation_object.name_search(cr, uid, relation_value, context=context) + if relation_ids and len(relation_ids) == 1: + relation_id = relation_ids[0][0] + else: + values.update({'name': relation_value}) + relation_id = relation_object.create(cr, uid, values, context=context) + return relation_id def edi_import(self, cr, uid, edi_document, context=None): @@ -465,13 +469,9 @@ class edi(object): #multiple results are found, go to next step. #Create the new record using the only field value that is known: the #name, and create the ir.model.data entry to map to it. - - relation_object = self.pool.get(_fields[field]['relation']) - relation_ids = relation_object.search(cr, uid, [('name','=',edi_parent_document[1])]) - if relation_ids and len(relation_ids) == 1: - relation_id = relation_ids[0] - else: - relation_id = relation_object.create(cr, uid, {'name': edi_parent_document[1]}, context=context) + relation_model = _fields[field]['relation'] + relation_id = self.edi_import_relation(cr, uid, relation_model, edi_parent_document[1], context=context) + relation_object = self.pool.get(relation_model) model_data.create(cr, uid, { 'name': xml_id, 'model': relation_object._name, From 3be8619d32f3ca9ca3859fde34585ccb3f3d3ae8 Mon Sep 17 00:00:00 2001 From: "Harry (OpenERP)" Date: Wed, 29 Jun 2011 12:10:37 +0530 Subject: [PATCH 8/8] [IMP] web_service: introduce EDI Services to provide service like get_edi_document, import_edi_document, import_edi_url bzr revid: hmo@tinyerp.com-20110629064037-2wb76qua48m1g2bh --- openerp/service/web_services.py | 42 +++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/openerp/service/web_services.py b/openerp/service/web_services.py index 39457807868..37dadc195fb 100644 --- a/openerp/service/web_services.py +++ b/openerp/service/web_services.py @@ -37,6 +37,47 @@ import openerp.modules import locale import logging from cStringIO import StringIO +import threading + +class edi(netsvc.ExportService): + def exp_get_edi_document(self, edi_token): + db_name = getattr(threading.currentThread(), 'dbname', None) + if db_name: + cr = pooler.get_db_only(db_name).cursor() + else: + raise Exception("No database cursor found!") + pool = pooler.get_pool(db_name) + edi_pool = pool.get('ir.edi.document') + return edi_pool.get_document(cr, 1, edi_token) + + def exp_import_edi_document(self, db, uid, passwd, edi_document, context=None): + cr = pooler.get_db_only(db).cursor() + pool = pooler.get_pool(db) + edi_pool = pool.get('ir.edi.document') + return edi_pool.import_edi(cr, uid, edi_document=edi_document, context=context) + + def exp_import_edi_url(self, db, uid, passwd, edi_url, context=None): + cr = pooler.get_db_only(db).cursor() + pool = pooler.get_pool(db) + edi_pool = pool.get('ir.edi.document') + return edi_pool.import_edi(cr, uid, edi_url=edi_url, context=context) + + def __init__(self, name="edi"): + netsvc.ExportService.__init__(self, name) + self.joinGroup("web-services") + + def dispatch(self, method, auth, params): + if method in ['import_edi_document', 'import_edi_url']: + (db, uid, passwd ) = params[0:3] + security.check(db, uid, passwd) + elif method in ['get_edi_document']: + # params = params + # No security check for these methods + pass + else: + raise KeyError("Method not found: %s" % method) + fn = getattr(self, 'exp_'+method) + return fn(*params) class db(netsvc.ExportService): def __init__(self, name="db"): @@ -763,6 +804,7 @@ def start_web_services(): objects_proxy() wizard() report_spool() + edi() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: