diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml index 8c0854bd6c6..c2f21c0d8bc 100644 --- a/addons/account/account_invoice_view.xml +++ b/addons/account/account_invoice_view.xml @@ -453,10 +453,11 @@ - + + diff --git a/addons/account_analytic_analysis/account_analytic_analysis_view.xml b/addons/account_analytic_analysis/account_analytic_analysis_view.xml index 6f670b2c6b9..97a4bb8fac2 100644 --- a/addons/account_analytic_analysis/account_analytic_analysis_view.xml +++ b/addons/account_analytic_analysis/account_analytic_analysis_view.xml @@ -267,7 +267,7 @@ - + diff --git a/addons/crm/__openerp__.py b/addons/crm/__openerp__.py index 64bad21ede1..072624a7d98 100644 --- a/addons/crm/__openerp__.py +++ b/addons/crm/__openerp__.py @@ -81,6 +81,8 @@ Dashboard for CRM will include: 'crm_lead_view.xml', 'crm_lead_menu.xml', + 'crm_case_section_view.xml', + 'crm_meeting_menu.xml', 'crm_phonecall_view.xml', @@ -114,9 +116,26 @@ Dashboard for CRM will include: 'test/crm_lead_copy.yml', 'test/crm_lead_unlink.yml', ], + 'css': [ + 'static/src/css/crm.css' + ], + 'js': [ + 'static/src/js/crm.js' + ], 'installable': True, 'application': True, 'auto_install': False, - 'images': ['images/crm_dashboard.png', 'images/customers.png','images/leads.png','images/opportunities_kanban.png','images/opportunities_form.png','images/opportunities_calendar.png','images/opportunities_graph.png','images/logged_calls.png','images/scheduled_calls.png','images/stages.png'], + 'images': [ + 'images/crm_dashboard.png', + 'images/customers.png', + 'images/leads.png', + 'images/opportunities_kanban.png', + 'images/opportunities_form.png', + 'images/opportunities_calendar.png', + 'images/opportunities_graph.png', + 'images/logged_calls.png', + 'images/scheduled_calls.png', + 'images/stages.png', + ], } # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/crm/crm.py b/addons/crm/crm.py index df6d5e12b66..7b6fe02afa8 100644 --- a/addons/crm/crm.py +++ b/addons/crm/crm.py @@ -98,6 +98,7 @@ class crm_case_stage(osv.osv): 'case_default': True, } + class crm_case_section(osv.osv): """ Model for sales teams. """ _name = "crm.case.section" @@ -107,7 +108,7 @@ class crm_case_section(osv.osv): _order = "complete_name" def get_full_name(self, cr, uid, ids, field_name, arg, context=None): - return dict(self.name_get(cr, uid, ids, context=context)) + return dict(self.name_get(cr, uid, ids, context=context)) _columns = { 'name': fields.char('Sales Team', size=64, required=True, translate=True), @@ -117,27 +118,36 @@ class crm_case_section(osv.osv): "true, it will allow you to hide the sales team without removing it."), 'change_responsible': fields.boolean('Reassign Escalated', help="When escalating to this team override the salesman with the team leader."), 'user_id': fields.many2one('res.users', 'Team Leader'), - 'member_ids':fields.many2many('res.users', 'sale_member_rel', 'section_id', 'member_id', 'Team Members'), + 'member_ids': fields.many2many('res.users', 'sale_member_rel', 'section_id', 'member_id', 'Team Members'), 'reply_to': fields.char('Reply-To', size=64, help="The email address put in the 'Reply-To' of all emails sent by OpenERP about cases in this sales team"), 'parent_id': fields.many2one('crm.case.section', 'Parent Team'), 'child_ids': fields.one2many('crm.case.section', 'parent_id', 'Child Teams'), 'resource_calendar_id': fields.many2one('resource.calendar', "Working Time", help="Used to compute open days"), 'note': fields.text('Description'), - 'working_hours': fields.float('Working Hours', digits=(16,2 )), + 'working_hours': fields.float('Working Hours', digits=(16, 2)), 'stage_ids': fields.many2many('crm.case.stage', 'section_stage_rel', 'section_id', 'stage_id', 'Stages'), 'alias_id': fields.many2one('mail.alias', 'Alias', ondelete="cascade", required=True, help="The email address associated with this team. New emails received will automatically " "create new leads assigned to the team."), + 'open_lead_ids': fields.one2many('crm.lead', 'section_id', + string='Open Leads', readonly=True, + domain=['&', ('type', '!=', 'opportunity'), ('state', 'not in', ['done', 'cancel'])]), + 'open_opportunity_ids': fields.one2many('crm.lead', 'section_id', + string='Open Opportunities', readonly=True, + domain=['&', '|', ('type', '=', 'opportunity'), ('type', '=', 'both'), ('state', 'not in', ['done', 'cancel'])]), + 'color': fields.integer('Color Index'), + 'use_leads': fields.boolean('Leads', + help="This enables the management of leads in the sales team. Otherwise the sales team manages only opportunities."), } def _get_stage_common(self, cr, uid, context): - ids = self.pool.get('crm.case.stage').search(cr, uid, [('case_default','=',1)], context=context) + ids = self.pool.get('crm.case.stage').search(cr, uid, [('case_default', '=', 1)], context=context) return ids _defaults = { 'active': 1, 'stage_ids': _get_stage_common, - 'alias_domain': False, # always hide alias during creation + 'use_leads': True, } _sql_constraints = [ @@ -150,7 +160,7 @@ class crm_case_section(osv.osv): def name_get(self, cr, uid, ids, context=None): """Overrides orm name_get method""" - if not isinstance(ids, list) : + if not isinstance(ids, list): ids = [ids] res = [] if not ids: @@ -167,20 +177,20 @@ class crm_case_section(osv.osv): def create(self, cr, uid, vals, context=None): mail_alias = self.pool.get('mail.alias') if not vals.get('alias_id'): - vals.pop('alias_name', None) # prevent errors during copy() + alias_name = vals.pop('alias_name', None) or vals.get('name') # prevent errors during copy() alias_id = mail_alias.create_unique_alias(cr, uid, - {'alias_name': vals['name']}, + {'alias_name': alias_name}, model_name="crm.lead", context=context) vals['alias_id'] = alias_id res = super(crm_case_section, self).create(cr, uid, vals, context) - mail_alias.write(cr, uid, [vals['alias_id']], {'alias_defaults': {'section_id': res, 'type':'lead'}}, context) + mail_alias.write(cr, uid, [vals['alias_id']], {'alias_defaults': {'section_id': res, 'type': 'lead'}}, context) return res def unlink(self, cr, uid, ids, context=None): # Cascade-delete mail aliases as well, as they should not exist without the sales team. mail_alias = self.pool.get('mail.alias') - alias_ids = [team.alias_id.id for team in self.browse(cr, uid, ids, context=context) if team.alias_id ] + alias_ids = [team.alias_id.id for team in self.browse(cr, uid, ids, context=context) if team.alias_id] res = super(crm_case_section, self).unlink(cr, uid, ids, context=context) mail_alias.unlink(cr, uid, alias_ids, context=context) return res @@ -230,4 +240,5 @@ class crm_payment_mode(osv.osv): 'section_id': fields.many2one('crm.case.section', 'Sales Team'), } + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/crm/crm_case_section_view.xml b/addons/crm/crm_case_section_view.xml new file mode 100644 index 00000000000..c788872b47e --- /dev/null +++ b/addons/crm/crm_case_section_view.xml @@ -0,0 +1,294 @@ + + + + + + + + Leads + crm.lead + tree,form + ['|', ('type','=','lead'), ('type','=',False)] + + + { + 'search_default_section_id': [active_id], + 'search_default_open': 1, + 'default_section_id': active_id, + 'default_type': 'lead', + 'stage_type': 'lead', + } + + +

+ Use leads if you need a qualification step before creating an + opportunity or a customer. It can be a business card you received, + a contact form filled in your website, or a file of unqualified + prospects you import, etc. +

+ Once qualified, the lead can be converted into a business + opportunity and/or a new customer in your address book. +

+
+
+ + + + + Opportunities + crm.lead + kanban,tree,graph,form,calendar + [('type','=','opportunity')] + + + { + 'search_default_section_id': [active_id], + 'search_default_new': 1, + 'search_default_open': 1, + 'default_section_id': active_id, + 'stage_type': 'opportunity', + 'default_type': 'opportunity', + 'default_user_id': uid, + } + + +

+ Click to create a new opportunity. +

+ OpenERP helps you keep track of your sales pipeline to follow + up potential sales and better forecast your future revenues. +

+ You will be able to plan meetings and phone calls from + opportunities, convert them into quotations, attach related + documents, track all discussions, and much more. +

+
+
+ + + + + crm.case.section.kanban + crm.case.section + + + + + + + + + + + + + +
+
+ í +
+
+

+
+ %% +
+ +
+ + + + +
+
+
+
+
+
+
+
+ + + + + Sales Teams + crm.case.section + form + kanban,tree,form + + +

+ Click here to define a new sales team. +

+ Use sales team to organize your different salespersons or + departments into separate teams. Each team will work in + its own list of opportunities. +

