From 7c9afe52aa685bda5c08973399d2282cd422630c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Gil=20Sorribes?= Date: Wed, 28 Nov 2018 09:34:31 +0100 Subject: [PATCH 01/32] [12.0][ADD] Add new module crm_lead_product add filter for open opportunities in pipeline by product report [IMP] Extend test coverage --- crm_lead_product/README.rst | 96 ++++ crm_lead_product/__init__.py | 4 + crm_lead_product/__manifest__.py | 22 + crm_lead_product/models/__init__.py | 4 + crm_lead_product/models/crm_lead.py | 35 ++ crm_lead_product/models/crm_lead_line.py | 138 ++++++ crm_lead_product/readme/CONFIGURE.rst | 2 + crm_lead_product/readme/CONTRIBUTORS.rst | 2 + crm_lead_product/readme/DESCRIPTION.rst | 9 + crm_lead_product/readme/USAGE.rst | 4 + crm_lead_product/report/__init__.py | 3 + crm_lead_product/report/crm_product_report.py | 102 +++++ .../report/crm_product_report_views.xml | 130 ++++++ crm_lead_product/security/ir.model.access.csv | 3 + crm_lead_product/static/description/icon.png | Bin 0 -> 9455 bytes .../static/description/index.html | 417 ++++++++++++++++++ crm_lead_product/tests/__init__.py | 3 + crm_lead_product/tests/test_crm_lead_line.py | 137 ++++++ .../views/crm_lead_line_views.xml | 20 + crm_lead_product/views/crm_lead_views.xml | 30 ++ 20 files changed, 1161 insertions(+) create mode 100644 crm_lead_product/README.rst create mode 100644 crm_lead_product/__init__.py create mode 100644 crm_lead_product/__manifest__.py create mode 100644 crm_lead_product/models/__init__.py create mode 100644 crm_lead_product/models/crm_lead.py create mode 100644 crm_lead_product/models/crm_lead_line.py create mode 100644 crm_lead_product/readme/CONFIGURE.rst create mode 100644 crm_lead_product/readme/CONTRIBUTORS.rst create mode 100644 crm_lead_product/readme/DESCRIPTION.rst create mode 100644 crm_lead_product/readme/USAGE.rst create mode 100644 crm_lead_product/report/__init__.py create mode 100644 crm_lead_product/report/crm_product_report.py create mode 100644 crm_lead_product/report/crm_product_report_views.xml create mode 100644 crm_lead_product/security/ir.model.access.csv create mode 100644 crm_lead_product/static/description/icon.png create mode 100644 crm_lead_product/static/description/index.html create mode 100644 crm_lead_product/tests/__init__.py create mode 100644 crm_lead_product/tests/test_crm_lead_line.py create mode 100644 crm_lead_product/views/crm_lead_line_views.xml create mode 100644 crm_lead_product/views/crm_lead_views.xml diff --git a/crm_lead_product/README.rst b/crm_lead_product/README.rst new file mode 100644 index 00000000000..fa84831de20 --- /dev/null +++ b/crm_lead_product/README.rst @@ -0,0 +1,96 @@ +================= +Lead Line Product +================= + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fcrm-lightgray.png?logo=github + :target: https://github.com/OCA/crm/tree/12.0/crm_lead_product + :alt: OCA/crm +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/crm-12-0/crm-12-0-crm_lead_product + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/111/12.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + + +This module allows the user to link multiple products, product categories or product templates to a lead or an opportunity +in order to be able to do a product demand forecasting taking into account the leads and opportunities defined in odoo. +Included in the product line there are two computed fields, the planned revenue and expected revenue. On one hand, the +planned revenue is computed as the selling price times the quantity. On the other hand, the expected revenue takes into account +the probability of the opportunity and is computed as the planned revenue times the probability. + +The module also includes a reporting section where the user can easily see in a pivot and graph view the relationship +between products, stage of the lead/opportunity and the planned or expected revenue for that product. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + + +To configure this module to be available for the Leads the user needs to activate the Leads option in CRM settings + +Usage +===== + + +* Go to menu **CRM > Lead** and create or edit a Lead adding all the products associated to it. +* Go to menu **CRM > My Pipeline** and create or edit an Opportunity adding all the products associated to it. +* Go to menu **CRM > Reporting > Pipeline by Product** to run the report that relates product to planned and expected revenue per stage + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Eficent + +Contributors +~~~~~~~~~~~~ + + +* Adria Gil Sorribes + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/crm `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/crm_lead_product/__init__.py b/crm_lead_product/__init__.py new file mode 100644 index 00000000000..47808b3977d --- /dev/null +++ b/crm_lead_product/__init__.py @@ -0,0 +1,4 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import models +from . import report \ No newline at end of file diff --git a/crm_lead_product/__manifest__.py b/crm_lead_product/__manifest__.py new file mode 100644 index 00000000000..d6b693ec0d7 --- /dev/null +++ b/crm_lead_product/__manifest__.py @@ -0,0 +1,22 @@ +# Copyright (C) 2017 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +{ + 'name': 'Lead Line Product', + 'version': '12.0.1.0.0', + 'category': 'Customer Relationship Management', + 'license': 'LGPL-3', + 'summary': 'Adds a lead line in the lead/opportunity model ' + 'in odoo', + 'author': "Eficent, Odoo Community Association (OCA)", + 'website': 'http://www.github.com/OCA/crm', + 'depends': ['crm', 'product'], + 'data': [ + 'security/ir.model.access.csv', + 'views/crm_lead_views.xml', + 'views/crm_lead_line_views.xml', + 'report/crm_product_report_views.xml', + ], + 'installable': True, + 'auto_install': False, +} diff --git a/crm_lead_product/models/__init__.py b/crm_lead_product/models/__init__.py new file mode 100644 index 00000000000..edd13ec2c94 --- /dev/null +++ b/crm_lead_product/models/__init__.py @@ -0,0 +1,4 @@ +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from . import crm_lead_line +from . import crm_lead diff --git a/crm_lead_product/models/crm_lead.py b/crm_lead_product/models/crm_lead.py new file mode 100644 index 00000000000..5032997f20e --- /dev/null +++ b/crm_lead_product/models/crm_lead.py @@ -0,0 +1,35 @@ +# Copyright (C) 2018 Eficent Business and IT Consulting Services S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class CrmLead(models.Model): + _inherit = 'crm.lead' + + lead_line_ids = fields.One2many( + comodel_name='crm.lead.line', + inverse_name='lead_id', + string='Lead Lines', + ) + + @api.onchange('lead_line_ids') + def _onchange_lead_line_ids(self): + planned_revenue = 0 + for lead_line in self.lead_line_ids: + if lead_line.planned_revenue != 0: + planned_revenue += lead_line.planned_revenue + self.planned_revenue = planned_revenue + + @api.multi + def _convert_opportunity_data(self, customer, team_id=False): + res = super(CrmLead, self)._convert_opportunity_data(customer, team_id) + + # Update planned_revenue + planned_revenue = 0 + for lead_line in self.lead_line_ids: + planned_revenue += lead_line.planned_revenue + + res['planned_revenue'] = planned_revenue + + return res diff --git a/crm_lead_product/models/crm_lead_line.py b/crm_lead_product/models/crm_lead_line.py new file mode 100644 index 00000000000..e7254299fa7 --- /dev/null +++ b/crm_lead_product/models/crm_lead_line.py @@ -0,0 +1,138 @@ +# Copyright (C) 2018 Eficent Business and IT Consulting Services S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class CrmLeadLine(models.Model): + _name = "crm.lead.line" + _description = "Line in CRM Lead" + + @api.multi + @api.depends('price_unit', 'product_qty') + def _compute_planned_revenue(self): + for rec in self: + rec.planned_revenue = rec.product_qty * rec.price_unit + + @api.multi + @api.depends('lead_id.probability', 'planned_revenue') + def _compute_expected_revenue(self): + for rec in self: + if rec.lead_id and rec.lead_id.type != 'lead': + rec.expected_revenue = \ + rec.planned_revenue * rec.lead_id.probability * (1/100) + + lead_id = fields.Many2one( + 'crm.lead', + string='Lead') + name = fields.Char('Description', required=True, translate=True) + product_id = fields.Many2one("product.product", + string="Product", + index=True) + category_id = fields.Many2one('product.category', + string='Product Category', + index=True) + product_tmpl_id = fields.Many2one('product.template', + string='Product Template', + index=True) + product_qty = fields.Integer(string='Product Quantity', + default=1, + required=True) + uom_id = fields.Many2one('uom.uom', + string='Unit of Measure', + readonly=True) + price_unit = fields.Float(string='Price Unit') + planned_revenue = fields.Float(compute='_compute_planned_revenue', + string='Planned revenue', + compute_sudo=True, + store=True) + expected_revenue = fields.Float(compute='_compute_expected_revenue', + string='Expected revenue', + compute_sudo=True, + store=True) + + @api.onchange('product_id') + def _onchange_product_id(self): + domain = {} + if not self.lead_id: + return + + if not self.product_id: + self.price_unit = 0.0 + domain['uom_id'] = [] + if self.name and self.name != self.category_id.name: + self.name = "" + else: + product = self.product_id + self.category_id = product.categ_id.id + self.product_tmpl_id = product.product_tmpl_id.id + self.price_unit = product.list_price + + if product.name: + self.name = product.name + + if not self.uom_id or product.uom_id.category_id.id != \ + self.uom_id.category_id.id: + self.uom_id = product.uom_id.id + domain['uom_id'] = [( + 'category_id', '=', product.uom_id.category_id.id)] + + if self.uom_id and self.uom_id.id != product.uom_id.id: + self.price_unit = product.uom_id._compute_price( + self.price_unit, self.uom_id) + + return {'domain': domain} + + @api.onchange('category_id') + def _onchange_category_id(self): + domain = {} + if not self.lead_id: + return + if self.category_id: + categ_id = self.category_id + if categ_id.name and not self.name: + self.name = categ_id.name + + # Check if there are already defined product and product template + # and remove them if categories do not match + if self.product_id and self.product_id.categ_id != categ_id: + self.product_id = None + self.name = categ_id.name + if self.product_tmpl_id and \ + self.product_tmpl_id.categ_id != categ_id: + self.product_tmpl_id = None + + return {'domain': domain} + + @api.onchange('product_tmpl_id') + def _onchange_product_tmpl_id(self): + domain = {} + if not self.lead_id: + return + if self.product_tmpl_id: + product_tmpl = self.product_tmpl_id + if product_tmpl.name and not self.name: + self.name = product_tmpl.name + self.category_id = product_tmpl.categ_id + + if self.product_id: + # Check if there are already defined product and remove + # if it does not match + if self.product_id.product_tmpl_id != product_tmpl: + self.product_id = None + self.name = product_tmpl.name + + return {'domain': domain} + + @api.onchange('uom_id') + def _onchange_uom_id(self): + result = {} + if not self.uom_id: + self.price_unit = 0.0 + + if self.product_id and self.uom_id: + price_unit = self.product_id.list_price + self.price_unit = self.product_id.uom_id._compute_price( + price_unit, self.uom_id) + + return result diff --git a/crm_lead_product/readme/CONFIGURE.rst b/crm_lead_product/readme/CONFIGURE.rst new file mode 100644 index 00000000000..f62459d620f --- /dev/null +++ b/crm_lead_product/readme/CONFIGURE.rst @@ -0,0 +1,2 @@ + +To configure this module to be available for the Leads the user needs to activate the Leads option in CRM settings diff --git a/crm_lead_product/readme/CONTRIBUTORS.rst b/crm_lead_product/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000000..67acbc4c446 --- /dev/null +++ b/crm_lead_product/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ + +* Adria Gil Sorribes diff --git a/crm_lead_product/readme/DESCRIPTION.rst b/crm_lead_product/readme/DESCRIPTION.rst new file mode 100644 index 00000000000..f249dfb756a --- /dev/null +++ b/crm_lead_product/readme/DESCRIPTION.rst @@ -0,0 +1,9 @@ + +This module allows the user to link multiple products, product categories or product templates to a lead or an opportunity +in order to be able to do a product demand forecasting taking into account the leads and opportunities defined in odoo. +Included in the product line there are two computed fields, the planned revenue and expected revenue. On one hand, the +planned revenue is computed as the selling price times the quantity. On the other hand, the expected revenue takes into account +the probability of the opportunity and is computed as the planned revenue times the probability. + +The module also includes a reporting section where the user can easily see in a pivot and graph view the relationship +between products, stage of the lead/opportunity and the planned or expected revenue for that product. diff --git a/crm_lead_product/readme/USAGE.rst b/crm_lead_product/readme/USAGE.rst new file mode 100644 index 00000000000..3a3ada4eb18 --- /dev/null +++ b/crm_lead_product/readme/USAGE.rst @@ -0,0 +1,4 @@ + +* Go to menu **CRM > Lead** and create or edit a Lead adding all the products associated to it. +* Go to menu **CRM > My Pipeline** and create or edit an Opportunity adding all the products associated to it. +* Go to menu **CRM > Reporting > Pipeline by Product** to run the report that relates product to planned and expected revenue per stage diff --git a/crm_lead_product/report/__init__.py b/crm_lead_product/report/__init__.py new file mode 100644 index 00000000000..c5ef7615c19 --- /dev/null +++ b/crm_lead_product/report/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import crm_product_report \ No newline at end of file diff --git a/crm_lead_product/report/crm_product_report.py b/crm_lead_product/report/crm_product_report.py new file mode 100644 index 00000000000..d46e0e5293e --- /dev/null +++ b/crm_lead_product/report/crm_product_report.py @@ -0,0 +1,102 @@ +# Copyright (C) 2017 Eficent Business and IT Consulting Services S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from psycopg2.extensions import AsIs + +from odoo import fields, models, tools, api + + +class ActivityReport(models.Model): + """ CRM Lead Analysis """ + + _name = "crm.product.report" + _auto = False + _description = "CRM Pipeline by Product Analysis" + _rec_name = 'id' + + active = fields.Boolean('Active', readonly=True) + campaign_id = fields.Many2one('utm.campaign', 'Campaing', readonly=True) + country_id = fields.Many2one('res.country', 'Country', readonly=True) + company_id = fields.Many2one('res.company', 'Company', readonly=True) + create_date = fields.Datetime('Create Date', readonly=True) + date_closed = fields.Datetime('Closed Date', readonly=True) + date_conversion = fields.Datetime('Conversion Date', readonly=True) + date_deadline = fields.Datetime('Deadline Date', readonly=True) + date_open = fields.Datetime('Open Date', readonly=True) + lost_reason = fields.Many2one('crm.lost.reason', 'Lost Reason', + readonly=True) + name = fields.Char('Lead Name', readonly=True) + partner_id = fields.Many2one('res.partner', 'Partner/Customer', + readonly=True) + partner_name = fields.Char('Contact Name', readonly=True) + probability = fields.Float('Probability', group_operator='avg', + readonly=True) + stage_id = fields.Many2one('crm.stage', 'Stage', readonly=True) + team_id = fields.Many2one('crm.team', 'Sales Team', readonly=True) + type = fields.Char( + string='Type', + selection=[('lead', 'Lead'), ('opportunity', 'Opportunity')], + help="Type is used to separate Leads and Opportunities") + user_id = fields.Many2one('res.users', 'Salesperson', readonly=True) + category_id = fields.Many2one('product.category', 'Category', + readonly=True) + expected_revenue = fields.Float('Expected Revenue', readonly=True) + planned_revenue = fields.Float('Planned Revenue', readonly=True) + product_id = fields.Many2one('product.product', 'Product', readonly=True) + product_qty = fields.Integer('Product Quantity', readonly=True) + product_tmpl_id = fields.Many2one('product.template', 'Product Template', + readonly=True) + + def _select(self): + return """ + SELECT + l.id, + l.active, + l.id as lead_id, + l.campaign_id, + l.country_id, + l.company_id, + l.create_date, + l.date_closed, + l.date_conversion, + l.date_deadline, + l.date_open, + l.lost_reason, + l.name, + l.partner_id, + l.partner_name, + l.probability, + l.type, + l.stage_id, + l.team_id, + l.user_id, + ll.category_id, + ll.expected_revenue, + ll.planned_revenue, + ll.product_id, + ll.product_qty, + ll.product_tmpl_id + """ + + def _from(self): + return """ + FROM crm_lead AS l + """ + + def _join(self): + return """ + JOIN crm_lead_line AS ll ON l.id = ll.lead_id + """ + + @api.model_cr + def init(self): + tools.drop_view_if_exists(self._cr, self._table) + self._cr.execute(""" + CREATE OR REPLACE VIEW %s AS ( + %s + %s + %s + ) + """, (AsIs(self._table), AsIs(self._select()), + AsIs(self._from()), AsIs(self._join())) + ) diff --git a/crm_lead_product/report/crm_product_report_views.xml b/crm_lead_product/report/crm_product_report_views.xml new file mode 100644 index 00000000000..f3b44e293ae --- /dev/null +++ b/crm_lead_product/report/crm_product_report_views.xml @@ -0,0 +1,130 @@ + + + + + + crm.opportunity.report.pivot + crm.product.report + 60 + + + + + + + + + + + + crm.opportunity.report.graph + crm.product.report + + + + + + + + + + + + crm.opportunity.report.list + crm.product.report + + + + + + + + + + + + + + + + + + + + crm.lead.search + crm.product.report + 32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Pipeline by Product Analysis + crm.product.report + form + pivot,graph,tree,form + + {'search_default_opportunity': True, 'search_default_current': True} + + Pipeline Analysis gives you an instant access to +your opportunities with information such as the expected revenue, planned cost, +missed deadlines or the number of interactions per opportunity. This report is +mainly used by the sales manager in order to do the periodic review with the +teams of the sales pipeline. + + + + + diff --git a/crm_lead_product/security/ir.model.access.csv b/crm_lead_product/security/ir.model.access.csv new file mode 100644 index 00000000000..66361e6f149 --- /dev/null +++ b/crm_lead_product/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_crm_lead_line_group_user,crm.lead.line,model_crm_lead_line,base.group_user,1,1,1,1 +access_crm_product_report_user,crm.product.report.user,model_crm_product_report,base.group_user,1,0,0,0 diff --git a/crm_lead_product/static/description/icon.png b/crm_lead_product/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/crm_lead_product/static/description/index.html b/crm_lead_product/static/description/index.html new file mode 100644 index 00000000000..29cf2b3f5a8 --- /dev/null +++ b/crm_lead_product/static/description/index.html @@ -0,0 +1,417 @@ + + + + + + +Lead Line Product + + + +
+

