diff --git a/purchase_stock_ux/models/purchase_order_line.py b/purchase_stock_ux/models/purchase_order_line.py index 3631e5c2..735dbde5 100644 --- a/purchase_stock_ux/models/purchase_order_line.py +++ b/purchase_stock_ux/models/purchase_order_line.py @@ -156,12 +156,28 @@ def _onchange_product_qty(self): return {"warning": warning_mess} return {} + @api.depends("qty_received_method", "qty_received_manual") + def _compute_qty_received(self): + super()._compute_qty_received() + for line in self.filtered(lambda l: l.qty_received_method in ["manual", "stock_moves"]): + exchange_move_ids = line.move_ids.filtered( + lambda m: m.state == "done" and m.location_id.usage != "supplier" and m._is_exchange_move_helper() + ) + if exchange_move_ids: + line.qty_received -= sum( + line.product_uom._compute_quantity(move.product_uom_qty, line.product_uom) + for move in exchange_move_ids + ) + @api.depends("order_id.state", "move_ids.state") def _compute_qty_returned(self): for line in self: qty = 0.0 for move in line.move_ids.filtered( - lambda m: m.state == "done" and m.location_id.usage != "supplier" and m.to_refund + lambda m: m.state == "done" + and m.location_id.usage != "supplier" + and m.to_refund + and not m._is_exchange_move_helper() ): qty += move.product_uom._compute_quantity(move.product_uom_qty, line.product_uom) line.qty_returned = qty diff --git a/purchase_stock_ux/models/stock_move.py b/purchase_stock_ux/models/stock_move.py index bdc6d9f9..f9ac75a1 100644 --- a/purchase_stock_ux/models/stock_move.py +++ b/purchase_stock_ux/models/stock_move.py @@ -26,3 +26,13 @@ def _prepare_merge_moves_distinct_fields(self): if self.env.context.get("cancel_from_order") and "price_unit" in distinct_fields: distinct_fields.remove("price_unit") return distinct_fields + + def _is_exchange_move_helper(self): + # Como is_exchange_move se crea en sale_stock_ux, chequeamos si el campo existe antes de usarlo + # sino existe el valor deberia ser False + # en 19 vamos mover el campo a stock ux asi no tenemos que hacer este + # feo hack + self.ensure_one() + if self.fields_get().get("is_exchange_move"): + return self.is_exchange_move + return False diff --git a/purchase_stock_ux/wizards/stock_return_picking.py b/purchase_stock_ux/wizards/stock_return_picking.py new file mode 100644 index 00000000..05513d14 --- /dev/null +++ b/purchase_stock_ux/wizards/stock_return_picking.py @@ -0,0 +1,51 @@ +############################################################################## +# For copyright and license notices, see __manifest__.py file in module root +# directory +############################################################################## +from odoo import _, api, models +from odoo.exceptions import UserError + + +class StockReturnPicking(models.TransientModel): + _inherit = "stock.return.picking" + + @api.model + def default_get(self, fields): + """Set to_refund=True by default for purchase returns.""" + result = super().default_get(fields) + try: + for line in result["product_return_moves"]: + assert line[0] == 0 + # Marcar to_refund por defecto en devoluciones a proveedor + line[2]["to_refund"] = True + except KeyError: + pass + return result + + def action_create_exchanges(self): + """Create exchanges for purchase returns. + + Exchange = devuelves producto defectuoso al proveedor y el proveedor + te envĂ­a un reemplazo. No es un reembolso monetario. + """ + if any(self.product_return_moves.mapped("to_refund")): + raise UserError(_("You cannot create exchanges for return lines marked to refund.")) + return super(StockReturnPicking, self.with_context(is_exchange_move=True)).action_create_exchanges() + + +class StockReturnPickingLine(models.TransientModel): + _inherit = "stock.return.picking.line" + + def _prepare_move_default_values(self, new_picking): + """Mark moves created from exchanges with is_exchange_move flag.""" + vals = super()._prepare_move_default_values(new_picking) + if self.env.context.get("is_exchange_move"): + vals["is_exchange_move"] = True + return vals + + def _prepare_picking_default_values_based_on(self, picking): + """Propagate is_exchange_move flag to the new picking.""" + vals = super()._prepare_picking_default_values_based_on(picking) + if self.env.context.get("is_exchange_move"): + vals["is_exchange_move"] = True + return vals