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
38 changes: 24 additions & 14 deletions sale_tier_validation/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ To configure this module, you need to:
1. Go to *Settings > Technical > Tier Validations > Tier Definition*.
2. Create as many tiers as you want for Sale Order model.

If necessary, update the "Block Printing of Unvalidated Quotations"
under *Sales > Configuration > Settings* to block the printing of
quotation when the order has yet to be validated (disabled by default).

Usage
=====

Expand All @@ -63,18 +67,18 @@ To use this module, you need to:

Additional features:

- You can filter the SOs requesting your review through the filter
*Needs my Review*.
- User with rights to confirm the SO (validate all tiers that would be
generated) can directly do the operation, this is, there is no need
for her/him to request a validation.
- You can filter the SOs requesting your review through the filter
*Needs my Review*.
- User with rights to confirm the SO (validate all tiers that would be
generated) can directly do the operation, this is, there is no need
for her/him to request a validation.

Known issues / Roadmap
======================

- The sales order, when moved to the state sent, will still send the
email even if the validation is not approved by the corresponding
tier. Code to consider this particular case is not developed.
- The sales order, when moved to the state sent, will still send the
email even if the validation is not approved by the corresponding
tier. Code to consider this particular case is not developed.

Bug Tracker
===========
Expand All @@ -97,15 +101,21 @@ Authors
Contributors
------------

- Mayank Gosai <mgosai@opensourceintegrators.com>
- `Tecnativa <https://www.tecnativa.com>`__:
- Mayank Gosai <mgosai@opensourceintegrators.com>
- `Tecnativa <https://www.tecnativa.com>`__:

- Sergio Teruel

- Tharathip Chaweewongphan <tharathipc@ecosoft.co.th>
- `Dynapps <https://www.dynapps.eu>`__:

- Bert Van Groenendael <bert.vangroenendael@dynapps.eu>

- Sergio Teruel
- `Quartile <https://www.quartile.co>`__:

- Tharathip Chaweewongphan <tharathipc@ecosoft.co.th>
- `Dynapps <https://www.dynapps.eu>`__:
- Aung Ko Ko Lin

- Bert Van Groenendael <bert.vangroenendael@dynapps.eu>
- Panithan kongthong <panithank@ecosoft.co.th>

Maintainers
-----------
Expand Down
1 change: 1 addition & 0 deletions sale_tier_validation/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from . import models
from . import report
6 changes: 5 additions & 1 deletion sale_tier_validation/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,9 @@
"application": False,
"installable": True,
"depends": ["sale", "base_tier_validation"],
"data": ["data/mail_data.xml", "views/sale_order_view.xml"],
"data": [
"data/mail_data.xml",
"views/sale_order_view.xml",
"views/res_config_settings_views.xml",
],
}
2 changes: 2 additions & 0 deletions sale_tier_validation/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@

