Skip to content
Open
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
102 changes: 102 additions & 0 deletions sale_confirm_group/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

=======================
Sale Confirmation Group
=======================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:8e2190fe6ab83943e118620c7b3be92f1cc525eabf95b57c350e131544e0f2e6
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |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/license-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fsale--workflow-lightgray.png?logo=github
:target: https://github.com/OCA/sale-workflow/tree/19.0/sale_confirm_group
:alt: OCA/sale-workflow
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/sale-workflow-19-0/sale-workflow-19-0-sale_confirm_group
: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/sale-workflow&target_branch=19.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This module allows configuring a list of groups per-company who are
granted permission to confirm sale orders:

1. button "Confirm" in sale views is always hidden for users not in
those groups
2. if users outside those groups try to confirm a SO, an error is raised

**Table of contents**

.. contents::
:local:

Configuration
=============

- go to Sales / Configuration / Settings
- scroll until you find the "Use SO Confirmation Groups" checkbox
- if you want to restrict SO confirmation permission:

- activate the checkbox
- add at least 1 security group to the list below the checkbox

- if you don't want to restrict SO confirmation permission:

- deactivate the checkbox, or remove all security groups from the list
below the checkbox

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/sale-workflow/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 <https://github.com/OCA/sale-workflow/issues/new?body=module:%20sale_confirm_group%0Aversion:%2019.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

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

Credits
=======

Authors
-------

* Camptocamp

Contributors
------------

- Silvio Gregorini <silvio.gregorini@camptocamp.com>
- Simone Orsi <simone.orsi@camptocamp.com>
- Joshua Jan <joshua@openerp.cn>

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/sale-workflow <https://github.com/OCA/sale-workflow/tree/19.0/sale_confirm_group>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
2 changes: 2 additions & 0 deletions sale_confirm_group/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import models
from . import wizards
19 changes: 19 additions & 0 deletions sale_confirm_group/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright 2025 Camptocamp SA
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)

{
"name": "Sale Confirmation Group",
"summary": "Allows configuring a list of groups per-company who are granted"
" permission to confirm sale orders",
"version": "19.0.1.0.0",
"author": "Camptocamp, Odoo Community Association (OCA) ",
"website": "https://github.com/OCA/sale-workflow",
"category": "Sale",
"license": "AGPL-3",
"depends": ["sale"],
"data": [
# Settings view
"wizards/res_config_settings.xml",
],
"installable": True,
}
64 changes: 64 additions & 0 deletions sale_confirm_group/i18n/sale_confirm_group.pot
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * sale_confirm_group
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 18.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: sale_confirm_group
#: model:ir.model,name:sale_confirm_group.model_res_company
msgid "Companies"
msgstr ""

#. module: sale_confirm_group
#: model:ir.model,name:sale_confirm_group.model_res_config_settings
msgid "Config Settings"
msgstr ""

#. module: sale_confirm_group
#: model_terms:ir.ui.view,arch_db:sale_confirm_group.sale_res_config_settings_view_form_inherit
msgid ""
"If the checkbox is flagged and at least 1 group is selected, SO confirmation"
" will be allowed to such groups only. This is company-specific."
msgstr ""

#. module: sale_confirm_group
#: model:ir.model.fields,field_description:sale_confirm_group.field_res_company__sale_confirmation_group_ids
#: model:ir.model.fields,field_description:sale_confirm_group.field_res_config_settings__sale_confirmation_group_ids
msgid "Sale Confirmation Group"
msgstr ""

#. module: sale_confirm_group
#: model:ir.model,name:sale_confirm_group.model_sale_order
msgid "Sales Order"
msgstr ""

#. module: sale_confirm_group
#: model_terms:ir.ui.view,arch_db:sale_confirm_group.sale_res_config_settings_view_form_inherit
msgid "Use SO Confirmation Groups"
msgstr ""

#. module: sale_confirm_group
#: model:ir.model.fields,field_description:sale_confirm_group.field_res_company__use_sale_confirmation_groups
#: model:ir.model.fields,field_description:sale_confirm_group.field_res_config_settings__use_sale_confirmation_groups
msgid "Use Sale Confirmation Groups"
msgstr ""

#. module: sale_confirm_group
#. odoo-python
#: code:addons/sale_confirm_group/models/sale_order.py:0
msgid "User %s cannot confirm Sale(s) %s"
msgstr ""

#. module: sale_confirm_group
#: model:ir.model.fields,field_description:sale_confirm_group.field_sale_order__user_can_confirm
msgid "User Can Confirm"
msgstr ""
2 changes: 2 additions & 0 deletions sale_confirm_group/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import res_company
from . import sale_order
16 changes: 16 additions & 0 deletions sale_confirm_group/models/res_company.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright 2025 Camptocamp SA
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)

