[IMP] mass_mailing: campaigns: some refactoring !
authorThibault Delavallée <tde@openerp.com>
Fri, 4 Apr 2014 15:34:32 +0000 (17:34 +0200)
committerThibault Delavallée <tde@openerp.com>
Fri, 4 Apr 2014 15:34:32 +0000 (17:34 +0200)
- state is now stage_id, many2one towaqrds a newly added stage model, allowing to
tune your process of mailign campaigns. Todo: menu to configure stages + access rights.
- cleaned campaign kanban view, to be smaller.
- added statbuttons in form view of campaigns

bzr revid: tde@openerp.com-20140404153432-b171x0frbfepyfkn

addons/mass_mailing/data/mass_mailing_data.xml
addons/mass_mailing/data/mass_mailing_demo.xml
addons/mass_mailing/models/mass_mailing.py
addons/mass_mailing/static/src/css/mass_mailing.css
addons/mass_mailing/views/mass_mailing.xml

index 6982aac..6bd1df7 100644 (file)
             <field name="category_id" ref="base.module_category_hidden"/>
         </record>
 
+        <!-- Default stages of mass mailing campaigns -->
+        <record id="campaign_stage_1" model="mail.mass_mailing.stage">
+            <field name="name">Schedule</field>
+            <field name="sequence">10</field>
+        </record>
+        <record id="campaign_stage_2" model="mail.mass_mailing.stage">
+            <field name="name">Design</field>
+            <field name="sequence">20</field>
+        </record>
+        <record id="campaign_stage_3" model="mail.mass_mailing.stage">
+            <field name="name">Sent</field>
+            <field name="sequence">30</field>
+        </record>
+
     </data>
 </openerp>
\ No newline at end of file
index fd4e6e0..4857c23 100644 (file)
         </record>
         <record id="mass_mail_campaign_1" model="mail.mass_mailing.campaign">
             <field name="name">Newsletter</field>
-            <field name="state">design</field>
+            <field name="stage_id" ref="mass_mailing.campaign_stage_1"/>
             <field name="user_id" eval="ref('base.user_root')"/>
             <field name="category_id" eval="ref('mass_mailing.mass_mail_category_1')"/>
         </record>
index cfad94b..9bdaceb 100644 (file)
@@ -210,6 +210,22 @@ class MassMailingList(osv.Model):
         return model_to_domains
 
 
+class MassMailingStage(osv.Model):
+    """Stage for mass mailing campaigns. """
+    _name = 'mail.mass_mailing.stage'
+    _description = 'Mass Mailing Campaign Stage'
+    _order = 'sequence ASC'
+
+    _columns = {
+        'name': fields.char('Name', required=True),
+        'sequence': fields.integer('Sequence'),
+    }
+
+    _defaults = {
+        'sequence': 0,
+    }
+
+
 class MassMailingCampaign(osv.Model):
     """Model of mass mailing campaigns. """
     _name = "mail.mass_mailing.campaign"
@@ -231,17 +247,14 @@ class MassMailingCampaign(osv.Model):
                 'bounced': Statistics.search(cr, uid, [('mass_mailing_campaign_id', '=', cid), ('bounced', '!=', False)], count=True, context=context),
             }
             results[cid]['delivered'] = results[cid]['sent'] - results[cid]['bounced']
+            results[cid]['received_ratio'] = 100.0 * results[cid]['delivered'] / (results[cid]['sent'] or 1)
+            results[cid]['opened_ratio'] = 100.0 * results[cid]['opened'] / (results[cid]['sent'] or 1)
+            results[cid]['replied_ratio'] = 100.0 * results[cid]['replied'] / (results[cid]['sent'] or 1)
         return results
 
-    def _get_state_list(self, cr, uid, context=None):
-        return [('draft', 'Schedule'), ('design', 'Design'), ('done', 'Sent')]
-
-    # indirections for inheritance
-    _state = lambda self, *args, **kwargs: self._get_state_list(*args, **kwargs)
-
     _columns = {
         'name': fields.char('Name', required=True),
-        'state': fields.selection(_state, string='Status', required=True),
+        'stage_id': fields.many2one('mail.mass_mailing.stage', 'Stage', required=True),
         'user_id': fields.many2one(
             'res.users', 'Responsible',
             required=True,
@@ -288,43 +301,30 @@ class MassMailingCampaign(osv.Model):
             _get_statistics, string='Bounced',
             type='integer', multi='_get_statistics'
         ),
+        'received_ratio': fields.function(
+            _get_statistics, string='Received Ratio',
+            type='integer', multi='_get_statistics',
+        ),
+        'opened_ratio': fields.function(
+            _get_statistics, string='Opened Ratio',
+            type='integer', multi='_get_statistics',
+        ),
+        'replied_ratio': fields.function(
+            _get_statistics, string='Replied Ratio',
+            type='integer', multi='_get_statistics',
+        ),
     }
 
