Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion crm_sale_ux/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ CRM Sale UX
This module:

#. If the option "Allow any user as salesman" is enable, it would be possible to assign any user as salesperson in leads, opportunities and teams.
#. Adds a CRM setting to automatically mark opportunities as Won when their quotation is confirmed.

Installation
============
Expand All @@ -30,7 +31,8 @@ Configuration

To configure this module, you need to:

#. Nothing to configure
#. Go to CRM -> Configuration -> Settings.
#. Enable "Auto mark opportunities as Won".

Usage
=====
Expand Down
2 changes: 2 additions & 0 deletions crm_sale_ux/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
# © 2016 ADHOC SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from . import models
3 changes: 2 additions & 1 deletion crm_sale_ux/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
"website": "www.adhoc.com.ar",
"license": "AGPL-3",
"images": [],
"depends": ["crm", "sale_ux"],
"depends": ["sale_crm", "sale_ux"],
"data": [
"views/crm_lead_views.xml",
"views/res_config_settings_views.xml",
],
"demo": [],
"installable": True,
Expand Down
5 changes: 5 additions & 0 deletions crm_sale_ux/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# © 2016 ADHOC SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from . import res_config_settings
from . import sale_order
14 changes: 14 additions & 0 deletions crm_sale_ux/models/res_config_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# © 2026 ADHOC SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import fields, models


class ResConfigSettings(models.TransientModel):
_inherit = "res.config.settings"

crm_auto_won_on_sale_confirm = fields.Boolean(
string="Mark opportunity as won on sales order confirmation",
config_parameter="crm_sale_ux.auto_won_on_sale_confirm",
help="When enabled, confirming a quotation linked to an opportunity marks that opportunity as Won.",
)
27 changes: 27 additions & 0 deletions crm_sale_ux/models/sale_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# © 2026 ADHOC SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import models
from odoo.tools import str2bool


class SaleOrder(models.Model):
_inherit = "sale.order"

def action_confirm(self):
res = super().action_confirm()

enabled = str2bool(
self.env["ir.config_parameter"].sudo().get_param("crm_sale_ux.auto_won_on_sale_confirm", "False"),
False,
)
if not enabled:
return res

opportunities = self.mapped("opportunity_id").filtered(
lambda lead: lead.type == "opportunity" and not lead.stage_id.is_won
)
if opportunities:
opportunities.action_set_won()

return res
4 changes: 4 additions & 0 deletions crm_sale_ux/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# © 2026 ADHOC SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from . import test_auto_set_won
77 changes: 77 additions & 0 deletions crm_sale_ux/tests/test_auto_set_won.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# © 2026 ADHOC SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo.addons.crm.tests.common import TestCrmCommon
from odoo.fields import Command
from odoo.tests import tagged


@tagged("crm_sale_ux", "post_install", "-at_install")
class TestCrmSaleUxAutoSetWon(TestCrmCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.partner = cls.env.user.partner_id
cls.product = cls.env["product.product"].create(
{
"name": "CRM Sale UX product",
"type": "service",
"list_price": 100.0,
}
)

def _create_opportunity(self, name):
stage = self.env["crm.stage"].search([("is_won", "=", False)], order="sequence, id", limit=1)
return self.env["crm.lead"].create(
{
"name": name,
"type": "opportunity",
"partner_id": self.partner.id,
"stage_id": stage.id,
"user_id": self.env.user.id,
}
)

def _create_quotation(self, opportunity):
return self.env["sale.order"].create(
{
"partner_id": self.partner.id,
"opportunity_id": opportunity.id,
"order_line": [
Command.create(
{
"product_id": self.product.id,
"product_uom_qty": 1.0,
"price_unit": self.product.list_price,
"name": self.product.name,
}
)
],
}
)

def test_confirm_quotation_does_not_set_won_when_disabled(self):
self.env["ir.config_parameter"].sudo().set_param("crm_sale_ux.auto_won_on_sale_confirm", False)
opportunity = self._create_opportunity("Won setting disabled")
stage_before = opportunity.stage_id

quotation = self._create_quotation(opportunity)
quotation.action_confirm()

self.assertEqual(opportunity.stage_id, stage_before)
self.assertFalse(opportunity.stage_id.is_won)

def test_confirm_quotation_sets_won_when_enabled(self):
self.env["ir.config_parameter"].sudo().set_param("crm_sale_ux.auto_won_on_sale_confirm", True)
opportunity = self._create_opportunity("Won setting enabled")

quotation = self._create_quotation(opportunity)

sale_exception_installed = self.env["sale.order"]._fields.get("ignore_exception")
if sale_exception_installed:
self.env["exception.rule"].search([("active", "=", True)]).write({"active": False})

quotation.action_confirm()

self.assertTrue(opportunity.stage_id.is_won)
self.assertEqual(opportunity.probability, 100)
19 changes: 19 additions & 0 deletions crm_sale_ux/views/res_config_settings_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="crm_sale_ux_res_config_settings_view_form" model="ir.ui.view">
<field name="name">res.config.settings.view.form.inherit.crm.sale.ux</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="crm.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//setting[@id='crm_lead']" position="after">
<setting
id="crm_auto_won_on_sale_confirm"
string="Auto mark opportunities as Won"
help="When a quotation linked to an opportunity is confirmed, mark that opportunity as Won automatically."
>
<field name="crm_auto_won_on_sale_confirm"/>
</setting>
</xpath>
</field>
</record>
</odoo>
Loading