Lead Line Product

+ + +

Beta License: LGPL-3 OCA/crm Translate me on Weblate Try me on Runbot

+

This module allows the user to link multiple products, product categories or product templates to a lead or an opportunity +in order to be able to do a product demand forecasting taking into account the leads and opportunities defined in odoo. +Included in the product line there are two computed fields, the planned revenue and expected revenue. On one hand, the +planned revenue is computed as the selling price times the quantity. On the other hand, the expected revenue takes into account +the probability of the opportunity and is computed as the planned revenue times the probability.

+

The module also includes a reporting section where the user can easily see in a pivot and graph view the relationship +between products, stage of the lead/opportunity and the planned or expected revenue for that product.

+

Table of contents

+ +
+

Configuration

+

To configure this module to be available for the Leads the user needs to activate the Leads option in CRM settings

+
+
+

Usage

+
    +
  • Go to menu CRM > Lead and create or edit a Lead adding all the products associated to it.
  • +
  • Go to menu CRM > My Pipeline and create or edit an Opportunity adding all the products associated to it.
  • +
  • Go to menu CRM > Reporting > Pipeline by Product to run the report that relates product to planned and expected revenue per stage
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Eficent
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/crm project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/crm_lead_product/tests/__init__.py b/crm_lead_product/tests/__init__.py new file mode 100644 index 00000000000..5067521c431 --- /dev/null +++ b/crm_lead_product/tests/__init__.py @@ -0,0 +1,3 @@ +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +from . import test_crm_lead_line diff --git a/crm_lead_product/tests/test_crm_lead_line.py b/crm_lead_product/tests/test_crm_lead_line.py new file mode 100644 index 00000000000..946b30d4567 --- /dev/null +++ b/crm_lead_product/tests/test_crm_lead_line.py @@ -0,0 +1,137 @@ +# © 2017-TODAY Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) + +from odoo.tests import common + + +class TestCrmLeadLine(common.TransactionCase): + + def setUp(self): + super(TestCrmLeadLine, self).setUp() + self.product_obj = self.env['product.product'] + self.lead_line_obj = self.env['crm.lead.line'] + self.lead = self.env['crm.lead'].create({ + 'type': "lead", + 'name': "Test lead new", + 'partner_id': self.env.ref("base.res_partner_1").id, + 'description': "This is the description of the test new lead.", + 'team_id': self.env.ref("sales_team.team_sales_department").id + }) + + # Products + self.product_1 = self.product_obj.create({ + 'name': 'Product 1', + 'categ_id': self.env.ref('product.product_category_1').id, + 'price': 142.0, + }) + self.product_2 = self.product_obj.create({ + 'name': 'Product 2', + 'categ_id': self.env.ref('product.product_category_2').id, + 'price': 1420.0, + }) + self.product_3 = self.product_obj.create({ + 'name': 'Product 3', + 'categ_id': self.env.ref('product.product_category_3').id, + 'price': 14200.0, + }) + self.product_4 = self.env.ref('product.product_product_25') + + def test_01_lead_lines(self): + """Tests for Crm Lead Line""" + + # Create new lead line with product id + self.lead_line_1 = self.lead_line_obj.create({ + 'lead_id': self.lead.id, + 'name': self.product_1.name, + 'product_id': self.product_1.id, + 'uom.id': self.product_1.uom_id.id, + 'price_unit': self.product_1.price, + }) + # Create new lead line with category id + self.lead_line_2 = self.lead_line_obj.create({ + 'lead_id': self.lead.id, + 'name': self.product_2.categ_id.name, + 'category_id': self.product_2.categ_id.id, + }) + # Create new lead line with product template + self.lead_line_3 = self.lead_line_obj.create({ + 'lead_id': self.lead.id, + 'name': self.product_3.product_tmpl_id.name, + 'product_tmpl_id': self.product_3.product_tmpl_id.id, + }) + + self.lead_line_1._onchange_product_id() + self.lead_line_2._onchange_category_id() + self.lead_line_2._onchange_uom_id() + self.lead_line_3._onchange_product_tmpl_id() + self.lead_line_3._onchange_product_id() + + # Check values have been introduced correctly + self.assertEqual(self.lead_line_1.category_id, + self.product_1.categ_id, + "Lead line category should be equal to product 1" + "category") + self.assertEqual(self.lead_line_1.product_tmpl_id, + self.product_1.product_tmpl_id, + "Lead line product template should be equal to " + "product 1 template") + self.assertEqual(self.lead_line_3.category_id, + self.product_3.categ_id, + "Lead line category should be equal to product 3" + "category") + + lead_line_4 = self.lead_line_obj.create({ + 'lead_id': self.lead.id, + 'name': self.product_1.name, + 'product_id': self.product_1.id, + }) + lead_line_4._onchange_product_id() + + # Change category and check that product and template are now None + lead_line_4.write({ + 'category_id': self.product_2.categ_id.id, + }) + lead_line_4._onchange_category_id() + self.assertNotEqual(lead_line_4.product_id, self.product_1, + "Lead line product should be equal to None") + self.assertNotEqual(lead_line_4.product_tmpl_id, + self.product_1.product_tmpl_id, + "Lead line product template should be equal " + "to None") + + def test_02_lead_to_opportunity(self): + # Write one lead line to CRM Lead + self.lead.write({ + 'lead_line_ids': [(0, 0, { + 'lead_id': self.lead.id, + 'name': self.product_4.name, + 'product_id': self.product_4.id, + 'category_id': self.product_4.categ_id.id, + 'price_unit': self.product_4.list_price, + })] + }) + self.lead._onchange_lead_line_ids() + + # Check if planned revenue is correctly set for lead line 1 + self.assertEqual(self.lead.lead_line_ids[0].planned_revenue, + self.product_4.list_price, + "Planned revenue should be equal " + "to the product standard price") + + self.lead.convert_opportunity(self.env.ref("base.res_partner_1").id) + + lead_line_1 = self.lead.lead_line_ids[0] + + self.assertEqual(lead_line_1.expected_revenue, + lead_line_1.planned_revenue * + self.lead.probability * (1 / 100), + "Expected revenue should be planned " + "revenue times the probability") + + self.lead.write({'probability': 30}) + + self.assertEqual(lead_line_1.expected_revenue, + round(lead_line_1.planned_revenue * + self.lead.probability * (1 / 100), 5), + "Expected revenue should be planned " + "revenue times the probability") diff --git a/crm_lead_product/views/crm_lead_line_views.xml b/crm_lead_product/views/crm_lead_line_views.xml new file mode 100644 index 00000000000..08aeb16efdc --- /dev/null +++ b/crm_lead_product/views/crm_lead_line_views.xml @@ -0,0 +1,20 @@ + + + + + crm.lead.form.lead + crm.lead.line + + + + + + + + + + + + + + diff --git a/crm_lead_product/views/crm_lead_views.xml b/crm_lead_product/views/crm_lead_views.xml new file mode 100644 index 00000000000..ff8a1d6093b --- /dev/null +++ b/crm_lead_product/views/crm_lead_views.xml @@ -0,0 +1,30 @@ + + + + + crm.lead.form.lead + crm.lead + + + + + + + + + + + + crm.lead.form.oppor + crm.lead + 20 + + + + + + + + + + From 2eab21f188219c4af2bffe6a7e2f210926ef387e Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Thu, 24 Jan 2019 03:45:27 +0000 Subject: [PATCH 02/32] [UPD] README.rst --- .../static/description/index.html | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/crm_lead_product/static/description/index.html b/crm_lead_product/static/description/index.html index 29cf2b3f5a8..1f194b9c7d8 100644 --- a/crm_lead_product/static/description/index.html +++ b/crm_lead_product/static/description/index.html @@ -3,13 +3,13 @@ - + Lead Line Product -
-

