Skip to content

Commit

Permalink
[IMP] rma_sale: Display the allowed quantity to return in the RMA wizard
Browse files Browse the repository at this point in the history
- Display the allowed quantity to return
- Simplify data encoding by adding a button to select/deselect all lines
- Ensure that the quantity to return is always less than or equal to the allowed quantity
  • Loading branch information
sbejaoui committed Jul 12, 2024
1 parent 3436ec6 commit eb0bede
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 2 deletions.
2 changes: 2 additions & 0 deletions rma_sale/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ Contributors

* Chafique Delli <[email protected]>
* Giovanni Serra - Ooops <[email protected]>
* Souheil Bejaoui - ACSONE SA/NV <[email protected]>
* Jacques-Etienne Baudoux - BCIM <[email protected]>

Maintainers
~~~~~~~~~~~
Expand Down
1 change: 1 addition & 0 deletions rma_sale/models/sale.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def _prepare_rma_wizard_line_vals(self, data):
return {
"product_id": data["product"].id,
"quantity": data["quantity"],
"allowed_quantity": data["quantity"],
"sale_line_id": data["sale_line_id"].id,
"uom_id": data["uom"].id,
"picking_id": data["picking"] and data["picking"].id,
Expand Down
2 changes: 2 additions & 0 deletions rma_sale/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@

* Chafique Delli <[email protected]>
* Giovanni Serra - Ooops <[email protected]>
* Souheil Bejaoui - ACSONE SA/NV <[email protected]>
* Jacques-Etienne Baudoux - BCIM <[email protected]>
2 changes: 2 additions & 0 deletions rma_sale/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,8 @@ <h2><a class="toc-backref" href="#toc-entry-6">Contributors</a></h2>
</li>
<li>Chafique Delli &lt;<a class="reference external" href="mailto:chafique.delli&#64;akretion.com">chafique.delli&#64;akretion.com</a>&gt;</li>
<li>Giovanni Serra - Ooops &lt;<a class="reference external" href="mailto:giovanni&#64;ooops404.com">giovanni&#64;ooops404.com</a>&gt;</li>
<li>Souheil Bejaoui - ACSONE SA/NV &lt;<a class="reference external" href="mailto:souheil.bejaoui&#64;acsone.eu.com">souheil.bejaoui&#64;acsone.eu.com</a>&gt;</li>
<li>Jacques-Etienne Baudoux - BCIM &lt;<a class="reference external" href="mailto:je&#64;bcim.be">je&#64;bcim.be</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
Expand Down
1 change: 1 addition & 0 deletions rma_sale/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@

from . import test_rma_sale
from . import test_rma_sale_portal
from . import test_rma_sale_allowed_qty
1 change: 1 addition & 0 deletions rma_sale/tests/test_rma_sale.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ def test_create_rma_from_so_portal_user(self):
"product_id": order.order_line.product_id.id,
"sale_line_id": order.order_line.id,
"quantity": order.order_line.product_uom_qty,
"allowed_quantity": order.order_line.qty_delivered,
"uom_id": order.order_line.product_uom.id,
"picking_id": order.picking_ids[0].id,
"operation_id": operation.id,
Expand Down
110 changes: 110 additions & 0 deletions rma_sale/tests/test_rma_sale_allowed_qty.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Copyright 2024 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import Command
from odoo.exceptions import ValidationError
from odoo.tests.common import TransactionCase


class TestRmaSaleQuantityAllowed(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.warehouse = cls.env.ref("stock.warehouse0")
cls.loc_stock = cls.warehouse.lot_stock_id
cls.partner1 = cls.env["res.partner"].create({"name": "Partner"})
cls.p1 = cls.env["product.product"].create(
{"name": "Unittest P1", "type": "product"}
)
cls.so = cls.env["sale.order"].create(
{
"partner_id": cls.partner1.id,
"order_line": [
Command.create(
{
"name": cls.p1.name,
"product_id": cls.p1.id,
"product_uom_qty": 5,
"price_unit": 50,
},
)
],
}
)
cls.env["stock.quant"].with_context(inventory_mode=True).create(
{
"product_id": cls.p1.id,
"inventory_quantity": 10,
"location_id": cls.loc_stock.id,
}
)._apply_inventory()
cls.so.action_confirm()
cls.picking = cls.so.picking_ids[0]

def _get_rma_wizard(self):
action = self.so.action_create_rma()
return self.env[action.get("res_model")].browse(action.get("res_id"))

def _deliver(self, qty):
self.picking.move_line_ids.qty_done = qty
self.picking._action_done()
self.assertEqual(self.picking.state, "done")
self.assertEqual(self.so.order_line.qty_delivered, qty)

def test_1(self):
"""
Test rma wizard:
- fully deliver the so
- open rma wizard
expected:
- qty proposed: 5
- allowed qty 5
- qty 0 if is_return_all = False
"""
self._deliver(5)
wizard = self._get_rma_wizard()
self.assertEqual(len(wizard.line_ids), 1)
self.assertEqual(wizard.line_ids.quantity, 5)
self.assertEqual(wizard.line_ids.allowed_quantity, 5)
wizard.is_return_all = False
self.assertEqual(wizard.line_ids.quantity, 0)
wizard.is_return_all = True
self.assertEqual(wizard.line_ids.quantity, 5)

def test_2(self):
"""
Test rma wizard:
- partially deliver the so
- open rma wizard
expected:
- qty proposed: 3
- allowed qty 3
- qty 0 if is_return_all = False
"""
self._deliver(3)
wizard = self._get_rma_wizard()
self.assertEqual(len(wizard.line_ids), 1)
self.assertEqual(wizard.line_ids.quantity, 3)
self.assertEqual(wizard.line_ids.allowed_quantity, 3)
wizard.is_return_all = False
self.assertEqual(wizard.line_ids.quantity, 0)
wizard.is_return_all = True
self.assertEqual(wizard.line_ids.quantity, 3)

def test_3(self):
"""
Test rma wizard:
Try to return more than the allowed qty
"""
self._deliver(3)
wizard = self._get_rma_wizard()
self.assertEqual(len(wizard.line_ids), 1)
self.assertEqual(wizard.line_ids.quantity, 3)
self.assertEqual(wizard.line_ids.allowed_quantity, 3)
with self.assertRaises(
ValidationError, msg="You can't exceed the allowed quantity"
):
wizard.line_ids.quantity = 5
wizard.line_ids.quantity = 1
36 changes: 36 additions & 0 deletions rma_sale/wizard/sale_order_rma_wizard.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# Copyright 2020 Tecnativa - Ernesto Tejeda
# Copyright 2022 Tecnativa - Víctor Martínez
# Copyright 2024 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import SUPERUSER_ID, _, api, fields, models
from odoo.exceptions import ValidationError
from odoo.tools.float_utils import float_compare


class SaleOrderRmaWizard(models.TransientModel):
Expand Down Expand Up @@ -46,6 +49,7 @@ def _domain_location_id(self):
custom_description = fields.Text(
help="Values coming from portal RMA request form custom fields",
)
is_return_all = fields.Boolean(string="Return All?", default=True)

def create_rma(self, from_portal=False):
self.ensure_one()
Expand Down Expand Up @@ -126,7 +130,11 @@ class SaleOrderLineRmaWizard(models.TransientModel):
quantity = fields.Float(
digits="Product Unit of Measure",
required=True,
compute="_compute_quantity",
store=True,
readonly=False,
)
allowed_quantity = fields.Float(digits="Product Unit of Measure", readonly=True)
uom_id = fields.Many2one(
comodel_name="uom.uom",
string="Unit of Measure",
Expand All @@ -151,6 +159,14 @@ class SaleOrderLineRmaWizard(models.TransientModel):
)
description = fields.Text()

@api.depends("wizard_id.is_return_all", "allowed_quantity")
def _compute_quantity(self):
for rec in self:
if not rec.wizard_id.is_return_all:
rec.quantity = 0
else:
rec.quantity = rec.allowed_quantity

@api.onchange("product_id")
def onchange_product_id(self):
self.picking_id = False
Expand Down Expand Up @@ -187,6 +203,26 @@ def _compute_allowed_picking_ids(self):
lambda x: x.state == "done"
)

@api.constrains("quantity", "allowed_quantity")
def _check_quantity(self):
precision = self.env["decimal.precision"].precision_get(
"Product Unit of Measure"
)
for rec in self:
if (
float_compare(
rec.quantity, rec.allowed_quantity, precision_digits=precision
)
== 1
):
raise ValidationError(
_(
"You can't exceed the allowed quantity for returning product "
"%(product)s.",
product=rec.product_id.display_name,
)
)

def _prepare_rma_values(self):
self.ensure_one()
partner_shipping = (
Expand Down
2 changes: 2 additions & 0 deletions rma_sale/wizard/sale_order_rma_wizard_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
<field name="arch" type="xml">
<form>
<group>
<field name="is_return_all" widget="boolean_toggle" />
<field name="line_ids" nolabel="1" colspan="2">
<tree editable="bottom">
<field name="order_id" invisible="1" />
<field name="allowed_product_ids" invisible="1" />
<field name="product_id" options="{'no_create': True}" />
<field name="quantity" />
<field name="allowed_quantity" />
<field name="uom_category_id" invisible="1" />
<field
name="uom_id"
Expand Down
3 changes: 1 addition & 2 deletions rma_sale_mrp/tests/test_rma_sale_mrp.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,8 @@ def test_create_rma_from_so(self):
wizard_id = order.action_create_rma()["res_id"]
wizard = self.env["sale.order.rma.wizard"].browse(wizard_id)
self.assertEqual(wizard.line_ids.quantity, 0)
wizard.line_ids.quantity = 1
with self.assertRaises(ValidationError):
wizard.create_and_open_rma()
wizard.line_ids.quantity = 1

def test_report_rma(self):
wizard = self._rma_sale_wizard(self.sale_order)
Expand Down

0 comments on commit eb0bede

Please sign in to comment.