Skip to main content

Overview

This guide will walk you through creating your first stock request and understanding the complete workflow from request creation to fulfillment.
Before starting, ensure you have:
  • Installed the Stock Request module
  • Been assigned to “Stock Request / User” or “Stock Request / Manager” group
  • At least one warehouse and location configured

Creating Your First Stock Request

1

Navigate to Stock Requests

From the main menu, click Stock RequestsStock RequestsYou’ll see a list view of all stock requests (filtered by your access rights).
2

Click New to create a request

Click the New button in the top-left corner.A form will open with the following fields:
3

Fill in the request details

Product Select the product you need. Only storable products are available.
# Field: product_id
# Type: Many2one('product.product')
Quantity Enter the quantity you need.
# Field: product_uom_qty
# Type: Float
# Must be > 0
UoM (Unit of Measure) Automatically filled based on product. Can be changed if needed.
# Field: product_uom_id
# Type: Many2one('uom.uom')
Location Where you want the stock delivered.
# Field: location_id
# Type: Many2one('stock.location')
# Default: Warehouse's stock location
Warehouse The warehouse that will process your request.
# Field: warehouse_id
# Type: Many2one('stock.warehouse')
4

Save the request

Click SaveThe system will:
  • Generate a unique reference number (e.g., SR/00001)
  • Set the state to Draft
  • Set you as the Requested By user
The request can be edited freely while in Draft state.

Example: Simple Request

# Create a stock request programmatically
stock_request = env['stock.request'].create({
    'product_id': env.ref('product.product_product_27').id,  # PC1 product
    'product_uom_qty': 5.0,
    'product_uom_id': env.ref('uom.product_uom_unit').id,
    'location_id': env.ref('stock.stock_location_stock').id,
    'warehouse_id': env.ref('stock.warehouse0').id,
    'expected_date': fields.Datetime.now(),
    'picking_policy': 'direct',
})

print(f"Created request: {stock_request.name}")
# Output: Created request: SR/00001

Confirming the Request

Once your request is ready, confirm it to trigger the procurement process.
1

Click Confirm

Click the Confirm button at the top of the form.The system will:
  1. Validate the request (quantity > 0, valid product, etc.)
  2. Change state from Draft to In Progress
  3. Run the procurement engine
2

Procurement engine evaluates

The system checks:
If company.stock_request_check_available_first == True:
# Check if stock is available in the location
if product.with_context(location=location_id).free_qty >= product_uom_qty:
    # Create and execute immediate transfer
    self._action_use_stock_available()
else:
    # Run procurement rules
    self._action_launch_procurement_rule()
The system selects routes in this priority:
  1. Route specified on the stock request
  2. Routes on the product’s “Routes” field
  3. Routes configured on the warehouse
  4. Global routes matching the destination location
def _prepare_procurement_values(self, group_id=False):
    return {
        'date_planned': self.expected_date,
        'warehouse_id': self.warehouse_id,
        'route_ids': self.route_id,
        'group_id': group_id or self.procurement_group_id.id,
    }
Based on the selected route’s rules:
  • pull/push: Create stock moves and transfers
  • buy: Create purchase order (requires stock_request_purchase)
  • manufacture: Create manufacturing order (requires stock_request_mrp)
3

Review created operations

After confirmation, click the Transfers button to view:
  • Stock pickings
  • Purchase orders (if applicable)
  • Manufacturing orders (if applicable)
The smart button shows the count of related operations.

Understanding Request States

Stock requests progress through these states:
1

Draft

Initial state when the request is created.
  • Request can be edited or deleted
  • No procurement has been triggered
  • No stock movements exist
Available actions:
  • Edit any field
  • Delete the request
  • Confirm to move to next state
2

In Progress

Active state after confirmation.
  • Procurement has been triggered
  • Stock movements, POs, or MOs are created
  • Request is being fulfilled
Available actions:
  • Cancel the request (cancels all pending moves)
  • View transfers/orders
  • Limited editing (some fields locked)
Quantity tracking:
# Three computed quantities track progress
qty_in_progress  # Quantity being processed
qty_done         # Quantity completed
qty_cancelled    # Quantity cancelled
3

Done

Completed state when all stock has been received.
  • All requested quantity has been fulfilled
  • All transfers are completed
  • Request is read-only
Auto-transition:
# System automatically moves to Done when
if qty_done >= product_uom_qty:
    state = 'done'
4

Cancelled

Terminal state when request is cancelled.
  • All pending moves are cancelled
  • No further action possible
  • Request is read-only
Manual action: Click Cancel button to cancel the request and all pending operations.

Working Example: Internal Transfer

Let’s walk through a complete example with stock available.
1

Setup: Ensure stock is available

# Add stock to source location
product = env['product.product'].create({
    'name': 'Widget A',
    'type': 'product',
    'default_code': 'WGT-A',
})

# Add 100 units to WH/Stock
quant = env['stock.quant'].create({
    'product_id': product.id,
    'location_id': env.ref('stock.stock_location_stock').id,
    'quantity': 100.0,
})
2

Create destination location

production_loc = env['stock.location'].create({
    'name': 'Production Floor',
    'location_id': env.ref('stock.warehouse0').view_location_id.id,
    'usage': 'internal',
})
3

Configure route and rule

# Create route
route = env['stock.route'].create({
    'name': 'WH to Production',
    'warehouse_ids': [(4, env.ref('stock.warehouse0').id)],
})

# Create rule
rule = env['stock.rule'].create({
    'name': 'Transfer to Production',
    'route_id': route.id,
    'location_src_id': env.ref('stock.stock_location_stock').id,
    'location_dest_id': production_loc.id,
    'action': 'pull',
    'picking_type_id': env.ref('stock.warehouse0').int_type_id.id,
    'procure_method': 'make_to_stock',
    'warehouse_id': env.ref('stock.warehouse0').id,
})