Lead Line Product

+
+

CRM Lead Product

-

Beta License: LGPL-3 OCA/crm Translate me on Weblate Try me on Runboat

+

Beta License: LGPL-3 OCA/crm Translate me on Weblate Try me on Runboat

This module allows the user to link multiple products, product categories or product templates to a lead or an opportunity -in order to be able to do a product demand forecasting taking into account the leads and opportunities defined in odoo. -Included in the product line there are two computed fields, the planned revenue and expected revenue. On one hand, the -planned revenue is computed as the selling price times the quantity. On the other hand, the expected revenue takes into account +in order to be able to do a product demand forecasting taking into account the leads and opportunities defined in Odoo.

+

Included in the product line there are two computed fields, the expected revenue and prorated revenue. On one hand, the +expected revenue is computed as the selling price times the quantity. On the other hand, the prorated revenue takes into account the probability of the opportunity and is computed as the planned revenue times the probability.

The module also includes a reporting section where the user can easily see in a pivot and graph view the relationship -between products, stage of the lead/opportunity and the planned or expected revenue for that product.

+between products, stage of the lead/opportunity and the expected or prorated revenue for that product.

Table of contents

    @@ -400,7 +399,7 @@

    Usage

    • Go to menu CRM > Lead and create or edit a Lead adding all the products associated to it.
    • Go to menu CRM > My Pipeline and create or edit an Opportunity adding all the products associated to it.
    • -
    • Go to menu CRM > Reporting > Pipeline by Product to run the report that relates product to planned and expected revenue per stage
    • +
    • Go to menu CRM > Reporting > Pipeline by Product to run the report that relates product to expected and prorated revenue per stage
