[IMP] rma_sale: operation required

The rma operation is required in the portal, and it makes sense
for it to be required in the sales wizard as well
This commit is contained in:
sbejaoui
2024-07-22 09:53:34 +02:00
committed by Víctor Martínez
parent 994d480b41
commit 6404daedcb
7 changed files with 94 additions and 45 deletions

View File

@@ -91,8 +91,8 @@ To use this module, you need to:
it will be accessible via the smart button labeled Refund. The RMA it will be accessible via the smart button labeled Refund. The RMA
will be set automatically to 'Refunded' state when the refund is will be set automatically to 'Refunded' state when the refund is
validated. validated.
- If you click on 'Replace' or 'Return to customer' button instead, a - If you click on 'Replace' or 'Return to customer' button instead,
popup wizard will guide you to create a Delivery order to the a popup wizard will guide you to create a Delivery order to the
client and this order will be accessible via the smart button client and this order will be accessible via the smart button
labeled Delivery. The RMA will be set automatically to 'Replaced' labeled Delivery. The RMA will be set automatically to 'Replaced'
or 'Returned' state when the RMA quantity is equal or lower than or 'Returned' state when the RMA quantity is equal or lower than
@@ -140,9 +140,9 @@ Known issues / Roadmap
- As soon as the picking is selected, the user should select the move, - As soon as the picking is selected, the user should select the move,
but perhaps stock.move \_rec_name could be improved to better show but perhaps stock.move \_rec_name could be improved to better show
what the product of that move is. what the product of that move is.
- Add RMA reception and/or RMA delivery on several steps - 2 or 3 - like - Add RMA reception and/or RMA delivery on several steps - 2 or 3 -
normal receptions/deliveries. It should be a separate option inside like normal receptions/deliveries. It should be a separate option
the warehouse definition. inside the warehouse definition.
Bug Tracker Bug Tracker
=========== ===========
@@ -179,6 +179,8 @@ Contributors
- Antoni Marroig <amarroig@apsl.net> - Antoni Marroig <amarroig@apsl.net>
- Michael Tietz (MT Software) mtietz@mt-software.de - Michael Tietz (MT Software) mtietz@mt-software.de
- Jacques-Etienne Baudoux - BCIM je@bcim.be
- Souheil Bejaoui - ACSONE SA/NV souheil.bejaoui@acsone.eu
Maintainers Maintainers
----------- -----------

View File

@@ -856,6 +856,7 @@ class Rma(models.Model):
"partner_invoice_id", "partner_invoice_id",
"product_id", "product_id",
"location_id", "location_id",
"operation_id",
] ]
for record in self: for record in self:
desc = "" desc = ""

View File

