'Moves all given stock.quant in the given destination location.  Unreserve from current move.
:param quants: list of tuple(browse record(stock.quant) or None, quantity to move)
:param move: browse record (stock.move)
:param location_to: browse record (stock.location) depicting where the quants have to be moved
:param location_from: optional browse record (stock.location) explaining where the quant has to be taken
(may differ from the move source location in case a removal strategy applied).
This parameter is only used to pass to _quant_create_from_move if a negative quant must be created
:param lot_id: ID of the lot that must be set on the quants to move
:param owner_id: ID of the partner that must own the quants to move
:param src_package_id: ID of the package that contains the quants to move
:param dest_package_id: ID of the package that must be set on the moved quant'

@api.model
def quants_move(self, quants, move, location_to, location_from=False, lot_id=False, owner_id=False, src_package_id=False, dest_package_id=False, entire_pack=False):

    if (location_to.usage == 'view'):
        raise UserError((_('You    cannot    move    to    a    location    of    type    view    %s.') % location_to.name))
    quants_reconcile_sudo = self.env['stock.quant'].sudo()
    quants_move_sudo = self.env['stock.quant'].sudo()
    check_lot = False
    for (quant, qty) in quants:
        if (not quant):
            quant = self._quant_create_from_move(qty, move, lot_id=lot_id, owner_id=owner_id, src_package_id=src_package_id, dest_package_id=dest_package_id, force_location_from=location_from, force_location_to=location_to)
            check_lot = True
        else:
            quant._quant_split(qty)
            quants_move_sudo |= quant
        quants_reconcile_sudo |= quant
    if quants_move_sudo:
        moves_recompute = quants_move_sudo.filtered((lambda self: (self.reservation_id != move))).mapped('reservation_id')
        quants_move_sudo._quant_update_from_move(move, location_to, dest_package_id, lot_id=lot_id, entire_pack=entire_pack)
        moves_recompute.recalculate_move_state()
    if (location_to.usage == 'internal'):
        self._cr.execute('\n                                                                SELECT    0    FROM    stock_quant,    stock_location    WHERE    product_id    =    %s    AND    stock_location.id    =    stock_quant.location_id    AND\n                                                                ((stock_location.parent_left    >=    %s    AND    stock_location.parent_left    <    %s)    OR    stock_location.id    =    %s)    AND    qty    <    0.0    LIMIT    1\n                                                ', (move.product_id.id, location_to.parent_left, location_to.parent_right, location_to.id))
        if self._cr.fetchone():
            quants_reconcile_sudo._quant_reconcile_negative(move)
    picking_type = ((move.picking_id and move.picking_id.picking_type_id) or False)
    if (check_lot and lot_id and (move.product_id.tracking == 'serial') and ((not picking_type) or (picking_type.use_create_lots or picking_type.use_existing_lots))):
        other_quants = self.search([('product_id', '=', move.product_id.id), ('lot_id', '=', lot_id), ('qty', '>', 0.0), ('location_id.usage', '=', 'internal')])
        if other_quants:
            if ((sum(other_quants.mapped('qty')) > 1.0) or (len([q for q in other_quants.mapped('qty') if (q < 0)]) > 1)):
                lot_name = self.env['stock.production.lot'].browse(lot_id).name
                raise UserError(((_('The    serial    number    %s    is    already    in    stock.') % lot_name) + _('Otherwise    make    sure    the    right    stock/owner    is    set.')))