@@ -408,7 +407,7 @@

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -feedback.

+feedback.

Do not contact contributors directly about support or help with technical issues.

@@ -423,6 +422,7 @@

Authors

Contributors

@@ -432,7 +432,7 @@

Maintainers

OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

-

This module is part of the OCA/crm project on GitHub.

+

This module is part of the OCA/crm project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

diff --git a/crm_lead_product/tests/__init__.py b/crm_lead_product/tests/__init__.py index ab2d5b2769b..d727a8c201f 100644 --- a/crm_lead_product/tests/__init__.py +++ b/crm_lead_product/tests/__init__.py @@ -1,3 +1,3 @@ -# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). - +# Copyright (C) 2017-2024 ForgeFlow S.L. (https://www.forgeflow.com) +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) from . import test_crm_lead_line diff --git a/crm_lead_product/tests/test_crm_lead_line.py b/crm_lead_product/tests/test_crm_lead_line.py index 048277430a8..c6da84702a9 100644 --- a/crm_lead_product/tests/test_crm_lead_line.py +++ b/crm_lead_product/tests/test_crm_lead_line.py @@ -1,12 +1,11 @@ -# Copyright 2017-19 ForgeFlow S.L. (https://www.forgeflow.com) +# Copyright 2017-2024 ForgeFlow S.L. (https://www.forgeflow.com) # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from odoo.tests import common +from odoo.tests.common import TransactionCase, tagged -@common.at_install(False) -@common.post_install(True) -class TestCrmLeadLine(common.TransactionCase): +@tagged("post_install", "-at_install") +class TestCrmLeadLine(TransactionCase): def setUp(self): super(TestCrmLeadLine, self).setUp() self.product_obj = self.env["product.product"] @@ -144,7 +143,7 @@ def test_02_lead_to_opportunity(self): # Check if planned revenue is correctly set for lead line 1 self.assertEqual( - self.lead.lead_line_ids[0].planned_revenue, + self.lead.lead_line_ids[0].expected_revenue, self.product_4.list_price, "Planned revenue should be equal " "to the product standard price", ) @@ -154,15 +153,15 @@ def test_02_lead_to_opportunity(self): lead_line_1 = self.lead.lead_line_ids[0] self.assertEqual( - lead_line_1.expected_revenue, - lead_line_1.planned_revenue * self.lead.probability * (1 / 100), + lead_line_1.prorated_revenue, + lead_line_1.expected_revenue * self.lead.probability * (1 / 100), "Expected revenue should be planned " "revenue times the probability", ) self.lead.write({"probability": 30}) self.assertEqual( - lead_line_1.expected_revenue, - round(lead_line_1.planned_revenue * self.lead.probability * (1 / 100), 5), + lead_line_1.prorated_revenue, + round(lead_line_1.expected_revenue * self.lead.probability * (1 / 100), 5), "Expected revenue should be planned " "revenue times the probability", ) diff --git a/crm_lead_product/views/crm_lead_line_views.xml b/crm_lead_product/views/crm_lead_line_views.xml index e4bddf3b79d..73d931734ff 100644 --- a/crm_lead_product/views/crm_lead_line_views.xml +++ b/crm_lead_product/views/crm_lead_line_views.xml @@ -1,7 +1,7 @@ - crm.lead.form.lead + crm.lead.line.tree - crm_lead_product crm.lead.line @@ -11,8 +11,8 @@ - - + + diff --git a/crm_lead_product/views/crm_lead_views.xml b/crm_lead_product/views/crm_lead_views.xml index 35f62aa245b..5273ebfe2a8 100644 --- a/crm_lead_product/views/crm_lead_views.xml +++ b/crm_lead_product/views/crm_lead_views.xml @@ -1,7 +1,7 @@ - crm.lead.form.lead + crm.lead.form - crm_lead_product crm.lead From bba8d3601b78f76c3a69de50a78726b499359c47 Mon Sep 17 00:00:00 2001 From: JasminSForgeFlow Date: Thu, 6 Jun 2024 09:59:31 +0530 Subject: [PATCH 27/32] [IMP] crm_lead_product: black, isort, prettier --- crm_lead_product/README.rst | 53 +++++++++++-------- crm_lead_product/pyproject.toml | 3 ++ .../readme/{CONFIGURE.rst => CONFIGURE.md} | 3 +- crm_lead_product/readme/CONTRIBUTORS.md | 2 + crm_lead_product/readme/CONTRIBUTORS.rst | 2 - crm_lead_product/readme/DESCRIPTION.md | 15 ++++++ crm_lead_product/readme/DESCRIPTION.rst | 9 ---- crm_lead_product/readme/USAGE.md | 6 +++ crm_lead_product/readme/USAGE.rst | 3 -- .../static/description/index.html | 50 ++++++++++------- 10 files changed, 92 insertions(+), 54 deletions(-) create mode 100644 crm_lead_product/pyproject.toml rename crm_lead_product/readme/{CONFIGURE.rst => CONFIGURE.md} (55%) create mode 100644 crm_lead_product/readme/CONTRIBUTORS.md delete mode 100644 crm_lead_product/readme/CONTRIBUTORS.rst create mode 100644 crm_lead_product/readme/DESCRIPTION.md delete mode 100644 crm_lead_product/readme/DESCRIPTION.rst create mode 100644 crm_lead_product/readme/USAGE.md delete mode 100644 crm_lead_product/readme/USAGE.rst diff --git a/crm_lead_product/README.rst b/crm_lead_product/README.rst index fe08a5c05bf..672f64d55dc 100644 --- a/crm_lead_product/README.rst +++ b/crm_lead_product/README.rst @@ -17,26 +17,32 @@ CRM Lead Product :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html :alt: License: LGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fcrm-lightgray.png?logo=github - :target: https://github.com/OCA/crm/tree/14.0/crm_lead_product + :target: https://github.com/OCA/crm/tree/17.0/crm_lead_product :alt: OCA/crm .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/crm-14-0/crm-14-0-crm_lead_product + :target: https://translation.odoo-community.org/projects/crm-17-0/crm-17-0-crm_lead_product :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png - :target: https://runboat.odoo-community.org/builds?repo=OCA/crm&target_branch=14.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/crm&target_branch=17.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| -This module allows the user to link multiple products, product categories or product templates to a lead or an opportunity -in order to be able to do a product demand forecasting taking into account the leads and opportunities defined in Odoo. +This module allows the user to link multiple products, product +categories or product templates to a lead or an opportunity in order to +be able to do a product demand forecasting taking into account the leads +and opportunities defined in Odoo. -Included in the product line there are two computed fields, the expected revenue and prorated revenue. On one hand, the -expected revenue is computed as the selling price times the quantity. On the other hand, the prorated revenue takes into account -the probability of the opportunity and is computed as the planned revenue times the probability. +Included in the product line there are two computed fields, the expected +revenue and prorated revenue. On one hand, the expected revenue is +computed as the selling price times the quantity. On the other hand, the +prorated revenue takes into account the probability of the opportunity +and is computed as the planned revenue times the probability. -The module also includes a reporting section where the user can easily see in a pivot and graph view the relationship -between products, stage of the lead/opportunity and the expected or prorated revenue for that product. +The module also includes a reporting section where the user can easily +see in a pivot and graph view the relationship between products, stage +of the lead/opportunity and the expected or prorated revenue for that +product. **Table of contents** @@ -46,14 +52,19 @@ between products, stage of the lead/opportunity and the expected or prorated rev Configuration ============= -To configure this module to be available for the Leads the user needs to activate the Leads option in CRM settings +To configure this module to be available for the Leads the user needs to +activate the Leads option in CRM settings Usage ===== -* Go to menu **CRM > Lead** and create or edit a Lead adding all the products associated to it. -* Go to menu **CRM > My Pipeline** and create or edit an Opportunity adding all the products associated to it. -* Go to menu **CRM > Reporting > Pipeline by Product** to run the report that relates product to expected and prorated revenue per stage +- Go to menu **CRM > Lead** and create or edit a Lead adding all the + products associated to it. +- Go to menu **CRM > My Pipeline** and create or edit an Opportunity + adding all the products associated to it. +- Go to menu **CRM > Reporting > Pipeline by Product** to run the + report that relates product to expected and prorated revenue per + stage Bug Tracker =========== @@ -61,7 +72,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -69,18 +80,18 @@ Credits ======= Authors -~~~~~~~ +------- * ForgeFlow Contributors -~~~~~~~~~~~~ +------------ -* Adria Gil Sorribes -* Guillem Casassas +- Adria Gil Sorribes +- Guillem Casassas Maintainers -~~~~~~~~~~~ +----------- This module is maintained by the OCA. @@ -92,6 +103,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -This module is part of the `OCA/crm `_ project on GitHub. +This module is part of the `OCA/crm `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/crm_lead_product/pyproject.toml b/crm_lead_product/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/crm_lead_product/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/crm_lead_product/readme/CONFIGURE.rst b/crm_lead_product/readme/CONFIGURE.md similarity index 55% rename from crm_lead_product/readme/CONFIGURE.rst rename to crm_lead_product/readme/CONFIGURE.md index 8b4d020ccdf..92df568efa4 100644 --- a/crm_lead_product/readme/CONFIGURE.rst +++ b/crm_lead_product/readme/CONFIGURE.md @@ -1 +1,2 @@ -To configure this module to be available for the Leads the user needs to activate the Leads option in CRM settings +To configure this module to be available for the Leads the user needs to +activate the Leads option in CRM settings diff --git a/crm_lead_product/readme/CONTRIBUTORS.md b/crm_lead_product/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..c68f1bd9507 --- /dev/null +++ b/crm_lead_product/readme/CONTRIBUTORS.md @@ -0,0 +1,2 @@ +- Adria Gil Sorribes \<\> +- Guillem Casassas \<\> diff --git a/crm_lead_product/readme/CONTRIBUTORS.rst b/crm_lead_product/readme/CONTRIBUTORS.rst deleted file mode 100644 index 9925ec25580..00000000000 --- a/crm_lead_product/readme/CONTRIBUTORS.rst +++ /dev/null @@ -1,2 +0,0 @@ -* Adria Gil Sorribes -* Guillem Casassas diff --git a/crm_lead_product/readme/DESCRIPTION.md b/crm_lead_product/readme/DESCRIPTION.md new file mode 100644 index 00000000000..c54f1f18301 --- /dev/null +++ b/crm_lead_product/readme/DESCRIPTION.md @@ -0,0 +1,15 @@ +This module allows the user to link multiple products, product +categories or product templates to a lead or an opportunity in order to +be able to do a product demand forecasting taking into account the leads +and opportunities defined in Odoo. + +Included in the product line there are two computed fields, the expected +revenue and prorated revenue. On one hand, the expected revenue is +computed as the selling price times the quantity. On the other hand, the +prorated revenue takes into account the probability of the opportunity +and is computed as the planned revenue times the probability. + +The module also includes a reporting section where the user can easily +see in a pivot and graph view the relationship between products, stage +of the lead/opportunity and the expected or prorated revenue for that +product. diff --git a/crm_lead_product/readme/DESCRIPTION.rst b/crm_lead_product/readme/DESCRIPTION.rst deleted file mode 100644 index a0850605d71..00000000000 --- a/crm_lead_product/readme/DESCRIPTION.rst +++ /dev/null @@ -1,9 +0,0 @@ -This module allows the user to link multiple products, product categories or product templates to a lead or an opportunity -in order to be able to do a product demand forecasting taking into account the leads and opportunities defined in Odoo. - -Included in the product line there are two computed fields, the expected revenue and prorated revenue. On one hand, the -expected revenue is computed as the selling price times the quantity. On the other hand, the prorated revenue takes into account -the probability of the opportunity and is computed as the planned revenue times the probability. - -The module also includes a reporting section where the user can easily see in a pivot and graph view the relationship -between products, stage of the lead/opportunity and the expected or prorated revenue for that product. diff --git a/crm_lead_product/readme/USAGE.md b/crm_lead_product/readme/USAGE.md new file mode 100644 index 00000000000..d59fe041c1f --- /dev/null +++ b/crm_lead_product/readme/USAGE.md @@ -0,0 +1,6 @@ +- Go to menu **CRM \> Lead** and create or edit a Lead adding all the + products associated to it. +- Go to menu **CRM \> My Pipeline** and create or edit an Opportunity + adding all the products associated to it. +- Go to menu **CRM \> Reporting \> Pipeline by Product** to run the + report that relates product to expected and prorated revenue per stage diff --git a/crm_lead_product/readme/USAGE.rst b/crm_lead_product/readme/USAGE.rst deleted file mode 100644 index 12ba600dd6c..00000000000 --- a/crm_lead_product/readme/USAGE.rst +++ /dev/null @@ -1,3 +0,0 @@ -* Go to menu **CRM > Lead** and create or edit a Lead adding all the products associated to it. -* Go to menu **CRM > My Pipeline** and create or edit an Opportunity adding all the products associated to it. -* Go to menu **CRM > Reporting > Pipeline by Product** to run the report that relates product to expected and prorated revenue per stage diff --git a/crm_lead_product/static/description/index.html b/crm_lead_product/static/description/index.html index 9c22830baff..b9304caaa99 100644 --- a/crm_lead_product/static/description/index.html +++ b/crm_lead_product/static/description/index.html @@ -8,10 +8,11 @@ /* :Author: David Goodger (goodger@python.org) -:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ +:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. +Despite the name, some widely supported CSS2 features are used. See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to customize this style sheet. @@ -274,7 +275,7 @@ margin-left: 2em ; margin-right: 2em } -pre.code .ln { color: grey; } /* line numbers */ +pre.code .ln { color: gray; } /* line numbers */ pre.code, code { background-color: #eeeeee } pre.code .comment, code .comment { color: #5C6576 } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } @@ -300,7 +301,7 @@ span.pre { white-space: pre } -span.problematic { +span.problematic, pre.problematic { color: red } span.section-subtitle { @@ -368,14 +369,20 @@

