[IMP] stock: replenishment using qty from the BoM
The replenishement creation currently calculates the quantity to order using a default multiple quantity of 1. In case of manufacturing route, we want to calculate the multiple quantity according to the quantity produced in the BoMs. closes odoo/odoo#62766 Signed-off-by: Rémy Voet <ryv-odoo@users.noreply.github.com>
This commit is contained in:
@@ -75,6 +75,16 @@ class StockWarehouseOrderpoint(models.Model):
|
||||
res[orderpoint.id] = orderpoint.product_id.uom_id._compute_quantity(product_qty, orderpoint.product_uom, round=False)
|
||||
return res
|
||||
|
||||
def _get_qty_multiple_to_order(self):
|
||||
""" Calculates the minimum quantity that can be ordered according to the qty and UoM of the BoM
|
||||
"""
|
||||
self.ensure_one()
|
||||
qty_multiple_to_order = super()._get_qty_multiple_to_order()
|
||||
if 'manufacture' in self.rule_ids.mapped('action'):
|
||||
bom = self.env['mrp.bom']._bom_find(product=self.product_id, bom_type='normal')
|
||||
return bom.product_uom_id._compute_quantity(bom.product_qty, self.product_uom)
|
||||
return qty_multiple_to_order
|
||||
|
||||
def _set_default_route_id(self):
|
||||
route_id = self.env['stock.rule'].search([
|
||||
('action', '=', 'manufacture')
|
||||
|
||||
@@ -835,3 +835,51 @@ class TestBoM(TestMrpCommon):
|
||||
line.product_uom_id = uom_unit
|
||||
line.product_qty = 5
|
||||
bom_finished = bom_finished.save()
|
||||
|
||||
def test_replenishment(self):
|
||||
""" Tests the auto generation of manual orderpoints.
|
||||
The multiple quantity of the orderpoint should be the
|
||||
quantity of the BoM in the UoM of the product.
|
||||
"""
|
||||
|
||||
uom_kg = self.env.ref('uom.product_uom_kgm')
|
||||
uom_gram = self.env.ref('uom.product_uom_gram')
|
||||
|
||||
product_gram = self.env['product.product'].create({
|
||||
'name': 'Product sold in grams',
|
||||
'type': 'product',
|
||||
'uom_id': uom_gram.id,
|
||||
'uom_po_id': uom_gram.id,
|
||||
})
|
||||
# We create a BoM that manufactures 2kg of product
|
||||
self.env['mrp.bom'].create({
|
||||
'product_id': product_gram.id,
|
||||
'product_tmpl_id': product_gram.product_tmpl_id.id,
|
||||
'product_uom_id': uom_kg.id,
|
||||
'product_qty': 2.0,
|
||||
'type': 'normal',
|
||||
})
|
||||
# We create a delivery order of 2300 grams
|
||||
picking_form = Form(self.env['stock.picking'])
|
||||
picking_form.picking_type_id = self.env.ref('stock.picking_type_out')
|
||||
with picking_form.move_ids_without_package.new() as move:
|
||||
move.product_id = product_gram
|
||||
move.product_uom_qty = 2300.0
|
||||
customer_picking = picking_form.save()
|
||||
customer_picking.action_confirm()
|
||||
|
||||
# We check the created orderpoint without manufacturing route manufacturing
|
||||
self.env['stock.warehouse.orderpoint']._get_orderpoint_action()
|
||||
self.env['stock.warehouse.orderpoint']._get_orderpoint_action()
|
||||
orderpoint = self.env['stock.warehouse.orderpoint'].search([('product_id', '=', product_gram.id)])
|
||||
self.assertEqual(orderpoint.qty_multiple, 0.0)
|
||||
self.assertEqual(orderpoint.qty_to_order, 2300.0)
|
||||
|
||||
# We select the manufacturing route and check the impact on the quantities
|
||||
manufacturing_route_id = self.ref('mrp.route_warehouse0_manufacture')
|
||||
manufacturing_route = self.env['stock.location.route'].search([('id', '=', manufacturing_route_id)])
|
||||
orderpoint_form = Form(orderpoint)
|
||||
orderpoint_form.route_id = manufacturing_route
|
||||
orderpoint_form.save()
|
||||
self.assertEqual(orderpoint.qty_multiple, 2000.0)
|
||||
self.assertEqual(orderpoint.qty_to_order, 4000.0)
|
||||
|
||||
@@ -200,6 +200,11 @@ class StockWarehouseOrderpoint(models.Model):
|
||||
('company_id', '=', self.company_id.id)
|
||||
], limit=1)
|
||||
|
||||
@api.onchange('route_id')
|
||||
def _onchange_route_id(self):
|
||||
if self.route_id:
|
||||
self.qty_multiple = self._get_qty_multiple_to_order()
|
||||
|
||||
def write(self, vals):
|
||||
if 'company_id' in vals:
|
||||
for orderpoint in self:
|
||||
@@ -259,6 +264,12 @@ class StockWarehouseOrderpoint(models.Model):
|
||||
qty_to_order += orderpoint.qty_multiple - remainder
|
||||
orderpoint.qty_to_order = qty_to_order
|
||||
|
||||
def _get_qty_multiple_to_order(self):
|
||||
""" Calculates the minimum quantity that can be ordered according to the PO UoM or BoM
|
||||
"""
|
||||
self.ensure_one()
|
||||
return 0
|
||||
|
||||
def _set_default_route_id(self):
|
||||
""" Write the `route_id` field on `self`. This method is intendend to be called on the
|
||||
orderpoints generated when openning the replenish report.
|
||||
@@ -358,8 +369,8 @@ class StockWarehouseOrderpoint(models.Model):
|
||||
|
||||
orderpoints = self.env['stock.warehouse.orderpoint'].with_user(SUPERUSER_ID).create(orderpoint_values_list)
|
||||
for orderpoint in orderpoints:
|
||||
orderpoint.route_id = orderpoint.product_id.route_ids[:1]
|
||||
orderpoints.filtered(lambda o: not o.route_id)._set_default_route_id()
|
||||
orderpoint.route_id = orderpoint.product_id.route_ids[:1] or orderpoint._set_default_route_id()
|
||||
orderpoint.qty_multiple = orderpoint._get_qty_multiple_to_order()
|
||||
return action
|
||||
|
||||
@api.model
|
||||
|
||||
@@ -153,6 +153,8 @@
|
||||
<group>
|
||||
<group>
|
||||
<field name="active" invisible="1"/>
|
||||
<field name="allowed_route_ids" invisible="1"/>
|
||||
<field name="route_id" invisible="1"/>
|
||||
<field name="product_id"/>
|
||||
<label for="product_min_qty"/>
|
||||
<div class="o_row">
|
||||
|
||||
Reference in New Issue
Block a user