# Assign route to product
product.route_ids = [(4, route.id)]
4

Create and confirm request

# Create stock request
request = env['stock.request'].create({
    'product_id': product.id,
    'product_uom_qty': 10.0,
    'location_id': production_loc.id,
    'warehouse_id': env.ref('stock.warehouse0').id,
})

print(f"Request created: {request.name}, State: {request.state}")
# Output: Request created: SR/00001, State: draft

# Confirm the request
request.action_confirm()

print(f"State after confirm: {request.state}")
# Output: State after confirm: open
5

Verify transfer was created

# Check pickings
pickings = request.picking_ids
print(f"Number of transfers: {len(pickings)}")
# Output: Number of transfers: 1

picking = pickings[0]
print(f"Picking: {picking.name}")
print(f"State: {picking.state}")
print(f"Source: {picking.location_id.name}")
print(f"Destination: {picking.location_dest_id.name}")

# Output:
# Picking: INT/00001
# State: assigned
# Source: WH/Stock
# Destination: Production Floor
6

Process the transfer

# Validate the transfer
picking.button_validate()

# Check request status
print(f"Request state: {request.state}")
print(f"Qty done: {request.qty_done}")
print(f"Qty in progress: {request.qty_in_progress}")

# Output:
# Request state: done
# Qty done: 10.0
# Qty in progress: 0.0

Using Stock Request Orders

If you enabled Stock Request Orders, you can group multiple requests:
1

Navigate to Stock Request Orders

Stock Requests → Stock Request Orders → New
2

Fill in order header

Set common attributes for all requests in the order:
  • Warehouse
  • Location
  • Expected Date
  • Shipping Policy
  • Requested By
3

Add request lines

In the Stock Requests tab, add lines:
order = env['stock.request.order'].create({
    'warehouse_id': env.ref('stock.warehouse0').id,
    'location_id': production_loc.id,
    'expected_date': fields.Datetime.now(),
    'stock_request_ids': [
        (0, 0, {
            'product_id': product1.id,
            'product_uom_qty': 5.0,
        }),
        (0, 0, {
            'product_id': product2.id,
            'product_uom_qty': 10.0,
        }),
        (0, 0, {
            'product_id': product3.id,
            'product_uom_qty': 3.0,
        }),
    ],
})
4

Confirm the entire order

Click Confirm to process all requests at once.
order.action_confirm()

# All child requests are confirmed
for request in order.stock_request_ids:
    assert request.state == 'open'

Monitoring Request Progress

View Request Details

The request form shows real-time progress:
State Badge Shows current state with color coding:
  • Draft (gray)
  • In Progress (blue)
  • Done (green)
  • Cancelled (red)
Quantity Tracking
# Display fields
product_uom_qty    # Requested quantity
qty_in_progress    # Being processed
qty_done          # Completed
qty_cancelled     # Cancelled
Progress Bar Visual indicator of completion percentage

List View Filters

Quickly find requests using built-in filters:
# Common searches
# My requests
[('requested_by', '=', uid)]

# Open requests
[('state', '=', 'open')]

# Requests for specific product
[('product_id', '=', product_id)]

# Urgent requests (expected date soon)
[('expected_date', '<=', today + 7 days)]

# By warehouse
[('warehouse_id', '=', warehouse_id)]

Cancelling Requests

1

Open the request

Navigate to the request you want to cancel
2

Click Cancel button

The system will:
  1. Cancel all pending stock moves
  2. Update move states to “cancelled”
  3. Set request state to “Cancelled”
  4. Update qty_cancelled field
def action_cancel(self):
    self.sudo().mapped('move_ids')._action_cancel()
    self.write({'state': 'cancel'})
3

Verify cancellation

Cancelling a request does not:
  • Delete the request record
  • Cancel already completed transfers
  • Cancel confirmed purchase orders (must cancel separately)
  • Refund or return already received stock

Common Workflows

Workflow 1: Request with Available Stock

Workflow 2: Request Triggering Purchase

Workflow 3: Request Triggering Manufacturing

Tips and Best Practices

Use Expected Dates

Always set realistic expected dates to help warehouse teams prioritize fulfillment.

Group Related Requests

Use Stock Request Orders to group requests for the same project or purpose.

Configure Routes Properly

Ensure routes are configured before requesting products, or procurement may fail.

Monitor Progress

Regularly check your open requests and follow up on delays.
Pro tip: Enable “Check Available Stock First” if you want to prioritize using existing inventory before triggering new procurement.

Troubleshooting

Possible causes:
  1. No route configured for the product/location combination
  2. Product type is not “Storable Product”
  3. Procurement rules misconfigured
Solution:
# Check procurement error
try:
    request.action_confirm()
except UserError as e:
    print(f"Error: {e}")

# Verify routes
routes = request._get_routes()
print(f"Available routes: {routes.mapped('name')}")
Cause: Security rules filter requests by creator.Solution:
  • As a User: You can only see requests you created or are following
  • As a Manager: You can see all requests
  • Ask a manager to add you as follower on specific requests
Cause: Transfers not completed or quantities don’t match.Solution:
# Check quantities
print(f"Requested: {request.product_uom_qty}")
print(f"Done: {request.qty_done}")
print(f"In progress: {request.qty_in_progress}")
print(f"Cancelled: {request.qty_cancelled}")

# Manually complete if needed
if request.qty_done >= request.product_uom_qty:
    request.action_done()

Next Steps

Integrations

Learn about tier validation, Purchase, MRP, and automation

API Reference

Explore the complete API documentation

Procurement Rules

Learn recommended procurement patterns and workflows

Build docs developers (and LLMs) love