CRM Lead Product

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! source digest: sha256:e329f5a385e7f3371baeccb7831a37fb163dd62362c2b8ad0d99b6a75a311fc6 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: LGPL-3 OCA/crm Translate me on Weblate Try me on Runboat

-

This module allows the user to link multiple products, product categories or product templates to a lead or an opportunity -in order to be able to do a product demand forecasting taking into account the leads and opportunities defined in Odoo.

-

Included in the product line there are two computed fields, the expected revenue and prorated revenue. On one hand, the -expected revenue is computed as the selling price times the quantity. On the other hand, the prorated revenue takes into account -the probability of the opportunity and is computed as the planned revenue times the probability.

-

The module also includes a reporting section where the user can easily see in a pivot and graph view the relationship -between products, stage of the lead/opportunity and the expected or prorated revenue for that product.

+

Beta License: LGPL-3 OCA/crm Translate me on Weblate Try me on Runboat

+

This module allows the user to link multiple products, product +categories or product templates to a lead or an opportunity in order to +be able to do a product demand forecasting taking into account the leads +and opportunities defined in Odoo.

+

Included in the product line there are two computed fields, the expected +revenue and prorated revenue. On one hand, the expected revenue is +computed as the selling price times the quantity. On the other hand, the +prorated revenue takes into account the probability of the opportunity +and is computed as the planned revenue times the probability.

+

The module also includes a reporting section where the user can easily +see in a pivot and graph view the relationship between products, stage +of the lead/opportunity and the expected or prorated revenue for that +product.

Table of contents

    @@ -392,14 +399,19 @@

    CRM Lead Product

Configuration

-

To configure this module to be available for the Leads the user needs to activate the Leads option in CRM settings

+

To configure this module to be available for the Leads the user needs to +activate the Leads option in CRM settings

