Initial commit: Crm packages

This commit is contained in:
Ernad Husremovic 2025-08-29 15:20:49 +02:00
commit 21a345b5b9
654 changed files with 418312 additions and 0 deletions

12
README.md Normal file
View file

@ -0,0 +1,12 @@
# Crm
This repository contains OCA OCB packages for crm.
## Packages Included
- odoo-bringout-oca-ocb-crm
- odoo-bringout-oca-ocb-crm_iap_enrich
- odoo-bringout-oca-ocb-crm_iap_mine
- odoo-bringout-oca-ocb-crm_livechat
- odoo-bringout-oca-ocb-crm_mail_plugin
- odoo-bringout-oca-ocb-crm_sms

View file

@ -0,0 +1,54 @@
# CRM
Odoo addon: crm
## Installation
```bash
pip install odoo-bringout-oca-ocb-crm
```
## Dependencies
This addon depends on:
- base_setup
- sales_team
- mail
- calendar
- resource
- utm
- web_tour
- web_kanban_gauge
- contacts
- digest
- phone_validation
## Manifest Information
- **Name**: CRM
- **Version**: 1.8
- **Category**: Sales/CRM
- **License**: LGPL-3
- **Installable**: True
## Source
Based on [OCA/OCB](https://github.com/OCA/OCB) branch 16.0, addon `crm`.
## License
This package maintains the original LGPL-3 license from the upstream Odoo project.
## Documentation
- Overview: doc/OVERVIEW.md
- Architecture: doc/ARCHITECTURE.md
- Models: doc/MODELS.md
- Controllers: doc/CONTROLLERS.md
- Wizards: doc/WIZARDS.md
- Install: doc/INSTALL.md
- Usage: doc/USAGE.md
- Configuration: doc/CONFIGURATION.md
- Dependencies: doc/DEPENDENCIES.md
- Troubleshooting: doc/TROUBLESHOOTING.md
- FAQ: doc/FAQ.md

View file

@ -0,0 +1,97 @@
Odoo CRM
--------
Boost sales productivity, improve win rates, grow revenue with the Odoo
<a href="https://www.odoo.com/app/crm">Open Source CRM</a>.
Manage your sales funnel with no effort. Attract leads, follow-up on phone
calls and meetings. Analyse the quality of your leads to make informed
decisions and save time by integrating emails directly into the application.
Your Sales Funnel, The Way You Like It
--------------------------------------
Track your opportunities pipeline with the revolutionary kanban view. Work
inside your sales funnel and get instant visual information about next actions,
new messages, top opportunities and expected revenues.
Lead Management Made Easy
-------------------------
Create leads automatically from incoming emails. Analyse leads efficiency and
compare performance by campaigns, channels or Sales Team.
Find duplicates, merge leads and assign them to the right salesperson in one
operation. Spend less time on administration and more time on qualifying leads.
Organize Your Opportunities
---------------------------
Get your opportunities organized to stay focused on the best deals. Manage all
your customer interactions from the opportunity like emails, phone calls,
internal notes, meetings and quotations.
Follow opportunities that interest you to get notified upon specific events:
deal won or lost, stage changed, new customer demand, etc.
Email Integration and Automation
--------------------------------
Work with the email applications you already use every day. Whether your
company uses Microsoft Outlook or Gmail, no one needs to change the way they
work, so everyone stays productive.
Route, sort and filter incoming emails automatically. Odoo CRM handles incoming
emails and route them to the right opportunities or Sales Team. New leads are
created on the fly and interested salespersons are notified automatically.
Collaborative Agenda
--------------------
Schedule your meetings and phone calls using the integrated calendar. You can
see your agenda and your colleagues' in one view. As a manager, it's easy to
see what your team is busy with.
Lead Automation and Marketing Campaigns
---------------------------------------
Drive performance by automating tasks with Odoo <a href="https://www.odoo.com/app/crm">CRM</a>.
Use our marketing campaigns to automate lead acquisition, follow ups and
promotions. Define automated actions (e.g. ask a salesperson to call, send an
email, ...) based on triggers (no activity since 20 days, answered a
promotional email, etc.)
Optimize campaigns from lead to close, on every channel. Make smarter decisions
about where to invest and show the impact of your marketing activities on your
company's bottom line.
Customize Your Sales Cycle
--------------------------
Customize your sales cycle by configuring sales stages that perfectly fit your
sales approach. Control statistics to get accurate forecasts to improve your
sales performance at every stage of your customer relationship.
Drive Engagement with Gamification
----------------------------------
### Leverage your team's natural desire for competition
Reinforce good habits and improve win rates with real-time recognition and
rewards inspired by [game mechanics](http://en.wikipedia.org/wiki/Gamification).
Align Sales Teams around clear business objectives with challenges, personal
objectives and team leader boards.
### Leaderboards
Promote leaders and competition amongst Sales Team with performance ratios.
### Personal Objectives
Assign clear goals to users to align them with the company objectives.
### Team Targets
Compare revenues with forecasts and budgets in real time.

View file

@ -0,0 +1,8 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import controllers
from . import models
from . import populate
from . import report
from . import wizard

View file

@ -0,0 +1,95 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
{
'name': 'CRM',
'version': '1.8',
'category': 'Sales/CRM',
'sequence': 15,
'summary': 'Track leads and close opportunities',
'website': 'https://www.odoo.com/app/crm',
'depends': [
'base_setup',
'sales_team',
'mail',
'calendar',
'resource',
'utm',
'web_tour',
'web_kanban_gauge',
'contacts',
'digest',
'phone_validation',
],
'data': [
'security/crm_security.xml',
'security/ir.model.access.csv',
'data/crm_lead_merge_template.xml',
'data/crm_lead_prediction_data.xml',
'data/crm_lost_reason_data.xml',
'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_message_subtype_data.xml',
'data/crm_recurring_plan_data.xml',
'wizard/crm_lead_lost_views.xml',
'wizard/crm_lead_to_opportunity_views.xml',
'wizard/crm_lead_to_opportunity_mass_views.xml',
'wizard/crm_merge_opportunities_views.xml',
'wizard/crm_lead_pls_update_views.xml',
'views/calendar_views.xml',
'views/crm_recurring_plan_views.xml',
'views/crm_lost_reason_views.xml',
'views/crm_stage_views.xml',
'views/crm_lead_views.xml',
'views/crm_team_member_views.xml',
'views/digest_views.xml',
'views/mail_activity_views.xml',
'views/res_config_settings_views.xml',
'views/res_partner_views.xml',
'views/utm_campaign_views.xml',
'report/crm_activity_report_views.xml',
'report/crm_opportunity_report_views.xml',
'views/crm_team_views.xml',
'views/crm_menu_views.xml',
'views/crm_helper_templates.xml',
],
'demo': [
'data/crm_team_demo.xml',
'data/mail_template_demo.xml',
'data/crm_team_member_demo.xml',
'data/mail_activity_type_demo.xml',
'data/crm_lead_demo.xml',
],
'installable': True,
'application': True,
'assets': {
'mail.assets_messaging': [
'crm/static/src/models/*.js',
],
'web.assets_backend': [
'crm/static/src/views/**/*.js',
'crm/static/src/views/**/*.xml',
'crm/static/src/js/tours/crm.js',
'crm/static/src/scss/crm.scss',
'crm/static/src/scss/crm_team_member_views.scss',
],
'web.assets_tests': [
'crm/static/tests/tours/**/*',
],
'web.qunit_suite_tests': [
'crm/static/tests/crm_kanban_progress_bar_mrr_sum_field_tests.js',
'crm/static/tests/mock_server.js',
'crm/static/tests/forecast_kanban_tests.js',
'crm/static/tests/forecast_view_tests.js',
'crm/static/tests/crm_rainbowman_tests.js',
],
},
'license': 'LGPL-3',
}

View file

@ -0,0 +1,2 @@
# -*- coding: utf-8 -*
from . import main

View file

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
from odoo.addons.mail.controllers.mail import MailController
from odoo import http
_logger = logging.getLogger(__name__)
class CrmController(http.Controller):
@http.route('/lead/case_mark_won', type='http', auth='user', methods=['GET'])
def crm_lead_case_mark_won(self, res_id, token):
comparison, record, redirect = MailController._check_token_and_record_or_redirect('crm.lead', int(res_id), token)
if comparison and record:
try:
record.action_set_won_rainbowman()
except Exception:
_logger.exception("Could not mark crm.lead as won")
return MailController._redirect_to_generic_fallback('crm.lead', res_id)
return redirect
@http.route('/lead/case_mark_lost', type='http', auth='user', methods=['GET'])
def crm_lead_case_mark_lost(self, res_id, token):
comparison, record, redirect = MailController._check_token_and_record_or_redirect('crm.lead', int(res_id), token)
if comparison and record:
try:
record.action_set_lost()
except Exception:
_logger.exception("Could not mark crm.lead as lost")
return MailController._redirect_to_generic_fallback('crm.lead', res_id)
return redirect
@http.route('/lead/convert', type='http', auth='user', methods=['GET'])
def crm_lead_convert(self, res_id, token):
comparison, record, redirect = MailController._check_token_and_record_or_redirect('crm.lead', int(res_id), token)
if comparison and record:
try:
record.convert_opportunity(record.partner_id)
except Exception:
_logger.exception("Could not convert crm.lead to opportunity")
return MailController._redirect_to_generic_fallback('crm.lead', res_id)
return redirect

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,182 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="crm_lead_merge_summary" name="crm_lead_merge_summary">
<div class="crm_lead_merge_summary">
<t t-foreach="opportunities" t-as="lead">
<div>
<span>Merged the Lead/Opportunity</span>
<span class="fw-bold" t-field="lead.name"/>
<span>into this one.</span>
</div>
<blockquote class="border-start" data-o-mail-quote="1">
<div t-if="lead.expected_revenue">
<span>Expected Revenues:</span>
<span t-if="lead.expected_revenue">
<span t-if="lead.company_currency" t-field="lead.expected_revenue"
t-options='{"widget": "monetary", "display_currency": lead.company_currency}'/>
<span t-else="" t-out="lead.expected_revenue"/>
<span t-if="lead.recurring_revenue" groups="crm.group_use_recurring_revenues"> + </span>
</span>
<span t-if="lead.recurring_revenue" groups="crm.group_use_recurring_revenues">
<span t-if="lead.company_currency" t-field="lead.recurring_revenue"
t-options='{"widget": "monetary", "display_currency": lead.company_currency}'/>
<span t-else="" t-out="lead.recurring_revenue"/>
<span t-field="lead.recurring_plan.name"/>
</span>
</div>
<div t-elif="lead.recurring_revenue" groups="crm.group_use_recurring_revenues">
<span t-if="lead.company_currency" t-field="lead.recurring_revenue"
t-options='{"widget": "monetary", "display_currency": lead.company_currency}'/>
<span t-else="" t-out="lead.recurring_revenue"/>
<span t-field="lead.recurring_plan.name"/>
</div>
<div t-if="lead.probability">
Probability: <span t-field="lead.probability"/>%
</div>
<div>
Type: <span t-field="lead.type"/>
</div>
<div t-if="lead.type != 'lead'">
Stage: <span t-field="lead.stage_id"/>
</div>
<div t-if="lead.priority">
Priority: <span t-field="lead.priority"/>
</div>
<div t-if="lead.lost_reason_id">
Lost Reason: <span t-field="lead.lost_reason_id"/>
</div>
<div>
Created on: <span t-field="lead.create_date"/>
</div>
<div t-if="lead.date_action_last">
Last Action: <span t-field="lead.date_action_last"/>
</div>
<div t-if="lead.date_deadline">
Expected Closing: <span t-field="lead.date_deadline"/>
</div>
<div t-if="not is_html_empty(lead.description)">
Notes: <span t-field="lead.description"/>
</div>
<div t-if="lead.lang_id" name="lang_id">
Language: <span t-field="lead.lang_id"/>
</div>
<div t-if="lead.referred" name="referred">
Referred By: <span t-field="lead.referred"/>
</div>
<div t-if="lead.tag_ids" name="tag_ids" class="d-flex flex-row">
Tags:
<div class="ms-2 d-flex flex-row">
<div t-foreach="lead.tag_ids" t-as="tag" t-esc="tag.name"
t-attf-class="badge rounded-pill o_tag_color_#{tag.color} d-inline-block"/>
</div>
</div>
<div t-if="lead.user_id" class="mt-3">
Salesperson: <span t-field="lead.user_id"/>
</div>
<div t-if="lead.team_id">
Sales Team: <span t-field="lead.team_id"/>
</div>
<div name="company" groups="base.group_multi_company">
Company: <span t-field="lead.company_id"/>
</div>
<div>
<div class="mt-3"
t-if="lead.contact_name or lead.partner_name or lead.phone or lead.mobile or lead.email_from or lead.website">
<div class="fw-bold">
Contact Details:
</div>
<div t-if="lead.contact_name">
Contact: <span t-field="lead.contact_name"/>
</div>
<div t-if="lead.partner_name">
Company Name: <span t-field="lead.partner_name"/>
</div>
<div t-if="lead.phone">
Phone: <span t-field="lead.phone"/>
</div>
<div t-if="lead.mobile">
Mobile: <span t-field="lead.mobile"/>
</div>
<div t-if="lead.email_from">
Email: <span t-field="lead.email_from"/>
</div>
<div t-if="lead.email_cc">
Email cc: <span t-field="lead.email_cc"/>
</div>
<div t-if="lead.website">
Website: <span t-field="lead.website"/>
</div>
<div t-if="lead.function">
Job Position: <span t-field="lead.function"/>
</div>
</div>
</div>
<div class="mt-3"
t-if="lead.street or lead.street2 or lead.zip or lead.city or lead.state_id or lead.country_id"
name="address">
<div class="fw-bold">
Address:
</div>
<div t-if="lead.street" t-field="lead.street"/>
<div t-if="lead.street2" t-field="lead.street2"/>
<div t-if="lead.zip" t-field="lead.zip"/>
<div t-if="lead.city" t-field="lead.city"/>
<div t-if="lead.state_id" t-field="lead.state_id"/>
<div t-if="lead.country_id" t-field="lead.country_id"/>
</div>
<div class="mt-3" name="marketing"
t-if="lead.campaign_id or lead.medium_id or lead.source_id">
<div class="fw-bold">
Marketing:
</div>
<div t-if="lead.campaign_id">
Campaign: <span t-field="lead.campaign_id"/>
</div>
<div t-if="lead.medium_id">
Medium: <span t-field="lead.medium_id"/>
</div>
<div t-if="lead.source_id">
Source: <span t-field="lead.source_id"/>
</div>
</div>
<t t-set="lead_followers" t-value="merged_followers and merged_followers.get(lead.id)"/>
<div class="mt-3 mb-3" name="merged_followers" t-if="lead_followers">
<div>
The contacts below have been added as followers of this lead
because they have been contacted less than 30 days ago on
<span class="fw-bold" t-esc="lead.name"/>.
</div>
<ul>
<li t-foreach="lead_followers" t-as="follower">
<t t-esc="follower.partner_id.name"/>
<t t-if="follower.partner_id.email">
(<t t-esc="follower.partner_id.email"/>)
</t>
</li>
</ul>
</div>
<t t-set="properties" t-value="lead._format_properties()"/>
<div t-if="properties" class="mt-3 mb-3">
<div class="fw-bold">
Properties
</div>
<ul class="p-0">
<li t-foreach="properties" t-as="property"
class="d-flex flex-row align-items-center">
<t t-esc="property['label']"/>:
<div t-if="'values' in property"
class="ms-2 d-flex flex-row"> <!-- Tags -->
<div t-foreach="property['values']" t-as="tag" t-esc="tag['name']"
t-attf-class="badge rounded-pill o_tag_color_#{tag.get('color', 0)} d-inline-block me-2"/>
</div>
<div t-else="" class="ms-2" t-esc="property['value']"/>
</li>
</ul>
</div>
</blockquote>
</t>
</div>
</template>
</odoo>

View file

@ -0,0 +1,47 @@
<?xml version="1.0" encoding='UTF-8'?>
<odoo>
<data noupdate="1">
<!-- Lead scoring frequency fields -->
<record id="frequency_field_state_id" model="crm.lead.scoring.frequency.field">
<field name="field_id" ref="crm.field_crm_lead__state_id"/>
</record>
<record id="frequency_field_country_id" model="crm.lead.scoring.frequency.field">
<field name="field_id" ref="crm.field_crm_lead__country_id"/>
</record>
<record id="frequency_field_phone_state" model="crm.lead.scoring.frequency.field">
<field name="field_id" ref="crm.field_crm_lead__phone_state"/>
</record>
<record id="frequency_field_email_state" model="crm.lead.scoring.frequency.field">
<field name="field_id" ref="crm.field_crm_lead__email_state"/>
</record>
<record id="frequency_field_source_id" model="crm.lead.scoring.frequency.field">
<field name="field_id" ref="crm.field_crm_lead__source_id"/>
</record>
<record id="frequency_field_lang_id" model="crm.lead.scoring.frequency.field">
<field name="field_id" ref="crm.field_crm_lead__lang_id"/>
</record>
<record id="frequency_field_tag_ids" model="crm.lead.scoring.frequency.field">
<field name="field_id" ref="crm.field_crm_lead__tag_ids"/>
</record>
<record id="crm_pls_fields_param" model="ir.config_parameter">
<field name="key">crm.pls_fields</field>
<field name="value" eval="'phone_state,email_state'"/>
</record>
<record id="crm_pls_start_date_param" model="ir.config_parameter">
<field name="key">crm.pls_start_date</field>
<field name="value" eval="(datetime.now() - timedelta(days=8)).strftime('%Y-%m-%d')"/>
</record>
</data>
<record id="website_crm_score_cron" model="ir.cron">
<field name="name">Predictive Lead Scoring: Recompute Automated Probabilities</field>
<field name="model_id" ref="model_crm_lead"/>
<field name="state">code</field>
<field name="code">model._cron_update_automated_probabilities()</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field name="active" eval="False"/>
<field name="doall" eval="False"/>
</record>
</odoo>

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo><data noupdate="1">
<!-- opportunities' lost causes -->
<record id="lost_reason_1" model="crm.lost.reason">
<field name="name">Too expensive</field>
</record>
<record id="lost_reason_2" model="crm.lost.reason">
<field name="name">We don't have people/skills</field>
</record>
<record id="lost_reason_3" model="crm.lost.reason">
<field name="name">Not enough stock</field>
</record>
</data></odoo>

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo><data noupdate="1">
<record id="crm_recurring_plan_monthly" model="crm.recurring.plan">
<field name="name">Monthly</field>
<field name="number_of_months">1</field>
</record>
<record id="crm_recurring_plan_yearly" model="crm.recurring.plan">
<field name="name">Yearly</field>
<field name="number_of_months">12</field>
</record>
<record id="crm_recurring_plan_over_3_years" model="crm.recurring.plan">
<field name="name">Over 3 years</field>
<field name="number_of_months">36</field>
</record>
<record id="crm_recurring_plan_over_5_years" model="crm.recurring.plan">
<field name="name">Over 5 years </field>
<field name="number_of_months">60</field>
</record>
</data></odoo>

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo noupdate="1">
<record model="crm.stage" id="stage_lead1">
<field name="name">New</field>
<field name="sequence">1</field>
</record>
<record model="crm.stage" id="stage_lead2">
<field name="name">Qualified</field>
<field name="sequence">2</field>
</record>
<record model="crm.stage" id="stage_lead3">
<field name="name">Proposition</field>
<field name="sequence">3</field>
</record>
<record model="crm.stage" id="stage_lead4">
<field name="name">Won</field>
<field name="fold" eval="False"/>
<field name="is_won">True</field>
<field name="sequence">70</field>
</record>
</odoo>

View file

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo><data noupdate="1">
<record id="sales_team.team_sales_department" model="crm.team" forcecreate="False">
<field name="alias_name">info</field>
<field name="alias_user_id" ref="base.user_admin"/>
</record>
<record id="sales_team.salesteam_website_sales" model="crm.team" forcecreate="False">
<field name="use_opportunities" eval="False"/>
</record>
<record id="sales_team.pos_sales_team" model="crm.team" forcecreate="False">
<field name="use_opportunities" eval="False"/>
</record>
<record id="sales_team.ebay_sales_team" model="crm.team" forcecreate="False">
<field name="use_opportunities" eval="False"/>
</record>
</data></odoo>

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="sales_team.team_sales_department" model="crm.team" forcecreate="False">
<field name="assignment_domain">[['probability', '>=', '20']]</field>
</record>
<record id="sales_team.crm_team_1" model="crm.team">
<field name="use_leads">True</field>
<field name="assignment_domain">[['phone', '!=', False]]</field>
</record>
</data>
</odoo>

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo><data noupdate="1">
<record id="sales_team.crm_team_member_admin_sales" model="crm.team.member">
<field name="assignment_max">30</field>
<field name="assignment_domain">[['probability', '>=', 20]]</field>
</record>
<record id="sales_team.crm_team_member_demo_team_1" model="crm.team.member">
<field name="assignment_max">45</field>
<field name="assignment_domain">[['probability', '>=', 5]]</field>
</record>
</data></odoo>

View file

@ -0,0 +1,90 @@
<?xml version='1.0' encoding='utf-8'?>
<odoo>
<data noupdate="1">
<record id="digest.digest_digest_default" model="digest.digest">
<field name="kpi_crm_lead_created">True</field>
<field name="kpi_crm_opportunities_won">True</field>
</record>
</data>
<data>
<record id="digest_tip_crm_0" model="digest.tip">
<field name="name">Tip: Convert incoming emails into opportunities</field>
<field name="sequence">200</field>
<field name="group_id" ref="sales_team.group_sale_salesman_all_leads"/>
<field name="tip_description" type="html">
<div>
<t t-set="record" t-value="object.env['crm.team'].search([('alias_name', '!=', 'False')], limit=1)" />
<p class="tip_title">Tip: Convert incoming emails into opportunities</p>
<t t-if="record and record.alias_domain">
<p class="tip_content">Did you know emails sent to <t t-out="record.alias_id.display_name or ''"></t> generate opportunities in your pipeline?<br/>
<a t-attf-href="mailto:{{record.alias_id.display_name}}" target="_blank">Try sending an email</a> to your CRM. This email address is configurable by sales team members.</p>
</t>
<t t-else="">
<p class="tip_content">Did you know emails sent to a Sales Team alias generate opportunities in your pipeline?</p>
</t>
</div>
</field>
</record>
<record id="digest_tip_crm_1" model="digest.tip">
<field name="name">Tip: Did you know Odoo has built-in lead mining?</field>
<field name="sequence">1500</field>
<field name="group_id" ref="sales_team.group_sale_salesman_all_leads"/>
<field name="tip_description" type="html">
<div>
<p class="tip_title">Tip: Did you know Odoo has built-in lead mining?</p>
<p class="tip_content">For a sales team, there is nothing worse than being dry on leads. Fortunately, in just a few clicks, you can generate leads specifically targeted to your needs: company size, industry, etc. To help you test the feature, we offer you 200 credits for free.</p>
<img src="https://download.odoocdn.com/digests/crm/static/src/img/generate-leads.gif" class="illustration_border" />
</div>
</field>
</record>
<record id="digest_tip_crm_2" model="digest.tip">
<field name="name">Tip: Opportunity win rate is predicted with AI</field>
<field name="sequence">1700</field>
<field name="group_id" ref="sales_team.group_sale_salesman_all_leads"/>
<field name="tip_description" type="html">
<div>
<p class="tip_title">Tip: Opportunity win rate is predicted with AI</p>
<p class="tip_content">Odoo's artificial intelligence engine predicts the success rate of each opportunity based on your history. You can always update the success rate manually, but if you let Odoo do the job the score is updated while the opportunity moves forward in your sales cycle.</p>
<img src="https://download.odoocdn.com/digests/crm/static/src/img/probability-rate.gif" class="illustration_border" />
</div>
</field>
</record>
<record id="digest_tip_crm_3" model="digest.tip">
<field name="name">Tip: Manage your pipeline</field>
<field name="sequence">2600</field>
<field name="group_id" ref="sales_team.group_sale_salesman_all_leads"/>
<field name="tip_description" type="html">
<div>
<p class="tip_title">Tip: Manage your pipeline</p>
<p class="tip_content">A great tip to boost sales efficiency is to always define a next step on each opportunity. To manage ongoing activities, click on any status of the progress bar to filter opportunities based on their next activities' status. Click on the grey area of the progress bar to see all opportunities that have no next activity.</p>
<img src="https://download.odoocdn.com/digests/crm/static/src/img/pipeline-progress.gif" class="illustration_border" />
</div>
</field>
</record>
<record id="digest_tip_crm_4" model="digest.tip">
<field name="name">Tip: Do not waste time recording customers' data</field>
<field name="sequence">2800</field>
<field name="group_id" ref="sales_team.group_sale_salesman_all_leads"/>
<field name="tip_description" type="html">
<div>
<p class="tip_title">Tip: Do not waste time recording customers' data</p>
<p class="tip_content">Did you know you can search a company by name or VAT number to instantly fill in all its data? Odoo autocompletes everything for you: logo, address, company size, business information, social media accounts, etc.</p>
<img src="https://download.odoocdn.com/digests/crm/static/src/img/autofill.gif" class="illustration_border" />
</div>
</field>
</record>
<record id="digest_tip_crm_5" model="digest.tip">
<field name="name">Tip: Turn a selection of opportunities into a map</field>
<field name="sequence">3000</field>
<field name="group_id" ref="sales_team.group_sale_salesman_all_leads"/>
<field name="tip_description" type="html">
<div>
<p class="tip_title">Tip: Turn a selection of opportunities into a map</p>
<p class="tip_content">Did you know you can turn a list of opportunities into a map view, using the top-right map icon? A lot of screens in Odoo can be turned into a map: tasks, contacts, delivery orders, etc.</p>
<img src="https://download.odoocdn.com/digests/crm/static/src/img/mapview-toggle.gif" class="illustration_border" />
</div>
</field>
</record>
</data>
</odoo>

View file

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!--
'Mark as Lost' in action dropdown
-->
<record id="action_mark_as_lost" model="ir.actions.server">
<field name="name">Mark as lost</field>
<field name="model_id" ref="model_crm_lead"/>
<field name="binding_model_id" ref="crm.model_crm_lead"/>
<field name="binding_view_types">list</field>
<field name="state">code</field>
<field name="code">
if not 'opportunity' in records.mapped('type'):
records.action_set_lost()
elif records:
action_values = env.ref('crm.crm_lead_lost_action').sudo().read()[0]
action_values.update({'context': env.context})
action = action_values
</field>
</record>
<record id="action_your_pipeline" model="ir.actions.server">
<field name="name">Crm: My Pipeline</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_your_pipeline()</field>
</record>
<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>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo><data noupdate="1">
<record forcecreate="True" id="ir_cron_crm_lead_assign" model="ir.cron">
<field name="name">CRM: Lead Assignment</field>
<field name="model_id" ref="crm.model_crm_team"/>
<field name="state">code</field>
<field name="code">model._cron_assign_leads()</field>
<field name="active" eval="False"/>
<field name="user_id" ref="base.user_root"/>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field name="doall" eval="False"/>
</record>
</data></odoo>

View file

@ -0,0 +1,30 @@
<?xml version="1.0"?>
<odoo>
<record id="mail_activity_demo_followup_quote" model="mail.activity.type">
<field name="name">Follow-up Quote</field>
<field name="icon">fa-file-text-o</field>
<field name="res_model">crm.lead</field>
<field name="delay_count">30</field>
</record>
<record id="mail_activity_demo_make_quote" model="mail.activity.type">
<field name="name">Make Quote</field>
<field name="icon">fa-file-text-o</field>
<field name="res_model">crm.lead</field>
<field name="delay_count">15</field>
</record>
<record id="mail_activity_demo_call_demo" model="mail.activity.type">
<field name="name">Call for Demo</field>
<field name="icon">fa-phone</field>
<field name="res_model">crm.lead</field>
<field name="delay_count">10</field>
<field name="category">phonecall</field>
</record>
<record id="mail_activity_type_demo_email_with_template" model="mail.activity.type">
<field name="name">Email: Welcome Demo</field>
<field name="icon">fa-envelope</field>
<field name="res_model">crm.lead</field>
<field name="mail_template_ids" eval="[(4, ref('crm.mail_template_demo_crm_lead'))]"/>
</record>
</odoo>

View file

@ -0,0 +1,76 @@
<?xml version="1.0"?>
<odoo>
<data noupdate="1">
<!-- CRM-related subtypes for messaging / Chatter -->
<record id="mt_lead_create" model="mail.message.subtype">
<field name="name">Opportunity Created</field>
<field name="hidden" eval="True"/>
<field name="res_model">crm.lead</field>
<field name="default" eval="False"/>
<field name="description">Lead/Opportunity created</field>
</record>
<record id="mt_lead_stage" model="mail.message.subtype">
<field name="name">Stage Changed</field>
<field name="res_model">crm.lead</field>
<field name="default" eval="False"/>
<field name="description">Stage changed</field>
</record>
<record id="mt_lead_won" model="mail.message.subtype">
<field name="name">Opportunity Won</field>
<field name="res_model">crm.lead</field>
<field name="default" eval="False"/>
<field name="description">Opportunity won</field>
</record>
<record id="mt_lead_lost" model="mail.message.subtype">
<field name="name">Opportunity Lost</field>
<field name="res_model">crm.lead</field>
<field name="default" eval="False"/>
<field name="description">Opportunity lost</field>
</record>
<record id="mt_lead_restored" model="mail.message.subtype">
<field name="name">Opportunity Restored</field>
<field name="res_model">crm.lead</field>
<field name="default" eval="False"/>
<field name="description">Opportunity restored</field>
</record>
<!-- Salesteam-related subtypes for messaging / Chatter -->
<record id="mt_salesteam_lead" model="mail.message.subtype">
<field name="name">Opportunity Created</field>
<field name="sequence">10</field>
<field name="res_model">crm.team</field>
<field name="default" eval="True"/>
<field name="parent_id" ref="mt_lead_create"/>
<field name="relation_field">team_id</field>
</record>
<record id="mt_salesteam_lead_stage" model="mail.message.subtype">
<field name="name">Opportunity Stage Changed</field>
<field name="sequence">11</field>
<field name="res_model">crm.team</field>
<field name="parent_id" ref="mt_lead_stage"/>
<field name="relation_field">team_id</field>
</record>
<record id="mt_salesteam_lead_won" model="mail.message.subtype">
<field name="name">Opportunity Won</field>
<field name="sequence">12</field>
<field name="res_model">crm.team</field>
<field name="parent_id" ref="mt_lead_won"/>
<field name="relation_field">team_id</field>
</record>
<record id="mt_salesteam_lead_lost" model="mail.message.subtype">
<field name="name">Opportunity Lost</field>
<field name="sequence">13</field>
<field name="res_model">crm.team</field>
<field name="default" eval="False"/>
<field name="parent_id" ref="mt_lead_lost"/>
<field name="relation_field">team_id</field>
</record>
<record id="mt_salesteam_lead_restored" model="mail.message.subtype">
<field name="name">Opportunity Restored</field>
<field name="sequence">14</field>
<field name="res_model">crm.team</field>
<field name="default" eval="False"/>
<field name="parent_id" ref="mt_lead_restored"/>
<field name="relation_field">team_id</field>
</record>
</data>
</odoo>

View file

@ -0,0 +1,84 @@
<?xml version="1.0"?>
<odoo><data noupdate="1">
<record id="mail_template_demo_crm_lead" model="mail.template">
<field name="name">Welcome Demo</field>
<field name="model_id" ref="crm.model_crm_lead"/>
<field name="partner_to">{{ object.partner_id != False and object.partner_id.id }}</field>
<field name="email_to">{{ (not object.partner_id and object.email_from) }}</field>
<field name="body_html" type="html">
<table border="0" cellpadding="0" cellspacing="0" style="padding-top: 16px; background-color: #F1F1F1; font-family:Verdana, Arial,sans-serif; color: #454748; width: 100%; border-collapse:separate;"><tr><td align="center">
<table border="0" cellpadding="0" cellspacing="0" width="590" style="padding: 24px; background-color: white; color: #454748; border-collapse:separate;">
<tbody>
<!-- HEADER -->
<tr>
<td align="center" style="min-width: 590px;">
<table border="0" cellpadding="0" cellspacing="0" width="100%" style="background-color: white; padding: 0; border-collapse:separate;">
<tr><td valign="middle">
<span style="font-size: 10px;">Your Lead/Opportunity</span><br/>
<span style="font-size: 20px; font-weight: bold;" t-out="object.name or ''">Interest in your products</span>
</td><td valign="middle" align="right">
<img t-attf-src="/logo.png?company={{ object.company_id.id }}" style="padding: 0px; margin: 0px; height: 48px;" t-att-alt="object.company_id.name"/>
</td></tr>
<tr><td colspan="2" style="text-align:center;">
<hr width="100%" style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin:4px 0px 32px 0px;"/>
</td></tr>
</table>
</td>
</tr>
<!-- CONTENT -->
<tr>
<td style="min-width: 590px;">
<table border="0" cellpadding="0" cellspacing="0" width="590" style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;">
<tr>
<td valign="top" style="font-size: 13px;">
<div>
Hi <t t-out="object.partner_id and object.partner_id.name or ''">Deco Addict</t>,<br/><br/>
Welcome to <t t-out="object.company_id.name or ''">My Company (San Francisco)</t>.
It's great to meet you! Now that you're on board, you'll discover what <t t-out="object.company_id.name or ''">My Company (San Francisco)</t> has to offer. My name is <t t-out="object.user_id.name or ''">Marc Demo</t> and I'll help you get the most out of Odoo. Could we plan a quick demo soon?<br/>
Feel free to reach out at any time!<br/><br/>
Best,<br/>
<t t-if="object.user_id">
<b><t t-out="object.user_id.name or ''">Marc Demo</t></b>
<br/>Email: <t t-out="object.user_id.email or ''">mark.brown23@example.com</t>
<br/>Phone: <t t-out="object.user_id.phone or ''">+1 650-123-4567</t>
</t>
<t t-else="">
<t t-out="object.company_id.name or ''">My Company (San Francisco)</t>
</t>
</div>
</td>
</tr>
</table>
</td>
</tr>
<!-- FOOTER -->
<tr>
<td align="center" style="min-width: 590px; padding: 0 8px 0 8px; font-size:11px;">
<hr width="100%" style="background-color:rgb(204,204,204);border:medium none;clear:both;display:block;font-size:0px;min-height:1px;line-height:0; margin: 16px 0px 4px 0px;"/>
<b t-out="object.company_id.name or ''">My Company (San Francisco)</b><br/>
<div style="color: #999999;">
<t t-out="object.company_id.phone or ''">+1 650-123-4567</t>
<t t-if="object.company_id.email">
| <a t-attf-href="'mailto:%s' % {{ object.company_id.email }}" style="text-decoration:none; color: #999999;" t-out="object.company_id.email or ''">info@yourcompany.com</a>
</t>
<t t-if="object.company_id.website">
| <a t-attf-href="'%s' % {{ object.company_id.website }}" style="text-decoration:none; color: #999999;" t-out="object.company_id.website or ''">http://www.example.com</a>
</t>
</div>
</td>
</tr>
</tbody>
</table>
</td></tr>
<!-- POWERED BY -->
<tr><td align="center" style="min-width: 590px;">
Powered by <a target="_blank" href="https://www.odoo.com?utm_source=db&amp;utm_medium=email" style="color: #875A7B;">Odoo</a>
</td></tr>
</table>
</field>
<field name="lang">{{ object.partner_id.lang }}</field>
<field name="auto_delete" eval="True"/>
</record>
</data></odoo>

View file

@ -0,0 +1,17 @@
.. _changelog:
Changelog
=========
`trunk (saas-2)`
----------------
- Stage/state update
- ``crm.lead``: removed ``state`` field. Added ``date_last_stage_update`` field
holding last stage_id modification. Updated reports.
- ``crm.case.stage``: removed ``state`` field.
- ``crm``, ``crm_claim``: removed inheritance from ``base_stage`` class. Missing
methods have been added into ``crm`` and ``crm_claim``. Also removed inheritance
in ``crm_helpdesk`` because it uses states, not stages.

View file

@ -0,0 +1,18 @@
CRM module documentation
========================
CRM documentation topics
'''''''''''''''''''''''''
.. toctree::
:maxdepth: 1
stage_status.rst
Changelog
'''''''''
.. toctree::
:maxdepth: 1
changelog.rst

View file

@ -0,0 +1,61 @@
.. _stage_status:
Stage and Status
================
.. versionchanged:: 8.0 saas-2 state/stage cleaning
Stage
+++++
This revision removed the concept of state on crm.lead objects. The ``state``
field has been totally removed and replaced by stages, using ``stage_id``. The
following models are impacted:
- ``crm.lead`` now use only stages. However conventions still exist about
'New', 'Won' and 'Lost' stages. Those conventions are:
- ``new``: ``stage_id and stage_id.sequence = 1``
- ``won``: ``stage_id and stage_id.probability = 100 and stage_id.on_change = True``
- ``lost``: ``stage_id and stage_id.probability = 0 and stage_id.on_change = True
and stage_id.sequence != 1``
- ``crm.case.stage`` do not have any ``state`` field anymore.
- ``crm.lead.report`` do not have any ``state`` field anymore.
By default a newly created lead is in a new stage. It means that it will
fetch the stage having ``sequence = 1``. Stage mangement is done using the
kanban view or the clikable statusbar. It is not done using buttons anymore.
Stage analysis
++++++++++++++
Stage analysis can be performed using the newly introduced ``date_last_stage_update``
datetime field. This field is updated everytime ``stage_id`` is updated.
``crm.lead.report`` model also uses the ``date_last_stage_update`` field.
This allows to group and analyse the time spend in the various stages.
Open / Assignment date
+++++++++++++++++++++++
The ``date_open`` field meaning has been updated. It is now set when the ``user_id``
(responsible) is set. It is therefore the assignment date.
Subtypes
++++++++
The following subtypes are triggered on ``crm.lead``:
- ``mt_lead_create``: new leads. Condition: ``obj.probability == 0 and obj.stage_id
and obj.stage_id.sequence == 1``
- ``mt_lead_stage``: stage changed. Condition: ``(obj.stage_id and obj.stage_id.sequence != 1)
and obj.probability < 100``
- ``mt_lead_won``: lead/oportunity is won. condition: `` obj.probability == 100
and obj.stage_id and obj.stage_id.on_change``
- ``mt_lead_lost``: lead/opportunity is lost. Condition: ``obj.probability == 0
and obj.stage_id and obj.stage_id.sequence != 1'``
Those subtypes are also available on the ``crm.case.section`` model and are used
for the auto subscription.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more