+    def _get_default_stage_id(self, cr, uid, context=None):
+        stage_ids = self.pool['mail.mass_mailing.stage'].search(cr, uid, [], limit=1, context=context)
+        return stage_ids and stage_ids[0]
+
     _defaults = {
         'user_id': lambda self, cr, uid, ctx=None: uid,
-        'state': 'draft',
+        'stage_id': lambda self, cr, uid, ctx=None: self._get_default_stage_id(cr, uid, context=ctx),
     }
 
     #------------------------------------------------------
-    # Technical stuff
-    #------------------------------------------------------
-
-    def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False):
-        """ Override read_group to always display all states. """
-        if groupby and groupby[0] == "state":
-            # Default result structure
-            states = self._get_state_list(cr, uid, context=context)
-            read_group_all_states = [{
-                '__context': {'group_by': groupby[1:]},
-                '__domain': domain + [('state', '=', state_value)],
-                'state': state_value,
-                'state_count': 0,
-            } for state_value, state_name in states]
-            # Get standard results
-            read_group_res = super(MassMailingCampaign, self).read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby)
-            # Update standard results with default results
-            result = []
-            for state_value, state_name in states:
-                res = filter(lambda x: x['state'] == state_value, read_group_res)
-                if not res:
-                    res = filter(lambda x: x['state'] == state_value, read_group_all_states)
-                res[0]['state'] = [state_value, state_name]
-                result.append(res[0])
-            return result
-        else:
-            return super(MassMailingCampaign, self).read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby)
-
-    #------------------------------------------------------
     # Actions
     #------------------------------------------------------
 