from odoo import fields, models


class Company(models.Model):
_inherit = "res.company"

use_sale_confirmation_groups = fields.Boolean()
sale_confirmation_group_ids = fields.Many2many(
"res.groups",
relation="res_company_2_res_groups_sales_confirm_rel",
column1="company_id",
column2="group_id",
)
92 changes: 92 additions & 0 deletions sale_confirm_group/models/sale_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Copyright 2025 Camptocamp SA
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)

from odoo import api, exceptions, fields, models


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

user_can_confirm = fields.Boolean(
compute="_compute_user_can_confirm", compute_sudo=True
)

@api.depends(
# Keep these dotted fields as dependencies, because:
# - chances of them being updated very often (leading to lots of records cache
# invalidations and field recomputation) are quite low
# - removing them in favor of ``company_id`` alone (or no deps at all) means
# we'd have to invalidate the records cache manually when we need to check
# whether a user can actually confirm a sale order (to avoid using an outdated
# value for this field, since settings may have been updated in the meanwhile)
"company_id.use_sale_confirmation_groups",
"company_id.sale_confirmation_group_ids.user_ids",
)
@api.depends_context("uid")
def _compute_user_can_confirm(self):
user = self.env.user
for company, sales in self.grouped("company_id").items():
if not company.use_sale_confirmation_groups:
sales.user_can_confirm = True
elif not (groups := company.sale_confirmation_group_ids):
sales.user_can_confirm = True
else:
sales.user_can_confirm = (
user in groups.with_context(active_test=False).user_ids
)

def action_confirm(self):
# OVERRIDE: prevent unallowed users from confirming a sale order,
# and raise a ``ValidationError`` instead

# 1- check skipped: exit early
if self._skip_check_user_can_confirm():
return super().action_confirm()

# 2- all SO in ``self`` can be confirmed
elif (can_confirm := self._filter_user_can_confirm()) == self:
return super().action_confirm()

# 3- at least 1 SO cannot be confirmed by the user
raise exceptions.ValidationError(
self.env._(
"User %(user)s cannot confirm Sale(s) %(sales)s",
user=self.env.user.name,
sales=", ".join(
(self - can_confirm).mapped(lambda s: f"'{s.display_name}'")
),
)
)

def _skip_check_user_can_confirm(self) -> bool:
"""Defines whether checks upon user permissions to confirm should be skipped

Set context key "skip_check_user_can_confirm" as ``True`` to skip the checks.
"""
return bool(self.env.context.get("skip_check_user_can_confirm", self.env.su))

def _filter_user_can_confirm(self) -> "SaleOrder":
"""Returns the subset of records that the current user can confirm

Hook method, can be overridden
"""
return self.filtered("user_can_confirm")

@api.model
def _get_view(self, view_id=None, view_type="form", **options):
# OVERRIDE: hide the SO ``action_confirm`` button to users who shouldn't be
# allowed confirmation
# NB: we override ``sale.order._get_view()``, not ``sale.order.get_view()``,
# because:
# - the result of ``sale.order._get_view()`` is cached
# - the result of ``sale.order._get_view()`` is updated by method
# ``ir.ui.view._add_missing_fields()`` to automatically add fields needed for
# the evaluation of nodes' attributes (required, invisible, etc...),
# so we don't need to do it here
arch, view = super()._get_view(view_id=view_id, view_type=view_type, **options)
for node in arch.xpath("//button[@name='action_confirm']"):
if value := node.get("invisible"):
node.set("invisible", f"not user_can_confirm or ({value})")
else:
node.set("invisible", "not user_can_confirm")
return arch, view
3 changes: 3 additions & 0 deletions sale_confirm_group/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
7 changes: 7 additions & 0 deletions sale_confirm_group/readme/CONFIGURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
* go to Sales / Configuration / Settings
* scroll until you find the "Use SO Confirmation Groups" checkbox
* if you want to restrict SO confirmation permission:
* activate the checkbox
* add at least 1 security group to the list below the checkbox
* if you don't want to restrict SO confirmation permission:
* deactivate the checkbox, or remove all security groups from the list below the checkbox
3 changes: 3 additions & 0 deletions sale_confirm_group/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- Silvio Gregorini \<silvio.gregorini@camptocamp.com\>
- Simone Orsi \<simone.orsi@camptocamp.com\>
- Joshua Jan \<joshua@openerp.cn\>
4 changes: 4 additions & 0 deletions sale_confirm_group/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
This module allows configuring a list of groups per-company who are granted permission to confirm sale orders:

1. button "Confirm" in sale views is always hidden for users not in those groups
2. if users outside those groups try to confirm a SO, an error is raised
Binary file added sale_confirm_group/static/description/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading