[MERGE] backlog correction by atp team + error reporting + soft dependency, if the module is not installed, ignore data

bzr revid: tfr@openerp.com-20110713135604-i4ydmqmyjt65e5f9
This commit is contained in:
tfr@openerp.com 2011-07-13 15:56:04 +02:00
commit 43e1fa4c54
6 changed files with 121 additions and 66 deletions

View File

@ -73,7 +73,6 @@
<record id="base_setup_installer_todo" model="ir.actions.todo">
<field name="action_id" ref="action_base_setup_installer"/>
<field name="category_id" ref="base.category_administration_config"/>
<field name="sequence">2</field>
<field name="type">normal_recurring</field>
</record>
@ -124,7 +123,6 @@
<record id="migrade_application_installer_modules_todo" model="ir.actions.todo">
<field name="action_id" ref="action_migrade_application_installer_modules"/>
<field name="category_id" ref="base.category_administration_config"/>
<field name="type">normal</field>
<field name="state">skip</field>
</record>
@ -144,7 +142,6 @@
<!-- register configuration wizard -->
<record id="config_wizard_action_import_create_installer" model="ir.actions.todo">
<field name="action_id" ref="action_import_create_installer"/>
<field name="category_id" ref="base.category_administration_config"/>
<field name="type">normal</field>
<field name="target">current</field>
<field name="state">skip</field>
@ -199,7 +196,6 @@
<record id="config_action_user_preferences_config_form" model="ir.actions.todo">
<field name="action_id" ref="action_user_preferences_config_form"/>
<field name="category_id" ref="base.category_administration_config"/>
<field name="type">normal</field>
<field name="state">skip</field>
</record>
@ -219,7 +215,6 @@
<record id="config_wizard_action_config_user_form" model="ir.actions.todo">
<field name="action_id" ref="action_config_access_other_user"/>
<field name="category_id" ref="base.category_administration_config"/>
<field name="type">normal</field>
<field name="target">current</field>
<field name="sequence">1000</field>
@ -230,7 +225,6 @@
<record id="config_wizard_action_res_company_logo" model="ir.actions.todo">
<field name="action_id" ref="action_res_company_logo"/>
<field name="category_id" ref="base.category_administration_config"/>
<field name="type">normal</field>
<field name="state">cancel</field>
</record>
@ -281,7 +275,6 @@
<record id="config_action_partner_terminology_config_form" model="ir.actions.todo">
<field name="action_id" ref="action_partner_terminology_config_form"/>
<field name="category_id" ref="base.category_administration_config"/>
<field name="type">normal</field>
<field name="state">skip</field>
</record>
@ -299,7 +292,6 @@
<record id="base_setup_company_todo" model="ir.actions.todo">
<field name="action_id" ref="action_base_setup_company"/>
<field name="category_id" ref="base.category_administration_config"/>
<field name="sequence">1</field>
<field name="type">normal</field>
<field name="state">skip</field>

View File