index ec833f5..ff54b8c 100644 (file)
@@ -1,5 +1,5 @@
 .openerp .oe_kanban_view .oe_kanban_mass_mailing_campaign {
-    width: 360px;
+    width: 280px;
 }
 
 .openerp .oe_kanban_view .oe_kanban_mass_mailing_campaign .oe_kanban_header_right {
index 844d017..aab2b42 100644 (file)
                     <field name="mass_mailing_campaign_id"/>
                     <field name="template_id"/>
                     <group expand="0" string="Group By...">
+                        <filter string="State" name="group_state"
+                            context="{'group_by': 'state'}"/>
                         <filter string="Campaign" name="group_mass_mailing_campaign_id"
                             groups="mass_mailing.group_mass_mailing_campaign"
                             context="{'group_by': 'mass_mailing_campaign_id'}"/>
                                         <t t-if="record.mass_mailing_campaign_id.raw_value" groups="mass_mailing.group_mass_mailing_campaign"> - </t><field name="date"/>
                                     </div>
                                     <div>
-                                    <div style="display: inline-block">
-                                        <field name="delivered" widget="gauge" style="width:120px; height: 90px;"
-                                            options="{'max_field': 'total'}"/>
-                                    </div>
-                                    <div style="display: inline-block; vertical-align: top;">
-                                        <strong>Opened</strong> <field name="opened_ratio"/> %<br />
-                                        <strong>Replied</strong> <field name="replied_ratio"/> %
-                                    </div>
+                                        <div style="display: inline-block">
+                                            <field name="delivered" widget="gauge" style="width:120px; height: 90px;"
+                                                options="{'max_field': 'total'}"/>
+                                        </div>
+                                        <div style="display: inline-block; vertical-align: top;">
+                                            <strong>Opened</strong> <field name="opened_ratio"/> %<br />
+                                            <strong>Replied</strong> <field name="replied_ratio"/> %
+                                        </div>
                                     </div>
                                 </div>
                                 <div class="oe_clear"></div>
                     <field name="category_id"/>
                     <field name="user_id"/>
                     <group expand="0" string="Group By...">
+                        <filter string="Stage" name="group_stage_id"
+                            context="{'group_by': 'stage_id'}"/>
                         <filter string="Responsible" name="group_user_id"
                             context="{'group_by': 'user_id'}"/>
                         <filter string="Category" name="group_category_id"
                 <tree string="Mass Mailing Campaigns">
                     <field name="name"/>
                     <field name="user_id"/>
-                    <field name="state"/>
+                    <field name="stage_id"/>
                     <field name="category_id"/>
                 </tree>
             </field>
                 <form string="Mass Mailing Campaign" version="7.0">
                     <header>
                         <button name="action_new_mailing" type="object" class="oe_highlight" string="New Mailing"/>
-                        <field name="state" widget="statusbar" clickable="True"/>
+                        <field name="stage_id" widget="statusbar" clickable="True"/>
                     </header>
                     <sheet>
                         <group>
                                 <field name="ab_testing"/>
                             </group>
                             <group>
-                                <!-- <p>Here be some graphs</p> -->
-                                <field name="total"/>
-                                <field name="sent" attrs="{'invisible': [('total', '=', 0)]}"/>
-                                <field name="opened" attrs="{'invisible': [('total', '=', 0)]}"/>
-                                <field name="replied" attrs="{'invisible': [('total', '=', 0)]}"/>
+                                <field name="total" invisible="1"/>
+                                <div class="oe_right oe_button_box" name="buttons"
+                                    attrs="{'invisible': [('total', '=', 0)]}">
+                                    <button name="%(action_mail_mass_mailing_report)d"
+                                        type="action" class="oe_stat_button oe_inline">
+                                        <field name="received_ratio" widget="percentpie"/>
+                                        <span>Received</span>
+                                    </button>
+                                    <button name="%(action_mail_mass_mailing_report)d"
+                                        type="action" class="oe_stat_button oe_inline">
+                                        <field name="opened_ratio" widget="percentpie"/>
+                                        <span>Opened</span>
+                                    </button>
+                                    <button name="%(action_mail_mass_mailing_report)d"
+                                        type="action" class="oe_stat_button oe_inline">
+                                        <field name="replied_ratio" widget="percentpie"/>
+                                        <span>Replied</span>
+                                    </button>
+                                </div>
                             </group>
                         </group>
-                        <group>
-                            <field name="mass_mailing_ids" readonly="1" string="Related Mailing(s)">
-                                <tree>
-                                    <field name="name"/>
-                                    <field name="date"/>
-                                    <field name="state"/>
-                                    <field name="delivered"/>
-                                    <field name="opened"/>
-                                    <field name="replied"/>
-                                    <field name="bounced"/>
-                                    <button name="action_duplicate" type="object" string="Duplicate"/>
-                                </tree>
-                            </field>
-                        </group>
+                        <strong>Related Mailing(s)</strong>
+                        <field name="mass_mailing_ids" readonly="1" string="Related Mailing(s)">
+                            <tree>
+                                <field name="name"/>
+                                <field name="date"/>
+                                <field name="state"/>
+                                <field name="delivered"/>
+                                <field name="opened"/>
+                                <field name="replied"/>
+                                <field name="bounced"/>
+                                <button name="action_duplicate" type="object" string="Duplicate"/>
+                            </tree>
+                        </field>
                     </sheet>
                 </form>
             </field>
             <field name="name">mail.mass_mailing.campaign.kanban</field>
             <field name="model">mail.mass_mailing.campaign</field>
             <field name="arch" type="xml">
-                <kanban default_group_by='state'>
+                <kanban default_group_by='stage_id'>
                     <field name='total'/>
                     <field name='color'/>
                     <field name='user_id'/>
                                  <div class="oe_kanban_content">
                                     <div>
                                         <img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value)"
-                                            t-att-title="record.user_id.value" width="48" height="48o" class="oe_kanban_avatar oe_kanban_header_right"/>
+                                            t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar oe_kanban_header_right"/>
                                         <h3 style="margin-bottom: 8px;"><field name="name"/></h3>
                                         <span class="oe_tag"><field name="category_id"/></span>
                                         <a name="%(action_view_mass_mailings_from_campaign)d" type="action"
                                     </div>
                                     <div class="oe_clear"></div>
                                     <div>
-                                        <field name="total" widget="gauge" style="width:160px; height: 120px;"
-                                            options="{'max_field': 'total'}"/>
-                                        <field name="delivered" widget="gauge" style="width:160px; height: 120px;"
-                                            options="{'max_field': 'total'}"/>
-                                    </div>
-                                    <div>
-                                        <field name="opened" widget="gauge" style="width:160px; height: 120px;"
-                                            options="{'max_field': 'total'}"/>
-                                        <field name="replied" widget="gauge" style="width:160px; height: 120px;"
-                                            options="{'max_field': 'total'}"/>
+                                        <div style="display: inline-block">
+                                            <field name="delivered" widget="gauge" style="width:120px; height: 90px;"
+                                                options="{'max_field': 'total'}"/>
+                                        </div>
+                                        <div style="display: inline-block; vertical-align: top;">
+                                            <strong>Opened</strong> <field name="opened_ratio"/> %<br />
+                                            <strong>Replied</strong> <field name="replied_ratio"/> %
+                                        </div>
                                     </div>
                                 </div>
                                 <div class="oe_clear"></div>