hunk.code_window:             for line, line_data in lines:
                   production._update_raw_move(line, line_data)
               operation_bom_qty = {}
               for bom, bom_data in boms:
                   for operation in bom.routing.operation_ids:
                       operation_bom_qty[operation.id] = bom_data['qty']
               self._update_product_to_produce(production, production.product_qty - production.qty_produced)
               moves = production.move_raw_ids.filtered(lambda x: x.state not in ('done', 'cancel'))
               moves.do_unreserve()
               moves.action_assign()
  
hunk.labels: keep keep keep keep replace keep keep keep keep keep
hunk.after_edit:                 for operation in bom.routing_id.operation_ids:
  
hunk.file_path: addons/mrp/wizard/change_production_qty.py
hunk.type: replace
file: # -*- coding: utf-8 -*-
  # Part of Odoo. See LICENSE file for full copyright and licensing details.
  
  from odoo import api, fields, models, _
  from odoo.addons import decimal_precision as dp
  from odoo.exceptions import UserError
  import math
  
  class ChangeProductionQty(models.TransientModel):
      _name = 'change.production.qty'
      _description = 'Change Quantity of Products'
  
      # TDE FIXME: add production_id field
      mo_id = fields.Many2one('mrp.production', 'Manufacturing Order', required=True)
      product_qty = fields.Float(
          'Quantity To Produce',
          digits=dp.get_precision('Product Unit of Measure'), required=True)
  
      @api.model
      def default_get(self, fields):
          res = super(ChangeProductionQty, self).default_get(fields)
          if 'mo_id' in fields and not res.get('mo_id') and self._context.get('active_model') == 'mrp.production' and self._context.get('active_id'):
              res['mo_id'] = self._context['active_id']
          if 'product_qty' in fields and not res.get('product_qty') and res.get('mo_id'):
              res['product_qty'] = self.env['mrp.production'].browse(res.get['mo_id']).product_qty
          return res
  
      @api.model
      def _update_product_to_produce(self, production, qty):
          production_move = production.move_finished_ids.filtered(lambda x:x.product_id.id == production.product_id.id and x.state not in ('done', 'cancel'))
          if production_move:
              production_move.write({'product_uom_qty': qty})
          else:
              production_move = production._generate_finished_moves()
              production_move = production.move_finished_ids.filtered(lambda x : x.state not in ('done', 'cancel') and production.product_id.id == x.product_id.id)
              production_move.write({'product_uom_qty': qty})
  
      @api.multi
      def change_prod_qty(self):
          for wizard in self:
              production = wizard.mo_id
              produced = sum(production.move_finished_ids.mapped('quantity_done'))
              if wizard.product_qty < produced:
                  raise UserError(_("You have already processed %d. Please input a quantity higher than %d ")%(produced, produced))
              production.write({'product_qty': wizard.product_qty})
              bom_point = production.bom_id
              factor = self.env['product.uom']._compute_qty(production.product_uom_id.id, production.product_qty - production.qty_produced, production.bom_id.product_uom_id.id) / production.bom_id.product_qty
              boms, lines = production.bom_id.explode(production.product_id, factor, picking_type=production.bom_id.picking_type_id)
              for line, line_data in lines:
                  production._update_raw_move(line, line_data)
              operation_bom_qty = {}
              for bom, bom_data in boms:
                  for operation in bom.routing.operation_ids:
                      operation_bom_qty[operation.id] = bom_data['qty']
              self._update_product_to_produce(production, production.product_qty - production.qty_produced)
              moves = production.move_raw_ids.filtered(lambda x: x.state not in ('done', 'cancel'))
              moves.do_unreserve()
              moves.action_assign()
              for wo in production.workorder_ids:
                  operation = wo.operation_id
                  if operation_bom_qty.get(operation.id):
                      cycle_number = math.ceil(operation_bom_qty[operation.id] / operation.workcenter_id.capacity)  # TODO: float_round UP
                      wo.duration_expected = (operation.workcenter_id.time_start +
                                   operation.workcenter_id.time_stop +
                                   cycle_number * operation.time_cycle * 100.0 / operation.workcenter_id.time_efficiency)
                  if production.product_id.tracking == 'serial':
                      quantity = 1.0
                  else:
                      quantity = wo.qty_production - wo.qty_produced
                      quantity = quantity if (quantity > 0) else 0
                  wo.qty_producing = quantity
                  if wo.qty_produced < wo.qty_production and wo.state == 'done':
                      wo.state = 'progress'
                  # assign moves; last operation receive all unassigned moves
                  # TODO: following could be put in a function as it is similar as code in _workorders_create
                  # TODO: only needed when creating new moves
                  moves_raw = production.move_raw_ids.filtered(lambda move: move.operation_id == operation and move.state not in ('done', 'cancel'))
                  if wo == production.workorder_ids[-1]:
                      moves_raw |= production.move_raw_ids.filtered(lambda move: not move.operation_id)
                  moves_finished = production.move_finished_ids.filtered(lambda move: move.operation_id == operation) #TODO: code does nothing, unless maybe by_products?
                  moves_raw.mapped('move_lot_ids').write({'workorder_id': wo.id})
                  (moves_finished + moves_raw).write({'workorder_id': wo.id})
                  if wo.move_raw_ids.filtered(lambda x: x.product_id.tracking != 'none') and not wo.active_move_lot_ids:
                      wo._generate_lot_ids()
          return {}
  