@ -22,11 +22,13 @@ import pprint
import mapper
import pooler
import tools
from tools.translate import _
from threading import Thread
import datetime
import logging
import StringIO
import traceback
pp = pprint.PrettyPrinter(indent=4)
@ -58,6 +60,7 @@ class import_framework(Thread):
self.context = context or {}
self.email = email_to_notify
self.table_list = []
self.logger = logging.getLogger('import_framework')
"""
Abstract Method to be implemented in
@ -175,8 +178,9 @@ class import_framework(Thread):
model_obj = self.obj.pool.get(model)
if not model_obj:
raise ValueError("%s is not a valid model name" % model)
raise ValueError(_("%s is not a valid model name") % model)
self.logger.debug(_("fields imported : "))
self.logger.debug(fields)
(p, r, warning, s) = model_obj.import_data(self.cr, self.uid, fields, res, mode='update', current_module=self.module_name, noupdate=True, context=self.context)
for (field, field_name) in self_dependencies:
self._import_self_dependencies(model_obj, field, datas)
@ -311,6 +315,9 @@ class import_framework(Thread):
"""
domain_search = not domain_search and [('name', 'ilike', name)] or domain_search
obj = self.obj.pool.get(model)
if not obj: #if the model doesn't exist
return False
xml_id = self._generate_xml_id(name, table)
xml_ref = self.mapped_id_if_exist(model, domain_search, table, name)
fields.append('id')
@ -359,6 +366,7 @@ class import_framework(Thread):
"""
self.data_started = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.cr = pooler.get_db(self.cr.dbname).cursor()
error = False
try:
self.initialize()
result = []
@ -369,16 +377,22 @@ class import_framework(Thread):
res = self._resolve_dependencies(self.get_mapping()[table].get('dependencies', []), imported)
result.extend(res)
if to_import:
self.logger.debug(_("import : ") + table )
(position, warning) = self._import_table(table)
result.append((table, position, warning))
imported.add(table)
self.cr.commit()
except Exception, err:
sh = StringIO.StringIO()
traceback.print_exc(file=sh)
error = sh.getvalue()
print error
finally:
self.cr.close()
self.date_ended = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self._send_notification_email(result)
self._send_notification_email(result, error)
def _resolve_dependencies(self, dep, imported):
"""
@ -392,26 +406,29 @@ class import_framework(Thread):
res = self._resolve_dependencies(self.get_mapping()[dependency].get('dependencies', []), imported)
result.extend(res)
if to_import:
self.logger.debug("import dependency : " + dependency)
r = self._import_table(dependency)
(position, warning) = r
result.append((dependency, position, warning))
imported.add(dependency)
return result
def _send_notification_email(self, result):
if not self.email:
def _send_notification_email(self, result, error):
if not self.email or not self.email[0]:
return False
tools.email_send(
'import@module.openerp',
self.email,
self.get_email_subject(result),
self.get_email_body(result),
self.get_email_subject(result, error),
self.get_email_body(result, error),
)
logger = logging.getLogger('import_sugarcam')
logger.info("Import finished, notification email sended")
if error:
self.logger.error(_("Import failed due to an unexpected error"))
else:
self.logger.info(_("Import finished, notification email sended"))
def get_email_subject(self, result):
def get_email_subject(self, result, error=False):
"""
This method define the subject of the email send by openerp at the end of import
@param result: a list of tuple
@ -419,9 +436,11 @@ class import_framework(Thread):
@return the subject of the mail
"""
return "Import of your data finished at %s" % self.date_ended
if error:
return _("Data Import failed at %s due to an unexpected error") % self.date_ended
return _("Import of your data finished at %s") % self.date_ended
def get_email_body(self, result):
def get_email_body(self, result, error=False):
"""
This method define the body of the email send by openerp at the end of import. The body is separated in two part
the header (@see get_body_header), and the generate body with the list of table and number of record imported.
@ -432,20 +451,23 @@ class import_framework(Thread):
"""
body = "started at %s and finished at %s \n" % (self.data_started, self.date_ended)
body = _("started at %s and finished at %s \n") % (self.data_started, self.date_ended)
if error:
body += _("but failed, in consequence no data were imported to keep database consistency \n error : \n") + error
for (table, nb, warning) in result:
if not warning:
warning = "with no warning"
warning = _("with no warning")
else:
warning = "with warning : %s" % warning
body += "%s records were imported from table %s, %s \n" % (nb, table, warning)
warning = _("with warning : %s") % warning
body += _("%s records were imported from table %s, %s \n") % (nb, table, warning)
return self.get_body_header(result) + "\n\n" + body
def get_body_header(self, result):
"""
@return the first sentences written in the mail's body
"""
return "The import of data \n instance name : %s \n" % self.instance_name
return _("The import of data \n instance name : %s \n") % self.instance_name
#TODO documentation test

View File

