[IMP] crm: implement the forecast feature for opportunities
Add a new submenu "Forecast" in "Reporting" for CRM The Forecast shows 4 views: 1. Kanban 2. Graph 3. Pivot 4. List Objective Shows the short term forecast for opportunities (crm_lead) based on their expected closing (date_deadline) and have an overview of the prorated revenues for each period (defaults to month). Implementation 1. Kanban - the progressbar is using the prorated_revenue - the forecast_field is date_deadline - the default groupby is date_deadline 2.3. Graph, Pivot - the measure defaults to the prorated_revenue - the row defaults to date_deadline 4. List - shows the prorated_revenue The special filter "Forecast" is defined to be used by the forecastModelExtension (JS). (define the forecast_filter context key) The forecast_field context key is defined in the action to be used by the forecastModelExtension and the forecastService (JS). The demo data for opportunities is updated to spread date_deadline over 4 months Enable drag&drop and quickCreate features for the kanban view with the use of the allow_group_range_value <field> xml attribute Add a "Won" flag for the forecast view to better distinguish opportunities that need to be worked on Test tour Task-ID: 2243913 PR odoo/odoo#69380 ENT PR odoo/enterprise#18547
This commit is contained in:
@@ -33,6 +33,7 @@
|
||||
'data/crm_stage_data.xml',
|
||||
'data/crm_team_data.xml',
|
||||
'data/digest_data.xml',
|
||||
'data/ir_action_data.xml',
|
||||
'data/ir_cron_data.xml',
|
||||
'data/mail_data.xml',
|
||||
'data/crm_recurring_plan_data.xml',
|
||||
|
||||
@@ -353,7 +353,7 @@ Andrew</p>]]></field>
|
||||
<field name="street">Kensington Road 189</field>
|
||||
<field name="tag_ids" eval="[(6, 0, [ref('sales_team.categ_oppor1')])]"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="date_deadline" eval="(DateTime.today() + relativedelta(weeks=2)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="date_deadline" eval="(DateTime.today() + relativedelta(weeks=4)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="team_id" ref="sales_team.team_sales_department"/>
|
||||
<field name="user_id" ref="base.user_admin"/>
|
||||
<field name="stage_id" ref="crm.stage_lead1"/>
|
||||
@@ -379,7 +379,7 @@ Andrew</p>]]></field>
|
||||
<field name="phone">+32 10 588 558</field>
|
||||
<field name="tag_ids" eval="[(6, 0, [ref('sales_team.categ_oppor2')])]"/>
|
||||
<field name="priority">2</field>
|
||||
<field name="date_deadline" eval="(DateTime.today() + relativedelta(weeks=2)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="date_deadline" eval="(DateTime.today() + relativedelta(months=1)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="team_id" ref="sales_team.crm_team_1"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="stage_id" ref="crm.stage_lead1"/>
|
||||
@@ -402,7 +402,7 @@ Andrew</p>]]></field>
|
||||
<field name="phone">+32 10 588 558</field>
|
||||
<field name="tag_ids" eval="[(6, 0, [ref('sales_team.categ_oppor1')])]"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="date_deadline" eval="(DateTime.today() + relativedelta(weeks=1)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="date_deadline" eval="(DateTime.today() + relativedelta(months=1)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="team_id" ref="sales_team.team_sales_department"/>
|
||||
<field name="user_id" ref="base.user_admin"/>
|
||||
<field name="stage_id" ref="crm.stage_lead2"/>
|
||||
@@ -495,7 +495,7 @@ Andrew</p>]]></field>
|
||||
<field name="street">Union Road</field>
|
||||
<field name="tag_ids" eval="[(6, 0, [ref('sales_team.categ_oppor5')])]"/>
|
||||
<field name="priority">2</field>
|
||||
<field name="date_deadline" eval="(DateTime.today() + relativedelta(weeks=1)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="date_deadline" eval="DateTime.today().strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="team_id" ref="sales_team.team_sales_department"/>
|
||||
<field name="user_id" ref="base.user_admin"/>
|
||||
<field name="stage_id" ref="crm.stage_lead2"/>
|
||||
@@ -520,7 +520,7 @@ Andrew</p>]]></field>
|
||||
<field name="street">Rue des Palais 51, bte 33</field>
|
||||
<field name="tag_ids" eval="[(6, 0, [ref('sales_team.categ_oppor3'),ref('sales_team.categ_oppor4')])]"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="date_deadline" eval="(DateTime.today() + relativedelta(days=3)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="date_deadline" eval="(DateTime.today() + relativedelta(months=1)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="team_id" ref="sales_team.crm_team_1"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="stage_id" ref="crm.stage_lead2"/>
|
||||
@@ -553,7 +553,7 @@ Andrew</p>]]></field>
|
||||
<field name="partner_id" ref="base.res_partner_4"/>
|
||||
<field name="tag_ids" eval="[(6, 0, [ref('sales_team.categ_oppor4'),ref('sales_team.categ_oppor6')])]"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="date_deadline" eval="(DateTime.today() + relativedelta(weeks=3)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="date_deadline" eval="(DateTime.today() + relativedelta(months=2)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="team_id" ref="sales_team.crm_team_1"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="stage_id" ref="crm.stage_lead2"/>
|
||||
@@ -628,6 +628,7 @@ Andrew</p>]]></field>
|
||||
<field name="phone">+1 312 349 2324</field>
|
||||
<field name="tag_ids" eval="[(6, 0, [ref('sales_team.categ_oppor4'),ref('sales_team.categ_oppor8')])]"/>
|
||||
<field name="priority">2</field>
|
||||
<field name="date_deadline" eval="DateTime.today().strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="team_id" ref="sales_team.team_sales_department"/>
|
||||
<field name="user_id" ref="base.user_admin"/>
|
||||
<field name="stage_id" ref="crm.stage_lead3"/>
|
||||
@@ -684,6 +685,7 @@ Andrew</p>]]></field>
|
||||
<field name="partner_id" ref="base.res_partner_18"/>
|
||||
<field name="priority">0</field>
|
||||
<field name="tag_ids" eval="[(6, 0, [ref('sales_team.categ_oppor3')])]"/>
|
||||
<field name="date_deadline" eval="DateTime.today().strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="team_id" ref="sales_team.crm_team_1"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="stage_id" ref="crm.stage_lead3"/>
|
||||
@@ -702,6 +704,7 @@ Andrew</p>]]></field>
|
||||
<field name="country_id" ref="base.pe"/>
|
||||
<field name="city">Lima</field>
|
||||
<field name="priority">0</field>
|
||||
<field name="date_deadline" eval="(DateTime.today() + relativedelta(months=2)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="tag_ids" eval="[(6, 0, [ref('sales_team.categ_oppor7')])]"/>
|
||||
<field name="team_id" ref="sales_team.team_sales_department"/>
|
||||
<field name="user_id" ref="base.user_admin"/>
|
||||
@@ -750,7 +753,6 @@ Andrew</p>]]></field>
|
||||
<field name="zip">1300</field>
|
||||
<field name="priority">2</field>
|
||||
<field name="tag_ids" eval="[(6, 0, [ref('sales_team.categ_oppor2')])]"/>
|
||||
<field name="date_deadline" eval="(DateTime.today() + relativedelta(days=6)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="team_id" ref="sales_team.crm_team_1"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="stage_id" ref="crm.stage_lead3"/>
|
||||
@@ -774,7 +776,7 @@ Andrew</p>]]></field>
|
||||
<field name="street">Rue de Namur 69</field>
|
||||
<field name="priority">2</field>
|
||||
<field name="tag_ids" eval="[(6, 0, [ref('sales_team.categ_oppor2')])]"/>
|
||||
<field name="date_deadline" eval="(DateTime.today() + relativedelta(days=6)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="date_deadline" eval="DateTime.today().strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="team_id" ref="sales_team.crm_team_1"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="stage_id" ref="crm.stage_lead3"/>
|
||||
@@ -865,7 +867,7 @@ Andrew</p>]]></field>
|
||||
<field name="street">1920 Del Dew Drive</field>
|
||||
<field name="tag_ids" eval="[(6, 0, [ref('sales_team.categ_oppor1')])]"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="date_deadline" eval="(DateTime.today() + relativedelta(weeks=2)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="date_deadline" eval="(DateTime.today() + relativedelta(months=1)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="team_id" ref="sales_team.team_sales_department"/>
|
||||
<field name="user_id" ref="base.user_admin"/>
|
||||
<field name="stage_id" ref="crm.stage_lead1"/>
|
||||
@@ -887,7 +889,7 @@ Andrew</p>]]></field>
|
||||
<field name="street">1920 Del Dew Drive</field>
|
||||
<field name="tag_ids" eval="[(6, 0, [ref('sales_team.categ_oppor1')])]"/>
|
||||
<field name="priority">1</field>
|
||||
<field name="date_deadline" eval="(DateTime.today() + relativedelta(weeks=2)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="date_deadline" eval="(DateTime.today() + relativedelta(months=2)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="team_id" ref="sales_team.team_sales_department"/>
|
||||
<field name="user_id" ref="base.user_admin"/>
|
||||
<field name="stage_id" ref="crm.stage_lead2"/>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="action_opportunity_forecast" model="ir.actions.server">
|
||||
<field name="name">Crm: Forecast</field>
|
||||
<field name="model_id" ref="crm.model_crm_team"/>
|
||||
<field name="state">code</field>
|
||||
<field name="groups_id" eval="[(4, ref('base.group_user'))]"/>
|
||||
<field name="code">action = model.action_opportunity_forecast()</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -587,6 +587,15 @@ class Team(models.Model):
|
||||
@api.model
|
||||
def action_your_pipeline(self):
|
||||
action = self.env["ir.actions.actions"]._for_xml_id("crm.crm_lead_action_pipeline")
|
||||
return self._action_update_to_pipeline(action)
|
||||
|
||||
@api.model
|
||||
def action_opportunity_forecast(self):
|
||||
action = self.env['ir.actions.actions']._for_xml_id('crm.crm_lead_action_forecast')
|
||||
return self._action_update_to_pipeline(action)
|
||||
|
||||
@api.model
|
||||
def _action_update_to_pipeline(self, action):
|
||||
user_team_id = self.env.user.sale_team_id.id
|
||||
if user_team_id:
|
||||
# To ensure that the team is readable in multi company
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
name="Activities"
|
||||
parent="crm_menu_report"
|
||||
action="crm_activity_report_action"
|
||||
sequence="3"/>
|
||||
sequence="4"/>
|
||||
|
||||
<record id="crm_activity_report_action_team" model="ir.actions.act_window">
|
||||
<field name="name">Pipeline Activities</field>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.oe_kanban_card_lost_ribbon {
|
||||
.oe_kanban_card_ribbon {
|
||||
min-height: 105px;
|
||||
.o_kanban_record_title {
|
||||
max-width: calc(100% - 65px);
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/** @odoo-module */
|
||||
import tour from 'web_tour.tour';
|
||||
const today = moment();
|
||||
|
||||
tour.register('crm_forecast', {
|
||||
test: true,
|
||||
url: "/web",
|
||||
}, [
|
||||
tour.stepUtils.showAppsMenuItem(),
|
||||
{
|
||||
trigger: ".o_app[data-menu-xmlid='crm.crm_menu_root']",
|
||||
content: "open crm app",
|
||||
}, {
|
||||
trigger: '.o_dropdown_toggler[data-menu-xmlid="crm.crm_menu_report"]',
|
||||
content: 'Open Reporting menu',
|
||||
run: 'click',
|
||||
}, {
|
||||
trigger: '.o_dropdown_item[data-menu-xmlid="crm.crm_menu_forecast"]',
|
||||
content: 'Open Forecast menu',
|
||||
run: 'click',
|
||||
}, {
|
||||
trigger: '.o_column_quick_create:contains(Add next month)',
|
||||
content: 'Wait page loading'
|
||||
}, {
|
||||
trigger: ".o-kanban-button-new",
|
||||
content: "click create",
|
||||
run: 'click',
|
||||
}, {
|
||||
trigger: "input[name=name]",
|
||||
content: "complete name",
|
||||
run: "text Test Opportunity 1",
|
||||
}, {
|
||||
trigger: "div[name=expected_revenue] > input",
|
||||
content: "complete expected revenue",
|
||||
run: "text 999999",
|
||||
}, {
|
||||
trigger: "button.o_kanban_edit",
|
||||
content: "edit lead",
|
||||
}, {
|
||||
trigger: "input[name=date_deadline]",
|
||||
content: "complete expected closing",
|
||||
run: `text ${today.format("MM/DD/YYYY")}`,
|
||||
}, {
|
||||
trigger: "input[name=date_deadline]",
|
||||
content: "click to make the datepicker disappear",
|
||||
run: "click"
|
||||
}, {
|
||||
trigger: "body:not(:has(div.bootstrap-datetimepicker-widget))",
|
||||
content: "wait for date_picker to disappear",
|
||||
run: function () {},
|
||||
}, {
|
||||
trigger: '.o_back_button',
|
||||
content: 'navigate back to the kanban view',
|
||||
position: "bottom",
|
||||
run: "click"
|
||||
}, {
|
||||
trigger: ".o_kanban_record .o_kanban_record_title:contains('Test Opportunity 1')",
|
||||
content: "move to the next month",
|
||||
run: function (actions) {
|
||||
const undefined_groups = $('.o_column_title:contains("Undefined")').length;
|
||||
actions.drag_and_drop(` .o_opportunity_kanban .o_kanban_group:eq(${1 + undefined_groups})`, this.$anchor);
|
||||
}
|
||||
}, {
|
||||
trigger: ".o_kanban_record .o_kanban_record_title:contains('Test Opportunity 1')",
|
||||
content: "edit lead",
|
||||
run: "click"
|
||||
}, {
|
||||
trigger: `span[name=date_deadline]:contains("${moment(today).add(2, 'months').startOf('month').subtract(1, 'days').format("MM/DD/YYYY")}")`,
|
||||
content: "edit datetime",
|
||||
position: "bottom",
|
||||
run: "click"
|
||||
}, {
|
||||
trigger: "input[name=date_deadline]",
|
||||
content: "complete expected closing",
|
||||
run: `text ${moment(today).add(5, 'months').startOf('month').subtract(1, 'days').format("MM/DD/YYYY")}`
|
||||
}, {
|
||||
trigger: "body:not(:has(div.bootstrap-datetimepicker-widget))",
|
||||
content: "wait for date_picker to disappear",
|
||||
run: function () {},
|
||||
}, {
|
||||
trigger: "input[name=probability]",
|
||||
content: "max out probability",
|
||||
run: "text 100"
|
||||
}, {
|
||||
trigger: '.o_back_button',
|
||||
content: 'navigate back to the kanban view',
|
||||
position: "bottom",
|
||||
run: "click"
|
||||
}, {
|
||||
trigger: '.o_kanban_add_column',
|
||||
content: "add next month",
|
||||
run: "click"
|
||||
}, {
|
||||
trigger: ".o_kanban_record:contains('Test Opportunity 1'):contains('Won')",
|
||||
content: "assert that the opportunity has the Won banner",
|
||||
run: function () {},
|
||||
}
|
||||
]);
|
||||
@@ -25,6 +25,8 @@ class TestUi(HttpCase):
|
||||
})
|
||||
self.start_tour("/web", 'crm_rainbowman', login="temp_crm_user")
|
||||
|
||||
def test_03_crm_tour_forecast(self):
|
||||
self.start_tour("/web", 'crm_forecast', login="admin")
|
||||
|
||||
class TestCRMLeadMisc(TestCrmCommon):
|
||||
|
||||
|
||||
@@ -535,7 +535,7 @@
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<t t-set="lost_ribbon" t-value="!record.active.raw_value and record.probability and record.probability.raw_value == 0"/>
|
||||
<div t-attf-class="#{!selection_mode ? kanban_color(record.color.raw_value) : ''} #{lost_ribbon ? 'oe_kanban_card_lost_ribbon' : ''} oe_kanban_global_click oe_kanban_card d-flex flex-column">
|
||||
<div t-attf-class="#{!selection_mode ? kanban_color(record.color.raw_value) : ''} #{lost_ribbon ? 'oe_kanban_card_ribbon' : ''} oe_kanban_global_click oe_kanban_card d-flex flex-column">
|
||||
<div class="ribbon ribbon-top-right"
|
||||
attrs="{'invisible': ['|', ('probability', '>', 0), ('active', '=', True)]}">
|
||||
<span class="bg-danger">Lost</span>
|
||||
@@ -591,6 +591,59 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="crm_lead_view_kanban_forecast" model="ir.ui.view">
|
||||
<field name="name">crm.lead.view.kanban.forecast</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="inherit_id" ref="crm.crm_case_kanban_view_leads"/>
|
||||
<field name="mode">primary</field>
|
||||
<field name="priority">32</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//kanban" position="attributes">
|
||||
<attribute name="default_group_by">date_deadline</attribute>
|
||||
<attribute name="js_class">forecast_kanban</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//kanban" position="inside">
|
||||
<field name="date_deadline" allow_group_range_value="true"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='expected_revenue']" position="replace">
|
||||
<field name="prorated_revenue"/>
|
||||
</xpath>
|
||||
<xpath expr="//progressbar" position="attributes">
|
||||
<attribute name="sum_field">prorated_revenue</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//t[@t-set='lost_ribbon']" position="after">
|
||||
<t t-set="won_ribbon" t-value="record.active.raw_value and record.probability and record.probability.raw_value == 100"/>
|
||||
</xpath>
|
||||
<xpath expr="//div[contains(@t-attf-class, 'oe_kanban_card')]" position="attributes">
|
||||
<attribute name="t-attf-class">
|
||||
#{!selection_mode ? kanban_color(record.color.raw_value) : ''}
|
||||
#{lost_ribbon || won_ribbon ? 'oe_kanban_card_ribbon' : ''}
|
||||
oe_kanban_global_click oe_kanban_card d-flex flex-column
|
||||
</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//div[hasclass('ribbon')]" position="replace">
|
||||
<div class="ribbon ribbon-top-right"
|
||||
attrs="{'invisible': ['&', '|', ('probability', '>', 0), ('active', '=', True),
|
||||
'|', ('probability', '<', 100), ('active', '=', False)]}">
|
||||
<span t-if="won_ribbon" class="bg-success">Won</span>
|
||||
<span t-elif="lost_ribbon" class="bg-danger">Lost</span>
|
||||
</div>
|
||||
</xpath>
|
||||
<xpath expr="//div[hasclass('o_kanban_record_subtitle')]" position="replace">
|
||||
<div class="o_kanban_record_subtitle">
|
||||
<t t-if="record.prorated_revenue.raw_value">
|
||||
<field name="prorated_revenue" widget="monetary" options="{'currency_field': 'company_currency'}"/>
|
||||
<span t-if="record.recurring_revenue and record.recurring_revenue.raw_value"> + </span>
|
||||
</t>
|
||||
<t t-if="record.recurring_revenue and record.recurring_revenue.raw_value">
|
||||
<field name="recurring_revenue" widget="monetary" options="{'currency_field': 'company_currency'}"/>
|
||||
<field name="recurring_plan"/>
|
||||
</t>
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_crm_case_leads_filter" model="ir.ui.view">
|
||||
<field name="name">crm.lead.search.lead</field>
|
||||
<field name="model">crm.lead</field>
|
||||
@@ -738,6 +791,25 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="crm_lead_view_tree_forecast" model="ir.ui.view">
|
||||
<field name="name">crm.lead.view.tree.forecast</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="inherit_id" ref="crm.crm_case_tree_view_oppor"/>
|
||||
<field name="mode">primary</field>
|
||||
<field name="priority">32</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//tree" position="attributes">
|
||||
<attribute name="js_class">forecast_list</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='expected_revenue']" position="attributes">
|
||||
<attribute name="optional">hide</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='expected_revenue']" position="after">
|
||||
<field name="prorated_revenue" sum="Prorated Revenues" optional="show" widget="monetary" options="{'currency_field': 'company_currency'}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="crm_lead_view_list_activities" model="ir.ui.view">
|
||||
<field name="name">crm.lead.list.activities</field>
|
||||
<field name="model">crm.lead</field>
|
||||
@@ -797,6 +869,24 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="crm_lead_view_graph_forecast" model="ir.ui.view">
|
||||
<field name="name">crm.lead.view.graph.forecast</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="priority">32</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Opportunities Forecast" sample="1" js_class="forecast_graph">
|
||||
<field name="date_deadline" type="row"/>
|
||||
<field name="prorated_revenue" type="measure"/>
|
||||
<field name="automated_probability" invisible="1"/>
|
||||
<field name="color" invisible="1"/>
|
||||
<field name="day_open" invisible="1"/>
|
||||
<field name="day_close" invisible="1"/>
|
||||
<field name="message_bounce" invisible="1"/>
|
||||
<field name="probability" invisible="1"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="crm_lead_view_pivot" model="ir.ui.view">
|
||||
<field name="name">crm.lead.view.pivot</field>
|
||||
<field name="model">crm.lead</field>
|
||||
@@ -811,6 +901,25 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="crm_lead_view_pivot_forecast" model="ir.ui.view">
|
||||
<field name="name">crm.lead.view.pivot.forecast</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="priority">32</field>
|
||||
<field name="arch" type="xml">
|
||||
<pivot string="Forecast Analysis" sample="1" js_class="forecast_pivot">
|
||||
<field name="date_deadline" interval="month" type="row"/>
|
||||
<field name="stage_id" type="col"/>
|
||||
<field name="prorated_revenue" type="measure"/>
|
||||
<field name="automated_probability" invisible="1"/>
|
||||
<field name="color" invisible="1"/>
|
||||
<field name="day_open" invisible="1"/>
|
||||
<field name="day_close" invisible="1"/>
|
||||
<field name="message_bounce" invisible="1"/>
|
||||
<field name="probability" invisible="1"/>
|
||||
</pivot>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_crm_case_opportunities_filter" model="ir.ui.view">
|
||||
<field name="name">crm.lead.search.opportunity</field>
|
||||
<field name="model">crm.lead</field>
|
||||
@@ -887,6 +996,24 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="crm_lead_view_search_forecast" model="ir.ui.view">
|
||||
<field name="name">crm.lead.view.search.forecast</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="inherit_id" ref="crm.view_crm_case_opportunities_filter"/>
|
||||
<field name="mode">primary</field>
|
||||
<field name="priority">32</field>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//filter[@name='assigned_to_me']" position="before">
|
||||
<filter name="forecast" string="Upcoming Closings" context="{'forecast_filter':1}"/>
|
||||
<separator/>
|
||||
</xpath>
|
||||
<xpath expr="//filter[@name='date_deadline']" position="replace"/>
|
||||
<filter name="month" position="before">
|
||||
<filter string="Expected Closing" name="date_deadline" context="{'group_by':'date_deadline:month'}"/>
|
||||
</filter>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
'Mark as Lost' in action dropdown
|
||||
-->
|
||||
@@ -1095,9 +1222,62 @@ if record:
|
||||
<field name="act_window_id" ref="crm_lead_action_pipeline"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_lead_action_forecast" model="ir.actions.act_window">
|
||||
<field name="name">Forecast</field>
|
||||
<field name="res_model">crm.lead</field>
|
||||
<field name="view_mode">kanban,graph,pivot,tree,form</field>
|
||||
<field name="domain">[('type', '=', 'opportunity')]</field>
|
||||
<field name="context">{
|
||||
'default_type': 'opportunity',
|
||||
'search_default_assigned_to_me': 1,
|
||||
'search_default_forecast': 1,
|
||||
'search_default_date_deadline': 1,
|
||||
'forecast_field': 'date_deadline'
|
||||
}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
No opportunity to display!
|
||||
</p><p>
|
||||
Easily set expected closing dates and overview your revenue streams.
|
||||
</p>
|
||||
</field>
|
||||
<field name="search_view_id" ref="crm.crm_lead_view_search_forecast"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_lead_action_forecast_view_kanban" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="0"/>
|
||||
<field name="view_mode">kanban</field>
|
||||
<field name="view_id" ref="crm_lead_view_kanban_forecast"/>
|
||||
<field name="act_window_id" ref="crm_lead_action_forecast"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_lead_action_forecast_view_graph" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="1"/>
|
||||
<field name="view_mode">graph</field>
|
||||
<field name="view_id" ref="crm_lead_view_graph_forecast"/>
|
||||
<field name="act_window_id" ref="crm_lead_action_forecast"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_lead_action_forecast_view_pivot" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="2"/>
|
||||
<field name="view_mode">pivot</field>
|
||||
<field name="view_id" ref="crm_lead_view_pivot_forecast"/>
|
||||
<field name="act_window_id" ref="crm_lead_action_forecast"/>
|
||||
</record>
|
||||
|
||||
<record id="crm_lead_action_forecast_view_tree" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="3"/>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="view_id" ref="crm_lead_view_tree_forecast"/>
|
||||
<field name="act_window_id" ref="crm_lead_action_forecast"/>
|
||||
</record>
|
||||
|
||||
<record id="menu_crm_opportunities" model="ir.ui.menu">
|
||||
<field name="action" ref="crm.action_your_pipeline"/>
|
||||
</record>
|
||||
<record id="crm_menu_forecast" model="ir.ui.menu">
|
||||
<field name="action" ref="crm.action_opportunity_forecast"/>
|
||||
</record>
|
||||
<record id="crm_menu_root" model="ir.ui.menu">
|
||||
<field name="action" ref="crm.action_your_pipeline"/>
|
||||
</record>
|
||||
|
||||
@@ -60,17 +60,22 @@
|
||||
parent="crm_menu_root"
|
||||
sequence="20"
|
||||
groups="sales_team.group_sale_salesman"/>
|
||||
<menuitem
|
||||
id="crm_menu_forecast"
|
||||
name="Forecast"
|
||||
parent="crm_menu_report"
|
||||
sequence="1"/>
|
||||
<menuitem
|
||||
id="crm_opportunity_report_menu_lead"
|
||||
name="Leads"
|
||||
parent="crm_menu_report"
|
||||
groups="crm.group_use_lead"
|
||||
sequence="1"/>
|
||||
sequence="2"/>
|
||||
<menuitem
|
||||
id="crm_opportunity_report_menu"
|
||||
name="Pipeline"
|
||||
parent="crm_menu_report"
|
||||
sequence="2"/>
|
||||
sequence="3"/>
|
||||
|
||||
<!-- CONFIGURATION -->
|
||||
<menuitem
|
||||
|
||||
Reference in New Issue
Block a user