diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 68d87736e9d..478848a337e 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -772,7 +772,16 @@ class mrp_production(osv.osv): """ return 1 - def action_produce(self, cr, uid, production_id, production_qty, production_mode, context=None): + + + + + + + + + + def action_produce(self, cr, uid, production_id, production_qty, production_mode, wiz, 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. If Production mode is consume & produce, all stock move lines of raw materials will be done/consumed @@ -784,7 +793,80 @@ class mrp_production(osv.osv): """ stock_mov_obj = self.pool.get('stock.move') production = self.browse(cr, uid, production_id, context=context) + if not production.move_lines and production.state == 'ready': + # trigger workflow if not products to consume (eg: services) + self.signal_button_produce(cr, uid, [production_id]) + produced_qty = 0 + for produced_product in production.move_created_ids2: + if (produced_product.scrapped) or (produced_product.product_id.id != production.product_id.id): + continue + produced_qty += produced_product.product_qty + if production_mode in ['consume','consume_produce']: + consumed_data = {} + + # Calculate already consumed qtys + for consumed in production.move_lines2: + if consumed.scrapped: + continue + if not consumed_data.get(consumed.product_id.id, False): + consumed_data[consumed.product_id.id] = 0 + consumed_data[consumed.product_id.id] += consumed.product_qty + for consume in wiz.consume_lines: + # Search move for the product + corresponding_move = [x for x in production.move_lines if x.product_id.id == consume.product_id.id] + if corresponding_move: + corresponding_move = corresponding_move[0] + if corresponding_move.product_qty > consume.product_qty: + stock_mov_obj.action_consume(cr, uid, [corresponding_move.id], consume.product_qty, corresponding_move.location_id.id, + restrict_lot_id = consume.lot_id.id, context=context) + else: + stock_mov_obj.action_consume(cr, uid, [corresponding_move.id], corresponding_move.product_qty, corresponding_move.location_id.id, + restrict_lot_id = consume.lot_id.id, context=context) + + if production_mode == 'consume_produce': + # To produce remaining qty of final product + #vals = {'state':'confirmed'} + #final_product_todo = [x.id for x in production.move_created_ids] + #stock_mov_obj.write(cr, uid, final_product_todo, vals) + #stock_mov_obj.action_confirm(cr, uid, final_product_todo, context) + produced_products = {} + for produced_product in production.move_created_ids2: + if produced_product.scrapped: + continue + if not produced_products.get(produced_product.product_id.id, False): + 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: + produced_qty = produced_products.get(produce_product.product_id.id, 0) + subproduct_factor = self._get_subproduct_factor(cr, uid, production.id, produce_product.id, context=context) + rest_qty = (subproduct_factor * production.product_qty) - produced_qty + + if rest_qty < (subproduct_factor * production_qty): + prod_name = produce_product.product_id.name_get()[0][1] + raise osv.except_osv(_('Warning!'), _('You are going to produce total %s quantities of "%s".\nBut you can only produce up to total %s quantities.') % ((subproduct_factor * production_qty), prod_name, rest_qty)) + if rest_qty > 0 : + stock_mov_obj.action_consume(cr, uid, [produce_product.id], (subproduct_factor * production_qty), context=context) + + self.message_post(cr, uid, production_id, body=_("%s produced") % self._description, context=context) + self.signal_button_produce_done(cr, uid, [production_id]) + return True + + + + def action_produce2(self, cr, uid, production_id, production_qty, production_mode, 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. + If Production mode is consume & produce, all stock move lines of raw materials will be done/consumed + and stock move lines of final product will be also done/produced. + @param production_id: the ID of mrp.production object + @param production_qty: specify qty to produce + @param production_mode: specify production mode (consume/consume&produce). + @return: True + """ + stock_mov_obj = self.pool.get('stock.move') + production = self.browse(cr, uid, production_id, context=context) if not production.move_lines and production.state == 'ready': # trigger workflow if not products to consume (eg: services) self.signal_button_produce(cr, uid, [production_id]) @@ -992,7 +1074,6 @@ class mrp_production(osv.osv): 'product_uos': production_line.product_uos and production_line.product_uos.id or False, 'location_id': source_location_id, 'location_dest_id': destination_location_id, - 'move_dest_id': parent_move_id, 'company_id': production.company_id.id, 'procure_method': 'make_to_order', }) diff --git a/addons/mrp/stock.py b/addons/mrp/stock.py index ff59fcd5118..518755627ef 100644 --- a/addons/mrp/stock.py +++ b/addons/mrp/stock.py @@ -30,6 +30,8 @@ class StockMove(osv.osv): _columns = { 'production_id': fields.many2one('mrp.production', 'Production Order for Produced Products', select=True), 'raw_material_production_id': fields.many2one('mrp.production', 'Production Order for Raw Materials', select=True), + 'consumed_for': fields.many2one('stock.move', 'Consumed for'), + 'track_production': fields.related('product_id', 'track_production'), } def check_tracking(self, cr, uid, move, lot_id, context=None): diff --git a/addons/mrp/wizard/mrp_product_produce.py b/addons/mrp/wizard/mrp_product_produce.py index 0851657587c..6ccfbc25adc 100644 --- a/addons/mrp/wizard/mrp_product_produce.py +++ b/addons/mrp/wizard/mrp_product_produce.py @@ -22,6 +22,18 @@ from openerp.osv import fields, osv import openerp.addons.decimal_precision as dp + +class mrp_product_produce_line(osv.osv_memory): + _name="mrp.product.produce.line" + _description = "Product Produce Consume lines" + + _columns = { + 'product_id': fields.many2one('product.product', 'Product'), + 'product_qty': fields.float('Quantity'), + 'lot_id': fields.many2one('stock.production.lot', 'Lot'), + 'produce_id': fields.many2one('mrp.product.produce') + } + class mrp_product_produce(osv.osv_memory): _name = "mrp.product.produce" _description = "Product Produce" @@ -33,7 +45,56 @@ class mrp_product_produce(osv.osv_memory): help="'Consume only' mode will only consume the products with the quantity selected.\n" "'Consume & Produce' mode will consume as well as produce the products with the quantity selected " "and it will finish the production order when total ordered quantities are produced."), + 'lot_id': fields.many2one('stock.production.lot', 'Lot'), #Should only be visible when it is consume and produce mode + 'consume_lines': fields.one2many('mrp.product.produce.line', 'produce_id', 'Products Consumed'), } + + + def on_change_qty(self, cr, uid, ids, product_qty, consume_lines, context=None): + """ Will calculate number of products based on + """ + prod_obj = self.pool.get("mrp.production") + production = prod_obj.browse(cr, uid, context['active_id'], context=context) + + produced_qty = 0 + for produced_product in production.move_created_ids2: + if (produced_product.scrapped) or (produced_product.product_id.id != production.product_id.id): + continue + produced_qty += produced_product.product_qty + + + #Calculate consume lines + consumed_data = {} + for consumed in production.move_lines2: + if consumed.scrapped: + continue + if not consumed_data.get(consumed.product_id.id, False): + consumed_data[consumed.product_id.id] = 0 + consumed_data[consumed.product_id.id] += consumed.product_qty + + print "Consumed data", consumed_data + + new_consume_lines = [] + + # Find product qty to be consumed and consume it + for scheduled in production.product_lines: + + # total qty of consumed product we need after this consumption + total_consume = ((product_qty + produced_qty) * scheduled.product_qty / production.product_qty) + + # qty available for consume and produce + qty_avail = scheduled.product_qty - consumed_data.get(scheduled.product_id.id, 0.0) + + if qty_avail <= 0.0: + # there will be nothing to consume for this raw material + continue + + qty = total_consume - consumed_data.get(scheduled.product_id.id, 0.0) + dict_new = {'product_id': scheduled.product_id.id, 'product_qty': qty} + new_consume_lines.append([0, False, dict_new]) + + return {'value': {'consume_lines': new_consume_lines}} + def _get_product_qty(self, cr, uid, context=None): """ To obtain product quantity @@ -64,7 +125,7 @@ class mrp_product_produce(osv.osv_memory): assert production_id, "Production Id should be specified in context as a Active ID." data = self.browse(cr, uid, ids[0], context=context) self.pool.get('mrp.production').action_produce(cr, uid, production_id, - data.product_qty, data.mode, context=context) + data.product_qty, data.mode, data, context=context) return {} diff --git a/addons/mrp/wizard/mrp_product_produce_view.xml b/addons/mrp/wizard/mrp_product_produce_view.xml index f3e892a1b0a..0c9c1b7e060 100644 --- a/addons/mrp/wizard/mrp_product_produce_view.xml +++ b/addons/mrp/wizard/mrp_product_produce_view.xml @@ -12,8 +12,25 @@
- - + + + + + + + + + + + + +