diff --git a/addons/crm/__openerp__.py b/addons/crm/__openerp__.py index 2a7996655a2..dd36aa19041 100644 --- a/addons/crm/__openerp__.py +++ b/addons/crm/__openerp__.py @@ -36,7 +36,7 @@ It manages key tasks such as communication, identification, prioritization, assi OpenERP ensures that all cases are successfully tracked by users, customers and suppliers. It can automatically send reminders, escalate the request, trigger specific methods and many other actions based on your own enterprise rules. -The greatest thing about this system is that users don't need to do anything special. The CRM module has an email gateway for the synchronization interface between mails and OpenERP. That way, users can just send emails to the request tracker. +The greatest thing about this system is that users don't need to do anything special. The CRM module has an email gateway for the synchronization interface between mails and OpenERP. That way, users can just send emails to the request tracker. OpenERP will take care of thanking them for their message, automatically routing it to the appropriate staff and make sure all future correspondence gets to the right place. @@ -99,7 +99,7 @@ Dashboard for CRM will include: 'res_partner_view.xml', 'board_crm_view.xml', - + 'res_config_view.xml', ], @@ -115,9 +115,10 @@ Dashboard for CRM will include: 'test/process/cancel_lead.yml', 'test/process/action_rule.yml', 'test/process/segmentation.yml', + 'test/process/phonecalls.yml', 'test/ui/crm_demo.yml', 'test/ui/duplicate_lead.yml', - 'test/ui/delete_lead.yml' + 'test/ui/delete_lead.yml', ], 'installable': True, 'application': True, diff --git a/addons/crm/crm_demo.xml b/addons/crm/crm_demo.xml index 551e4e93fb8..dde3e63cc4a 100644 --- a/addons/crm/crm_demo.xml +++ b/addons/crm/crm_demo.xml @@ -1,46 +1,47 @@ - + + - + - - Meetings - ir.ui.menu - - - + + Meetings + ir.ui.menu + + + - + Sales Marketing Department SMD - - + + - + Support Department SPD - - + + - + Direct Marketing DM - - + + - + Online Support OS - - + + - - OpenERP partners - True - - + + OpenERP partners + True + + diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index d3f7e1d77ef..d668ea710c1 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -298,7 +298,7 @@ class crm_lead(base_stage, format_address, osv.osv): if partner_id: partner = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context) values = { - 'partner_name' : partner.name, + 'partner_name' : partner.name, 'street' : partner.street, 'street2' : partner.street2, 'city' : partner.city, @@ -495,7 +495,8 @@ class crm_lead(base_stage, format_address, osv.osv): title = "%s : %s" % (merge_message, opportunity.name) details.append(self._mail_body(cr, uid, opportunity, fields, title=title, context=context)) - subject = subject[0] + ", ".join(subject[1:]) + # Chatter message's subject + subject = subject[0] + ": " + ", ".join(subject[1:]) details = "\n\n".join(details) return self.message_post(cr, uid, [opportunity_id], body=details, subject=subject, context=context) @@ -564,19 +565,18 @@ class crm_lead(base_stage, format_address, osv.osv): 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 + # Merge messages 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 + # Merge notifications about loss of information self._merge_notification(cr, uid, first_opportunity, opportunities, context=context) - #delete tail opportunities + # Write merged data into first opportunity + self.write(cr, uid, [first_opportunity.id], data, context=context) + # Delete tail opportunities self.unlink(cr, uid, [x.id for x in tail_opportunities], context=context) - #open first opportunity + # Open first opportunity self.case_open(cr, uid, [first_opportunity.id]) return first_opportunity.id @@ -585,13 +585,16 @@ class crm_lead(base_stage, format_address, osv.osv): 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, @@ -608,7 +611,6 @@ class crm_lead(base_stage, format_address, osv.osv): 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) diff --git a/addons/crm/crm_lead_demo.xml b/addons/crm/crm_lead_demo.xml index b3c00256b06..7849125282e 100644 --- a/addons/crm/crm_lead_demo.xml +++ b/addons/crm/crm_lead_demo.xml @@ -1,10 +1,8 @@ - + lead Plan to Attend a Training @@ -26,9 +24,9 @@ Hello, -I am Jason from Le Club SARL, -I am intertested to attend Training organized in your company, -Can you send details, +I am Jason from Le Club SARL. +I am intertested to attend a training organized in your company. +Can you send me the details ? @@ -110,7 +108,8 @@ Can you send details, - Hi, Can you send a quotation for 20 Computers with speakers? + Hi, +Can you send me a quotation for 20 computers with speakers? Regards, Carrie Helle, Purchase Manager @@ -215,8 +214,9 @@ Contact: +1 813 494 5005 - hi, -I want to know specification and cost of laptops of your company. + Hi, +I would like to know more about specification and cost of laptops of your company. + Thanks, Andrew @@ -260,25 +260,20 @@ Andrew - - + - + + - - - - + opportunity Plan to buy 60 keyboards and mouses @@ -563,9 +558,9 @@ Andrew Dear Customer, Thanks for showing interest in our products. We have attached the catalogue, -We would like to know your interests, Let us know if we can call you for more details. +We would like to know your interests, so let us know when we can call you for more details. -Thanks +Regards @@ -600,9 +595,9 @@ Thanks crm.lead Hello, -I am Jason from Le Club SARL, -I am intertested to attend Training organized in your company, -Can you send details, +I am Jason from Le Club SARL. +I am intertested to attend a training organized in your company. +Can you send me the details ? email @@ -613,7 +608,7 @@ Can you send details, comment - + - + + @@ -47,7 +46,7 @@ - Wanted information about pricing of Laptops + Wanted information about pricing of laptops done (077) 582-4035 (077) 341-3591 @@ -79,6 +78,7 @@ - + + diff --git a/addons/crm/test/process/action_rule.yml b/addons/crm/test/process/action_rule.yml index 9c869009906..f76e6c250bc 100644 --- a/addons/crm/test/process/action_rule.yml +++ b/addons/crm/test/process/action_rule.yml @@ -7,14 +7,14 @@ new_id = self.create(cr, uid, {'name': 'New Rule', 'model_id': model_ids[0], 'trg_user_id': ref('base.user_root'), 'trg_partner_id': ref('base.res_partner_1'), 'act_user_id': ref('base.user_demo') }) self._check(cr, uid) - - I create new lead to check record rule. + I create a new lead to check the record rule. - !record {model: crm.lead, id: crm_lead_test_rules_id}: name: 'Test lead rules' partner_id: base.res_partner_1 - - I check record rule is apply and responsible is changed. + I check if the record rule is applied and the responsible is changed. - !python {model: crm.lead}: | lead_user = self.browse(cr, uid, ref('crm_lead_test_rules_id')) - assert lead_user.user_id.id == ref('base.user_demo'), "Responsible of lead is not changed." + assert lead_user.user_id.id == ref('base.user_demo'), "Responsible of lead is not changed." diff --git a/addons/crm/test/process/cancel_lead.yml b/addons/crm/test/process/cancel_lead.yml index 31c159c3fdf..edaf844952a 100644 --- a/addons/crm/test/process/cancel_lead.yml +++ b/addons/crm/test/process/cancel_lead.yml @@ -10,7 +10,7 @@ lead = self.browse(cr, uid, ref('crm_case_1')) assert lead.stage_id.id == ref('crm.stage_lead7'), "Stage should be 'Dead' and is %s." % (lead.stage_id.name) assert lead.state == 'cancel', "Opportunity is not in 'cancel' state." - assert lead.probability == 0.0, 'Opportunity probability is wrong and should be 0.0.' + assert lead.probability == 0.0, 'Opportunity is probably wrong and should be 0.0.' - I reset cancelled lead into unqualified lead. - diff --git a/addons/crm/test/process/communication_with_customer.yml b/addons/crm/test/process/communication_with_customer.yml index ec11528d15a..2137616ae3e 100644 --- a/addons/crm/test/process/communication_with_customer.yml +++ b/addons/crm/test/process/communication_with_customer.yml @@ -1,7 +1,7 @@ - - Customer interested in our product. so he send request by email to get more details. + Customer interested in our product, so he sends 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 + Mail script will fetch his request from mail server. Then I process that mail after read EML file. - !python {model: mail.thread}: | import addons @@ -15,27 +15,27 @@ lead_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right ')]) 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 not lead.partner_id, "Customer should be a new one" assert lead.name == "Fournir votre devis avec le meilleur prix.", "Subject does not match" - - I reply him request with welcome message. TODO revert mail.mail to mail.compose.message (conversion to customer should be automatic). + I reply his request with welcome message. TODO revert mail.mail to mail.compose.message (conversion to customer should be automatic). - !python {model: mail.mail}: | lead_ids = self.pool.get('crm.lead').search(cr, uid, [('email_from','=', 'Mr. John Right ')]) context.update({'active_model': 'crm.lead','active_id': lead_ids[0]}) - id = self.create(cr, uid, {'body': "Merci à l'intérêt pour notre produit.nous vous contacterons bientôt. Merci", 'email_from': 'sales@mycompany.com'}, context=context) + id = self.create(cr, uid, {'body': "Merci de votre intérêt pour notre produit, nous vous contacterons bientôt. Bien à vous", '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. + Now, I convert him into customer and put him into regular customer list. - !python {model: crm.lead}: | lead_ids = self.search(cr, uid, [('email_from','=', 'Mr. John Right ')]) self.convert_partner(cr, uid, lead_ids, context=context) - - I convert one phonecall request as a customer and put into regular customer list. + I convert one phonecall request to a customer and put him into regular customer list. - !python {model: crm.phonecall2partner}: | context.update({'active_model': 'crm.phonecall', 'active_ids': [ref("crm.crm_phonecall_4")], 'active_id': ref("crm.crm_phonecall_4")}) @@ -48,5 +48,5 @@ partner_id = self.search(cr, uid, [('phonecall_ids', '=', ref('crm.crm_phonecall_4'))]) 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 == "Wanted information about pricing of Laptops", "Bad partner name" + assert data.user_id.id == ref("base.user_root"), "User not assigned properly" + assert data.name == "Wanted information about pricing of laptops", "Bad partner name" diff --git a/addons/crm/test/process/lead2opportunity2win.yml b/addons/crm/test/process/lead2opportunity2win.yml index ed552421cf0..eadb46f0f55 100644 --- a/addons/crm/test/process/lead2opportunity2win.yml +++ b/addons/crm/test/process/lead2opportunity2win.yml @@ -1,17 +1,17 @@ - - In order to test convert customer lead into opportunity, + 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_4")]) -- - I check lead state is "Open". +- + I check lead state is "Open". - !assert {model: crm.lead, id: crm.crm_case_4, string: Lead in open state}: - state == "open" - - I create partner from lead. + I create partner from lead. - !record {model: crm.lead2partner, id: crm_lead2partner_id1, context: '{"active_model": "crm.lead", "active_ids": [ref("crm_case_4")]}'}: - @@ -24,7 +24,7 @@ !python {model: crm.lead}: | self.convert_opportunity(cr, uid ,[ref("crm_case_4")], ref("base.res_partner_2")) - - I check details of converted opportunity. + I check details of converted opportunity. - !python {model: crm.lead}: | lead = self.browse(cr, uid, ref('crm_case_4')) @@ -37,15 +37,15 @@ !python {model: crm.opportunity2phonecall}: | import time context.update({'active_model': 'crm.lead', 'active_ids': [ref('crm_case_4')]}) - 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) + call_id = self.create(cr, uid, {'date': time.strftime('%Y-%m-%d %H:%M:%S'), + 'name': "Bonjour M. Jean, Comment allez-vous? J'ai bien reçu votre demande, pourrions-nous en parler 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_4'))]) - assert len(ids), 'phonecall is not scheduled' + assert len(ids), 'Phonecall is not scheduled' - Now I schedule meeting with customer. - @@ -55,7 +55,7 @@ After communicated with customer, I put some notes with contract details. - !python {model: crm.lead}: | - self.message_post(cr, uid, [ref('crm_case_4')], subject='Test note', body='ces détails envoyés par le client sur ​​le FAX pour la qualité') + self.message_post(cr, uid, [ref('crm_case_4')], subject='Test note', body='Détails envoyés par le client sur ​​le FAX pour la qualité') - I win this opportunity - @@ -73,7 +73,7 @@ I convert mass lead into opportunity customer. - !python {model: crm.lead2opportunity.partner.mass}: | - context.update({'active_model': 'crm.lead', 'active_ids': [ref("crm_case_11"), ref("crm_case_2")], 'active_id': ref("crm_case_11")}) + context.update({'active_model': 'crm.lead', 'active_ids': [ref("crm_case_11"), ref("crm_case_2")], 'active_id': ref("crm_case_11")}) 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) - @@ -111,7 +111,7 @@ I confirm review needs meeting. - !python {model: crm.meeting}: | - context.update({'active_model': 'crm.meeting'}) + context.update({'active_model': 'crm.meeting'}) self.case_open(cr, uid, [ref('base_calendar.crm_meeting_4')]) - I invite a user for meeting. diff --git a/addons/crm/test/process/merge_opportunity.yml b/addons/crm/test/process/merge_opportunity.yml index 6d13278eded..155cd68274f 100644 --- a/addons/crm/test/process/merge_opportunity.yml +++ b/addons/crm/test/process/merge_opportunity.yml @@ -1,19 +1,19 @@ - - I make direct opportunity for customer. + I make an opportunity from 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) + 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. + I make another opportunity from a phone call with the same customer. - !python {model: crm.phonecall2opportunity}: | context.update({'active_model': 'crm.phonecall', 'active_ids': [ref("crm.crm_phonecall_6")]}) - res_id = self.create(cr, uid, {'name': "Quoi de prix de votre autre service?", 'partner_id': ref("base.res_partner_9")}, context=context) + res_id = self.create(cr, uid, {'name': "À propos du 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. + Now I merge these opportunities. - !python {model: crm.lead}: | opportunity_ids = self.search(cr, uid, [('partner_id','=', ref("base.res_partner_9"))]) @@ -24,7 +24,7 @@ !python {model: crm.merge.opportunity}: | self.action_merge(cr, uid, [ref("opportunity_merge_id")], context=context) - - I check for merged opportunities for customer. + I check for merged opportunities for customer. - !python {model: crm.lead}: | merge_id = self.search(cr, uid, [('partner_id','=', ref("base.res_partner_9"))]) @@ -32,55 +32,3 @@ 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_phonecall_6")], 'active_id': ref("crm.crm_phonecall_6")}) - 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_phonecall_6")]) -- - I set phone call to not held. -- - !python {model: crm.phonecall}: | - self.case_pending(cr, uid, [ref("crm.crm_phonecall_6")]) -- - I check that the phone call is in 'Not Held' state. -- - !assert {model: crm.phonecall, id: crm.crm_phonecall_6, string: Phone call held.}: - - state == "pending" -- - I cancelled the phone call. -- - !python {model: crm.phonecall}: | - self.case_cancel(cr, uid, [ref("crm.crm_phonecall_6")]) -- - I check that the phone call is in 'Cancelled' state. -- - !assert {model: crm.phonecall, id: crm.crm_phonecall_6, string: Phone call is not cancelled.}: - - state == "cancel" -- - I reset the phone call. -- - !python {model: crm.phonecall}: | - self.case_reset(cr, uid, [ref("crm.crm_phonecall_6")]) -- - I check that the phone call is reset or not. -- - !assert {model: crm.phonecall, id: crm.crm_phonecall_6, string: Phone call is not reset.}: - - state == "open" -- - I set phone call to held (done). -- - !python {model: crm.phonecall}: | - self.case_close(cr, uid, [ref("crm.crm_phonecall_6")]) -- - I check that the phone call is in 'Held' state. -- - !assert {model: crm.phonecall, id: crm.crm_phonecall_6, string: Phone call is not held.}: - - state == "done" diff --git a/addons/crm/test/process/phonecalls.yml b/addons/crm/test/process/phonecalls.yml new file mode 100644 index 00000000000..51a933f3223 --- /dev/null +++ b/addons/crm/test/process/phonecalls.yml @@ -0,0 +1,52 @@ +- + I schedule a phone call with a customer. +- + !python {model: crm.phonecall2phonecall}: | + context.update({'active_model': 'crm.phonecall', 'active_ids': [ref("crm.crm_phonecall_6")], 'active_id': ref("crm.crm_phonecall_6")}) + res_id = self.create(cr, uid, {'name': "Proposition de réduction"}, context=context) + self.action_schedule(cr, uid, [res_id], context=context) +- + I schedule a meeting based on this phone call. +- + !python {model: crm.phonecall}: | + self.action_make_meeting(cr, uid, [ref("crm.crm_phonecall_6")]) +- + I set the phone call to not held. +- + !python {model: crm.phonecall}: | + self.case_pending(cr, uid, [ref("crm.crm_phonecall_6")]) +- + I check that the phone call is in 'Not Held' state. +- + !assert {model: crm.phonecall, id: crm.crm_phonecall_6, string: Phone call held.}: + - state == "pending" +- + I cancel the phone call. +- + !python {model: crm.phonecall}: | + self.case_cancel(cr, uid, [ref("crm.crm_phonecall_6")]) +- + I check that the phone call is in 'Cancelled' state. +- + !assert {model: crm.phonecall, id: crm.crm_phonecall_6, string: Phone call is not cancelled.}: + - state == "cancel" +- + I reset the phone call. +- + !python {model: crm.phonecall}: | + self.case_reset(cr, uid, [ref("crm.crm_phonecall_6")]) +- + I check that the phone call is reset. +- + !assert {model: crm.phonecall, id: crm.crm_phonecall_6, string: Phone call is not reset.}: + - state == "open" +- + I set phone call to held (done). +- + !python {model: crm.phonecall}: | + self.case_close(cr, uid, [ref("crm.crm_phonecall_6")]) +- + I check that the phone call is in 'Held' state. +- + !assert {model: crm.phonecall, id: crm.crm_phonecall_6, string: Phone call is not held.}: + - state == "done" diff --git a/addons/crm/wizard/crm_lead_to_opportunity.py b/addons/crm/wizard/crm_lead_to_opportunity.py index 44ce73c23fe..2473a83206c 100644 --- a/addons/crm/wizard/crm_lead_to_opportunity.py +++ b/addons/crm/wizard/crm_lead_to_opportunity.py @@ -34,15 +34,17 @@ class crm_lead2opportunity_partner(osv.osv_memory): ('create', 'Create a new customer'), \ ('nothing', 'Do not link to a customer')], \ 'Related Customer', required=True), - 'name': fields.selection([('convert', 'Convert to Opportunities'), ('merge', 'Merge with existing Opportunities')], 'Conversion Action', required=True), + 'name': fields.selection([('convert', 'Convert to opportunity'), \ + ('merge', 'Merge with existing opportunities')], \ + 'Conversion Action', required=True), 'opportunity_ids': fields.many2many('crm.lead', string='Opportunities', domain=[('type', '=', 'opportunity')]), } def default_get(self, cr, uid, fields, context=None): """ - Default get for name, opportunity_ids - if there is an exisitng partner link to the lead, find all existing opportunity link with this partnet to merge - all information together + Default get for name, opportunity_ids. + If there is an exisitng partner link to the lead, find all existing + opportunities links with this partner to merge all information together """ lead_obj = self.pool.get('crm.lead') @@ -62,12 +64,13 @@ class crm_lead2opportunity_partner(osv.osv_memory): ids = [] if partner_id: + # Search for opportunities that have the same partner and that arent done or cancelled ids = lead_obj.search(cr, uid, [('partner_id', '=', partner_id), ('type', '=', 'opportunity'), '!', ('state', 'in', ['done', 'cancel'])]) if ids: opportunities.append(ids[0]) if not partner_id: if email: - # Find email of existing opportunity matches the email_from of the lead + # Find email of existing opportunity matching the email_from of the lead cr.execute("""select id from crm_lead where type='opportunity' and substring(email_from from '([^ ,<@]+@[^> ,]+)') in (%s)""" % (','.join(email))) ids = map(lambda x:x[0], cr.fetchall()) @@ -83,12 +86,11 @@ class crm_lead2opportunity_partner(osv.osv_memory): if 'opportunity_ids' in fields: res.update({'opportunity_ids': opportunities}) - return res def view_init(self, cr, uid, fields, context=None): """ - This function checks for precondition before wizard executes + Check some preconditions before the wizard executes. """ if context is None: context = {} @@ -110,7 +112,7 @@ class crm_lead2opportunity_partner(osv.osv_memory): partner_id = partner_ids_map.get(lead_id, False) # FIXME: cannot pass user_ids as the salesman allocation only works in batch res = lead.convert_opportunity(cr, uid, [lead_id], partner_id, [], team_id, context=context) - # FIXME: must perform salesman allocation in batch separately here + # FIXME: must perform salesman allocation in batch separately here user_ids = vals.get('user_ids', False) if user_ids: lead.allocate_salesman(cr, uid, lead_ids, user_ids, team_id=team_id, context=context) @@ -136,9 +138,10 @@ class crm_lead2opportunity_partner(osv.osv_memory): def action_apply(self, cr, uid, ids, context=None): """ - This converts lead to opportunity and opens Opportunity view + Convert lead to opportunity or merge lead and opportunity and open + the freshly created opportunity view. """ - if not context: + if context is None: context = {} lead = self.pool.get('crm.lead') lead_ids = context.get('active_ids', []) diff --git a/addons/crm/wizard/crm_lead_to_opportunity_view.xml b/addons/crm/wizard/crm_lead_to_opportunity_view.xml index ef8acf95b58..3390ad8f547 100644 --- a/addons/crm/wizard/crm_lead_to_opportunity_view.xml +++ b/addons/crm/wizard/crm_lead_to_opportunity_view.xml @@ -7,15 +7,9 @@ crm.lead2opportunity.partner
- - - - - + @@ -24,6 +18,12 @@ + + + +
+
-
+
@@ -83,10 +88,11 @@ +
diff --git a/addons/crm/wizard/crm_merge_opportunities.py b/addons/crm/wizard/crm_merge_opportunities.py index 381bb9871ea..edfefb5e5bc 100644 --- a/addons/crm/wizard/crm_merge_opportunities.py +++ b/addons/crm/wizard/crm_merge_opportunities.py @@ -27,6 +27,8 @@ class crm_merge_opportunity(osv.osv_memory): _description = 'Merge two Opportunities' def action_merge(self, cr, uid, ids, context=None): + if context is None: + context = {} lead = self.pool.get('crm.lead') record = self.browse(cr, uid, ids[0], context=context) opportunities = record.opportunity_ids @@ -38,7 +40,7 @@ class crm_merge_opportunity(osv.osv_memory): 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')]), + 'opportunity_ids': fields.many2many('crm.lead', rel='merge_opportunity_rel', id1='merge_id', id2='opportunity_id', string='Leads/Opportunities'), } def default_get(self, cr, uid, fields, context=None): diff --git a/addons/crm/wizard/crm_merge_opportunities_view.xml b/addons/crm/wizard/crm_merge_opportunities_view.xml index 3a0b11c4255..4b035200737 100644 --- a/addons/crm/wizard/crm_merge_opportunities_view.xml +++ b/addons/crm/wizard/crm_merge_opportunities_view.xml @@ -3,13 +3,12 @@ - crm.merge.opportunity.form crm.merge.opportunity -
- + + @@ -19,7 +18,7 @@
-
@@ -27,10 +26,9 @@ - - + - Merge Opportunities + Merge leads/opportunities crm.merge.opportunity form form @@ -40,7 +38,7 @@