from . import sale_order
from . import tier_definition
from . import res_company
from . import res_config_settings
15 changes: 15 additions & 0 deletions sale_tier_validation/models/res_company.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2024 Quartile (https://www.quartile.co)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import fields, models


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

sale_report_print_block = fields.Boolean(
help=(
"Block the printing of the sale order report if the order is not "
"validated."
)
)
16 changes: 16 additions & 0 deletions sale_tier_validation/models/res_config_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright 2024 Quartile (https://www.quartile.co)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import fields, models


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

sale_report_print_block = fields.Boolean(
related="company_id.sale_report_print_block",
readonly=False,
help=(
"Block the printing of the sale order report if the order is not validated."
),
)
4 changes: 4 additions & 0 deletions sale_tier_validation/readme/CONFIGURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@ To configure this module, you need to:
1. Go to *Settings \> Technical \> Tier Validations \> Tier
Definition*.
2. Create as many tiers as you want for Sale Order model.

If necessary, update the "Block Printing of Unvalidated Quotations" under *Sales \>
Configuration \> Settings* to block the printing of quotation when the order has yet
to be validated (disabled by default).
3 changes: 3 additions & 0 deletions sale_tier_validation/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
- Tharathip Chaweewongphan \<<tharathipc@ecosoft.co.th>\>
- [Dynapps](https://www.dynapps.eu):
- Bert Van Groenendael \<<bert.vangroenendael@dynapps.eu>\>
- [Quartile](https://www.quartile.co):
- Aung Ko Ko Lin
- Panithan kongthong \<<panithank@ecosoft.co.th>\>
2 changes: 2 additions & 0 deletions sale_tier_validation/report/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import sale_report
from . import sale_report_raw
27 changes: 27 additions & 0 deletions sale_tier_validation/report/sale_report.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright 2024 Quartile (https://www.quartile.co)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import _, api, models
from odoo.exceptions import UserError


class ReportSaleOrder(models.AbstractModel):
_name = "report.sale.report_saleorder"
_description = "Sale Order Report"

@api.model
def _get_report_values(self, docids, data=None):
docs = self.env["sale.order"].browse(docids)
for order in docs:
if not order.company_id.sale_report_print_block:
continue
if order.need_validation or (order.review_ids and not order.validated):
raise UserError(
_("Quotation printing is blocked until the order is approved.")
)
return {
"doc_ids": docids,
"doc_model": "sale.order",
"docs": docs,
"data": data,
}
27 changes: 27 additions & 0 deletions sale_tier_validation/report/sale_report_raw.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Copyright 2025 Ecosoft Co., Ltd (https://ecosoft.co.th)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)

from odoo import _, api, models
from odoo.exceptions import UserError


class ReportSaleOrderRaw(models.AbstractModel):
_name = "report.sale.report_saleorder_raw"
_description = "Sale Order Report Raw"

@api.model
def _get_report_values(self, docids, data=None):
docs = self.env["sale.order"].browse(docids)
for order in docs:
if not order.company_id.sale_report_print_block:
continue
if order.need_validation or (order.review_ids and not order.validated):
raise UserError(
_("Quotation printing is blocked until the order is approved.")
)
return {
"doc_ids": docids,
"doc_model": "sale.order",
"docs": docs,
"data": data,
}
8 changes: 8 additions & 0 deletions sale_tier_validation/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,9 @@ <h1><a class="toc-backref" href="#toc-entry-2">Configuration</a></h1>
<li>Go to <em>Settings &gt; Technical &gt; Tier Validations &gt; Tier Definition</em>.</li>
<li>Create as many tiers as you want for Sale Order model.</li>
</ol>
<p>If necessary, update the “Block Printing of Unvalidated Quotations”
under <em>Sales &gt; Configuration &gt; Settings</em> to block the printing of
quotation when the order has yet to be validated (disabled by default).</p>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#toc-entry-3">Usage</a></h1>
Expand Down Expand Up @@ -457,6 +460,11 @@ <h2><a class="toc-backref" href="#toc-entry-8">Contributors</a></h2>
<li>Bert Van Groenendael &lt;<a class="reference external" href="mailto:bert.vangroenendael&#64;dynapps.eu">bert.vangroenendael&#64;dynapps.eu</a>&gt;</li>
</ul>
</li>
<li><a class="reference external" href="https://www.quartile.co">Quartile</a>:<ul>
<li>Aung Ko Ko Lin</li>
</ul>
</li>
<li>Panithan kongthong &lt;<a class="reference external" href="mailto:panithank&#64;ecosoft.co.th">panithank&#64;ecosoft.co.th</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
Expand Down
79 changes: 74 additions & 5 deletions sale_tier_validation/tests/test_tier_validation.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Copyright 2020 Sergio Teruel <sergio.teruel@tecnativa.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from odoo.exceptions import ValidationError
from odoo.exceptions import UserError, ValidationError
from odoo.tests import common, tagged

from odoo.addons.base.tests.common import DISABLED_MAIL_CONTEXT
Expand All @@ -11,7 +11,7 @@ class TestSaleTierValidation(common.TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.env = cls.env(context=dict(cls.env.context, **DISABLED_MAIL_CONTEXT))
cls.env = cls.env["base"].with_context(**DISABLED_MAIL_CONTEXT).env
# Get sale order model
cls.so_model = cls.env.ref("sale.model_sale_order")

Expand Down Expand Up @@ -71,8 +71,77 @@ def test_validation_sale_order(self):
)
with self.assertRaises(ValidationError):
so.action_confirm()
so.order_line.price_unit = 45
so.request_validation()
so.with_user(self.test_user_1).validate_tier()
so.order_line.price_unit = 55
reviews = so.request_validation()
self.assertTrue(reviews)
record = so.with_user(self.test_user_1.id)
record.invalidate_model()
record.validate_tier()
so.action_confirm()
self.assertEqual(so.state, "sale")

def test_block_print_unvalidated_sale_order(self):
so = self.env["sale.order"].create(
{
"partner_id": self.customer.id,
"order_line": [
(
0,
0,
{
"name": "Test line",
"product_id": self.product.id,
"product_uom_qty": 1,
"product_uom": self.product.uom_id.id,
"price_unit": self.product.list_price,
},
)
],
}
)
so.company_id.sale_report_print_block = True
report = self.env["report.sale.report_saleorder"]
# Attempt to render the report before validation
with self.assertRaises(UserError):
report._get_report_values(docids=[so.id])
so.request_validation()
with self.assertRaises(UserError):
report._get_report_values(docids=[so.id])
record = so.with_user(self.test_user_1.id)
record.invalidate_model()
record.validate_tier()
# Attempt to render the report after validation
report._get_report_values(docids=[so.id])

def test_block_print_unvalidated_sale_order_raw(self):
so = self.env["sale.order"].create(
{
"partner_id": self.customer.id,
"order_line": [
(
0,
0,
{
"name": "Test line",
"product_id": self.product.id,
"product_uom_qty": 1,
"product_uom": self.product.uom_id.id,
"price_unit": self.product.list_price,
},
)
],
}
)
so.company_id.sale_report_print_block = True
report = self.env["report.sale.report_saleorder_raw"]
# Attempt to render the report before validation
with self.assertRaises(UserError):
report._get_report_values(docids=[so.id])
so.request_validation()
with self.assertRaises(UserError):
report._get_report_values(docids=[so.id])
record = so.with_user(self.test_user_1.id)
record.invalidate_model()
record.validate_tier()
# Attempt to render the report after validation
report._get_report_values(docids=[so.id])
21 changes: 21 additions & 0 deletions sale_tier_validation/views/res_config_settings_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record model="ir.ui.view" id="sale_config_settings_form_view">
<field name="name">res.config.settings.form</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="sale.res_config_settings_view_form" />
<field name="arch" type="xml">
<xpath
expr="//block[@name='quotation_order_setting_container']/setting[@id='proforma_configuration']"
position="after"
>
<setting
id="block_print_sale_order"
help="Block the printing of the sale order report if the order is not validated."
>
<field name="sale_report_print_block" />
</setting>
</xpath>
</field>
</record>
</odoo>