diff --git a/addons/analytic/analytic.py b/addons/analytic/analytic.py
index ee458ca0076..39ffeb70eed 100644
--- a/addons/analytic/analytic.py
+++ b/addons/analytic/analytic.py
@@ -205,7 +205,7 @@ class account_analytic_account(osv.osv):
def check_recursion(self, cr, uid, ids, parent=None):
return super(account_analytic_account, self)._check_recursion(cr, uid, ids, parent=parent)
- _order = 'date_start desc,parent_id desc,code'
+ _order = 'name asc'
_constraints = [
(check_recursion, 'Error! You can not create recursive analytic accounts.', ['parent_id']),
]
diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py
index f7b70ca9921..fb3a8f5e223 100644
--- a/addons/crm/crm_lead.py
+++ b/addons/crm/crm_lead.py
@@ -98,6 +98,27 @@ class crm_lead(crm_case, osv.osv):
res[lead.id][field] = abs(int(duration))
return res
+ def _history_search(self, cr, uid, obj, name, args, context=None):
+ res = []
+ msg_obj = self.pool.get('mailgate.message')
+ message_ids = msg_obj.search(cr, uid, [('history','=',True), ('name', args[0][1], args[0][2])], context=context)
+ lead_ids = self.search(cr, uid, [('message_ids', 'in', message_ids)], context=context)
+
+ if lead_ids:
+ return [('id', 'in', lead_ids)]
+ else:
+ return [('id', '=', '0')]
+
+ def _get_email_subject(self, cr, uid, ids, fields, args, context=None):
+ res = {}
+ for obj in self.browse(cr, uid, ids, context=context):
+ res[obj.id] = ''
+ for msg in obj.message_ids:
+ if msg.history:
+ res[obj.id] = msg.name
+ break
+ return res
+
_columns = {
# Overridden from res.partner.address:
'partner_id': fields.many2one('res.partner', 'Partner', ondelete='set null',
@@ -149,6 +170,7 @@ class crm_lead(crm_case, osv.osv):
\nWhen the case is over, the state is set to \'Done\'.\
\nIf the case needs to be reviewed then the state is set to \'Pending\'.'),
'message_ids': fields.one2many('mailgate.message', 'res_id', 'Messages', domain=[('model','=',_name)]),
+ 'subjects': fields.function(_get_email_subject, fnct_search=_history_search, string='Subject of Email', method=True, type='char', size=64),
}
@@ -289,17 +311,6 @@ class crm_lead(crm_case, osv.osv):
self.log(cr, uid, case.id, message)
return super(crm_lead,self).write(cr, uid, ids, vals, context)
- def stage_historize(self, cr, uid, ids, stage, context=None):
- stage_obj = self.pool.get('crm.case.stage').browse(cr, uid, stage, context=context)
- self.history(cr, uid, ids, _('Stage'), details=stage_obj.name)
- for case in self.browse(cr, uid, ids, context=context):
- if case.type == 'lead':
- message = _("The stage of lead '%s' has been changed to '%s'.") % (case.name, stage_obj.name)
- elif case.type == 'opportunity':
- message = _("The stage of opportunity '%s' has been changed to '%s'.") % (case.name, stage_obj.name)
- self.log(cr, uid, case.id, message)
- return True
-
def stage_next(self, cr, uid, ids, context=None):
stage = super(crm_lead, self).stage_next(cr, uid, ids, context=context)
if stage:
diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml
index 2ea72155dbe..55be89c2252 100644
--- a/addons/crm/crm_lead_view.xml
+++ b/addons/crm/crm_lead_view.xml
@@ -183,7 +183,7 @@
-
+
-
+
+
+
-
-
+
+
@@ -230,6 +230,7 @@
+
+
diff --git a/addons/crm/wizard/crm_lead_to_opportunity.py b/addons/crm/wizard/crm_lead_to_opportunity.py
index ead591d39c6..33ec426d7d6 100644
--- a/addons/crm/wizard/crm_lead_to_opportunity.py
+++ b/addons/crm/wizard/crm_lead_to_opportunity.py
@@ -21,6 +21,8 @@
from osv import osv, fields
from tools.translate import _
+import tools
+import re
import time
@@ -46,21 +48,35 @@ class crm_lead2opportunity_partner(osv.osv_memory):
"""
lead_obj = self.pool.get('crm.lead')
-
res = super(crm_lead2opportunity_partner, self).default_get(cr, uid, fields, context=context)
opportunities = res.get('opportunity_ids') or []
-
partner_id = False
+ email = False
for lead in lead_obj.browse(cr, uid, opportunities, context=context):
partner_id = lead.partner_id and lead.partner_id.id or False
+ email = re.findall(r'([^ ,<@]+@[^> ,]+)', lead.email_from or '')
+ email = map(lambda x: "'" + x + "'", email)
if not partner_id and res.get('partner_id'):
partner_id = res.get('partner_id')
ids = []
if partner_id:
- ids = lead_obj.search(cr, uid, [('partner_id', '=', partner_id), ('type', '=', 'opportunity')])
- opportunities += ids
+ ids = lead_obj.search(cr, uid, [('partner_id', '=', partner_id), ('type', '=', 'opportunity'), '!', ('state', 'in', ['done', 'cancel'])])
+ if ids:
+ opportunities.append(ids[0])
+
+
+ if not partner_id:
+ label = False
+ opp_ids = []
+ if email:
+ # Find email of existing opportunity matches the email_from of the lead
+ cr.execute("""select id from crm_lead where type='opportunity' and
+ substring(email_from from '([^ ,<@]+@[^> ,]+)') in (%s)""" % (','.join(email)))
+ ids = map(lambda x:x[0], cr.fetchall())
+ if ids:
+ opportunities.append(ids[0])
if 'action' in fields:
res.update({'action' : partner_id and 'exist' or 'create'})
@@ -82,7 +98,6 @@ class crm_lead2opportunity_partner(osv.osv_memory):
@param uid: the current user’s ID for security checks,
@param fields: List of fields for default value
@param context: A standard dictionary for contextual values
-
"""
if context is None:
context = {}
@@ -90,13 +105,14 @@ class crm_lead2opportunity_partner(osv.osv_memory):
for lead in lead_obj.browse(cr, uid, context.get('active_ids', []), context=context):
if lead.state in ['done', 'cancel']:
- raise osv.except_osv(_("Warning !"), _("Closed/Cancelled \
-Leads Could not convert into Opportunity"))
+ raise osv.except_osv(_("Warning !"), _("Closed/Cancelled Leads Could not convert into Opportunity"))
return False
def _convert(self, cr, uid, ids, lead, partner_id, stage_ids, context=None):
leads = self.pool.get('crm.lead')
- address_id = self.pool.get('res.partner.address').search(cr, uid,
+ address_id = False
+ if partner_id:
+ address_id = self.pool.get('res.partner.address').search(cr, uid,
[('partner_id', '=', partner_id)],
order='create_date desc',
limit=1)
@@ -110,8 +126,10 @@ Leads Could not convert into Opportunity"))
'stage_id': stage_ids and stage_ids[0] or False,
'date_action': time.strftime('%Y-%m-%d %H:%M:%S'),
}
- if address_id:
+ if partner_id and address_id:
vals['partner_address_id'] = address_id[0]
+ else:
+ vals['partner_address_id'] = False
lead.write(vals, context=context)
leads.history(cr, uid, [lead], _('Converted to opportunity'), details='Converted to Opportunity', context=context)
@@ -122,6 +140,18 @@ Leads Could not convert into Opportunity"))
}, context=context)
leads.log(cr, uid, lead.id, _("Lead '%s' has been converted to an opportunity.") % lead.name)
+ def send_mail_to_salesman(self, lead):
+ email_to = lead.user_id and lead.user_id.user_email
+ if not email_to:
+ return
+ email_from = lead.section_id and lead.section_id.user_id and lead.section_id.user_id.user_email or email_to
+ partner = lead.partner_id and lead.partner_id.name or lead.partner_name
+ subject = "lead %s converted into opportunity" % lead.name
+ body = "Info \n Id : %s \n Subject: %s \n Partner: %s \n Description : %s " % (lead.id, lead.name, lead.partner_id.name, lead.description)
+ try :
+ tools.email_send(email_from, [email_to], subject, body)
+ except:
+ pass
def action_apply(self, cr, uid, ids, context=None):
"""
@@ -130,6 +160,9 @@ Leads Could not convert into Opportunity"))
@return : View dictionary opening the Opportunity form view
"""
+ if not context:
+ context = {}
+
record_id = context and context.get('active_ids') or False
if not record_id:
return {'type': 'ir.actions.act_window_close'}
@@ -154,22 +187,30 @@ Leads Could not convert into Opportunity"))
cr, uid, opportunity_view_tree, context=context).res_id
for lead in leads.browse(cr, uid, record_id, context=context):
- if(lead.section_id):
+ if lead.section_id:
stage_ids = self.pool.get('crm.case.stage').search(cr, uid, [('type','=','opportunity'),('sequence','>=',1), ('section_ids','=', lead.section_id.id)])
else:
stage_ids = self.pool.get('crm.case.stage').search(cr, uid, [('type','=','opportunity'),('sequence','>=',1)])
data = self.browse(cr, uid, ids[0], context=context)
- partner_ids = []
- if data.action == 'create':
- partner_ids = self._create_partner(cr, uid, ids, context=context)
- partner_id = partner_ids and partner_ids[0] or data.partner_id.id
+
+ if data.action == 'create':
+ partner_ids = []
+ partner_ids = self._create_partner(cr, uid, ids, context=context)
+ partner_id = partner_ids and partner_ids[0]
+ elif data.action == 'exist':
+ partner_id = data.partner_id and data.partner_id.id
+ else:
+ partner_id = False
+
self._convert(cr, uid, ids, lead, partner_id, stage_ids, context=context)
- if data.name == 'merge':
+ self.send_mail_to_salesman(lead)
+ #If we convert in mass, don't merge if there is no other opportunity but no warning
+ if data.name == 'merge' and (len(data.opportunity_ids) > 1 or not context.get('mass_convert') ):
merge_obj = self.pool.get('crm.merge.opportunity')
self.write(cr, uid, ids, {'opportunity_ids' : [(6,0, [data.opportunity_ids[0].id])]}, context=context)
- context.update({'lead_ids' : record_id})
+ context.update({'lead_ids' : record_id, "convert" : True})
return merge_obj.merge(cr, uid, data.opportunity_ids, context=context)
return {
@@ -189,4 +230,66 @@ Leads Could not convert into Opportunity"))
crm_lead2opportunity_partner()
+class crm_lead2opportunity_mass_convert(osv.osv_memory):
+ _name = 'crm.lead2opportunity.partner.mass'
+ _description = 'Mass Lead To Opportunity Partner'
+ _inherit = 'crm.lead2opportunity.partner'
+
+
+ _columns = {
+ 'user_ids': fields.many2many('res.users', 'mass_convert_rel', 'user_id', 'wizard_id', 'Salesmans'),
+ 'section_id': fields.many2one('crm.case.section', 'Sales Team'),
+
+ }
+
+ def mass_convert(self, cr, uid, ids, context=None):
+ lead_obj = self.pool.get('crm.lead')
+ if not context:
+ context = {}
+
+ active_ids = context.get('active_ids')
+ data = self.browse(cr, uid, ids, context=context)[0]
+
+ salesteam = data.section_id and data.section_id.id
+ if data.user_ids:
+ salesmans = map(lambda x : x.id, data.user_ids)
+ index = 0
+ else:
+ salesmans = False
+
+ for lead_id in active_ids:
+ value = {}
+ if salesteam:
+ value['section_id'] = salesteam
+ if salesmans:
+ value['user_id'] = salesmans[index]
+ index += 1
+ index = index < len(salesmans) and index or 0
+ if value:
+ lead_obj.write(cr, uid, [lead_id], value, context=context)
+
+ context['active_ids'] = [lead_id]
+ value = self.default_get(cr, uid, ['partner_id', 'opportunity_ids'], context=context)
+ value['opportunity_ids'] = [(6, 0, value['opportunity_ids'])]
+ self.write(cr, uid, ids, value, context=context)
+
+ self.action_apply(cr, uid, ids, context=context)
+
+
+
+ models_data = self.pool.get('ir.model.data')
+ result = models_data._get_id(cr, uid, 'crm', 'view_crm_case_opportunities_filter')
+ opportunity_view_search = models_data.browse(cr, uid, result, context=context).res_id
+
+ return {
+ 'name': _('Opportunity'),
+ 'view_type': 'form',
+ 'view_mode': 'tree,form',
+ 'res_model': 'crm.lead',
+ 'domain': [('type', '=', 'opportunity'), ('id', 'in', active_ids)],
+ 'type': 'ir.actions.act_window',
+ 'search_view_id': opportunity_view_search,
+ }
+
+crm_lead2opportunity_mass_convert()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/crm/wizard/crm_lead_to_opportunity_view.xml b/addons/crm/wizard/crm_lead_to_opportunity_view.xml
index e86e14af218..833c04c3575 100644
--- a/addons/crm/wizard/crm_lead_to_opportunity_view.xml
+++ b/addons/crm/wizard/crm_lead_to_opportunity_view.xml
@@ -36,5 +36,42 @@
+
+ crm.lead2opportunity.partner.mass.form
+ crm.lead2opportunity.partner.mass
+ form
+
+
+
+
+
+
diff --git a/addons/crm/wizard/crm_lead_to_partner.py b/addons/crm/wizard/crm_lead_to_partner.py
index a6aabf1cc2f..ae9943cb6db 100644
--- a/addons/crm/wizard/crm_lead_to_partner.py
+++ b/addons/crm/wizard/crm_lead_to_partner.py
@@ -71,9 +71,8 @@ class crm_lead2partner(osv.osv_memory):
contact_obj = self.pool.get('res.partner.address')
partner_id = False
- data = context and context.get('active_ids', []) or []
+ data = list(context and context.get('active_ids', []) or [])
res = super(crm_lead2partner, self).default_get(cr, uid, fields, context=context)
-
for lead in lead_obj.browse(cr, uid, data, context=context):
partner_ids = []
# Find partner address matches the email_from of the lead
@@ -85,17 +84,15 @@ class crm_lead2partner(osv.osv_memory):
substring(email from '([^ ,<@]+@[^> ,]+)') in (%s)""" % (','.join(email)))
address_ids = map(lambda x: x[0], cr.fetchall())
if address_ids:
- addresses = contact_obj.browse(cr, uid, address_ids)
- partner_ids = addresses and [addresses[0].partner_id.id] or False
-
+ partner_ids = partner_obj.search(cr, uid, [('address', 'in', address_ids)], context=context)
+
# Find partner name that matches the name of the lead
if not partner_ids and lead.partner_name:
partner_ids = partner_obj.search(cr, uid, [('name', '=', lead.partner_name)], context=context)
- if not partner_ids:
- cr.execute("""SELECT p.id from res_partner p
- where regexp_replace(lower(p.name), '[^a-z]*', '', 'g') = regexp_replace(%s, '[^a-z]*', '', 'g')""", (lead.name.lower(), ))
- partner_ids = map(lambda x: x[0], cr.fetchall())
+
partner_id = partner_ids and partner_ids[0] or False
+
+
if 'partner_id' in fields:
res.update({'partner_id': partner_id})
diff --git a/addons/crm/wizard/crm_merge_opportunities.py b/addons/crm/wizard/crm_merge_opportunities.py
index c34fc5ab532..8cf1d14ce17 100644
--- a/addons/crm/wizard/crm_merge_opportunities.py
+++ b/addons/crm/wizard/crm_merge_opportunities.py
@@ -27,13 +27,19 @@ class crm_merge_opportunity(osv.osv_memory):
_name = 'crm.merge.opportunity'
_description = 'Merge two Opportunities'
- def _get_first_not_null_id(self, attr, ops):
+ def _get_first_not_null_id(self, attr, ops, oldest):
+ if hasattr(oldest, attr) and getattr(oldest, attr):
+ return getattr(oldest, attr).id
+
for op in ops:
if hasattr(op, attr) and getattr(op, attr):
return getattr(op, attr).id
return False
- def _get_first_not_null(self, attr, ops):
+ def _get_first_not_null(self, attr, ops, oldest):
+ if hasattr(oldest, attr) and getattr(oldest, attr):
+ return getattr(oldest, attr)
+
for op in ops:
if hasattr(op, attr) and getattr(op, attr):
return getattr(op, attr)
@@ -54,6 +60,16 @@ class crm_merge_opportunity(osv.osv_memory):
attach_obj.write(cr, uid, attach_ids, {'res_id' : op_id})
+ def find_oldest(self, cr, uid, op_ids, context=None):
+ if not context:
+ context = {}
+ ids = [op_id.id for op_id in op_ids]
+ if context.get('convert'):
+ ids = list(set(ids) - set(context.get('lead_ids', False)) )
+ lead_obj = self.pool.get('crm.lead')
+ op_id = lead_obj.search(cr, uid, [('id', 'in', ids)], order='create_date' , context=context)
+ opps = lead_obj.browse(cr, uid, [op_id[0]], context=context)
+ return opps[0]
def merge(self, cr, uid, op_ids, context=None):
"""
@@ -62,61 +78,68 @@ class crm_merge_opportunity(osv.osv_memory):
opp_obj = self.pool.get('crm.lead')
message_obj = self.pool.get('mailgate.message')
- lead_ids = context and context.pop('lead_ids', []) or []
-
+ lead_ids = context and context.get('lead_ids', []) or []
if len(op_ids) <= 1:
raise osv.except_osv(_('Warning !'),_('Please select more than one opportunities.'))
opportunities = opp_obj.browse(cr, uid, lead_ids, context=context)
opportunities_list = list(set(op_ids) - set(opportunities))
-
+ oldest_opp = self.find_oldest(cr, uid, op_ids, context=context)
if opportunities :
first_opportunity = opportunities[0]
tail_opportunities = opportunities_list
else:
first_opportunity = opportunities_list[0]
tail_opportunities = opportunities_list[1:]
-
+
data = {
- 'partner_id': self._get_first_not_null_id('partner_id', op_ids), # !!
- 'title': self._get_first_not_null_id('title', op_ids),
- 'name' : self._concat_all('name', op_ids), #not lost
- 'categ_id' : self._get_first_not_null_id('categ_id', op_ids), # !!
- 'channel_id' : self._get_first_not_null_id('channel_id', op_ids), # !!
- 'city' : self._get_first_not_null('city', op_ids), # !!
- 'company_id' : self._get_first_not_null_id('company_id', op_ids), #!!
- 'contact_name' : self._concat_all('contact_name', op_ids), #not lost
- 'country_id' : self._get_first_not_null_id('country_id', op_ids), #!!
- 'partner_address_id' : self._get_first_not_null_id('partner_address_id', op_ids), #!!
- 'partner_assigned_id' : hasattr(opp_obj,'partner_assigned_id') and self._get_first_not_null_id('partner_assigned_id', op_ids), #!!
- 'type_id' : self._get_first_not_null_id('type_id', op_ids), #!!
- 'user_id' : self._get_first_not_null_id('user_id', op_ids), #!!
- 'section_id' : self._get_first_not_null_id('section_id', op_ids), #!!
- 'state_id' : self._get_first_not_null_id('state_id', op_ids),
+ 'partner_id': self._get_first_not_null_id('partner_id', op_ids, oldest_opp), # !!
+ 'title': self._get_first_not_null_id('title', op_ids, oldest_opp),
+ 'name' : self._get_first_not_null('name', op_ids, oldest_opp), #not lost
+ 'categ_id' : self._get_first_not_null_id('categ_id', op_ids, oldest_opp), # !!
+ 'channel_id' : self._get_first_not_null_id('channel_id', op_ids, oldest_opp), # !!
+ 'city' : self._get_first_not_null('city', op_ids, oldest_opp), # !!
+ 'company_id' : self._get_first_not_null_id('company_id', op_ids, oldest_opp), #!!
+ 'contact_name' : self._get_first_not_null('contact_name', op_ids, oldest_opp), #not lost
+ 'country_id' : self._get_first_not_null_id('country_id', op_ids, oldest_opp), #!!
+ 'partner_address_id' : self._get_first_not_null_id('partner_address_id', op_ids, oldest_opp), #!!
+ 'partner_assigned_id' : hasattr(opp_obj,'partner_assigned_id') and self._get_first_not_null_id('partner_assigned_id', op_ids, oldest_opp), #!!
+ 'type_id' : self._get_first_not_null_id('type_id', op_ids, oldest_opp), #!!
+ 'user_id' : self._get_first_not_null_id('user_id', op_ids, oldest_opp), #!!
+ 'section_id' : self._get_first_not_null_id('section_id', op_ids, oldest_opp), #!!
+ 'state_id' : self._get_first_not_null_id('state_id', op_ids, oldest_opp),
'description' : self._concat_all('description', op_ids), #not lost
- 'email' : self._get_first_not_null('email', op_ids), # !!
- 'fax' : self._get_first_not_null('fax', op_ids),
- 'mobile' : self._get_first_not_null('mobile', op_ids),
- 'partner_latitude' : hasattr(opp_obj,'partner_latitude') and self._get_first_not_null('partner_latitude', op_ids),
- 'partner_longitude' : hasattr(opp_obj,'partner_longitude') and self._get_first_not_null('partner_longitude', op_ids),
- 'partner_name' : self._get_first_not_null('partner_name', op_ids),
- 'phone' : self._get_first_not_null('phone', op_ids),
- 'probability' : self._get_first_not_null('probability', op_ids),
- 'planned_revenue' : self._get_first_not_null('planned_revenue', op_ids),
- 'street' : self._get_first_not_null('street', op_ids),
- 'street2' : self._get_first_not_null('street2', op_ids),
- 'zip' : self._get_first_not_null('zip', op_ids),
+ 'email' : self._get_first_not_null('email', op_ids, oldest_opp), # !!
+ 'fax' : self._get_first_not_null('fax', op_ids, oldest_opp),
+ 'mobile' : self._get_first_not_null('mobile', op_ids, oldest_opp),
+ 'partner_latitude' : hasattr(opp_obj,'partner_latitude') and self._get_first_not_null('partner_latitude', op_ids, oldest_opp),
+ 'partner_longitude' : hasattr(opp_obj,'partner_longitude') and self._get_first_not_null('partner_longitude', op_ids, oldest_opp),
+ 'partner_name' : self._get_first_not_null('partner_name', op_ids, oldest_opp),
+ 'phone' : self._get_first_not_null('phone', op_ids, oldest_opp),
+ 'probability' : self._get_first_not_null('probability', op_ids, oldest_opp),
+ 'planned_revenue' : self._get_first_not_null('planned_revenue', op_ids, oldest_opp),
+ 'street' : self._get_first_not_null('street', op_ids, oldest_opp),
+ 'street2' : self._get_first_not_null('street2', op_ids, oldest_opp),
+ 'zip' : self._get_first_not_null('zip', op_ids, oldest_opp),
+ 'state' : 'open',
+ 'create_date' : self._get_first_not_null('create_date', op_ids, oldest_opp),
+ 'date_action_last': self._get_first_not_null('date_action_last', op_ids, oldest_opp),
+ 'date_action_next': self._get_first_not_null('date_action_nexte', op_ids, oldest_opp),
+ 'email_from' : self._get_first_not_null('email_from', op_ids, oldest_opp),
+ 'email_cc' : self._get_first_not_null('email_cc', op_ids, oldest_opp),
+ 'partner_name' : self._get_first_not_null('partner_name', op_ids, oldest_opp),
}
-
+
#copy message into the first opportunity + merge attachement
- for opp in tail_opportunities:
+
+ for opp in tail_opportunities + [first_opportunity]:
attach_ids = self.get_attachments(cr, uid, opp, context=context)
self.set_attachements_res_id(cr, uid, first_opportunity.id, attach_ids)
for history in opp.message_ids:
- new_history = message_obj.copy(cr, uid, history.id, default={'res_id': opp.id})
+ new_history = message_obj.write(cr, uid, history.id, {'res_id': first_opportunity.id, 'name' : _("From %s : %s") % (opp.name, history.name) }, context=context)
#Notification about loss of information
details = []
@@ -214,8 +237,13 @@ class crm_merge_opportunity(osv.osv_memory):
res = super(crm_merge_opportunity, self).default_get(cr, uid, fields, context=context)
if record_ids:
+ opp_ids = []
+ opps = self.pool.get('crm.lead').browse(cr, uid, record_ids, context=context)
+ for opp in opps:
+ if opp.state not in ('done', 'cancel'):
+ opp_ids.append(opp.id)
if 'opportunity_ids' in fields:
- res.update({'opportunity_ids': record_ids})
+ res.update({'opportunity_ids': opp_ids})
return res
diff --git a/addons/crm/wizard/crm_send_email.py b/addons/crm/wizard/crm_send_email.py
index 62e8ee77c1e..21902d9ece4 100644
--- a/addons/crm/wizard/crm_send_email.py
+++ b/addons/crm/wizard/crm_send_email.py
@@ -57,9 +57,25 @@ class crm_send_new_email(osv.osv_memory):
'body': fields.text('Message Body', required=True),
'state': fields.selection(AVAILABLE_STATES, string='Set New State To', required=True),
'attachment_ids' : fields.one2many('crm.send.mail.attachment', 'wizard_id', 'Attachment'),
- 'html': fields.boolean('HTML formatting?', help="Select this if you want to send email with HTML formatting."),
+ 'html': fields.boolean('HTML formatting?', help="Select this if you want to send email with HTML formatting."),
}
+ def action_mass_send(self, cr, uid, ids, context=None):
+
+ if not context:
+ context = {}
+
+ context.update({'mail' : 'new'})
+ actives_ids = context.get('active_ids')
+ print "mass_mail", context.get('mass_mail')
+ model = context.get('active_model')
+ case_pool = self.pool.get(model)
+ for id in actives_ids:
+ context.update({'active_id' : id})
+ self.action_send(cr, uid, ids, context=context)
+
+ return {'type': 'ir.actions.act_window_close'}
+
def action_send(self, cr, uid, ids, context=None):
""" This sends an email to ALL the addresses of the selected partners.
"""
@@ -75,6 +91,8 @@ class crm_send_new_email(osv.osv_memory):
case_pool = self.pool.get(model)
res_id = context and context.get('active_id', False) or False
+
+
for obj in self.browse(cr, uid, ids, context=context):
attach = [
(x.name, base64.decodestring(x.binary)) for x in obj.attachment_ids
@@ -110,8 +128,15 @@ class crm_send_new_email(osv.osv_memory):
res_id = hist.res_id
ref_id = hist.ref_id
case = case_pool.browse(cr, uid, res_id, context=context)
- emails = re.findall(r'([^ ,<@]+@[^> ,]+)', obj.email_to or '')
+
+ if context.get('mass_mail'):
+ email_temp = case.email_from and tools.ustr(case.email_from) or ''
+ emails = re.findall(r'([^ ,<@]+@[^> ,]+)', email_temp)
+ else:
+ emails = re.findall(r'([^ ,<@]+@[^> ,]+)', obj.email_to or '')
+
email_cc = re.findall(r'([^ ,<@]+@[^> ,]+)', obj.email_cc or '')
+
emails = filter(None, emails)
body = obj.body
@@ -180,10 +205,11 @@ class crm_send_new_email(osv.osv_memory):
user_obj = self.pool.get('res.users')
user_mail_from = user_obj._get_email_from(cr, uid, [uid], context=context)[uid]
-
for case in mod_obj.browse(cr, uid, res_id, context=context):
if 'email_to' in fields:
res.update({'email_to': case.email_from and tools.ustr(case.email_from) or ''})
+ if context.get('mass_mail'):
+ res.update({'email_to': ''})
if 'email_from' in fields:
res.update({'email_from': user_mail_from and tools.ustr(user_mail_from) or ''})
if 'reply_to' in fields:
@@ -191,8 +217,12 @@ class crm_send_new_email(osv.osv_memory):
res.update({'reply_to': case.section_id and case.section_id.reply_to or False})
if 'subject' in fields:
res.update({'subject': tools.ustr(context.get('subject', case.name) or '')})
+ if context.get('mass_mail'):
+ res.update({'subject': ''})
if 'email_cc' in fields:
res.update({'email_cc': tools.ustr(case.email_cc or '')})
+ if context.get('mass_mail'):
+ res.update({'email_cc': ''})
if 'body' in fields:
res.update({'body': u'\n'+(tools.ustr(case.user_id.signature or ''))})
if 'state' in fields:
diff --git a/addons/crm/wizard/crm_send_email_view.xml b/addons/crm/wizard/crm_send_email_view.xml
index e973eb477c9..be1644b6bbb 100644
--- a/addons/crm/wizard/crm_send_email_view.xml
+++ b/addons/crm/wizard/crm_send_email_view.xml
@@ -44,6 +44,45 @@
+
+ crm.new.send.mass.mail.form
+ crm.send.mail
+ form
+
+
+
+
+
@@ -56,6 +95,14 @@
+
+
@@ -89,6 +136,9 @@
+
+
+
diff --git a/addons/crm_partner_assign/__openerp__.py b/addons/crm_partner_assign/__openerp__.py
index 2eb16399ca6..a00434e8ee0 100644
--- a/addons/crm_partner_assign/__openerp__.py
+++ b/addons/crm_partner_assign/__openerp__.py
@@ -43,6 +43,7 @@ You can also use the geolocalization without using the GPS coordinates.
'wizard/crm_forward_to_partner_view.xml',
'crm_lead_view.xml',
'report/crm_lead_report_view.xml',
+ 'report/crm_partner_report_view.xml',
],
'test': ['test/test_crm_partner_assign.yml'],
'installable': True,
diff --git a/addons/crm_partner_assign/partner_geo_assign.py b/addons/crm_partner_assign/partner_geo_assign.py
index 3d524e32c42..50eae5825cb 100644
--- a/addons/crm_partner_assign/partner_geo_assign.py
+++ b/addons/crm_partner_assign/partner_geo_assign.py
@@ -142,21 +142,6 @@ class crm_lead(osv.osv):
('country', '=', part.country_id.id),
], context=context)
- # 3. third way: other countries, small area
- if not part_ids:
- part_ids = self.pool.get('res.partner').search(cr, uid, [
- ('partner_weight','>',0),
- ('partner_latitude','>',result[0]-2), ('partner_latitude','<',result[0]+2),
- ('partner_longitude','>',result[1]-1.5), ('partner_longitude','<',result[1]+1.5)
- ], context=context)
-
- # 4. fourth way: other countries, big area
- if not part_ids:
- part_ids = self.pool.get('res.partner').search(cr, uid, [
- ('partner_weight','>',0),
- ('partner_latitude','>',result[0]-4), ('partner_latitude','<',result[0]+4),
- ('partner_longitude','>',result[1]-3), ('partner_longitude','<',result[1]+3)
- ], context=context)
# 5. fifth way: anywhere in same country
if not part_ids:
diff --git a/addons/crm_partner_assign/report/__init__.py b/addons/crm_partner_assign/report/__init__.py
index 9b7860b8de4..a211aeede1e 100644
--- a/addons/crm_partner_assign/report/__init__.py
+++ b/addons/crm_partner_assign/report/__init__.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
-#
+#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL ().
#
@@ -15,9 +15,10 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
+# along with this program. If not, see .
#
##############################################################################
import crm_lead_report
+import crm_partner_report
diff --git a/addons/crm_partner_assign/report/crm_lead_report.py b/addons/crm_partner_assign/report/crm_lead_report.py
index cf1d06dc36d..8fa9963a945 100644
--- a/addons/crm_partner_assign/report/crm_lead_report.py
+++ b/addons/crm_partner_assign/report/crm_lead_report.py
@@ -37,7 +37,7 @@ class crm_lead_report_assign(osv.osv):
_auto = False
_description = "CRM Lead Report"
_columns = {
- 'name': fields.char('Year', size=64, required=False, readonly=True),
+ 'year': fields.char('Year', size=64, required=False, readonly=True),
'partner_assigned_id':fields.many2one('res.partner', 'Partner', readonly=True),
'grade_id':fields.many2one('res.partner.grade', 'Grade', readonly=True),
'user_id':fields.many2one('res.users', 'User', readonly=True),
@@ -51,7 +51,7 @@ class crm_lead_report_assign(osv.osv):
('09', 'September'), ('10', 'October'),\
('11', 'November'), ('12', 'December')], 'Month', readonly=True),
'company_id': fields.many2one('res.company', 'Company', readonly=True),
- 'partner_date': fields.date('Partner Date', readonly=True),
+ 'date_assign': fields.date('Partner Date', readonly=True),
'create_date': fields.datetime('Create Date', readonly=True),
'day': fields.char('Day', size=128, readonly=True),
'delay_open': fields.float('Delay to Open',digits=(16,2),readonly=True, group_operator="avg",help="Number of Days to open the case"),
@@ -82,18 +82,20 @@ class crm_lead_report_assign(osv.osv):
CRM Lead Report
@param cr: the current row, from the database cursor
"""
+ print "WHATTT "
tools.drop_view_if_exists(cr, 'crm_lead_report_assign')
cr.execute("""
CREATE OR REPLACE VIEW crm_lead_report_assign AS (
SELECT
c.id,
- to_char(c.create_date, 'YYYY') as name,
- to_char(c.create_date, 'MM') as month,
- to_char(c.create_date, 'YYYY-MM-DD') as day,
+ to_char(c.date_assign, 'YYYY') as year,
+ to_char(c.date_assign, 'MM') as month,
+ to_char(c.date_assign, 'YYYY-MM-DD') as day,
to_char(c.create_date, 'YYYY-MM-DD') as creation_date,
to_char(c.date_open, 'YYYY-MM-DD') as opening_date,
to_char(c.date_closed, 'YYYY-mm-dd') as date_closed,
c.state,
+ c.date_assign,
c.user_id,
c.probability,
c.probability as probability_max,
diff --git a/addons/crm_partner_assign/report/crm_lead_report_view.xml b/addons/crm_partner_assign/report/crm_lead_report_view.xml
index c71d19df49d..3b1e067f4c3 100644
--- a/addons/crm_partner_assign/report/crm_lead_report_view.xml
+++ b/addons/crm_partner_assign/report/crm_lead_report_view.xml
@@ -69,17 +69,17 @@
domain="[]"
context="{'group_by':'company_id'}" />
-
+ context="{'group_by':'date_assign'}"/>
+ domain="[]" context="{'group_by':'year'}" />
@@ -107,9 +107,9 @@
tree
-
+
-
+
diff --git a/addons/crm_partner_assign/report/crm_partner_report.py b/addons/crm_partner_assign/report/crm_partner_report.py
new file mode 100644
index 00000000000..10e74a34b76
--- /dev/null
+++ b/addons/crm_partner_assign/report/crm_partner_report.py
@@ -0,0 +1,63 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2004-2010 Tiny SPRL ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+#
+##############################################################################
+from osv import fields,osv
+import tools
+
+
+class crm_partner_report_assign(osv.osv):
+ """ CRM Lead Report """
+ _name = "crm.partner.report.assign"
+ _auto = False
+ _description = "CRM Partner Report"
+ _columns = {
+ 'name': fields.char('Partner name', size=64, required=False, readonly=True),
+ 'grade_id':fields.many2one('res.partner.grade', 'Grade', readonly=True),
+ 'user_id':fields.many2one('res.users', 'User', readonly=True),
+ 'country_id':fields.many2one('res.country', 'Country', readonly=True),
+ 'section_id':fields.many2one('crm.case.section', 'Sales Team', readonly=True),
+ 'nbr': fields.integer('# of Partner', readonly=True),
+ 'opp': fields.integer('# of Opportunity', readonly=True),
+ }
+
+ def init(self, cr):
+
+ """
+ CRM Lead Report
+ @param cr: the current row, from the database cursor
+ """
+ tools.drop_view_if_exists(cr, 'crm_partner_report_assign')
+ cr.execute("""
+ CREATE OR REPLACE VIEW crm_partner_report_assign AS (
+ SELECT
+ p.id,
+ p.name,
+ (SELECT country_id FROM res_partner_address a WHERE a.partner_id=p.id AND country_id is not null limit 1) as country_id,
+ p.grade_id,
+ p.user_id,
+ p.section_id,
+ 1 as nbr,
+ (SELECT count(id) FROM crm_lead WHERE partner_assigned_id=p.id) AS opp
+ FROM
+ res_partner p
+
+ )""")
+
+crm_partner_report_assign()
diff --git a/addons/crm_partner_assign/report/crm_partner_report_view.xml b/addons/crm_partner_assign/report/crm_partner_report_view.xml
new file mode 100644
index 00000000000..8ac65f6b57e
--- /dev/null
+++ b/addons/crm_partner_assign/report/crm_partner_report_view.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+ crm.partner.report.assign.select
+ crm.partner.report.assign
+ search
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ crm.partner.assign.report.tree
+ crm.partner.report.assign
+ tree
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Partnership Analysis
+ crm.partner.report.assign
+ {'search_default_group_country': 1, 'search_default_group_grade': 1, 'group_by_no_leaf':1,'group_by':[]}
+ tree
+ [('grade_id', '!=', False)]
+
+
+
+
+
+
diff --git a/addons/crm_partner_assign/security/ir.model.access.csv b/addons/crm_partner_assign/security/ir.model.access.csv
index 79e7611eedb..b5bb64ad3dd 100644
--- a/addons/crm_partner_assign/security/ir.model.access.csv
+++ b/addons/crm_partner_assign/security/ir.model.access.csv
@@ -1,5 +1,6 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
-"access_ crm_lead_report_assign"," crm.lead.report.assign","model_crm_lead_report_assign","base.group_sale_salesman",1,1,1,0
+"access_ crm_lead_report_assign","crm.lead.report.assign","model_crm_lead_report_assign","base.group_sale_salesman",1,1,1,0
"access_ crm_lead_report_assign_all","crm.lead.report.assign.all","model_crm_lead_report_assign","base.group_user",1,0,0,0
+"access_crm_partner_report","crm.partner.report.assign.all","model_crm_partner_report_assign","base.group_sale_salesman",1,0,0,0
"access_res_partner_grade","res.partner.grade","model_res_partner_grade","base.group_sale_salesman",1,1,1,0
"access_res_partner_grade_manager","res.partner.grade.manager","model_res_partner_grade","base.group_sale_manager",1,1,1,1
diff --git a/addons/crm_partner_assign/wizard/crm_forward_to_partner.py b/addons/crm_partner_assign/wizard/crm_forward_to_partner.py
index 0e4a5515ac1..f531165e942 100644
--- a/addons/crm_partner_assign/wizard/crm_forward_to_partner.py
+++ b/addons/crm_partner_assign/wizard/crm_forward_to_partner.py
@@ -44,9 +44,10 @@ class crm_lead_forward_to_partner(osv.osv_memory):
_defaults = {
'name' : 'email',
'history': 'latest',
- 'email_from': lambda self, cr, uid, *a: self.pool.get('res.users')._get_email_from(cr, uid, uid)[uid]
+ 'email_from': lambda self, cr, uid, *a: self.pool.get('res.users')._get_email_from(cr, uid, uid)[uid],
}
+
def get_whole_history(self, cr, uid, ids, context=None):
"""This function gets whole communication history and returns as top posting style
@param self: The object pointer
@@ -87,7 +88,7 @@ class crm_lead_forward_to_partner(osv.osv_memory):
@param uid: the current user’s ID for security checks,
@param ids: List of Mail’s IDs
@param user: Changed User id
- @param partner: Changed Partner id
+ @param partner: Changed Partner id
"""
if not user:
return {'value': {'email_to': False}}
@@ -146,7 +147,7 @@ class crm_lead_forward_to_partner(osv.osv_memory):
@param uid: the current user’s ID for security checks,
@param ids: List of Mail’s IDs
@param user: Changed User id
- @param partner: Changed Partner id
+ @param partner: Changed Partner id
"""
if not partner_id:
return {'value' : {'email_to' : False, 'address_id': False}}
@@ -155,13 +156,13 @@ class crm_lead_forward_to_partner(osv.osv_memory):
addr = partner_obj.address_get(cr, uid, [partner_id], ['contact'])
data = {'address_id': addr['contact']}
data.update(self.on_change_address(cr, uid, ids, addr['contact'])['value'])
-
+
partner = partner_obj.browse(cr, uid, [partner_id])
user_id = partner and partner[0].user_id or False
email = user_id and user_id.user_email or ''
data.update({'email_cc' : email})
return {
- 'value' : data,
+ 'value' : data,
'domain' : {'address_id' : partner_id and "[('partner_id', '=', partner_id)]" or "[]"}
}
@@ -236,23 +237,23 @@ class crm_lead_forward_to_partner(osv.osv_memory):
body.append("%s: %s" % (field_definition.string, value or ''))
elif lead.type == 'opportunity':
pa = lead.partner_address_id
- body = [
- "Partner: %s" % (lead.partner_id and lead.partner_id.name_get()[0][1]),
- "Contact: %s" % (pa.name or ''),
- "Title: %s" % (pa.title or ''),
- "Function: %s" % (pa.function or ''),
- "Street: %s" % (pa.street or ''),
- "Street2: %s" % (pa.street2 or ''),
- "Zip: %s" % (pa.zip or ''),
- "City: %s" % (pa.city or ''),
- "Country: %s" % (pa.country_id and pa.country_id.name_get()[0][1] or ''),
- "State: %s" % (pa.state_id and pa.state_id.name_get()[0][1] or ''),
- "Email: %s" % (pa.email or ''),
- "Phone: %s" % (pa.phone or ''),
- "Fax: %s" % (pa.fax or ''),
- "Mobile: %s" % (pa.mobile or ''),
- "Lead Category: %s" % (lead.categ_id and lead.categ_id.name or ''),
- "Details: %s" % (lead.description or ''),
+ body += [
+ "Partner: %s" % (lead.partner_id and lead.partner_id.name_get()[0][1]),
+ "Contact: %s" % (pa.name or ''),
+ "Title: %s" % (pa.title or ''),
+ "Function: %s" % (pa.function or ''),
+ "Street: %s" % (pa.street or ''),
+ "Street2: %s" % (pa.street2 or ''),
+ "Zip: %s" % (pa.zip or ''),
+ "City: %s" % (pa.city or ''),
+ "Country: %s" % (pa.country_id and pa.country_id.name_get()[0][1] or ''),
+ "State: %s" % (pa.state_id and pa.state_id.name_get()[0][1] or ''),
+ "Email: %s" % (pa.email or ''),
+ "Phone: %s" % (pa.phone or ''),
+ "Fax: %s" % (pa.fax or ''),
+ "Mobile: %s" % (pa.mobile or ''),
+ "Lead Category: %s" % (lead.categ_id and lead.categ_id.name or ''),
+ "Details: %s" % (lead.description or ''),
]
return "\n".join(body + ['---'])
@@ -260,26 +261,66 @@ class crm_lead_forward_to_partner(osv.osv_memory):
"""
This function gets default values
"""
+
if context is None:
context = {}
defaults = super(crm_lead_forward_to_partner, self).default_get(cr, uid, fields, context=context)
-
active_id = context.get('active_id')
if not active_id:
return defaults
lead_proxy = self.pool.get('crm.lead')
+ partner_obj = self.pool.get('res.partner')
lead = lead_proxy.browse(cr, uid, active_id, context=context)
+ email_cc = ''
+ email = ''
+ if lead.partner_assigned_id:
+ partner = partner_obj.browse(cr, uid, [lead.partner_assigned_id.id])
+ user_id = partner and partner[0].user_id or False
+ email_cc = user_id and user_id.user_email or ''
+
+ addr = partner_obj.address_get(cr, uid, [partner[0].id], ['contact'])
+ email = self.pool.get('res.partner.address').browse(cr, uid, addr['contact']).email
+
body = self._get_case_history(cr, uid, defaults.get('history', 'latest'), lead.id, context=context)
defaults.update({
- 'subject' : '%s: %s' % (_('Fwd'), lead.name),
+ 'subject' : '%s: %s - %s' % (_('Fwd'), 'Openerp lead forward', lead.name),
'body' : body,
- 'email_cc' : ''
+ 'email_cc' : email_cc,
+ 'email_to' : email or 'dummy@dummy.ly'
})
return defaults
crm_lead_forward_to_partner()
+class crm_lead_mass_forward_to_partner(osv.osv_memory):
+ _name = 'crm.lead.mass.forward.to.partner'
+ _inherit = 'crm.lead.forward.to.partner'
+
+ def action_mass_forward(self, cr, uid, ids, context=None):
+ if not context:
+ context = {}
+
+ active_ids = context.get('active_ids')
+ case_obj = self.pool.get('crm.lead')
+ for case in case_obj.browse(cr, uid, active_ids, context=context):
+ if not case.partner_assigned_id:
+ case_obj.assign_partner(cr,uid, [case.id], context=context)
+ case = case_obj.browse(cr, uid, case.id, context=context)
+
+ if not case.partner_assigned_id:
+ continue
+
+ context.update({'active_id' : case.id})
+ value = self.default_get(cr, uid, ['body', 'email_to', 'email_cc', 'subject', 'history'], context=context)
+ self.write(cr, uid, ids, value, context=context)
+ self.action_forward(cr,uid, ids, context=context)
+
+ return {'type': 'ir.actions.act_window_close'}
+
+
+crm_lead_mass_forward_to_partner()
+
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/crm_partner_assign/wizard/crm_forward_to_partner_view.xml b/addons/crm_partner_assign/wizard/crm_forward_to_partner_view.xml
index 9ee2870335a..9826bf9d45c 100644
--- a/addons/crm_partner_assign/wizard/crm_forward_to_partner_view.xml
+++ b/addons/crm_partner_assign/wizard/crm_forward_to_partner_view.xml
@@ -38,14 +38,70 @@
+
Forward to Partner
crm.lead.forward.to.partner
form
form
-
+
new
+
+
+ crm.new.mass.forward.mail.form
+ crm.lead.mass.forward.to.partner
+ form
+
+
+
+
+
+
+
+
+
diff --git a/addons/document/document.py b/addons/document/document.py
index 1a553b23ed1..27a6c3d3c19 100644
--- a/addons/document/document.py
+++ b/addons/document/document.py
@@ -279,10 +279,22 @@ class document_file(osv.osv):
else:
if vals.get('file_size'):
del vals['file_size']
- if not self._check_duplication(cr, uid, vals):
- raise osv.except_osv(_('ValidateError'), _('File name must be unique!'))
- result = super(document_file, self).create(cr, uid, vals, context)
- cr.commit() # ?
+ result = self._check_duplication(cr, uid, vals)
+ if not result:
+ domain = [
+ ('res_id', '=', vals['res_id']),
+ ('res_model', '=', vals['res_model']),
+ ('datas_fname', '=', vals['datas_fname']),
+ ]
+ attach_ids = self.search(cr, uid, domain, context=context)
+ super(document_file, self).write(cr, uid, attach_ids,
+ {'datas' : vals['datas']},
+ context=context)
+ result = attach_ids[0]
+ else:
+ #raise osv.except_osv(_('ValidateError'), _('File name must be unique!'))
+ result = super(document_file, self).create(cr, uid, vals, context)
+ cr.commit() # ?
return result
def __get_partner_id(self, cr, uid, res_model, res_id, context=None):
diff --git a/addons/email_template/email_template_mailbox.py b/addons/email_template/email_template_mailbox.py
index 49d61bf05df..4486cb5451e 100644
--- a/addons/email_template/email_template_mailbox.py
+++ b/addons/email_template/email_template_mailbox.py
@@ -92,6 +92,7 @@ class email_template_mailbox(osv.osv):
self.unlink(cr, uid, [id], context=context)
# Remove attachments for this mail
attachment_pool.unlink(cr, uid, values['attachments_ids'], context=context)
+ return result
else:
self.write(cr, uid, id, {'folder':'sent', 'state':'na', 'date_mail':time.strftime("%Y-%m-%d %H:%M:%S")}, context)
self.historise(cr, uid, [id], "Email sent successfully", context)
diff --git a/addons/email_template/email_template_view.xml b/addons/email_template/email_template_view.xml
index 5da74772c44..7d2a5f7ad5c 100644
--- a/addons/email_template/email_template_view.xml
+++ b/addons/email_template/email_template_view.xml
@@ -201,7 +201,7 @@
+ parent="menu_email_template" action="action_email_template_tree_all" />
+
diff --git a/addons/project/project.py b/addons/project/project.py
index 14ee94e76a1..134364d8b1a 100644
--- a/addons/project/project.py
+++ b/addons/project/project.py
@@ -26,6 +26,10 @@ from datetime import datetime, date
from tools.translate import _
from osv import fields, osv
+class project_project(osv.osv):
+ _name = 'project.project'
+
+project_project()
class project_task_type(osv.osv):
_name = 'project.task.type'
@@ -35,6 +39,7 @@ class project_task_type(osv.osv):
'name': fields.char('Stage Name', required=True, size=64, translate=True),
'description': fields.text('Description'),
'sequence': fields.integer('Sequence'),
+ 'project_ids': fields.many2many('project.project', 'project_task_type_rel', 'type_id', 'project_id', 'Projects'),
}
_defaults = {
diff --git a/addons/project_issue/project_issue.py b/addons/project_issue/project_issue.py
index aaaff37305e..a8a32847243 100644
--- a/addons/project_issue/project_issue.py
+++ b/addons/project_issue/project_issue.py
@@ -43,9 +43,9 @@ project_issue_version()
class project_issue(crm.crm_case, osv.osv):
_name = "project.issue"
_description = "Project Issue"
- _order = "priority, id desc"
+ _order = "priority, create_date desc"
_inherit = ['mailgate.thread']
-
+
def case_open(self, cr, uid, ids, *args):
"""
@param self: The object pointer
@@ -56,7 +56,7 @@ class project_issue(crm.crm_case, osv.osv):
"""
res = super(project_issue, self).case_open(cr, uid, ids, *args)
- self.write(cr, uid, ids, {'date_open': time.strftime('%Y-%m-%d %H:%M:%S')})
+ self.write(cr, uid, ids, {'date_open': time.strftime('%Y-%m-%d %H:%M:%S'), 'assigned_to' : uid})
for (id, name) in self.name_get(cr, uid, ids):
message = _("Issue '%s' has been opened.") % name
self.log(cr, uid, id, message)
@@ -175,7 +175,7 @@ class project_issue(crm.crm_case, osv.osv):
'section_id': fields.many2one('crm.case.section', 'Sales Team', \
select=True, help='Sales team to which Case belongs to.\
Define Responsible user and Email account for mail gateway.'),
- 'user_id': fields.many2one('res.users', 'Responsible'),
+ 'user_id': fields.related('project_id', 'user_id', type='many2one', relation='res.users', store=True, select=1, string='Responsible'),
'partner_id': fields.many2one('res.partner', 'Partner'),
'partner_address_id': fields.many2one('res.partner.address', 'Partner Contact', \
domain="[('partner_id','=',partner_id)]"),
@@ -200,19 +200,19 @@ class project_issue(crm.crm_case, osv.osv):
'partner_name': fields.char("Employee's Name", size=64),
'partner_mobile': fields.char('Mobile', size=32),
'partner_phone': fields.char('Phone', size=32),
- 'type_id': fields.many2one ('project.task.type', 'Resolution'),
+ 'type_id': fields.many2one ('project.task.type', 'Resolution', domain="[('project_ids', '=', project_id)]"),
'project_id':fields.many2one('project.project', 'Project'),
'duration': fields.float('Duration'),
'task_id': fields.many2one('project.task', 'Task', domain="[('project_id','=',project_id)]"),
'day_open': fields.function(_compute_day, string='Days to Open', \
- method=True, multi='day_open', type="float", store=True),
+ method=True, multi='compute_day', type="float", store=True),
'day_close': fields.function(_compute_day, string='Days to Close', \
- method=True, multi='day_close', type="float", store=True),
- 'assigned_to': fields.related('task_id', 'user_id', string = 'Assigned to', type="many2one", relation="res.users", store=True, help='This is the current user to whom the related task have been assigned'),
+ method=True, multi='compute_day', type="float", store=True),
+ 'assigned_to': fields.many2one('res.users', 'Assigned to', required=False, select=1),
'working_hours_open': fields.function(_compute_day, string='Working Hours to Open the Issue', \
- method=True, multi='working_days_open', type="float", store=True),
+ method=True, multi='compute_day', type="float", store=True),
'working_hours_close': fields.function(_compute_day, string='Working Hours to Close the Issue', \
- method=True, multi='working_days_close', type="float", store=True),
+ method=True, multi='compute_day', type="float", store=True),
'message_ids': fields.one2many('mailgate.message', 'res_id', 'Messages', domain=[('model','=',_name)]),
'date_action_last': fields.datetime('Last Action', readonly=1),
'date_action_next': fields.datetime('Next Action', readonly=1),
@@ -230,17 +230,30 @@ class project_issue(crm.crm_case, osv.osv):
return user.context_project_id.id
return False
+ def on_change_project(self, cr, uid, ids, project_id, context=None):
+ result = {}
+
+ if project_id:
+ project = self.pool.get('project.project').browse(cr, uid, project_id, context=context)
+ if project.user_id:
+ result['value'] = {'user_id' : project.user_id.id}
+
+ return result
+
+
_defaults = {
'active': 1,
- 'user_id': crm.crm_case._get_default_user,
+ #'user_id': crm.crm_case._get_default_user,
'partner_id': crm.crm_case._get_default_partner,
'partner_address_id': crm.crm_case._get_default_partner_address,
- 'email_from': crm.crm_case. _get_default_email,
+ 'email_from': crm.crm_case._get_default_email,
'state': 'draft',
- 'section_id': crm.crm_case. _get_section,
+ 'section_id': crm.crm_case._get_section,
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.helpdesk', context=c),
'priority': crm.AVAILABLE_PRIORITIES[2][0],
'project_id':_get_project,
+ 'categ_id' : lambda *a: False,
+ #'assigned_to' : lambda obj, cr, uid, context: uid,
}
def convert_issue_task(self, cr, uid, ids, context=None):
diff --git a/addons/project_issue/project_issue_view.xml b/addons/project_issue/project_issue_view.xml
index 36c0e4ba82f..2224527e9d2 100644
--- a/addons/project_issue/project_issue_view.xml
+++ b/addons/project_issue/project_issue_view.xml
@@ -52,13 +52,14 @@
-
-
-
-
-
+
+
+
+
+
+
-
+
@@ -73,7 +74,6 @@
-
-
+
-
-
+
@@ -218,8 +217,8 @@
-
-
+
+
@@ -233,7 +232,7 @@
+ domain="[]" context="{'group_by':'assigned_to'}" />
@@ -264,7 +263,7 @@
calendar
-
+
@@ -285,11 +284,11 @@
-
-
-
+
+
+
-
+
@@ -312,7 +311,7 @@
-
+
diff --git a/addons/project_issue/report/project_issue_report.py b/addons/project_issue/report/project_issue_report.py
index b66963569e7..29542f32912 100644
--- a/addons/project_issue/report/project_issue_report.py
+++ b/addons/project_issue/report/project_issue_report.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
##############################################################################
-#
+#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL ().
#
@@ -16,7 +16,7 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
+# along with this program. If not, see .
#
##############################################################################
@@ -101,10 +101,11 @@ class project_issue_report(osv.osv):
c.task_id,
date_trunc('day',c.create_date) as create_date,
extract('epoch' from (c.date_open-c.create_date))/(3600*24) as delay_open,
- extract('epoch' from (c.date_closed-c.create_date))/(3600*24) as delay_close,
+ extract('epoch' from (c.date_closed-c.date_open))/(3600*24) as delay_close,
(SELECT count(id) FROM mailgate_message WHERE model='project.issue' AND res_id=c.id) AS email
FROM
project_issue c
+ WHERE c.categ_id IN (select id from crm_case_categ where object_id in (select id from ir_model where model = 'project.issue'))
)""")
project_issue_report()
diff --git a/addons/project_issue/report/project_issue_report_view.xml b/addons/project_issue/report/project_issue_report_view.xml
index 4ca0fbf2279..015a7750548 100644
--- a/addons/project_issue/report/project_issue_report_view.xml
+++ b/addons/project_issue/report/project_issue_report_view.xml
@@ -28,8 +28,8 @@
-
-
+
+
diff --git a/addons/project_issue_sheet/project_issue_sheet.py b/addons/project_issue_sheet/project_issue_sheet.py
index f96ce9a4ac5..e9396f9d030 100644
--- a/addons/project_issue_sheet/project_issue_sheet.py
+++ b/addons/project_issue_sheet/project_issue_sheet.py
@@ -27,8 +27,36 @@ class project_issue(osv.osv):
_description = 'project issue'
_columns = {
'timesheet_ids': fields.one2many('hr.analytic.timesheet', 'issue_id', 'Timesheets'),
- 'analytic_account_id': fields.related('project_id', 'analytic_account_id', type='many2one', relation='account.analytic.account',string='Analytic Account')
+ 'analytic_account_id': fields.many2one('account.analytic.account', 'Analytic Account'),
}
+
+ def on_change_project(self, cr, uid, ids, project_id, context=None):
+ if not project_id:
+ return {}
+
+ result = super(project_issue, self).on_change_project(cr, uid, ids, project_id, context=context)
+
+ project = self.pool.get('project.project').browse(cr, uid, project_id, context=context)
+ if 'value' not in result:
+ result['value'] = {}
+
+ account = project.analytic_account_id
+ if account:
+ result['value']['analytic_account_id'] = account.id
+
+ return result
+
+ def on_change_account_id(self, cr, uid, ids, account_id, context=None):
+ if not account_id:
+ return {}
+
+ account = self.pool.get('account.analytic.account').browse(cr, uid, account_id, context=context)
+ result = {}
+
+ if account and account.state == 'pending':
+ result = {'warning' : {'title' : _('Analytic Account'), 'message' : _('The Analytic Account is in pending !')}}
+
+ return result
project_issue()
diff --git a/addons/project_issue_sheet/project_issue_sheet_view.xml b/addons/project_issue_sheet/project_issue_sheet_view.xml
index 2222ef12ea5..058fd67a946 100644
--- a/addons/project_issue_sheet/project_issue_sheet_view.xml
+++ b/addons/project_issue_sheet/project_issue_sheet_view.xml
@@ -7,14 +7,22 @@
form
+
+ on_change_project(project_id)
+
+
+
+
-
-
+
-
-
-
+
+
+