1 ## -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Management Solution
5 # Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ##############################################################################
22 from datetime import date
29 from osv import osv, fields
31 class RPCProxyOne(object):
32 def __init__(self, server, ressource):
34 local_url = 'http://%s:%d/xmlrpc/common'%(server.server_url,server.server_port)
35 rpc = xmlrpclib.ServerProxy(local_url)
36 self.uid = rpc.login(server.server_db, server.login, server.password)
37 local_url = 'http://%s:%d/xmlrpc/object'%(server.server_url,server.server_port)
38 self.rpc = xmlrpclib.ServerProxy(local_url)
39 self.ressource = ressource
40 def __getattr__(self, name):
41 return lambda cr, uid, *args, **kwargs: self.rpc.execute(self.server.server_db, self.uid, self.server.password, self.ressource, name, *args, **kwargs)
43 class RPCProxy(object):
44 def __init__(self, server):
46 def get(self, ressource):
47 return RPCProxyOne(self.server, ressource)
49 class base_synchro(osv.osv_memory):
50 """Base Synchronization """
51 _name = 'base.synchro'
54 'server_url': fields.many2one('base.synchro.server', "Server URL", required=True),
55 'user_id': fields.many2one('res.users', "Send Result To",),
59 'user_id': lambda self,cr,uid,context: uid,
62 start_date = time.strftime('%Y-%m-%d, %Hh %Mm %Ss')
68 def synchronize(self, cr, uid, server, object, context=None):
69 pool = pooler.get_pool(cr.dbname)
72 pool1 = RPCProxy(server)
75 if object.action in ('d','b'):
76 ids = pool1.get('base.synchro.obj').get_ids(cr, uid,
77 object.model_id.model,
78 object.synchronize_date,
82 if object.action in ('u','b'):
83 ids += pool2.get('base.synchro.obj').get_ids(cr, uid,
84 object.model_id.model,
85 object.synchronize_date,
91 for dt, id, action in ids:
92 print 'Process', dt, id, action
100 print 'Read', object.model_id.model, id
102 if object.model_id.model=='crm.case.history':
103 fields = ['email','description','log_id']
104 value = pool_src.get(object.model_id.model).read(cr, uid, [id], fields)[0]
105 value = self.data_transform(cr, uid, pool_src, pool_dest, object.model_id.model, value, action)
106 id2 = self.get_id(cr, uid, object.id, id, action, context)
110 #tid=pool_dest.get(object.model_id.model).name_search(cr, uid, value['name'],[],'=',)
114 # Filter fields to not sync
115 for field in object.avoid_ids:
116 if field.name in value:
117 del value[field.name]
121 pool_dest.get(object.model_id.model).write(cr, uid, [id2], value)
122 #except Exception, e:
123 #self.report.append('ERROR: Unable to update record ['+str(id2)+']:'+str(value.get('name', '?')))
128 idnew = pool_dest.get(object.model_id.model).create(cr, uid, value)
129 synid = self.pool.get('base.synchro.obj.line').create(cr, uid, {
131 'local_id': (action=='u') and id or idnew,
132 'remote_id': (action=='d') and id or idnew
135 self.report_create+=1
139 def get_id(self, cr, uid, object_id, id, action, context=None):
140 pool = pooler.get_pool(cr.dbname)
141 line_pool = pool.get('base.synchro.obj.line')
142 field_src = (action=='u') and 'local_id' or 'remote_id'
143 field_dest = (action=='d') and 'local_id' or 'remote_id'
144 rid = line_pool.search(cr, uid, [('obj_id','=',object_id), (field_src,'=',id)], context=context)
147 result = line_pool.read(cr, uid, rid, [field_dest], context=context)[0][field_dest]
150 def relation_transform(self, cr, uid, pool_src, pool_dest, object, id, action, context=None):
153 pool = pooler.get_pool(cr.dbname)
154 cr.execute('''select o.id from base_synchro_obj o left join ir_model m on (o.model_id =m.id) where
156 o.active''', (object,))
161 # If the object is synchronised and found, set it
163 result = self.get_id(cr, uid, obj[0], id, action, context)
166 # If not synchronized, try to find it with name_get/name_search
168 names = pool_src.get(object).name_get(cr, uid, [id])[0][1]
169 res = pool_dest.get(object).name_search(cr, uid, names, [], 'like')
173 # LOG this in the report, better message.
174 print self.report.append('WARNING: Record "%s" on relation %s not found, set to null.' % (names,object))
179 # OUT: ID of the remote object computed:
180 # If object is synchronised, read the sync database
181 # Otherwise, use the name_search method
184 def data_transform(self, cr, uid, pool_src, pool_dest, object, data, action='u', context=None):
185 self.meta.setdefault(pool_src, {})
186 if not object in self.meta[pool_src]:
187 self.meta[pool_src][object] = pool_src.get(object).fields_get(cr, uid)
188 fields = self.meta[pool_src][object]
193 ftype = fields[f]['type']
195 if ftype in ('function', 'one2many', 'one2one'):
197 elif ftype == 'many2one':
199 df = self.relation_transform(cr, uid, pool_src, pool_dest, fields[f]['relation'], data[f][0], action, context=context)
203 elif ftype == 'many2many':
204 res = map(lambda x: self.relation_transform(cr, uid, pool_src, pool_dest, fields[f]['relation'], x, action, context), data[f])
205 data[f] = [(6, 0, res)]
210 # Find all objects that are created or modified after the synchronize_date
211 # Synchronize these obejcts
215 def upload_download(self, cr, uid, ids, context=None):
216 start_date = time.strftime('%Y-%m-%d, %Hh %Mm %Ss')
217 syn_obj = self.browse(cr, uid, ids, context=context)[0]
218 pool = pooler.get_pool(cr.dbname)
219 server = pool.get('base.synchro.server').browse(cr, uid, ids, context=context)[0]
220 for object in server.obj_ids:
221 dt = time.strftime('%Y-%m-%d %H:%M:%S')
222 self.synchronize(cr, uid, server, object, context)
223 if object.action=='b':
225 dt = time.strftime('%Y-%m-%d %H:%M:%S')
226 self.pool.get('base.synchro.obj').write(cr, uid, [object.id], {'synchronize_date': dt})
227 end_date = time.strftime('%Y-%m-%d, %Hh %Mm %Ss')
229 request = pooler.get_pool(cr.dbname).get('res.request')
231 self.report.append('No exception.')
232 summary = '''Here is the synchronization report:
234 Synchronization started: %s
235 Synchronization finnished: %s
237 Synchronized records: %d
242 '''% (start_date,end_date,self.report_total, self.report_write,self.report_create)
243 summary += '\n'.join(self.report)
244 request.create(cr, uid, {
245 'name' : "Synchronization report",
247 'act_to' : syn_obj.user_id.id,
252 def upload_download_multi_thread(self, cr, uid, data, context=None):
253 threaded_synchronization = threading.Thread(target=self.upload_download, args=(cr, uid, data, context))
254 threaded_synchronization.run()
255 data_obj = self.pool.get('ir.model.data')
256 id2 = data_obj._get_id(cr, uid, 'base_synchro', 'view_base_synchro_finish')
258 id2 = data_obj.browse(cr, uid, id2, context=context).res_id
262 'res_model': 'base.synchro',
263 'views': [(id2, 'form')],
265 'type': 'ir.actions.act_window',
269 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: