diff --git a/addons/account/account.py b/addons/account/account.py
index 04a0bb5da68..61319f7f973 100644
--- a/addons/account/account.py
+++ b/addons/account/account.py
@@ -1965,13 +1965,12 @@ class account_add_tmpl_wizard(osv.osv_memory):
if not tids or not tids[0]['parent_id']:
return False
ptids = tmpl_obj.read(cr, uid, [tids[0]['parent_id'][0]],['code'])
+ res = None
if not ptids or not ptids[0]['code']:
raise osv.except_osv(_('Error !'), _('Cannot locate parent code for template account!'))
res = acc_obj.search(cr,uid,[('code','=',ptids[0]['code'])])
- if res:
- return res[0]
- else:
- return False
+
+ return res and res[0] or False
_columns = {
'cparent_id':fields.many2one('account.account', 'Parent target', help="Creates an account with the selected template under this existing parent.", required=True),
diff --git a/addons/account/partner_view.xml b/addons/account/partner_view.xml
index e1e43420d6e..7fbc1c14eb7 100644
--- a/addons/account/partner_view.xml
+++ b/addons/account/partner_view.xml
@@ -133,11 +133,7 @@
-
-
-
-
-
+
diff --git a/addons/base_action_rule/base_action_rule.py b/addons/base_action_rule/base_action_rule.py
index a1213dd7542..85c4e9d4480 100644
--- a/addons/base_action_rule/base_action_rule.py
+++ b/addons/base_action_rule/base_action_rule.py
@@ -19,14 +19,16 @@
#
##############################################################################
-import time
-import mx.DateTime
-import re
-
-import tools
+from datetime import datetime
from osv import fields, osv, orm
from osv.orm import except_orm
+from osv.osv import osv_pool
from tools.translate import _
+import mx.DateTime
+import pooler
+import re
+import time
+import tools
class base_action_rule(osv.osv):
""" Base Action Rules """
@@ -132,6 +134,74 @@ the rule to mark CC(mail to any other person defined in actions)."),
_order = 'sequence'
+ def pre_action(self, cr, uid, ids, model, context=None):
+ # Searching for action rules
+ cr.execute("SELECT m.model, r.id from base_action_rule r left join ir_model m on (m.id = r.name)")
+ res = cr.fetchall()
+ # Check if any rule matching with current object
+ for obj_name, rule_id in res:
+ if not (model == obj_name):
+ continue
+ else:
+ obj = self.pool.get(obj_name)
+ self._action(cr, uid, [rule_id], obj.browse(cr, uid, ids, context=context))
+ return True
+
+ def new_create(self, old_create, model, context=None):
+ if not context:
+ context = {}
+ def make_call_old(cr, uid, vals, context=context):
+ new_id = old_create(cr, uid, vals, context=context)
+ if not context.get('action'):
+ self.pre_action(cr, uid, [new_id], model, context=context)
+ return new_id
+ return make_call_old
+
+ def new_write(self, old_write, model, context=None):
+ if not context:
+ context = {}
+ def make_call_old(cr, uid, ids, vals, context=context):
+ if isinstance(ids, (str, int, long)):
+ ids = [ids]
+ if not context.get('action'):
+ self.pre_action(cr, uid, ids, model, context=context)
+ return old_write(cr, uid, ids, vals, context=context)
+ return make_call_old
+
+ def create(self, cr, uid, vals, context=None):
+ if not context:
+ context = {}
+ res_id = super(base_action_rule, self).create(cr, uid, vals, context)
+ model_pool = self.pool.get('ir.model')
+ model = model_pool.browse(cr, uid, vals.get('name'), context=context).model
+ obj_pool = self.pool.get(model)
+ obj_pool.__setattr__('old_create', obj_pool.create)
+ obj_pool.__setattr__('old_write', obj_pool.write)
+ obj_pool.__setattr__('create', self.new_create(obj_pool.create, model, context=context))
+ obj_pool.__setattr__('write', self.new_write(obj_pool.write, model, context=context))
+ return res_id
+
+ def write(self, cr, uid, ids, vals, context=None):
+ res = super(base_action_rule, self).write(cr, uid, ids, vals, context)
+ model_pool = self.pool.get('ir.model')
+ if not context:
+ context = {}
+ for rule in self.browse(cr, uid, ids, context=context):
+ model = model_pool.browse(cr, uid, rule.name.id, context=context).model
+ obj_pool = self.pool.get(model)
+ obj_pool.__setattr__('old_create', obj_pool.create)
+ obj_pool.__setattr__('old_write', obj_pool.write)
+ obj_pool.__setattr__('create', self.new_create(obj_pool.create, model, context=context))
+ obj_pool.__setattr__('write', self.new_write(obj_pool.write, model, context=context))
+ return res
+
+ def _check(self, cr, uid, automatic=False, use_new_cursor=False, \
+ context=None):
+ rule_pool= self.pool.get('base.action.rule')
+ rule_ids = rule_pool.search(cr, uid, [], context=context)
+ return rule_pool.write(cr, uid, rule_ids, {}, context=context)
+
+
def format_body(self, body):
""" Foramat Action rule's body
@param self: The object pointer """
@@ -235,6 +305,7 @@ the rule to mark CC(mail to any other person defined in actions)."),
context.update({'active_id':obj.id, 'active_ids':[obj.id]})
self.pool.get('ir.actions.server').run(cr, uid, [action.server_action_id.id], context)
write = {}
+
if hasattr(obj, 'user_id') and action.act_user_id:
obj.user_id = action.act_user_id
write['user_id'] = action.act_user_id.id
@@ -279,12 +350,10 @@ the rule to mark CC(mail to any other person defined in actions)."),
@param ids: List of Basic Action Rule’s IDs,
@param objects: pass objects
@param context: A standard dictionary for contextual values """
-
+ context.update({'action': True})
if not scrit:
scrit = []
- cr.execute("select id from base_action_rule order by sequence")
- rule_ids = map(lambda x: x[0], cr.fetchall())
- for action in self.browse(cr, uid, rule_ids):
+ for action in self.browse(cr, uid, ids):
level = action.max_level
if not level:
break
@@ -333,6 +402,7 @@ the rule to mark CC(mail to any other person defined in actions)."),
self.do_action(cr, uid, action, model_obj, obj, context)
break
level -= 1
+ context.update({'action': False})
return True
def _check_mail(self, cr, uid, ids, context=None):
@@ -359,4 +429,27 @@ the rule to mark CC(mail to any other person defined in actions)."),
base_action_rule()
+
+class ir_cron(osv.osv):
+ _inherit = 'ir.cron'
+
+ def _poolJobs(self, db_name, check=False):
+ try:
+ db, pool = pooler.get_db_and_pool(db_name)
+ except:
+ return False
+ cr = db.cursor()
+ try:
+ next = datetime.now().strftime('%Y-%m-%d %H:00:00')
+ # Putting nextcall always less than current time in order to call it every time
+ cr.execute('UPDATE ir_cron set nextcall = \'%s\' where numbercall<>0 and active and model=\'base.action.rule\' ' % (next))
+ cr.commit()
+ res = super(ir_cron, self)._poolJobs(db_name, check=check)
+ finally:
+ cr.commit()
+ cr.close()
+
+ir_cron()
+
+
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml
index 31872e27ef4..dbfbeedf0a8 100644
--- a/addons/crm/crm_lead_view.xml
+++ b/addons/crm/crm_lead_view.xml
@@ -12,9 +12,11 @@
[('object_id.model', '=', 'crm.lead')]
{'object_id':'crm.lead'}
-
+
+
+
@@ -26,10 +28,11 @@
[('object_id.model', '=', 'crm.lead')]
{'object_id':'crm.lead'}
-
+
+
diff --git a/addons/crm/crm_meeting.py b/addons/crm/crm_meeting.py
index e45ee85b31d..133cb98f9dc 100644
--- a/addons/crm/crm_meeting.py
+++ b/addons/crm/crm_meeting.py
@@ -57,7 +57,8 @@ class crm_meeting(osv.osv, crm_case):
Define Responsible user and Email account for mail gateway.'),
'email_from': fields.char('Email', size=128, help="These people will receive email."),
'id': fields.integer('ID'),
-
+ 'create_date': fields.datetime('Creation Date' , readonly=True),
+ 'write_date': fields.datetime('Write Date' , readonly=True),
# Meeting fields
'thread_id': fields.many2one('mailgate.thread', 'Thread', required=False),
'categ_id': fields.many2one('crm.case.categ', 'Meeting Type', \
diff --git a/addons/crm/crm_meeting_view.xml b/addons/crm/crm_meeting_view.xml
index e84bbb673ee..e2decc30340 100644
--- a/addons/crm/crm_meeting_view.xml
+++ b/addons/crm/crm_meeting_view.xml
@@ -13,8 +13,8 @@
{'object_id':'crm.meeting'}
-
+
diff --git a/addons/crm/crm_opportunity_view.xml b/addons/crm/crm_opportunity_view.xml
index 8b5cc42c502..407c3c53cf4 100644
--- a/addons/crm/crm_opportunity_view.xml
+++ b/addons/crm/crm_opportunity_view.xml
@@ -14,8 +14,8 @@
+ id="menu_crm_case_opportunity-act" name="Categories"
+ parent="menu_crm_config_opportunity" />
@@ -29,8 +29,8 @@
+ id="menu_crm_opportunity_stage_act" name="Stages"
+ parent="menu_crm_config_opportunity" />
@@ -44,8 +44,8 @@
+ id="menu_crm_opportunity_resource_act" name="Resource"
+ parent="menu_crm_config_opportunity" />
@@ -329,7 +329,7 @@
-
+
diff --git a/addons/crm/crm_phonecall_view.xml b/addons/crm/crm_phonecall_view.xml
index 65b77ed5abe..c5813a38b09 100644
--- a/addons/crm/crm_phonecall_view.xml
+++ b/addons/crm/crm_phonecall_view.xml
@@ -13,8 +13,8 @@
{'object_id':'crm.phonecall'}
-
+
@@ -27,10 +27,9 @@
{'object_id':'crm.phonecall'}
-
-
+
diff --git a/addons/crm/crm_view.xml b/addons/crm/crm_view.xml
index 52450419fd2..f854981858c 100644
--- a/addons/crm/crm_view.xml
+++ b/addons/crm/crm_view.xml
@@ -1,8 +1,20 @@
-
+
+
+
+
+
+
+
+
+
@@ -117,9 +129,7 @@
-
-
-
+
crm.case.categ.form
@@ -156,11 +166,11 @@
form
-
+ id="menu_crm_case_section_act" sequence="4"
+ parent="base.menu_crm_config_sales" />
+
@@ -201,8 +211,6 @@
form
-
Cases by section
@@ -342,10 +350,11 @@
form
tree,form
-
+ groups="base.group_extended" sequence="5"
+ parent="base.menu_crm_config_sales" />
view.users.form.crm.modif.inherited1
diff --git a/addons/crm/res_partner_view.xml b/addons/crm/res_partner_view.xml
index 24523f7b072..254d2c8f3b4 100644
--- a/addons/crm/res_partner_view.xml
+++ b/addons/crm/res_partner_view.xml
@@ -11,52 +11,48 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/crm/test/test_crm_meeting.yml b/addons/crm/test/test_crm_meeting.yml
index 6365c913b1f..94a7b7a9442 100644
--- a/addons/crm/test/test_crm_meeting.yml
+++ b/addons/crm/test/test_crm_meeting.yml
@@ -9,11 +9,11 @@
date: '2010-04-21 16:04:00'
date_deadline: '2010-04-22 00:04:00'
duration: 8.0
- email_from: info@balmerinc.be
- location: Ahmedabad
- name: Regarding Presentation
+ email_from: info@mycompany.com
+ location: B-1367 Grand-Rosière
+ name: Technical Presentation
partner_address_id: base.res_partner_address_1
- partner_id: base.res_partner_9
+ partner_id: base.main_partner
rrule_type: weekly
section_id: crm.section_sales_department
- |
@@ -77,11 +77,9 @@
I can invite internal user.
-
!record {model: base_calendar.invite.attendee, id: base_calendar_invite_attendee_0}:
- type: internal
partner_id: base.res_partner_9
- user_ids:
- - base.user_demo
-- |
+ type: email
+ email: noemail@openerp.com- |
If I set Send mail boolean as True I can see that an email is send to
specified email address with proper meeting information.
-
diff --git a/addons/crm/wizard/crm_send_email.py b/addons/crm/wizard/crm_send_email.py
index 8bc63f2f1a1..8d394ddcf9e 100644
--- a/addons/crm/wizard/crm_send_email.py
+++ b/addons/crm/wizard/crm_send_email.py
@@ -20,11 +20,12 @@
#
##############################################################################
+from crm import crm
from osv import osv, fields
from tools.translate import _
import base64
+import time
import tools
-from crm import crm
class crm_send_new_email(osv.osv_memory):
""" Sends new email for the case"""
@@ -93,10 +94,12 @@ class crm_send_new_email(osv.osv_memory):
if context.get('mail', 'new') == 'new':
if len(case.message_ids):
message_id = case.message_ids[0].message_id
+ else:
+ message_id = "<%s-openerp-@%s-%s-%d>" % (time.time(), cr.dbname, model, res_id)
else:
hist = hist_obj.browse(cr, uid, res_id)
message_id = hist.message_id
- model = hist.model_id.model
+ model = hist.model
model_pool = self.pool.get(model)
res_ids = model_pool.search(cr, uid, [('thread_id','=', hist.thread_id.id)])
res_id = res_ids and res_ids[0] or False
@@ -196,7 +199,7 @@ class crm_send_new_email(osv.osv_memory):
include_original = context and context.get('include_original', False) or False
res = {}
for hist in hist_obj.browse(cr, uid, res_ids, context=context):
- model = hist.model_id.model
+ model = hist.model
# In the case where the crm.case does not exist in the database
if not model:
@@ -225,7 +228,7 @@ class crm_send_new_email(osv.osv_memory):
original = [header, sender, to, sentdate, desc, signature]
- res['text']= '\n'.join(original)
+ res['text']= '\n\n\n' + '\n'.join(original)
if 'subject' in fields:
res.update({'subject': '[%s] %s' %(str(case.id), case.name or '')})
diff --git a/addons/document/document_view.xml b/addons/document/document_view.xml
index a8999d69138..1dc0cd5a561 100644
--- a/addons/document/document_view.xml
+++ b/addons/document/document_view.xml
@@ -193,10 +193,7 @@
-
-
-
@@ -219,7 +216,9 @@
-
+
+
+
diff --git a/addons/document/std_index.py b/addons/document/std_index.py
index 2f2f2094bc3..2facb14eeb3 100644
--- a/addons/document/std_index.py
+++ b/addons/document/std_index.py
@@ -19,10 +19,11 @@
#
##############################################################################
+from content_index import indexer, cntIndex
+from subprocess import Popen, PIPE
import StringIO
import odt2txt
-from subprocess import Popen, PIPE
-from content_index import indexer, cntIndex
+import sys, zipfile, xml.dom.minidom
def _to_unicode(s):
try:
@@ -36,6 +37,15 @@ def _to_unicode(s):
except UnicodeError:
return s
+def textToString(element) :
+ buffer = u""
+ for node in element.childNodes :
+ if node.nodeType == xml.dom.Node.TEXT_NODE :
+ buffer += node.nodeValue
+ elif node.nodeType == xml.dom.Node.ELEMENT_NODE :
+ buffer += textToString(node)
+ return buffer
+
class TxtIndex(indexer):
def _getMimeTypes(self):
return ['text/plain','text/html','text/diff','text/xml', 'text/*',
@@ -57,14 +67,23 @@ class PptxIndex(indexer):
return ['.pptx']
def _doIndexFile(self,fname):
- # pptx2txt.pl package not support in windows platform.
- # Download pptx2txt package from http://sourceforge.net/projects/pptx2txt/" link.
- # To install this tool, just copy pptx2txt.pl to appropriate place (e.g. /usr/bin directory)
- fp = Popen(['pptx2txt.pl', fname], shell=False, stdout=PIPE).stdout
- fp.read()
- file_obj = open(str(fname + ".txt"), "r")
- data = file_obj.read()
- return _to_unicode(data)
+ def toString () :
+ """ Converts the document to a string. """
+ buffer = u""
+ for val in ["a:t"]:
+ for paragraph in content.getElementsByTagName(val) :
+ buffer += textToString(paragraph) + "\n"
+ return buffer
+
+ data = []
+ zip = zipfile.ZipFile(fname)
+ files = filter(lambda x: x.startswith('ppt/slides/slide'), zip.namelist())
+ for i in range(1, len(files) + 1):
+ content = xml.dom.minidom.parseString(zip.read('ppt/slides/slide%s.xml' % str(i)))
+ res = toString().encode('ascii','replace')
+ data.append(res)
+
+ return _to_unicode('\n'.join(data))
cntIndex.register(PptxIndex())
@@ -76,33 +95,60 @@ class DocIndex(indexer):
return ['.doc']
def _doIndexFile(self,fname):
- fp = Popen(['antiword', fname], shell=False, stdout=PIPE).stdout
- return _to_unicode( fp.read())
+ #fp = Popen(['antiword', fname], shell=False, stdout=PIPE).stdout
+ return _to_unicode( 'None')
cntIndex.register(DocIndex())
class DocxIndex(indexer):
def _getMimeTypes(self):
return [ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document']
-
+
def _getExtensions(self):
return ['.docx']
def _doIndexFile(self,fname):
- # docx2txt.pl package not support in windows platform.
- # Download docx2txt package from "http://sourceforge.net/projects/docx2txt/" link.
- # In case, you don't want to use Makefile for installation, you can follow these steps for manual installation.
- # Copy docx2txt.pl, docx2txt.sh and docx2txt.config to appropriate place (e.g. /usr/bin directory) . used following command.
- # --> cp docx2txt.pl docx2txt.sh docx2txt.config /usr/bin/
+ zip = zipfile.ZipFile(fname)
+ content = xml.dom.minidom.parseString(zip.read("word/document.xml"))
+ def toString () :
+ """ Converts the document to a string. """
+ buffer = u""
+ for val in ["w:p", "w:h", "text:list"]:
+ for paragraph in content.getElementsByTagName(val) :
+ buffer += textToString(paragraph) + "\n"
+ return buffer
- fp = Popen(['docx2txt.pl', fname], shell=False, stdout=PIPE).stdout
- fp.read()
- file_obj = open(str(fname + ".txt"), "r")
- data = file_obj.read()
- return _to_unicode(data)
+ res = toString().encode('ascii','replace')
+
+ return _to_unicode(res)
cntIndex.register(DocxIndex())
+
+class XlsxIndex(indexer):
+ def _getMimeTypes(self):
+ return [ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
+
+ def _getExtensions(self):
+ return ['.xlsx']
+
+ def _doIndexFile(self,fname):
+ zip = zipfile.ZipFile(fname)
+ content = xml.dom.minidom.parseString(zip.read("xl/sharedStrings.xml"))
+ def toString () :
+ """ Converts the document to a string. """
+ buffer = u""
+ for val in ["t"]:
+ for paragraph in content.getElementsByTagName(val) :
+ buffer += textToString(paragraph) + "\n"
+ return buffer
+
+ res = toString().encode('ascii','replace')
+
+ return _to_unicode(res)
+
+cntIndex.register(XlsxIndex())
+
class PdfIndex(indexer):
def _getMimeTypes(self):
return [ 'application/pdf']
diff --git a/addons/document_webdav/webdav.py b/addons/document_webdav/webdav.py
index b69c21d62ee..b9b1a1f8a65 100644
--- a/addons/document_webdav/webdav.py
+++ b/addons/document_webdav/webdav.py
@@ -23,8 +23,12 @@ import xml.dom.minidom
domimpl = xml.dom.minidom.getDOMImplementation()
import urlparse
import urllib
-from DAV import utils
-from DAV.propfind import PROPFIND
+try:
+ from DAV import utils
+ from DAV.propfind import PROPFIND
+except ImportError:
+ raise osv.except_osv('PyWebDAV Import Error!','Please install pywebdav \
+ from http://pywebdav.googlecode.com/files/PyWebDAV-0.9.3.tar.gz/')
import tools
diff --git a/addons/hr_timesheet/wizard/hr_timesheet_sign_in_out.py b/addons/hr_timesheet/wizard/hr_timesheet_sign_in_out.py
index fa57cfdd1a5..dc1a6723786 100644
--- a/addons/hr_timesheet/wizard/hr_timesheet_sign_in_out.py
+++ b/addons/hr_timesheet/wizard/hr_timesheet_sign_in_out.py
@@ -115,31 +115,19 @@ class hr_si_project(osv.osv_memory):
# get the latest action (sign_in or out) for this employee
cr.execute('select action from hr_attendance where employee_id=%s and action in (\'sign_in\',\'sign_out\') order by name desc limit 1', (emp_id,))
res = (cr.fetchone() or ('sign_out',))[0]
+ in_out = res == 'sign_out' and 'out' or 'in'
#TODO: invert sign_in et sign_out
- if res == 'sign_out':
- model_data_ids = obj_model.search(cr,uid,[('model','=','ir.ui.view'),('name','=','view_hr_timesheet_sign_in')])
- resource_id = obj_model.read(cr,uid,model_data_ids,fields=['res_id'])[0]['res_id']
- return {
- 'name': 'Sign in / Sign out',
- 'view_type': 'form',
- 'view_mode': 'tree,form',
- 'res_model': 'hr.sign.in.project',
- 'views': [(False,'tree'), (resource_id,'form')],
- 'type': 'ir.actions.act_window',
- 'target': 'new'
- }
- else:
- model_data_ids = obj_model.search(cr,uid,[('model','=','ir.ui.view'),('name','=','view_hr_timesheet_sign_out')])
- resource_id = obj_model.read(cr,uid,model_data_ids,fields=['res_id'])[0]['res_id']
- return {
- 'name': 'Sign in / Sign out',
- 'view_type': 'form',
- 'view_mode': 'tree,form',
- 'res_model': 'hr.sign.out.project',
- 'views': [(False,'tree'), (resource_id,'form')],
- 'type': 'ir.actions.act_window',
- 'target': 'new'
- }
+ model_data_ids = obj_model.search(cr,uid,[('model','=','ir.ui.view'),('name','=','view_hr_timesheet_sign_%s' % in_out)])
+ resource_id = obj_model.read(cr,uid,model_data_ids,fields=['res_id'])[0]['res_id']
+ return {
+ 'name': 'Sign in / Sign out',
+ 'view_type': 'form',
+ 'view_mode': 'tree,form',
+ 'res_model': 'hr.sign.%s.project' % in_out,
+ 'views': [(False,'tree'), (resource_id,'form')],
+ 'type': 'ir.actions.act_window',
+ 'target': 'new'
+ }
def _get_empid(self, cr, uid, context=None):
emp_obj = self.pool.get('hr.employee')
@@ -153,10 +141,7 @@ class hr_si_project(osv.osv_memory):
emp_obj = self.pool.get('hr.employee')
data = self.read(cr, uid, ids, [], context)[0]
emp_id = data['emp_id']
- try:
- success = emp_obj.attendance_action_change(cr, uid, [emp_id], type = 'sign_in' ,dt=data['date'] or False)
- except except_osv, e:
- raise osv.except_osv(e.name, e.value)
+ success = emp_obj.attendance_action_change(cr, uid, [emp_id], type = 'sign_in' ,dt=data['date'] or False)
return {}
def default_get(self, cr, uid, fields_list, context=None):
@@ -166,4 +151,4 @@ class hr_si_project(osv.osv_memory):
hr_si_project()
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
\ No newline at end of file
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/mail_gateway/mail_gateway.py b/addons/mail_gateway/mail_gateway.py
index fb4920e9632..5a4ab95c935 100644
--- a/addons/mail_gateway/mail_gateway.py
+++ b/addons/mail_gateway/mail_gateway.py
@@ -50,9 +50,11 @@ class mailgate_thread(osv.osv):
_rec_name = 'thread'
_columns = {
- 'thread': fields.char('Thread', size=32, required=False),
+ 'thread': fields.char('Thread', size=124, required=False),
'message_ids': one2many_domain('mailgate.message', 'thread_id', 'Messages', domain=[('history', '=', True)], required=False),
- 'log_ids': one2many_domain('mailgate.message', 'thread_id', 'Logs', domain=[('history', '=', False)], required=False),
+ 'log_ids': one2many_domain('mailgate.message', 'thread_id', 'Logs', domain=[('history', '=', False)], required=False),
+ 'model': fields.char('Model Name', size=64, required=False),
+ 'res_id': fields.integer('Resource ID'),
}
def __history(self, cr, uid, cases, keyword, history=False, subject=None, email=False, details=None, email_from=False, message_id=False, attach=[], context={}):
@@ -78,11 +80,11 @@ class mailgate_thread(osv.osv):
obj = self.pool.get('mailgate.message')
for case in cases:
- model_ids = model_obj.search(cr, uid, [('model', '=', case._name)])
data = {
'name': keyword,
'user_id': uid,
- 'model_id' : model_ids and model_ids[0] or False,
+ 'model' : case._name,
+ 'res_id': case.id,
'date': time.strftime('%Y-%m-%d %H:%M:%S'),
'thread_id': case.thread_id.id,
'message_id': message_id,
@@ -96,7 +98,7 @@ class mailgate_thread(osv.osv):
'name': subject or 'History',
'history': True,
'user_id': uid,
- 'model_id' : model_ids and model_ids[0] or False,
+ 'model' : case._name,
'res_id': case.id,
'date': time.strftime('%Y-%m-%d %H:%M:%S'),
'description': details or (hasattr(case, 'description') and case.description or False),
@@ -130,8 +132,6 @@ class mailgate_message(osv.osv):
_columns = {
'name':fields.char('Message', size=64),
- 'model_id': fields.many2one('ir.model', 'Model'),
- 'res_id': fields.integer('Resource ID'),
'thread_id':fields.many2one('mailgate.thread', 'Thread'),
'date': fields.datetime('Date'),
'history': fields.boolean('Is History?', required=False),
@@ -144,7 +144,9 @@ class mailgate_message(osv.osv):
'message_id': fields.char('Message Id', size=1024, readonly=True, help="Message Id on Email Server.", select=True),
'description': fields.text('Description'),
'partner_id': fields.many2one('res.partner', 'Partner', required=False),
- 'attachment_ids': fields.many2many('ir.attachment', 'message_attachment_rel', 'message_id', 'attachment_id', 'Attachments'),
+ 'attachment_ids': fields.many2many('ir.attachment', 'message_attachment_rel', 'message_id', 'attachment_id', 'Attachments'),
+ 'model': fields.char('Model Name', size=64, required=False),
+ 'res_id': fields.integer('Resource ID'),
}
mailgate_message()
diff --git a/addons/mail_gateway/mail_gateway_view.xml b/addons/mail_gateway/mail_gateway_view.xml
index 611416055f7..436492460eb 100644
--- a/addons/mail_gateway/mail_gateway_view.xml
+++ b/addons/mail_gateway/mail_gateway_view.xml
@@ -8,21 +8,27 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -41,8 +47,9 @@
-
-
+
+
+
@@ -68,28 +75,30 @@
form
-
\ No newline at end of file
+
diff --git a/addons/mail_gateway/scripts/openerp_mailgate/openerp_mailgate.py b/addons/mail_gateway/scripts/openerp_mailgate/openerp_mailgate.py
index a865443c1b9..4a18d8cb251 100755
--- a/addons/mail_gateway/scripts/openerp_mailgate/openerp_mailgate.py
+++ b/addons/mail_gateway/scripts/openerp_mailgate/openerp_mailgate.py
@@ -130,7 +130,7 @@ class rpc_proxy(object):
return self.rpc.execute(self.dbname, self.user_id, self.passwd, *request, **kwargs)
class email_parser(object):
- def __init__(self, uid, password, model, email, email_default, dbname, host, port):
+ def __init__(self, uid, password, model, email, email_default, dbname, host, port, smtp_server=None, smtp_port=None, smtp_ssl=None, smtp_user=None, smtp_password=None):
self.rpc = rpc_proxy(uid, password, host=host, port=port, dbname=dbname)
try:
self.model_id = int(model)
@@ -141,7 +141,13 @@ class email_parser(object):
self.email = email
self.email_default = email_default
self.canal_id = False
-
+ self.smtp_server = smtp_server
+ self.smtp_port = smtp_port
+ self.smtp_ssl = smtp_ssl
+ self.smtp_user = smtp_user
+ self.smtp_password = smtp_password
+
+
def email_get(self, email_from):
res = email_re.search(email_from)
return res and res.group(1)
@@ -170,7 +176,24 @@ class email_parser(object):
from email.Header import decode_header
s = decode_header(s.replace('\r', ''))
return ''.join(map(lambda x:self._to_decode(x[0], [x[1]]), s or []))
-
+
+ def history(self, model, new_id, msg_id, subject, msg_to, msg_from, body, attach):
+ msg_data = {
+ 'name': subject,
+ 'history': True,
+ 'model': model,
+ 'res_id': new_id,
+ 'message_id': msg_id,
+ 'user_id': self.rpc.user_id,
+ 'date': time.strftime('%Y-%m-%d %H:%M:%S'),
+ 'email_from': msg_from,
+ 'email_to': msg_to,
+ 'description': body,
+ 'attachment_ids': [(6, 0, attach)]
+ }
+ msg_id = self.rpc('mailgate.message', 'create', msg_data)
+ return True
+
def msg_new(self, msg):
message = self.msg_body_get(msg)
msg_subject = self._decode_header(msg['Subject'])
@@ -189,26 +212,30 @@ class email_parser(object):
data.update(self.partner_get(msg_from))
try:
- id = self.rpc(self.model, 'create', data)
- self.rpc(self.model, 'history', [id], 'Receive', True, msg_to, message['body'], msg_from, False, {'model' : self.model})
- #self.rpc(self.model, 'case_open', [id])
+ att_ids = []
+ new_id = self.rpc(self.model, 'create', data)
+ attachments = message['attachment']
+ for attach in attachments or []:
+ data_attach = {
+ 'name': str(attach),
+ 'datas': binascii.b2a_base64(str(attachments[attach])),
+ 'datas_fname': str(attach),
+ 'description': 'Mail attachment',
+ 'res_model': self.model,
+ 'res_id': new_id
+ }
+ att_ids.append(self.rpc('ir.attachment', 'create', data_attach))
+ try:
+ self.rpc(self.model, 'history', [new_id], 'Receive', True, msg_to, message['body'], msg_from, False, {'model' : self.model})
+ except Exception, e:
+ self.history(self.model, new_id, msg['Message-Id'], msg_subject, msg_to, msg_from, message['body'], att_ids)
except Exception, e:
if getattr(e, 'faultCode', '') and 'AccessError' in e.faultCode:
- e = '\n\nThe Specified user does not have an access to the CRM case.'
+ e = '\n\nThe Specified user does not have an access to the Model.'
print e
- attachments = message['attachment']
- for attach in attachments or []:
- data_attach = {
- 'name': str(attach),
- 'datas': binascii.b2a_base64(str(attachments[attach])),
- 'datas_fname': str(attach),
- 'description': 'Mail attachment',
- 'res_model': self.model,
- 'res_id': id
- }
- self.rpc('ir.attachment', 'create', data_attach)
+
- return id
+ return new_id
# #change the return type format to dictionary
# {
@@ -262,63 +289,6 @@ class email_parser(object):
#end for
return message
- def msg_user(self, msg, id):
- body = self.msg_body_get(msg)
-
- # handle email body commands (ex: Set-State: Draft)
- actions = {}
- body_data=''
- for line in body['body'].split('\n'):
- res = command_re.match(line)
- if res:
- actions[res.group(1).lower()] = res.group(2).lower()
- else:
- body_data += line+'\n'
- body['body'] = body_data
-
- data = {
-# 'description': body['body'],
- }
- act = 'case_open'
- if 'state' in actions:
- if actions['state'] in ['draft', 'close', 'cancel', 'open', 'pending']:
- act = 'case_' + actions['state']
-
- for k1, k2 in [('cost', 'planned_cost'), ('revenue', 'planned_revenue'), ('probability', 'probability')]:
- try:
- data[k2] = float(actions[k1])
- except:
- pass
-
- if 'priority' in actions:
- if actions['priority'] in ('1', '2', '3', '4', '5'):
- data['priority'] = actions['priority']
-
- if 'partner' in actions:
- data['email_from'] = actions['partner'][:128]
-
- if 'user' in actions:
- uids = self.rpc('res.users', 'name_search', actions['user'])
- if uids:
- data['user_id'] = uids[0][0]
-
- self.rpc(self.model, act, [id])
- self.rpc(self.model, 'write', [id], data)
- attachments = body['attachment']
- for attach in attachments or []:
- data_attach = {
- 'name': str(attach),
- 'datas': binascii.b2a_base64(str(attachments[attach])),
- 'datas_fname': str(attach),
- 'description': 'Mail attachment',
- 'res_model': self.model,
- 'res_id': id
- }
- self.rpc('ir.attachment', 'create', data_attach)
-
- self.rpc(self.model, 'history', [id], 'Send', True, self._decode_header(msg['To']), body['body'], self._decode_header(msg['From']), False, {'model' : self.model})
- return id
-
def msg_send(self, msg, emails, priority=None):
if not len(emails):
return False
@@ -330,85 +300,38 @@ class email_parser(object):
msg['Cc'] = ','.join(emails[1:])
del msg['Reply-To']
msg['Reply-To'] = self.email
- if priority:
- msg['X-Priority'] = priorities.get(priority, '3 (Normal)')
- s = smtplib.SMTP()
- s.connect()
- s.sendmail(self.email, emails, msg.as_string())
+ s = smtplib.SMTP(self.smtp_server, self.smtp_port)
+ s.ehlo()
+ s.starttls()
+ s.ehlo()
+
+ if self.smtp_user and self.smtp_password:
+ s.login(self.smtp_user, self.smtp_password)
+ s.sendmail(self.email, emails, msg.as_string())
s.close()
return True
- def msg_partner(self, msg, id):
- message = self.msg_body_get(msg)
- body = message['body']
- act = 'case_open'
- self.rpc(self.model, act, [id])
- #body2 = '\n'.join(map(lambda l: '> '+l, (body or '').split('\n')))
- #data = {
- # 'description':body,
- #}
- #self.rpc(self.model, 'write', [id], data)
- attachments = message['attachment']
- for attach in attachments or []:
- data_attach = {
- 'name': str(attach),
- 'datas': binascii.b2a_base64(str(attachments[attach])),
- 'datas_fname': str(attach),
- 'description': 'Mail attachment',
- 'res_model': self.model,
- 'res_id': id
- }
- self.rpc('ir.attachment', 'create', data_attach)
-
- self.rpc(self.model, 'history', [id], 'Send', True, self._decode_header(msg['To']), message['body'], self._decode_header(msg['From']), False, {'model' : self.model})
- return id
-
- def msg_test(self, msg, case_str):
- if not case_str:
- return (False, False)
- emails = self.rpc(self.model, 'emails_get', int(case_str))
- return (int(case_str), emails)
def parse(self, msg):
- case_str = reference_re.search(msg.get('References', ''))
- if case_str:
- case_str = case_str.group(1)
- else:
- case_str = case_re.search(msg.get('Subject', ''))
- if case_str:
- case_str = case_str.group(1)
- (case_id, emails) = self.msg_test(msg, case_str)
- if case_id:
- if emails[0] and self.email_get(emails[0])==self.email_get(self._decode_header(msg['From'])):
- self.msg_user(msg, case_id)
- else:
- self.msg_partner(msg, case_id)
- else:
- case_id = self.msg_new(msg)
- subject = self._decode_header(msg['subject'])
- if msg.get('Subject', ''):
- del msg['Subject']
- msg['Subject'] = '['+str(case_id)+'] '+subject
- msg['Message-Id'] = '<'+str(time.time())+'-openerpcrm-'+str(case_id)+'@'+socket.gethostname()+'>'
-
- emails = self.rpc(self.model, 'emails_get', case_id)
- priority = emails[3]
- em = [emails[0], emails[1]] + (emails[2] or '').split(',')
- emails = map(self.email_get, filter(None, em))
+ #TODO: Something with Message hierarchy
+ res_id = self.msg_new(msg)
+ subject = self._decode_header(msg['subject'])
+ if msg.get('Subject', ''):
+ del msg['Subject']
+ msg['Subject'] = '['+str(res_id)+'] '+subject
+ msg['Message-Id'] = '<'+str(time.time())+'-openerpcrm-'+str(res_id)+'@'+socket.gethostname()+'>'
mm = [self._decode_header(msg['From']), self._decode_header(msg['To'])]+self._decode_header(msg.get('Cc', '')).split(',')
msg_mails = map(self.email_get, filter(None, mm))
-
- emails = filter(lambda m: m and m not in msg_mails, emails)
try:
- self.msg_send(msg, emails, priority)
- except:
+ self.msg_send(msg, msg_mails)
+ except Exception, e:
if self.email_default:
a = self._decode_header(msg['Subject'])
del msg['Subject']
- msg['Subject'] = '[OpenERP-CaseError] ' + a
+ msg['Subject'] = '[OpenERP-FetchError] ' + a
self.msg_send(msg, self.email_default.split(','))
- return case_id, emails
+ return res_id, msg_mails
if __name__ == '__main__':
import sys, optparse
@@ -425,10 +348,14 @@ if __name__ == '__main__':
parser.add_option("-d", "--dbname", dest="dbname", help="Database name (default: terp)", default='terp')
parser.add_option("--host", dest="host", help="Hostname of the Open ERP Server", default="localhost")
parser.add_option("--port", dest="port", help="Port of the Open ERP Server", default="8069")
-
+ parser.add_option('--smtp', dest='smtp_server', default='', help='specify the SMTP server for sending email')
+ parser.add_option('--smtp-port', dest='smtp_port', default='25', help='specify the SMTP port', type="int")
+ parser.add_option('--smtp-ssl', dest='smtp_ssl', default='', help='specify the SMTP server support SSL or not')
+ parser.add_option('--smtp-user', dest='smtp_user', default='', help='specify the SMTP username for sending email')
+ parser.add_option('--smtp-password', dest='smtp_password', default='', help='specify the SMTP password for sending email')
(options, args) = parser.parse_args()
- parser = email_parser(options.userid, options.password, options.model, options.email, options.default, dbname=options.dbname, host=options.host, port=options.port)
+ parser = email_parser(options.userid, options.password, options.model, options.email, options.default, dbname=options.dbname, host=options.host, port=options.port, smtp_server=options.smtp_server, smtp_port=options.smtp_port, smtp_ssl=options.smtp_ssl, smtp_user=options.smtp_user, smtp_password=options.smtp_password)
msg_txt = email.message_from_file(sys.stdin)
diff --git a/addons/mrp/report/mrp_production_order_view.xml b/addons/mrp/report/mrp_production_order_view.xml
index 99fd967b91d..55957619e31 100644
--- a/addons/mrp/report/mrp_production_order_view.xml
+++ b/addons/mrp/report/mrp_production_order_view.xml
@@ -47,14 +47,14 @@
-
-
-
-
+
diff --git a/addons/project/report/project_report_view.xml b/addons/project/report/project_report_view.xml
index a94ffac39d9..26488eae254 100644
--- a/addons/project/report/project_report_view.xml
+++ b/addons/project/report/project_report_view.xml
@@ -58,7 +58,7 @@
-
-
+
diff --git a/addons/project_issue/project_issue_view.xml b/addons/project_issue/project_issue_view.xml
index 9631e3151f6..dd3ed036691 100644
--- a/addons/project_issue/project_issue_view.xml
+++ b/addons/project_issue/project_issue_view.xml
@@ -213,7 +213,7 @@
-
+
-
+
diff --git a/addons/purchase/purchase_view.xml b/addons/purchase/purchase_view.xml
index 72d4feb0ae9..10c5ccd9749 100644
--- a/addons/purchase/purchase_view.xml
+++ b/addons/purchase/purchase_view.xml
@@ -169,7 +169,7 @@
-
+
diff --git a/addons/purchase/report/purchase_report_view.xml b/addons/purchase/report/purchase_report_view.xml
index 5dd8dd31900..8fb7836468d 100644
--- a/addons/purchase/report/purchase_report_view.xml
+++ b/addons/purchase/report/purchase_report_view.xml
@@ -1,7 +1,7 @@
-
+
product.month.graph
purchase.report
graph
@@ -88,7 +88,7 @@
-
+
diff --git a/addons/resource/resource_view.xml b/addons/resource/resource_view.xml
index 275c111225f..df0974fd9ed 100644
--- a/addons/resource/resource_view.xml
+++ b/addons/resource/resource_view.xml
@@ -55,7 +55,7 @@
-
+
diff --git a/addons/stock/report/report_stock_move_view.xml b/addons/stock/report/report_stock_move_view.xml
index 673fd14e76e..a3771b4a480 100755
--- a/addons/stock/report/report_stock_move_view.xml
+++ b/addons/stock/report/report_stock_move_view.xml
@@ -44,16 +44,16 @@
-
-
-
-
-
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
diff --git a/addons/stock/report/report_stock_picking_view.xml b/addons/stock/report/report_stock_picking_view.xml
index e570e2b55ea..a14298ff771 100644
--- a/addons/stock/report/report_stock_picking_view.xml
+++ b/addons/stock/report/report_stock_picking_view.xml
@@ -54,38 +54,38 @@
-
-
-
-
-
+
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
diff --git a/addons/stock/report/report_stock_view.xml b/addons/stock/report/report_stock_view.xml
index 27f18d4ff43..34121d0c9ed 100644
--- a/addons/stock/report/report_stock_view.xml
+++ b/addons/stock/report/report_stock_view.xml
@@ -9,17 +9,17 @@
-
-
-
+
+
+
-
-
+
+
@@ -155,12 +155,12 @@
search
-
-
-
diff --git a/addons/stock/stock_view.xml b/addons/stock/stock_view.xml
index 92653501ed3..d821ab39d51 100644
--- a/addons/stock/stock_view.xml
+++ b/addons/stock/stock_view.xml
@@ -55,9 +55,9 @@
-
-
-
+
+
+
@@ -271,7 +271,7 @@
-
+
@@ -280,8 +280,8 @@
-
-
+
+
@@ -438,11 +438,11 @@
search
-
-
-
@@ -712,10 +712,10 @@
-
-
+
+
-
+
@@ -723,10 +723,10 @@
-
-
-
-
+
+
+
+
@@ -859,20 +859,20 @@
-
-
+
+
-
+
-
-
-
-
+
+
+
+
@@ -1041,8 +1041,8 @@
-
-
+
+
@@ -1051,11 +1051,11 @@
-
-
-
-
-
+
+
+
+
+
@@ -1216,9 +1216,9 @@
-
+
-
+
@@ -1226,13 +1226,13 @@
-
-
+
+
-
+
-
-
+
+
@@ -1275,20 +1275,20 @@
-
-
+
+
-
-
-
-
-
-
+
+
+
+
+
+
@@ -1397,9 +1397,9 @@
-
+
-
+
@@ -1407,18 +1407,18 @@
-
-
-
-
+
+
+
+
-
-
+
+
-
+
-
-
+
+
@@ -1451,7 +1451,7 @@
-
+
@@ -1526,9 +1526,9 @@
-
-
-
+
+
+
@@ -1539,12 +1539,12 @@
-
-
-
+
+
+
-
-
+
+
diff --git a/addons/stock_planning/stock_planning_view.xml b/addons/stock_planning/stock_planning_view.xml
index dfca96b0163..1bfb1d0f1aa 100644
--- a/addons/stock_planning/stock_planning_view.xml
+++ b/addons/stock_planning/stock_planning_view.xml
@@ -239,7 +239,7 @@
-
+
diff --git a/addons/survey/survey_view.xml b/addons/survey/survey_view.xml
index f838739d0da..a604b7c7c37 100644
--- a/addons/survey/survey_view.xml
+++ b/addons/survey/survey_view.xml
@@ -255,8 +255,8 @@
-
-
+
+
@@ -1065,13 +1065,13 @@
-
-
+
+
-
+