[REF] stock: products on hand action
Instead of hardcoding a domain in the action, we add a field that will
be used to apply the domain. The goal is to be able to define a static
domain in the xml so we'll be able to default on the filter while still
being able to remove it.
Let's consider this usecase:
Physical
| \
WH Subcontracting
| |
Stock 5 units
|
10 units
With the hardcoded domain, we have two problems
- the right part of the tree isn't visible
- the user can add a quant in subcontracting but it will disappear at
the creation since it isn't part of the hardcoded domain.
The complicated part of the domain is the `_get_domain_locations` call.
It will use multiple context keys, the current company and get the
hierarchy of internal locations below warehouses to see what it should
include or not.
To be able to remove a domain, it should be declared in the xml and not
hardcoded in the action. Since the domain is complex, we can't express
it. So we add a computed field "on_hand" and its search method is
overiden to call `_get_domain_locations`.
task-2061825
closes odoo/odoo#40403
Signed-off-by: Simon Lejeune (sle) <sle@openerp.com>
This commit is contained in:
@@ -481,8 +481,7 @@ class Product(models.Model):
|
||||
|
||||
# Be aware that the exact same function exists in product.template
|
||||
def action_open_quants(self):
|
||||
location_domain = self._get_domain_locations()[0]
|
||||
domain = expression.AND([[('product_id', 'in', self.ids)], location_domain])
|
||||
domain = [('product_id', 'in', self.ids)]
|
||||
hide_location = not self.user_has_groups('stock.group_stock_multi_locations')
|
||||
hide_lot = all([product.tracking == 'none' for product in self])
|
||||
self = self.with_context(hide_location=hide_location, hide_lot=hide_lot)
|
||||
@@ -507,7 +506,7 @@ class Product(models.Model):
|
||||
else:
|
||||
self = self.with_context(product_tmpl_id=self.product_tmpl_id.id)
|
||||
ctx = dict(self.env.context)
|
||||
ctx.update({'no_at_date': True})
|
||||
ctx.update({'no_at_date': True, 'search_default_on_hand': True})
|
||||
return self.env['stock.quant'].with_context(ctx)._get_quants_action(domain)
|
||||
|
||||
def action_update_quantity_on_hand(self):
|
||||
|
||||
@@ -51,15 +51,13 @@ class StockQuant(models.Model):
|
||||
'product.product', 'Product',
|
||||
domain=lambda self: self._domain_product_id(),
|
||||
ondelete='restrict', readonly=True, required=True, index=True, check_company=True)
|
||||
# so user can filter on template in webclient
|
||||
product_tmpl_id = fields.Many2one(
|
||||
'product.template', string='Product Template',
|
||||
related='product_id.product_tmpl_id', readonly=False)
|
||||
product_uom_id = fields.Many2one(
|
||||
'uom.uom', 'Unit of Measure',
|
||||
readonly=True, related='product_id.uom_id')
|
||||
company_id = fields.Many2one(related='location_id.company_id',
|
||||
string='Company', store=True, readonly=True)
|
||||
company_id = fields.Many2one(related='location_id.company_id', string='Company', store=True, readonly=True)
|
||||
location_id = fields.Many2one(
|
||||
'stock.location', 'Location',
|
||||
domain=lambda self: self._domain_location_id(),
|
||||
@@ -93,6 +91,7 @@ class StockQuant(models.Model):
|
||||
compute='_compute_available_quantity')
|
||||
in_date = fields.Datetime('Incoming Date', readonly=True)
|
||||
tracking = fields.Selection(related='product_id.tracking', readonly=True)
|
||||
on_hand = fields.Boolean('On Hand', store=False, search='_search_on_hand')
|
||||
|
||||
@api.depends('quantity', 'reserved_quantity')
|
||||
def _compute_available_quantity(self):
|
||||
@@ -128,6 +127,18 @@ class StockQuant(models.Model):
|
||||
move = quant.env['stock.move'].with_context(inventory_mode=False).create(move_vals)
|
||||
move._action_done()
|
||||
|
||||
def _search_on_hand(self, operator, value):
|
||||
"""Handle the "on_hand" filter, indirectly calling `_get_domain_locations`."""
|
||||
if operator not in ['=', '!='] or not isinstance(value, bool):
|
||||
raise UserError(_('Operation not supported'))
|
||||
domain_loc = self.env['product.product']._get_domain_locations()[0]
|
||||
quant_ids = [l['id'] for l in self.env['stock.quant'].search_read(domain_loc, ['id'])]
|
||||
if (operator == '!=' and value is True) or (operator == '=' and value is False):
|
||||
domain_operator = 'not in'
|
||||
else:
|
||||
domain_operator = 'in'
|
||||
return [('id', domain_operator, quant_ids)]
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
""" Override to handle the "inventory mode" and create a quant as
|
||||
@@ -612,7 +623,7 @@ class StockQuant(models.Model):
|
||||
'view_mode': 'list',
|
||||
'res_model': 'stock.quant',
|
||||
'type': 'ir.actions.act_window',
|
||||
'context': dict(self.env.context),
|
||||
'context': self.env.context,
|
||||
'domain': domain or [],
|
||||
'help': """
|
||||
<p class="o_view_nocontent_empty_folder">No Stock On Hand</p>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<group expand='0' string='Filters'>
|
||||
<filter name='internal_loc' string="Internal Locations" domain="[('location_id.usage','=', 'internal')]"/>
|
||||
<filter name='transit_loc' string="Transit Locations" domain="[('location_id.usage' ,'=', 'transit')]"/>
|
||||
<filter name="on_hand" string="On Hand" domain="[('on_hand', '=', True)]"/>
|
||||
<separator/>
|
||||
<filter name="negative" string="Negative Stock" domain="[('quantity', '<', 0.0)]"/>
|
||||
<filter name="positive" string="Positive Stock" domain="[('quantity', '>', 0.0)]"/>
|
||||
|
||||
Reference in New Issue
Block a user