Usage

    -
  • Go to menu CRM > Lead and create or edit a Lead adding all the products associated to it.
  • -
  • Go to menu CRM > My Pipeline and create or edit an Opportunity adding all the products associated to it.
  • -
  • Go to menu CRM > Reporting > Pipeline by Product to run the report that relates product to expected and prorated revenue per stage
  • +
  • Go to menu CRM > Lead and create or edit a Lead adding all the +products associated to it.
  • +
  • Go to menu CRM > My Pipeline and create or edit an Opportunity +adding all the products associated to it.
  • +
  • Go to menu CRM > Reporting > Pipeline by Product to run the +report that relates product to expected and prorated revenue per +stage
@@ -407,7 +419,7 @@

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -feedback.

+feedback.

Do not contact contributors directly about support or help with technical issues.

@@ -428,11 +440,13 @@

Contributors

Maintainers

This module is maintained by the OCA.

-Odoo Community Association + +Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

-

This module is part of the OCA/crm project on GitHub.

+

This module is part of the OCA/crm project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

From 68a0aad6098663a03d260e4396995c378242309f Mon Sep 17 00:00:00 2001 From: JasminSForgeFlow Date: Thu, 6 Jun 2024 14:02:16 +0530 Subject: [PATCH 28/32] [MIG] crm_lead_product: Migration to 17.0 --- crm_lead_product/__manifest__.py | 2 +- .../migrations/14.0.1.0.0/pre-migration.py | 59 ------------------- crm_lead_product/models/crm_lead.py | 2 +- crm_lead_product/models/crm_lead_line.py | 2 +- crm_lead_product/report/crm_product_report.py | 19 +++--- .../report/crm_product_report_views.xml | 4 +- crm_lead_product/tests/test_crm_lead_line.py | 14 ++--- .../views/crm_lead_line_views.xml | 2 +- 8 files changed, 22 insertions(+), 82 deletions(-) delete mode 100644 crm_lead_product/migrations/14.0.1.0.0/pre-migration.py diff --git a/crm_lead_product/__manifest__.py b/crm_lead_product/__manifest__.py index aa64c1ff950..64de49cfdc0 100644 --- a/crm_lead_product/__manifest__.py +++ b/crm_lead_product/__manifest__.py @@ -2,7 +2,7 @@ # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) { "name": "CRM Lead Product", - "version": "14.0.1.0.0", + "version": "17.0.1.0.0", "category": "Customer Relationship Management", "license": "LGPL-3", "summary": "Adds a lead line in the lead/opportunity model in odoo", diff --git a/crm_lead_product/migrations/14.0.1.0.0/pre-migration.py b/crm_lead_product/migrations/14.0.1.0.0/pre-migration.py deleted file mode 100644 index 02f741a92f1..00000000000 --- a/crm_lead_product/migrations/14.0.1.0.0/pre-migration.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (C) 2017-2024 ForgeFlow S.L. (https://www.forgeflow.com) -# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) -from openupgradelib import openupgrade - - -@openupgrade.migrate() -def migrate(env, version): - if openupgrade.column_exists( - env.cr, "crm_lead_line", "expected_revenue" - ) and not openupgrade.column_exists(env.cr, "crm_lead_line", "prorated_revenue"): - env.cr.execute( - """ - ALTER TABLE crm_lead_line - ADD COLUMN prorated_revenue NUMERIC; - COMMENT ON COLUMN crm_lead_line.prorated_revenue - IS 'Prorated Revenue'; - """ - ) - # PostgreSQL already automatically truncates from `double_precision` type to - # `numeric` type, this is needed as we are converting from Float Odoo field - # to Monetary Odoo field - env.cr.execute( - """ - UPDATE crm_lead_line - SET prorated_revenue = expected_revenue; - """ - ) - env.cr.execute( - """ - ALTER TABLE crm_lead_line - DROP COLUMN expected_revenue; - """ - ) - if openupgrade.column_exists( - env.cr, "crm_lead_line", "planned_revenue" - ) and not openupgrade.column_exists(env.cr, "crm_lead_line", "expected_revenue"): - env.cr.execute( - """ - ALTER TABLE crm_lead_line - ADD COLUMN expected_revenue NUMERIC; - COMMENT ON COLUMN crm_lead_line.expected_revenue - IS 'Expected Revenue'; - """ - ) - # PostgreSQL already automatically truncates from `double_precision` type to - # `numeric` type, this is needed as we are converting from Float Odoo field - # to Monetary Odoo field - env.cr.execute( - """ - UPDATE crm_lead_line - SET expected_revenue = planned_revenue; - """ - ) - env.cr.execute( - """ - ALTER TABLE crm_lead_line - DROP COLUMN planned_revenue; - """ - ) diff --git a/crm_lead_product/models/crm_lead.py b/crm_lead_product/models/crm_lead.py index 005a125dd07..1887983ee92 100644 --- a/crm_lead_product/models/crm_lead.py +++ b/crm_lead_product/models/crm_lead.py @@ -19,7 +19,7 @@ def _onchange_lead_line_ids(self): self.expected_revenue = expected_revenue def _convert_opportunity_data(self, customer, team_id=False): - res = super(CrmLead, self)._convert_opportunity_data(customer, team_id) + res = super()._convert_opportunity_data(customer, team_id) expected_revenue = 0 for lead_line in self.lead_line_ids: expected_revenue += lead_line.expected_revenue diff --git a/crm_lead_product/models/crm_lead_line.py b/crm_lead_product/models/crm_lead_line.py index 12177631c6e..4f59fa77042 100644 --- a/crm_lead_product/models/crm_lead_line.py +++ b/crm_lead_product/models/crm_lead_line.py @@ -32,7 +32,7 @@ def _compute_prorated_revenue(self): ) product_qty = fields.Integer(string="Product Quantity", default=1, required=True) uom_id = fields.Many2one("uom.uom", string="Unit of Measure", readonly=True) - price_unit = fields.Float(string="Price Unit", digits="Product Price") + price_unit = fields.Float(digits="Product Price") company_currency = fields.Many2one( "res.currency", string="Currency", diff --git a/crm_lead_product/report/crm_product_report.py b/crm_lead_product/report/crm_product_report.py index 4bc3c19c7c2..12ae81e68fd 100644 --- a/crm_lead_product/report/crm_product_report.py +++ b/crm_lead_product/report/crm_product_report.py @@ -13,31 +13,30 @@ class ActivityReport(models.Model): _description = "CRM Pipeline by Product Analysis" _rec_name = "id" - active = fields.Boolean("Active", readonly=True) + active = fields.Boolean(readonly=True) campaign_id = fields.Many2one("utm.campaign", "Campaing", readonly=True) country_id = fields.Many2one("res.country", "Country", readonly=True) company_id = fields.Many2one("res.company", "Company", readonly=True) - create_date = fields.Datetime("Create Date", readonly=True) + create_date = fields.Datetime(readonly=True) date_closed = fields.Datetime("Closed Date", readonly=True) date_conversion = fields.Datetime("Conversion Date", readonly=True) date_deadline = fields.Datetime("Deadline Date", readonly=True) date_open = fields.Datetime("Open Date", readonly=True) - lost_reason = fields.Many2one("crm.lost.reason", "Lost Reason", readonly=True) + lost_reason_id = fields.Many2one("crm.lost.reason", readonly=True) name = fields.Char("Lead Name", readonly=True) partner_id = fields.Many2one("res.partner", "Partner/Customer", readonly=True) partner_name = fields.Char("Contact Name", readonly=True) - probability = fields.Float("Probability", group_operator="avg", readonly=True) + probability = fields.Float(group_operator="avg", readonly=True) stage_id = fields.Many2one("crm.stage", "Stage", readonly=True) team_id = fields.Many2one("crm.team", "Sales Team", readonly=True) - type = fields.Char( - string="Type", - selection=[("lead", "Lead"), ("opportunity", "Opportunity")], + type = fields.Selection( + [("lead", "Lead"), ("opportunity", "Opportunity")], help="Type is used to separate Leads and Opportunities", ) user_id = fields.Many2one("res.users", "Salesperson", readonly=True) category_id = fields.Many2one("product.category", "Category", readonly=True) - expected_revenue = fields.Float("Expected Revenue", readonly=True) - prorated_revenue = fields.Float("Prorated Revenue", readonly=True) + expected_revenue = fields.Float(readonly=True) + prorated_revenue = fields.Float(readonly=True) product_id = fields.Many2one("product.product", "Product", readonly=True) product_qty = fields.Integer("Product Quantity", readonly=True) product_tmpl_id = fields.Many2one( @@ -58,7 +57,7 @@ def _select(self): l.date_conversion, l.date_deadline, l.date_open, - l.lost_reason, + l.lost_reason_id, l.name, l.partner_id, l.partner_name, diff --git a/crm_lead_product/report/crm_product_report_views.xml b/crm_lead_product/report/crm_product_report_views.xml index 440b292b635..c733acef937 100644 --- a/crm_lead_product/report/crm_product_report_views.xml +++ b/crm_lead_product/report/crm_product_report_views.xml @@ -30,7 +30,7 @@ crm.opportunity.report.list crm.product.report - + @@ -173,7 +173,7 @@ diff --git a/crm_lead_product/tests/test_crm_lead_line.py b/crm_lead_product/tests/test_crm_lead_line.py index c6da84702a9..ea4be75a7c4 100644 --- a/crm_lead_product/tests/test_crm_lead_line.py +++ b/crm_lead_product/tests/test_crm_lead_line.py @@ -7,7 +7,7 @@ @tagged("post_install", "-at_install") class TestCrmLeadLine(TransactionCase): def setUp(self): - super(TestCrmLeadLine, self).setUp() + super().setUp() self.product_obj = self.env["product.product"] self.lead_line_obj = self.env["crm.lead.line"] self.lead = self.env["crm.lead"].create( @@ -25,21 +25,21 @@ def setUp(self): { "name": "Product 1", "categ_id": self.env.ref("product.product_category_1").id, - "price": 142.0, + "list_price": 142.0, } ) self.product_2 = self.product_obj.create( { "name": "Product 2", "categ_id": self.env.ref("product.product_category_2").id, - "price": 1420.0, + "list_price": 1420.0, } ) self.product_3 = self.product_obj.create( { "name": "Product 3", "categ_id": self.env.ref("product.product_category_3").id, - "price": 14200.0, + "list_price": 14200.0, } ) self.product_4 = self.env.ref("product.product_product_25") @@ -54,7 +54,7 @@ def test_01_lead_lines(self): "name": self.product_1.name, "product_id": self.product_1.id, "uom_id": self.product_1.uom_id.id, - "price_unit": self.product_1.price, + "price_unit": self.product_1.list_price, } ) # Create new lead line with category id @@ -148,13 +148,13 @@ def test_02_lead_to_opportunity(self): "Planned revenue should be equal " "to the product standard price", ) - self.lead.convert_opportunity(self.env.ref("base.res_partner_1").id) + self.lead.convert_opportunity(self.env.ref("base.res_partner_1")) lead_line_1 = self.lead.lead_line_ids[0] self.assertEqual( lead_line_1.prorated_revenue, - lead_line_1.expected_revenue * self.lead.probability * (1 / 100), + round(lead_line_1.expected_revenue * self.lead.probability * (1 / 100), 2), "Expected revenue should be planned " "revenue times the probability", ) diff --git a/crm_lead_product/views/crm_lead_line_views.xml b/crm_lead_product/views/crm_lead_line_views.xml index 73d931734ff..fdff2ebbb62 100644 --- a/crm_lead_product/views/crm_lead_line_views.xml +++ b/crm_lead_product/views/crm_lead_line_views.xml @@ -4,7 +4,7 @@ crm.lead.line.tree - crm_lead_product crm.lead.line - + From 2d618b9d9acb7724cbed9e21897188d77e98f519 Mon Sep 17 00:00:00 2001 From: oca-ci Date: Sat, 8 Jun 2024 10:23:53 +0000 Subject: [PATCH 29/32] [UPD] Update crm_lead_product.pot --- crm_lead_product/i18n/crm_lead_product.pot | 41 ++++++++++------------ 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/crm_lead_product/i18n/crm_lead_product.pot b/crm_lead_product/i18n/crm_lead_product.pot index 9246f7c63f6..4e96092c542 100644 --- a/crm_lead_product/i18n/crm_lead_product.pot +++ b/crm_lead_product/i18n/crm_lead_product.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 13.0\n" +"Project-Id-Version: Odoo Server 17.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: \n" "Language-Team: \n" @@ -87,6 +87,11 @@ msgstr "" msgid "Creation Date" msgstr "" +#. module: crm_lead_product +#: model:ir.model.fields,field_description:crm_lead_product.field_crm_lead_line__company_currency +msgid "Currency" +msgstr "" + #. module: crm_lead_product #: model_terms:ir.ui.view,arch_db:crm_lead_product.crm_opportunity_report_view_search msgid "Date Closed" @@ -120,7 +125,6 @@ msgstr "" #. module: crm_lead_product #: model:ir.model.fields,field_description:crm_lead_product.field_crm_lead_line__expected_revenue -#: model_terms:ir.ui.view,arch_db:crm_lead_product.view_tree_lead_line msgid "Expected revenue" msgstr "" @@ -140,12 +144,6 @@ msgstr "" msgid "ID" msgstr "" -#. module: crm_lead_product -#: model:ir.model.fields,field_description:crm_lead_product.field_crm_lead_line____last_update -#: model:ir.model.fields,field_description:crm_lead_product.field_crm_product_report____last_update -msgid "Last Modified on" -msgstr "" - #. module: crm_lead_product #: model:ir.model.fields,field_description:crm_lead_product.field_crm_lead_line__write_uid msgid "Last Updated by" @@ -158,6 +156,7 @@ msgstr "" #. module: crm_lead_product #: model:ir.model.fields,field_description:crm_lead_product.field_crm_lead_line__lead_id +#: model:ir.model.fields.selection,name:crm_lead_product.selection__crm_product_report__type__lead #: model_terms:ir.ui.view,arch_db:crm_lead_product.crm_opportunity_report_view_search msgid "Lead" msgstr "" @@ -188,7 +187,7 @@ msgid "Lost" msgstr "" #. module: crm_lead_product -#: model:ir.model.fields,field_description:crm_lead_product.field_crm_product_report__lost_reason +#: model:ir.model.fields,field_description:crm_lead_product.field_crm_product_report__lost_reason_id #: model_terms:ir.ui.view,arch_db:crm_lead_product.crm_opportunity_report_view_search msgid "Lost Reason" msgstr "" @@ -214,6 +213,7 @@ msgid "Opportunities Analysis" msgstr "" #. module: crm_lead_product +#: model:ir.model.fields.selection,name:crm_lead_product.selection__crm_product_report__type__opportunity #: model_terms:ir.ui.view,arch_db:crm_lead_product.crm_opportunity_report_view_search msgid "Opportunity" msgstr "" @@ -226,7 +226,6 @@ msgstr "" #. module: crm_lead_product #: model_terms:ir.ui.view,arch_db:crm_lead_product.crm_opportunity_report_view_graph #: model_terms:ir.ui.view,arch_db:crm_lead_product.crm_opportunity_report_view_pivot -#: model_terms:ir.ui.view,arch_db:crm_lead_product.crm_opportunity_report_view_tree msgid "Pipeline Analysis" msgstr "" @@ -250,17 +249,6 @@ msgstr "" msgid "Pipeline by product" msgstr "" -#. module: crm_lead_product -#: model:ir.model.fields,field_description:crm_lead_product.field_crm_product_report__planned_revenue -msgid "Planned Revenue" -msgstr "" - -#. module: crm_lead_product -#: model:ir.model.fields,field_description:crm_lead_product.field_crm_lead_line__planned_revenue -#: model_terms:ir.ui.view,arch_db:crm_lead_product.view_tree_lead_line -msgid "Planned revenue" -msgstr "" - #. module: crm_lead_product #: model:ir.model.fields,field_description:crm_lead_product.field_crm_lead_line__price_unit #: model_terms:ir.ui.view,arch_db:crm_lead_product.view_tree_lead_line @@ -297,10 +285,19 @@ msgstr "" #. module: crm_lead_product #: model_terms:ir.ui.view,arch_db:crm_lead_product.crm_lead_view_form -#: model_terms:ir.ui.view,arch_db:crm_lead_product.view_tree_lead_line msgid "Products" msgstr "" +#. module: crm_lead_product +#: model:ir.model.fields,field_description:crm_lead_product.field_crm_product_report__prorated_revenue +msgid "Prorated Revenue" +msgstr "" + +#. module: crm_lead_product +#: model:ir.model.fields,field_description:crm_lead_product.field_crm_lead_line__prorated_revenue +msgid "Prorated revenue" +msgstr "" + #. module: crm_lead_product #: model_terms:ir.ui.view,arch_db:crm_lead_product.view_tree_lead_line msgid "Quantity" From ef2974b5710b5b63a8dc47bf05da82fcb8c18e9f Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Sat, 8 Jun 2024 10:26:03 +0000 Subject: [PATCH 30/32] [BOT] post-merge updates --- crm_lead_product/README.rst | 2 +- crm_lead_product/static/description/index.html | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/crm_lead_product/README.rst b/crm_lead_product/README.rst index 672f64d55dc..9abb7dea377 100644 --- a/crm_lead_product/README.rst +++ b/crm_lead_product/README.rst @@ -7,7 +7,7 @@ CRM Lead Product !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:e329f5a385e7f3371baeccb7831a37fb163dd62362c2b8ad0d99b6a75a311fc6 + !! source digest: sha256:24d4c1f6fa68ecc15510e005185543af4dbe7b792fba9c8355579601dfce32a6 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/crm_lead_product/static/description/index.html b/crm_lead_product/static/description/index.html index b9304caaa99..083001e979e 100644 --- a/crm_lead_product/static/description/index.html +++ b/crm_lead_product/static/description/index.html @@ -8,11 +8,10 @@ /* :Author: David Goodger (goodger@python.org) -:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $ +:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. -Despite the name, some widely supported CSS2 features are used. See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to customize this style sheet. @@ -275,7 +274,7 @@ margin-left: 2em ; margin-right: 2em } -pre.code .ln { color: gray; } /* line numbers */ +pre.code .ln { color: grey; } /* line numbers */ pre.code, code { background-color: #eeeeee } pre.code .comment, code .comment { color: #5C6576 } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } @@ -301,7 +300,7 @@ span.pre { white-space: pre } -span.problematic, pre.problematic { +span.problematic { color: red } span.section-subtitle { @@ -367,7 +366,7 @@