@@ -8,3 +8,5 @@
- [APSL-Nagarro](https://www.apsl.tech): - [APSL-Nagarro](https://www.apsl.tech):
- Antoni Marroig \<<amarroig@apsl.net>\> - Antoni Marroig \<<amarroig@apsl.net>\>
- Michael Tietz (MT Software) <mtietz@mt-software.de> - Michael Tietz (MT Software) <mtietz@mt-software.de>
- Jacques-Etienne Baudoux - BCIM <je@bcim.be>
- Souheil Bejaoui - ACSONE SA/NV <souheil.bejaoui@acsone.eu>

View File

@@ -439,8 +439,8 @@ operations can be done by clicking on the buttons in the status bar.<ul>
it will be accessible via the smart button labeled Refund. The RMA it will be accessible via the smart button labeled Refund. The RMA
will be set automatically to Refunded state when the refund is will be set automatically to Refunded state when the refund is
validated.</li> validated.</li>
<li>If you click on Replace or Return to customer button instead, a <li>If you click on Replace or Return to customer button instead,
popup wizard will guide you to create a Delivery order to the a popup wizard will guide you to create a Delivery order to the
client and this order will be accessible via the smart button client and this order will be accessible via the smart button
labeled Delivery. The RMA will be set automatically to Replaced labeled Delivery. The RMA will be set automatically to Replaced
or Returned state when the RMA quantity is equal or lower than or Returned state when the RMA quantity is equal or lower than
@@ -494,9 +494,9 @@ team will be the default one if no team is set.</li>
<li>As soon as the picking is selected, the user should select the move, <li>As soon as the picking is selected, the user should select the move,
but perhaps stock.move _rec_name could be improved to better show but perhaps stock.move _rec_name could be improved to better show
what the product of that move is.</li> what the product of that move is.</li>
<li>Add RMA reception and/or RMA delivery on several steps - 2 or 3 - like <li>Add RMA reception and/or RMA delivery on several steps - 2 or 3 -
normal receptions/deliveries. It should be a separate option inside like normal receptions/deliveries. It should be a separate option
the warehouse definition.</li> inside the warehouse definition.</li>
</ul> </ul>
</div> </div>
<div class="section" id="bug-tracker"> <div class="section" id="bug-tracker">
@@ -532,6 +532,8 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
</ul> </ul>
</li> </li>
<li>Michael Tietz (MT Software) <a class="reference external" href="mailto:mtietz&#64;mt-software.de">mtietz&#64;mt-software.de</a></li> <li>Michael Tietz (MT Software) <a class="reference external" href="mailto:mtietz&#64;mt-software.de">mtietz&#64;mt-software.de</a></li>
<li>Jacques-Etienne Baudoux - BCIM <a class="reference external" href="mailto:je&#64;bcim.be">je&#64;bcim.be</a></li>
<li>Souheil Bejaoui - ACSONE SA/NV <a class="reference external" href="mailto:souheil.bejaoui&#64;acsone.eu">souheil.bejaoui&#64;acsone.eu</a></li>
</ul> </ul>
</div> </div>
<div class="section" id="maintainers"> <div class="section" id="maintainers">

View File

@@ -71,8 +71,11 @@ class TestRma(BaseCommon):
cls.warehouse = cls.env.ref("stock.warehouse0") cls.warehouse = cls.env.ref("stock.warehouse0")
# Ensure grouping # Ensure grouping
cls.env.company.rma_return_grouping = True cls.env.company.rma_return_grouping = True
cls.operation = cls.env.ref("rma.rma_operation_replace")
def _create_rma(self, partner=None, product=None, qty=None, location=None): def _create_rma(
self, partner=None, product=None, qty=None, location=None, operation=None
):
vals = {} vals = {}
if partner: if partner:
vals["partner_id"] = partner.id vals["partner_id"] = partner.id
@@ -82,14 +85,17 @@ class TestRma(BaseCommon):
vals["product_uom_qty"] = qty vals["product_uom_qty"] = qty
if location: if location:
vals["location_id"] = location.id vals["location_id"] = location.id
if operation:
vals["operation_id"] = operation.id
elif operation is None:
vals["operation_id"] = self.operation.id
vals["user_id"] = self.env.user.id vals["user_id"] = self.env.user.id
return self.env["rma"].create(vals) return self.env["rma"].create(vals)
def _create_confirm_receive( def _create_confirm_receive(
self, partner=None, product=None, qty=None, location=None self, partner=None, product=None, qty=None, location=None, operation=None
): ):
rma = self._create_rma(partner, product, qty, location) rma = self._create_rma(partner, product, qty, location, operation)
rma.action_confirm() rma.action_confirm()
rma.reception_move_id.quantity = rma.product_uom_qty rma.reception_move_id.quantity = rma.product_uom_qty
rma.reception_move_id.picking_id.button_validate() rma.reception_move_id.picking_id.button_validate()
@@ -221,19 +227,26 @@ class TestRmaCase(TestRma):
self.assertEqual(rma.product_uom, self.product.uom_id) self.assertEqual(rma.product_uom, self.product.uom_id)
def test_ensure_required_fields_on_confirm(self): def test_ensure_required_fields_on_confirm(self):
rma = self._create_rma() rma = self._create_rma(operation=False)
with self.assertRaises(ValidationError) as e: with self.assertRaises(ValidationError) as e:
rma.action_confirm() rma.action_confirm()
self.assertEqual( self.assertEqual(
e.exception.args[0], e.exception.args[0],
"Required field(s):\nCustomer\nShipping Address\nInvoice Address\nProduct", "Required field(s):\nCustomer\nShipping Address\nInvoice Address\nProduct"
"\nRequested operation",
) )
rma.partner_id = self.partner.id rma.partner_id = self.partner.id
with self.assertRaises(ValidationError) as e: with self.assertRaises(ValidationError) as e:
rma.action_confirm() rma.action_confirm()
self.assertEqual(e.exception.args[0], "Required field(s):\nProduct") self.assertEqual(
e.exception.args[0], "Required field(s):\nProduct\nRequested operation"
)
rma.product_id = self.product.id rma.product_id = self.product.id
rma.location_id = self.rma_loc.id rma.location_id = self.rma_loc.id
with self.assertRaises(ValidationError) as e:
rma.action_confirm()
self.assertEqual(e.exception.args[0], "Required field(s):\nRequested operation")
rma.operation_id = self.operation
rma.action_confirm() rma.action_confirm()
self.assertEqual(rma.state, "confirmed") self.assertEqual(rma.state, "confirmed")
@@ -670,6 +683,7 @@ class TestRmaCase(TestRma):
) )
) )
stock_return_picking_form.create_rma = True stock_return_picking_form.create_rma = True
stock_return_picking_form.rma_operation_id = self.operation
return_wizard = stock_return_picking_form.save() return_wizard = stock_return_picking_form.save()
picking_action = return_wizard.create_returns() picking_action = return_wizard.create_returns()
# Each origin move is linked to a different RMA # Each origin move is linked to a different RMA
@@ -698,6 +712,7 @@ class TestRmaCase(TestRma):
rma_form.move_id = origin_delivery.move_ids.filtered( rma_form.move_id = origin_delivery.move_ids.filtered(
lambda r: r.product_id == self.product lambda r: r.product_id == self.product
) )
rma_form.operation_id = self.operation
rma = rma_form.save() rma = rma_form.save()
rma.action_confirm() rma.action_confirm()
rma.reception_move_id.quantity = 10 rma.reception_move_id.quantity = 10

