Odoo Manufacturing Picking - Show lots having quantity greater than zero 0

1.3k views Asked by At

I have added a lot quantity field in Manufacturing picking operations. It is reflecting the lot quantity perfectly with respect to location. Now the problem is I do not want to show the lots having no product i.e. 0 quantity. How do I achieve this?

Here is the screenshot where I want to make changes.enter image description here

Here is the model code (stock_move_line.py):

class StockMoveLine(models.Model):
    _name = "stock.move.line"
    _description = "Product Moves (Stock Move Line)"
    _rec_name = "product_id"
    _order = "result_package_id desc, id"
    lot_id = fields.Many2one('stock.production.lot', 'Lot/Serial Number123')
    x_lot_qty = fields.Float(compute="fetch_lot_wrt_location", 
                       name="Lot Quantity", 
                       store=True,
                       readonly=True, 
                       digits=(12,3))
    
    @api.onchange('lot_id','location_id')
    def fetch_lot_wrt_location(self):
        self.x_lot_qty = 0.0
        for row in self:
            quants = self.env['stock.quant'].search([('lot_id.id','=',row.lot_id.id)])
            for quant in quants:
                if row.location_id.display_name == quant.location_id.display_name:
                    row.x_lot_qty = quant.quantity
    

Here are the views (stock_move_views.xml):

<field name="lot_id" 
            attrs="{'readonly': ['&amp;', ('package_level_id', '!=', False), ('parent.picking_type_entire_packs', '=', True)]}" 
            invisible="not context.get('show_lots_m2o')" 
            domain="[('product_id', '=', parent.product_id)]" 
            groups="stock.group_production_lot" 
            context="{'default_product_id': parent.product_id, 'active_picking_id': picking_id}"/>
<field name="x_lot_qty" 
            attrs="{'readonly': ['&amp;', ('package_level_id', '!=', False), ('parent.picking_type_entire_packs', '=', True)]}" 
            invisible="not context.get('show_lots_m2o')" 
            domain="[('product_id', '=', parent.product_id)]" 
            groups="stock.group_production_lot" 
            context="{'default_product_id': parent.product_id, 'active_picking_id': picking_id}"/>

I did applied filter via domain attribute but it is not working. How can I restrict the lot numbers with quantity 0.

UPDATE: I tried following solution: I created a new dynamic selection field and tried populating the lots which are not empty with respect to location, below is the code:

@api.onchange('location_id')
def _fetch_non_empty_lots(self):
    lots = []
    for row in self:
        quants = self.env['stock.quant'].search([('location_id.id','=',row.location_id.id), ('product_id.id', '=', row.product_id.id), ('quantity', '>', 0)])
        for quant in quants:
            lots.append(quant)
            
    return lots

x_lot_id = fields.Selection(selection="_fetch_non_empty_lots", name="Non Empty Lots")

But now when I select a new location, I get following error:

Odoo Server Error
Traceback (most recent call last):
  File "C:\virtual_odoo12\Scripts\odoo\http.py", line 656, in _handle_exception
    return super(JsonRequest, self)._handle_exception(exception)
  File "C:\virtual_odoo12\Scripts\odoo\http.py", line 314, in _handle_exception
    raise pycompat.reraise(type(exception), exception, sys.exc_info()[2])
  File "C:\virtual_odoo12\Scripts\odoo\tools\pycompat.py", line 87, in reraise
    raise value
  File "C:\virtual_odoo12\Scripts\odoo\http.py", line 698, in dispatch
    result = self._call_function(**self.params)
  File "C:\virtual_odoo12\Scripts\odoo\http.py", line 346, in _call_function
    return checked_call(self.db, *args, **kwargs)
  File "C:\virtual_odoo12\Scripts\odoo\service\model.py", line 97, in wrapper
    return f(dbname, *args, **kwargs)
  File "C:\virtual_odoo12\Scripts\odoo\http.py", line 339, in checked_call
    result = self.endpoint(*a, **kw)
  File "C:\virtual_odoo12\Scripts\odoo\http.py", line 941, in __call__
    return self.method(*args, **kw)
  File "C:\virtual_odoo12\Scripts\odoo\http.py", line 519, in response_wrap
    response = f(*args, **kw)
  File "c:\virtual_odoo12\scripts\addons\web\controllers\main.py", line 962, in call_kw
    return self._call_kw(model, method, args, kwargs)
  File "c:\virtual_odoo12\scripts\addons\web\controllers\main.py", line 954, in _call_kw
    return call_kw(request.env[model], method, args, kwargs)
  File "C:\virtual_odoo12\Scripts\odoo\api.py", line 759, in call_kw
    return _call_kw_multi(method, model, args, kwargs)
  File "C:\virtual_odoo12\Scripts\odoo\api.py", line 746, in _call_kw_multi
    result = method(recs, *args, **kwargs)
  File "C:\virtual_odoo12\Scripts\odoo\models.py", line 5524, in onchange
    record._onchange_eval(name, field_onchange[name], result)
  File "C:\virtual_odoo12\Scripts\odoo\models.py", line 5369, in _onchange_eval
    process(method_res)
  File "C:\virtual_odoo12\Scripts\odoo\models.py", line 5355, in process
    if res.get('value'):
