I understand. You're seeing the "This transfer was created from: S21812" (or similar) on the stock move, indicating that Odoo is aware of the originating sales order. However, you're expecting a "Transfer" button on the sales order that would directly link you to the related stock moves, and it's not appearing. Let's address why this button is missing and how to establish that link:
Reasons for the Missing "Transfer" Button
- Standard Odoo Behavior: Odoo doesn't automatically add a "Transfer" button to the sales order form in all cases. The presence of such a button often depends on specific modules being installed or certain configurations being enabled.
- Missing or Incorrect sale_line_id: Even though the origin field on the stock move shows the sales order, the direct link between the stock move and the sales order line (via the sale_line_id field) is crucial for Odoo to understand the relationship and display the button. If this field is missing or incorrect, Odoo won't know to show the "Transfer" button.
- View Definition: The sales order form view might not be configured to display the related stock moves, even if the sale_line_id is present. The view needs to be customized to show the button or a related list of stock moves.
- Security Permissions: The user might not have the necessary permissions to view the stock moves.
Solutions
- Ensure sale_line_id is Correctly Populated (Most Important):
- As emphasized in the previous response, this is the foundation. If the sale_line_id is missing or incorrect on the stock.move records, the link won't be established. Review the routing configuration and the server action (if you're using one) to ensure this field is being populated correctly.
- Verify the Value: After a transfer is created, manually inspect the stock.move record and confirm that the sale_line_id field contains the correct ID of the sales order line.
- Customize the Sales Order View to Add the "Transfer" Button or a Related List:
- Inherit the View: Create a custom module and inherit the sale.order.form view.
- Add a Smart Button: Add a smart button to the sales order form that links to the related stock moves.
<record id="sale_order_form_inherit_add_transfer_button" model="ir.ui.view">
<field name="name">sale.order.form.inherit.add.transfer.button</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/> <!-- Replace with the actual XML ID of the sale order form view -->
<field name="arch" type="xml">
<xpath expr="//div[@class='oe_button_box']" position="inside">
<button class="oe_stat_button"
icon="fa-truck"
name="%(action_stock_moves_from_sale)d" <!-- Define this action below -->
string="Transfers"
type="action"
groups="stock.group_stock_user"/> <!-- Restrict to inventory users -->
</xpath>
</field>
</record>
<record id="action_stock_moves_from_sale" model="ir.actions.act_window">
<field name="name">Transfers</field>
<field name="res_model">stock.picking</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('sale_id', '=', active_id)]</field> <!-- Filter by the current sale order -->
<field name="context">{'default_sale_id': active_id}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
No transfers found for this sale order.
</p>
</field>
</record>
Explanation:- xpath expr="//div[@class='oe_button_box']": This locates the button box in the sales order form. You might need to adjust this XPath depending on the exact structure of the view.
- <button ...>: This defines the smart button.
- name="%(action_stock_moves_from_sale)d": Links to the action defined below.
- string="Transfers": The text on the button.
- icon="fa-truck": The icon to display.
- type="action": Specifies that it's an action button.
- groups="stock.group_stock_user": Restricts the button to users in the "Inventory / User" group.
- action_stock_moves_from_sale: This defines the action that opens the list of stock moves.
- res_model="stock.picking": Specifies that it opens the stock.picking model.
- domain="[('sale_id', '=', active_id)]": This is the key part. It filters the stock moves to only show those related to the current sales order (active_id is the ID of the current record).
- context="{'default_sale_id': active_id}": This sets the default value of the sale_id field when creating a new stock move from the sales order.
- Add a Related List (Alternative): Instead of a button, you could add a related list of stock moves directly to the sales order form. This would display the stock moves in a table within the sales order view.
- Ensure Correct Security Permissions:
- Verify that the user has the necessary permissions to view stock.picking records. They should be in the "Inventory / User" group or a similar group that grants access to inventory operations.
- Check for Conflicting Modules:
- In rare cases, other installed modules might be interfering with the display of the "Transfer" button. Try disabling any recently installed or potentially conflicting modules to see if that resolves the issue.
Code Example: Adding sale_id to stock.picking (if needed)
If you need to add the sale_id field to the stock.picking model, here's how:
from odoo import models, fields, api
class StockPicking(models.Model):
_inherit = 'stock.picking'
sale_id = fields.Many2one('sale.order', string='Sales Order', compute='_compute_sale_id', store=True)
@api.depends('move_ids.sale_line_id.order_id')
def _compute_sale_id(self):
for picking in self:
sale = self.env['sale.order'].search([('id', 'in', picking.move_ids.sale_line_id.order_id.ids)], limit=1)
if sale:
picking.sale_id = sale.id
else:
picking.sale_id = False
Important Considerations:
- sale_id on stock.picking: While the sale_line_id on stock.move is the primary link, adding a sale_id field directly to the stock.picking model can simplify querying and reporting. The code above shows how to compute this field based on the related stock.move records.
- store=True: The store=True attribute on the computed field is important for performance. It tells Odoo to store the computed value in the database, so it doesn't have to be recalculated every time the view is rendered.
- Performance: Be mindful of performance when adding computed fields and complex view customizations. Test thoroughly to ensure that the changes don't slow down the system.
By implementing these solutions, you should be able to:
- Ensure that the sale_line_id is correctly populated on the stock.move records.
- Add a "Transfer" button or a related list to the sales order view, allowing users to easily navigate to the related stock moves.
Remember to adapt the code and configuration to your specific needs and test thoroughly.
🚀 Did This Solve Your
Problem?
If this answer helped you save time, money, or
frustration, consider:
✅ Upvoting (👍)
to help others find it faster
✅ Marking
as "Best Answer" if it resolved your issue
Your feedback keeps the Odoo community strong! 💪
(Need further customization? Drop a comment—I’m happy to
refine the solution!)