[IMP] salesteams: duration only by month

bzr revid: chm@openerp.com-20130527093036-bn4kjnre9vhxf76k
This commit is contained in:
Christophe Matthieu 2013-05-27 11:30:36 +02:00
parent 15c9537eb1
commit 4e7b20dfb6
4 changed files with 50 additions and 114 deletions

View File

@ -23,7 +23,7 @@ from openerp import tools
from openerp.osv import fields from openerp.osv import fields
from openerp.osv import osv from openerp.osv import osv
from openerp.tools.translate import _ from openerp.tools.translate import _
from datetime import date from datetime import date, datetime
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
MAX_LEVEL = 15 MAX_LEVEL = 15
@ -43,20 +43,6 @@ AVAILABLE_PRIORITIES = [
('5', 'Lowest'), ('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): class crm_case_channel(osv.osv):
_name = "crm.case.channel" _name = "crm.case.channel"
_description = "Channels" _description = "Channels"
@ -123,45 +109,30 @@ class crm_case_section(osv.osv):
def get_full_name(self, cr, uid, ids, field_name, arg, context=None): 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))
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): def _get_open_lead_per_duration(self, cr, uid, ids, field_name, arg, context=None):
res = dict.fromkeys(ids, []) res = dict.fromkeys(ids, [])
lead_obj = self.pool.get('crm.lead') obj = self.pool.get('crm.lead')
first_day = date.today().replace(day=1) today = date.today().replace(day=1)
begin = (today + relativedelta(months=-5)).strftime(tools.DEFAULT_SERVER_DATE_FORMAT)
for section in self.browse(cr, uid, ids, context=context): 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)] domain = [("section_id", "=", section.id), '|', ('type', '=', 'lead'), ('date_open', '!=', None), ('create_date', '>=', begin)]
nb_leads = [] group_obj = obj.read_group(cr, uid, domain, ["create_date"], "create_date", context=context)
for when in range(0, 5): group_list = [group['create_date_count'] for group in group_obj]
domain = [("section_id", "=", section.id), '|', ('type', '=', 'lead'), ('date_open', '!=', None), ('create_date', '>=', dates[when].strftime(tools.DEFAULT_SERVER_DATE_FORMAT))] nb_month = group_obj and relativedelta(today, datetime.strptime(group_obj[-1]['__domain'][0][2], '%Y-%m-%d')).months or 0
if when: res[section.id] = [0]*(5 - len(group_list) - nb_month) + group_list + [0]*nb_month
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 return res
def _get_won_opportunity_per_duration(self, cr, uid, ids, field_name, arg, context=None): def _get_won_opportunity_per_duration(self, cr, uid, ids, field_name, arg, context=None):
res = dict.fromkeys(ids, []) res = dict.fromkeys(ids, [])
obj = self.pool.get('crm.lead') obj = self.pool.get('crm.lead')
first_day = date.today().replace(day=1) today = date.today().replace(day=1)
begin = (today + relativedelta(months=-5)).strftime(tools.DEFAULT_SERVER_DATE_FORMAT)
for section in self.browse(cr, uid, ids, context=context): 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)] domain = [("section_id", "=", section.id), '|', ('type', '=', 'opportunity'), ('date_open', '!=', None), ('create_date', '>=', begin)]
rates = [] group_obj = obj.read_group(cr, uid, domain, ['planned_revenue', "create_date"], "create_date", context=context)
for when in range(0, 5): group_list = [group['planned_revenue'] for group in group_obj]
domain = [("section_id", "=", section.id), ('state', '=', 'done'), ('type', '=', 'opportunity'), ('date_closed', '>=', dates[when].strftime(tools.DEFAULT_SERVER_DATE_FORMAT))] nb_month = group_obj and relativedelta(today, datetime.strptime(group_obj[-1]['__domain'][0][2], '%Y-%m-%d')).months or 0
if when: res[section.id] = [0]*(5 - len(group_list) - nb_month) + group_list + [0]*nb_month
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
return res return res
_columns = { _columns = {
@ -187,12 +158,6 @@ class crm_case_section(osv.osv):
'use_leads': fields.boolean('Leads', '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."), 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), '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) 'won_opportunity_per_duration': fields.function(_get_won_opportunity_per_duration, string='Revenue of opporunities whon per duration', type="string", readonly=True)
} }
@ -205,7 +170,6 @@ class crm_case_section(osv.osv):
'active': 1, 'active': 1,
'stage_ids': _get_stage_common, 'stage_ids': _get_stage_common,
'use_leads': True, 'use_leads': True,
'target_duration': "monthly",
} }
_sql_constraints = [ _sql_constraints = [

View File

@ -78,7 +78,6 @@
<field name="note"/> <field name="note"/>
<field name="alias_id"/> <field name="alias_id"/>
<field name="color"/> <field name="color"/>
<field name="target_duration_txt"/>
<field name="open_lead_per_duration"/> <field name="open_lead_per_duration"/>
<field name="won_opportunity_per_duration"/> <field name="won_opportunity_per_duration"/>
<templates> <templates>
@ -100,10 +99,10 @@
<div class="oe_items_list"> <div class="oe_items_list">
<div class="oe_salesteams_leads" t-if="record.use_leads.raw_value"> <div class="oe_salesteams_leads" t-if="record.use_leads.raw_value">
<a name="%(crm_case_form_view_salesteams_lead)d" type="action">Leads</a> <a name="%(crm_case_form_view_salesteams_lead)d" type="action">Leads</a>
<a name="%(action_report_crm_lead)d" type="action" class="oe_sparkline_bar_link"><field name="open_lead_per_duration" widget="sparkline_bar">Number of opening leads per duration.<br/>(last one is <t t-esc="record.target_duration_txt.value"/>).<br/>Click to see a detailed analysis of leads.</field></a> <a name="%(action_report_crm_lead)d" type="action" class="oe_sparkline_bar_link"><field name="open_lead_per_duration" widget="sparkline_bar">Number of opening leads per month.<br/>Click to see a detailed analysis of leads.</field></a>
</div><div class="oe_salesteams_opportunities"> </div><div class="oe_salesteams_opportunities">
<a name="%(crm_case_form_view_salesteams_opportunity)d" type="action">Opportunities</a> <a name="%(crm_case_form_view_salesteams_opportunity)d" type="action">Opportunities</a>
<a name="%(action_report_crm_opportunity)d" type="action"><field name="won_opportunity_per_duration" widget="sparkline_bar">Revenue of won opportunities per duration.<br/>(last one is <t t-esc="record.target_duration_txt.value"/>).<br/>Click to see a detailed analysis of opportunities.</field></a> <a name="%(action_report_crm_opportunity)d" type="action"><field name="won_opportunity_per_duration" widget="sparkline_bar">Revenue of won opportunities per month.<br/>Click to see a detailed analysis of opportunities.</field></a>
</div> </div>
</div> </div>
</div> </div>
@ -190,9 +189,6 @@
<field name="user_id"/> <field name="user_id"/>
<field name="change_responsible"/> <field name="change_responsible"/>
</group> </group>
<group colspan="4" col="2">
<field name="target_duration" widget="radio"/>
</group>
<group colspan="4" attrs="{'invisible': [('use_leads', '=', False)]}"> <group colspan="4" attrs="{'invisible': [('use_leads', '=', False)]}">
</group> </group>

View File

@ -19,17 +19,11 @@
# #
############################################################################## ##############################################################################
from datetime import date from datetime import date, datetime
from openerp import tools from openerp import tools
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
from openerp.osv import osv, fields from openerp.osv import osv, fields
MONTHS = {
"monthly": 1,
"semesterly": 3,
"semiannually": 6,
"annually": 12
}
class sale_order(osv.osv): class sale_order(osv.osv):
_inherit = 'sale.order' _inherit = 'sale.order'
@ -57,60 +51,40 @@ class crm_case_section(osv.osv):
def _get_created_quotation_per_duration(self, cr, uid, ids, field_name, arg, context=None): def _get_created_quotation_per_duration(self, cr, uid, ids, field_name, arg, context=None):
res = dict.fromkeys(ids, []) res = dict.fromkeys(ids, [])
obj = self.pool.get('sale.order') obj = self.pool.get('sale.order')
first_day = date.today().replace(day=1) today = date.today().replace(day=1)
begin = (today + relativedelta(months=-5)).strftime(tools.DEFAULT_SERVER_DATE_FORMAT)
for section in self.browse(cr, uid, ids, context=context): 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)] domain = [("section_id", "=", section.id), ('state', 'in', ['draft', 'sent']), ('date_order', '>=', begin)]
rates = [] group_obj = obj.read_group(cr, uid, domain, ['amount_total', "date_order"], "date_order", context=context)
for when in range(0, 5): group_list = [group['amount_total'] for group in group_obj]
domain = [("section_id", "=", section.id), ('state', 'in', ['draft', 'sent']), ('date_order', '>=', dates[when].strftime(tools.DEFAULT_SERVER_DATE_FORMAT))] nb_month = group_obj and relativedelta(today, datetime.strptime(group_obj[-1]['__domain'][0][2], '%Y-%m-%d')).months or 0
if when: res[section.id] = [0]*(5 - len(group_list) - nb_month) + group_list + [0]*nb_month
domain += [('date_order', '<', dates[when-1].strftime(tools.DEFAULT_SERVER_DATE_FORMAT))]
# rate = 0
# order_ids = obj.search(cr, uid, domain, context=context)
# for order in obj.browse(cr, uid, order_ids, context=context):
# rate += order.amount_total
# rates.append(rate)
group_obj = obj.read_group(cr, uid, domain, ['amount_total', 'section_id'], "section_id", context=context)
rates.append(group_obj and group_obj[0]['amount_total'] or 0)
rates.reverse()
res[section.id] = rates
return res return res
def _get_validate_saleorder_per_duration(self, cr, uid, ids, field_name, arg, context=None): def _get_validate_saleorder_per_duration(self, cr, uid, ids, field_name, arg, context=None):
res = dict.fromkeys(ids, []) res = dict.fromkeys(ids, [])
obj = self.pool.get('sale.order') obj = self.pool.get('sale.order')
first_day = date.today().replace(day=1) today = date.today().replace(day=1)
begin = (today + relativedelta(months=-5)).strftime(tools.DEFAULT_SERVER_DATE_FORMAT)
for section in self.browse(cr, uid, ids, context=context): 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)] domain = [("section_id", "=", section.id), ('state', 'not in', ['draft', 'sent']), ('date_confirm', '>=', begin)]
rates = [] group_obj = obj.read_group(cr, uid, domain, ['amount_total', "date_confirm"], "date_confirm", context=context)
for when in range(0, 5): group_list = [group['amount_total'] for group in group_obj]
domain = [("section_id", "=", section.id), ('state', 'not in', ['draft', 'sent']), ('date_confirm', '>=', dates[when].strftime(tools.DEFAULT_SERVER_DATE_FORMAT))] nb_month = group_obj and relativedelta(today, datetime.strptime(group_obj[-1]['__domain'][0][2], '%Y-%m-%d')).months or 0
if when: res[section.id] = [0]*(5 - len(group_list) - nb_month) + group_list + [0]*nb_month
domain += [('date_confirm', '<', dates[when-1].strftime(tools.DEFAULT_SERVER_DATE_FORMAT))]
group_obj = obj.read_group(cr, uid, domain, ['amount_total', 'section_id'], "section_id", context=context)
rates.append(group_obj and group_obj[0]['amount_total'] or 0)
rates.reverse()
res[section.id] = rates
return res return res
def _get_sent_invoice_per_duration(self, cr, uid, ids, field_name, arg, context=None): def _get_sent_invoice_per_duration(self, cr, uid, ids, field_name, arg, context=None):
res = dict.fromkeys(ids, []) res = dict.fromkeys(ids, [])
obj = self.pool.get('account.invoice.report') obj = self.pool.get('account.invoice.report')
first_day = date.today().replace(day=1) today = date.today().replace(day=1)
begin = (today + relativedelta(months=-5)).strftime(tools.DEFAULT_SERVER_DATE_FORMAT)
for section in self.browse(cr, uid, ids, context=context): 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)] domain = [("section_id", "=", section.id), ('state', 'not in', ['draft', 'cancel']), ('date', '>=', begin)]
rates = [] group_obj = obj.read_group(cr, uid, domain, ['price_total', "date"], "date", context=context)
for when in range(0, 5): group_list = [group['price_total'] for group in group_obj]
domain = [("section_id", "=", section.id), ('state', 'not in', ['draft', 'cancel']), ('date', '>=', dates[when].strftime(tools.DEFAULT_SERVER_DATE_FORMAT))] nb_month = group_obj and relativedelta(today, datetime.strptime(group_obj[-1]['__domain'][0][2], '%Y-%m-%d')).months or 0
if when: res[section.id] = [0]*(5 - len(group_list) - nb_month) + group_list + [0]*nb_month
domain += [('date', '<', dates[when-1].strftime(tools.DEFAULT_SERVER_DATE_FORMAT))]
group_obj = obj.read_group(cr, uid, domain, ['price_total', 'section_id'], "section_id", context=context)
rates.append(group_obj and group_obj[0]['price_total'] or 0)
rates.reverse()
res[section.id] = rates
return res return res
_columns = { _columns = {

View File

@ -217,9 +217,11 @@
<field name="inherit_id" ref="crm.crm_case_section_view_form"/> <field name="inherit_id" ref="crm.crm_case_section_view_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<data> <data>
<field name="target_duration" position="before"> <xpath expr="//group" position="inside">
<field name="target_invoice"/> <group>
</field> <field name="target_invoice"/>
</group>
</xpath>
</data> </data>
</field> </field>
</record> </record>
@ -240,19 +242,19 @@
</xpath> </xpath>
<xpath expr="//div[@class='oe_salesteams_leads']" position="after"><div class="oe_salesteams_orders"> <xpath expr="//div[@class='oe_salesteams_leads']" position="after"><div class="oe_salesteams_orders">
<a name="%(action_orders_salesteams)d" type="action">Sales Orders</a> <a name="%(action_orders_salesteams)d" type="action">Sales Orders</a>
<a name="%(sale.action_order_report_all)d" type="action" class="oe_sparkline_bar_link"><field name="validate_saleorder_per_duration" widget="sparkline_bar">Revenue of confirmed sales orders per <t t-esc="record.target_duration_txt.value"/>).<br/>Click the acces to Sales Analysis</field></a> <a name="%(sale.action_order_report_all)d" type="action" class="oe_sparkline_bar_link"><field name="validate_saleorder_per_duration" widget="sparkline_bar">Revenue of confirmed sales orders per month.<br/>Click the acces to Sales Analysis</field></a>
</div></xpath> </div></xpath>
<xpath expr="//div[@class='oe_salesteams_opportunities']" position="after"><div class="oe_salesteams_invoices"> <xpath expr="//div[@class='oe_salesteams_opportunities']" position="after"><div class="oe_salesteams_invoices">
<a name="%(action_invoice_salesteams)d" type="action" groups="account.group_account_invoice">Invoices</a> <a name="%(action_invoice_salesteams)d" type="action" groups="account.group_account_invoice">Invoices</a>
<a name="%(account.action_account_invoice_report_all)d" type="action" class="oe_sparkline_bar_link"><field name="sent_invoice_per_duration" widget="sparkline_bar">Revenue of sent invoices per <t t-esc="record.target_duration_txt.value"/>.<br/>Click to see a detailed analysis of invoices.</field></a> <a name="%(account.action_account_invoice_report_all)d" type="action" class="oe_sparkline_bar_link"><field name="sent_invoice_per_duration" widget="sparkline_bar">Revenue of sent invoices per month.<br/>Click to see a detailed analysis of invoices.</field></a>
</div><div class="oe_salesteams_quotations"> </div><div class="oe_salesteams_quotations">
<a name="%(action_quotations_salesteams)d" type="action" class="oe_sparkline_bar_link">Quotations</a> <a name="%(action_quotations_salesteams)d" type="action" class="oe_sparkline_bar_link">Quotations</a>
<a name="%(sale.action_order_report_all)d" type="action" class="oe_sparkline_bar_link"><field name="created_quotation_per_duration" widget="sparkline_bar">Revenue of created quotation per <t t-esc="record.target_duration_txt.value"/>.<br/>Click to see a detailed analysis of sales.</field></a> <a name="%(sale.action_order_report_all)d" type="action" class="oe_sparkline_bar_link"><field name="created_quotation_per_duration" widget="sparkline_bar">Revenue of created quotation per month.<br/>Click to see a detailed analysis of sales.</field></a>
</div></xpath> </div></xpath>
<xpath expr="//div[@class='oe_items_list']" position="after"> <xpath expr="//div[@class='oe_items_list']" position="after">
<div class="oe_center" t-if="record.target_invoice.raw_value"> <div class="oe_center" t-if="record.target_invoice.raw_value">
<field name="sent_invoice_per_duration" widget="gage" style="width:160px; height: 120px;" options="{'max_field': 'target_invoice', 'label_field': 'target_duration_txt'}">Invoiced</field> <field name="sent_invoice_per_duration" widget="gage" style="width:160px; height: 120px;" options="{'max_field': 'target_invoice'}">Invoiced</field>
<field name="forecast" widget="gage" style="width:160px; height: 120px;" options="{'max_field': 'target_invoice', 'label_field': 'target_duration_txt', 'action_change': 'action_forecast'}">Forecast</field> <field name="forecast" widget="gage" style="width:160px; height: 120px;" options="{'max_field': 'target_invoice', 'action_change': 'action_forecast'}">Forecast</field>
</div> </div>
<div class="oe_center" style="color:#bbbbbb;" t-if="!record.target_invoice.raw_value"> <div class="oe_center" style="color:#bbbbbb;" t-if="!record.target_invoice.raw_value">
<br/>Define an invoicing target in the sales team settings to see the period's achievement and forecast at a glance. <br/>Define an invoicing target in the sales team settings to see the period's achievement and forecast at a glance.