diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 0d3c52fd487..20cd71535cf 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -855,17 +855,6 @@ class mrp_production(osv.osv): res = False return res - def _get_subproduct_factor(self, cr, uid, production_id, move_id=None, context=None): - """ Compute the factor to compute the qty of procucts to produce for the given production_id. By default, - it's always equal to the quantity encoded in the production order or the production wizard, but if the - module mrp_subproduct is installed, then we must use the move_id to identify the product to produce - and its quantity. - :param production_id: ID of the mrp.order - :param move_id: ID of the stock move that needs to be produced. Will be used in mrp_subproduct. - :return: The factor to apply to the quantity that we should produce for the given production order. - """ - return 1 - def _get_produced_qty(self, cr, uid, production, context=None): ''' returns the produced quantity of product 'production.product_id' for the given production, in the product UoM ''' @@ -968,6 +957,16 @@ class mrp_production(osv.osv): consume_lines.append({'product_id': prod, 'product_qty': qty, 'lot_id': lot}) return consume_lines + def _calculate_produce_line_qty(self, cr, uid, move, quantity, context=None): + """ Compute the quantity and remainig quantity of products to produce. + :param move: Record set of stock move that needs to be produced, identify the product to produce. + :param quantity: specify quantity to produce in the uom of the production order. + :return: The quantity and remaining quantity of product produce. + """ + qty = min(quantity, move.product_qty) + remaining_qty = quantity - qty + return qty, remaining_qty + def action_produce(self, cr, uid, production_id, production_qty, production_mode, wiz=False, context=None): """ To produce final product based on production mode (consume/consume&produce). If Production mode is consume, all stock move lines of raw materials will be done/consumed. @@ -996,15 +995,13 @@ class mrp_production(osv.osv): produced_products[produced_product.product_id.id] = 0 produced_products[produced_product.product_id.id] += produced_product.product_qty for produce_product in production.move_created_ids: - subproduct_factor = self._get_subproduct_factor(cr, uid, production.id, produce_product.id, context=context) lot_id = False if wiz: lot_id = wiz.lot_id.id - qty = min(subproduct_factor * production_qty_uom, produce_product.product_qty) #Needed when producing more than maximum quantity + qty, remaining_qty = self._calculate_produce_line_qty(cr, uid, produce_product, production_qty_uom, context=context) new_moves = stock_mov_obj.action_consume(cr, uid, [produce_product.id], qty, location_id=produce_product.location_id.id, restrict_lot_id=lot_id, context=context) stock_mov_obj.write(cr, uid, new_moves, {'production_id': production_id}, context=context) - remaining_qty = subproduct_factor * production_qty_uom - qty if not float_is_zero(remaining_qty, precision_digits=precision): # In case you need to make more than planned #consumed more in wizard than previously planned diff --git a/addons/mrp_byproduct/__init__.py b/addons/mrp_byproduct/__init__.py index e222e677142..3e4207dc81c 100644 --- a/addons/mrp_byproduct/__init__.py +++ b/addons/mrp_byproduct/__init__.py @@ -1,3 +1,4 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. import mrp_byproduct +import stock_move diff --git a/addons/mrp_byproduct/mrp_byproduct.py b/addons/mrp_byproduct/mrp_byproduct.py index 982723cc85c..a86f8bf485c 100644 --- a/addons/mrp_byproduct/mrp_byproduct.py +++ b/addons/mrp_byproduct/mrp_byproduct.py @@ -88,41 +88,51 @@ class mrp_production(osv.osv): 'location_id': source, 'location_dest_id': production.location_dest_id.id, 'move_dest_id': production.move_prod_id.id, - 'production_id': production.id + 'production_id': production.id, + 'origin': production.name, + 'subproduct_id': sub_product.id } move_id = move_obj.create(cr, uid, data, context=context) move_obj.action_confirm(cr, uid, [move_id], context=context) return picking_id - def _get_subproduct_factor(self, cr, uid, production_id, move_id=None, context=None): - """Compute the factor to compute the qty of procucts to produce for the given production_id. By default, - it's always equal to the quantity encoded in the production order or the production wizard, but with + def _get_subproduct_factor(self, cr, uid, move, context=None): + """Compute the factor to compute the quantity of products to produce. By default, + it's always equal to the quantity encoded in the production order or the production wizard, but with the module mrp_byproduct installed it can differ for byproducts having type 'variable'. - :param production_id: ID of the mrp.order - :param move_id: ID of the stock move that needs to be produced. Identify the product to produce. + :param move: Record set of stock move that needs to be produced, identify the product to produce. :return: The factor to apply to the quantity that we should produce for the given production order and stock move. """ - sub_obj = self.pool.get('mrp.subproduct') - move_obj = self.pool.get('stock.move') - production_obj = self.pool.get('mrp.production') - production_browse = production_obj.browse(cr, uid, production_id, context=context) - move_browse = move_obj.browse(cr, uid, move_id, context=context) - subproduct_factor = 1 - sub_id = sub_obj.search(cr, uid,[('product_id', '=', move_browse.product_id.id),('bom_id', '=', production_browse.bom_id.id), ('subproduct_type', '=', 'variable')], context=context) - if sub_id: - subproduct_record = sub_obj.browse(cr ,uid, sub_id[0], context=context) + subproduct_record = move.subproduct_id + if subproduct_record.subproduct_type == 'variable': if subproduct_record.bom_id.product_qty: subproduct_factor = subproduct_record.product_qty / subproduct_record.bom_id.product_qty return subproduct_factor - return super(mrp_production, self)._get_subproduct_factor(cr, uid, production_id, move_id, context=context) + return super(mrp_production, self)._get_subproduct_factor(cr, uid, move, context=context) + + def _calculate_produce_line_qty(self, cr, uid, move, quantity, context=None): + """ Compute the quantity and remainig quantity of products to produce. + :param move: stock.move record that needs to be produced, identify the product to produce. + :param quantity: quantity to produce, in the uom of the production order. + :return: The quantity and remaining quantity of product produce. + """ + if move.subproduct_id.subproduct_type == 'variable': + subproduct_factor = self._get_subproduct_factor(cr, uid, move, context=context) + # Needed when producing more than maximum quantity + qty = min(subproduct_factor * quantity, move.product_qty) + remaining_qty = subproduct_factor * quantity - qty + return qty, remaining_qty + elif move.subproduct_id.subproduct_type == 'fixed': + return move.product_qty, 0 + # no subproduct + return super(mrp_production, self)._calculate_produce_line_qty(cr, uid, move, quantity, context=context) class change_production_qty(osv.osv_memory): _inherit = 'change.production.qty' def _update_product_to_produce(self, cr, uid, prod, qty, context=None): - bom_obj = self.pool.get('mrp.bom') move_lines_obj = self.pool.get('stock.move') prod_obj = self.pool.get('mrp.production') for m in prod.move_created_ids: @@ -131,6 +141,6 @@ class change_production_qty(osv.osv_memory): else: for sub_product_line in prod.bom_id.sub_products: if sub_product_line.product_id.id == m.product_id.id: - factor = prod_obj._get_subproduct_factor(cr, uid, prod.id, m.id, context=context) + factor = prod_obj._get_subproduct_factor(cr, uid, m, context=context) subproduct_qty = sub_product_line.subproduct_type == 'variable' and qty * factor or sub_product_line.product_qty move_lines_obj.write(cr, uid, [m.id], {'product_uom_qty': subproduct_qty}) diff --git a/addons/mrp_byproduct/stock_move.py b/addons/mrp_byproduct/stock_move.py new file mode 100644 index 00000000000..c315c364454 --- /dev/null +++ b/addons/mrp_byproduct/stock_move.py @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from openerp import fields, models + + +class Stok_Move(models.Model): + _inherit = 'stock.move' + + subproduct_id = fields.Many2one('mrp.subproduct', 'Subproduct', + help="Subproduct line that generated the move in a manufacturing order") diff --git a/addons/mrp_byproduct/test/mrp_byproduct.yml b/addons/mrp_byproduct/test/mrp_byproduct.yml index 23a458241a5..009f59289b5 100644 --- a/addons/mrp_byproduct/test/mrp_byproduct.yml +++ b/addons/mrp_byproduct/test/mrp_byproduct.yml @@ -2,7 +2,8 @@ In order to test mrp_byproduct with OpenERP, I add byproduct in bill of material. I make a production order, confirm it so stock moves for byproducts are generated. - - I add a sub product in Bill of material for product External Hard Disk. + I add a sub product in Bill of material for product Datacard with Switch, 24 + ports as byproduct - !record {model: mrp.bom, id: mrp.mrp_bom_kit}: product_id: product.product_delivery_02 @@ -10,10 +11,10 @@ sub_products: - product_id: product.product_delivery_01 product_uom: product.product_uom_unit - product_qty: 2.0 + product_qty: 3.0 subproduct_type: fixed - - I create a production order for External Hard Disk. + I create a production order for 2 Datacard. - !record {model: mrp.production, id: mrp_production_mo0}: product_id: product.product_delivery_02 @@ -40,8 +41,10 @@ This move is created automatically when I confirmed the production order. - !python {model: stock.move}: | - move_ids = self.search(cr, uid, [('product_id','=',ref('product.product_delivery_01'))]) + production_order = self.pool.get('mrp.production').browse(cr, uid, ref("mrp_production_mo0")) + move_ids = self.search(cr, uid, [('origin','=',production_order.name), ('product_id','=',ref('product.product_delivery_01'))]) assert move_ids, 'No moves are created !' + assert self.browse(cr, uid, move_ids).product_uom_qty == 3, "Incorrect quantity for byproduct move" - I want to start the production so I force the reservation of products. - @@ -77,3 +80,4 @@ move_ids = self.search(cr, uid, [('origin','=',production_order.name), ('product_id','in',[ref("product.product_delivery_02"),ref("product.product_delivery_01")])]) moves = self.browse(cr, uid, move_ids) assert all(move.state == 'done' for move in moves), 'Moves are not done!' +