AttributeError: 'list' object has no attribute 'get'

UPDATE 2: Instead of modifying the existing dropdown, I created a dynamic dropdown. When location is selected, the drop down is populated with lot numbers which have quantity greater than 0. However, I am facing a basic issue/error:

AttributeError: 'list' object has no attribute 'get'

Here is the model selection field and code to populate it:

@api.onchange('location_id')
def _fetch_non_empty_lots(self):
        quants = self.env['stock.quant'].search([('location_id.id','=',self.location_id.id), 
                        ('product_id.id', '=', self.product_id.id), 
                        ('quantity', '>', 0)])
        return {str(quant.lot_id.id) :str.title(quant.lot_id.display_name) for quant in quants} 

## declare field    

x_lot_id = fields.Selection(selection="_fetch_non_empty_lots", name="Non Empty Lots")

When the list is empty, there is no error. When there is non-empty lot then I am getting the eror. Ineed some assistance.

4

There are 4 answers

3
Paxmees On

I think it should be like that?

lot_id = fields.Many2one('stock.production.lot', 'Lot/Serial Number123' 
  domain="[('product_id', '=', parent.product_id),('product_qty', '>', 0)]" )
6
Adam Strauss On

What I understand is you want to show only those lots which have more than 0 products, in your lots drop down

You can try this in your XML

<field name="lot_id" 
            attrs="{'readonly': ['&amp;', ('package_level_id', '!=', False), ('parent.picking_type_entire_packs', '=', True)]}" 
            invisible="not context.get('show_lots_m2o')" 
            domain="[('product_qty', '>', 0)]"     //View this
            groups="stock.group_production_lot" 
            context="{'default_product_id': parent.product_id, 'active_picking_id': picking_id}"/>
14
Kenly On

Odoo defines a product quantity field in the stock production lot model, you can use that field in the domain to filter lots, and you need to set store to True to make it searchable. If you need to define a new field then use the same logic and define it in the lot model to use in the lot_id field domain.

You got that error because Odoo expects a dictionary and it got a list instead.

The method may return a dictionary for changing field domains and pop up a warning message, like in the old API.

In your two last examples, you set the selection attribute to a string but the selection attribute specifies the possible values for this field. It is given as either a list of pairs (value, string), or a model method, or a method name. You can find an example in website_customer module.

Edit: (return a domain from onchange method)

The method may return a dictionary for changing field domains and pop up a warning message, like in the old API::

return {
    'domain': {'other_id': [('partner_id', '=', partner_id)]},
    'warning': {'title': "Warning", 'message': "What is this?"},
}
8
SDBot On

add this on your stock.move.line model:

@api.onchange('parent.product_id')
def _onchange_product_id(self):
    quants = self.env['stock.quant'].search([('product_id', '=', self.parent.product_id.id), ('quantity', '>', 0)])
    return {
        'domain': {
            'lot_id': [
                ('id', 'in', quants.lot_id.ids)
            ],
        },
    }