Skip to content

[16.0][ADD] sale_order_line_discount_switch: add module#10

Open
Aldeigja wants to merge 1 commit into
16.0from
16.0-t5378-sale_order_line_discount_switch-add-module
Open

[16.0][ADD] sale_order_line_discount_switch: add module#10
Aldeigja wants to merge 1 commit into
16.0from
16.0-t5378-sale_order_line_discount_switch-add-module

Conversation

@Aldeigja

@Aldeigja Aldeigja commented Apr 23, 2026

Copy link
Copy Markdown

Summary by CodeRabbit

  • New Features

    • Added ability to switch between percentage and fixed-amount discounts on individual sales order lines, with inactive discount values automatically hidden and cleared.
  • Documentation

    • Added comprehensive guides covering configuration, usage, and context for the new discount switching functionality.
  • Tests

    • Added automated test coverage for discount mode switching and calculations.

@coderabbitai

coderabbitai Bot commented Apr 23, 2026

Copy link
Copy Markdown

Walkthrough

This PR introduces a new Odoo module sale_order_line_discount_switch that enables toggling between percentage-based and fixed-amount discount modes on individual sales order lines, with corresponding model extensions, UI views, test coverage, documentation, and packaging configuration.

Changes

Cohort / File(s) Summary
Module Foundation
sale_order_line_discount_switch/__manifest__.py, sale_order_line_discount_switch/__init__.py
Module metadata, dependencies on sale_fixed_discount, data file registration, post-init hook declaration, and package initialization.
Discount Logic & Hooks
sale_order_line_discount_switch/models/sale_order_line.py, sale_order_line_discount_switch/hooks.py, sale_order_line_discount_switch/models/__init__.py
Adds discount_mode field to sale.order.line, implements constraint to clear discount_fixed in percent mode, onchange logic for mode switching with value conversion, overridden create and write methods for auto-population, and post-init hook to migrate existing fixed discounts.
UI & Views
sale_order_line_discount_switch/views/sale_order_views.xml
Inherited sale order form view with conditional field visibility: hides discount_fixed in percent mode and standard discount fields in fixed mode.
Test Suite
sale_order_line_discount_switch/tests/test_sale_order_line_discount_switch.py, sale_order_line_discount_switch/tests/__init__.py
Comprehensive test cases verifying percent/fixed mode defaults, field synchronization, mode switching behavior, constraint validation, and write-based conversions.
Documentation
README.md, sale_order_line_discount_switch/README.rst, sale_order_line_discount_switch/readme/*, sale_order_line_discount_switch/static/description/index.html
Main README update, module documentation (DESCRIPTION, USAGE, CONFIGURE, CONTEXT), contributor attribution, and static HTML description.
Package Setup
setup/_metapackage/setup.py, setup/sale_order_line_discount_switch/setup.py, setup/sale_order_line_discount_switch/odoo/addons/sale_order_line_discount_switch
Metapackage dependency addition, new addon-specific setup.py with setuptools-odoo integration, and package path reference file.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and specifically describes the main change: adding a new Odoo module for sale order line discount switching functionality.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@sale_order_line_discount_switch/models/sale_order_line.py`:
- Line 80: Replace the confusing conditional "if not line.discount_mode ==
'fixed':" with the clearer inequality operator by changing the condition to use
"!="; locate the check on line.discount_mode in the sale order line logic (the
conditional that branches on discount_mode) and update it to "if
line.discount_mode != 'fixed':" so readability and static-analysis warnings are
resolved.
- Around line 26-27: Summary: The fallback for rounding is incorrect because
when prec is 0 the current expression yields 1.0 instead of using the intended
fallback. Fix: change the logic around precision_get and rounding (the lines
using precision_get("Product Price") storing to prec and the subsequent rounding
calculation) to explicitly treat None (or missing) as the fallback case; e.g.
call precision_get into prec and then set rounding = 10 ** -prec when prec is
not None, otherwise use the fallback 0.0001. Ensure you only treat None/missing
as the fallback so a valid prec == 0 produces the correct 10**-0 result (1.0) if
that is intended, or if you want 0.0001 for zero decimals, explicitly check prec
== 0 and choose the fallback accordingly.
- Around line 82-84: Replace the hardcoded tolerance 1e-10 with the project's
decimal precision: retrieve the "Product Price" precision via
self.env['decimal.precision'].precision_get('Product Price') and pass it to
float_is_zero using the precision_digits argument (e.g.,
precision_digits=product_price_digits) for both checks of line.price_unit and
line.discount; update the call(s) at the float_is_zero(...) site(s) in
sale_order_line.py so they use that retrieved precision for consistency with
other uses in the file.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8d9581b7-ba69-4c8b-91a8-4ec369253105

📥 Commits

Reviewing files that changed from the base of the PR and between 4b5ee6d and 1bbf2d1.

⛔ Files ignored due to path filters (1)
  • sale_order_line_discount_switch/static/description/icon.png is excluded by !**/*.png