+
+
+ + + + + crm.case.section.form + crm.case.section + +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ X +
+
+ +
+
+
+
+
+
+
+
+ + + + + + + +
+
+
+ + +
+
+
+
+ + + + + crm.case.section.tree + crm.case.section + child_ids + + + + + + + + + + + + + + kanban + + + + + + + tree + + + + + + + form + + + + + + Cases by Sales Team + crm.case.section + [('parent_id','=',False)] + tree + + + + + Sales Teams + crm.case.section + form + + +

+ Click here to define a new sales team. +

+ Use sales team to organize your different salespersons or + departments into separate teams. Each team will work in + its own list of opportunities. +

+
+
+ + +
+
\ No newline at end of file diff --git a/addons/crm/crm_data.xml b/addons/crm/crm_data.xml index 3db7a457dfd..f24aee13c1d 100644 --- a/addons/crm/crm_data.xml +++ b/addons/crm/crm_data.xml @@ -27,8 +27,10 @@
- Sales Department + Sales Sales + True + @@ -64,12 +66,6 @@

To manage quotations and sale orders, install the "Sales Management" application.

]]>
- - sales - - - {'type':'lead'} - diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index 3f676329765..6d195fec383 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -85,6 +85,22 @@ class crm_lead(base_stage, format_address, osv.osv): }, } + def get_empty_list_help(self, cr, uid, help, context=None): + if context.get('default_type') == 'lead': + context['empty_list_help_model'] = 'crm.case.section' + context['empty_list_help_id'] = context.get('default_section_id') + context['empty_list_help_document_name'] = _("leads") + return super(crm_lead, self).get_empty_list_help(cr, uid, help, context=context) + + def onchange_user_id(self, cr, uid, ids, section_id, user_id, context=None): + """ When changing the user, also set a section_id or restrict section id + to the ones user_id is member of. """ + if user_id: + section_ids = self.pool.get('crm.case.section').search(cr, uid, ['|', ('user_id', '=', user_id), ('member_ids', '=', user_id)], context=context) + if len(section_ids) > 0 and section_id not in section_ids: + section_id = section_ids[0] + return {'value': {'section_id': section_id}} + def create(self, cr, uid, vals, context=None): if context is None: context = {} diff --git a/addons/crm/crm_lead_data.xml b/addons/crm/crm_lead_data.xml index e410cbe3d85..0979a94eb3f 100644 --- a/addons/crm/crm_lead_data.xml +++ b/addons/crm/crm_lead_data.xml @@ -54,6 +54,7 @@ Won + done diff --git a/addons/crm/crm_lead_menu.xml b/addons/crm/crm_lead_menu.xml index 8c38ed41a1c..2226b4ac895 100644 --- a/addons/crm/crm_lead_menu.xml +++ b/addons/crm/crm_lead_menu.xml @@ -9,34 +9,23 @@ ['|', ('type','=','lead'), ('type','=',False)] - {'default_type':'lead', 'stage_type':'lead'} - -

- Click to create an unqualified lead. -

- Use leads if you need a qualification step before creating an - opportunity or a customer. It can be a business card you received, - a contact form filled in your website, or a file of unqualified - prospects you import, etc. -

- Once qualified, the lead can be converted into a business - opportunity and/or a new customer in your address book. -

+ { + 'default_type':'lead', + 'stage_type':'lead', + 'search_default_unassigned':1, + } + + +

+ Use leads if you need a qualification step before creating an + opportunity or a customer. It can be a business card you received, + a contact form filled in your website, or a file of unqualified + prospects you import, etc. +

+ Once qualified, the lead can be converted into a business + opportunity and/or a new customer in your address book. +

-
- - - - tree - - - - - - - form - - @@ -44,20 +33,25 @@ crm.lead kanban,tree,graph,form,calendar [('type','=','opportunity')] - {'stage_type': 'opportunity', 'default_type': 'opportunity', 'default_user_id': uid} + { + 'stage_type': 'opportunity', + 'default_type': 'opportunity', + 'default_user_id': uid + } + -