@ -27,7 +27,7 @@
"Contacts", "Employees", Meetings, Phonecalls, Emails, and Project, Project Tasks Data into OpenERP Module.""",
'author': 'OpenERP SA',
'website': 'http://www.openerp.com',
'depends': ['import_base', 'crm_claim', 'project', 'project_issue', 'hr', 'document'],
'depends': ['import_base','crm', 'document'],
'init_xml': [],
'update_xml': ["wizard/import_message_view.xml",
"import_sugarcrm_view.xml"],

View File

@ -75,7 +75,6 @@ class sugar_import(import_framework):
def get_data(self, table):
offset = 0
res = []
while True:
r = sugar.search(self.context.get('port'), self.context.get('session_id'), table, offset, self.MAX_RESULT_PER_PAGE)
@ -157,6 +156,7 @@ class sugar_import(import_framework):
def import_document(self, val):
File,Filename = sugar.get_document_revision_search(self.context.get('port'), self.context.get('session_id'), val.get('document_revision_id'))
#File = base64.encodestring(File)
res_id, res_model = self.import_related_document(val)
val['res_id'] = res_id
val['res_model'] = res_model
@ -168,9 +168,10 @@ class sugar_import(import_framework):
def get_document_mapping(self):
return {
'model' : 'ir.attachment',
'dependencies' : [self.TABLE_USER, self.TABLE_ACCOUNT,self.TABLE_CONTACT, self.TABLE_OPPORTUNITY, self.TABLE_CASE, self.TABLE_BUG],
'dependencies' : [self.TABLE_USER],
'hook' : self.import_document,
'map' : {'name':'document_name',
'map' : {
'name':'document_name',
'description': ppconcat('description'),
'datas': 'datas',
'datas_fname': 'datas_fname',
@ -203,10 +204,11 @@ class sugar_import(import_framework):
def get_email_mapping(self):
return {
'model' : 'mailgate.message',
'dependencies' : [self.TABLE_USER, self.TABLE_PROJECT, self.TABLE_PROJECT_TASK, self.TABLE_ACCOUNT, self.TABLE_CONTACT, self.TABLE_LEAD, self.TABLE_OPPORTUNITY, self.TABLE_MEETING, self.TABLE_CALL],
'dependencies' : [self.TABLE_USER, self.TABLE_ACCOUNT, self.TABLE_CONTACT, self.TABLE_LEAD, self.TABLE_OPPORTUNITY, self.TABLE_MEETING, self.TABLE_CALL],
'hook' : self.import_email,
'map' : {'name':'name',
'history' : const("1"),
'map' : {
'name':'name',
'history' : const("1"),
'date':'date_sent',
'email_from': 'from_addr_name',
'email_to': 'to_addrs_names',
@ -245,7 +247,7 @@ class sugar_import(import_framework):
def get_history_mapping(self):
return {
'model' : 'ir.attachment',
'dependencies' : [self.TABLE_USER, self.TABLE_PROJECT, self.TABLE_PROJECT_TASK, self.TABLE_ACCOUNT, self.TABLE_CONTACT, self.TABLE_LEAD, self.TABLE_OPPORTUNITY, self.TABLE_MEETING, self.TABLE_CALL, self.TABLE_EMAIL],
'dependencies' : [self.TABLE_USER, self.TABLE_ACCOUNT, self.TABLE_CONTACT, self.TABLE_LEAD, self.TABLE_OPPORTUNITY, self.TABLE_MEETING, self.TABLE_CALL, self.TABLE_EMAIL],
'hook' : self.import_history,
'map' : {
'name':'name',
@ -880,7 +882,7 @@ class sugar_import(import_framework):
'hook' : self.import_user,
'map' : {
'name': concat('first_name', 'last_name'),
'login': 'user_name',
'login': value('user_name', fallback='last_name'),
'context_lang' : 'context_lang',
'password' : 'password',
'.id' : '.id',
@ -914,7 +916,9 @@ class sugar_import(import_framework):
"""
Email notification
"""
def get_email_subject(self, result):
def get_email_subject(self, result, error=False):
if error:
return "Sugarcrm data import failed at %s due to an unexpected error" % self.date_ended
return "your sugarcrm data were successfully imported at %s" % self.date_ended
def get_body_header(self, result):
@ -948,23 +952,42 @@ class import_sugarcrm(osv.osv):
}
def _get_email_id(self, cr, uid, context=None):
return self.pool.get('res.users').browse(cr, uid, uid, context=context).user_email
return self.pool.get('res.users').browse(cr, uid, uid, context=context).user_email
def _module_installed(self, cr, uid, model, context=None):
module_id = self.pool.get('ir.module.module').search(cr, uid, [('name', '=', model), ('state', "=", "installed")], context=context)
return bool(module_id)
def _project_installed(self, cr, uid, context=None):
return self._module_installed(cr,uid,'project',context=context)
def _crm_claim_installed(self, cr, uid, context=None):
return self._module_installed(cr,uid,'crm_claim',context=context)
def _project_issue_installed(self, cr, uid, context=None):
return self._module_installed(cr,uid,'project_issue',context=context)
def _hr_installed(self, cr, uid, context=None):
return self._module_installed(cr,uid,'hr',context=context)
_defaults = {#to be set to true, but easier for debugging
'opportunity': True,
'contact' : True,
'account' : True,
'employee' : False,
'employee' : _hr_installed,
'meeting' : True,
'call' : True,
'claim' : True,
'claim' : _crm_claim_installed,
'email_history' : True,
'project' : True,
'project_task': True,
'bug': True,
'document': False,
'project' : _project_installed,
'project_task': _project_installed,
'bug': _project_issue_installed,
'document': True,
'instance_name': 'sugarcrm',
'email_from': _get_email_id,
#'username' : 'admin',
#'password' : '',
#'url': "http://sugarcrm.example.com/soap.php"
'username' : 'tfr',
'password' : 'a',
'url': "http://localhost/sugarcrm/soap.php"
@ -987,8 +1010,6 @@ class import_sugarcrm(osv.osv):
if not context:
context = {}
url = context.get('url')
url_split = str(url).split('/')
while len(url_split) >= 3:
#3 case, soap.php is already at the end of url should be valid
@ -1011,35 +1032,41 @@ class import_sugarcrm(osv.osv):
if not context:
context = {}
key_list = []
module = {}
for current in self.browse(cr, uid, ids, context):
context.update({'username': current.username, 'password': current.password, 'url': current.url, 'email_user': current.email_from or False, 'instance_name': current.instance_name or False})
if current.opportunity:
key_list.append('Leads')
key_list.append('Opportunities')
if current.contact:
key_list.append('Contacts')
if current.account:
key_list.append('Accounts')
key_list.append('Accounts')
if current.opportunity:
key_list.append('Leads')
key_list.append('Opportunities')
if current.employee:
key_list.append('Employees')
key_list.append('Employees')
module.update({'Employees':'hr'})
if current.meeting:
key_list.append('Meetings')
if current.call:
key_list.append('Calls')
if current.claim:
key_list.append('Cases')
key_list.append('Cases')
module.update({'Cases':'crm_claim'})
if current.email_history:
key_list.append('Emails')
key_list.append('Notes')
if current.project:
key_list.append('Project')
module.update({'Project':'project'})
if current.project_task:
key_list.append('ProjectTask')
module.update({'ProjectTask':'project'})
if current.bug:
key_list.append('Bugs')
module.update({'Bugs':'project_issue'})
if current.document:
key_list.append('Documents')
return key_list
return key_list,module
def do_import_all(self, cr, uid, *args):
@ -1053,9 +1080,16 @@ class import_sugarcrm(osv.osv):
return True
def import_from_scheduler_all(self, cr, uid, ids, context=None):
keys = self.get_key(cr, uid, ids, context)
keys, module_list = self.get_key(cr, uid, ids, context)
if not keys:
raise osv.except_osv(_('Warning !'), _('Select Module to Import.'))
key_list = module_list.keys()
for module in key_list :
module = module_list[module]
state = self.get_all(cr,uid,module,context=context)
if state == False:
keys = ', '.join(key_list)
raise osv.except_osv(_('Error !!'), _("%s data required %s Module to be installed, Please install %s module") %(keys,module,module))
cron_obj = self.pool.get('ir.cron')
url = self.parse_valid_url(context)
args = (keys,context.get('email_user'), context.get('instance_name'), url, context.get('username'), context.get('password') )
@ -1068,18 +1102,25 @@ class import_sugarcrm(osv.osv):
'res_id': new_create_id,
'type': 'ir.actions.act_window',
}
def import_all(self, cr, uid, ids, context=None):
# """Import all sugarcrm data into openerp module"""
keys = self.get_key(cr, uid, ids, context)
keys, module_list = self.get_key(cr, uid, ids, context)
if not keys:
raise osv.except_osv(_('Warning !'), _('Select Module to Import.'))
key_list = module_list.keys()
for module in key_list :
module = module_list[module]
state = self._module_installed(cr,uid,module,context=context)
if state == False:
keys = ', '.join(key_list)
raise osv.except_osv(_('Error !!'), _("%s data required %s Module to be installed, Please install %s module") %(keys,module,module))
url = self.parse_valid_url(context)
context.update({'url': url})
imp = sugar_import(self, cr, uid, context.get('instance_name'), "import_sugarcrm", [context.get('email_user')], context)
imp.set_table_list(keys)
imp.start()
obj_model = self.pool.get('ir.model.data')
model_data_ids = obj_model.search(cr,uid,[('model','=','ir.ui.view'),('name','=','import.message.form')])
resource_id = obj_model.read(cr, uid, model_data_ids, fields=['res_id'])

View File

@ -13,13 +13,13 @@
<group colspan="2" col="1" width="200">
<label colspan="2" string="Import your data from SugarCRM :"/>
<label colspan="2" string="" />
<label colspan="2" string="Use the SugarSoap API URL (read tooltip), a full access Sugar login."/>
<label colspan="2" string="Use the SugarSoap API URL (read tooltip) and a full access SugarCRM login."/>
<label colspan="2" string="" />
<label colspan="2" string="Choose groups of data you want to import. Click 'Import' to get data manually or click 'schedule reccurent import' to get recurrently and automatically data."/>
<label colspan="2" string="Choose data you want to import. Click 'Import' to get data manually or 'Schedule Reccurent Import' to get recurrently and automatically data."/>
<label colspan="2" string="" />
<label colspan="2" string="If you make recurrent or ponctual import, data already imported in OpenERP will be erased by Sugar data."/>
<label colspan="2" string="If you make recurrent or ponctual import, data already in OpenERP will be updated by SugarCRM data."/>
<label colspan="2" string="" />
<label colspan="2" string="Don't forget to add an address email to be notified of the success of the import."/>
<label colspan="2" string="Do not forget the email address to be notified of the success of the import."/>
<label colspan="2" />
<label colspan="2" string="Online documentation:"/>
<label colspan="2" string="(Comming Soon)"/>
@ -74,8 +74,8 @@
<group colspan="4" col="6">
<label string="" colspan="2"/>
<button icon="gtk-cancel" special="cancel" string="_Cancel"/>
<button name="import_from_scheduler_all" string="_Schedule recurrent import"
type="object" icon="gtk-execute"/>
<button name="import_from_scheduler_all" groups="base.group_extended" string="_Schedule Recurrent Import"
type="object" icon="gtk-execute" />
<button name="import_all" string="_Import"
type="object" icon="terp-camera_test"/>
</group>

View File

@ -9,7 +9,7 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Import Message">
<label colspan="4" nolabel="1" string="Import Data Launch: The Import Process is running in the background. You'll receive an email soon when import will be finished"/>
<label colspan="4" nolabel="1" string="Data are importing, the process is running in the background, You will receive an email at the end of the import."/>
<separator string="" colspan="4" />
<button icon="gtk-ok" special="cancel" string="_Ok"/>
</form>