Skip to content

Commit e912c52

Browse files
committed
[IMP] rma: allow standard refund
1 parent 4d23c6e commit e912c52

File tree

9 files changed

+171
-3
lines changed

9 files changed

+171
-3
lines changed

rma/models/rma.py

+22-2
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,14 @@ def _domain_location_id(self):
329329
show_create_refund = fields.Boolean(
330330
string="Show Create refund Button", compute="_compute_show_refund_replace"
331331
)
332+
return_product_id = fields.Many2one(
333+
"product.product",
334+
help="Product to be returned if it's different from the originally delivered "
335+
"item.",
336+
)
337+
different_return_product = fields.Boolean(
338+
related="operation_id.different_return_product"
339+
)
332340

333341
@api.depends("operation_id.action_create_receipt", "state", "reception_move_id")
334342
def _compute_show_create_receipt(self):
@@ -774,6 +782,7 @@ def _prepare_reception_procurement_vals(self, group=None):
774782
vals = self._prepare_common_procurement_vals(group=group)
775783
vals["route_ids"] = self.warehouse_id.rma_in_route_id
776784
vals["rma_receiver_ids"] = [(6, 0, self.ids)]
785+
vals["to_refund"] = self.operation_id.action_create_refund == "update_quantity"
777786
if self.move_id:
778787
vals["origin_returned_move_id"] = self.move_id.id
779788
return vals
@@ -787,13 +796,24 @@ def _prepare_reception_procurements(self):
787796
group = rma.procurement_group_id
788797
if not group:
789798
group = group_model.create(rma._prepare_procurement_group_vals())
799+
product = self.product_id
800+
if self.different_return_product:
801+
if not self.return_product_id:
802+
raise ValidationError(
803+
_(
804+
"The selected operation requires a return product different"
805+
" from the originally delivered item. Please select the "
806+
"product to return."
807+
)
808+
)
809+
product = self.return_product_id
790810
procurements.append(
791811
group_model.Procurement(
792-
rma.product_id,
812+
product,
793813
rma.product_uom_qty,
794814
rma.product_uom,
795815
rma.location_id,
796-
rma.product_id.display_name,
816+
product.display_name,
797817
group.name,
798818
rma.company_id,
799819
rma._prepare_reception_procurement_vals(group),

rma/models/rma_operation.py

+5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ class RmaOperation(models.Model):
1919
default="automatic_on_confirm",
2020
help="Define how the receipt action should be handled.",
2121
)
22+
different_return_product = fields.Boolean(
23+
help="If checked, allows the return of a product different from the one "
24+
"originally ordered. Used if the delivery is created automatically",
25+
)
2226
action_create_delivery = fields.Selection(
2327
[
2428
("manual_on_confirm", "Manually on Confirm"),
@@ -36,6 +40,7 @@ class RmaOperation(models.Model):
3640
("automatic_on_confirm", "Automatically on Confirm"),
3741
("manual_after_receipt", "Manually After Receipt"),
3842
("automatic_after_receipt", "Automatically After Receipt"),
43+
("update_quantity", "Update Quantities"),
3944
],
4045
string="Refund Action",
4146
default="manual_after_receipt",

rma/tests/test_rma_operation.py

+54
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,13 @@ def test_07(self):
149149
ValidationError, msg="Complete the replacement information"
150150
):
151151
rma.action_confirm()
152+
rma.return_product_id = self.product_product.create(
153+
{"name": "return Product test 1", "type": "product"}
154+
)
152155
rma.action_confirm()
156+
self.assertEqual(rma.delivery_move_ids.product_id, rma.product_id)
157+
self.assertEqual(rma.reception_move_id.product_id, rma.return_product_id)
158+
self.assertEqual(rma.state, "waiting_return")
153159

154160
def test_08(self):
155161
"""test refund, manually after confirm"""
@@ -233,3 +239,51 @@ def test_13(self):
233239
rma.reception_move_id.picking_id._action_done()
234240
self.assertEqual(rma.state, "received")
235241
self.assertFalse(rma.delivery_move_ids)
242+
243+
def test_14(self):
244+
"""if the refund action is not ment to update quantity, return picking line
245+
to_refund field should be False"""
246+
self.operation.action_create_refund = "manual_after_receipt"
247+
origin_delivery = self._create_delivery()
248+
stock_return_picking_form = Form(
249+
self.env["stock.return.picking"].with_context(
250+
active_ids=origin_delivery.ids,
251+
active_id=origin_delivery.id,
252+
active_model="stock.picking",
253+
)
254+
)
255+
stock_return_picking_form.create_rma = True
256+
stock_return_picking_form.rma_operation_id = self.operation
257+
return_wizard = stock_return_picking_form.save()
258+
return_line = return_wizard.product_return_moves.filtered(
259+
lambda m, p=self.product: m.product_id == p
260+
)
261+
self.assertEqual(return_line.rma_operation_id, self.operation)
262+
picking_action = return_wizard.create_returns()
263+
reception = self.env["stock.picking"].browse(picking_action["res_id"])
264+
move = reception.move_ids.filtered(lambda m, p=self.product: m.product_id == p)
265+
self.assertFalse(move.to_refund)
266+
267+
def test_15(self):
268+
"""if the refund action is ment to update quantity, return picking line
269+
to_refund field should be True"""
270+
self.operation.action_create_refund = "update_quantity"
271+
origin_delivery = self._create_delivery()
272+
stock_return_picking_form = Form(
273+
self.env["stock.return.picking"].with_context(
274+
active_ids=origin_delivery.ids,
275+
active_id=origin_delivery.id,
276+
active_model="stock.picking",
277+
)
278+
)
279+
stock_return_picking_form.create_rma = True
280+
stock_return_picking_form.rma_operation_id = self.operation
281+
return_wizard = stock_return_picking_form.save()
282+
return_line = return_wizard.product_return_moves.filtered(
283+
lambda m, p=self.product: m.product_id == p
284+
)
285+
self.assertEqual(return_line.rma_operation_id, self.operation)
286+
picking_action = return_wizard.create_returns()
287+
reception = self.env["stock.picking"].browse(picking_action["res_id"])
288+
move = reception.move_ids.filtered(lambda m, p=self.product: m.product_id == p)
289+
self.assertTrue(move.to_refund)

rma/views/rma_operation.xml

+8-1
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,19 @@
1717
<field name="action_create_receipt" />
1818

1919
</group>
20-
<group />
20+
<group>
21+
<field
22+
name="different_return_product"
23+
widget="boolean_toggle"
24+
attrs="{'invisible': [('action_create_receipt', '=', False)]}"
25+
/>
26+
</group>
2127
<group>
2228
<field name="action_create_delivery" />
2329

2430
</group>
2531
<group />
32+
2633
<group>
2734
<field name="action_create_refund" />
2835

rma/views/rma_views.xml

+6
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,11 @@
272272
force_save="1"
273273
attrs="{'readonly': ['|', ('picking_id', '!=', False), ('state', '!=', 'draft')]}"
274274
/>
275+
<field
276+
name="return_product_id"
277+
force_save="1"
278+
attrs="{'readonly': ['|', ('picking_id', '!=', False), ('state', '!=', 'draft')], 'invisible': [('different_return_product', '=', False)], 'required': [('different_return_product', '=', True)]}"
279+
/>
275280
<field name="uom_category_id" invisible="1" />
276281
<label for="product_uom_qty" />
277282
<div class="o_row">
@@ -352,6 +357,7 @@
352357
<field name="show_create_refund" invisible="1" />
353358
<field name="show_create_return" invisible="1" />
354359
<field name="show_create_replace" invisible="1" />
360+
<field name="different_return_product" invisible="1" />
355361
<field name="can_be_split" invisible="1" />
356362
<field name="can_be_locked" invisible="1" />
357363
<field name="can_be_finished" invisible="1" />

rma_sale/models/rma.py

+7
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,10 @@ def _prepare_delivery_procurements(self, scheduled_date=None, qty=None, uom=None
175175
return super()._prepare_delivery_procurements(
176176
scheduled_date=scheduled_date, qty=qty, uom=uom
177177
)
178+
179+
def _prepare_reception_procurement_vals(self, group=None):
180+
"""This method is used only for reception and a specific RMA IN route."""
181+
vals = super()._prepare_reception_procurement_vals(group=group)
182+
if self.move_id and self.move_id.sale_line_id:
183+
vals["sale_line_id"] = self.move_id.sale_line_id.id
184+
return vals

rma_sale/tests/test_rma_sale.py

+55
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# Copyright 2023 Tecnativa - Pedro M. Baeza
44
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
55

6+
from odoo.exceptions import ValidationError
67
from odoo.tests import Form, TransactionCase
78
from odoo.tests.common import users
89

@@ -222,3 +223,57 @@ def test_report_rma(self):
222223
res = str(res[0])
223224
self.assertRegex(res, self.sale_order.name)
224225
self.assertRegex(res, operation.name)
226+
227+
def test_manual_refund_no_quantity_impact(self):
228+
"""If the operation is meant for a manual refund, the delivered quantity
229+
should not be updated."""
230+
self.operation.action_create_refund = "manual_after_receipt"
231+
order = self.sale_order
232+
order_line = order.order_line
233+
self.assertEqual(order_line.qty_delivered, 5)
234+
wizard = self._rma_sale_wizard(order)
235+
rma = self.env["rma"].browse(wizard.create_and_open_rma()["res_id"])
236+
self.assertEqual(rma.reception_move_id.sale_line_id, order_line)
237+
rma.action_confirm()
238+
rma.reception_move_id.quantity_done = rma.product_uom_qty
239+
rma.reception_move_id.picking_id._action_done()
240+
self.assertEqual(order.order_line.qty_delivered, 5)
241+
242+
def test_no_manual_refund_quantity_impact(self):
243+
"""If the operation is meant for a manual refund, the delivered quantity
244+
should not be updated."""
245+
self.operation.action_create_refund = "update_quantity"
246+
order = self.sale_order
247+
order_line = order.order_line
248+
self.assertEqual(order_line.qty_delivered, 5)
249+
wizard = self._rma_sale_wizard(order)
250+
rma = self.env["rma"].browse(wizard.create_and_open_rma()["res_id"])
251+
self.assertEqual(rma.reception_move_id.sale_line_id, order_line)
252+
self.assertFalse(rma.can_be_refunded)
253+
rma.reception_move_id.quantity_done = rma.product_uom_qty
254+
rma.reception_move_id.picking_id._action_done()
255+
self.assertEqual(order.order_line.qty_delivered, 0)
256+
257+
def test_return_different_product(self):
258+
self.operation.action_create_delivery = False
259+
self.operation.different_return_product = True
260+
self.operation.action_create_refund = "update_quantity"
261+
order = self.sale_order
262+
order_line = order.order_line
263+
self.assertEqual(order_line.qty_delivered, 5)
264+
wizard = self._rma_sale_wizard(order)
265+
with self.assertRaises(
266+
ValidationError, msg="Complete the replacement information"
267+
):
268+
rma = self.env["rma"].browse(wizard.create_and_open_rma()["res_id"])
269+
return_product = self.product_product.create(
270+
{"name": "return Product test 1", "type": "product"}
271+
)
272+
wizard.line_ids.return_product_id = return_product
273+
rma = self.env["rma"].browse(wizard.create_and_open_rma()["res_id"])
274+
self.assertEqual(rma.reception_move_id.sale_line_id, order_line)
275+
self.assertEqual(rma.reception_move_id.product_id, return_product)
276+
self.assertFalse(rma.can_be_refunded)
277+
rma.reception_move_id.quantity_done = rma.product_uom_qty
278+
rma.reception_move_id.picking_id._action_done()
279+
self.assertEqual(order.order_line.qty_delivered, 5)

rma_sale/wizard/sale_order_rma_wizard.py

+9
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,14 @@ class SaleOrderLineRmaWizard(models.TransientModel):
157157
comodel_name="sale.order.line",
158158
)
159159
description = fields.Text()
160+
return_product_id = fields.Many2one(
161+
"product.product",
162+
help="Product to be returned if it's different from the originally delivered "
163+
"item.",
164+
)
165+
different_return_product = fields.Boolean(
166+
related="operation_id.different_return_product"
167+
)
160168

161169
@api.depends("wizard_id.operation_id")
162170
def _compute_operation_id(self):
@@ -223,4 +231,5 @@ def _prepare_rma_values(self):
223231
"product_uom": self.uom_id.id,
224232
"operation_id": self.operation_id.id,
225233
"description": description,
234+
"return_product_id": self.return_product_id.id,
226235
}

rma_sale/wizard/sale_order_rma_wizard_views.xml

+5
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@
3535
name="operation_id"
3636
attrs="{'required': [('quantity', '>', 0)]}"
3737
/>
38+
<field
39+
name="return_product_id"
40+
attrs="{'invisible': [('different_return_product', '=', False)], 'required': [('different_return_product', '=', True)]}"
41+
/>
42+
<field name="different_return_product" invisible="1" />
3843
</tree>
3944
</field>
4045
</group>

0 commit comments

Comments
 (0)