Skip to main content

Overview

The Stock Request framework extends the standard Odoo stock.move model to integrate stock requests with inventory movements. This allows stock moves to be linked to stock request allocations and enables tracking of which stock requests are being fulfilled by specific moves.

Model Information

_inherit
string
stock.move
_name
string
stock.move

Fields

Stock Request Module

allocation_ids
One2many
Links to stock request allocations associated with this move.
stock_request_ids
One2many
Computed field that returns all stock requests linked to this move through allocations.

Stock Return Request Module

qty_returnable
Float
Computes the quantity from this move that can still be returned. Takes into account already returned quantities from chained return moves.

Methods

Stock Request Module

_compute_stock_request_ids
method
Computes the stock_request_ids field by extracting all stock requests from the allocation_ids.Depends on: allocation_ids
@api.depends("allocation_ids")
def _compute_stock_request_ids(self):
    for rec in self:
        rec.stock_request_ids = rec.allocation_ids.mapped("stock_request_id")
_merge_moves_fields
method
Extends the base merge moves functionality to include allocation_ids when merging moves.Returns: Dictionary of fields to merge
def _merge_moves_fields(self):
    res = super()._merge_moves_fields()
    res["allocation_ids"] = [(4, m.id) for m in self.mapped("allocation_ids")]
    return res
_check_company_stock_request
method
Constraint method that validates the company of the stock request matches the company of the stock move.Constrains: company_idRaises: ValidationError if companies don’t match
@api.constrains("company_id")
def _check_company_stock_request(self):
    if any(
        self.env["stock.request.allocation"].search(
            [
                ("company_id", "!=", rec.company_id.id),
                ("stock_move_id", "=", rec.id),
            ],
            limit=1,
        )
        for rec in self
    ):
        raise ValidationError(
            _("The company of the stock request must match with that of the location.")
        )
copy_data
method
Extends copy functionality to duplicate allocation_ids when copying a stock move.Parameters:
  • default (dict, optional): Default values for the copy
Returns: Dictionary of copied data
def copy_data(self, default=None):
    if not default:
        default = {}
    if "allocation_ids" not in default:
        default["allocation_ids"] = []
    for alloc in self.allocation_ids:
        default["allocation_ids"].append(
            (
                0,
                0,
                {
                    "stock_request_id": alloc.stock_request_id.id,
                    "requested_product_uom_qty": alloc.requested_product_uom_qty,
                },
            )
        )
    return super().copy_data(default)
_action_cancel
method
Extends the cancel action to trigger stock request cancellation checks. Uses sudo to prevent ACL errors when users don’t have direct request permissions.Returns: Result from parent method
def _action_cancel(self):
    res = super()._action_cancel()
    self.mapped("allocation_ids.stock_request_id").sudo().check_cancel()
    return res
This method applies sudo to prevent ACL errors if the user doesn’t have permissions on stock requests (e.g., when canceling production moves).
_action_done
method
Extends the done action to trigger stock request completion checks. Uses sudo to prevent ACL errors when users don’t have direct request permissions.Parameters:
  • cancel_backorder (bool): Whether to cancel the backorder
Returns: Result from parent method
def _action_done(self, cancel_backorder=False):
    res = super()._action_done(cancel_backorder=cancel_backorder)
    self.mapped("allocation_ids.stock_request_id").sudo().check_done()
    return res
This method applies sudo to prevent ACL errors if the user doesn’t have permissions on stock requests (e.g., when completing production moves).

Stock Return Request Module

_compute_qty_returnable
method
Computes the returnable quantity by looking at chained returned moves. Only processes moves that are not in draft or cancelled state.Logic:
  • If the move has no returned_move_ids and is done, the full quantity is returnable
  • Otherwise, returnable qty = original quantity - sum of returned quantities from chained returns
def _compute_qty_returnable(self):
    self.qty_returnable = 0
    for move in self.filtered(lambda x: x.state not in ["draft", "cancel"]):
        if not move.returned_move_ids:
            if move.state == "done":
                move.qty_returnable = move.quantity
            continue
        move.qty_returnable = move.quantity - sum(
            move.returned_move_ids.mapped("qty_returnable")
        )
_get_lot_returnable_qty
method
Computes the returnable quantity for a specific lot by analyzing chained returned moves.Parameters:
  • lot_id (recordset): The lot/serial number to check
  • qty (float, default=0): Starting quantity (used in recursion)
Returns: Float representing the returnable quantity for the specified lot
def _get_lot_returnable_qty(self, lot_id, qty=0):
    for move in self.filtered(lambda x: x.state not in ["draft", "cancel"]):
        mls = move.move_line_ids.filtered(lambda x: x.lot_id == lot_id)
        qty += sum(mls.mapped("quantity"))
        qty -= move.returned_move_ids._get_lot_returnable_qty(lot_id)
    return qty
_action_assign
method
Extends the assign action to allow skipping automatic assignment when creating stock move lines manually.Context Variables:
  • skip_assign_move (bool): If True, skips the assignment
Returns: Result from parent method or None if skipped
def _action_assign(self):
    if self.env.context.get("skip_assign_move", False):
        # Avoid assign stock moves allowing create stock move lines manually
        return
    return super()._action_assign()
Set the skip_assign_move context variable to True when you want to manually create stock move lines without automatic assignment.

Usage Examples

Accessing Stock Requests from a Move

# Get all stock requests linked to a move
move = self.env['stock.move'].browse(move_id)
stock_requests = move.stock_request_ids

# Get allocations
allocations = move.allocation_ids

Checking Returnable Quantity

# Check how much of a move can be returned
move = self.env['stock.move'].browse(move_id)
returnable_qty = move.qty_returnable

# Check returnable quantity for a specific lot
lot = self.env['stock.lot'].browse(lot_id)
lot_returnable_qty = move._get_lot_returnable_qty(lot)

Creating Moves with Manual Line Assignment

# Skip automatic assignment to create lines manually
move = move.with_context(skip_assign_move=True)
move._action_assign()  # This will return without assigning

Source Code References

  • Stock Request extensions: stock_request/models/stock_move.py
  • Stock Return Request extensions: stock_return_request/models/stock_move.py

Build docs developers (and LLMs) love