View File

@@ -11,6 +11,20 @@ from odoo.tools import float_compare
class ReturnPickingLine(models.TransientModel): class ReturnPickingLine(models.TransientModel):
_inherit = "stock.return.picking.line" _inherit = "stock.return.picking.line"
rma_operation_id = fields.Many2one(
comodel_name="rma.operation",
string="Operation",
compute="_compute_rma_operation_id",
store=True,
readonly=False,
)
@api.depends("wizard_id.rma_operation_id")
def _compute_rma_operation_id(self):
for rec in self:
if rec.wizard_id.rma_operation_id:
rec.rma_operation_id = rec.wizard_id.rma_operation_id
def _prepare_rma_vals(self): def _prepare_rma_vals(self):
self.ensure_one() self.ensure_one()
return { return {
@@ -19,6 +33,7 @@ class ReturnPickingLine(models.TransientModel):
"product_uom_qty": self.quantity, "product_uom_qty": self.quantity,
"product_uom": self.product_id.uom_id.id, "product_uom": self.product_id.uom_id.id,
"location_id": self.wizard_id.location_id.id or self.move_id.location_id.id, "location_id": self.wizard_id.location_id.id or self.move_id.location_id.id,
"operation_id": self.rma_operation_id.id,
} }
@@ -30,6 +45,10 @@ class ReturnPicking(models.TransientModel):
rma_location_ids = fields.Many2many( rma_location_ids = fields.Many2many(
comodel_name="stock.location", compute="_compute_rma_location_id" comodel_name="stock.location", compute="_compute_rma_location_id"
) )
rma_operation_id = fields.Many2one(
comodel_name="rma.operation",
string="Requested operation",
)
# Expand domain for RMAs # Expand domain for RMAs
location_id = fields.Many2one( location_id = fields.Many2one(
domain="create_rma and [('id', 'child_of', rma_location_ids)]" domain="create_rma and [('id', 'child_of', rma_location_ids)]"

View File

@@ -8,12 +8,20 @@
<field name="model">stock.return.picking</field> <field name="model">stock.return.picking</field>
<field name="inherit_id" ref="stock.view_stock_return_picking_form" /> <field name="inherit_id" ref="stock.view_stock_return_picking_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="product_return_moves" position="after"> <xpath expr="//field[@name='product_return_moves']//tree" position="inside">
<field
name="rma_operation_id"
required="parent.create_rma and quantity>0"
column_invisible="not parent.create_rma"
/>
</xpath>
<field name="product_return_moves" position="before">
<group name="group_rma"> <group name="group_rma">
<field <field
name="create_rma" name="create_rma"
invisible="picking_type_code != 'outgoing'" invisible="picking_type_code != 'outgoing'"
/> />
<field name="rma_operation_id" invisible="not create_rma" />
<field name="rma_location_ids" invisible="1" /> <field name="rma_location_ids" invisible="1" />
<field name="picking_id" invisible="1" /> <field name="picking_id" invisible="1" />
<field name="picking_type_code" invisible="1" /> <field name="picking_type_code" invisible="1" />