'Process completely the moves given and if all moves are done, it will finish the picking.'

@api.multi
def action_done(self):

    self.filtered((lambda move: (move.state == 'draft'))).action_confirm()
    Uom = self.env['product.uom']
    Quant = self.env['stock.quant']
    pickings = self.env['stock.picking']
    procurements = self.env['procurement.order']
    operations = self.env['stock.pack.operation']
    remaining_move_qty = {}
    for move in self:
        if move.picking_id:
            pickings |= move.picking_id
        remaining_move_qty[move.id] = move.product_qty
        for link in move.linked_move_operation_ids:
            operations |= link.operation_id
            pickings |= link.operation_id.picking_id
    operations = operations.sorted(key=(lambda x: (((((x.package_id and (not x.product_id)) and (-4)) or 0) + ((x.package_id and (-2)) or 0)) + ((x.pack_lot_ids and (-1)) or 0))))
    for operation in operations:
        quant_dest_package_id = ((operation.product_id and operation.result_package_id.id) or False)
        entire_pack = (((not operation.product_id) and True) or False)
        lot_quantities = dict(((pack_lot.lot_id.id, operation.product_uom_id._compute_quantity(pack_lot.qty, operation.product_id.uom_id)) for pack_lot in operation.pack_lot_ids))
        qty = operation.product_qty
        if (operation.product_uom_id and (operation.product_uom_id != operation.product_id.uom_id)):
            qty = operation.product_uom_id._compute_quantity(qty, operation.product_id.uom_id)
        if (operation.pack_lot_ids and (float_compare(sum(lot_quantities.values()), qty, precision_rounding=operation.product_id.uom_id.rounding) != 0.0)):
            raise UserError(_('You    have    a    difference    between    the    quantity    on    the    operation    and    the    quantities    specified    for    the    lots.    '))
        quants_taken = []
        false_quants = []
        lot_move_qty = {}
        prout_move_qty = {}
        for link in operation.linked_move_operation_ids:
            prout_move_qty[link.move_id] = (prout_move_qty.get(link.move_id, 0.0) + link.qty)
        for move in prout_move_qty.keys():
            move.check_tracking(operation)
            if (not remaining_move_qty.get(move.id)):
                raise UserError((_("The    roundings    of    your    unit    of    measure    %s    on    the    move    vs.    %s    on    the    product    don't    allow    to    do    these    operations    or    you    are    not    transferring    the    picking    at    once.    ") % (move.product_uom.name, move.product_id.uom_id.name)))
            if (not operation.pack_lot_ids):
                preferred_domain_list = [[('reservation_id', '=', move.id)], [('reservation_id', '=', False)], ['&', ('reservation_id', '!=', move.id), ('reservation_id', '!=', False)]]
                quants = Quant.quants_get_preferred_domain(prout_move_qty[move], move, ops=operation, domain=[('qty', '>', 0)], preferred_domain_list=preferred_domain_list)
                Quant.quants_move(quants, move, operation.location_dest_id, location_from=operation.location_id, lot_id=False, owner_id=operation.owner_id.id, src_package_id=operation.package_id.id, dest_package_id=quant_dest_package_id, entire_pack=entire_pack)
            else:
                qty_on_link = prout_move_qty[move]
                rounding = operation.product_id.uom_id.rounding
                for reserved_quant in move.reserved_quant_ids:
                    if ((reserved_quant.owner_id.id != operation.owner_id.id) or (reserved_quant.location_id.id != operation.location_id.id) or (reserved_quant.package_id.id != operation.package_id.id)):
                        continue
                    if (not reserved_quant.lot_id):
                        false_quants += [reserved_quant]
                    elif (float_compare(lot_quantities.get(reserved_quant.lot_id.id, 0), 0, precision_rounding=rounding) > 0):
                        if (float_compare(lot_quantities[reserved_quant.lot_id.id], reserved_quant.qty, precision_rounding=rounding) >= 0):
                            lot_quantities[reserved_quant.lot_id.id] -= reserved_quant.qty
                            quants_taken += [(reserved_quant, reserved_quant.qty)]
                            qty_on_link -= reserved_quant.qty
                        else:
                            quants_taken += [(reserved_quant, lot_quantities[reserved_quant.lot_id.id])]
                            lot_quantities[reserved_quant.lot_id.id] = 0
                            qty_on_link -= lot_quantities[reserved_quant.lot_id.id]
                lot_move_qty[move.id] = qty_on_link
            remaining_move_qty[move.id] -= prout_move_qty[move]
        if operation.pack_lot_ids:
            self._move_quants_by_lot(operation, lot_quantities, quants_taken, false_quants, lot_move_qty, quant_dest_package_id)
        if ((not operation.product_id) and operation.package_id and (operation.result_package_id.id != operation.package_id.parent_id.id)):
            operation.package_id.sudo().write({'parent_id': operation.result_package_id.id})
    move_dest_ids = set()
    for move in self:
        if (float_compare(remaining_move_qty[move.id], 0, precision_rounding=move.product_id.uom_id.rounding) > 0):
            move.check_tracking(False)
            preferred_domain_list = [[('reservation_id', '=', move.id)], [('reservation_id', '=', False)], ['&', ('reservation_id', '!=', move.id), ('reservation_id', '!=', False)]]
            quants = Quant.quants_get_preferred_domain(remaining_move_qty[move.id], move, domain=[('qty', '>', 0)], preferred_domain_list=preferred_domain_list)
            Quant.quants_move(quants, move, move.location_dest_id, lot_id=move.restrict_lot_id.id, owner_id=move.restrict_partner_id.id)
        if (move.move_dest_id and (move.move_dest_id.state in ('waiting', 'confirmed'))):
            move_dest_ids.add(move.move_dest_id.id)
        if move.procurement_id:
            procurements |= move.procurement_id
        move.quants_unreserve()
    self.mapped('quant_ids').filtered((lambda quant: (quant.package_id and (quant.qty > 0)))).mapped('package_id')._check_location_constraint()
    self.write({'state': 'done', 'date': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)})
    procurements.check()
    if move_dest_ids:
        self.browse(list(move_dest_ids)).action_assign()
    pickings.filtered((lambda picking: ((picking.state == 'done') and (not picking.date_done)))).write({'date_done': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)})
    return True