- Click to create a new opportunity. -

- OpenERP helps you keep track of your sales pipeline to follow - up potential sales and better forecast your future revenues. -

- You will be able to plan meetings and phone calls from - opportunities, convert them into quotations, attach related - documents, track all discussions, and much more. -

+

+ Click to create a new opportunity. +

+ OpenERP helps you keep track of your sales pipeline to follow + up potential sales and better forecast your future revenues. +

+ You will be able to plan meetings and phone calls from + opportunities, convert them into quotations, attach related + documents, track all discussions, and much more. +

@@ -82,9 +76,13 @@ - - - + + + diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml index 894df92b70f..3001e8b1d88 100644 --- a/addons/crm/crm_lead_view.xml +++ b/addons/crm/crm_lead_view.xml @@ -152,12 +152,13 @@ --> - - - - + - - + diff --git a/addons/crm/res_partner_view.xml b/addons/crm/res_partner_view.xml index 00a071fa954..dd6c50dbaba 100644 --- a/addons/crm/res_partner_view.xml +++ b/addons/crm/res_partner_view.xml @@ -10,7 +10,7 @@ - + @@ -30,8 +30,11 @@ crm.lead kanban,tree,form,graph,calendar [('type','=','opportunity')] - {'search_default_partner_id': active_id, - 'stage_type': 'opportunity', 'default_type': 'opportunity'} + { + 'search_default_partner_id': active_id, + 'stage_type': 'opportunity', + 'default_type': 'opportunity' + } diff --git a/addons/crm/security/crm_security.xml b/addons/crm/security/crm_security.xml index 2c34252209c..34137dc0fac 100644 --- a/addons/crm/security/crm_security.xml +++ b/addons/crm/security/crm_security.xml @@ -22,6 +22,19 @@ + + + Do Not Use Sales Teams + + + + + + + + Manage Sales Teams + + Manage Fund Raising diff --git a/addons/crm/static/src/css/crm.css b/addons/crm/static/src/css/crm.css new file mode 100644 index 00000000000..3ad3840a4e1 --- /dev/null +++ b/addons/crm/static/src/css/crm.css @@ -0,0 +1,42 @@ +.openerp .oe_kanban_view .oe_kanban_crm_salesteams { + width: 345px; +} +.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_avatars { + text-align: right; + margin: -5px 0 -10px 0; +} + +.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_avatars img { + width: 30px; + height: 30px; + padding-left: 0px; + margin-top: 3px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + border-radius: 2px; + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); + -box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); +} + +.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_items_list { + margin: 10px 0; +} +.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_items_list a { + width: 110px; + display: inline-block; +} +.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_items_list a:hover { + text-decoration: underline !important; +} +.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_center { + text-align: center; + margin: 3px 0; +} +.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_center .oe_sum { + margin: 0; + font-size: 40px; +} +.openerp .oe_kanban_view .oe_kanban_crm_salesteams .oe_center .oe_subsum { + font-size: 10px; +} diff --git a/addons/crm/static/src/js/crm.js b/addons/crm/static/src/js/crm.js new file mode 100644 index 00000000000..e027313d6dc --- /dev/null +++ b/addons/crm/static/src/js/crm.js @@ -0,0 +1,11 @@ +openerp.crm = function(openerp) { + openerp.web_kanban.KanbanRecord.include({ + on_card_clicked: function() { + if (this.view.dataset.model === 'crm.case.section') { + this.$('.oe_kanban_crm_salesteams_list a').first().click(); + } else { + this._super.apply(this, arguments); + } + }, + }); +}; diff --git a/addons/crm/wizard/crm_lead_to_opportunity_view.xml b/addons/crm/wizard/crm_lead_to_opportunity_view.xml index 00686de1c8e..4093df910d0 100644 --- a/addons/crm/wizard/crm_lead_to_opportunity_view.xml +++ b/addons/crm/wizard/crm_lead_to_opportunity_view.xml @@ -22,7 +22,7 @@ - + @@ -68,13 +68,13 @@ - + - + diff --git a/addons/crm/wizard/crm_merge_opportunities_view.xml b/addons/crm/wizard/crm_merge_opportunities_view.xml index f68abeb8a52..919d83cb9a7 100644 --- a/addons/crm/wizard/crm_merge_opportunities_view.xml +++ b/addons/crm/wizard/crm_merge_opportunities_view.xml @@ -19,7 +19,7 @@ - +