### Impacted versions:
10.0
### Steps to reproduce:
1/ Install a database with sale_stock module
2/ Initialize some data with this script to run through shell command:

```python
# -*- coding: utf-8 -*-
import logging

_logger = logging.getLogger(__name__)
self = self  # noqa

# Install a language

wizard = self.env['base.language.install'].create({
        'lang': 'fr_BE'
    })
wizard.lang_install()


# Product creation
nb_product = 5000

i = 0

while i < nb_product:
    prod = self.env['product.template'].with_context(
        tracking_disable=True, lang='fr_BE').create({
            'name': 'product_%s' % i,
        })
    i += 1
    if i % 1000 == 0:
        self.env.cr.commit()
        _logger.info("%s Products Created" % i)

# Add a lot of fake translations
cpt = 200000
values = []
cr = self.env.cr
while cpt:
    cpt -= 1
    values.append(
        cr.mogrify(
            "(%s, %s, %s, %s)", (
                'fr_BE',
                'product.template,name',
                'translated',
                '%s' % cpt)
        )
    )
_logger.info('Create %d fake translations' % len(values))
self.env.cr.execute(
    """
    INSERT INTO ir_translation (lang, name, state, value) VALUES
    """ + ','.join(values))
_logger.info('%d fake translations created' % len(values))

# Update stock
i = 0
for product in self.env['product.product'].search([]):
    self.env['stock.quant'].sudo().create({
        'product_id': product.id,
        'location_id': self.env.ref('stock.stock_location_stock').id,
        'qty': 1.0
        })
    i += 1
    if i % 1000 == 0:
        self.env.cr.commit()
        _logger.info("%s Quants Created" % i)
```

3/ / Run the following code through shell command with log_level=debug_sql:

`odoo  shell -d odoo-tmp -c odoo.cfg --log-level=debug_sql < test.py &> log.txt`

This script 
* add a new field `x_product_virtual_available` on `sale.order.line`. This field is a related on `product_id.virtual_available`. (Our users want to see the Forecast quantity on the sale.order.line)
*  simulate a call to  onchange  from the browser on the model `the sale.order` for the field `order_line`. Our so is a new SO with 20 lines.

```python
# -*- coding: utf-8 -*-
import logging
import random
import time

_logger = logging.getLogger(__name__)


partner = self.env.ref('base.res_partner_1')

# create a in memory SO
order_line =[]
sale_order = self.env['sale.order']
so_values = {
    'partner_id': partner.id,
    'partner_invoice_id': partner.id,
    'partner_shipping_id': partner.id,
    'order_line': [],
    'amount_total': 0,
    'amount_tax': 0,
    'amount_untaxed': 0,
    'order_line': order_line
}

original_so = sale_order.new(so_values)
sale_order_line_model_id = self.env['ir.model'].search([('model', '=',
                                              'sale.order.line')])


# add a related on sale.order.line to product_id

if not self.env['ir.model.fields'].search([('name', '=', 'x_product_virtual_available')]):
    self.env['ir.model.fields'].create({
        'name': 'x_product_virtual_available',
        'ttype': 'float',
        'related': 'product_id.virtual_available',
        'required': False,
        'readonly': True,
        'model_id': sale_order_line_model_id.id,
        'store': False,
    })

user_demo = self.env.ref('base.user_demo')
self = self.sudo(user_demo.id).with_context(lang='fr_BE')  # noqa


onchange_specs = sale_order._onchange_spec()
print onchange_specs
onchange_specs['order_line.x_product_virtual_available'] = 0


NB_PRODUCT = 5000
STEP = 20
MAX_LINES =  20

i = 0

while i < MAX_LINES:
    if i % STEP == 0:
        # add lines
        for p in range(STEP):
            x_product_name = 'product_%s' % random.randint(0, NB_PRODUCT)
            p = self.env['product.product'].search([('name', '=', x_product_name)])
            order_line.append(
                (0, 0,
                 {'name': p.name,
                  'product_id': p.id,
                  'product_uom_qty': 2,
                  'product_uom': p.uom_id.id,
                  'price_unit': p.list_price,
                  'x_product_name': '',
                  'price_unit': 10,
                  'price_total': 10,
                  'price_subtotal': 10,
                  'product_uom': self.env.ref('product.product_uom_unit').id})
            )
            # we work on a temporary record

        start_time = time.time()
        res = original_so.onchange(so_values, 'order_line', onchange_specs)
        elapsed_time = time.time() - start_time
        _logger.info('On change with %s lines took %.3f' % (len(
            order_line), elapsed_time))
    i+=1

```

4/ Takes a look into the `log.txt`file .......

### Current behavior:

Our related products on the line are read one by one and the compute of `virtual_available` is also done one by one.

### Expected behavior:

Our related products on the lines are read all at once and the compute of `virtual_available` is done for all the products at once.

For our customer, the screen to create a new sale order becomes unusable beyond about twenty new lines because we have to show him an information that takes 0.5 sec to be computed.This compute is called up for each line and not for all products at once.

vals = super(SaleOrderLine, self)._prepare_order_line_procurement(group_id=group_id)
        date_planned = datetime.strptime(self.order_id.date_order, DEFAULT_SERVER_DATETIME_FORMAT)\
            + timedelta(days=self.customer_lead or 0.0) - timedelta(days=self.order_id.company_id.security_lead)
        vals.update({
            'date_planned': date_planned.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
            'location_id': self.order_id.partner_shipping_id.property_stock_customer.id,
            'route_ids': self.route_id and [(4, self.route_id.id)] or [],
            'warehouse_id': self.order_id.warehouse_id and self.order_id.warehouse_id.id or False,
            'partner_dest_id': self.order_id.partner_shipping_id.id,
            'sale_line_id': self.id,
        })
        return vals
    @api.multi
    def _get_delivered_qty(self):
        """Computes the delivered quantity on sale order lines, based on done stock moves related to its procurements
        """
        self.ensure_one()
        super(SaleOrderLine, self)._get_delivered_qty()
        qty = 0.0
        for move in self.procurement_ids.mapped('move_ids').filtered(lambda r: r.state == 'done' and not r.scrapped):
            if move.location_dest_id.usage == "customer":
                if not move.origin_returned_move_id:
                    qty += move.product_uom._compute_quantity(move.product_uom_qty, self.product_uom)
            elif move.location_dest_id.usage != "customer" and move.to_refund_so:
                qty -= move.product_uom._compute_quantity(move.product_uom_qty, self.product_uom)
        return qty
    @api.multi
    def _check_package(self):