CRM Lead Product

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:e329f5a385e7f3371baeccb7831a37fb163dd62362c2b8ad0d99b6a75a311fc6 +!! source digest: sha256:24d4c1f6fa68ecc15510e005185543af4dbe7b792fba9c8355579601dfce32a6 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: LGPL-3 OCA/crm Translate me on Weblate Try me on Runboat

This module allows the user to link multiple products, product @@ -440,9 +439,7 @@

Contributors

Maintainers

This module is maintained by the OCA.

- -Odoo Community Association - +Odoo Community Association

OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

From 9f33d927779318b33052559b8f315c778d018c68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20GRALL?= Date: Wed, 20 Nov 2024 16:27:50 +0100 Subject: [PATCH 31/32] [MIG] crm_lead_product: Migration to 18.0 --- crm_lead_product/__manifest__.py | 2 +- crm_lead_product/report/crm_product_report_views.xml | 10 +++++----- crm_lead_product/views/crm_lead_line_views.xml | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/crm_lead_product/__manifest__.py b/crm_lead_product/__manifest__.py index 64de49cfdc0..34471ea5448 100644 --- a/crm_lead_product/__manifest__.py +++ b/crm_lead_product/__manifest__.py @@ -2,7 +2,7 @@ # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html) { "name": "CRM Lead Product", - "version": "17.0.1.0.0", + "version": "18.0.1.0.0", "category": "Customer Relationship Management", "license": "LGPL-3", "summary": "Adds a lead line in the lead/opportunity model in odoo", diff --git a/crm_lead_product/report/crm_product_report_views.xml b/crm_lead_product/report/crm_product_report_views.xml index c733acef937..f6cbad3a9c3 100644 --- a/crm_lead_product/report/crm_product_report_views.xml +++ b/crm_lead_product/report/crm_product_report_views.xml @@ -25,12 +25,12 @@ - + crm.opportunity.report.list crm.product.report - + @@ -42,7 +42,7 @@ - + @@ -182,7 +182,7 @@ Pipeline by Product Analysis crm.product.report - pivot,graph,tree,form + pivot,graph,list,form Pipeline Analysis gives you an instant access to your opportunities with information such as the expected revenue, planned cost, diff --git a/crm_lead_product/views/crm_lead_line_views.xml b/crm_lead_product/views/crm_lead_line_views.xml index fdff2ebbb62..391c4fc2f30 100644 --- a/crm_lead_product/views/crm_lead_line_views.xml +++ b/crm_lead_product/views/crm_lead_line_views.xml @@ -4,7 +4,7 @@ crm.lead.line.tree - crm_lead_product crm.lead.line - + @@ -13,7 +13,7 @@ - + From a25eed16d0e2c5d24d52262b12df252ee734c20d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20GRALL?= Date: Thu, 21 Nov 2024 12:25:41 +0100 Subject: [PATCH 32/32] [MIG] crm_lead_product: Migration to 18.0 --- crm_lead_product/README.rst | 11 ++++++----- crm_lead_product/readme/CONTRIBUTORS.md | 1 + crm_lead_product/report/crm_product_report.py | 2 +- crm_lead_product/static/description/index.html | 18 +++++++++++------- crm_lead_product/tests/test_crm_lead_line.py | 1 - 5 files changed, 19 insertions(+), 14 deletions(-) diff --git a/crm_lead_product/README.rst b/crm_lead_product/README.rst index 9abb7dea377..7af8338e627 100644 --- a/crm_lead_product/README.rst +++ b/crm_lead_product/README.rst @@ -17,13 +17,13 @@ CRM Lead Product :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html :alt: License: LGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fcrm-lightgray.png?logo=github - :target: https://github.com/OCA/crm/tree/17.0/crm_lead_product + :target: https://github.com/OCA/crm/tree/18.0/crm_lead_product :alt: OCA/crm .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/crm-17-0/crm-17-0-crm_lead_product + :target: https://translation.odoo-community.org/projects/crm-18-0/crm-18-0-crm_lead_product :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png - :target: https://runboat.odoo-community.org/builds?repo=OCA/crm&target_branch=17.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/crm&target_branch=18.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -72,7 +72,7 @@ Bug Tracker Bugs are tracked on `GitHub Issues `_. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -89,6 +89,7 @@ Contributors - Adria Gil Sorribes - Guillem Casassas +- Frederic Grall Maintainers ----------- @@ -103,6 +104,6 @@ OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use. -This module is part of the `OCA/crm `_ project on GitHub. +This module is part of the `OCA/crm `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/crm_lead_product/readme/CONTRIBUTORS.md b/crm_lead_product/readme/CONTRIBUTORS.md index c68f1bd9507..6c53a883b7f 100644 --- a/crm_lead_product/readme/CONTRIBUTORS.md +++ b/crm_lead_product/readme/CONTRIBUTORS.md @@ -1,2 +1,3 @@ - Adria Gil Sorribes \<\> - Guillem Casassas \<\> +- Frederic Grall \<> \ No newline at end of file diff --git a/crm_lead_product/report/crm_product_report.py b/crm_lead_product/report/crm_product_report.py index 12ae81e68fd..d883e51e754 100644 --- a/crm_lead_product/report/crm_product_report.py +++ b/crm_lead_product/report/crm_product_report.py @@ -26,7 +26,7 @@ class ActivityReport(models.Model): name = fields.Char("Lead Name", readonly=True) partner_id = fields.Many2one("res.partner", "Partner/Customer", readonly=True) partner_name = fields.Char("Contact Name", readonly=True) - probability = fields.Float(group_operator="avg", readonly=True) + probability = fields.Float(aggregator="avg", readonly=True) stage_id = fields.Many2one("crm.stage", "Stage", readonly=True) team_id = fields.Many2one("crm.team", "Sales Team", readonly=True) type = fields.Selection( diff --git a/crm_lead_product/static/description/index.html b/crm_lead_product/static/description/index.html index 083001e979e..4643d5f8b4d 100644 --- a/crm_lead_product/static/description/index.html +++ b/crm_lead_product/static/description/index.html @@ -8,10 +8,11 @@ /* :Author: David Goodger (goodger@python.org) -:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ +:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. +Despite the name, some widely supported CSS2 features are used. See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to customize this style sheet. @@ -274,7 +275,7 @@ margin-left: 2em ; margin-right: 2em } -pre.code .ln { color: grey; } /* line numbers */ +pre.code .ln { color: gray; } /* line numbers */ pre.code, code { background-color: #eeeeee } pre.code .comment, code .comment { color: #5C6576 } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } @@ -300,7 +301,7 @@ span.pre { white-space: pre } -span.problematic { +span.problematic, pre.problematic { color: red } span.section-subtitle { @@ -368,7 +369,7 @@

