[MERGE] Sync with trunk
[odoo/odoo.git] / addons / crm / crm.py
index 92e6584..d119450 100644 (file)
 #
 ##############################################################################
 
+from datetime import date, datetime
+from dateutil import relativedelta
+
 from openerp import tools
 from openerp.osv import fields
 from openerp.osv import osv
-from openerp.tools.translate import _
-from datetime import date
-from dateutil.relativedelta import relativedelta
 
 MAX_LEVEL = 15
 AVAILABLE_STATES = [
@@ -43,20 +43,6 @@ AVAILABLE_PRIORITIES = [
     ('5', 'Lowest'),
 ]
 
-DURATION_TXT = {
-    "monthly": _("month"),
-    "quarterly": _("quarter"),
-    "semesterly": _("semester"),
-    "annually": _("year")
-}
-
-MONTHS = {
-    "monthly": 1,
-    "quarterly": 3,
-    "semesterly": 6,
-    "annually": 12
-}
-
 class crm_case_channel(osv.osv):
     _name = "crm.case.channel"
     _description = "Channels"
@@ -119,49 +105,55 @@ class crm_case_section(osv.osv):
     _inherit = "mail.thread"
     _description = "Sales Teams"
     _order = "complete_name"
+    # number of periods for lead/opportunities/... tracking in salesteam kanban dashboard/kanban view
+    _period_number = 5
 
     def get_full_name(self, cr, uid, ids, field_name, arg, context=None):
         return dict(self.name_get(cr, uid, ids, context=context))
 
-    def _get_target_duration_txt(self, cr, uid, ids, field_name, arg, context=None):
-        res = dict.fromkeys(ids, "")
-        for section in self.browse(cr, uid, ids, context=context):
-            res[section.id] = DURATION_TXT[section.target_duration]
-        return res
-
-    def _get_open_lead_per_duration(self, cr, uid, ids, field_name, arg, context=None):
-        res = dict.fromkeys(ids, [])
-        lead_obj = self.pool.get('crm.lead')
-        first_day = date.today().replace(day=1)
-
-        for section in self.browse(cr, uid, ids, context=context):
-            dates = [first_day + relativedelta(months=-(MONTHS[section.target_duration]*(key+1)-1)) for key in range(0, 5)]
-            nb_leads = []
-            for when in range(0, 5):
-                domain = [("section_id", "=", section.id), '|', ('type', '=', 'lead'), ('date_open', '!=', None), ('create_date', '>=', dates[when].strftime(tools.DEFAULT_SERVER_DATE_FORMAT))]
-                if when:
-                    domain += [('create_date', '<', dates[when-1].strftime(tools.DEFAULT_SERVER_DATE_FORMAT))]
-                nb_leads.append(lead_obj.search(cr, uid, domain, context=context, count=True))
-            nb_leads.reverse()
-            res[section.id] = nb_leads
-        return res
-
-    def _get_won_opportunity_per_duration(self, cr, uid, ids, field_name, arg, context=None):
-        res = dict.fromkeys(ids, [])
+    def __get_bar_values(self, cr, uid, obj, domain, read_fields, value_field, groupby_field, context=None):
+        """ Generic method to generate data for bar chart values using SparklineBarWidget.
+            This method performs obj.read_group(cr, uid, domain, read_fields, groupby_field).
+
+            :param obj: the target model (i.e. crm_lead)
+            :param domain: the domain applied to the read_group
+            :param list read_fields: the list of fields to read in the read_group
+            :param str value_field: the field used to compute the value of the bar slice
+            :param str groupby_field: the fields used to group
+
+            :return list section_result: a list of dicts: [
+                                                {   'value': (int) bar_column_value,
+                                                    'tootip': (str) bar_column_tooltip,
+                                                }
+                                            ]
+        """
+        month_begin = date.today().replace(day=1)
+        section_result = [{
+                            'value': 0,
+                            'tooltip': (month_begin + relativedelta.relativedelta(months=-i)).strftime('%B'),
+                            } for i in range(self._period_number - 1, -1, -1)]
+        group_obj = obj.read_group(cr, uid, domain, read_fields, groupby_field, context=context)
+        for group in group_obj:
+            group_begin_date = datetime.strptime(group['__domain'][0][2], tools.DEFAULT_SERVER_DATE_FORMAT)
+            month_delta = relativedelta.relativedelta(month_begin, group_begin_date)
+            section_result[self._period_number - (month_delta.months + 1)] = {'value': group.get(value_field, 0), 'tooltip': group_begin_date.strftime('%B')}
+        return section_result
+
+    def _get_opportunities_data(self, cr, uid, ids, field_name, arg, context=None):
+        """ Get opportunities-related data for salesteam kanban view
+            monthly_open_leads: number of open lead during the last months
+            monthly_planned_revenue: planned revenu of opportunities during the last months
+        """
         obj = self.pool.get('crm.lead')
-        first_day = date.today().replace(day=1)
-
-        for section in self.browse(cr, uid, ids, context=context):
-            dates = [first_day + relativedelta(months=-(MONTHS[section.target_duration]*(key+1)-1)) for key in range(0, 5)]
-            rates = []
-            for when in range(0, 5):
-                domain = [("section_id", "=", section.id), ('state', '=', 'done'), ('type', '=', 'opportunity'), ('date_closed', '>=', dates[when].strftime(tools.DEFAULT_SERVER_DATE_FORMAT))]
-                if when:
-                    domain += [('date_closed', '<', dates[when-1].strftime(tools.DEFAULT_SERVER_DATE_FORMAT))]
-                group_obj = obj.read_group(cr, uid, domain, ['planned_revenue', 'section_id'], "section_id", context=context)
-                rates.append(group_obj and group_obj[0]['planned_revenue'] or 0)
-            rates.reverse()
-            res[section.id] = rates
+        res = dict.fromkeys(ids, False)
+        month_begin = date.today().replace(day=1)
+        groupby_begin = (month_begin + relativedelta.relativedelta(months=-4)).strftime(tools.DEFAULT_SERVER_DATE_FORMAT)
+        for id in ids:
+            res[id] = dict()
+            lead_domain = [('type', '=', 'lead'), ('section_id', '=', id), ('create_date', '>=', groupby_begin)]
+            res[id]['monthly_open_leads'] = self.__get_bar_values(cr, uid, obj, lead_domain, ['create_date'], 'create_date_count', 'create_date', context=context)
+            opp_domain = [('type', '=', 'opportunity'), ('section_id', '=', id), ('create_date', '>=', groupby_begin)]
+            res[id]['monthly_planned_revenue'] = self.__get_bar_values(cr, uid, obj, opp_domain, ['planned_revenue', 'create_date'], 'planned_revenue', 'create_date', context=context)
         return res
 
     _columns = {
@@ -187,14 +179,12 @@ class crm_case_section(osv.osv):
         'use_leads': fields.boolean('Leads',
             help="The first contact you get with a potential customer is a lead you qualify before converting it into a real business opportunity. Check this box to manage leads in this sales team."),
 
-        'target_duration': fields.selection([("monthly", "Monthly"), ("quarterly", "Quarterly"), ("semesterly", "Semesterly"), ("annually", "Annually")],
-            string='Report Duration', required=True),
-        'target_duration_txt': fields.function(_get_target_duration_txt,
-            string='Duration',
-            type="string", readonly=True),
-
-        'open_lead_per_duration': fields.function(_get_open_lead_per_duration, string='Open Leads per duration', type="string", readonly=True),
-        'won_opportunity_per_duration': fields.function(_get_won_opportunity_per_duration, string='Revenue of opporunities whon per duration', type="string", readonly=True)
+        'monthly_open_leads': fields.function(_get_opportunities_data,
+            type="string", readonly=True, multi='_get_opportunities_data',
+            string='Open Leads per Month'),
+        'monthly_planned_revenue': fields.function(_get_opportunities_data,
+            type="string", readonly=True, multi='_get_opportunities_data',
+            string='Planned Revenue per Month')
     }
 
     def _get_stage_common(self, cr, uid, context):
@@ -205,7 +195,6 @@ class crm_case_section(osv.osv):
         'active': 1,
         'stage_ids': _get_stage_common,
         'use_leads': True,
-        'target_duration': "monthly",
     }
 
     _sql_constraints = [
@@ -233,17 +222,13 @@ class crm_case_section(osv.osv):
         return res
 
     def create(self, cr, uid, vals, context=None):
-        mail_alias = self.pool.get('mail.alias')
-        if not vals.get('alias_id'):
-            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': 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)
-        return res
+        if context is None:
+            context = {}
+        create_context = dict(context, alias_model_name='crm.lead', alias_parent_model_name=self._name)
+        section_id = super(crm_case_section, self).create(cr, uid, vals, context=create_context)
+        section = self.browse(cr, uid, section_id, context=context)
+        self.pool.get('mail.alias').write(cr, uid, [section.alias_id.id], {'alias_parent_thread_id': section_id, 'alias_defaults': {'section_id': section_id, 'type': 'lead'}}, context=context)
+        return section_id
 
     def unlink(self, cr, uid, ids, context=None):
         # Cascade-delete mail aliases as well, as they should not exist without the sales team.