feat: Restrict lot selection dropdown to lots available in the source location for internal/transit pickings by adding a stock.lot search override and passing context variables from stock.move.line views.

This commit is contained in:
Suherdy Yacob 2026-03-05 13:56:06 +07:00
parent 7737a32459
commit a0a0b81ec6
2 changed files with 32 additions and 0 deletions

View File

@ -126,6 +126,31 @@ class StockLocation(models.Model):
return super()._name_search(name=name, domain=domain, operator=operator, limit=limit, order=order)
class StockLot(models.Model):
_inherit = 'stock.lot'
@api.model
def _search(self, domain, offset=0, limit=None, order=None, *args, **kwargs):
ctx = self.env.context
# We only want to filter if the user is in a picking using lot_id directly (like Receive operations)
active_picking_id = ctx.get('active_picking_id')
loc_id = ctx.get('default_location_id')
if active_picking_id and loc_id:
picking = self.env['stock.picking'].sudo().browse(active_picking_id)
loc = self.env['stock.location'].sudo().browse(loc_id)
# If the source is an internal or transit location, restrict the dropdown to lots actually present there.
# If the source is a supplier, we do not filter (they could be receiving brand new lots).
if picking.exists() and loc.exists() and loc.usage != 'supplier':
domain = Domain.AND([domain, [
('quant_ids.location_id', 'child_of', loc.id),
('quant_ids.quantity', '>', 0)
]])
return super()._search(domain, offset=offset, limit=limit, order=order, *args, **kwargs)
_logger.info("="*80)
_logger.info("STOCK_RESTRICT_SOURCE_LOCATION: stock_location.py module loaded successfully!")
_logger.info("="*80)

View File

@ -38,6 +38,10 @@
<!-- Rely on backend StockQuant._search override for location filtering -->
<attribute name="context">{'default_location_id': location_id, 'default_product_id': product_id, 'search_view_ref': 'stock.quant_search_view', 'list_view_ref': 'stock.view_stock_quant_tree', 'form_view_ref': 'stock.view_stock_quant_form', 'readonly_form': True, 'show_src_package': 1, 'active_mo_id': context.get('active_mo_id'), 'default_picking_type_id': context.get('default_picking_type_id'), 'default_allowed_source_location_ids': allowed_source_location_ids}</attribute>
</xpath>
<xpath expr="//field[@name='lot_id']" position="attributes">
<!-- Add default_location_id to context so python override can filter lots for transit receipts -->
<attribute name="context">{'default_product_id': product_id, 'active_picking_id': picking_id, 'default_location_id': location_id}</attribute>
</xpath>
<xpath expr="//field[@name='location_id']" position="attributes">
<!-- Rely on backend StockLocation._name_search override -->
<attribute name="options">{'no_create': True}</attribute>
@ -57,6 +61,9 @@
<!-- Rely on backend StockQuant._search override for location filtering -->
<attribute name="context">{'default_location_id': location_id, 'default_product_id': product_id, 'search_view_ref': 'stock.quant_search_view', 'list_view_ref': 'stock.view_stock_quant_tree', 'form_view_ref': 'stock.view_stock_quant_form', 'readonly_form': True, 'show_src_package': 1, 'active_mo_id': context.get('active_mo_id'), 'default_picking_type_id': context.get('default_picking_type_id'), 'default_allowed_source_location_ids': allowed_source_location_ids}</attribute>
</xpath>
<xpath expr="//field[@name='lot_id']" position="attributes">
<attribute name="context">{'default_product_id': parent.product_id, 'active_picking_id': picking_id, 'default_location_id': location_id}</attribute>
</xpath>
<xpath expr="//field[@name='location_id']" position="attributes">
<!-- Rely on backend StockLocation._name_search override -->
<attribute name="options">{'no_create': True}</attribute>