CRM Lead Product

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! source digest: sha256:24d4c1f6fa68ecc15510e005185543af4dbe7b792fba9c8355579601dfce32a6 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: LGPL-3 OCA/crm Translate me on Weblate Try me on Runboat

+

Beta License: LGPL-3 OCA/crm Translate me on Weblate Try me on Runboat

This module allows the user to link multiple products, product categories or product templates to a lead or an opportunity in order to be able to do a product demand forecasting taking into account the leads @@ -418,7 +419,7 @@

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed -feedback.

+feedback.

Do not contact contributors directly about support or help with technical issues.

@@ -434,16 +435,19 @@

Contributors

Maintainers

This module is maintained by the OCA.

-Odoo Community Association + +Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose mission is to support the collaborative development of Odoo features and promote its widespread use.

-

This module is part of the OCA/crm project on GitHub.

+

This module is part of the OCA/crm project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

diff --git a/crm_lead_product/tests/test_crm_lead_line.py b/crm_lead_product/tests/test_crm_lead_line.py index ea4be75a7c4..35f2d65f3a6 100644 --- a/crm_lead_product/tests/test_crm_lead_line.py +++ b/crm_lead_product/tests/test_crm_lead_line.py @@ -46,7 +46,6 @@ def setUp(self): def test_01_lead_lines(self): """Tests for Crm Lead Line""" - # Create new lead line with product id self.lead_line_1 = self.lead_line_obj.create( {