📒 Files selected for processing (19)
  • README.md
  • sale_order_line_discount_switch/README.rst
  • sale_order_line_discount_switch/__init__.py
  • sale_order_line_discount_switch/__manifest__.py
  • sale_order_line_discount_switch/hooks.py
  • sale_order_line_discount_switch/models/__init__.py
  • sale_order_line_discount_switch/models/sale_order_line.py
  • sale_order_line_discount_switch/readme/CONFIGURE.rst
  • sale_order_line_discount_switch/readme/CONTEXT.rst
  • sale_order_line_discount_switch/readme/CONTRIBUTORS.rst
  • sale_order_line_discount_switch/readme/DESCRIPTION.rst
  • sale_order_line_discount_switch/readme/USAGE.rst
  • sale_order_line_discount_switch/static/description/index.html
  • sale_order_line_discount_switch/tests/__init__.py
  • sale_order_line_discount_switch/tests/test_sale_order_line_discount_switch.py
  • sale_order_line_discount_switch/views/sale_order_views.xml
  • setup/_metapackage/setup.py
  • setup/sale_order_line_discount_switch/odoo/addons/sale_order_line_discount_switch
  • setup/sale_order_line_discount_switch/setup.py

Comment on lines +26 to +27
prec = self.env["decimal.precision"].precision_get("Product Price")
rounding = 10**-prec if prec else 0.0001

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Bug: Incorrect fallback when precision is zero.

When prec is 0, the expression 10**-prec evaluates to 10**0 = 1.0, not 0.0001. The condition if prec else only triggers when prec is falsy (i.e., None or 0), but precision_get returns 0 for zero decimal places, making the else branch unreachable for that case.

🐛 Proposed fix
-        rounding = 10**-prec if prec else 0.0001
+        rounding = 10**-prec if prec is not None else 0.0001

Or more defensively, handle zero precision explicitly:

-        rounding = 10**-prec if prec else 0.0001
+        rounding = 10**-prec if prec and prec > 0 else 0.0001
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sale_order_line_discount_switch/models/sale_order_line.py` around lines 26 -
27, Summary: The fallback for rounding is incorrect because when prec is 0 the
current expression yields 1.0 instead of using the intended fallback. Fix:
change the logic around precision_get and rounding (the lines using
precision_get("Product Price") storing to prec and the subsequent rounding
calculation) to explicitly treat None (or missing) as the fallback case; e.g.
call precision_get into prec and then set rounding = 10 ** -prec when prec is
not None, otherwise use the fallback 0.0001. Ensure you only treat None/missing
as the fallback so a valid prec == 0 produces the correct 10**-0 result (1.0) if
that is intended, or if you want 0.0001 for zero decimals, explicitly check prec
== 0 and choose the fallback accordingly.

)
res = super().write(vals)
for line in lines_to_fill_fixed:
if not line.discount_mode == "fixed":

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Use != instead of not ... == for clarity.

Static analysis correctly flags this as less readable.

♻️ Proposed fix
-            if not line.discount_mode == "fixed":
+            if line.discount_mode != "fixed":
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if not line.discount_mode == "fixed":
if line.discount_mode != "fixed":
🧰 Tools
🪛 Ruff (0.15.10)

[warning] 80-80: Use line.discount_mode != "fixed" instead of not line.discount_mode == "fixed"

Replace with != operator

(SIM201)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sale_order_line_discount_switch/models/sale_order_line.py` at line 80,
Replace the confusing conditional "if not line.discount_mode == 'fixed':" with
the clearer inequality operator by changing the condition to use "!="; locate
the check on line.discount_mode in the sale order line logic (the conditional
that branches on discount_mode) and update it to "if line.discount_mode !=
'fixed':" so readability and static-analysis warnings are resolved.

Comment on lines +82 to +84
if float_is_zero(
line.price_unit, precision_rounding=1e-10
) or float_is_zero(line.discount, precision_rounding=1e-10):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider using consistent precision handling.

The hardcoded 1e-10 differs from the decimal precision approach used elsewhere in this file (lines 26-27, 48, 86). For consistency, consider using the "Product Price" precision or at minimum documenting why a different tolerance is needed here.

♻️ Proposed fix for consistency
+        prec = self.env["decimal.precision"].precision_get("Product Price")
+        rounding = 10**-prec if prec and prec > 0 else 0.0001
         for line in lines_to_fill_fixed:
             if line.discount_mode != "fixed":
                 continue
-            if float_is_zero(
-                line.price_unit, precision_rounding=1e-10
-            ) or float_is_zero(line.discount, precision_rounding=1e-10):
+            if float_is_zero(
+                line.price_unit, precision_rounding=rounding
+            ) or float_is_zero(line.discount, precision_rounding=rounding):
                 continue
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@sale_order_line_discount_switch/models/sale_order_line.py` around lines 82 -
84, Replace the hardcoded tolerance 1e-10 with the project's decimal precision:
retrieve the "Product Price" precision via
self.env['decimal.precision'].precision_get('Product Price') and pass it to
float_is_zero using the precision_digits argument (e.g.,
precision_digits=product_price_digits) for both checks of line.price_unit and
line.discount; update the call(s) at the float_is_zero(...) site(s) in
sale_order_line.py so they use that retrieved precision for consistency with
other uses in the file.

@tendil tendil changed the title [ADD] sale_order_line_discount_switch: add module [16.0][ADD] sale_order_line_discount_switch: add module Apr 23, 2026
@@ -0,0 +1 @@
* Cetmix

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Cetmix:
    • Ivan Sokolov
    • George Smirnov

@@ -0,0 +1,7 @@
Teams that use fixed monetary discounts on some order lines and standard percentage

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the file formats in the readme folder should be .md, not .rst

_inherit = "sale.order.line"

discount_mode = fields.Selection(
selection=[

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use the same approach here as you did there - https://arc.net/l/quote/pehcjdwq

("fixed", "Fixed amount"),
],
string="Discount type",
default="percent",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants