[MERGE] refactoring in modules crm, crm_claim, crm_fundraising, crm_helpdesk, crm_partner_assign, crm_profiling
bzr revid: rco@openerp.com-20111201160819-synohhq5k98lqf24
This commit is contained in:
commit
4fc148ac73
|
@ -118,18 +118,14 @@ Creates a dashboard for CRM that includes:
|
|||
'crm_phonecall_demo.xml',
|
||||
],
|
||||
'test': [
|
||||
'test/test_crm_lead.yml',
|
||||
'test/test_crm_meeting.yml',
|
||||
'test/test_crm_opportunity.yml',
|
||||
'test/test_crm_phonecall.yml',
|
||||
'test/test_crm_recurrent_meeting.yml',
|
||||
'test/test_crm_stage_changes.yml',
|
||||
'test/test_crm_recurrent_meeting_case2.yml',
|
||||
'test/test_crm_lead_case2.yml',
|
||||
'test/test_crm_opportunity_case2.yml',
|
||||
'test/test_crm_phonecall_case2.yml',
|
||||
'test/test_crm_partner2opportunity.yml',
|
||||
'test/test_crm_segmentation.yml',
|
||||
'test/process/communication_with_customer.yml',
|
||||
'test/process/lead2opportunity2win.yml',
|
||||
'test/process/merge_opportunity.yml',
|
||||
'test/process/cancel_lead.yml',
|
||||
'test/process/segmentation.yml',
|
||||
'test/ui/crm_demo.yml',
|
||||
'test/ui/duplicate_lead.yml',
|
||||
'test/ui/delete_lead.yml'
|
||||
],
|
||||
'installable': True,
|
||||
'active': False,
|
||||
|
|
|
@ -468,10 +468,12 @@ class crm_case(crm_base):
|
|||
self._action(cr, uid, cases, state)
|
||||
return True
|
||||
|
||||
#DEAD Code
|
||||
def remind_partner(self, cr, uid, ids, context=None, attach=False):
|
||||
return self.remind_user(cr, uid, ids, context, attach,
|
||||
destination=False)
|
||||
|
||||
#DEAD Code
|
||||
def remind_user(self, cr, uid, ids, context=None, attach=False, destination=True):
|
||||
mail_message = self.pool.get('mail.message')
|
||||
for case in self.browse(cr, uid, ids, context=context):
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
<data>
|
||||
<record id="base.user_demo" model="res.users">
|
||||
<field name="groups_id" eval="[(4,ref('base.group_sale_salesman'))]"/>
|
||||
</record>
|
||||
|
@ -12,5 +12,17 @@
|
|||
<field name="res_id" ref="crm.menu_crm_case_categ_meet"/>
|
||||
</record>
|
||||
|
||||
<record model="crm.case.section" id="section_sales_marketing_department">
|
||||
<field name="name">Sales Marketing Department</field>
|
||||
<field name="code">Sales Marketing</field>
|
||||
<field name="parent_id" ref="crm.section_sales_department"></field>
|
||||
</record>
|
||||
|
||||
<record model="crm.segmentation" id="crm_segmentation0">
|
||||
<field name="name">OpenERP partners</field>
|
||||
<field name="exclusif">True</field>
|
||||
<field name="categ_id" ref="base.res_partner_category_2"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
|
|
@ -27,7 +27,7 @@ from tools.translate import _
|
|||
from crm import crm_case
|
||||
import binascii
|
||||
import tools
|
||||
|
||||
from mail.mail_message import to_email
|
||||
|
||||
CRM_LEAD_PENDING_STATES = (
|
||||
crm.AVAILABLE_STATES[2][0], # Cancelled
|
||||
|
@ -352,36 +352,380 @@ class crm_lead(crm_case, osv.osv):
|
|||
"""
|
||||
return self.set_priority(cr, uid, ids, '3')
|
||||
|
||||
def convert_opportunity(self, cr, uid, ids, context=None):
|
||||
""" Precomputation for converting lead to opportunity
|
||||
|
||||
def _merge_data(self, cr, uid, ids, oldest, fields, context=None):
|
||||
# prepare opportunity data into dictionary for merging
|
||||
opportunities = self.browse(cr, uid, ids, context=context)
|
||||
def _get_first_not_null(attr):
|
||||
if hasattr(oldest, attr):
|
||||
return getattr(oldest, attr)
|
||||
for opportunity in opportunities:
|
||||
if hasattr(opportunity, attr):
|
||||
return getattr(opportunity, attr)
|
||||
return False
|
||||
|
||||
def _get_first_not_null_id(attr):
|
||||
res = _get_first_not_null(attr)
|
||||
return res and res.id or False
|
||||
|
||||
def _concat_all(attr):
|
||||
return ', '.join(filter(lambda x: x, [getattr(opportunity, attr) or '' for opportunity in opportunities if hasattr(opportunity, attr)]))
|
||||
|
||||
data = {}
|
||||
for field_name in fields:
|
||||
field_info = self._all_columns.get(field_name)
|
||||
if field_info is None:
|
||||
continue
|
||||
field = field_info.column
|
||||
if field._type in ('many2many', 'one2many'):
|
||||
continue
|
||||
elif field._type == 'many2one':
|
||||
data[field_name] = _get_first_not_null_id(field_name) # !!
|
||||
elif field._type == 'text':
|
||||
data[field_name] = _concat_all(field_name) #not lost
|
||||
else:
|
||||
data[field_name] = _get_first_not_null(field_name) #not lost
|
||||
return data
|
||||
|
||||
def _merge_find_oldest(self, cr, uid, ids, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
#TOCHECK: where pass 'convert' in context ?
|
||||
if context.get('convert'):
|
||||
ids = list(set(ids) - set(context.get('lead_ids', False)) )
|
||||
|
||||
#search opportunities order by create date
|
||||
opportunity_ids = self.search(cr, uid, [('id', 'in', ids)], order='create_date' , context=context)
|
||||
oldest_id = opportunity_ids[0]
|
||||
return self.browse(cr, uid, oldest_id, context=context)
|
||||
|
||||
def _mail_body_text(self, cr, uid, lead, fields, title=False, context=None):
|
||||
body = []
|
||||
if title:
|
||||
body.append("%s\n" % (title))
|
||||
for field_name in fields:
|
||||
field_info = self._all_columns.get(field_name)
|
||||
if field_info is None:
|
||||
continue
|
||||
field = field_info.column
|
||||
value = None
|
||||
|
||||
if field._type == 'selection':
|
||||
if hasattr(field.selection, '__call__'):
|
||||
key = field.selection(self, cr, uid, context=context)
|
||||
else:
|
||||
key = field.selection
|
||||
value = dict(key).get(lead[field_name], lead[field_name])
|
||||
elif field._type == 'many2one':
|
||||
if lead[field_name]:
|
||||
value = lead[field_name].name_get()[0][1]
|
||||
else:
|
||||
value = lead[field_name]
|
||||
|
||||
body.append("%s: %s" % (field.string, value or ''))
|
||||
return "\n".join(body + ['---'])
|
||||
|
||||
def _merge_notification(self, cr, uid, opportunity_id, opportunities, context=None):
|
||||
#TOFIX: mail template should be used instead of fix body, subject text
|
||||
details = []
|
||||
merge_message = _('Merged opportunities')
|
||||
subject = [merge_message]
|
||||
fields = ['name', 'partner_id', 'stage_id', 'section_id', 'user_id', 'categ_id', 'channel_id', 'company_id', 'contact_name',
|
||||
'email_from', 'phone', 'fax', 'mobile', 'state_id', 'description', 'probability', 'planned_revenue',
|
||||
'country_id', 'city', 'street', 'street2', 'zip']
|
||||
for opportunity in opportunities:
|
||||
subject.append(opportunity.name)
|
||||
title = "%s : %s" % (merge_message, opportunity.name)
|
||||
details.append(self._mail_body_text(cr, uid, opportunity, fields, title=title, context=context))
|
||||
|
||||
subject = subject[0] + ", ".join(subject[1:])
|
||||
details = "\n\n".join(details)
|
||||
return self.message_append(cr, uid, [opportunity_id], subject, body_text=details, context=context)
|
||||
|
||||
def _merge_opportunity_history(self, cr, uid, opportunity_id, opportunities, context=None):
|
||||
message = self.pool.get('mail.message')
|
||||
for opportunity in opportunities:
|
||||
for history in opportunity.message_ids:
|
||||
message.write(cr, uid, history.id, {
|
||||
'res_id': opportunity_id,
|
||||
'subject' : _("From %s : %s") % (opportunity.name, history.subject)
|
||||
}, context=context)
|
||||
|
||||
return True
|
||||
|
||||
def _merge_opportunity_attachments(self, cr, uid, opportunity_id, opportunities, context=None):
|
||||
attachment = self.pool.get('ir.attachment')
|
||||
|
||||
# return attachments of opportunity
|
||||
def _get_attachments(opportunity_id):
|
||||
attachment_ids = attachment.search(cr, uid, [('res_model', '=', self._name), ('res_id', '=', opportunity_id)], context=context)
|
||||
return attachment.browse(cr, uid, attachment_ids, context=context)
|
||||
|
||||
count = 1
|
||||
first_attachments = _get_attachments(opportunity_id)
|
||||
for opportunity in opportunities:
|
||||
attachments = _get_attachments(opportunity.id)
|
||||
for first in first_attachments:
|
||||
for attachment in attachments:
|
||||
if attachment.name == first.name:
|
||||
values = dict(
|
||||
name = "%s (%s)" % (attachment.name, count,),
|
||||
res_id = opportunity_id,
|
||||
)
|
||||
attachment.write(values)
|
||||
count+=1
|
||||
|
||||
return True
|
||||
|
||||
def merge_opportunity(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
To merge opportunities
|
||||
:param ids: list of opportunities ids to merge
|
||||
"""
|
||||
if context is None: context = {}
|
||||
|
||||
#TOCHECK: where pass lead_ids in context?
|
||||
lead_ids = context and context.get('lead_ids', []) or []
|
||||
|
||||
if len(ids) <= 1:
|
||||
raise osv.except_osv(_('Warning !'),_('Please select more than one opportunities.'))
|
||||
|
||||
ctx_opportunities = self.browse(cr, uid, lead_ids, context=context)
|
||||
opportunities = self.browse(cr, uid, ids, context=context)
|
||||
opportunities_list = list(set(opportunities) - set(ctx_opportunities))
|
||||
oldest = self._merge_find_oldest(cr, uid, ids, context=context)
|
||||
if ctx_opportunities :
|
||||
first_opportunity = ctx_opportunities[0]
|
||||
tail_opportunities = opportunities_list
|
||||
else:
|
||||
first_opportunity = opportunities_list[0]
|
||||
tail_opportunities = opportunities_list[1:]
|
||||
|
||||
fields = ['partner_id', 'title', 'name', 'categ_id', 'channel_id', 'city', 'company_id', 'contact_name', 'country_id',
|
||||
'partner_address_id', 'type_id', 'user_id', 'section_id', 'state_id', 'description', 'email', 'fax', 'mobile',
|
||||
'partner_name', 'phone', 'probability', 'planned_revenue', 'street', 'street2', 'zip', 'create_date', 'date_action_last',
|
||||
'date_action_next', 'email_from', 'email_cc', 'partner_name']
|
||||
|
||||
data = self._merge_data(cr, uid, ids, oldest, fields, context=context)
|
||||
|
||||
# merge data into first opportunity
|
||||
self.write(cr, uid, [first_opportunity.id], data, context=context)
|
||||
|
||||
#copy message and attachements into the first opportunity
|
||||
self._merge_opportunity_history(cr, uid, first_opportunity.id, tail_opportunities, context=context)
|
||||
self._merge_opportunity_attachments(cr, uid, first_opportunity.id, tail_opportunities, context=context)
|
||||
|
||||
#Notification about loss of information
|
||||
self._merge_notification(cr, uid, first_opportunity, opportunities, context=context)
|
||||
#delete tail opportunities
|
||||
self.unlink(cr, uid, [x.id for x in tail_opportunities], context=context)
|
||||
|
||||
#open first opportunity
|
||||
self.case_open(cr, uid, [first_opportunity.id])
|
||||
return first_opportunity.id
|
||||
|
||||
def _convert_opportunity_data(self, cr, uid, lead, customer, section_id=False, context=None):
|
||||
crm_stage = self.pool.get('crm.case.stage')
|
||||
contact_id = False
|
||||
if customer:
|
||||
contact_id = self.pool.get('res.partner').address_get(cr, uid, [customer.id])['default']
|
||||
if not section_id:
|
||||
section_id = lead.section_id and lead.section_id.id or False
|
||||
if section_id:
|
||||
stage_ids = crm_stage.search(cr, uid, [('sequence','>=',1), ('section_ids','=', section_id)])
|
||||
else:
|
||||
stage_ids = crm_stage.search(cr, uid, [('sequence','>=',1)])
|
||||
stage_id = stage_ids and stage_ids[0] or False
|
||||
return {
|
||||
'planned_revenue': lead.planned_revenue,
|
||||
'probability': lead.probability,
|
||||
'name': lead.name,
|
||||
'partner_id': customer and customer.id or False,
|
||||
'user_id': (lead.user_id and lead.user_id.id),
|
||||
'type': 'opportunity',
|
||||
'stage_id': stage_id or False,
|
||||
'date_action': time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'partner_address_id': contact_id
|
||||
}
|
||||
def _convert_opportunity_notification(self, cr, uid, lead, context=None):
|
||||
success_message = _("Lead '%s' has been converted to an opportunity.") % lead.name
|
||||
self.message_append(cr, uid, [lead.id], success_message, body_text=success_message, context=context)
|
||||
self.log(cr, uid, lead.id, success_message)
|
||||
self._send_mail_to_salesman(cr, uid, lead, context=context)
|
||||
return True
|
||||
|
||||
def convert_opportunity(self, cr, uid, ids, partner_id, user_ids=False, section_id=False, context=None):
|
||||
partner = self.pool.get('res.partner')
|
||||
mail_message = self.pool.get('mail.message')
|
||||
customer = False
|
||||
if partner_id:
|
||||
customer = partner.browse(cr, uid, partner_id, context=context)
|
||||
for lead in self.browse(cr, uid, ids, context=context):
|
||||
if lead.state in ('done', 'cancel'):
|
||||
continue
|
||||
if user_ids or section_id:
|
||||
self.allocate_salesman(cr, uid, [lead.id], user_ids, section_id, context=context)
|
||||
|
||||
vals = self._convert_opportunity_data(cr, uid, lead, customer, section_id, context=context)
|
||||
self.write(cr, uid, [lead.id], vals, context=context)
|
||||
|
||||
self._convert_opportunity_notification(cr, uid, lead, context=context)
|
||||
#TOCHECK: why need to change partner details in all messages of lead ?
|
||||
if lead.partner_id:
|
||||
msg_ids = [ x.id for x in lead.message_ids]
|
||||
mail_message.write(cr, uid, msg_ids, {
|
||||
'partner_id': lead.partner_id.id
|
||||
}, context=context)
|
||||
return True
|
||||
|
||||
def _lead_create_partner(self, cr, uid, lead, context=None):
|
||||
partner = self.pool.get('res.partner')
|
||||
partner_id = partner.create(cr, uid, {
|
||||
'name': lead.partner_name or lead.contact_name or lead.name,
|
||||
'user_id': lead.user_id.id,
|
||||
'comment': lead.description,
|
||||
'section_id': lead.section_id.id or False,
|
||||
'address': []
|
||||
})
|
||||
return partner_id
|
||||
|
||||
def _lead_set_partner(self, cr, uid, lead, partner_id, context=None):
|
||||
res = False
|
||||
res_partner = self.pool.get('res.partner')
|
||||
if partner_id:
|
||||
res_partner.write(cr, uid, partner_id, {'section_id': lead.section_id.id or False})
|
||||
contact_id = res_partner.address_get(cr, uid, [partner_id])['default']
|
||||
res = lead.write({'partner_id' : partner_id, 'partner_address_id': contact_id}, context=context)
|
||||
|
||||
return res
|
||||
|
||||
def _lead_create_partner_address(self, cr, uid, lead, partner_id, context=None):
|
||||
address = self.pool.get('res.partner.address')
|
||||
return address.create(cr, uid, {
|
||||
'partner_id': partner_id,
|
||||
'name': lead.contact_name,
|
||||
'phone': lead.phone,
|
||||
'mobile': lead.mobile,
|
||||
'email': lead.email_from and to_email(lead.email_from)[0],
|
||||
'fax': lead.fax,
|
||||
'title': lead.title and lead.title.id or False,
|
||||
'function': lead.function,
|
||||
'street': lead.street,
|
||||
'street2': lead.street2,
|
||||
'zip': lead.zip,
|
||||
'city': lead.city,
|
||||
'country_id': lead.country_id and lead.country_id.id or False,
|
||||
'state_id': lead.state_id and lead.state_id.id or False,
|
||||
})
|
||||
|
||||
def convert_partner(self, cr, uid, ids, action='create', partner_id=False, context=None):
|
||||
"""
|
||||
This function convert partner based on action.
|
||||
if action is 'create', create new partner with contact and assign lead to new partner_id.
|
||||
otherwise assign lead to specified partner_id
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
context.update({'active_ids': ids})
|
||||
partner_ids = {}
|
||||
for lead in self.browse(cr, uid, ids, context=context):
|
||||
if action == 'create':
|
||||
if not partner_id:
|
||||
partner_id = self._lead_create_partner(cr, uid, lead, context=context)
|
||||
self._lead_create_partner_address(cr, uid, lead, partner_id, context=context)
|
||||
self._lead_set_partner(cr, uid, lead, partner_id, context=context)
|
||||
partner_ids[lead.id] = partner_id
|
||||
return partner_ids
|
||||
|
||||
data_obj = self.pool.get('ir.model.data')
|
||||
value = {}
|
||||
def _send_mail_to_salesman(self, cr, uid, lead, context=None):
|
||||
"""
|
||||
Send mail to salesman with updated Lead details.
|
||||
@ lead: browse record of 'crm.lead' object.
|
||||
"""
|
||||
#TOFIX: mail template should be used here instead of fix subject, body text.
|
||||
message = self.pool.get('mail.message')
|
||||
email_to = lead.user_id and lead.user_id.user_email
|
||||
if not email_to:
|
||||
return False
|
||||
|
||||
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)
|
||||
return message.schedule_with_attach(cr, uid, email_from, [email_to], subject, body)
|
||||
|
||||
|
||||
for case in self.browse(cr, uid, ids, context=context):
|
||||
context.update({'active_id': case.id})
|
||||
data_id = data_obj._get_id(cr, uid, 'crm', 'view_crm_lead2opportunity_partner')
|
||||
view_id1 = False
|
||||
if data_id:
|
||||
view_id1 = data_obj.browse(cr, uid, data_id, context=context).res_id
|
||||
value = {
|
||||
'name': _('Create Partner'),
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form,tree',
|
||||
'res_model': 'crm.lead2opportunity.partner',
|
||||
'view_id': False,
|
||||
'context': context,
|
||||
'views': [(view_id1, 'form')],
|
||||
'type': 'ir.actions.act_window',
|
||||
'target': 'new',
|
||||
'nodestroy': True
|
||||
def allocate_salesman(self, cr, uid, ids, user_ids, team_id=False, context=None):
|
||||
index = 0
|
||||
for lead_id in ids:
|
||||
value = {}
|
||||
if team_id:
|
||||
value['section_id'] = team_id
|
||||
if index < len(user_ids):
|
||||
value['user_id'] = user_ids[index]
|
||||
index += 1
|
||||
if value:
|
||||
self.write(cr, uid, [lead_id], value, context=context)
|
||||
return True
|
||||
|
||||
def schedule_phonecall(self, cr, uid, ids, schedule_time, call_summary, desc, phone, contact_name, user_id=False, section_id=False, categ_id=False, action='schedule', context=None):
|
||||
"""
|
||||
action :('schedule','Schedule a call'), ('log','Log a call')
|
||||
"""
|
||||
phonecall = self.pool.get('crm.phonecall')
|
||||
model_data = self.pool.get('ir.model.data')
|
||||
phonecall_dict = {}
|
||||
if not categ_id:
|
||||
res_id = model_data._get_id(cr, uid, 'crm', 'categ_phone2')
|
||||
if res_id:
|
||||
categ_id = model_data.browse(cr, uid, res_id, context=context).res_id
|
||||
for lead in self.browse(cr, uid, ids, context=context):
|
||||
if not section_id:
|
||||
section_id = lead.section_id and lead.section_id.id or False
|
||||
if not user_id:
|
||||
user_id = lead.user_id and lead.user_id.id or False
|
||||
vals = {
|
||||
'name' : call_summary,
|
||||
'opportunity_id' : lead.id,
|
||||
'user_id' : user_id or False,
|
||||
'categ_id' : categ_id or False,
|
||||
'description' : desc or '',
|
||||
'date' : schedule_time,
|
||||
'section_id' : section_id or False,
|
||||
'partner_id': lead.partner_id and lead.partner_id.id or False,
|
||||
'partner_address_id': lead.partner_address_id and lead.partner_address_id.id or False,
|
||||
'partner_phone' : phone or lead.phone or (lead.partner_address_id and lead.partner_address_id.phone or False),
|
||||
'partner_mobile' : lead.partner_address_id and lead.partner_address_id.mobile or False,
|
||||
'priority': lead.priority,
|
||||
}
|
||||
return value
|
||||
|
||||
new_id = phonecall.create(cr, uid, vals, context=context)
|
||||
phonecall.case_open(cr, uid, [new_id])
|
||||
if action == 'log':
|
||||
phonecall.case_close(cr, uid, [new_id])
|
||||
phonecall_dict[lead.id] = new_id
|
||||
return phonecall_dict
|
||||
|
||||
|
||||
def redirect_opportunity_view(self, cr, uid, opportunity_id, context=None):
|
||||
models_data = self.pool.get('ir.model.data')
|
||||
|
||||
# Get Opportunity views
|
||||
form_view = models_data.get_object_reference(cr, uid, 'crm', 'crm_case_form_view_oppor')
|
||||
tree_view = models_data.get_object_reference(cr, uid, 'crm', 'crm_case_tree_view_oppor')
|
||||
return {
|
||||
'name': _('Opportunity'),
|
||||
'view_type': 'form',
|
||||
'view_mode': 'tree, form',
|
||||
'res_model': 'crm.lead',
|
||||
'domain': [('type', '=', 'opportunity')],
|
||||
'res_id': int(opportunity_id),
|
||||
'view_id': False,
|
||||
'views': [(form_view and form_view[1] or False, 'form'),
|
||||
(tree_view and tree_view[1] or False, 'tree'),
|
||||
(False, 'calendar'), (False, 'graph')],
|
||||
'type': 'ir.actions.act_window',
|
||||
}
|
||||
|
||||
|
||||
def message_new(self, cr, uid, msg, custom_values=None, context=None):
|
||||
"""Automatically calls when new email message arrives"""
|
||||
|
@ -447,17 +791,10 @@ class crm_lead(crm_case, osv.osv):
|
|||
data_obj = self.pool.get('ir.model.data')
|
||||
for opp in self.browse(cr, uid, ids, context=context):
|
||||
# Get meeting views
|
||||
result = data_obj._get_id(cr, uid, 'crm', 'view_crm_case_meetings_filter')
|
||||
res = data_obj.read(cr, uid, result, ['res_id'])
|
||||
id1 = data_obj._get_id(cr, uid, 'crm', 'crm_case_calendar_view_meet')
|
||||
id2 = data_obj._get_id(cr, uid, 'crm', 'crm_case_form_view_meet')
|
||||
id3 = data_obj._get_id(cr, uid, 'crm', 'crm_case_tree_view_meet')
|
||||
if id1:
|
||||
id1 = data_obj.browse(cr, uid, id1, context=context).res_id
|
||||
if id2:
|
||||
id2 = data_obj.browse(cr, uid, id2, context=context).res_id
|
||||
if id3:
|
||||
id3 = data_obj.browse(cr, uid, id3, context=context).res_id
|
||||
tree_view = data_obj.get_object_reference(cr, uid, 'crm', 'crm_case_tree_view_meet')
|
||||
form_view = data_obj.get_object_reference(cr, uid, 'crm', 'crm_case_form_view_meet')
|
||||
calander_view = data_obj.get_object_reference(cr, uid, 'crm', 'crm_case_calendar_view_meet')
|
||||
search_view = data_obj.get_object_reference(cr, uid, 'crm', 'view_crm_case_meetings_filter')
|
||||
context.update({
|
||||
'default_opportunity_id': opp.id,
|
||||
'default_partner_id': opp.partner_id and opp.partner_id.id or False,
|
||||
|
@ -474,9 +811,9 @@ class crm_lead(crm_case, osv.osv):
|
|||
'view_mode': 'calendar,form,tree',
|
||||
'res_model': 'crm.meeting',
|
||||
'view_id': False,
|
||||
'views': [(id1, 'calendar'), (id2, 'form'), (id3, 'tree')],
|
||||
'views': [(calander_view and calander_view[1] or False, 'calendar'), (form_view and form_view[1] or False, 'form'), (tree_view and tree_view[1] or False, 'tree')],
|
||||
'type': 'ir.actions.act_window',
|
||||
'search_view_id': res['res_id'],
|
||||
'search_view_id': search_view and search_view[1] or False,
|
||||
'nodestroy': True
|
||||
}
|
||||
return value
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
<data>
|
||||
<!-- Demo Leads -->
|
||||
<record id="crm_case_itisatelesalescampaign0" model="crm.lead">
|
||||
<field name="type_id" ref="crm.type_lead1"/>
|
||||
|
@ -9,8 +9,8 @@
|
|||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval="'The Oil Company'" name="partner_name"/>
|
||||
<field eval="'draft'" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="'Luc Latour'" name="contact_name"/>
|
||||
<field name="section_id" ref="crm.section_sales_marketing_department"/>
|
||||
<field eval="'Luc Latour'" name="contact_name"/>
|
||||
<field name="title" ref="base.res_partner_title_sir"/>
|
||||
<field eval="'Training Manager'" name="function"/>
|
||||
<field eval="'Paris'" name="city"/>
|
||||
|
@ -92,7 +92,7 @@
|
|||
<field eval="'Bruxelles'" name="city"/>
|
||||
<field name="country_id" ref="base.be"/>
|
||||
<field eval="'draft'" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field name="section_id" ref="crm.section_sales_marketing_department"/>
|
||||
<field eval="'(333) 715-1450'" name="mobile"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field name="categ_id" ref="crm.categ_oppor1"/>
|
||||
|
|
|
@ -59,10 +59,11 @@
|
|||
widget="selection"
|
||||
domain="[('object_id.model','=','crm.lead')]"/>
|
||||
<button
|
||||
name="convert_opportunity"
|
||||
name="%(crm.action_crm_lead2opportunity_partner)d"
|
||||
string="Convert to Opportunity"
|
||||
help="Convert to Opportunity" icon="gtk-go-forward"
|
||||
type="object"/>
|
||||
type="action"
|
||||
/>
|
||||
<newline />
|
||||
<field name="user_id" />
|
||||
<field name="section_id" widget="selection" />
|
||||
|
@ -142,34 +143,6 @@
|
|||
type="object" icon="gtk-convert" />
|
||||
</group>
|
||||
</page>
|
||||
<page string="Extra Info" groups="base.group_extended">
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Categorization" colspan="2" col="2"/>
|
||||
<field name="company_id"
|
||||
groups="base.group_multi_company"
|
||||
widget="selection" colspan="2" />
|
||||
<field name="type_id" select="1" widget="selection"/>
|
||||
<field name="channel_id" select="1" widget="selection"/>
|
||||
<field name="referred"/>
|
||||
</group>
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Dates" colspan="2" col="2"/>
|
||||
<field name="create_date"/>
|
||||
<field name="write_date"/>
|
||||
<field name="date_open"/>
|
||||
<field name="date_closed"/>
|
||||
</group>
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Mailings" colspan="2" col="2"/>
|
||||
<field name="optin" on_change="on_change_optin(optin)"/>
|
||||
<field name="optout" on_change="on_change_optout(optout)"/>
|
||||
</group>
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Statistics" colspan="2" col="2"/>
|
||||
<field name="day_open"/>
|
||||
<field name="day_close"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Communication & History" groups="base.group_extended">
|
||||
<group colspan="4">
|
||||
<field colspan="4" name="email_cc" widget="char" size="512"/>
|
||||
|
@ -222,6 +195,34 @@
|
|||
name="%(mail.action_email_compose_message_wizard)d"
|
||||
icon="terp-mail-message-new" type="action"/>
|
||||
</page>
|
||||
<page string="Extra Info" groups="base.group_extended">
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Categorization" colspan="2" col="2"/>
|
||||
<field name="company_id"
|
||||
groups="base.group_multi_company"
|
||||
widget="selection" colspan="2" />
|
||||
<field name="type_id" select="1" widget="selection"/>
|
||||
<field name="channel_id" select="1" widget="selection"/>
|
||||
<field name="referred"/>
|
||||
</group>
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Dates" colspan="2" col="2"/>
|
||||
<field name="create_date"/>
|
||||
<field name="write_date"/>
|
||||
<field name="date_open"/>
|
||||
<field name="date_closed"/>
|
||||
</group>
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Mailings" colspan="2" col="2"/>
|
||||
<field name="optin" on_change="on_change_optin(optin)"/>
|
||||
<field name="optout" on_change="on_change_optout(optout)"/>
|
||||
</group>
|
||||
<group colspan="2" col="2">
|
||||
<separator string="Statistics" colspan="2" col="2"/>
|
||||
<field name="day_open"/>
|
||||
<field name="day_close"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</form>
|
||||
</field>
|
||||
|
@ -459,7 +460,7 @@
|
|||
<field name="name">Opportunities</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="type">form</field>
|
||||
<field name="priority">10</field>
|
||||
<field name="priority">20</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Opportunities">
|
||||
<group colspan="4" col="7">
|
||||
|
@ -705,6 +706,7 @@
|
|||
domain="[('state','=','pending')]"/>
|
||||
<separator orientation="vertical"/>
|
||||
<field name="name" string="Opportunity / Customer" filter_domain="['|','|','|',('partner_id','ilike',self),('partner_name','ilike',self),('email_from','ilike',self),('name', 'ilike', self)]"/>
|
||||
<field name="partner_id" string="Customer / Email" filter_domain="['|','|',('partner_id','ilike',self),('partner_name','ilike',self),('email_from','ilike',self)]"/>
|
||||
<field name="user_id">
|
||||
<filter icon="terp-personal-"
|
||||
domain="[('user_id','=', False)]"
|
||||
|
|
|
@ -102,11 +102,6 @@ class crm_phonecall(crm_base, osv.osv):
|
|||
|
||||
def case_close(self, cr, uid, ids, *args):
|
||||
"""Overrides close for crm_case for setting close date
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of case Ids
|
||||
@param *args: Tuple Value for additional Params
|
||||
"""
|
||||
res = True
|
||||
for phone in self.browse(cr, uid, ids):
|
||||
|
@ -121,11 +116,6 @@ class crm_phonecall(crm_base, osv.osv):
|
|||
|
||||
def case_reset(self, cr, uid, ids, *args):
|
||||
"""Resets case as Todo
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of case Ids
|
||||
@param *args: Tuple Value for additional Params
|
||||
"""
|
||||
res = super(crm_phonecall, self).case_reset(cr, uid, ids, args, 'crm.phonecall')
|
||||
self.write(cr, uid, ids, {'duration': 0.0})
|
||||
|
@ -134,25 +124,147 @@ class crm_phonecall(crm_base, osv.osv):
|
|||
|
||||
def case_open(self, cr, uid, ids, *args):
|
||||
"""Overrides cancel for crm_case for setting Open Date
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of case's Ids
|
||||
@param *args: Give Tuple Value
|
||||
"""
|
||||
res = super(crm_phonecall, self).case_open(cr, uid, ids, *args)
|
||||
self.write(cr, uid, ids, {'date_open': time.strftime('%Y-%m-%d %H:%M:%S')})
|
||||
return res
|
||||
|
||||
def schedule_another_phonecall(self, cr, uid, ids, schedule_time, call_summary, \
|
||||
user_id=False, section_id=False, categ_id=False, action='schedule', context=None):
|
||||
"""
|
||||
action :('schedule','Schedule a call'), ('log','Log a call')
|
||||
"""
|
||||
model_data = self.pool.get('ir.model.data')
|
||||
phonecall_dict = {}
|
||||
if not categ_id:
|
||||
res_id = model_data._get_id(cr, uid, 'crm', 'categ_phone2')
|
||||
if res_id:
|
||||
categ_id = model_data.browse(cr, uid, res_id, context=context).res_id
|
||||
for call in self.browse(cr, uid, ids, context=context):
|
||||
if not section_id:
|
||||
section_id = call.section_id and call.section_id.id or False
|
||||
if not user_id:
|
||||
user_id = call.user_id and call.user_id.id or False
|
||||
vals = {
|
||||
'name' : call_summary,
|
||||
'user_id' : user_id or False,
|
||||
'categ_id' : categ_id or False,
|
||||
'description' : call.description or False,
|
||||
'date' : schedule_time,
|
||||
'section_id' : section_id or False,
|
||||
'partner_id': call.partner_id and call.partner_id.id or False,
|
||||
'partner_address_id': call.partner_address_id and call.partner_address_id.id or False,
|
||||
'partner_phone' : call.partner_phone,
|
||||
'partner_mobile' : call.partner_mobile,
|
||||
'priority': call.priority,
|
||||
}
|
||||
|
||||
new_id = self.create(cr, uid, vals, context=context)
|
||||
self.case_open(cr, uid, [new_id])
|
||||
if action == 'log':
|
||||
self.case_close(cr, uid, [new_id])
|
||||
phonecall_dict[call.id] = new_id
|
||||
return phonecall_dict
|
||||
|
||||
def _call_create_partner(self, cr, uid, phonecall, context=None):
|
||||
partner = self.pool.get('res.partner')
|
||||
partner_id = partner.create(cr, uid, {
|
||||
'name': phonecall.name,
|
||||
'user_id': phonecall.user_id.id,
|
||||
'comment': phonecall.description,
|
||||
'address': []
|
||||
})
|
||||
return partner_id
|
||||
|
||||
def _call_set_partner(self, cr, uid, ids, partner_id, context=None):
|
||||
return self.write(cr, uid, ids, {'partner_id' : partner_id}, context=context)
|
||||
|
||||
def _call_create_partner_address(self, cr, uid, phonecall, partner_id, context=None):
|
||||
address = self.pool.get('res.partner.address')
|
||||
return address.create(cr, uid, {
|
||||
'partner_id': partner_id,
|
||||
'name': phonecall.name,
|
||||
'phone': phonecall.partner_phone,
|
||||
})
|
||||
|
||||
def convert_partner(self, cr, uid, ids, action='create', partner_id=False, context=None):
|
||||
"""
|
||||
This function convert partner based on action.
|
||||
if action is 'create', create new partner with contact and assign lead to new partner_id.
|
||||
otherwise assign lead to specified partner_id
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
partner_ids = {}
|
||||
for call in self.browse(cr, uid, ids, context=context):
|
||||
if action == 'create':
|
||||
if not partner_id:
|
||||
partner_id = self._call_create_partner(cr, uid, call, context=context)
|
||||
self._call_create_partner_address(cr, uid, call, partner_id, context=context)
|
||||
self._call_set_partner(cr, uid, [call.id], partner_id, context=context)
|
||||
partner_ids[call.id] = partner_id
|
||||
return partner_ids
|
||||
|
||||
|
||||
def redirect_phonecall_view(self, cr, uid, phonecall_id, context=None):
|
||||
model_data = self.pool.get('ir.model.data')
|
||||
# Select the view
|
||||
tree_view = model_data.get_object_reference(cr, uid, 'crm', 'crm_case_phone_tree_view')
|
||||
form_view = model_data.get_object_reference(cr, uid, 'crm', 'crm_case_phone_form_view')
|
||||
search_view = model_data.get_object_reference(cr, uid, 'crm', 'view_crm_case_phonecalls_filter')
|
||||
value = {
|
||||
'name': _('Phone Call'),
|
||||
'view_type': 'form',
|
||||
'view_mode': 'tree,form',
|
||||
'res_model': 'crm.phonecall',
|
||||
'res_id' : int(phonecall_id),
|
||||
'views': [(form_view and form_view[1] or False, 'form'), (tree_view and tree_view[1] or False, 'tree'), (False, 'calendar')],
|
||||
'type': 'ir.actions.act_window',
|
||||
'search_view_id': search_view and search_view[1] or False,
|
||||
}
|
||||
return value
|
||||
|
||||
|
||||
def convert_opportunity(self, cr, uid, ids, opportunity_summary=False, partner_id=False, planned_revenue=0.0, probability=0.0, context=None):
|
||||
partner = self.pool.get('res.partner')
|
||||
address = self.pool.get('res.partner.address')
|
||||
opportunity = self.pool.get('crm.lead')
|
||||
opportunity_dict = {}
|
||||
default_contact = False
|
||||
for call in self.browse(cr, uid, ids, context=context):
|
||||
if not partner_id:
|
||||
partner_id = call.partner_id and call.partner_id.id or False
|
||||
if partner_id:
|
||||
address_id = partner.address_get(cr, uid, [partner_id])['default']
|
||||
if address_id:
|
||||
default_contact = address.browse(cr, uid, address_id, context=context)
|
||||
opportunity_id = opportunity.create(cr, uid, {
|
||||
'name': opportunity_summary or call.name,
|
||||
'planned_revenue': planned_revenue,
|
||||
'probability': probability,
|
||||
'partner_id': partner_id or False,
|
||||
'partner_address_id': default_contact and default_contact.id,
|
||||
'phone': default_contact and default_contact.phone,
|
||||
'mobile': default_contact and default_contact.mobile,
|
||||
'section_id': call.section_id and call.section_id.id or False,
|
||||
'description': call.description or False,
|
||||
'priority': call.priority,
|
||||
'type': 'opportunity',
|
||||
'phone': call.partner_phone or False,
|
||||
})
|
||||
vals = {
|
||||
'partner_id': partner_id,
|
||||
'opportunity_id' : opportunity_id,
|
||||
}
|
||||
self.write(cr, uid, [call.id], vals)
|
||||
self.case_close(cr, uid, [call.id])
|
||||
opportunity.case_open(cr, uid, [opportunity_id])
|
||||
opportunity_dict[call.id] = opportunity_id
|
||||
return opportunity_dict
|
||||
|
||||
def action_make_meeting(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
This opens Meeting's calendar view to schedule meeting on current Phonecall
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Phonecall to Meeting IDs
|
||||
@param context: A standard dictionary for contextual values
|
||||
|
||||
@return : Dictionary value for created Meeting view
|
||||
"""
|
||||
value = {}
|
||||
|
|
|
@ -83,9 +83,6 @@
|
|||
<field eval="2.08" name="duration"/>
|
||||
</record>
|
||||
<record id="crm_case_phone06" model="crm.phonecall">
|
||||
<field name="partner_address_id" ref="base.res_partner_address_1"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field name="partner_id" ref="base.res_partner_9"/>
|
||||
<field eval=""3"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval=""Bad time"" name="name"/>
|
||||
|
|
|
@ -33,6 +33,44 @@ class res_partner(osv.osv):
|
|||
'phonecall_ids': fields.one2many('crm.phonecall', 'partner_id',\
|
||||
'Phonecalls'),
|
||||
}
|
||||
|
||||
def redirect_partner_form(self, cr, uid, partner_id, context=None):
|
||||
search_view = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'view_res_partner_filter')
|
||||
value = {
|
||||
'domain': "[]",
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form,tree',
|
||||
'res_model': 'res.partner',
|
||||
'res_id': int(partner_id),
|
||||
'view_id': False,
|
||||
'context': context,
|
||||
'type': 'ir.actions.act_window',
|
||||
'search_view_id': search_view and search_view[1] or False
|
||||
}
|
||||
return value
|
||||
|
||||
def make_opportunity(self, cr, uid, ids, opportunity_summary, planned_revenue=0.0, probability=0.0, partner_id=None, context=None):
|
||||
categ = self.pool.get('crm.case.categ')
|
||||
address = self.address_get(cr, uid, ids)
|
||||
categ_ids = categ.search(cr, uid, [('object_id.model','=','crm.lead')])
|
||||
lead = self.pool.get('crm.lead')
|
||||
opportunity_ids = {}
|
||||
for partner in self.browse(cr, uid, ids, context=context):
|
||||
address = self.address_get(cr, uid, [partner.id])['default']
|
||||
if not partner_id:
|
||||
partner_id = partner.id
|
||||
opportunity_id = lead.create(cr, uid, {
|
||||
'name' : opportunity_summary,
|
||||
'planned_revenue' : planned_revenue,
|
||||
'probability' : probability,
|
||||
'partner_id' : partner_id,
|
||||
'partner_address_id' : address,
|
||||
'categ_id' : categ_ids and categ_ids[0] or '',
|
||||
'state' :'draft',
|
||||
'type': 'opportunity'
|
||||
})
|
||||
opportunity_ids[partner_id] = opportunity_id
|
||||
return opportunity_ids
|
||||
res_partner()
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
Return-Path: <info@customer.com>
|
||||
X-Original-To: info@customer.com
|
||||
Delivered-To: sales@my.com
|
||||
Received: by mail.my.com (Postfix, from userid xxx)
|
||||
id 822ECBFB67; Mon, 24 Oct 2011 07:36:51 +0200 (CEST)
|
||||
X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.my.com
|
||||
X-Spam-Level:
|
||||
X-Spam-Status: No, score=-1.0 required=5.0 tests=ALL_TRUSTED autolearn=ham
|
||||
version=3.3.1
|
||||
Received: from [192.168.1.146]
|
||||
(Authenticated sender: info@mail.customer.com)
|
||||
by mail.customer.com (Postfix) with ESMTPSA id 07A30BFAB4
|
||||
for <sales@my.com>; Mon, 24 Oct 2011 07:36:50 +0200 (CEST)
|
||||
Message-ID: <4EA4F95D.904@customer.com>
|
||||
Date: Mon, 24 Oct 2011 11:06:29 +0530
|
||||
From: Mr. John Right <info@customer.com>
|
||||
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.14) Gecko/20110223 Lightning/1.0b2 Thunderbird/3.1.8
|
||||
MIME-Version: 1.0
|
||||
To: sales@my.com
|
||||
Subject: Fournir votre devis avec le meilleur prix.
|
||||
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Bonjour l'équipe de vente,
|
||||
|
||||
Je veux acheter vos produits et services.
|
||||
|
||||
S'il vous plaît fournir votre cotation avec le meilleur prix.
|
||||
|
||||
Merci
|
|
@ -0,0 +1,53 @@
|
|||
-
|
||||
I cancel unqualified lead.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_cancel(cr, uid, [ref("crm_case_itisatelesalescampaign0")])
|
||||
-
|
||||
I check cancelled lead.
|
||||
-
|
||||
!assert {model: crm.lead, id: crm.crm_case_itisatelesalescampaign0, string: Lead is in cancel state}:
|
||||
- state == "cancel"
|
||||
-
|
||||
I reset cancelled lead into unqualified lead.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_reset(cr, uid, [ref("crm_case_itisatelesalescampaign0")])
|
||||
-
|
||||
I check unqualified lead after reset.
|
||||
-
|
||||
!assert {model: crm.lead, id: crm.crm_case_itisatelesalescampaign0, string: Lead is in draft state}:
|
||||
- state == "draft"
|
||||
-
|
||||
I put unqualified lead into pending.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_pending(cr, uid, [ref("crm_case_itisatelesalescampaign0")])
|
||||
-
|
||||
I check status of pending lead.
|
||||
-
|
||||
!assert {model: crm.lead, id: crm.crm_case_itisatelesalescampaign0, string: Lead is in pending state}:
|
||||
- state == "pending"
|
||||
-
|
||||
I Escalate the Lead to Parent Team.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_escalate(cr, uid, [ref("crm_case_itisatelesalescampaign0")])
|
||||
-
|
||||
I check lead escalate to Parent Team.
|
||||
-
|
||||
!assert {model: crm.lead, id: crm.crm_case_itisatelesalescampaign0, string: Escalate lead to parent team}:
|
||||
- section_id.name == "Sales Department"
|
||||
-
|
||||
I mark as lost the opportunity.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_mark_lost(cr, uid, [ref("crm_case_itisatelesalescampaign0")])
|
||||
-
|
||||
I check opportunity after lost.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
lead = self.browse(cr, uid, ref('crm_case_itisatelesalescampaign0'))
|
||||
assert lead.state == 'done', "lead is not done state"
|
||||
assert lead.stage_id.id == ref('crm.stage_lead6'), 'Stage is not changed!'
|
||||
assert lead.probability == 0.0, 'Probability is wrong!'
|
|
@ -0,0 +1,56 @@
|
|||
-
|
||||
Customer interested in our product. so He send request by email to get more details.
|
||||
-
|
||||
Mail script will be fetched him request from mail server. so I process that mail after read EML file
|
||||
-
|
||||
!python {model: mail.thread}: |
|
||||
import addons
|
||||
request_file = open(addons.get_module_resource('crm','test', 'customer_request.eml'),'rb')
|
||||
request_message = request_file.read()
|
||||
self.message_process(cr, uid, 'crm.lead', request_message)
|
||||
-
|
||||
After getting the mail, I check details of new lead of that customer.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
lead_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
|
||||
assert lead_ids and len(lead_ids), "Lead is not created after getting request"
|
||||
lead = self.browse(cr, uid, lead_ids[0], context=context)
|
||||
assert not lead.partner_id, "Customer should be a new"
|
||||
assert lead.name == "Fournir votre devis avec le meilleur prix.", "Subject does not match"
|
||||
-
|
||||
I reply him request with welcome message.
|
||||
-
|
||||
!python {model: mail.compose.message}: |
|
||||
lead_ids = self.pool.get('crm.lead').search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
|
||||
context.update({'active_model': 'crm.lead','active_id': lead_ids[0]})
|
||||
id = self.create(cr, uid, {'body_text': "Merci à l'intérêt pour notre produit.nous vous contacterons bientôt. Merci", 'email_from': 'sales@mycompany.com'}, context=context)
|
||||
try:
|
||||
self.send_mail(cr, uid, [id], context=context)
|
||||
except:
|
||||
pass
|
||||
-
|
||||
Now, I convert him into customer and put into regular customer list.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
lead_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
|
||||
self.convert_partner(cr, uid, lead_ids, context=context)
|
||||
-
|
||||
Now, I search customer in regular customer list.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
partner_ids = self.message_partner_by_email(cr, uid, 'Mr. John Right <info@customer.com>')
|
||||
assert partner_ids.get('partner_id'), "Customer is not found in regular customer list."
|
||||
-
|
||||
I convert one phonecall request as a customer and put into regular customer list.
|
||||
-
|
||||
!python {model: crm.phonecall}: |
|
||||
self.convert_partner(cr, uid, [ref('crm.crm_case_phone06')], context=context)
|
||||
-
|
||||
I check converted phonecall to partner.
|
||||
-
|
||||
!python {model: res.partner}: |
|
||||
partner_id = self.search(cr, uid, [('phonecall_ids', '=', ref('crm.crm_case_phone06'))])
|
||||
assert partner_id, "Customer is not found in regular customer list."
|
||||
data = self.browse(cr, uid, partner_id, context=context)[0]
|
||||
assert data.user_id.id == ref("base.user_root"), "User not assign properly"
|
||||
assert data.name == "Bad time", "User not assign properly"
|
|
@ -0,0 +1,90 @@
|
|||
-
|
||||
In order to test convert customer lead into opportunity,
|
||||
-
|
||||
I open customer lead.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_open(cr, uid, [ref("crm_case_qrecorp0")])
|
||||
-
|
||||
I check lead state is "Open".
|
||||
-
|
||||
!assert {model: crm.lead, id: crm.crm_case_qrecorp0, string: Lead in open state}:
|
||||
- state == "open"
|
||||
-
|
||||
I convert lead into opportunity for exiting customer.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.convert_opportunity(cr, uid ,[ref("crm_case_qrecorp0")], ref("base.res_partner_agrolait"))
|
||||
-
|
||||
I check details of converted opportunity.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
lead = self.browse(cr, uid, ref('crm_case_qrecorp0'))
|
||||
assert lead.type == 'opportunity', 'Lead is not converted to opportunity!'
|
||||
assert lead.partner_id.id == ref("base.res_partner_agrolait"), 'Partner missmatch!'
|
||||
assert lead.stage_id.id == ref("stage_lead1"), 'Stage of opportunity is incorrect!'
|
||||
-
|
||||
Now I begin communication and schedule a phone call with the customer.
|
||||
-
|
||||
!python {model: crm.opportunity2phonecall}: |
|
||||
import time
|
||||
context.update({'active_model': 'crm.lead', 'active_ids': [ref('crm_case_qrecorp0')]})
|
||||
call_id = self.create(cr, uid, {'date': time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'name': "Bonjour M. Jean, Comment êtes-vous? J'ai obtenu votre demande. peut-on parler au sujet de ce pour quelques minutes?"}, context=context)
|
||||
self.action_schedule(cr, uid, [call_id], context=context)
|
||||
-
|
||||
I check that phonecall is scheduled for that opportunity.
|
||||
-
|
||||
!python {model: crm.phonecall}: |
|
||||
ids = self.search(cr, uid, [('opportunity_id', '=', ref('crm_case_qrecorp0'))])
|
||||
assert len(ids), 'phonecall is not scheduled'
|
||||
-
|
||||
Now I schedule Meeting with Customer.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.action_makeMeeting(cr, uid, [ref('crm_case_qrecorp0')])
|
||||
|
||||
-
|
||||
After communicated with customer, I put some notes with Contract details.
|
||||
-
|
||||
!python {model: crm.add.note}: |
|
||||
context.update({'active_model': 'crm.lead', 'active_id': ref('crm_case_qrecorp0')})
|
||||
note_id = self.create(cr, uid, {'body': "ces détails envoyés par le client sur le FAX pour la qualité"})
|
||||
self.action_add(cr, uid, [note_id], context=context)
|
||||
-
|
||||
Finally, I won this opportunity, so I close this opportunity.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_mark_won(cr, uid, [ref("crm_case_qrecorp0")])
|
||||
-
|
||||
I check details of the opportunity After won the opportunity.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
lead = self.browse(cr, uid, ref('crm_case_qrecorp0'))
|
||||
assert lead.state == 'done', 'Opportunity is not in done state!'
|
||||
assert lead.stage_id.name == 'Won', ' Stage of Opportunity is not win!'
|
||||
assert lead.probability == 100.0, 'probability revenue should not be 100.0!'
|
||||
-
|
||||
I convert mass lead into opportunity customer.
|
||||
-
|
||||
!python {model: crm.lead2opportunity.partner.mass}: |
|
||||
context.update({'active_model': 'crm.lead', 'active_ids': [ref("crm_case_employee0"), ref("crm_case_electonicgoodsdealer0")], 'active_id': ref("crm_case_qrecorp0")})
|
||||
id = self.create(cr, uid, {'user_ids': [ref('base.user_root')], 'section_id': ref('crm.section_sales_department')}, context=context)
|
||||
self.mass_convert(cr, uid, [id], context=context)
|
||||
-
|
||||
Now I check First lead converted on opportunity.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
opp = self.browse(cr, uid, ref('crm_case_employee0'))
|
||||
assert opp.name == "Need Info about Onsite Intervention", "Opportunity name not correct"
|
||||
assert opp.type == 'opportunity', 'Lead is not converted to opportunity!'
|
||||
assert opp.partner_id.name == "Agrolait", 'Partner missmatch!'
|
||||
assert opp.stage_id.id == ref("stage_lead1"), 'Stage of probability is incorrect!'
|
||||
-
|
||||
Then check for Second lead converted on opportunity.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
opp = self.browse(cr, uid, ref('crm_case_electonicgoodsdealer0'))
|
||||
assert opp.name == "Interest in Your New Product", "Opportunity name not correct"
|
||||
assert opp.type == 'opportunity', 'Lead is not converted to opportunity!'
|
||||
assert opp.stage_id.id == ref("stage_lead1"), 'Stage of probability is incorrect!'
|
|
@ -0,0 +1,51 @@
|
|||
-
|
||||
I make direct opportunity for Customer.
|
||||
-
|
||||
!python {model: crm.partner2opportunity}: |
|
||||
context.update({'active_model': 'res.partner', 'active_ids': [ref("base.res_partner_9")]})
|
||||
res_id = self.create(cr, uid, {'name': "enquête pour l'achat de services"}, context=context)
|
||||
self.make_opportunity(cr, uid, [res_id], context=context)
|
||||
-
|
||||
I make another opportunity from phonecall for same customer.
|
||||
-
|
||||
!python {model: crm.phonecall2opportunity}: |
|
||||
context.update({'active_model': 'crm.phonecall', 'active_ids': [ref("crm.crm_case_phone06")]})
|
||||
res_id = self.create(cr, uid, {'name': "Quoi de prix de votre autre service?", 'partner_id': ref("base.res_partner_9")}, context=context)
|
||||
self.make_opportunity(cr, uid, [res_id], context=context)
|
||||
-
|
||||
Now I merge all opportunities of customer.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
opportunity_ids = self.search(cr, uid, [('partner_id','=', ref("base.res_partner_9"))])
|
||||
self.merge_opportunity(cr, uid, opportunity_ids, context=context)
|
||||
-
|
||||
I check for merged opportunities for customer.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
merge_id = self.search(cr, uid, [('partner_id','=', ref("base.res_partner_9"))])
|
||||
assert merge_id, 'Fail to create Merge opportunity'
|
||||
merge_data = self.browse(cr, uid, merge_id)[0]
|
||||
assert merge_data.type == 'opportunity', 'Merged opportunity type not change!'
|
||||
assert merge_data.partner_id.id == ref("base.res_partner_9"), 'Partner missmatch!'
|
||||
-
|
||||
Now I schedule another phonecall to customer after merged.
|
||||
-
|
||||
!python {model: crm.phonecall2phonecall}: |
|
||||
context.update({'active_model': 'crm.phonecall', 'active_ids': [ref("crm.crm_case_phone06")]})
|
||||
res_id = self.create(cr, uid, {'name': "vos chances sont fusionnés en un seul"}, context=context)
|
||||
self.action_schedule(cr, uid, [res_id], context=context)
|
||||
-
|
||||
I schedule Meeting on this phonecall.
|
||||
-
|
||||
!python {model: crm.phonecall}: |
|
||||
self.action_make_meeting(cr, uid, [ref("crm.crm_case_phone06")])
|
||||
-
|
||||
I setting Phone call to Held (Done).
|
||||
-
|
||||
!python {model: crm.phonecall}: |
|
||||
self.case_close(cr, uid, [ref("crm.crm_case_phone06")])
|
||||
-
|
||||
I check that the phone call is in 'Held' state.
|
||||
-
|
||||
!assert {model: crm.phonecall, id: crm.crm_case_phone06, string: Phone call Helded}:
|
||||
- state == "done"
|
|
@ -0,0 +1,16 @@
|
|||
-
|
||||
In order to test segmentation process which create specific partner categories criteria,
|
||||
-
|
||||
I start the process.
|
||||
-
|
||||
!python {model: crm.segmentation}: |
|
||||
self.process_start(cr, uid, [ref("crm_segmentation0")],context)
|
||||
#Todo: Need to check after segmentation started
|
||||
|
||||
-
|
||||
I create rule Segmentation line record for partner .
|
||||
-
|
||||
!python {model: crm.segmentation.line}: |
|
||||
id = self.create(cr, uid, {'name': "OpenERP partners",'expr_value': 25})
|
||||
self.test(cr, uid, [id],partner_id=0)
|
||||
#Todo: Need to test segmantation line record
|
|
@ -1,154 +0,0 @@
|
|||
-
|
||||
In order to test the CRM in OpenERP, I will do a customer qualification
|
||||
process that starts with a fist contact with a customer (a lead), which will
|
||||
be converted to a business opportunity and a partner.
|
||||
-
|
||||
I create a two new users "user_crm" and I assign the group "salesman".
|
||||
-
|
||||
!record {model: res.users, id: res_users_usercrm0}:
|
||||
company_id: base.main_company
|
||||
context_lang: en_US
|
||||
context_section_id: crm.section_sales_department
|
||||
groups_id:
|
||||
- base.group_sale_salesman
|
||||
login: user_crm
|
||||
name: user_crm
|
||||
password: user_crm
|
||||
|
||||
- |
|
||||
I start by creating a new lead "New Customer" and I provide an address to this
|
||||
new customer, as well as an email "info@mycustomer.com".
|
||||
-
|
||||
!record {model: crm.lead, id: crm_lead_newcustomer0}:
|
||||
email_from: info@mycustomer.com
|
||||
name: New Customer
|
||||
partner_name: Capegemini
|
||||
partner_id: base.res_partner_9
|
||||
phone: (855) 924-4364
|
||||
mobile: (333) 715-1450
|
||||
section_id: crm.section_sales_department
|
||||
referred: False
|
||||
- |
|
||||
I check that the lead is in 'draft' state.
|
||||
-
|
||||
!assert {model: crm.lead, id: crm_lead_newcustomer0, string: Lead in Draft}:
|
||||
- state == "draft"
|
||||
-
|
||||
I open lead by click on "Open" button.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_open(cr, uid, [ref("crm_lead_newcustomer0")])
|
||||
fields={
|
||||
'day_open': 0.0,
|
||||
'day_close': 0.0
|
||||
}
|
||||
self._compute_day(cr, uid, [ref("crm_lead_newcustomer0")], fields, context)
|
||||
- |
|
||||
I check that lead is now in 'open' state.
|
||||
-
|
||||
!assert {model: crm.lead, id: crm_lead_newcustomer0, string: Lead in open state}:
|
||||
- state == "open"
|
||||
-
|
||||
I search id for case object.
|
||||
-
|
||||
!python {model: crm.case.categ}: |
|
||||
self._find_object_id(cr, uid, context)
|
||||
- |
|
||||
As the lead seems to be a real business opportunity, I will convert it to a
|
||||
partner
|
||||
and a business opportunity by clicking on the "Convert" button.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
lead = self.browse(cr, uid, ref('crm_lead_newcustomer0'))
|
||||
action = self.convert_opportunity(cr, uid, [ref("crm_lead_newcustomer0")], {'active_ids': [ref("crm_lead_newcustomer0")]})
|
||||
assert action['res_model'] == 'crm.lead2opportunity.partner'
|
||||
-
|
||||
|
|
||||
I select "create a new partner" option.
|
||||
-
|
||||
!record {model: crm.lead2opportunity.partner, id: crm_lead2opportunity_partner_create_0}:
|
||||
action: 'create'
|
||||
name: 'convert'
|
||||
-
|
||||
Then, Click on "Create Opportunity" button.
|
||||
-
|
||||
!python {model: crm.lead2opportunity.partner}: |
|
||||
self.action_apply(cr, uid, [ref("crm_lead2opportunity_partner_create_0")], {'active_ids': [ref("crm_lead_newcustomer0")], 'active_id': ref("crm_lead_newcustomer0")})
|
||||
-
|
||||
|
|
||||
I select "Link to an existing partner" option.
|
||||
-
|
||||
!record {model: crm.lead2opportunity.partner, id: crm_lead2opportunity_partner_create_1}:
|
||||
action: 'exist'
|
||||
-
|
||||
Then, Click on "Create Opportunity" button.
|
||||
-
|
||||
!python {model: crm.lead2opportunity.partner}: |
|
||||
self.action_apply(cr, uid, [ref("crm_lead2opportunity_partner_create_1")], {'active_ids': [ref("crm_lead_newcustomer0")], 'active_id': ref("crm_lead_newcustomer0")})
|
||||
-
|
||||
|
|
||||
I select "Do not link to a partner" option.
|
||||
-
|
||||
!record {model: crm.lead2opportunity.partner, id: crm_lead2opportunity_partner_create_2}:
|
||||
action: 'nothing'
|
||||
-
|
||||
Then, Click on "Create Opportunity" button.
|
||||
-
|
||||
!python {model: crm.lead2opportunity.partner}: |
|
||||
self.action_apply(cr, uid, [ref("crm_lead2opportunity_partner_create_2")], {'active_ids': [ref("crm_lead_newcustomer0")], 'active_id': ref("crm_lead_newcustomer0")})
|
||||
- |
|
||||
In order to check the opportunity is created or not, I check type.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
lead = self.browse(cr, uid, ref("crm_lead_newcustomer0"))
|
||||
assert lead.type == 'opportunity'
|
||||
|
||||
-
|
||||
I create mass report of lead to opprtunity partner.
|
||||
-
|
||||
!record {model: crm.lead2opportunity.partner.mass, id: crm_lead2opportunity_partner_mass0}:
|
||||
user_ids:
|
||||
- base.user_root
|
||||
section_id: crm.section_sales_department
|
||||
-
|
||||
Then, execute that mass wizard.
|
||||
-
|
||||
!python {model: crm.lead2opportunity.partner.mass}: |
|
||||
self.mass_convert(cr, uid, [ref("crm_lead2opportunity_partner_mass0")],{'active_ids': [ref("crm_lead_newcustomer0")], 'active_id': ref("crm_lead_newcustomer0")})
|
||||
-
|
||||
I close lead by click on "close" button.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_close(cr, uid, [ref("crm_lead_newcustomer0")])
|
||||
- |
|
||||
I check that lead is now in 'done' state.
|
||||
-
|
||||
!assert {model: crm.lead, id: crm_lead_newcustomer0, string: Lead in done state}:
|
||||
- state == "done"
|
||||
-
|
||||
I cancel lead by click on "cancel" button.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_cancel(cr, uid, [ref("crm_lead_newcustomer0")])
|
||||
- |
|
||||
I check that lead is now in 'cancel' state.
|
||||
-
|
||||
!assert {model: crm.lead, id: crm_lead_newcustomer0, string: Lead in cancel state}:
|
||||
- state == "cancel"
|
||||
|
||||
#-
|
||||
# |
|
||||
# yaml is also not working with smtp server and send new email.
|
||||
|
||||
- |
|
||||
I configure with smtp server.
|
||||
- |
|
||||
And I communicate with lead through send New mail to Lead using its email address from the user who is logged in.
|
||||
- |
|
||||
I check that communication history generated when send email to lead.
|
||||
- |
|
||||
Then, I add a cc which receive copy of future communication between partner and users by mail.
|
||||
|
||||
- |
|
||||
I Reply to last Email to lead with some document attached.and check that communication history generated or not.
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
-
|
||||
In order to do complete test the CRM in OpenERP,
|
||||
I will create new full configured record and carry test on it.
|
||||
- |
|
||||
I Start by creating "Test Sales Team" with No Unlink.
|
||||
I create a crm.case.section record.
|
||||
-
|
||||
!record {model: crm.case.section, id: crm_case_section_demosalesteam}:
|
||||
code: DEMO
|
||||
complete_name: Test Sales Team
|
||||
name: Test Sales Team
|
||||
allow_unlink: False
|
||||
member_ids:
|
||||
- base.user_admin
|
||||
stage_ids:
|
||||
- crm.stage_lead1
|
||||
- crm.stage_lead2
|
||||
- crm.stage_lead3
|
||||
- crm.stage_lead4
|
||||
- crm.stage_lead5
|
||||
- crm.stage_lead6
|
||||
working_hours: 0.0
|
||||
resource_calendar_id: resource.timesheet_group1
|
||||
parent_id: crm.section_sales_department
|
||||
-
|
||||
I assign segmentation.
|
||||
-
|
||||
!record {model: res.users, id: res_users_usercrm0}:
|
||||
context_section_id: crm_case_section_demosalesteam
|
||||
- |
|
||||
I create a new lead "Test Customer" and I provide an address to this
|
||||
demo customer and email "info@democustomer.com" and Also "Test Sales Team".
|
||||
-
|
||||
!record {model: crm.lead, id: crm_lead_democustomer}:
|
||||
email_from: info@democustomer.com
|
||||
name: Test Customer
|
||||
partner_name: NotSoTinySARL
|
||||
phone: (+32).81.81.37.00
|
||||
mobile: (+32).81.81.37.00
|
||||
section_id: crm_case_section_demosalesteam
|
||||
referred: False
|
||||
type: lead
|
||||
-
|
||||
I check that the lead is in 'draft' state.
|
||||
-
|
||||
!assert {model: crm.lead, id: crm_lead_democustomer, string: Lead in Draft}:
|
||||
- state == "draft"
|
||||
-
|
||||
I create categories.
|
||||
-
|
||||
!record {model: crm.case.categ, id: crm_case_categ0}:
|
||||
name: crm_case_section_demosalesteam
|
||||
section_id: crm_case_section_demosalesteam
|
||||
-
|
||||
I assigning contact detail to the Lead "Test Customer" without address.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.onchange_partner_address_id(cr, uid, ref("crm_lead_democustomer"), None, email=False)
|
||||
|
||||
-
|
||||
I assigning contact detail to the Lead "Test Customer" with address.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.onchange_partner_address_id(cr, uid, ref("crm_lead_democustomer"), ref("base.res_partner_address_notsotinysarl0"), email=False)
|
||||
|
||||
-
|
||||
I selecting email "Opt-out" option for the "Test Customer" Lead.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.on_change_optout(cr, uid, ref("crm_lead_democustomer"), True)
|
||||
|
||||
-
|
||||
I change the Opt-out to Opt-in to show email receive preference.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.on_change_optin(cr, uid, ref("crm_lead_democustomer"), True)
|
||||
-
|
||||
I open lead by click on "Open" button.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_open(cr, uid, [ref("crm_lead_democustomer")])
|
||||
-
|
||||
I check that lead "Test Customer" is now in 'open' state.
|
||||
-
|
||||
!assert {model: crm.lead, id: crm_lead_democustomer, string: Lead in open state}:
|
||||
- state == "open"
|
||||
-
|
||||
I reset the lead "Test Customer".
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_reset(cr, uid, [ref("crm_lead_democustomer")])
|
||||
-
|
||||
I again opening lead by click on "Open" button.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_open(cr, uid, [ref("crm_lead_democustomer")])
|
||||
-
|
||||
I setting stage "New" for the lead "Test Customer".
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.stage_next(cr, uid, [ref("crm_lead_democustomer")], context={'stage_type': 'lead'})
|
||||
-
|
||||
I try to Unlink the Lead "Test Customer" demo Lead.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
try:
|
||||
self.unlink(cr, uid, [ref("crm_lead_democustomer")])
|
||||
except:
|
||||
pass
|
||||
-
|
||||
I setting Lead "Test Customer" to Pending State.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_pending(cr, uid, [ref("crm_lead_democustomer")])
|
||||
-
|
||||
I check that lead "Test Customer" is now in 'Pending' state.
|
||||
-
|
||||
!assert {model: crm.lead, id: crm_lead_democustomer, string: Lead in Pending state}:
|
||||
- state == "pending"
|
||||
-
|
||||
I Escalate the Lead "Test Customer" Parent "Sales Team".
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_escalate(cr, uid, [ref("crm_lead_democustomer")])
|
||||
-
|
||||
I add Internal Note Saying Escalated Reason.
|
||||
-
|
||||
!record {model: crm.add.note, id: crm_add_note_0}:
|
||||
body: Sales Lead Has Been Escalated Due to Some Technical reason to the parent 'Sales
|
||||
Team'
|
||||
state: unchanged
|
||||
-
|
||||
I click a note button to attach the record.
|
||||
-
|
||||
!python {model: crm.add.note}: |
|
||||
context['active_model'] = "crm.lead"
|
||||
context['active_ids'] = [ref("crm_lead_democustomer")]
|
||||
self.action_add(cr, uid, [ref("crm_add_note_0")], context=context)
|
||||
|
||||
-
|
||||
I Copying this lead "Test Customer" to New Lead.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.copy(cr, uid, ref("crm_lead_democustomer"))
|
||||
-
|
||||
I checking the Lead Copied or Not.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
sid = self.search(cr, uid, [('name', '=', 'Test Customer'),('state', '=', 'draft')])
|
||||
if not sid:
|
||||
raise AssertionError("Lead is not copied Successfully")
|
|
@ -1,97 +0,0 @@
|
|||
- |
|
||||
I will test Meetings which may be customer meeting or phonecall meeting or
|
||||
internal Meeting.
|
||||
- |
|
||||
I start by creating a new Meeting.
|
||||
-
|
||||
!record {model: crm.meeting, id: crm_meeting_regardingpresentation0}:
|
||||
categ_id: crm.categ_meet2
|
||||
date: !eval time.strftime('%Y-%m-%d 16:04:00')
|
||||
date_deadline: !eval "(datetime.now() + timedelta(1)).strftime('%Y-%m-%d 00:04:00')"
|
||||
duration: 8.0
|
||||
email_from: info@balmerinc.be
|
||||
location: Ahmedabad
|
||||
name: Regarding Presentation
|
||||
partner_address_id: base.res_partner_address_1
|
||||
partner_id: base.res_partner_9
|
||||
rrule_type: weekly
|
||||
section_id: crm.section_sales_department
|
||||
- |
|
||||
I check that the Meetings is in 'UnConfirmed' state.
|
||||
-
|
||||
!assert {model: crm.meeting, id: crm_meeting_regardingpresentation0}:
|
||||
- state == "draft"
|
||||
- |
|
||||
I can set reminder on meeting if I put reminder "40 minutes before" .
|
||||
- |
|
||||
For that, I first create alarm.
|
||||
-
|
||||
!record {model: res.alarm, id: res_alarm_minituesbefore0}:
|
||||
name: 40 minutes before
|
||||
trigger_duration: 40
|
||||
trigger_interval: minutes
|
||||
trigger_occurs: before
|
||||
trigger_related: start
|
||||
- |
|
||||
I will assign this reminder.
|
||||
|
||||
- !python {model: crm.meeting}: |
|
||||
self.write(cr, uid, [ref('crm_meeting_regardingpresentation0')], {'alarm_id': ref("res_alarm_minituesbefore0")})
|
||||
- |
|
||||
In order to check recurrence on meetings I will set Recurrency to Custom
|
||||
and I set the fields so that the meeting will occur weekly on Monday and Friday 10 times.
|
||||
-
|
||||
!python {model: crm.meeting}: |
|
||||
self.write(cr, uid, [ref("crm_meeting_regardingpresentation0")], {'fr': 1, 'mo': 1, 'th': 1, 'tu': 1, 'we':1, 'count':10, 'interval': 1, 'rrule_type': 'weekly', 'recurrency' : True})
|
||||
|
||||
- |
|
||||
I can see from the calendar view that the meeting is scheduled on Monday and Friday
|
||||
for 10 times.
|
||||
|
||||
-
|
||||
!python {model: crm.meeting}: |
|
||||
self.fields_view_get(cr, uid, False, 'calendar', context)
|
||||
- |
|
||||
I will search for one of the recurrent event and count the number of meeting.
|
||||
-
|
||||
!python {model: crm.meeting}: |
|
||||
import time
|
||||
from datetime import datetime, date, timedelta
|
||||
ids = self.search(cr, uid, [('date', '>=', time.strftime('%Y-%m-%d 00:00:00')), ('date', '<=', (datetime.now()+timedelta(31)).strftime('%Y-%m-%d 00:00:00')), ('name', '=', 'Regarding Presentation')], context={'virtual_id': True})
|
||||
assert len(ids) == 10
|
||||
|
||||
- |
|
||||
If I want to edit meetings information for all occurrence I click on "Edit All" button.
|
||||
-
|
||||
!python {model: crm.meeting}: |
|
||||
self.write(cr, uid, [ref('crm_meeting_regardingpresentation0')], {'edit_all':'True'},context)
|
||||
- |
|
||||
I can see that new meeting form is opened with same value.
|
||||
I change some data for meeting and save it.
|
||||
I can see from meeting's calendar view that all meeting occurrences are changed accordingly.
|
||||
-
|
||||
!record {model: crm.meeting, id: crm.crm_meeting_regardingpresentation0}:
|
||||
alarm_id: base_calendar.alarm9
|
||||
rrule_type: weekly
|
||||
|
||||
- |
|
||||
In order to invite people for this meetings, I click on "Invite People" button
|
||||
I can invite internal user.
|
||||
-
|
||||
!record {model: base_calendar.invite.attendee, id: base_calendar_invite_attendee_0}:
|
||||
type: internal
|
||||
send_mail: False
|
||||
partner_id: base.res_partner_9
|
||||
user_ids:
|
||||
- base.user_demo
|
||||
-
|
||||
I click on "Invite" button of "Invite attendee" wizard.
|
||||
-
|
||||
!python {model: base_calendar.invite.attendee}: |
|
||||
self.do_invite(cr, uid, [ref('base_calendar_invite_attendee_0')], {'active_id': ref('crm_meeting_regardingpresentation0'), 'model' : 'crm.meeting', 'attendee_field':'attendee_ids'})
|
||||
|
||||
- |
|
||||
After direct/indirect confirmation for meetings I can confirm meeting.
|
||||
-
|
||||
!python {model: crm.meeting}: |
|
||||
self.case_open(cr, uid, [ref('crm_meeting_regardingpresentation0')])
|
|
@ -1,113 +0,0 @@
|
|||
- |
|
||||
I start by creating a new Opportunity. And I select partner for opportunity.
|
||||
I can see that after selecting partner his contact and email is automatically filled.
|
||||
-
|
||||
!record {model: crm.lead, id: crm_opportunity_abcfuelcounits0}:
|
||||
email_from: info@balmerinc.be
|
||||
name: 'ABC FUEL CO 829264 - 10002 units'
|
||||
partner_address_id: base.res_partner_address_1
|
||||
partner_id: base.res_partner_9
|
||||
probability: 1.0
|
||||
stage_id: crm.stage_lead1
|
||||
categ_id: crm.categ_oppor2
|
||||
section_id: crm.section_sales_department
|
||||
- |
|
||||
I check that the opportunity is in 'New' state.
|
||||
-
|
||||
!assert {model: crm.lead, id: crm_opportunity_abcfuelcounits0}:
|
||||
- state == "draft"
|
||||
|
||||
- |
|
||||
I check that phonecall record is created for that opportunity.
|
||||
-
|
||||
!python {model: crm.phonecall}: |
|
||||
phone_obj = self.pool.get('crm.phonecall')
|
||||
- |
|
||||
I schedule Meeting on this current opportunity by clicking on "schedule
|
||||
Meeting".
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.action_makeMeeting(cr, uid, [ref("crm_opportunity_abcfuelcounits0")])
|
||||
|
||||
- |
|
||||
I can see that Meeting's calendar view is shown.
|
||||
then I click on the date on which I want to schedule meeting.
|
||||
I fill proper data for that meeting and save it.
|
||||
-
|
||||
!record {model: crm.meeting, id: crm_meeting_abcfuelcounits0}:
|
||||
date: !eval time.strftime('%Y-%m-%d 00:00:00')
|
||||
date_deadline: !eval time.strftime('%Y-%m-%d 08:00:00')
|
||||
duration: 8.0
|
||||
email_from: info@balmerinc.be
|
||||
name: 'ABC FUEL CO 829264 - 10002 units'
|
||||
opportunity_id: 'crm_opportunity_abcfuelcounits0'
|
||||
partner_address_id: base.res_partner_address_1
|
||||
partner_id: base.res_partner_9
|
||||
section_id: crm.section_sales_department
|
||||
state: open
|
||||
- |
|
||||
In order to schedule a phonecall to the partner
|
||||
I click on "schedule call" button and select planned date for the call.
|
||||
-
|
||||
!record {model: crm.opportunity2phonecall, id: crm_opportunity2phonecall_abcfuelcounits0}:
|
||||
date: !eval "(datetime.now() + timedelta(1)).strftime('%Y-%m-%d 11:15:00')"
|
||||
name: 'ABC FUEL CO 829264 - 10002 units'
|
||||
section_id: crm.section_sales_department
|
||||
user_id: base.user_demo
|
||||
categ_id: crm.categ_phone1
|
||||
- |
|
||||
schedule phonecall by opportunity2phoncall wizard.
|
||||
-
|
||||
!python {model: crm.opportunity2phonecall}: |
|
||||
self.action_apply(cr, uid, [ref('crm_opportunity2phonecall_abcfuelcounits0')], {'active_ids': [ref("crm_opportunity_abcfuelcounits0")]})
|
||||
- |
|
||||
I check that phonecall record is created for that opportunity.
|
||||
-
|
||||
!python {model: crm.phonecall}: |
|
||||
phone_obj = self.pool.get('crm.phonecall')
|
||||
ids = phone_obj.search(cr, uid, [('name', '=', 'ABC FUEL CO 829264 - 10002 units')])
|
||||
assert len(ids)
|
||||
- |
|
||||
I can see phonecall record after click on "Schedule call" wizard.
|
||||
-
|
||||
!record {model: crm.phonecall, id: crm_phonecall_abcfuelcounits0}:
|
||||
date: !eval "(datetime.now() + timedelta(1)).strftime('%Y-%m-%d 11:15:00')"
|
||||
duration: 3.0
|
||||
name: 'ABC FUEL CO 829264 - 10002 units'
|
||||
partner_address_id: base.res_partner_address_1
|
||||
partner_id: base.res_partner_9
|
||||
section_id: crm.section_sales_department
|
||||
- |
|
||||
I Merge the opportunities.
|
||||
-
|
||||
for that create two opportunities first opportunity 'Test FUEL CO'.
|
||||
-
|
||||
!record {model: crm.lead, id: crm_opportunity_1}:
|
||||
email_from: info@balmerinc.be
|
||||
name: 'Test FUEL CO 829264 - 10002 units'
|
||||
partner_address_id: base.res_partner_address_1
|
||||
partner_id: base.res_partner_9
|
||||
probability: 1.0
|
||||
stage_id: crm.stage_lead1
|
||||
categ_id: crm.categ_oppor2
|
||||
section_id: crm.section_sales_department
|
||||
-
|
||||
I create the opportunity 'FUEL CO'.
|
||||
-
|
||||
!record {model: crm.lead, id: crm_opportunity_2}:
|
||||
email_from: info@balmerinc.be
|
||||
name: 'FUEL CO 829264 - 10002 units'
|
||||
partner_address_id: base.res_partner_address_1
|
||||
partner_id: base.res_partner_9
|
||||
probability: 1.0
|
||||
stage_id: crm.stage_lead1
|
||||
categ_id: crm.categ_oppor2
|
||||
section_id: crm.section_sales_department
|
||||
- |
|
||||
I Merge two Opportunities.
|
||||
-
|
||||
!python {model: crm.merge.opportunity}: |
|
||||
op_list = [ref('crm_opportunity_1'),ref('crm_opportunity_2')]
|
||||
op_ids=self.pool.get('crm.lead').browse(cr,uid,op_list)
|
||||
lead_ids = [ref('crm_lead_newcustomer0')]
|
||||
self.merge(cr, uid, op_ids, {'lead_ids': lead_ids})
|
|
@ -1,45 +0,0 @@
|
|||
- |
|
||||
I start by creating a new Opportunity. And I select partner for opportunity.
|
||||
I can see that after selecting partner his contact and email is automatically filled.
|
||||
-
|
||||
!record {model: crm.lead, id: crm_opportunity_demotestopportunity}:
|
||||
email_from: info@balmerinc.be
|
||||
name: 'Demo Test Opportunity'
|
||||
partner_address_id: base.res_partner_address_1
|
||||
partner_id: base.res_partner_9
|
||||
probability: 1.0
|
||||
categ_id: crm.categ_oppor2
|
||||
section_id: crm.section_sales_department
|
||||
type: opportunity
|
||||
-
|
||||
I check that the opportunity is in 'New' state.
|
||||
-
|
||||
!assert {model: crm.lead, id: crm_opportunity_demotestopportunity, string: Opportunity in Draft}:
|
||||
- state == "draft"
|
||||
-
|
||||
I open opportunity by click on "Open" button.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_open(cr, uid, [ref("crm_opportunity_demotestopportunity")])
|
||||
-
|
||||
I change partner of the opportunity.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.onchange_partner_id(cr, uid, [ref("crm_opportunity_demotestopportunity")], ref("base.res_partner_agrolait"))
|
||||
|
||||
-
|
||||
I change Contact Detail of the opportunity.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.onchange_partner_address_id(cr, uid,[ref("crm_opportunity_demotestopportunity")], ref("base.res_partner_address_8invoice"))
|
||||
|
||||
-
|
||||
I change Opportunity to Won State.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_mark_won(cr, uid, [ref("crm_opportunity_demotestopportunity")])
|
||||
-
|
||||
I check that the opportunity is in 'Done' state.
|
||||
-
|
||||
!assert {model: crm.lead, id: crm_opportunity_demotestopportunity, string: Opportunity is Won}:
|
||||
- state == "done"
|
|
@ -1,25 +0,0 @@
|
|||
- |
|
||||
I start by creating a new opportunity from partner.
|
||||
-
|
||||
!record {model: crm.partner2opportunity, id: crm_partner2opportunity_id_0}:
|
||||
name: test
|
||||
planned_revenue: 0.0
|
||||
partner_id: base.res_partner_9
|
||||
probability: 0.0
|
||||
-
|
||||
I click on "Create Opportunity" button of this wizard.
|
||||
-
|
||||
!python {model: crm.partner2opportunity}: |
|
||||
fields = {
|
||||
'name': 'test',
|
||||
'planned_revenue': '0.0',
|
||||
'partner_id': ref('base.res_partner_9'),
|
||||
'probability': '0.0'
|
||||
}
|
||||
self.default_get(cr, uid, fields, {"active_ids": [ref("crm_partner2opportunity_id_0")]})
|
||||
- |
|
||||
In order to check the opportunity is created or not, I check type.
|
||||
-
|
||||
!python {model: crm.partner2opportunity}: |
|
||||
opportunity = self.make_opportunity(cr, uid, [ref("crm_partner2opportunity_id_0")], {"active_ids": [ref("crm_partner2opportunity_id_0")]})
|
||||
assert True
|
|
@ -1,116 +0,0 @@
|
|||
- |
|
||||
I start by creating a new phonecall.
|
||||
-
|
||||
!record {model: crm.phonecall, id: crm_phonecall_interviewcall0}:
|
||||
date: !eval time.strftime('%Y-%m-%d 08:00:00')
|
||||
name: Interview call
|
||||
duration: 2.0
|
||||
section_id: crm.section_sales_department
|
||||
-
|
||||
I select partner by click on "Create a Partner" button.
|
||||
-
|
||||
!record {model: crm.phonecall2partner, id: crm_phonecall2partner_1}:
|
||||
action: exist
|
||||
partner_id: base.res_partner_9
|
||||
|
||||
-
|
||||
I click on "Continue" button of this wizard and make partner.
|
||||
-
|
||||
!python {model: crm.phonecall2partner}: |
|
||||
|
||||
self._select_partner(cr, uid,{"active_ids": [ref("crm_phonecall_interviewcall0")]})
|
||||
self.open_create_partner(cr, uid, [ref("crm_phonecall2partner_1")], {"active_ids": [ref("crm_phonecall_interviewcall0")]})
|
||||
self.make_partner(cr, uid, [ref("crm_phonecall2partner_1")], {"active_ids": [ref("crm_phonecall_interviewcall0")]})
|
||||
|
||||
- |
|
||||
As the success of phonecall seems to be a real business opportunity, I will convert
|
||||
it to opportunity by clicking on the "Convert to Opportunity" button.
|
||||
-
|
||||
!record {model: crm.phonecall2opportunity, id: crm_phonecall2opportunity_interviewcall0}:
|
||||
name: Interview call
|
||||
partner_id: base.res_partner_9
|
||||
planned_revenue: 0.0
|
||||
probability: 0.0
|
||||
- |
|
||||
I can see that a business opportunity is now assigned to this phonecall
|
||||
-
|
||||
!assert {model: crm.phonecall, id: crm_phonecall_interviewcall0}:
|
||||
- opportunity_id != False
|
||||
-
|
||||
I click on "Convert" button of this wizard.
|
||||
-
|
||||
!python {model: crm.phonecall2opportunity}: |
|
||||
self.action_apply(cr, uid, [ref("crm_phonecall2opportunity_interviewcall0")], {"active_id": ref("crm_phonecall_interviewcall0")})
|
||||
- |
|
||||
And I check that the phonecall and the newly created business opportunity is linked
|
||||
to same partner.
|
||||
-
|
||||
!python {model: crm.phonecall}: |
|
||||
obj_phonecall = self.browse(cr, uid, ref('crm_phonecall_interviewcall0'))
|
||||
ids = self.pool.get('crm.lead').search(cr, uid, [('name', '=', obj_phonecall.opportunity_id.name)])
|
||||
obj_opp = self.pool.get('crm.lead').browse(cr, uid, ids)[0]
|
||||
assert obj_phonecall.partner_id == obj_opp.partner_id
|
||||
- |
|
||||
I schedule Meeting on this current phonecall by clicking on "schedule
|
||||
Meeting".
|
||||
-
|
||||
!python {model: crm.phonecall}: |
|
||||
self.action_make_meeting(cr, uid, [ref('crm_phonecall_interviewcall0')])
|
||||
|
||||
- |
|
||||
I can see that Meeting's calendar view is shown.
|
||||
then I click on the date on which I want schedule meeting.
|
||||
I fill proper data for that meeting and save it.
|
||||
-
|
||||
!record {model: crm.meeting, id: crm_meeting_interviewcall0}:
|
||||
alarm_id: base_calendar.alarm3
|
||||
date: !eval "'%s-%s-%s 09:00:00' %(datetime.now().year,datetime.now().month,datetime.now().day)"
|
||||
date_deadline: !eval "'%s-%s-%s 17:00:00' %(datetime.now().year,datetime.now().month,datetime.now().day)"
|
||||
duration: 8.0
|
||||
email_from: info@balmerinc.be
|
||||
name: Interview call
|
||||
partner_address_id: base.res_partner_address_1
|
||||
partner_id: base.res_partner_9
|
||||
phonecall_id: 'crm_phonecall_interviewcall0'
|
||||
state: open
|
||||
|
||||
- |
|
||||
In order to schedule other phonecall to the partner
|
||||
I click on "schedule other call" button. and plan for other call
|
||||
I can see that it will open other phonecall view with some data same as current
|
||||
phonecall.
|
||||
-
|
||||
!record {model: crm.phonecall2phonecall, id: crm_phonecall2phonecall_interviewcall0}:
|
||||
date: !eval "'%s-%s-%s 19:49:00' %(datetime.now().year,datetime.now().month,datetime.now().day)"
|
||||
name: Interview call
|
||||
section_id: crm.section_sales_department
|
||||
user_id: base.user_root
|
||||
action: schedule
|
||||
categ_id: crm.categ_phone1
|
||||
-
|
||||
I click on "schedule other call" button. and plan for other call.
|
||||
-
|
||||
!record {model: crm.phonecall2phonecall, id: crm_phonecall2phonecall_interviewcall1}:
|
||||
date: !eval "'%s-%s-%s 19:49:00' %(datetime.now().year,datetime.now().month,datetime.now().day)"
|
||||
name: Interview call
|
||||
section_id: crm.section_sales_department
|
||||
user_id: base.user_root
|
||||
action: log
|
||||
categ_id: crm.categ_phone1
|
||||
- |
|
||||
I click on "Schedule" button of this wizard.
|
||||
-
|
||||
!python {model: crm.phonecall2phonecall}: |
|
||||
fields = {
|
||||
'name': 'Interview call',
|
||||
'section_id': ref('crm.section_sales_department'),
|
||||
'user_id': ref('base.user_root'),
|
||||
'categ_id': ref('crm.categ_phone1')
|
||||
}
|
||||
self.default_get(cr, uid, fields,{'active_id': ref('crm_phonecall_interviewcall0')})
|
||||
self.action_apply(cr, uid, [ref('crm_phonecall2phonecall_interviewcall0')], {'active_id': ref('crm_phonecall_interviewcall0')})
|
||||
- |
|
||||
I click on "Schedule" button of this wizard with log option.
|
||||
-
|
||||
!python {model: crm.phonecall2phonecall}: |
|
||||
self.action_apply(cr, uid, [ref('crm_phonecall2phonecall_interviewcall1')], {'active_id': ref('crm_phonecall_interviewcall0')})
|
|
@ -1,26 +0,0 @@
|
|||
- |
|
||||
I start by creating a new phonecall.
|
||||
-
|
||||
!record {model: crm.phonecall, id: crm_phonecall_dummycall}:
|
||||
date: !eval time.strftime('%Y-%m-%d 08:00:00')
|
||||
name: Dummy call
|
||||
duration: 0.0
|
||||
section_id: crm.section_sales_department
|
||||
partner_id: base.res_partner_agrolait
|
||||
state: open
|
||||
-
|
||||
I change Contact Detail of the Partner.
|
||||
-
|
||||
!python {model: crm.phonecall}: |
|
||||
self.onchange_partner_address_id(cr, uid,[ref("crm_phonecall_dummycall")], ref("base.res_partner_address_8invoice"))
|
||||
|
||||
-
|
||||
I setting Phone call to Held (Done).
|
||||
-
|
||||
!python {model: crm.phonecall}: |
|
||||
self.case_close(cr, uid, [ref("crm_phonecall_dummycall")])
|
||||
-
|
||||
I check that the hone call is in 'Held' state.
|
||||
-
|
||||
!assert {model: crm.phonecall, id: crm_phonecall_dummycall, string: Phone call Helded}:
|
||||
- state == "done"
|
|
@ -1,106 +0,0 @@
|
|||
-
|
||||
In order to test recurrent meetings in OpenERP, I create meetings with different recurrency.
|
||||
-
|
||||
I create a customer meeting record with daily recurrency.
|
||||
-
|
||||
!record {model: crm.meeting, id: crm_meeting_pricelistdiscussion0}:
|
||||
categ_id: crm.categ_meet1
|
||||
count: 0.0
|
||||
date: '2011-01-05 00:00:00'
|
||||
date_deadline: '2011-01-05 01:00:00'
|
||||
day: 0.0
|
||||
duration: 1.0
|
||||
end_date: '2011-01-12'
|
||||
end_type: end_date
|
||||
name: Pricelist Discussion
|
||||
recurrency: true
|
||||
recurrent_uid: 0.0
|
||||
rrule: FREQ=DAILY;INTERVAL=1;UNTIL=20110112T235959Z
|
||||
rrule_type: daily
|
||||
sequence: 0.0
|
||||
-
|
||||
I create another meeting record with weekly recurrency.
|
||||
-
|
||||
!record {model: crm.meeting, id: crm_meeting_changesindesigning0}:
|
||||
categ_id: crm.categ_meet2
|
||||
count: 15
|
||||
date: '2011-01-22 11:05:05'
|
||||
date_deadline: '2011-01-22 16:05:05'
|
||||
day: 0.0
|
||||
duration: 5.0
|
||||
email_from: info@opensides.be
|
||||
end_type: count
|
||||
fr: true
|
||||
mo: true
|
||||
name: Changes in Designing
|
||||
partner_address_id: base.res_partner_address_1
|
||||
partner_id: base.res_partner_9
|
||||
recurrency: true
|
||||
recurrent_uid: 0.0
|
||||
rrule: FREQ=WEEKLY;BYDAY=FR,TU,TH,WE,MO;INTERVAL=1;COUNT=15
|
||||
rrule_type: weekly
|
||||
section_id: crm.section_sales_department
|
||||
sequence: 0.0
|
||||
th: true
|
||||
tu: true
|
||||
user_id: base.user_demo
|
||||
we: true
|
||||
-
|
||||
I create a meeting record with monthly recurrency.
|
||||
-
|
||||
!record {model: crm.meeting, id: crm_meeting_reviewneeds0}:
|
||||
categ_id: crm.categ_meet3
|
||||
count: 0.0
|
||||
date: '2011-01-20 10:02:02'
|
||||
date_deadline: '2011-01-20 16:02:02'
|
||||
day: 15
|
||||
duration: 6.0
|
||||
end_date: '2011-05-31'
|
||||
end_type: end_date
|
||||
name: Review needs
|
||||
partner_address_id: base.res_partner_address_15
|
||||
partner_id: base.res_partner_11
|
||||
recurrency: true
|
||||
recurrent_uid: 0.0
|
||||
rrule: FREQ=MONTHLY;INTERVAL=1;UNTIL=20110531T235959Z;BYMONTHDAY=15
|
||||
rrule_type: monthly
|
||||
section_id: crm.section_sales_department
|
||||
sequence: 0.0
|
||||
user_id: base.user_demo
|
||||
-
|
||||
I create a record for daily scrum meeting.
|
||||
-
|
||||
!record {model: crm.meeting, id: crm_meeting_scrummeeting0}:
|
||||
categ_id: crm.categ_meet2
|
||||
count: 0.0
|
||||
date: '2011-01-06 00:00:00'
|
||||
date_deadline: '2011-01-06 01:00:00'
|
||||
day: 0.0
|
||||
duration: 1.0
|
||||
name: Scrum meeting
|
||||
recurrency: true
|
||||
recurrent_uid: 0.0
|
||||
rrule: FREQ=DAILY;INTERVAL=1
|
||||
rrule_type: daily
|
||||
sequence: 0.0
|
||||
-
|
||||
I create a meeting record for yearly recurrency.
|
||||
-
|
||||
!record {model: crm.meeting, id: crm_meeting_updatethedata0}:
|
||||
categ_id: crm.categ_meet2
|
||||
count: 0.0
|
||||
date: '2011-01-18 13:12:49'
|
||||
date_deadline: '2011-01-19 02:30:49'
|
||||
day: 0.0
|
||||
duration: 13.300000000000001
|
||||
end_date: '2015-01-06'
|
||||
end_type: end_date
|
||||
name: Update the data
|
||||
partner_address_id: base.res_partner_address_7
|
||||
partner_id: base.res_partner_4
|
||||
recurrency: true
|
||||
recurrent_uid: 0.0
|
||||
rrule: FREQ=YEARLY;INTERVAL=1;UNTIL=20150106T235959Z
|
||||
rrule_type: yearly
|
||||
section_id: crm.section_sales_department
|
||||
sequence: 0.0
|
|
@ -1,38 +0,0 @@
|
|||
- |
|
||||
I will test segmentation which create specific partner categories criteria.
|
||||
-
|
||||
I create a new segmentation record.
|
||||
-
|
||||
!record {model: crm.segmentation, id: crm_segmentation_id_0}:
|
||||
categ_id: base.res_partner_category_5
|
||||
exclusif: true
|
||||
name: segment
|
||||
som_interval: 0.0
|
||||
sales_purchase_active : True
|
||||
-
|
||||
I start the process.
|
||||
-
|
||||
!python {model: crm.segmentation}: |
|
||||
self.process_start(cr, uid, [ref("crm_segmentation_id_0")],context)
|
||||
-
|
||||
I continue the segmentation process.
|
||||
-
|
||||
!python {model: crm.segmentation}: |
|
||||
context.update({'start': True})
|
||||
self.process_continue(cr, uid, [ref("crm_segmentation_id_0")], context)
|
||||
-
|
||||
I create the segmentation line.
|
||||
-
|
||||
!record {model: crm.segmentation.line, id: crm_segmentation_line_id_0}:
|
||||
expr_name: sale
|
||||
expr_operator: '>'
|
||||
expr_value: 1000.0
|
||||
name: Rule1
|
||||
operator: or
|
||||
segmentation_id: crm_segmentation_id_0
|
||||
|
||||
-
|
||||
I check the Segmentation line record.
|
||||
-
|
||||
!python {model: crm.segmentation.line}: |
|
||||
self.test(cr, uid, [ref("crm_segmentation_line_id_0")],partner_id=0)
|
|
@ -1,96 +0,0 @@
|
|||
-
|
||||
In order to test the changes on stage of a lead or an opportunity with OpenERP,
|
||||
I create some leads and test the stage changes.
|
||||
-
|
||||
I want to change the probability to 0.0 when the opportunity is marked as lost.
|
||||
So I set its Change probability automatically true.
|
||||
-
|
||||
!record {model: crm.case.stage, id: crm.stage_lead6}:
|
||||
name: Lost
|
||||
on_change: true
|
||||
probability: 0.0
|
||||
section_ids:
|
||||
- crm.section_sales_department
|
||||
sequence: 0
|
||||
-
|
||||
I create a lead 'Test Lead1'.
|
||||
-
|
||||
!record {model: crm.lead, id: crm_lead_openerppresentation0}:
|
||||
categ_id: crm.categ_oppor4
|
||||
day_close: 0.0
|
||||
day_open: 0.0
|
||||
name: Test Lead1
|
||||
planned_revenue: 0.0
|
||||
probability: 10.0
|
||||
section_id: crm.section_sales_department
|
||||
-
|
||||
I open the lead.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_open(cr, uid, [ref('crm_lead_openerppresentation0')])
|
||||
-
|
||||
I assigning stage.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.onchange_stage_id(cr, uid, [ref('crm_lead_openerppresentation0')], [], context)
|
||||
-
|
||||
I assigning percent.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.stage_find_percent(cr, uid, 10.0, [])
|
||||
-
|
||||
I find that this lead can be converted to opportunity.
|
||||
-
|
||||
!record {model: crm.lead2opportunity.partner, id: crm_lead2opportunity_partner0}:
|
||||
action: 'create'
|
||||
name: 'convert'
|
||||
-
|
||||
So I convert the lead to opportunity.
|
||||
-
|
||||
!python {model: crm.lead2opportunity.partner}: |
|
||||
self.action_apply(cr, uid, [ref('crm_lead2opportunity_partner0')], context={'active_ids': [ref('crm_lead_openerppresentation0')]})
|
||||
-
|
||||
I check that lead is now converted to opportunity.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
lead = self.browse(cr, uid, ref('crm_lead_openerppresentation0'))
|
||||
assert lead.type == 'opportunity', 'Lead is not converted to opportunity!'
|
||||
-
|
||||
I mark this opportunity as lost.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_mark_lost(cr, uid, [ref('crm_lead_openerppresentation0')])
|
||||
-
|
||||
I check whether the probability is set according to stage change or not.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
opportunity = self.browse(cr, uid, ref('crm_lead_openerppresentation0'))
|
||||
assert opportunity.stage_id.id == ref('crm.stage_lead6'), 'Stage is not changed!'
|
||||
assert opportunity.probability == 0.0, 'Probability is wrong!'
|
||||
-
|
||||
I create one more opportunity.
|
||||
-
|
||||
!record {model: crm.lead, id: crm_lead_test2}:
|
||||
name: Partner Demo
|
||||
type: opportunity
|
||||
categ_id: crm.categ_oppor3
|
||||
planned_revenue: 50000.0
|
||||
probability: 100.0
|
||||
section_id: crm.section_sales_department
|
||||
-
|
||||
I open this opportunity.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_open(cr, uid, [ref('crm_lead_test2')])
|
||||
-
|
||||
I mark this opportunity as won.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_mark_won(cr, uid, [ref('crm_lead_test2')])
|
||||
-
|
||||
I check whether the stage is changed to 'Won' and probability is 100.0 or not.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
opportunity = self.browse(cr, uid, ref('crm_lead_test2'))
|
||||
assert opportunity.stage_id.id == ref('crm.stage_lead5'), 'Stage is not changed!'
|
||||
assert opportunity.probability == 100.0, 'Probability is wrong!'
|
|
@ -0,0 +1,29 @@
|
|||
-
|
||||
I create lead record to call of partner onchange, stage onchange and Mailing opt-in onchange method.
|
||||
-
|
||||
!record {model: crm.lead, id: crm_case_shelvehouse}:
|
||||
name: 'Need more info about your pc2'
|
||||
partner_id: base.res_partner_theshelvehouse0
|
||||
type: opportunity
|
||||
stage_id: crm.stage_lead1
|
||||
state: draft
|
||||
optin: True
|
||||
-
|
||||
I create lead record to call Mailing opt-out onchange method.
|
||||
-
|
||||
!record {model: crm.lead, id: crm_case_mediapoleunits0}:
|
||||
name: 'Need 20 Days of Consultancy'
|
||||
type: opportunity
|
||||
state: draft
|
||||
optout: True
|
||||
-
|
||||
I create phonecall record to call partner onchange method.
|
||||
-
|
||||
!record {model: crm.phonecall, id: crm_case_phone05}:
|
||||
name: 'Bad time'
|
||||
partner_id: base.res_partner_5
|
||||
-
|
||||
I setting next stage "New" for the lead.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.stage_next(cr, uid, [ref("crm_case_qrecorp0")], context={'stage_type': 'lead'})
|
|
@ -0,0 +1,5 @@
|
|||
-
|
||||
I Unlink the Lead.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.unlink(cr, uid, [ref("crm_case_qrecorp0")])
|
|
@ -0,0 +1,5 @@
|
|||
-
|
||||
I make duplicate the Lead.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.copy(cr, uid, ref("crm_case_qrecorp0"))
|
|
@ -24,11 +24,11 @@ import crm_add_note
|
|||
|
||||
import crm_lead_to_partner
|
||||
import crm_lead_to_opportunity
|
||||
import crm_opportunity_to_phonecall
|
||||
import crm_phonecall_to_phonecall
|
||||
import crm_opportunity_to_phonecall
|
||||
import crm_phonecall_to_partner
|
||||
import crm_phonecall_to_opportunity
|
||||
import crm_partner_to_opportunity
|
||||
import crm_phonecall_to_opportunity
|
||||
|
||||
import crm_merge_opportunities
|
||||
|
||||
|
|
|
@ -54,6 +54,8 @@ class crm_lead2opportunity_partner(osv.osv_memory):
|
|||
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
|
||||
|
||||
#TOFIX: use mail.mail_message.to_mail
|
||||
email = re.findall(r'([^ ,<@]+@[^> ,]+)', lead.email_from or '')
|
||||
email = map(lambda x: "'" + x + "'", email)
|
||||
|
||||
|
@ -93,139 +95,51 @@ class crm_lead2opportunity_partner(osv.osv_memory):
|
|||
def view_init(self, cr, uid, fields, context=None):
|
||||
"""
|
||||
This function checks for precondition before wizard executes
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@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 = {}
|
||||
lead_obj = self.pool.get('crm.lead')
|
||||
|
||||
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 can not be converted 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 = 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)
|
||||
vals = {
|
||||
'planned_revenue': lead.planned_revenue,
|
||||
'probability': lead.probability,
|
||||
'name': lead.name,
|
||||
'partner_id': partner_id,
|
||||
'user_id': (lead.user_id and lead.user_id.id),
|
||||
'type': 'opportunity',
|
||||
'stage_id': stage_ids and stage_ids[0] or False,
|
||||
'date_action': time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
}
|
||||
if partner_id and address_id:
|
||||
vals['partner_address_id'] = address_id[0]
|
||||
else:
|
||||
vals['partner_address_id'] = False
|
||||
def _convert_opportunity(self, cr, uid, ids, vals, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
lead = self.pool.get('crm.lead')
|
||||
partner_id = self._create_partner(cr, uid, ids, context=context)
|
||||
lead_ids = vals.get('lead_ids', [])
|
||||
user_ids = vals.get('user_ids', False)
|
||||
team_id = vals.get('section_id', False)
|
||||
return lead.convert_opportunity(cr, uid, lead_ids, partner_id, user_ids, team_id, context=context)
|
||||
|
||||
lead.write(vals, context=context)
|
||||
text = _('Converted to opportunity')
|
||||
leads.message_append(cr, uid, [lead], text, body_text=text, context=context)
|
||||
if lead.partner_id:
|
||||
msg_ids = [ x.id for x in lead.message_ids]
|
||||
self.pool.get('mail.message').write(cr, uid, msg_ids, {
|
||||
'partner_id': lead.partner_id.id
|
||||
}, context=context)
|
||||
leads.log(cr, uid, lead.id, _("Lead '%s' has been converted to an opportunity.") % lead.name)
|
||||
|
||||
def send_mail_to_salesman(self, cr, uid, lead):
|
||||
email_to = lead.user_id and lead.user_id.user_email
|
||||
if not email_to:
|
||||
return False
|
||||
message_pool = self.pool.get('mail.message')
|
||||
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)
|
||||
return message_pool.schedule_with_attach(cr, uid, email_from, [email_to], subject, body)
|
||||
def _merge_opportunity(self, cr, uid, ids, opportunity_ids, action='merge', context=None):
|
||||
#TOFIX: is it usefully ?
|
||||
if context is None:
|
||||
context = {}
|
||||
merge_opportunity = self.pool.get('crm.merge.opportunity')
|
||||
res = False
|
||||
#If we convert in mass, don't merge if there is no other opportunity but no warning
|
||||
if action == 'merge' and (len(opportunity_ids) > 1 or not context.get('mass_convert') ):
|
||||
self.write(cr, uid, ids, {'opportunity_ids' : [(6,0, [opportunity_ids[0].id])]}, context=context)
|
||||
context.update({'lead_ids' : record_id, "convert" : True})
|
||||
res = merge_opportunity.merge(cr, uid, data.opportunity_ids, context=context)
|
||||
return res
|
||||
|
||||
def action_apply(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
This converts lead to opportunity and opens Opportunity view
|
||||
@param ids: ids of the leads to convert to opportunities
|
||||
|
||||
@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'}
|
||||
|
||||
leads = self.pool.get('crm.lead')
|
||||
models_data = self.pool.get('ir.model.data')
|
||||
|
||||
# Get Opportunity views
|
||||
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
|
||||
opportunity_view_form = models_data._get_id(
|
||||
cr, uid, 'crm', 'crm_case_form_view_oppor')
|
||||
opportunity_view_tree = models_data._get_id(
|
||||
cr, uid, 'crm', 'crm_case_tree_view_oppor')
|
||||
if opportunity_view_form:
|
||||
opportunity_view_form = models_data.browse(
|
||||
cr, uid, opportunity_view_form, context=context).res_id
|
||||
if opportunity_view_tree:
|
||||
opportunity_view_tree = models_data.browse(
|
||||
cr, uid, opportunity_view_tree, context=context).res_id
|
||||
|
||||
for lead in leads.browse(cr, uid, record_id, context=context):
|
||||
if lead.section_id:
|
||||
stage_ids = self.pool.get('crm.case.stage').search(cr, uid, [('sequence','>=',1), ('section_ids','=', lead.section_id.id)])
|
||||
else:
|
||||
stage_ids = self.pool.get('crm.case.stage').search(cr, uid, [('sequence','>=',1)])
|
||||
|
||||
data = self.browse(cr, uid, ids[0], context=context)
|
||||
|
||||
|
||||
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)
|
||||
self.send_mail_to_salesman(cr, uid, 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, "convert" : True})
|
||||
return merge_obj.merge(cr, uid, data.opportunity_ids, context=context)
|
||||
|
||||
return {
|
||||
'name': _('Opportunity'),
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form,tree',
|
||||
'res_model': 'crm.lead',
|
||||
'domain': [('type', '=', 'opportunity')],
|
||||
'res_id': int(lead.id),
|
||||
'view_id': False,
|
||||
'views': [(opportunity_view_form, 'form'),
|
||||
(opportunity_view_tree, 'tree'),
|
||||
(False, 'calendar'), (False, 'graph')],
|
||||
'type': 'ir.actions.act_window',
|
||||
'search_view_id': opportunity_view_search
|
||||
}
|
||||
|
||||
lead = self.pool.get('crm.lead')
|
||||
lead_ids = context.get('active_ids', [])
|
||||
data = self.browse(cr, uid, ids, context=context)[0]
|
||||
self._convert_opportunity(cr, uid, ids, {'lead_ids': lead_ids}, context=context)
|
||||
self._merge_opportunity(cr, uid, ids, data.opportunity_ids, data.action, context=context)
|
||||
return lead.redirect_opportunity_view(cr, uid, lead_ids[0], context=context)
|
||||
|
||||
crm_lead2opportunity_partner()
|
||||
|
||||
|
@ -240,55 +154,19 @@ class crm_lead2opportunity_mass_convert(osv.osv_memory):
|
|||
'section_id': fields.many2one('crm.case.section', 'Sales Team'),
|
||||
|
||||
}
|
||||
def _convert_opportunity(self, cr, uid, ids, vals, context=None):
|
||||
data = self.browse(cr, uid, ids, context=context)[0]
|
||||
salesteam_id = data.section_id and data.section_id.id or False
|
||||
salesman = []
|
||||
if data.user_ids:
|
||||
salesman = [x.id for x in data.user_ids]
|
||||
vals.update({'user_ids': salesman, 'section_id': salesteam_id})
|
||||
return super(crm_lead2opportunity_mass_convert, self)._convert_opportunity(cr, uid, ids, vals, context=context)
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
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)
|
||||
return self.action_apply(cr, uid, ids, context=context)
|
||||
crm_lead2opportunity_mass_convert()
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -65,6 +65,15 @@
|
|||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_crm_lead2opportunity_partner" model="ir.actions.act_window">
|
||||
<field name="name">Create a Partner</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">crm.lead2opportunity.partner</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_id" ref="view_crm_lead2opportunity_partner"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<act_window id="action_crm_send_mass_convert"
|
||||
multi="True"
|
||||
|
|
|
@ -21,11 +21,9 @@
|
|||
|
||||
from osv import osv, fields
|
||||
from tools.translate import _
|
||||
import re
|
||||
|
||||
class crm_lead2partner(osv.osv_memory):
|
||||
""" Converts lead to partner """
|
||||
|
||||
_name = 'crm.lead2partner'
|
||||
_description = 'Lead to Partner'
|
||||
|
||||
|
@ -35,171 +33,89 @@ class crm_lead2partner(osv.osv_memory):
|
|||
'Action', required=True),
|
||||
'partner_id': fields.many2one('res.partner', 'Partner'),
|
||||
}
|
||||
|
||||
def view_init(self, cr, uid, fields, context=None):
|
||||
"""
|
||||
This function checks for precondition before wizard executes
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@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
|
||||
|
||||
"""
|
||||
|
||||
lead_obj = self.pool.get('crm.lead')
|
||||
if context is None:
|
||||
context = {}
|
||||
model = context.get('active_model')
|
||||
model = self.pool.get(model)
|
||||
rec_ids = context and context.get('active_ids', [])
|
||||
for lead in lead_obj.browse(cr, uid, rec_ids, context=context):
|
||||
if lead.partner_id:
|
||||
for this in model.browse(cr, uid, rec_ids, context=context):
|
||||
if this.partner_id:
|
||||
raise osv.except_osv(_('Warning !'),
|
||||
_('A partner is already defined on this lead.'))
|
||||
_('A partner is already defined.'))
|
||||
|
||||
def _select_partner(self, cr, uid, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
lead = self.pool.get('crm.lead')
|
||||
partner = self.pool.get('res.partner')
|
||||
lead_ids = list(context and context.get('active_ids', []) or [])
|
||||
if not len(lead_ids):
|
||||
return False
|
||||
this = lead.browse(cr, uid, lead_ids[0], context=context)
|
||||
# Find partner address matches the email_from of the lead
|
||||
res = lead.message_partner_by_email(cr, uid, this.email_from, context=context)
|
||||
partner_id = res.get('partner_id', False)
|
||||
# Find partner name that matches the name of the lead
|
||||
if not partner_id and this.partner_name:
|
||||
partner_ids = partner.search(cr, uid, [('name', '=', this.partner_name)], context=context)
|
||||
if partner_ids and len(partner_ids):
|
||||
partner_id = partner_ids[0]
|
||||
return partner_id
|
||||
|
||||
def default_get(self, cr, uid, fields, context=None):
|
||||
"""
|
||||
This function gets default values
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@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
|
||||
|
||||
@return : default values of fields.
|
||||
"""
|
||||
res = super(crm_lead2partner, self).default_get(cr, uid, fields, context=context)
|
||||
partner_id = self._select_partner(cr, uid, context=context)
|
||||
|
||||
lead_obj = self.pool.get('crm.lead')
|
||||
partner_obj = self.pool.get('res.partner')
|
||||
partner_id = False
|
||||
|
||||
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
|
||||
email = re.findall(r'([^ ,<@]+@[^> ,]+)', lead.email_from or '')
|
||||
email = map(lambda x: "'" + x + "'", email)
|
||||
if email:
|
||||
cr.execute("""select partner_id from res_partner_address
|
||||
where
|
||||
substring(email from '([^ ,<@]+@[^> ,]+)') in (%s)""" % (','.join(email)))
|
||||
partner_ids = map(lambda x: x[0], cr.fetchall())
|
||||
|
||||
# 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', '=ilike', lead.partner_name)], context=context)
|
||||
|
||||
partner_id = partner_ids and partner_ids[0] or False
|
||||
if 'partner_id' in fields:
|
||||
res.update({'partner_id': partner_id})
|
||||
if 'action' in fields:
|
||||
res.update({'action': partner_id and 'exist' or 'create'})
|
||||
if 'opportunity_ids' in fields:
|
||||
res.update({'opportunity_ids': data})
|
||||
|
||||
if 'partner_id' in fields:
|
||||
res.update({'partner_id': partner_id})
|
||||
if 'action' in fields:
|
||||
res.update({'action': partner_id and 'exist' or 'create'})
|
||||
|
||||
return res
|
||||
|
||||
def open_create_partner(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
This function Opens form of create partner.
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Lead to Partner's IDs
|
||||
@param context: A standard dictionary for contextual values
|
||||
|
||||
@return : Dictionary value for next form.
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
view_obj = self.pool.get('ir.ui.view')
|
||||
view_id = view_obj.search(cr, uid, [('model', '=', 'crm.lead2partner'), \
|
||||
('name', '=', 'crm.lead2partner.view')])
|
||||
view_id = view_obj.search(cr, uid, [('model', '=', self._name), \
|
||||
('name', '=', self._name+'.view')])
|
||||
return {
|
||||
'view_mode': 'form',
|
||||
'view_type': 'form',
|
||||
'view_id': view_id or False,
|
||||
'res_model': 'crm.lead2partner',
|
||||
'res_model': self._name,
|
||||
'context': context,
|
||||
'type': 'ir.actions.act_window',
|
||||
'target': 'new',
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
def _create_partner(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
This function Creates partner based on action.
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Lead to Partner's IDs
|
||||
@param context: A standard dictionary for contextual values
|
||||
|
||||
@return : Dictionary {}.
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
lead_obj = self.pool.get('crm.lead')
|
||||
partner_obj = self.pool.get('res.partner')
|
||||
contact_obj = self.pool.get('res.partner.address')
|
||||
partner_ids = []
|
||||
partner_id = False
|
||||
rec_ids = context and context.get('active_ids', [])
|
||||
|
||||
for data in self.browse(cr, uid, ids, context=context):
|
||||
for lead in lead_obj.browse(cr, uid, rec_ids, context=context):
|
||||
if data.action == 'create':
|
||||
partner_id = partner_obj.create(cr, uid, {
|
||||
'name': lead.partner_name or lead.contact_name or lead.name,
|
||||
'user_id': lead.user_id.id,
|
||||
'comment': lead.description,
|
||||
'address': []
|
||||
})
|
||||
contact_obj.create(cr, uid, {
|
||||
'partner_id': partner_id,
|
||||
'name': lead.contact_name,
|
||||
'phone': lead.phone,
|
||||
'mobile': lead.mobile,
|
||||
'email': lead.email_from,
|
||||
'fax': lead.fax,
|
||||
'title': lead.title and lead.title.id or False,
|
||||
'function': lead.function,
|
||||
'street': lead.street,
|
||||
'street2': lead.street2,
|
||||
'zip': lead.zip,
|
||||
'city': lead.city,
|
||||
'country_id': lead.country_id and lead.country_id.id or False,
|
||||
'state_id': lead.state_id and lead.state_id.id or False,
|
||||
})
|
||||
|
||||
else:
|
||||
if data.partner_id:
|
||||
partner_id = data.partner_id.id
|
||||
self.assign_partner(cr, uid, lead.id, partner_id)
|
||||
partner_ids.append(partner_id)
|
||||
return partner_ids
|
||||
|
||||
|
||||
def assign_partner(self, cr, uid, lead_id, partner_id):
|
||||
self.pool.get("crm.lead").write(cr, uid, [lead_id], {'partner_id' : partner_id})
|
||||
|
||||
lead = self.pool.get('crm.lead')
|
||||
lead_ids = context and context.get('active_ids') or []
|
||||
data = self.browse(cr, uid, ids, context=context)[0]
|
||||
partner_id = data.partner_id and data.partner_id.id or False
|
||||
partner_ids = lead.convert_partner(cr, uid, lead_ids, data.action, partner_id, context=context)
|
||||
return partner_ids[lead_ids[0]]
|
||||
|
||||
def make_partner(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
This function Makes partner based on action.
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Lead to Partner's IDs
|
||||
@param context: A standard dictionary for contextual values
|
||||
|
||||
@return : Dictionary value for created Partner form.
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
|
||||
partner_ids = self._create_partner(cr, uid, ids, context=context)
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
partner_id = self._create_partner(cr, uid, ids, context=context)
|
||||
return self.pool.get('res.partner').redirect_partner_form(cr, uid, partner_id, context=context)
|
||||
|
||||
crm_lead2partner()
|
||||
|
||||
|
|
|
@ -26,195 +26,16 @@ class crm_merge_opportunity(osv.osv_memory):
|
|||
_name = 'crm.merge.opportunity'
|
||||
_description = 'Merge two Opportunities'
|
||||
|
||||
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, 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)
|
||||
return False
|
||||
|
||||
def _concat_all(self, attr, ops):
|
||||
return ', '.join([getattr(op, attr) for op in ops if hasattr(op, attr) and getattr(op, attr)])
|
||||
|
||||
|
||||
def get_attachments(self, cr, uid, id, context=None):
|
||||
proxy = self.pool.get('ir.attachment')
|
||||
ids = proxy.search(cr, uid, [('res_model', '=', 'crm.lead'), ('res_id', '=', id)], context=context)
|
||||
return proxy.browse(cr, uid, ids, context=context)
|
||||
|
||||
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)
|
||||
if not op_id:
|
||||
return False
|
||||
opps = lead_obj.browse(cr, uid, [op_id[0]], context=context)
|
||||
return opps[0]
|
||||
|
||||
def _update_data(self, op_ids, oldest_opp):
|
||||
data = {
|
||||
'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), #!!
|
||||
'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, 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_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_next', 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),
|
||||
}
|
||||
return data
|
||||
|
||||
def merge(self, cr, uid, op_ids, context=None):
|
||||
"""
|
||||
:param opp_ids: list of opportunities ids to merge
|
||||
"""
|
||||
opp_obj = self.pool.get('crm.lead')
|
||||
message_obj = self.pool.get('mail.message')
|
||||
|
||||
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 = self._update_data(op_ids, oldest_opp)
|
||||
|
||||
#copy message into the first opportunity + merge attachement
|
||||
count = 1
|
||||
first_attachments = self.get_attachments(cr, uid, first_opportunity, context=context)
|
||||
for opp in tail_opportunities:
|
||||
attachments = self.get_attachments(cr, uid, opp, context=context)
|
||||
for first in first_attachments:
|
||||
for attachment in attachments:
|
||||
if attachment.name == first.name:
|
||||
values = dict(
|
||||
name = "%s (%s)" % (attachment.name, count,),
|
||||
res_id = first_opportunity.id,
|
||||
)
|
||||
attachment.write(values)
|
||||
count+=1
|
||||
|
||||
for history in opp.message_ids:
|
||||
message_obj.write(cr, uid, history.id, {'res_id': first_opportunity.id, 'subject' : _("From %s : %s") % (opp.name, history.subject) }, context=context)
|
||||
|
||||
#Notification about loss of information
|
||||
details = []
|
||||
subject = ['Merged opportunities :']
|
||||
for opp in op_ids:
|
||||
subject.append(opp.name)
|
||||
details.append(_('Merged Opportunity: %s\n Partner: %s\n Stage: %s\n Section: %s\n Salesman: %s\n Category: %s\n Channel: %s\n Company: %s\n Contact name: %s\n Email: %s\n Phone number: %s\n Fax: %s\n Mobile: %s\n State: %s\n Description: %s\n Probability: %s\n Planned revennue: %s\n Country: %s\n City: %s\n Street: %s\n Street 2: %s\n Zip 2: %s') % ( opp.name, opp.partner_id.name or '',
|
||||
opp.stage_id.name or '',
|
||||
opp.section_id.name or '',
|
||||
opp.user_id.name or '',
|
||||
opp.categ_id.name or '',
|
||||
opp.channel_id.name or '',
|
||||
opp.company_id.name or '',
|
||||
opp.contact_name or '',
|
||||
opp.email_from or '',
|
||||
opp.phone or '',
|
||||
opp.fax or '',
|
||||
opp.mobile or '',
|
||||
opp.state_id.name or '',
|
||||
opp.description or '',
|
||||
opp.probability or '',
|
||||
opp.planned_revenue or '',
|
||||
opp.country_id.name or '',
|
||||
opp.city or '',
|
||||
opp.street or '',
|
||||
opp.street2 or '',
|
||||
opp.zip or '',
|
||||
))
|
||||
subject = subject[0] + ", ".join(subject[1:])
|
||||
details = "\n\n".join(details)
|
||||
|
||||
opp_obj.message_append(cr, uid, [first_opportunity], subject, body_text=details)
|
||||
#data.update({'message_ids' : [(6, 0 ,self._concat_o2m('message_ids', op_ids))]})
|
||||
opp_obj.write(cr, uid, [first_opportunity.id], data, context=context)
|
||||
unlink_ids = map(lambda x: x.id, tail_opportunities)
|
||||
opp_obj.unlink(cr, uid, unlink_ids, context=context)
|
||||
|
||||
models_data = self.pool.get('ir.model.data')
|
||||
|
||||
# Get Opportunity views
|
||||
opportunity_view_form = models_data._get_id(
|
||||
cr, uid, 'crm', 'crm_case_form_view_oppor')
|
||||
opportunity_view_tree = models_data._get_id(
|
||||
cr, uid, 'crm', 'crm_case_tree_view_oppor')
|
||||
if opportunity_view_form:
|
||||
opportunity_view_form = models_data.browse(
|
||||
cr, uid, opportunity_view_form, context=context).res_id
|
||||
if opportunity_view_tree:
|
||||
opportunity_view_tree = models_data.browse(
|
||||
cr, uid, opportunity_view_tree, context=context).res_id
|
||||
|
||||
return {
|
||||
'name': _('Opportunity'),
|
||||
'view_type': 'form',
|
||||
'view_mode': 'tree, form',
|
||||
'res_model': 'crm.lead',
|
||||
'domain': [('type', '=', 'opportunity')],
|
||||
'res_id': int(first_opportunity.id),
|
||||
'view_id': False,
|
||||
'views': [(opportunity_view_form, 'form'),
|
||||
(opportunity_view_tree, 'tree'),
|
||||
(False, 'calendar'), (False, 'graph')],
|
||||
'type': 'ir.actions.act_window',
|
||||
}
|
||||
|
||||
|
||||
def action_merge(self, cr, uid, ids, context=None):
|
||||
obj_opportunity = self.browse(cr, uid, ids[0], context=context)
|
||||
op_ids = obj_opportunity.opportunity_ids
|
||||
self.write(cr, uid, ids, {'opportunity_ids' : [(6,0, [op_ids[0].id])]}, context=context)
|
||||
context['lead_ids'] = [op_ids[0].id]
|
||||
return self.merge(cr, uid, op_ids, context)
|
||||
lead = self.pool.get('crm.lead')
|
||||
record = self.browse(cr, uid, ids[0], context=context)
|
||||
opportunities = record.opportunity_ids
|
||||
#TOFIX: why need to check lead_ids here
|
||||
lead_ids = [opportunities[0].id]
|
||||
self.write(cr, uid, ids, {'opportunity_ids' : [(6,0, lead_ids)]}, context=context)
|
||||
context['lead_ids'] = lead_ids
|
||||
merge_id = lead.merge_opportunity(cr, uid, [x.id for x in opportunities], context=context)
|
||||
return lead.redirect_opportunity_view(cr, uid, merge_id, context=context)
|
||||
|
||||
_columns = {
|
||||
'opportunity_ids' : fields.many2many('crm.lead', 'merge_opportunity_rel', 'merge_id', 'opportunity_id', 'Opportunities', domain=[('type', '=', 'opportunity')]),
|
||||
|
@ -223,13 +44,6 @@ class crm_merge_opportunity(osv.osv_memory):
|
|||
def default_get(self, cr, uid, fields, context=None):
|
||||
"""
|
||||
This function gets default values
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current users ID for security checks,
|
||||
@param fields: List of fields for default value
|
||||
@param context: A standard dictionary for contextual values
|
||||
|
||||
@return : default values of fields.
|
||||
"""
|
||||
record_ids = context and context.get('active_ids', False) or False
|
||||
res = super(crm_merge_opportunity, self).default_get(cr, uid, fields, context=context)
|
||||
|
|
|
@ -28,36 +28,11 @@ import time
|
|||
|
||||
class crm_opportunity2phonecall(osv.osv_memory):
|
||||
"""Converts Opportunity to Phonecall"""
|
||||
|
||||
_inherit = 'crm.phonecall2phonecall'
|
||||
_name = 'crm.opportunity2phonecall'
|
||||
_description = 'Opportunity to Phonecall'
|
||||
|
||||
_columns = {
|
||||
'name' : fields.char('Call summary', size=64, required=True, select=1),
|
||||
'user_id' : fields.many2one('res.users', "Assign To"),
|
||||
'contact_name':fields.char('Contact', size=64),
|
||||
'phone':fields.char('Phone', size=64),
|
||||
'partner_id' : fields.many2one('res.partner', "Partner"),
|
||||
'date': fields.datetime('Date'),
|
||||
'section_id': fields.many2one('crm.case.section', 'Sales Team'),
|
||||
'categ_id': fields.many2one('crm.case.categ', 'Category', \
|
||||
domain="['|',('section_id','=',False),('section_id','=',section_id),\
|
||||
('object_id.model', '=', 'crm.phonecall')]"),
|
||||
'action': fields.selection([('schedule','Schedule a call'), ('log','Log a call')], 'Action', required=True),
|
||||
'note':fields.text('Note'),
|
||||
}
|
||||
|
||||
def default_get(self, cr, uid, fields, context=None):
|
||||
"""
|
||||
This function gets default values
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@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
|
||||
|
||||
@return : default values of fields.
|
||||
"""
|
||||
opp_obj = self.pool.get('crm.lead')
|
||||
categ_id = False
|
||||
data_obj = self.pool.get('ir.model.data')
|
||||
|
@ -66,8 +41,8 @@ class crm_opportunity2phonecall(osv.osv_memory):
|
|||
categ_id = data_obj.browse(cr, uid, res_id, context=context).res_id
|
||||
|
||||
record_ids = context and context.get('active_ids', []) or []
|
||||
res = super(crm_opportunity2phonecall, self).default_get(cr, uid, fields, context=context)
|
||||
res.update({'action': 'log', 'date': time.strftime('%Y-%m-%d %H:%M:%S')})
|
||||
res = {}
|
||||
res.update({'action': 'schedule', 'date': time.strftime('%Y-%m-%d %H:%M:%S')})
|
||||
for opp in opp_obj.browse(cr, uid, record_ids, context=context):
|
||||
if 'name' in fields:
|
||||
res.update({'name': opp.name})
|
||||
|
@ -87,84 +62,20 @@ class crm_opportunity2phonecall(osv.osv_memory):
|
|||
res.update({'phone': opp.phone or (opp.partner_address_id and opp.partner_address_id.phone or False)})
|
||||
return res
|
||||
|
||||
def action_cancel(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Closes Opportunity to Phonecall form
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Opportunity to Phonecall's IDs
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
def action_apply(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
This converts Opportunity to Phonecall and opens Phonecall view
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user's ID for security checks,
|
||||
@param ids: List of Opportunity to Phonecall IDs
|
||||
@param context: A standard dictionary for contextual values
|
||||
|
||||
@return : Dictionary value for created Opportunity form
|
||||
"""
|
||||
def action_schedule(self, cr, uid, ids, context=None):
|
||||
value = {}
|
||||
record_ids = context and context.get('active_ids', []) or []
|
||||
|
||||
phonecall_obj = self.pool.get('crm.phonecall')
|
||||
opp_obj = self.pool.get('crm.lead')
|
||||
mod_obj = self.pool.get('ir.model.data')
|
||||
result = mod_obj._get_id(cr, uid, 'crm', 'view_crm_case_phonecalls_filter')
|
||||
res = mod_obj.read(cr, uid, result, ['res_id'])
|
||||
|
||||
data_obj = self.pool.get('ir.model.data')
|
||||
|
||||
# Select the view
|
||||
id2 = data_obj._get_id(cr, uid, 'crm', 'crm_case_phone_tree_view')
|
||||
id3 = data_obj._get_id(cr, uid, 'crm', 'crm_case_phone_form_view')
|
||||
if id2:
|
||||
id2 = data_obj.browse(cr, uid, id2, context=context).res_id
|
||||
if id3:
|
||||
id3 = data_obj.browse(cr, uid, id3, context=context).res_id
|
||||
|
||||
for this in self.browse(cr, uid, ids, context=context):
|
||||
for opp in opp_obj.browse(cr, uid, record_ids, context=context):
|
||||
vals = {
|
||||
'name' : opp.name,
|
||||
'case_id' : opp.id,
|
||||
'user_id' : this.user_id and this.user_id.id or False,
|
||||
'categ_id' : this.categ_id.id,
|
||||
'description' : opp.description or False,
|
||||
'date' : this.date,
|
||||
'section_id' : this.section_id.id or False,
|
||||
'partner_id': opp.partner_id and opp.partner_id.id or False,
|
||||
'partner_address_id': opp.partner_address_id and opp.partner_address_id.id or False,
|
||||
'partner_phone' : opp.phone or (opp.partner_address_id and opp.partner_address_id.phone or False),
|
||||
'partner_mobile' : opp.partner_address_id and opp.partner_address_id.mobile or False,
|
||||
'priority': opp.priority,
|
||||
'opportunity_id': opp.id,
|
||||
'date_open': time.strftime('%Y-%m-%d %H:%M:%S')
|
||||
}
|
||||
|
||||
new_case = phonecall_obj.create(cr, uid, vals, context=context)
|
||||
|
||||
if this.action == 'log':
|
||||
phonecall_obj.case_close(cr, uid, [new_case])
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
value = {
|
||||
'name': _('Phone Call'),
|
||||
'domain': "[('user_id','=',%s),('opportunity_id','=',%s)]" % (uid,opp.id),
|
||||
'view_type': 'form',
|
||||
'view_mode': 'tree,form',
|
||||
'res_model': 'crm.phonecall',
|
||||
'res_id' : new_case,
|
||||
'views': [(id3, 'form'), (id2, 'tree'), (False, 'calendar')],
|
||||
'type': 'ir.actions.act_window',
|
||||
'search_view_id': res['res_id'],
|
||||
}
|
||||
return value
|
||||
if context is None:
|
||||
context = {}
|
||||
phonecall = self.pool.get('crm.phonecall')
|
||||
opportunity_ids = context and context.get('active_ids') or []
|
||||
opportunity = self.pool.get('crm.lead')
|
||||
data = self.browse(cr, uid, ids, context=context)[0]
|
||||
call_ids = opportunity.schedule_phonecall(cr, uid, opportunity_ids, data.date, data.name, \
|
||||
data.note, data.phone, data.contact_name, data.user_id and data.user_id.id or False, \
|
||||
data.section_id and data.section_id.id or False, \
|
||||
data.categ_id and data.categ_id.id or False, \
|
||||
action=data.action, context=context)
|
||||
return phonecall.redirect_phonecall_view(cr, uid, call_ids[opportunity_ids[0]], context=context)
|
||||
|
||||
crm_opportunity2phonecall()
|
||||
|
||||
|
|
|
@ -16,24 +16,19 @@
|
|||
<field name="name"/>
|
||||
<field name="date" string="Planned Date" attrs="{'invisible': [('action','=','log')]}"/>
|
||||
<newline/>
|
||||
<group colspan="4">
|
||||
<field name="partner_id" readonly="True"/>
|
||||
<field name="categ_id" string="Type" widget="selection" domain="[('object_id.model', '=', 'crm.phonecall')]"/>
|
||||
<field name="contact_name"/>
|
||||
<field name="phone"/>
|
||||
</group>
|
||||
<group colspan="4">
|
||||
<field name="user_id" attrs="{'invisible': [('action','=','log')]}"/>
|
||||
<field name="section_id" widget="selection" attrs="{'invisible': [('action','=','log')]}"/>
|
||||
</group>
|
||||
<group colspan="4">
|
||||
<field name="note"/>
|
||||
</group>
|
||||
<field name="partner_id" readonly="True"/>
|
||||
<field name="categ_id" string="Type" widget="selection" domain="[('object_id.model', '=', 'crm.phonecall')]"/>
|
||||
<field name="contact_name"/>
|
||||
<field name="phone"/>
|
||||
<field name="user_id" attrs="{'invisible': [('action','=','log')]}"/>
|
||||
<field name="section_id" widget="selection" attrs="{'invisible': [('action','=','log')]}"/>
|
||||
<separator string="Notes" colspan="4"/>
|
||||
<field name="note" colspan="4" nolabel="1"/>
|
||||
<separator string="" colspan="4"/>
|
||||
<group colspan="4" col="3">
|
||||
<button name="action_cancel" string="_Cancel" icon="gtk-cancel" special="cancel" />
|
||||
<button name="action_apply" type="object" string="Log call" icon="gtk-ok" attrs="{'invisible' : [('action', '!=', 'log')]}" />
|
||||
<button name="action_apply" type="object" string="Schedule call" icon="gtk-ok" attrs="{'invisible' : [('action', '!=', 'schedule')]}" />
|
||||
<button name="action_schedule" type="object" string="Log call" icon="gtk-ok" attrs="{'invisible' : [('action', '!=', 'log')]}" />
|
||||
<button name="action_schedule" type="object" string="Schedule call" icon="gtk-ok" attrs="{'invisible' : [('action', '!=', 'schedule')]}" />
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
|
|
|
@ -35,16 +35,15 @@ class crm_partner2opportunity(osv.osv_memory):
|
|||
'partner_id': fields.many2one('res.partner', 'Partner'),
|
||||
}
|
||||
|
||||
def action_cancel(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Closes Partner 2 Opportunity
|
||||
"""
|
||||
return {'type':'ir.actions.act_window_close'}
|
||||
|
||||
def default_get(self, cr, uid, fields, context=None):
|
||||
"""
|
||||
This function gets default values
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@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
|
||||
|
||||
@return : default values of fields.
|
||||
"""
|
||||
partner_obj = self.pool.get('res.partner')
|
||||
data = context and context.get('active_ids', []) or []
|
||||
|
@ -58,56 +57,17 @@ class crm_partner2opportunity(osv.osv_memory):
|
|||
return res
|
||||
|
||||
def make_opportunity(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
|
||||
data = context and context.get('active_ids', []) or []
|
||||
make_opportunity = self.pool.get('crm.partner2opportunity')
|
||||
data_obj = self.pool.get('ir.model.data')
|
||||
part_obj = self.pool.get('res.partner')
|
||||
categ_obj = self.pool.get('crm.case.categ')
|
||||
case_obj = self.pool.get('crm.lead')
|
||||
|
||||
for make_opportunity_obj in make_opportunity.browse(cr, uid, ids, context=context):
|
||||
result = data_obj._get_id(cr, uid, 'crm', 'view_crm_case_opportunities_filter')
|
||||
res = data_obj.read(cr, uid, result, ['res_id'])
|
||||
|
||||
id2 = data_obj._get_id(cr, uid, 'crm', 'crm_case_form_view_oppor')
|
||||
id3 = data_obj._get_id(cr, uid, 'crm', 'crm_case_tree_view_oppor')
|
||||
if id2:
|
||||
id2 = data_obj.browse(cr, uid, id2, context=context).res_id
|
||||
if id3:
|
||||
id3 = data_obj.browse(cr, uid, id3, context=context).res_id
|
||||
|
||||
address = part_obj.address_get(cr, uid, data)
|
||||
categ_ids = categ_obj.search(cr, uid, [('object_id.model','=','crm.lead')])
|
||||
|
||||
opp_id = case_obj.create(cr, uid, {
|
||||
'name' : make_opportunity_obj.name,
|
||||
'planned_revenue' : make_opportunity_obj.planned_revenue,
|
||||
'probability' : make_opportunity_obj.probability,
|
||||
'partner_id' : make_opportunity_obj.partner_id.id,
|
||||
'partner_address_id' : address['default'],
|
||||
'categ_id' : categ_ids and categ_ids[0] or '',
|
||||
'state' :'draft',
|
||||
'type': 'opportunity'
|
||||
})
|
||||
value = {
|
||||
'name' : _('Opportunity'),
|
||||
'view_type' : 'form',
|
||||
'view_mode' : 'form,tree',
|
||||
'res_model' : 'crm.lead',
|
||||
'res_id' : opp_id,
|
||||
'view_id' : False,
|
||||
'views' : [(id2, 'form'), (id3, 'tree'), (False, 'calendar'), (False, 'graph')],
|
||||
'type' : 'ir.actions.act_window',
|
||||
'search_view_id' : res['res_id']
|
||||
}
|
||||
return value
|
||||
partner_ids = context and context.get('active_ids', []) or []
|
||||
partner = self.pool.get('res.partner')
|
||||
lead = self.pool.get('crm.lead')
|
||||
data = self.browse(cr, uid, ids, context=context)[0]
|
||||
opportunity_ids = partner.make_opportunity(cr, uid, partner_ids,
|
||||
data.name,
|
||||
data.planned_revenue,
|
||||
data.probability,
|
||||
)
|
||||
opportunity_id = opportunity_ids[partner_ids[0]]
|
||||
return lead.redirect_opportunity_view(cr, uid, opportunity_id, context=context)
|
||||
|
||||
crm_partner2opportunity()
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
<field name="probability"/>
|
||||
<separator string="" colspan="4" />
|
||||
<group col="4" colspan="4">
|
||||
<button special="cancel" string="_Cancel" icon="gtk-cancel"/>
|
||||
<button special="cancel" string="Cancel" icon="gtk-cancel"/>
|
||||
<button name="make_opportunity" string="Create Opportunity" type="object" icon="gtk-ok"/>
|
||||
</group>
|
||||
</form>
|
||||
|
|
|
@ -26,97 +26,31 @@ class crm_phonecall2opportunity(osv.osv_memory):
|
|||
""" Converts Phonecall to Opportunity"""
|
||||
|
||||
_name = 'crm.phonecall2opportunity'
|
||||
_inherit = 'crm.partner2opportunity'
|
||||
_description = 'Phonecall To Opportunity'
|
||||
|
||||
def action_cancel(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Closes Phonecall to Opportunity form
|
||||
"""
|
||||
|
||||
return {'type':'ir.actions.act_window_close'}
|
||||
|
||||
|
||||
def action_apply(self, cr, uid, ids, context=None):
|
||||
def make_opportunity(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
This converts Phonecall to Opportunity and opens Phonecall view
|
||||
"""
|
||||
record_id = context and context.get('active_id', False) or False
|
||||
if record_id:
|
||||
opp_obj = self.pool.get('crm.lead')
|
||||
phonecall_obj = self.pool.get('crm.phonecall')
|
||||
case = phonecall_obj.browse(cr, uid, record_id, context=context)
|
||||
data_obj = self.pool.get('ir.model.data')
|
||||
result = data_obj._get_id(cr, uid, 'crm', 'view_crm_case_opportunities_filter')
|
||||
res = data_obj.read(cr, uid, result, ['res_id'])
|
||||
id2 = data_obj._get_id(cr, uid, 'crm', 'crm_case_form_view_oppor')
|
||||
id3 = data_obj._get_id(cr, uid, 'crm', 'crm_case_tree_view_oppor')
|
||||
if id2:
|
||||
id2 = data_obj.browse(cr, uid, id2, context=context).res_id
|
||||
if id3:
|
||||
id3 = data_obj.browse(cr, uid, id3, context=context).res_id
|
||||
|
||||
for this in self.browse(cr, uid, ids, context=context):
|
||||
address = None
|
||||
if this.partner_id:
|
||||
address_id = self.pool.get('res.partner').address_get(cr, uid, [this.partner_id.id])
|
||||
if address_id['default']:
|
||||
address = self.pool.get('res.partner.address').browse(cr, uid, address_id['default'], context=context)
|
||||
new_opportunity_id = opp_obj.create(cr, uid, {
|
||||
'name': this.name,
|
||||
'planned_revenue': this.planned_revenue,
|
||||
'probability': this.probability,
|
||||
'partner_id': this.partner_id and this.partner_id.id or False,
|
||||
'partner_address_id': address and address.id,
|
||||
'phone': address and address.phone,
|
||||
'mobile': address and address.mobile,
|
||||
'section_id': case.section_id and case.section_id.id or False,
|
||||
'description': case.description or False,
|
||||
'phonecall_id': case.id,
|
||||
'priority': case.priority,
|
||||
'type': 'opportunity',
|
||||
'phone': case.partner_phone or False,
|
||||
})
|
||||
vals = {
|
||||
'partner_id': this.partner_id.id,
|
||||
'opportunity_id' : new_opportunity_id,
|
||||
}
|
||||
phonecall_obj.write(cr, uid, [case.id], vals)
|
||||
phonecall_obj.case_close(cr, uid, [case.id])
|
||||
opp_obj.case_open(cr, uid, [new_opportunity_id])
|
||||
|
||||
value = {
|
||||
'name': _('Opportunity'),
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form,tree',
|
||||
'res_model': 'crm.lead',
|
||||
'res_id': int(new_opportunity_id),
|
||||
'view_id': False,
|
||||
'views': [(id2, 'form'), (id3, 'tree'), (False, 'calendar'), (False, 'graph')],
|
||||
'type': 'ir.actions.act_window',
|
||||
'search_view_id': res['res_id']
|
||||
}
|
||||
return value
|
||||
|
||||
_columns = {
|
||||
'name' : fields.char('Opportunity Summary', size=64, required=True, select=1),
|
||||
'probability': fields.float('Success Probability'),
|
||||
'planned_revenue': fields.float('Expected Revenue'),
|
||||
'partner_id': fields.many2one('res.partner', 'Partner'),
|
||||
}
|
||||
if not len(ids):
|
||||
return False
|
||||
call_ids = context and context.get('active_ids', False) or False
|
||||
this = self.browse(cr, uid, ids[0], context=context)
|
||||
if not call_ids:
|
||||
return {}
|
||||
opportunity = self.pool.get('crm.lead')
|
||||
phonecall = self.pool.get('crm.phonecall')
|
||||
opportunity_ids = phonecall.convert_opportunity(cr, uid, call_ids, this.name, this.partner_id and this.partner_id.id or False, \
|
||||
this.planned_revenue, this.probability, context=context)
|
||||
return opportunity.redirect_opportunity_view(cr, uid, opportunity_ids[call_ids[0]], context=context)
|
||||
|
||||
def default_get(self, cr, uid, fields, context=None):
|
||||
"""
|
||||
This function gets default values
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@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
|
||||
|
||||
@return : default values of fields.
|
||||
"""
|
||||
record_id = context and context.get('active_id', False) or False
|
||||
res = super(crm_phonecall2opportunity, self).default_get(cr, uid, fields, context=context)
|
||||
res = {}
|
||||
|
||||
if record_id:
|
||||
phonecall = self.pool.get('crm.phonecall').browse(cr, uid, record_id, context=context)
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<group colspan="4" col="3" >
|
||||
<label string=" " />
|
||||
<button name="action_cancel" string="_Cancel" icon="gtk-cancel" special="cancel" />
|
||||
<button name="action_apply" type="object" string="_Convert" icon="gtk-convert" />
|
||||
<button name="make_opportunity" type="object" string="_Convert" icon="gtk-convert" />
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
|
|
|
@ -26,42 +26,12 @@ class crm_phonecall2partner(osv.osv_memory):
|
|||
""" Converts phonecall to partner """
|
||||
|
||||
_name = 'crm.phonecall2partner'
|
||||
_inherit = 'crm.lead2partner'
|
||||
_description = 'Phonecall to Partner'
|
||||
|
||||
_columns = {
|
||||
'action': fields.selection([('exist', 'Link to an existing partner'), \
|
||||
('create', 'Create a new partner')], \
|
||||
'Action', required=True),
|
||||
'partner_id': fields.many2one('res.partner', 'Partner')
|
||||
}
|
||||
|
||||
def view_init(self, cr, uid, fields, context=None):
|
||||
"""
|
||||
This function checks for precondition before wizard executes
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@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
|
||||
|
||||
"""
|
||||
phonecall_obj = self.pool.get('crm.phonecall')
|
||||
rec_ids = context and context.get('active_ids', [])
|
||||
for phonecall in phonecall_obj.browse(cr, uid, rec_ids, context=context):
|
||||
if phonecall.partner_id:
|
||||
raise osv.except_osv(_('Warning !'),
|
||||
_('A partner is already defined on this phonecall.'))
|
||||
|
||||
|
||||
def _select_partner(self, cr, uid, context=None):
|
||||
"""
|
||||
This function Searches for Partner from selected phonecall.
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@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
|
||||
|
||||
@return : Partner id if any for selected phonecall.
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
|
@ -75,7 +45,7 @@ class crm_phonecall2partner(osv.osv_memory):
|
|||
for phonecall in phonecall_obj.browse(cr, uid, rec_ids, context=context):
|
||||
partner_ids = partner_obj.search(cr, uid, [('name', '=', phonecall.name or phonecall.name)])
|
||||
if not partner_ids and phonecall.email_from:
|
||||
address_ids = contact_obj.search(cr, uid, [('email', '=', phonecall.email_from)])
|
||||
address_ids = contact_obj.search(cr, uid, ['|', ('phone', '=', phonecall.partner_phone), ('mobile','=',phonecall.partner_mobile)])
|
||||
if address_ids:
|
||||
addresses = contact_obj.browse(cr, uid, address_ids)
|
||||
partner_ids = addresses and [addresses[0].partner_id.id] or False
|
||||
|
@ -83,117 +53,20 @@ class crm_phonecall2partner(osv.osv_memory):
|
|||
partner_id = partner_ids and partner_ids[0] or False
|
||||
return partner_id
|
||||
|
||||
_defaults = {
|
||||
'action': lambda *a:'exist',
|
||||
'partner_id': _select_partner
|
||||
}
|
||||
|
||||
def open_create_partner(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
This function Opens form of create partner.
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Phonecall to Partner's IDs
|
||||
@param context: A standard dictionary for contextual values
|
||||
|
||||
@return : Dictionary value for next form.
|
||||
"""
|
||||
|
||||
view_obj = self.pool.get('ir.ui.view')
|
||||
view_id = view_obj.search(cr, uid, [('model', '=', 'crm.phonecall2partner'), \
|
||||
('name', '=', 'crm.phonecall2partner.view')])
|
||||
return {
|
||||
'view_mode': 'form',
|
||||
'view_type': 'form',
|
||||
'view_id': view_id or False,
|
||||
'res_model': 'crm.phonecall2partner',
|
||||
'context': context,
|
||||
'type': 'ir.actions.act_window',
|
||||
'target': 'new',
|
||||
}
|
||||
|
||||
|
||||
def _create_partner(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
This function Creates partner based on action.
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Phonecall to Partner's IDs
|
||||
@param context: A standard dictionary for contextual values
|
||||
|
||||
@return : Dictionary {}.
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
phonecall = self.pool.get('crm.phonecall')
|
||||
|
||||
phonecall_obj = self.pool.get('crm.phonecall')
|
||||
partner_obj = self.pool.get('res.partner')
|
||||
contact_obj = self.pool.get('res.partner.address')
|
||||
partner_ids = []
|
||||
contact_id = False
|
||||
|
||||
rec_ids = context and context.get('active_ids', [])
|
||||
|
||||
for data in self.browse(cr, uid, ids, context=context):
|
||||
for phonecall in phonecall_obj.browse(cr, uid, rec_ids, context=context):
|
||||
if data.action == 'create':
|
||||
partner_id = partner_obj.create(cr, uid, {
|
||||
'name': phonecall.name or phonecall.name,
|
||||
'user_id': phonecall.user_id.id,
|
||||
'comment': phonecall.description,
|
||||
})
|
||||
contact_id = contact_obj.create(cr, uid, {
|
||||
'partner_id': partner_id,
|
||||
'name': phonecall.name,
|
||||
'phone': phonecall.partner_phone,
|
||||
})
|
||||
|
||||
else:
|
||||
if data.partner_id:
|
||||
partner_id = data.partner_id.id
|
||||
contact_id = partner_obj.address_get(cr, uid, [partner_id])['default']
|
||||
|
||||
partner_ids.append(partner_id)
|
||||
|
||||
vals = {}
|
||||
if partner_id:
|
||||
vals.update({'partner_id': partner_id})
|
||||
if contact_id:
|
||||
vals.update({'partner_address_id': contact_id})
|
||||
phonecall_obj.write(cr, uid, [phonecall.id], vals)
|
||||
return partner_ids
|
||||
|
||||
def make_partner(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
This function Makes partner based on action.
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Phonecall to Partner's IDs
|
||||
@param context: A standard dictionary for contextual values
|
||||
|
||||
@return : Dictionary value for created Partner form.
|
||||
"""
|
||||
|
||||
partner_ids = self._create_partner(cr, uid, ids, context=context)
|
||||
mod_obj = self.pool.get('ir.model.data')
|
||||
result = mod_obj._get_id(cr, uid, 'base', 'view_res_partner_filter')
|
||||
res = mod_obj.read(cr, uid, result, ['res_id'])
|
||||
|
||||
value = {
|
||||
'domain': "[]",
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form,tree',
|
||||
'res_model': 'res.partner',
|
||||
'res_id': partner_ids and int(partner_ids[0]) or False,
|
||||
'view_id': False,
|
||||
'context': context,
|
||||
'type': 'ir.actions.act_window',
|
||||
'search_view_id': res['res_id']
|
||||
}
|
||||
return value
|
||||
data = self.browse(cr, uid, ids, context=context)[0]
|
||||
call_ids = context and context.get('active_ids') or []
|
||||
partner_id = data.partner_id and data.partner_id.id or False
|
||||
partner_ids = phonecall.convert_partner(cr, uid, call_ids, data.action, partner_id, context=context)
|
||||
return partner_ids[call_ids[0]]
|
||||
|
||||
crm_phonecall2partner()
|
||||
|
||||
|
|
|
@ -25,108 +25,50 @@ from tools.translate import _
|
|||
import time
|
||||
|
||||
class crm_phonecall2phonecall(osv.osv_memory):
|
||||
""" Converts Phonecall to Phonecall"""
|
||||
|
||||
_name = 'crm.phonecall2phonecall'
|
||||
_description = 'Phonecall To Phonecall'
|
||||
|
||||
_columns = {
|
||||
'name' : fields.char('Call summary', size=64, required=True, select=1),
|
||||
'user_id' : fields.many2one('res.users',"Assign To"),
|
||||
'contact_name':fields.char('Contact', size=64),
|
||||
'phone':fields.char('Phone', size=64),
|
||||
'categ_id': fields.many2one('crm.case.categ', 'Category', \
|
||||
domain="['|',('section_id','=',False),('section_id','=',section_id),\
|
||||
('object_id.model', '=', 'crm.phonecall')]"),
|
||||
'date': fields.datetime('Date'),
|
||||
'section_id':fields.many2one('crm.case.section','Sales Team'),
|
||||
'action': fields.selection([('schedule','Schedule a call'), ('log','Log a call')], 'Action', required=True),
|
||||
'partner_id' : fields.many2one('res.partner', "Partner"),
|
||||
'note':fields.text('Note')
|
||||
}
|
||||
|
||||
|
||||
def action_cancel(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Closes Phonecall to Phonecall form
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Phonecall to Phonecall's IDs
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
return {'type':'ir.actions.act_window_close'}
|
||||
|
||||
def action_apply(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
This converts Phonecall to Phonecall and opens Phonecall view
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of Phonecall to Phonecall IDs
|
||||
@param context: A standard dictionary for contextual values
|
||||
|
||||
@return : Dictionary value for created Opportunity form
|
||||
"""
|
||||
res = {}
|
||||
record_id = context and context.get('active_id', False) or False
|
||||
phonecall_obj = self.pool.get('crm.phonecall')
|
||||
|
||||
if record_id:
|
||||
data_obj = self.pool.get('ir.model.data')
|
||||
|
||||
# Get Phonecall views
|
||||
result = data_obj._get_id(cr, uid, 'crm', 'view_crm_case_phonecalls_filter')
|
||||
res = data_obj.read(cr, uid, result, ['res_id'])
|
||||
id2 = data_obj._get_id(cr, uid, 'crm', 'crm_case_phone_form_view')
|
||||
id3 = data_obj._get_id(cr, uid, 'crm', 'crm_case_phone_tree_view')
|
||||
if id2:
|
||||
id2 = data_obj.browse(cr, uid, id2, context=context).res_id
|
||||
if id3:
|
||||
id3 = data_obj.browse(cr, uid, id3, context=context).res_id
|
||||
|
||||
phonecall = phonecall_obj.browse(cr, uid, record_id, context=context)
|
||||
|
||||
for this in self.browse(cr, uid, ids, context=context):
|
||||
values = {
|
||||
'name': this.name,
|
||||
'user_id': this.user_id and this.user_id.id,
|
||||
'categ_id': this.categ_id.id,
|
||||
'section_id': this.section_id.id or (phonecall.section_id and phonecall.section_id.id),
|
||||
'description': phonecall.description or '',
|
||||
'partner_id': phonecall.partner_id.id,
|
||||
'partner_address_id': phonecall.partner_address_id.id,
|
||||
'partner_mobile': phonecall.partner_mobile or False,
|
||||
'priority': phonecall.priority,
|
||||
'partner_phone': phonecall.partner_phone or False,
|
||||
'date': this.date
|
||||
}
|
||||
phonecall_id = phonecall_obj.create(cr, uid, values, context=context)
|
||||
if this.action == 'schedule':
|
||||
phonecall_obj.case_open(cr, uid, [phonecall_id])
|
||||
elif this.action == 'log':
|
||||
phonecall_obj.case_close(cr, uid, [phonecall_id])
|
||||
|
||||
res = {
|
||||
'name': _('Phone Call'),
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form',
|
||||
'res_model': 'crm.phonecall',
|
||||
'view_id': False,
|
||||
'views': [(id2, 'form'), (id3, 'tree'), (False, 'calendar'), (False, 'graph')],
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_id': phonecall_id,
|
||||
'domain': [('id', '=', phonecall_id)],
|
||||
'search_view_id': res['res_id']
|
||||
}
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'name' : fields.char('Call summary', size=64, required=True, select=1),
|
||||
'user_id' : fields.many2one('res.users',"Assign To"),
|
||||
'categ_id': fields.many2one('crm.case.categ', 'Category', \
|
||||
domain="['|',('section_id','=',False),('section_id','=',section_id),\
|
||||
('object_id.model', '=', 'crm.phonecall')]"),
|
||||
'date': fields.datetime('Date'),
|
||||
'section_id':fields.many2one('crm.case.section','Sales Team'),
|
||||
'action': fields.selection([('schedule','Schedule a call'), ('log','Log a call')], 'Action', required=True),
|
||||
'partner_id' : fields.many2one('res.partner', "Partner"),
|
||||
}
|
||||
def action_schedule(self, cr, uid, ids, context=None):
|
||||
value = {}
|
||||
if context is None:
|
||||
context = {}
|
||||
phonecall = self.pool.get('crm.phonecall')
|
||||
phonecall_ids = context and context.get('active_ids') or []
|
||||
for this in self.browse(cr, uid, ids, context=context):
|
||||
phocall_ids = phonecall.schedule_another_phonecall(cr, uid, phonecall_ids, this.date, this.name, \
|
||||
this.user_id and this.user_id.id or False, \
|
||||
this.section_id and this.section_id.id or False, \
|
||||
this.categ_id and this.categ_id.id or False, \
|
||||
action=this.action, context=context)
|
||||
|
||||
return phonecall.redirect_phonecall_view(cr, uid, phocall_ids[phonecall_ids[0]], context=context)
|
||||
|
||||
def default_get(self, cr, uid, fields, context=None):
|
||||
"""
|
||||
This function gets default values
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@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
|
||||
|
||||
@return : default values of fields.
|
||||
|
||||
"""
|
||||
res = super(crm_phonecall2phonecall, self).default_get(cr, uid, fields, context=context)
|
||||
record_id = context and context.get('active_id', False) or False
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
<separator string=" " colspan="4"/>
|
||||
<group colspan="4" col="3" >
|
||||
<button name="action_cancel" string="_Cancel" icon="gtk-cancel" special="cancel" />
|
||||
<button name="action_apply" type="object" string="Log call" icon="gtk-ok" attrs="{'invisible' : [('action', '!=', 'log')]}" />
|
||||
<button name="action_apply" type="object" string="Schedule call" icon="gtk-ok" attrs="{'invisible' : [('action', '!=', 'schedule')]}" />
|
||||
<button name="action_schedule" type="object" string="Log call" icon="gtk-ok" attrs="{'invisible' : [('action', '!=', 'log')]}" />
|
||||
<button name="action_schedule" type="object" string="Schedule call" icon="gtk-ok" attrs="{'invisible' : [('action', '!=', 'schedule')]}" />
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
|
|
|
@ -48,7 +48,9 @@ automatically new claims based on incoming emails.
|
|||
'demo_xml': [
|
||||
'crm_claim_demo.xml',
|
||||
],
|
||||
'test': ['test/test_crm_claim.yml'],
|
||||
'test': ['test/process/claim.yml',
|
||||
'test/ui/claim_demo.yml'
|
||||
],
|
||||
'installable': True,
|
||||
'active': False,
|
||||
'certificate' : '00612027414703404749',
|
||||
|
|
|
@ -46,6 +46,7 @@ class crm_claim(crm.crm_case, osv.osv):
|
|||
_columns = {
|
||||
'id': fields.integer('ID', readonly=True),
|
||||
'name': fields.char('Claim Subject', size=128, required=True),
|
||||
'active': fields.boolean('Active'),
|
||||
'action_next': fields.char('Next Action', size=200),
|
||||
'date_action_next': fields.datetime('Next Action Date'),
|
||||
'description': fields.text('Description'),
|
||||
|
@ -95,6 +96,7 @@ class crm_claim(crm.crm_case, osv.osv):
|
|||
'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.case', context=c),
|
||||
'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
|
||||
'active': lambda *a: 1
|
||||
}
|
||||
|
||||
def onchange_partner_id(self, cr, uid, ids, part, email=False):
|
||||
|
@ -129,8 +131,6 @@ class crm_claim(crm.crm_case, osv.osv):
|
|||
if l.state == 'draft':
|
||||
message = _("The claim '%s' has been opened.") % l.name
|
||||
self.log(cr, uid, l.id, message)
|
||||
value = {'date_open': time.strftime('%Y-%m-%d %H:%M:%S')}
|
||||
self.write(cr, uid, [l.id], value)
|
||||
stage_id = self.stage_find(cr, uid, l.section_id.id or False, [('sequence','>',0)])
|
||||
if stage_id:
|
||||
self.stage_set(cr, uid, [l.id], stage_id)
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
<field eval=""Problem with the delivery of goods"" name="name"/>
|
||||
<field eval=""open"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval=""(726) 782-0636"" name="partner_mobile"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field name="categ_id" ref="crm_claim.categ_claim1"/>
|
||||
<field name="stage_id" ref="crm_claim.stage_claim1"/>
|
||||
<field eval=""(769) 703-274"" name="partner_phone"/>
|
||||
|
@ -31,8 +29,6 @@
|
|||
<field eval=""Damaged Products"" name="name"/>
|
||||
<field eval=""open"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval=""(392) 895-7917"" name="partner_mobile"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field name="categ_id" ref="crm_claim.categ_claim2"/>
|
||||
<field name="stage_id" ref="crm_claim.stage_claim5"/>
|
||||
<field eval=""(956) 293-2595"" name="partner_phone"/>
|
||||
|
@ -47,8 +43,6 @@
|
|||
<field eval=""Document related problems"" name="name"/>
|
||||
<field eval=""done"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval=""(820) 167-3208"" name="partner_mobile"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field name="categ_id" ref="crm_claim.categ_claim3"/>
|
||||
<field name="stage_id" ref="crm_claim.stage_claim2"/>
|
||||
<field eval=""(079) 681-2139"" name="partner_phone"/>
|
||||
|
@ -63,8 +57,6 @@
|
|||
<field eval=""Product quality not maintained"" name="name"/>
|
||||
<field eval=""draft"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval=""(077) 582-4035"" name="partner_mobile"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field name="categ_id" ref="crm_claim.categ_claim1"/>
|
||||
<field name="stage_id" ref="crm_claim.stage_claim5"/>
|
||||
<field eval=""(514) 698-4118"" name="partner_phone"/>
|
||||
|
@ -79,8 +71,6 @@
|
|||
<field eval=""Some products missing"" name="name"/>
|
||||
<field eval=""pending"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval=""(333) 715-1450"" name="partner_mobile"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field name="categ_id" ref="crm_claim.categ_claim3"/>
|
||||
<field name="stage_id" ref="crm_claim.stage_claim3"/>
|
||||
<field eval=""(855) 924-4364"" name="partner_phone"/>
|
||||
|
@ -88,14 +78,12 @@
|
|||
|
||||
<record id="crm_case_claim06" model="crm.claim">
|
||||
<field name="partner_address_id" ref="base.res_partner_address_1"/>
|
||||
<field eval="1" name="active"/>
|
||||
<field name="partner_id" ref="base.res_partner_9"/>
|
||||
<field eval=""3"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval=""Problem with the delivery of assignments"" name="name"/>
|
||||
<field eval=""cancel"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval=""(468) 017-2684"" name="partner_mobile"/>
|
||||
<field eval="time.strftime('%Y-%m-28 14:15:30')" name="date"/>
|
||||
<field name="categ_id" ref="crm_claim.categ_claim1"/>
|
||||
<field name="stage_id" ref="crm_claim.stage_claim5"/>
|
||||
|
@ -104,14 +92,12 @@
|
|||
</record>
|
||||
|
||||
<record id="crm_case_claims07" model="crm.claim">
|
||||
<field eval="1" name="active"/>
|
||||
<field name="partner_id" ref="base.res_partner_seagate"/>
|
||||
<field eval=""3"" name="priority"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field eval=""Documents unclear"" name="name"/>
|
||||
<field eval=""done"" name="state"/>
|
||||
<field name="section_id" ref="crm.section_sales_department"/>
|
||||
<field eval="" (463) 014-1208"" name="partner_mobile"/>
|
||||
<field eval="time.strftime('%Y-%m-19 13:01:05')" name="date"/>
|
||||
<field name="categ_id" ref="crm_claim.categ_claim3"/>
|
||||
<field name="stage_id" ref="crm_claim.stage_claim2"/>
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
Message-ID: <4EA66F25.7080001@customer.com>
|
||||
Date: Tue, 25 Oct 2011 13:41:17 +0530
|
||||
From: Mr. John Right <info@customer.com>
|
||||
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.14) Gecko/20110223 Lightning/1.0b2 Thunderbird/3.1.8
|
||||
MIME-Version: 1.0
|
||||
To: claims@my.com
|
||||
Subject: demande de =?ISO-8859-1?Q?r=E8glement_de_votre_produit=2E?=
|
||||
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
J'ai acheté votre produit il ya quelques jours. maintenant certains
|
||||
problèmes sont survenus sur votre produit.
|
||||
je demande donc à convertir cette demande que la réclamation et de
|
||||
résoudre les problèmes le plus tôt possible.
|
||||
|
||||
Merci
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
-
|
||||
Customer requests a claim after the sale of our product. He sends claim request by email.
|
||||
-
|
||||
Mail script will be fetched him request from mail server. so I process that mail after read EML file
|
||||
-
|
||||
!python {model: mail.thread}: |
|
||||
import addons
|
||||
request_file = open(addons.get_module_resource('crm_claim','test', 'customer_claim.eml'),'rb')
|
||||
request_message = request_file.read()
|
||||
self.message_process(cr, uid, 'crm.claim', request_message)
|
||||
-
|
||||
After getting the mail, I check details of new claim of that customer.
|
||||
-
|
||||
!python {model: crm.claim}: |
|
||||
from openerp import tools
|
||||
claim_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
|
||||
assert claim_ids and len(claim_ids), "Claim is not created after getting request"
|
||||
claim = self.browse(cr, uid, claim_ids[0], context=context)
|
||||
assert claim.name == tools.ustr("demande derèglement de votre produit."), "Subject does not match"
|
||||
-
|
||||
I open customer claim.
|
||||
-
|
||||
!python {model: crm.claim}: |
|
||||
claim_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
|
||||
self.case_open(cr, uid, claim_ids)
|
||||
-
|
||||
I check Claim Details after open.
|
||||
-
|
||||
!python {model: crm.claim}: |
|
||||
claim_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
|
||||
claim = self.browse(cr, uid, claim_ids[0])
|
||||
assert claim.state == "open", "Claim is not in Open state"
|
||||
assert claim.stage_id.id == ref("crm.stage_lead1"), "Claim is not in New stage"
|
||||
-
|
||||
After complete all service from our side, I close this claim.
|
||||
-
|
||||
!python {model: crm.claim}: |
|
||||
claim_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
|
||||
self.case_close(cr, uid, claim_ids)
|
||||
-
|
||||
I check Claim details after closed.
|
||||
-
|
||||
!python {model: crm.claim}: |
|
||||
claim_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
|
||||
claim = self.browse(cr, uid, claim_ids[0])
|
||||
assert claim.state == "done", "Claim is not in close state"
|
|
@ -1,44 +0,0 @@
|
|||
- |
|
||||
I check claims which contain customer claim information about document
|
||||
related problem, product related problem.
|
||||
- |
|
||||
I start by creating new claims for Damaged product as Value Claims with priority High and specify
|
||||
date of claim at which claim is created.
|
||||
-
|
||||
!record {model: crm.claim, id: crm_claim_damagedproduct0}:
|
||||
categ_id: crm_claim.categ_claim2
|
||||
date: !eval time.strftime('%Y-%m-%d %H:%M:%S')
|
||||
email_from: info@balmerinc.be
|
||||
name: 'Damaged product '
|
||||
partner_address_id: base.res_partner_address_1
|
||||
partner_id: base.res_partner_9
|
||||
priority: '2'
|
||||
section_id: crm.section_sales_department
|
||||
|
||||
- |
|
||||
I check that the claims is in 'draft' state.
|
||||
-
|
||||
!assert {model: crm.claim, id: crm_claim_damagedproduct0}:
|
||||
- state == 'draft'
|
||||
- |
|
||||
I can change that stage by next button right on it.
|
||||
-
|
||||
!python {model: crm.claim}: |
|
||||
self.stage_next(cr, uid, [ref('crm_claim_damagedproduct0')])
|
||||
- |
|
||||
I make this claim as Open.
|
||||
-
|
||||
!python {model: crm.claim}: |
|
||||
self.case_open(cr, uid, [ref('crm_claim_damagedproduct0')])
|
||||
- |
|
||||
I am changing partner Assigned to the Claim.
|
||||
-
|
||||
!python {model: crm.claim}: |
|
||||
self.onchange_partner_id(cr, uid, [ref('crm_claim_damagedproduct0')], [])
|
||||
self.onchange_partner_id(cr, uid, [ref('crm_claim_damagedproduct0')], ref('base.res_partner_10'))
|
||||
- |
|
||||
I am changing partner Address to the Claim.
|
||||
-
|
||||
!python {model: crm.claim}: |
|
||||
self.onchange_partner_address_id(cr, uid, [ref('crm_claim_damagedproduct0')], [], email = False)
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
-
|
||||
I create claim record to call of partner onchange method.
|
||||
-
|
||||
!record {model: crm.claim, id: crm_case_claim04}:
|
||||
name: 'Damaged Product'
|
||||
partner_id: base.res_partner_6
|
||||
-
|
||||
I Update the message for claim.
|
||||
-
|
||||
!python {model: crm.claim}: |
|
||||
try:
|
||||
self.message_update(cr, uid,[ref('crm_case_claim04')], {'subject': 'Claim Update record','body_text': 'first training session completed',})
|
||||
except:
|
||||
pass
|
||||
|
|
@ -51,7 +51,7 @@ fund status.
|
|||
'demo_xml': [
|
||||
'crm_fundraising_demo.xml',
|
||||
],
|
||||
'test': ['test/test_crm_fund.yml'],
|
||||
'test': ['test/process/fund-rising.yml'],
|
||||
'installable': True,
|
||||
'active': False,
|
||||
'certificate' : '00871545204231528989',
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
Message-ID: <4EA66F25.7080010@customer.com>
|
||||
Date: Tue, 25 Oct 2011 13:41:17 +0530
|
||||
From: Mr. John Right <info@customer.com>
|
||||
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.14) Gecko/20110223 Lightning/1.0b2 Thunderbird/3.1.8
|
||||
MIME-Version: 1.0
|
||||
To: contribute@my.com
|
||||
Subject: Demande de controbute dans votre fonds.
|
||||
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Client est très heureux d'utiliser notre produit et il l'intérêt de donner une partie des fonds dans notre produit. Il a donc envoyé la demande par courriel pour les collectes de fonds.
|
||||
|
||||
Merci
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
-
|
||||
Customer is very happy with our service and he interest to contribute into our fund. so He sent request by email for Fundraising.
|
||||
-
|
||||
Mail script will be fetched him request from mail server. so I process that mail after read EML file
|
||||
-
|
||||
!python {model: mail.thread}: |
|
||||
import addons
|
||||
request_file = open(addons.get_module_resource('crm_fundraising','test', 'customer_fundraising.eml'),'rb')
|
||||
request_message = request_file.read()
|
||||
self.message_process(cr, uid, 'crm.fundraising', request_message)
|
||||
-
|
||||
After getting the mail, I check details of new fundraising of that customer.
|
||||
-
|
||||
!python {model: crm.fundraising}: |
|
||||
from openerp import tools
|
||||
fund_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
|
||||
assert fund_ids and len(fund_ids), "Fund is not created after getting request"
|
||||
fund = self.browse(cr, uid, fund_ids[0], context=context)
|
||||
assert fund.name == tools.ustr("Demande de controbute dans votre fonds."), "Subject does not match"
|
|
@ -1,45 +0,0 @@
|
|||
- |
|
||||
I start test Fund Raising which contain information about Donation or charity
|
||||
given by user.
|
||||
- |
|
||||
I start by creating new Funds entry for donation for books to poor school children
|
||||
with cost 500000.00 and category as "Learning And Education"
|
||||
I make payment by Cheque so I make sure that the mode on fund is selected as cheque.
|
||||
-
|
||||
!record {model: crm.fundraising, id: crm_fundraising_donationforbookstopoorschoolchildren0}:
|
||||
categ_id: crm_fundraising.categ_fund2
|
||||
email_from: info@balmerinc.be
|
||||
name: Donation for books to poor school children
|
||||
partner_address_id: base.res_partner_address_1
|
||||
partner_id: base.res_partner_9
|
||||
planned_cost: 500000.0
|
||||
section_id: crm.section_sales_department
|
||||
type_id: crm_fundraising.type_fund2
|
||||
- |
|
||||
I check that the Funds is in 'draft' state.
|
||||
-
|
||||
!assert {model: crm.fundraising, id: crm_fundraising_donationforbookstopoorschoolchildren0}:
|
||||
- state == 'draft'
|
||||
- |
|
||||
I open Funds by click on "Open" button.
|
||||
-
|
||||
!python {model: crm.fundraising}: |
|
||||
self.case_open(cr, uid, [ref('crm_fundraising_donationforbookstopoorschoolchildren0')])
|
||||
-
|
||||
I create the message regarding the all details of fundraising.
|
||||
-
|
||||
!python {model: crm.fundraising}: |
|
||||
msg = {
|
||||
'subject': 'fundraising_email',
|
||||
'body_text': 'fundraising details',
|
||||
'from': 'Administrator <admin@openerp.com>',
|
||||
'priority':'3',
|
||||
}
|
||||
context = None
|
||||
self.message_new(cr, uid,msg,context)
|
||||
|
||||
- |
|
||||
After a request via email now I close this fundraising Request by clicking on "Done" button.
|
||||
-
|
||||
!python {model: crm.fundraising}: |
|
||||
self.case_close(cr, uid, [ref('crm_fundraising_donationforbookstopoorschoolchildren0')])
|
|
@ -49,7 +49,7 @@ and categorize your interventions with a channel and a priority level.
|
|||
'demo_xml': [
|
||||
'crm_helpdesk_demo.xml',
|
||||
],
|
||||
'test': ['test/test_crm_helpdesk.yml'],
|
||||
'test': ['test/process/help-desk.yml'],
|
||||
'installable': True,
|
||||
'active': False,
|
||||
'certificate' : '00830691522781519309',
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
Message-ID: <4EA66F25.7080013@customer.com>
|
||||
Date: Tue, 25 Oct 2011 13:41:17 +0530
|
||||
From: Mr. John Right <info@customer.com>
|
||||
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.14) Gecko/20110223 Lightning/1.0b2 Thunderbird/3.1.8
|
||||
MIME-Version: 1.0
|
||||
To: info@my.com
|
||||
Subject: Where is download link of user manual of your product ?
|
||||
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
I want to download user manual of your product.
|
||||
can you provide download link?
|
||||
|
||||
Thanks
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
-
|
||||
Customer has Questions regarding our service. so He sent questions list by email.
|
||||
-
|
||||
Mail script will be fetched him request from mail server. so I process that mail after read EML file
|
||||
-
|
||||
!python {model: mail.thread}: |
|
||||
import addons
|
||||
request_file = open(addons.get_module_resource('crm_helpdesk','test', 'customer_question.eml'),'rb')
|
||||
request_message = request_file.read()
|
||||
self.message_process(cr, uid, 'crm.helpdesk', request_message)
|
||||
-
|
||||
After getting the mail, I check details of new question of that customer.
|
||||
-
|
||||
!python {model: crm.helpdesk}: |
|
||||
from openerp import tools
|
||||
question_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
|
||||
assert question_ids and len(question_ids), "Question is not created after getting request"
|
||||
question = self.browse(cr, uid, question_ids[0], context=context)
|
||||
assert question.name == tools.ustr("Where is download link of user manual of your product ? "), "Subject does not match"
|
||||
-
|
||||
Now I Update message according to provide services.
|
||||
-
|
||||
!python {model: crm.helpdesk}: |
|
||||
question_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right <info@customer.com>')])
|
||||
try:
|
||||
self.message_update(cr, uid, question_ids, {'subject': 'Link of product', 'body_text': 'www.openerp.com'})
|
||||
except:
|
||||
pass
|
||||
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
-
|
||||
|
|
||||
I start by creating New helpdesk request regarding some functional questions.
|
||||
I select Date at which helpdesk request is created.
|
||||
-
|
||||
!record {model: crm.helpdesk, id: crm_helpdesk_somefunctionalquestion0}:
|
||||
date: !eval time.strftime('%Y-%m-%d %H:%M:%S')
|
||||
email_from: info@balmerinc.be
|
||||
name: Some functional question.
|
||||
partner_address_id: base.res_partner_address_1
|
||||
partner_id: base.res_partner_9
|
||||
section_id: crm.section_sales_department
|
||||
-
|
||||
I create the message.
|
||||
-
|
||||
!python {model: crm.helpdesk}: |
|
||||
msg = {
|
||||
'subject': 'test_email',
|
||||
'body_text': 'Testing',
|
||||
'from': 'Administrator <admin@openerp.com>',
|
||||
}
|
||||
context = None
|
||||
self.message_new(cr, uid,msg,context)
|
||||
|
||||
- |
|
||||
I check that the Helpdesk request is in 'Draft' state.
|
||||
-
|
||||
!assert {model: crm.helpdesk, id: crm_helpdesk_somefunctionalquestion0}:
|
||||
- state == 'draft'
|
||||
- |
|
||||
I make it "Open".
|
||||
-
|
||||
!python {model: crm.helpdesk}: |
|
||||
self.case_open(cr, uid, [ref('crm_helpdesk_somefunctionalquestion0')])
|
||||
-
|
||||
Update the created message.
|
||||
-
|
||||
!python {model: crm.helpdesk}: |
|
||||
vals = {}
|
||||
msg = {
|
||||
'subject': 'test_email',
|
||||
'body_text': 'Testing',
|
||||
'from': 'Administrator <admin@openerp.com>',
|
||||
'priority': 'done'
|
||||
}
|
||||
context = None
|
||||
default_act = 'pending'
|
||||
try:
|
||||
self.message_update(cr, uid,[ref('crm_helpdesk_somefunctionalquestion0')], msg,context)
|
||||
except:
|
||||
pass
|
||||
- |
|
||||
After a proper communication for the request via email I make sure that the request is fulfilled and
|
||||
I close this HelpDesk Request by clicking on "Close" button.
|
||||
-
|
||||
!python {model: crm.helpdesk}: |
|
||||
self.case_close(cr, uid, [ref('crm_helpdesk_somefunctionalquestion0')])
|
|
@ -38,6 +38,9 @@ You can also use the geolocalization without using the GPS coordinates.
|
|||
""",
|
||||
'author': 'OpenERP SA',
|
||||
'depends': ['crm'],
|
||||
'demo_xml': [
|
||||
'res_partner_demo.xml',
|
||||
],
|
||||
'update_xml': [
|
||||
'security/ir.model.access.csv',
|
||||
'res_partner_view.xml',
|
||||
|
@ -46,7 +49,9 @@ You can also use the geolocalization without using the GPS coordinates.
|
|||
'report/crm_lead_report_view.xml',
|
||||
'report/crm_partner_report_view.xml',
|
||||
],
|
||||
'test': ['test/test_crm_partner_assign.yml'],
|
||||
'test': [
|
||||
'test/process/partner_assign.yml',
|
||||
],
|
||||
'installable': True,
|
||||
'active': False,
|
||||
'certificate': '00503409558942442061',
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<field name="inherit_id" ref="crm.crm_case_form_view_oppor"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<xpath expr="//notebook[last()]" position="inside">
|
||||
<xpath expr="//notebook/page[@string='Lead']" position="after">
|
||||
<page string="Assignation" groups="base.group_extended">
|
||||
<group name="partner_assign_group" col="5" colspan="4">
|
||||
<separator string="Partner Assignation" colspan="5"/>
|
||||
|
@ -27,7 +27,7 @@
|
|||
<field name="partner_latitude"/>
|
||||
<field name="partner_longitude"/>
|
||||
<group colspan="1" col="1">
|
||||
<button string="Geo Assign" name="assign_partner" type="object" colspan="1"
|
||||
<button string="Geo Assign" name="action_assign_partner" type="object" colspan="1"
|
||||
icon="gtk-apply"/>
|
||||
</group>
|
||||
</group>
|
||||
|
|
|
@ -24,22 +24,25 @@ from osv import fields
|
|||
import urllib,re
|
||||
import random, time
|
||||
from tools.translate import _
|
||||
import tools
|
||||
|
||||
def geo_find(addr):
|
||||
addr = addr.encode('utf8')
|
||||
regex = '<coordinates>([+-]?[0-9\.]+),([+-]?[0-9\.]+),([+-]?[0-9\.]+)</coordinates>'
|
||||
url = 'http://maps.google.com/maps/geo?q=' + urllib.quote(addr) + '&output=xml&oe=utf8&sensor=false'
|
||||
try:
|
||||
regex = '<coordinates>([+-]?[0-9\.]+),([+-]?[0-9\.]+),([+-]?[0-9\.]+)</coordinates>'
|
||||
url = 'http://maps.google.com/maps/geo?q=' + urllib.quote(addr) + '&output=xml&oe=utf8&sensor=false'
|
||||
xml = urllib.urlopen(url).read()
|
||||
if '<error>' in xml:
|
||||
return None
|
||||
result = re.search(regex, xml, re.M|re.I)
|
||||
if not result:
|
||||
return None
|
||||
return float(result.group(2)),float(result.group(1))
|
||||
except Exception, e:
|
||||
raise osv.except_osv(_('Network error'),
|
||||
_('Could not contact geolocation servers, please make sure you have a working internet connection (%s)') % e)
|
||||
|
||||
if '<error>' in xml:
|
||||
return None
|
||||
result = re.search(regex, xml, re.M|re.I)
|
||||
if not result:
|
||||
return None
|
||||
return float(result.group(2)),float(result.group(1))
|
||||
|
||||
|
||||
class res_partner_grade(osv.osv):
|
||||
_order = 'sequence'
|
||||
|
@ -74,9 +77,13 @@ class res_partner(osv.osv):
|
|||
for partner in self.browse(cr, uid, ids, context=context):
|
||||
if not partner.address:
|
||||
continue
|
||||
part = partner.address[0]
|
||||
addr = ', '.join(filter(None, [part.street, (part.zip or '')+' '+(part.city or ''), part.state_id and part.state_id.name, part.country_id and part.country_id.name]))
|
||||
result = geo_find(addr.encode('utf8'))
|
||||
contact = partner.address[0] #TOFIX: should be get latitude and longitude for default contact?
|
||||
addr = ', '.join(filter(None, [
|
||||
contact.street,
|
||||
"%s %s" % (contact.zip , contact.city),
|
||||
contact.state_id and contact.state_id.name,
|
||||
contact.country_id and contact.country_id.name]))
|
||||
result = geo_find(tools.ustr(addr))
|
||||
if result:
|
||||
self.write(cr, uid, [partner.id], {
|
||||
'partner_latitude': result[0],
|
||||
|
@ -94,14 +101,13 @@ class crm_lead(osv.osv):
|
|||
'partner_assigned_id': fields.many2one('res.partner', 'Assigned Partner', help="Partner this case has been forwarded/assigned to.", select=True),
|
||||
'date_assign': fields.date('Assignation Date', help="Last date this case was forwarded/assigned to a partner"),
|
||||
}
|
||||
def _merge_data(self, cr, uid, ids, oldest, fields, context=None):
|
||||
fields += ['partner_latitude', 'partner_longitude', 'partner_assigned_id', 'date_assign']
|
||||
return super(crm_lead, self)._merge_data(cr, uid, ids, oldest, fields, context=context)
|
||||
|
||||
def onchange_assign_id(self, cr, uid, ids, partner_assigned_id, context=None):
|
||||
"""This function updates the "assignation date" automatically, when manually assign a partner in the geo assign tab
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of stage’s IDs
|
||||
@stage_id: change state id on run time """
|
||||
|
||||
"""
|
||||
if not partner_assigned_id:
|
||||
return {'value':{'date_assign': False}}
|
||||
else:
|
||||
|
@ -112,73 +118,113 @@ class crm_lead(osv.osv):
|
|||
'user_id' : user_id}
|
||||
}
|
||||
|
||||
def assign_partner(self, cr, uid, ids, context=None):
|
||||
ok = False
|
||||
for part in self.browse(cr, uid, ids, context=context):
|
||||
if not part.country_id:
|
||||
continue
|
||||
addr = ', '.join(filter(None, [part.street, (part.zip or '')+' '+(part.city or ''), part.state_id and part.state_id.name, part.country_id and part.country_id.name]))
|
||||
result = geo_find(addr.encode('utf8'))
|
||||
if result:
|
||||
self.write(cr, uid, [part.id], {
|
||||
'partner_latitude': result[0],
|
||||
'partner_longitude': result[1]
|
||||
}, context=context)
|
||||
def action_assign_partner(self, cr, uid, ids, context=None):
|
||||
return self.assign_partner(cr, uid, ids, partner_id=False, context=context)
|
||||
|
||||
def assign_partner(self, cr, uid, ids, partner_id=False, context=None):
|
||||
partner_ids = {}
|
||||
res = False
|
||||
res_partner = self.pool.get('res.partner')
|
||||
if not partner_id:
|
||||
partner_ids = self.search_geo_partner(cr, uid, ids, context=context)
|
||||
for lead in self.browse(cr, uid, ids, context=context):
|
||||
if not partner_id:
|
||||
partner_id = partner_ids.get(lead.id, False)
|
||||
if not partner_id:
|
||||
continue
|
||||
self.assign_geo_localize(cr, uid, [lead.id], lead.partner_latitude, lead.partner_longitude, context=context)
|
||||
partner = res_partner.browse(cr, uid, partner_id, context=context)
|
||||
if partner.user_id:
|
||||
for lead_id in ids:
|
||||
self.allocate_salesman(cr, uid, [lead_id], [partner.user_id.id], context=context)
|
||||
self.write(cr, uid, [lead.id], {'date_assign': time.strftime('%Y-%m-%d'), 'partner_assigned_id': partner_id}, context=context)
|
||||
return res
|
||||
|
||||
|
||||
def assign_geo_localize(self, cr, uid, ids, latitude=False, longitude=False, context=None):
|
||||
for lead in self.browse(cr, uid, ids, context=context):
|
||||
if not lead.country_id:
|
||||
continue
|
||||
addr = ', '.join(filter(None, [
|
||||
lead.street,
|
||||
"%s %s" % (lead.zip, lead.city),
|
||||
lead.state_id and lead.state_id.name or '',
|
||||
lead.country_id and lead.country_id.name or ''
|
||||
]))
|
||||
result = geo_find(tools.ustr(addr))
|
||||
if not latitude and result:
|
||||
latitude = result[0]
|
||||
if not longitude and result:
|
||||
longitude = result[1]
|
||||
self.write(cr, uid, [lead.id], {
|
||||
'partner_latitude': latitude,
|
||||
'partner_longitude': longitude
|
||||
}, context=context)
|
||||
return True
|
||||
|
||||
def search_geo_partner(self, cr, uid, ids, context=None):
|
||||
res_partner = self.pool.get('res.partner')
|
||||
res_partner_ids = {}
|
||||
self.assign_geo_localize(cr, uid, ids, context=context)
|
||||
for lead in self.browse(cr, uid, ids, context=context):
|
||||
partner_ids = []
|
||||
if not lead.country_id:
|
||||
continue
|
||||
latitude = lead.partner_latitude
|
||||
longitude = lead.partner_longitude
|
||||
if latitude and longitude:
|
||||
# 1. first way: in the same country, small area
|
||||
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),
|
||||
('country', '=', part.country_id.id),
|
||||
partner_ids = res_partner.search(cr, uid, [
|
||||
('partner_weight', '>', 0),
|
||||
('partner_latitude', '>', latitude - 2), ('partner_latitude', '<', latitude + 2),
|
||||
('partner_longitude', '>', longitude - 1.5), ('partner_longitude', '<', longitude + 1.5),
|
||||
('country', '=', lead.country_id.id),
|
||||
], context=context)
|
||||
|
||||
# 2. second way: in the same country, 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),
|
||||
('country', '=', part.country_id.id),
|
||||
if not partner_ids:
|
||||
partner_ids = res_partner.search(cr, uid, [
|
||||
('partner_weight', '>', 0),
|
||||
('partner_latitude', '>', latitude - 4), ('partner_latitude', '<', latitude + 4),
|
||||
('partner_longitude', '>', longitude - 3), ('partner_longitude', '<' , longitude + 3),
|
||||
('country', '=', lead.country_id.id),
|
||||
], context=context)
|
||||
|
||||
|
||||
# 5. fifth way: anywhere in same country
|
||||
if not part_ids:
|
||||
if not partner_ids:
|
||||
# still haven't found any, let's take all partners in the country!
|
||||
part_ids = self.pool.get('res.partner').search(cr, uid, [
|
||||
('partner_weight','>',0),
|
||||
('country', '=', part.country_id.id),
|
||||
partner_ids = res_partner.search(cr, uid, [
|
||||
('partner_weight', '>', 0),
|
||||
('country', '=', lead.country_id.id),
|
||||
], context=context)
|
||||
|
||||
# 6. sixth way: closest partner whatsoever, just to have at least one result
|
||||
if not part_ids:
|
||||
if not partner_ids:
|
||||
# warning: point() type takes (longitude, latitude) as parameters in this order!
|
||||
cr.execute("""SELECT id, distance
|
||||
FROM (select id, (point(partner_longitude, partner_latitude) <-> point(%s,%s)) AS distance FROM res_partner
|
||||
WHERE partner_longitude is not null
|
||||
AND partner_latitude is not null
|
||||
AND partner_weight > 0) AS d
|
||||
ORDER BY distance LIMIT 1""", (result[1],result[0]))
|
||||
ORDER BY distance LIMIT 1""", (longitude, latitude))
|
||||
res = cr.dictfetchone()
|
||||
if res:
|
||||
part_ids.append(res['id'])
|
||||
partner_ids.append(res['id'])
|
||||
|
||||
total = 0
|
||||
total_weight = 0
|
||||
toassign = []
|
||||
for part2 in self.pool.get('res.partner').browse(cr, uid, part_ids, context=context):
|
||||
total += part2.partner_weight
|
||||
toassign.append( (part2.id, total) )
|
||||
for partner in res_partner.browse(cr, uid, partner_ids, context=context):
|
||||
total_weight += partner.partner_weight
|
||||
toassign.append( (partner.id, total_weight) )
|
||||
|
||||
random.shuffle(toassign) # avoid always giving the leads to the first ones in db natural order!
|
||||
mypartner = random.randint(0,total)
|
||||
for t in toassign:
|
||||
if mypartner<=t[1]:
|
||||
vals = self.onchange_assign_id(cr,uid, ids, t[0], context=context)['value']
|
||||
vals.update({'partner_assigned_id': t[0], 'date_assign': time.strftime('%Y-%m-%d')})
|
||||
self.write(cr, uid, [part.id], vals, context=context)
|
||||
nearest_weight = random.randint(0, total_weight)
|
||||
for partner_id, weight in toassign:
|
||||
if nearest_weight <= weight:
|
||||
res_partner_ids[lead.id] = partner_id
|
||||
break
|
||||
ok = True
|
||||
return ok
|
||||
return res_partner_ids
|
||||
crm_lead()
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="res_partner_grade_first" model="res.partner.grade">
|
||||
<field name="name">First</field>
|
||||
<field name="sequence">1</field>
|
||||
</record>
|
||||
<record id="base.res_partner_ericdubois0" model="res.partner">
|
||||
<field name="grade_id" ref="res_partner_grade_first"/>
|
||||
<field name="partner_weight">10</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,37 @@
|
|||
-
|
||||
In order to test find nearest Partner functionality and assign to opportunity ,
|
||||
-
|
||||
I Set Geo Lattitude and Longitude according to partner address.
|
||||
-
|
||||
!python {model: res.partner}: |
|
||||
self.geo_localize(cr, uid, [ref('base.res_partner_ericdubois0')], context)
|
||||
-
|
||||
I check Geo Latitude and Longitude of partner after set
|
||||
-
|
||||
!python {model: res.partner}: |
|
||||
partner = self.browse(cr, uid, ref('base.res_partner_ericdubois0'))
|
||||
assert partner.partner_latitude == 50.4530495 , "Latitude is wrong"
|
||||
assert partner.partner_longitude == 3.9693885 , "Longitude is wrong"
|
||||
-
|
||||
I assign nearest partner to opportunity.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.assign_partner(cr, uid, [ref('crm.crm_case_abcfuelcounits0')], context=context)
|
||||
-
|
||||
I check assigned partner of opportunity who is nearest Geo Latitude and Longitude of opportunity.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
lead = self.browse(cr, uid, ref('crm.crm_case_abcfuelcounits0'))
|
||||
assert lead.partner_assigned_id.id == ref('base.res_partner_ericdubois0') , "Opportuniy is not assigned nearest partner"
|
||||
assert lead.partner_latitude == 50.8495239 , "Latitude is wrong"
|
||||
assert lead.partner_longitude == 4.3667002 , "Longitude is wrong"
|
||||
-
|
||||
I forward this opportunity to its nearest partner.
|
||||
-
|
||||
!python {model: crm.lead.forward.to.partner}: |
|
||||
context.update({'active_model': 'crm.lead', 'active_id': ref('crm.crm_case_abcfuelcounits0'), 'active_ids': [ref('crm.crm_case_abcfuelcounits0')]})
|
||||
forward_id = self.create(cr, uid, {'send_to': 'partner'}, context=context)
|
||||
try:
|
||||
self.action_forward(cr, uid, [forward_id], context=context)
|
||||
except:
|
||||
pass
|
|
@ -1,137 +0,0 @@
|
|||
-
|
||||
In order to test Forward Partner functionality, I create an opportunity and forward it to partner.
|
||||
-
|
||||
I assign an email address to Administrator.
|
||||
-
|
||||
!record {model: res.users, id: base.user_root}:
|
||||
user_email: admin@openerp.com
|
||||
-
|
||||
I create some partner grades.
|
||||
-
|
||||
I create a grade 'First'.
|
||||
-
|
||||
!record {model: res.partner.grade, id: res_partner_grade_first0}:
|
||||
name: First
|
||||
sequence: 1
|
||||
-
|
||||
I create another grade 'Second'.
|
||||
-
|
||||
!record {model: res.partner.grade, id: res_partner_grade_second0}:
|
||||
name: Second
|
||||
sequence: 2
|
||||
-
|
||||
I create one more grade 'Third'.
|
||||
-
|
||||
!record {model: res.partner.grade, id: res_partner_grade_third0}:
|
||||
name: Third
|
||||
sequence: 3
|
||||
-
|
||||
I assign grade 'First' to the partner 'Axelor'.
|
||||
-
|
||||
!record {model: res.partner, id: base.res_partner_desertic_hispafuentes}:
|
||||
grade_id: res_partner_grade_first0
|
||||
-
|
||||
I change the User email id or partner if needed.
|
||||
-
|
||||
!python {model: res.partner}: |
|
||||
self.geo_localize(cr, uid, [ref('base.res_partner_desertic_hispafuentes')], context)
|
||||
-
|
||||
I assgin a reply-to email address to Sales Team.
|
||||
-
|
||||
!record {model: crm.case.section, id: crm.section_sales_department}:
|
||||
reply_to: sales_openerp@openerp.com
|
||||
-
|
||||
I create an opportunity 'Questionnaire on OpenERP'.
|
||||
-
|
||||
!record {model: crm.lead, id: crm_lead_questionnaireonopenerp0}:
|
||||
categ_id: crm.categ_oppor7
|
||||
section_id: crm.section_sales_department
|
||||
country_id: base.fr
|
||||
date_assign: '2011-02-07'
|
||||
day_close: 0.0
|
||||
day_open: 0.0
|
||||
email_from: info@axelor.com
|
||||
name: Questionnaire on OpenERP
|
||||
partner_address_id: base.res_partner_address_3000
|
||||
partner_assigned_id: base.res_partner_desertic_hispafuentes
|
||||
partner_id: base.res_partner_desertic_hispafuentes
|
||||
partner_latitude: 0.0
|
||||
partner_longitude: 0.0
|
||||
phone: +33 1 64 61 04 01
|
||||
planned_revenue: 0.0
|
||||
probability: 0.0
|
||||
type: opportunity
|
||||
-
|
||||
I change the assigned partner.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.onchange_assign_id(cr, uid, [ref('crm_lead_questionnaireonopenerp0')], ref('base.res_partner_desertic_hispafuentes'), context)
|
||||
self.assign_partner(cr, uid, [ref('crm_lead_questionnaireonopenerp0')], context)
|
||||
-
|
||||
I change the User email id or partner if needed.
|
||||
-
|
||||
!python {model: crm.lead.forward.to.partner}: |
|
||||
context.update({'history': 'latest', })
|
||||
user = ref('base.user_root')
|
||||
self.on_change_email(cr, uid, [ref('crm_lead_questionnaireonopenerp0')], user)
|
||||
self.on_change_partner(cr, uid, [ref('crm_lead_questionnaireonopenerp0')], ref('base.res_partner_desertic_hispafuentes'))
|
||||
-
|
||||
I change in history define.
|
||||
-
|
||||
!python {model: crm.lead.forward.to.partner}: |
|
||||
context.update({'history': 'info', })
|
||||
self.on_change_history(cr, uid, [ref('crm_lead_questionnaireonopenerp0')], context.get('history'), context)
|
||||
-
|
||||
I check the case history.
|
||||
-
|
||||
!python {model: crm.lead.forward.to.partner}: |
|
||||
context.update({'history': 'latest', })
|
||||
self._get_case_history(cr, uid, context.get('history'), ref('crm_lead_questionnaireonopenerp0'), context=context)
|
||||
|
||||
context.update({'history': 'info', })
|
||||
self._get_case_history(cr, uid, context.get('history'), ref('crm_lead_questionnaireonopenerp0'), context=context)
|
||||
|
||||
context.update({'history': 'whole', })
|
||||
self._get_case_history(cr, uid, context.get('history'), ref('crm_lead_questionnaireonopenerp0'), context=context)
|
||||
-
|
||||
I get lead details.
|
||||
-
|
||||
!python {model: crm.lead.forward.to.partner}: |
|
||||
self.get_lead_details(cr, uid, ref('crm_lead_questionnaireonopenerp0'), context)
|
||||
-
|
||||
I click on Forward button.
|
||||
-
|
||||
!python {model: crm.lead.forward.to.partner}: |
|
||||
from tools import config
|
||||
vals = {
|
||||
'subject': 'email',
|
||||
'email_to': 'info@axelor.com',
|
||||
'email_from': 'Administrator <admin@openerp.com>',
|
||||
'reply_to': 'sales_openerp@openerp.com',
|
||||
'state': 'draft',
|
||||
'history': 'latest',
|
||||
}
|
||||
ids = self.create(cr, uid, vals, context={'active_id': ref('crm_lead_questionnaireonopenerp0'), 'active_model': 'crm.lead'})
|
||||
host = config.get('smtp_user', '127.0.0.1')
|
||||
assert config.get(host, True), 'SMTP not configured !'
|
||||
try:
|
||||
self.action_forward(cr, uid, [ids], context={'active_id': ref('crm_lead_questionnaireonopenerp0'), 'active_model': 'crm.lead'})
|
||||
except:
|
||||
pass
|
||||
-
|
||||
I create the opportunity.
|
||||
-
|
||||
!record {model: crm.lead, id: crm_opportunity2}:
|
||||
email_from: info@balmerinc.be
|
||||
name: 'FUEL CO 829264 - 10002 units'
|
||||
partner_address_id: base.res_partner_address_1
|
||||
partner_id: base.res_partner_9
|
||||
probability: 1.0
|
||||
stage_id: crm.stage_lead1
|
||||
categ_id: crm.categ_oppor2
|
||||
section_id: crm.section_sales_department
|
||||
- |
|
||||
I Update the data.
|
||||
-
|
||||
!python {model: crm.merge.opportunity}: |
|
||||
self._update_data([ref('crm_opportunity2')], ref('crm_lead_questionnaireonopenerp0'))
|
|
@ -20,6 +20,3 @@
|
|||
##############################################################################
|
||||
|
||||
import crm_forward_to_partner
|
||||
import crm_merge_opportunity
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -24,6 +24,7 @@ import time
|
|||
import re
|
||||
from osv import osv, fields
|
||||
from tools.translate import _
|
||||
from mail.mail_message import to_email
|
||||
|
||||
class crm_lead_forward_to_partner(osv.osv_memory):
|
||||
"""Forwards lead history"""
|
||||
|
@ -34,6 +35,7 @@ class crm_lead_forward_to_partner(osv.osv_memory):
|
|||
'send_to': fields.selection([('user', 'User'), ('partner', 'Partner'), \
|
||||
('email', 'Email Address')], 'Send to', required=True),
|
||||
'user_id': fields.many2one('res.users', "User"),
|
||||
'attachment_ids': fields.many2many('ir.attachment','lead_forward_to_partner_attachment_rel', 'wizard_id', 'attachment_id', 'Attachments'),
|
||||
'partner_id' : fields.many2one('res.partner', 'Partner'),
|
||||
'address_id' : fields.many2one('res.partner.address', 'Address'),
|
||||
'history': fields.selection([('info', 'Case Information'), ('latest', 'Latest email'), ('whole', 'Whole Story')], 'Send history', required=True),
|
||||
|
@ -46,48 +48,8 @@ class crm_lead_forward_to_partner(osv.osv_memory):
|
|||
}
|
||||
|
||||
|
||||
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
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of history IDs
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
whole = []
|
||||
for hist_id in ids:
|
||||
whole.append(self.get_latest_history(cr, uid, hist_id, context=context))
|
||||
whole = '\n\n'.join(whole)
|
||||
return whole or ''
|
||||
|
||||
def get_latest_history(self, cr, uid, hist_id, context=None):
|
||||
"""This function gets latest communication and returns as top posting style
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param hist_id: Id of latest history
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
log_pool = self.pool.get('mail.message')
|
||||
hist = log_pool.browse(cr, uid, hist_id, context=context)
|
||||
header = '-------- Original Message --------'
|
||||
sender = 'From: %s' %(hist.email_from or '')
|
||||
to = 'To: %s' % (hist.email_to or '')
|
||||
sentdate = 'Date: %s' % (hist.date or '')
|
||||
desc = '\n%s'%(hist.body_text)
|
||||
original = [header, sender, to, sentdate, desc]
|
||||
original = '\n'.join(original)
|
||||
return original
|
||||
|
||||
|
||||
def on_change_email(self, cr, uid, ids, user):
|
||||
"""This function fills email information based on user selected
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@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
|
||||
"""
|
||||
if not user:
|
||||
return {'value': {'email_to': False}}
|
||||
email = self.pool.get('res.users')._get_email_from(cr, uid, [user])[user]
|
||||
|
@ -98,54 +60,19 @@ class crm_lead_forward_to_partner(osv.osv_memory):
|
|||
* info: Forward the case information
|
||||
* whole: Send the whole history
|
||||
* latest: Send the latest histoy
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@param uid: the current user’s ID for security checks,
|
||||
@param ids: List of history IDs
|
||||
@param context: A standard dictionary for contextual values
|
||||
"""
|
||||
#TODO: ids and context are not comming
|
||||
res = False
|
||||
res = {}
|
||||
res_id = context.get('active_id')
|
||||
msg_val = self._get_case_history(cr, uid, history_type, res_id, context=context)
|
||||
if msg_val:
|
||||
res = {'value': {'body_text' : '\n\n' + msg_val}}
|
||||
model = context.get('active_model')
|
||||
lead = self.pool.get(model).browse(cr, uid, res_id, context)
|
||||
body_text = self._get_message_body_text(cr, uid, lead, history_type, context=context)
|
||||
if body_text:
|
||||
res = {'value': {'body_text' : body_text}}
|
||||
return res
|
||||
|
||||
def _get_case_history(self, cr, uid, history_type, res_id, context=None):
|
||||
if not res_id:
|
||||
return
|
||||
|
||||
msg_val = ''
|
||||
case_info = self.get_lead_details(cr, uid, res_id, context=context)
|
||||
model_pool = self.pool.get('crm.lead')
|
||||
|
||||
if history_type == 'info':
|
||||
msg_val = case_info
|
||||
|
||||
elif history_type == 'whole':
|
||||
log_ids = model_pool.browse(cr, uid, res_id, context=context).message_ids
|
||||
log_ids = map(lambda x: x.id, filter(lambda x: x.email_from, log_ids))
|
||||
msg_val = case_info + '\n\n' + self.get_whole_history(cr, uid, log_ids, context=context)
|
||||
|
||||
elif history_type == 'latest':
|
||||
log_ids = model_pool.browse(cr, uid, res_id, context=context).message_ids
|
||||
log_ids = filter(lambda x: x.email_from and x.id, log_ids)
|
||||
if not log_ids:
|
||||
msg_val = case_info
|
||||
else:
|
||||
msg_val = case_info + '\n\n' + self.get_latest_history(cr, uid, log_ids[0].id, context=context)
|
||||
|
||||
return msg_val
|
||||
|
||||
|
||||
def on_change_partner(self, cr, uid, ids, partner_id):
|
||||
"""This function fills address information based on partner/user selected
|
||||
@param self: The object pointer
|
||||
@param cr: the current row, from the database cursor,
|
||||
@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
|
||||
"""
|
||||
if not partner_id:
|
||||
return {'value' : {'email_to' : False, 'address_id': False}}
|
||||
|
@ -158,11 +85,11 @@ class crm_lead_forward_to_partner(osv.osv_memory):
|
|||
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})
|
||||
data.update({'email_cc' : email, 'user_id': user_id and user_id.id or False})
|
||||
return {
|
||||
'value' : data,
|
||||
'domain' : {'address_id' : partner_id and "[('partner_id', '=', partner_id)]" or "[]"}
|
||||
}
|
||||
}
|
||||
|
||||
def on_change_address(self, cr, uid, ids, address_id):
|
||||
email = ''
|
||||
|
@ -170,155 +97,125 @@ class crm_lead_forward_to_partner(osv.osv_memory):
|
|||
email = self.pool.get('res.partner.address').browse(cr, uid, address_id).email
|
||||
return {'value': {'email_to' : email}}
|
||||
|
||||
def send_mail(self, cr, uid, ids, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
super(crm_lead_forward_to_partner, self).send_mail(cr, uid, ids, context=context)
|
||||
self.action_forward(cr, uid, ids, context)
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
def action_forward(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Forward the lead to a partner
|
||||
"""
|
||||
if context is None:
|
||||
context = {}
|
||||
res = {'type': 'ir.actions.act_window_close'}
|
||||
model = context.get('active_model')
|
||||
if model not in ('crm.lead'):
|
||||
return res
|
||||
|
||||
this = self.browse(cr, uid, ids[0], context=context)
|
||||
case_pool = self.pool.get(context.get('active_model'))
|
||||
res_id = context and context.get('active_id', False) or False
|
||||
case = case_pool.browse(cr, uid, res_id, context=context)
|
||||
context.update({'mail': 'forward'})
|
||||
|
||||
to_write = {'date_assign': time.strftime('%Y-%m-%d')}
|
||||
if (this.send_to == 'partner' and this.partner_id):
|
||||
to_write['partner_assigned_id'] = this.partner_id.id
|
||||
|
||||
if this.send_to == 'user':
|
||||
to_write.update({'user_id' : this.user_id.id})
|
||||
email_re = r'([^ ,<@]+@[^> ,]+)'
|
||||
email_cc = re.findall(email_re, case.email_cc or '')
|
||||
new_cc = []
|
||||
if case.email_cc:
|
||||
new_cc.append(case.email_cc)
|
||||
for to in this.email_to.split(','):
|
||||
email_to = re.findall(email_re, to)
|
||||
email_to = email_to and email_to[0] or ''
|
||||
if email_to not in email_cc:
|
||||
new_cc.append(to)
|
||||
to_write.update({'email_cc' : ', '.join(new_cc) })
|
||||
case_pool.write(cr, uid, case.id, to_write, context=context)
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
def get_lead_details(self, cr, uid, lead_id, context=None):
|
||||
body = []
|
||||
lead_proxy = self.pool.get('crm.lead')
|
||||
lead = lead_proxy.browse(cr, uid, lead_id, context=context)
|
||||
if not lead.type or lead.type == 'lead' or not lead.partner_address_id:
|
||||
field_names = [
|
||||
'partner_name', 'title', 'function', 'street', 'street2',
|
||||
'zip', 'city', 'country_id', 'state_id', 'email_from',
|
||||
'phone', 'fax', 'mobile', 'categ_id', 'description',
|
||||
]
|
||||
|
||||
for field_name in field_names:
|
||||
field_definition = lead_proxy._columns[field_name]
|
||||
value = None
|
||||
|
||||
if field_definition._type == 'selection':
|
||||
if hasattr(field_definition.selection, '__call__'):
|
||||
key = field_definition.selection(lead_proxy, cr, uid, context=context)
|
||||
else:
|
||||
key = field_definition.selection
|
||||
value = dict(key).get(lead[field_name], lead[field_name])
|
||||
elif field_definition._type == 'many2one':
|
||||
if lead[field_name]:
|
||||
value = lead[field_name].name_get()[0][1]
|
||||
else:
|
||||
value = lead[field_name]
|
||||
|
||||
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 ''),
|
||||
]
|
||||
return "\n".join(body + ['---'])
|
||||
|
||||
def default_get(self, cr, uid, fields, context=None):
|
||||
"""
|
||||
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 - %s' % (_('Fwd'), 'Openerp lead forward', lead.name),
|
||||
'body_text' : body,
|
||||
'email_cc' : email_cc,
|
||||
'email_to' : email or 'dummy@dummy.ly'
|
||||
})
|
||||
return defaults
|
||||
|
||||
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})
|
||||
lead = self.pool.get(model)
|
||||
lead_id = context and context.get('active_id', False) or False
|
||||
lead_ids = lead_id and [lead_id] or []
|
||||
mode = context.get('mail.compose.message.mode')
|
||||
if mode == 'mass_mail':
|
||||
lead_ids = context and context.get('active_ids', []) or []
|
||||
value = self.default_get(cr, uid, ['body_text', 'email_to', 'email_cc', 'subject', 'history'], context=context)
|
||||
self.write(cr, uid, ids, value, context=context)
|
||||
self.action_forward(cr,uid, ids, context=context)
|
||||
context['mail.compose.message.mode'] = mode
|
||||
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
self.send_mail(cr, uid, ids, context=context)
|
||||
for case in lead.browse(cr, uid, lead_ids, context=context):
|
||||
if (this.send_to == 'partner' and this.partner_id):
|
||||
lead.assign_partner(cr, uid, [case.id], this.partner_id.id, context=context)
|
||||
|
||||
if this.send_to == 'user':
|
||||
lead.allocate_salesman(cr, uid, [case.id], [this.user_id.id], context=context)
|
||||
|
||||
email_cc = to_email(case.email_cc)
|
||||
email_cc = email_cc and email_cc[0] or ''
|
||||
new_cc = []
|
||||
if email_cc:
|
||||
new_cc.append(email_cc)
|
||||
for to in this.email_to.split(','):
|
||||
email_to = to_email(to)
|
||||
email_to = email_to and email_to[0] or ''
|
||||
if email_to not in new_cc:
|
||||
new_cc.append(to)
|
||||
update_vals = {'email_cc' : ', '.join(new_cc) }
|
||||
lead.write(cr, uid, case.id, update_vals, context=context)
|
||||
return res
|
||||
|
||||
def _get_info_body_text(self, cr, uid, lead, context=None):
|
||||
field_names = []
|
||||
proxy = self.pool.get(lead._name)
|
||||
if lead.type == 'opportunity':
|
||||
field_names += ['partner_id']
|
||||
field_names += [
|
||||
'partner_name' , 'title', 'function', 'street', 'street2',
|
||||
'zip', 'city', 'country_id', 'state_id', 'email_from',
|
||||
'phone', 'fax', 'mobile', 'categ_id', 'description',
|
||||
]
|
||||
return proxy._mail_body_text(cr, uid, lead, field_names, context=context)
|
||||
|
||||
def _get_message_body_text(self, cr, uid, lead, mode='whole', context=None):
|
||||
"""This function gets whole communication history and returns as top posting style
|
||||
"""
|
||||
mail_message = self.pool.get('mail.message')
|
||||
message_ids = []
|
||||
body = self._get_info_body_text(cr, uid, lead, context=context)
|
||||
if mode in ('whole', 'latest'):
|
||||
message_ids = lead.message_ids
|
||||
message_ids = map(lambda x: x.id, filter(lambda x: x.email_from, message_ids))
|
||||
if mode == 'latest' and len(message_ids):
|
||||
message_ids = [message_ids[0]]
|
||||
for message in mail_message.browse(cr, uid, message_ids, context=context):
|
||||
header = '-------- Original Message --------'
|
||||
sender = 'From: %s' %(message.email_from or '')
|
||||
to = 'To: %s' % (message.email_to or '')
|
||||
sentdate = 'Date: %s' % (message.date or '')
|
||||
desc = '\n%s'%(message.body_text)
|
||||
original = [header, sender, to, sentdate, desc, '\n']
|
||||
original = '\n'.join(original)
|
||||
body += original
|
||||
return body or ''
|
||||
|
||||
def get_value(self, cr, uid, model, res_id, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
res = super(crm_lead_forward_to_partner, self).get_value(cr, uid, model, res_id, context=context)
|
||||
if model not in ("crm.lead"):
|
||||
return res
|
||||
proxy = self.pool.get(model)
|
||||
partner = self.pool.get('res.partner')
|
||||
lead = proxy.browse(cr, uid, res_id, context=context)
|
||||
mode = context.get('mail.compose.message.mode')
|
||||
if mode == "forward":
|
||||
body_type = context.get('mail.compose.message.body')
|
||||
email_cc = res.get('email_cc', "")
|
||||
email = res.get('email_to', "")
|
||||
subject = '%s: %s - %s' % (_('Fwd'), 'Lead forward', lead.name)
|
||||
body = self._get_message_body_text(cr, uid, lead, body_type, context=context)
|
||||
partner_assigned_id = lead.partner_assigned_id and lead.partner_assigned_id.id or False
|
||||
user_id = False
|
||||
if not partner_assigned_id:
|
||||
partner_assigned_id = proxy.search_geo_partner(cr, uid, [lead.id], context=None).get(lead.id, False)
|
||||
if partner_assigned_id:
|
||||
assigned_partner = partner.browse(cr, uid, partner_assigned_id, context=context)
|
||||
user_id = assigned_partner.user_id and assigned_partner.user_id.id or False
|
||||
email_cc = assigned_partner.user_id and assigned_partner.user_id.user_email or ''
|
||||
email = assigned_partner.email
|
||||
|
||||
res.update({
|
||||
'subject' : subject,
|
||||
'body_text' : body,
|
||||
'email_cc' : email_cc,
|
||||
'email_to' : email,
|
||||
'partner_assigned_id': partner_assigned_id,
|
||||
'user_id': user_id,
|
||||
})
|
||||
return res
|
||||
|
||||
|
||||
def default_get(self, cr, uid, fields, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
context['mail.compose.message.mode'] = 'forward'
|
||||
context['mail.compose.message.body'] = 'info'
|
||||
return super(crm_lead_forward_to_partner, self).default_get(cr, uid, fields, context=context)
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
<separator string="" colspan="4"/>
|
||||
<notebook colspan="4">
|
||||
<page string="Body">
|
||||
<field name="body" colspan="4" nolabel="1"/>
|
||||
<field name="body_text" colspan="4" nolabel="1"/>
|
||||
</page>
|
||||
<page string="Attachments">
|
||||
<label string="Add here all attachments of the current document you want to include in the Email." colspan="4"/>
|
||||
|
@ -45,7 +45,7 @@
|
|||
<group col="4" colspan="4">
|
||||
<label string="" colspan="1"/>
|
||||
<button icon="gtk-close" special="cancel" string="Close"/>
|
||||
<button icon="gtk-ok" name="send_mail" string="Send" type="object"/>
|
||||
<button name="action_forward" string="Send" type="object" icon="gtk-go-forward"/>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
|
@ -61,56 +61,14 @@
|
|||
</record>
|
||||
|
||||
|
||||
<record model="ir.ui.view" id="crm_forward_mass_mail_view">
|
||||
<field name="name">crm.new.mass.forward.mail.form</field>
|
||||
<field name="model">crm.lead.mass.forward.to.partner</field>
|
||||
<field name="type">form</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Send Mail" col="4">
|
||||
<group colspan="4" col="2">
|
||||
<separator string="Forward to Partner" colspan="4" />
|
||||
|
||||
<field name="history" colspan="2" on_change="on_change_history(history, context)" invisible="1"/>
|
||||
<field name="email_from"/>
|
||||
<field name="reply_to"/>
|
||||
<field name="email_to" invisible="1" />
|
||||
<field name="email_cc" invisible="1" />
|
||||
<field name="subject" invisible="1" />
|
||||
<field name="html"/>
|
||||
</group>
|
||||
<notebook colspan="6" >
|
||||
<page string="Message" >
|
||||
<field name="body" nolabel="1" colspan="4" default_focus="1" readonly="1"/>
|
||||
</page>
|
||||
<page string="Attachments" >
|
||||
<field name="attachment_ids" colspan="4" nolabel="1">
|
||||
<form string="Attachment">
|
||||
<field name="binary" filename="name" />
|
||||
<field name="name" />
|
||||
</form>
|
||||
<tree string="Attachments">
|
||||
<field name="name" />
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
<separator string="" colspan="6"/>
|
||||
<group colspan="6" col="4" >
|
||||
<field name="state" />
|
||||
<button string="_Cancel" icon="gtk-cancel" special="cancel" />
|
||||
<button name="action_mass_forward" type="object" string="_Mass forward" icon="gtk-go-forward" />
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<act_window id="action_crm_send_mass_forward"
|
||||
multi="True"
|
||||
key2="client_action_multi" name="Mass forward to partner"
|
||||
res_model="crm.lead.mass.forward.to.partner" src_model="crm.lead"
|
||||
res_model="crm.lead.forward.to.partner" src_model="crm.lead"
|
||||
view_mode="form" target="new" view_type="form"
|
||||
context="{'mass_forward' : True}"
|
||||
view_id="crm_forward_mass_mail_view"
|
||||
context="{'mail.compose.message.mode' : 'mass_mail'}"
|
||||
view_id="crm_lead_forward_to_partner_form"
|
||||
/>
|
||||
|
||||
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from osv import osv, fields
|
||||
from tools.translate import _
|
||||
|
||||
|
||||
class crm_merge_opportunity_assign_partner(osv.osv_memory):
|
||||
"""Merge two Opportunities"""
|
||||
|
||||
_inherit = 'crm.merge.opportunity'
|
||||
|
||||
def _update_data(self, op_ids, oldest_opp):
|
||||
data = super(crm_merge_opportunity_assign_partner, self)._update_data(op_ids, oldest_opp)
|
||||
|
||||
new_data = {
|
||||
'partner_latitude': self._get_first_not_null('partner_latitude', op_ids, oldest_opp),
|
||||
'partner_longitude': self._get_first_not_null('partner_longitude', op_ids, oldest_opp),
|
||||
'partner_assigned_id': self._get_first_not_null_id('partner_assigned_id', op_ids, oldest_opp),
|
||||
'date_assign' : self._get_first_not_null('date_assign', op_ids, oldest_opp),
|
||||
}
|
||||
data.update(new_data)
|
||||
return data
|
||||
|
||||
crm_merge_opportunity_assign_partner()
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -41,7 +41,9 @@ It also has been merged with the earlier CRM & SRM segmentation tool because the
|
|||
'init_xml': [],
|
||||
'update_xml': ['security/ir.model.access.csv', 'crm_profiling_view.xml'],
|
||||
'demo_xml': ['crm_profiling_demo.xml'],
|
||||
'test': ['test/test_crm_profiling.yml'],
|
||||
'test': [
|
||||
#'test/process/profiling.yml', #TODO:It's not debuging because problem to write data for open.questionnaire from partner section.
|
||||
],
|
||||
'installable': True,
|
||||
'active': False,
|
||||
'certificate': '0033984979005',
|
||||
|
|
|
@ -102,7 +102,7 @@
|
|||
Profiles / crm.segmentation
|
||||
-->
|
||||
|
||||
<record model="crm.segmentation" id="crm_segmentation0">
|
||||
<record model="crm.segmentation" id="crm.crm_segmentation0">
|
||||
<field name="name">OpenERP partners</field>
|
||||
<field name="answer_yes" eval="[(6,0,[partner_tiny1])]" />
|
||||
<field name="categ_id" ref="base.res_partner_category_2"/>
|
||||
|
@ -111,22 +111,23 @@
|
|||
<record model="crm.segmentation" id="crm_segmentation1">
|
||||
<field name="name">Bronze partners</field>
|
||||
<field name="answer_yes" eval="[(6,0,[partner_quality1])]" />
|
||||
<field name="parent_id" ref="crm_segmentation0"/>
|
||||
<field name="parent_id" ref="crm.crm_segmentation0"/>
|
||||
<field name="categ_id" ref="base.res_partner_category_3"/>
|
||||
<field name="profiling_active">True</field>
|
||||
</record>
|
||||
<record model="crm.segmentation" id="crm_segmentation2">
|
||||
<field name="name">Silver partners</field>
|
||||
<field name="answer_yes" eval="[(6,0,[partner_quality2])]" />
|
||||
<field name="parent_id" ref="crm_segmentation0"/>
|
||||
<field name="parent_id" ref="crm.crm_segmentation0"/>
|
||||
<field name="categ_id" ref="base.res_partner_category_4"/>
|
||||
<field name="profiling_active">True</field>
|
||||
</record>
|
||||
<record model="crm.segmentation" id="crm_segmentation3">
|
||||
<field name="name">Gold partners</field>
|
||||
<field name="answer_yes" eval="[(6,0,[partner_quality3])]" />
|
||||
<field name="parent_id" ref="crm_segmentation0"/>
|
||||
<field name="parent_id" ref="crm.crm_segmentation0"/>
|
||||
<field name="categ_id" ref="base.res_partner_category_5"/>
|
||||
<field name="exclusif">True</field>
|
||||
<field name="profiling_active">True</field>
|
||||
</record>
|
||||
<record model="crm.segmentation" id="crm_segmentation4">
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
-
|
||||
I check segmentation which allows users to perform segmentation within partners
|
||||
and set the category according to question, so first compute questions(answers)
|
||||
scenario with parther and check that category set according to questions.
|
||||
-
|
||||
!python {model: res.partner}: |
|
||||
data ={'form': {'quest_form3': ref("partner_quality3"), 'quest_form2': ref("nb_employees2"),'quest_form1': ref("sector1"),'questionnaire_name': ref('questionnaire1')}, 'ids': [ref('base.res_partner_ericdubois0')], 'report_type': 'pdf', 'model': 'res.partner', 'id': ref('base.res_partner_ericdubois0')}
|
||||
data = self._questionnaire_compute(cr, uid, data, context)
|
||||
partner = self.browse(cr, uid, ref('base.res_partner_ericdubois0'))
|
||||
assert partner.category_id[0].id == ref("base.res_partner_category_17"), "Category not assign properly"
|
|
@ -1,77 +0,0 @@
|
|||
- |
|
||||
I check segmentation which allows users to perform segmentation within partners.
|
||||
-
|
||||
I create a crm profiling question record.
|
||||
-
|
||||
!record {model: crm_profiling.question, id: crm_profiling_question_openerppartner0}:
|
||||
answers_ids:
|
||||
- name: 'no'
|
||||
name: OpenERP partner?
|
||||
-
|
||||
I create a crm profiling answer record.
|
||||
-
|
||||
!record {model: crm_profiling.answer, id: crm_profiling_answer_openerppartner0}:
|
||||
name: 'yes'
|
||||
question_id: crm_profiling_question_openerppartner0
|
||||
-
|
||||
I create Partner category Customers.
|
||||
-
|
||||
!record {model: res.partner.category, id: res_partner_category_customers0}:
|
||||
name: Customers
|
||||
- |
|
||||
I'm creating new partner "John" with his email "info@mycustomer.com".
|
||||
-
|
||||
!record {model: res.partner, id: res_partner_john0}:
|
||||
address:
|
||||
- city: Bruxelles
|
||||
country_id: base.be
|
||||
street: Rue des Palais 51, bte 33
|
||||
type: default
|
||||
zip: '1000'
|
||||
email: 'info@mycustomer.com'
|
||||
name: John
|
||||
category_id:
|
||||
- res_partner_category_customers0
|
||||
answers_ids:
|
||||
- crm_profiling_answer_openerppartner0
|
||||
|
||||
-
|
||||
Define the answers and category to partner.
|
||||
-
|
||||
!python {model: res.partner}: |
|
||||
data ={'form': {'questionnaire_name': ref('res_partner_john0')}, 'ids': [ref('res_partner_john0')], 'report_type': 'pdf', 'model': 'res.partner', 'id': ref('res_partner_john0')}
|
||||
self._questionnaire_compute(cr, uid, data, context)
|
||||
- |
|
||||
I start by creating new Questionnaire.
|
||||
-
|
||||
!record {model: crm_profiling.questionnaire, id: crm_profiling_questionnaire_basequestionnaire0}:
|
||||
description: First questionnaire.
|
||||
name: Base questionnaire
|
||||
questions_ids:
|
||||
- crm_profiling.activity_sector
|
||||
- crm_profiling.nb_employees
|
||||
- crm_profiling.partner_level
|
||||
- |
|
||||
I create the form for the "Base questionnaire".
|
||||
-
|
||||
!python {model: crm_profiling.questionnaire}: |
|
||||
context.update({'active_id':ref('res_partner_john0')})
|
||||
data ={'form': {'questionnaire_name': ref('res_partner_john0')}, 'ids': [ref('res_partner_john0')], 'report_type': 'pdf', 'model': 'res.partner', 'id': ref('res_partner_john0')}
|
||||
self.build_form(cr, uid, data, context)
|
||||
-
|
||||
I create a segmentation record.
|
||||
-
|
||||
!record {model: crm.segmentation, id: crm_segmentation_test1}:
|
||||
answer_yes:
|
||||
- crm_profiling_answer_openerppartner0
|
||||
categ_id: res_partner_category_customers0
|
||||
name: test
|
||||
parent_id: crm_profiling.crm_segmentation0
|
||||
profiling_active: true
|
||||
som_interval: 0.0
|
||||
- |
|
||||
I continue the process of segmentation.
|
||||
-
|
||||
!python {model: crm.segmentation}: |
|
||||
self.process_continue(cr, uid, [ref('crm_segmentation_test1')], start=False)
|
||||
|
Loading…
Reference in New Issue