diff --git a/addons/sale_mrp/__openerp__.py b/addons/sale_mrp/__openerp__.py
index f36a565a3c7d464101d48726c291777d50c3ab25..b9c7b03356c34b55b9869b5efc75ec209a678899 100644
--- a/addons/sale_mrp/__openerp__.py
+++ b/addons/sale_mrp/__openerp__.py
@@ -21,9 +21,9 @@ from sales order. It adds sales name and sales Reference on production order.
     ],
     'demo': [],
     'test':[
-            'test/cancellation_propagated.yml',
-            'test/sale_mrp.yml',                        
-            ],
+        'test/cancellation_propagated.yml',
+        'test/sale_mrp.yml',
+        ],
     'installable': True,
     'auto_install': True,
 }
diff --git a/addons/sale_mrp/sale_mrp.py b/addons/sale_mrp/sale_mrp.py
index a113adaae0924ba040b64f154900108619262acd..9fb457abfb84fdbf499457ea4899e05cd8f81e86 100644
--- a/addons/sale_mrp/sale_mrp.py
+++ b/addons/sale_mrp/sale_mrp.py
@@ -1,93 +1,86 @@
 # -*- coding: utf-8 -*-
 # Part of Odoo. See LICENSE file for full copyright and licensing details.
 
-from openerp.osv import fields, osv
+from openerp import api, fields, models
+from openerp.tools import float_compare
 
-class mrp_production(osv.osv):
-    _inherit = 'mrp.production'
 
-    def _ref_calc(self, cr, uid, ids, field_names=None, arg=False, context=None):
-        """ Finds reference of sales order for production order.
-        @param field_names: Names of fields.
-        @param arg: User defined arguments
-        @return: Dictionary of values.
-        """
-        res = {}
-        if not field_names:
-            field_names = []
-        for id in ids:
-            res[id] = {}.fromkeys(field_names, False)
-        for f in field_names:
-            field_name = False
-            if f == 'sale_name':
-                field_name = 'name'
-            if f == 'sale_ref':
-                field_name = 'client_order_ref'
-            for key, value in self._get_sale_ref(cr, uid, ids, field_name).items():
-                res[key][f] = value
-        return res
+class MrpProduction(models.Model):
+    _inherit = 'mrp.production'
 
-    def _get_sale_ref(self, cr, uid, ids, field_name=False):
-        move_obj = self.pool.get('stock.move')
+    sale_name = fields.Char(compute='_compute_sale_name_sale_ref', string='Sale Name', help='Indicate the name of sales order.')
+    sale_ref = fields.Char(compute='_compute_sale_name_sale_ref', string='Sale Reference', help='Indicate the Customer Reference from sales order.')
 
-        def get_parent_move(move_id):
-            move = move_obj.browse(cr, uid, move_id)
+    @api.multi
+    def _compute_sale_name_sale_ref(self):
+        def get_parent_move(move):
             if move.move_dest_id:
                 return get_parent_move(move.move_dest_id.id)
-            return move_id
-
-        res = {}
-        productions = self.browse(cr, uid, ids)
-        for production in productions:
-            res[production.id] = False
+            return move
+        for production in self:
             if production.move_prod_id:
-                parent_move_line = get_parent_move(production.move_prod_id.id)
-                if parent_move_line:
-                    move = move_obj.browse(cr, uid, parent_move_line)
-                    if field_name == 'name':
-                        res[production.id] = move.procurement_id and move.procurement_id.sale_line_id and move.procurement_id.sale_line_id.order_id.name or False
-                    if field_name == 'client_order_ref':
-                        res[production.id] = move.procurement_id and move.procurement_id.sale_line_id and move.procurement_id.sale_line_id.order_id.client_order_ref or False
-        return res
+                move = get_parent_move(production.move_prod_id)
+            production.sale_name = move.procurement_id and move.procurement_id.sale_line_id and move.procurement_id.sale_line_id.order_id.name or False
+            production.sale_ref = move.procurement_id and move.procurement_id.sale_line_id and move.procurement_id.sale_line_id.order_id.client_order_ref or False
 
-    _columns = {
-        'sale_name': fields.function(_ref_calc, multi='sale_name', type='char', string='Sale Name', help='Indicate the name of sales order.'),
-        'sale_ref': fields.function(_ref_calc, multi='sale_name', type='char', string='Sale Reference', help='Indicate the Customer Reference from sales order.'),
-    }
 
+class SaleOrderLine(models.Model):
+    _inherit = 'sale.order.line'
 
-class sale_order(osv.Model):
-    _inherit = 'sale.order'
+    property_ids = fields.Many2many('mrp.property', 'sale_order_line_property_rel', 'order_id', 'property_id', 'Properties', readonly=True, states={'draft': [('readonly', False)]})
 
-    def _prepare_order_line_procurement(self, cr, uid, order, line, group_id=False, context=None):
-        result = super(sale_order, self)._prepare_order_line_procurement(cr, uid, order, line, group_id=group_id, context=context)
-        result['property_ids'] = [(6, 0, [x.id for x in line.property_ids])]
-        return result
+    @api.multi
+    def _get_delivered_qty(self):
+        self.ensure_one()
+        precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
 
+        # In the case of a kit, we need to check if all components are shipped. We use a all or
+        # nothing policy. A product can have several BoMs, we don't know which one was used when the
+        # delivery was created.
+        bom_delivered = {}
+        for bom in self.product_id.product_tmpl_id.bom_ids:
+            if bom.type != 'phantom':
+                continue
+            bom_delivered[bom.id] = False
+            bom_exploded = self.env['mrp.bom']._bom_explode(bom, self.product_id.product_tmpl_id, self.product_uom_qty)[0]
+            for bom_line in bom_exploded:
+                qty = 0.0
+                for move in self.procurement_ids.mapped('move_ids'):
+                    if move.state == 'done' and move.product_id.id == bom_line.get('product_id', False):
+                        qty += self.env['product.uom']._compute_qty_obj(move.product_uom, move.product_uom_qty, self.product_uom)
+                if float_compare(qty, bom_line['product_qty'], precision_digits=precision) < 0:
+                    bom_delivered[bom.id] = False
+                    break
+                else:
+                    bom_delivered[bom.id] = True
+        if bom_delivered and any(bom_delivered.values()):
+            return self.product_uom_qty
+        elif bom_delivered:
+            return 0.0
+        return super(SaleOrderLine, self)._get_delivered_qty()
 
-class sale_order_line(osv.osv):
+    @api.multi
+    def _prepare_order_line_procurement(self, group_id=False):
+        vals = super(SaleOrderLine, self)._prepare_order_line_procurement(group_id=group_id)
+        vals['property_ids'] = [(6, 0, self.property_ids.ids)]
+        return vals
 
-    _inherit = 'sale.order.line'
-    _columns = {
-        'property_ids': fields.many2many('mrp.property', 'sale_order_line_property_rel', 'order_id', 'property_id', 'Properties', readonly=True, states={'draft': [('readonly', False)]}),
-    }
-    
 
-class stock_move(osv.osv):
+class StockMove(models.Model):
     _inherit = 'stock.move'
-    
-    def _prepare_procurement_from_move(self, cr, uid, move, context=None):
-        res = super(stock_move, self)._prepare_procurement_from_move(cr, uid, move, context=context)
+
+    @api.model
+    def _prepare_procurement_from_move(self, move):
+        res = super(StockMove, self)._prepare_procurement_from_move(move)
         if res and move.procurement_id and move.procurement_id.property_ids:
-            res['property_ids'] = [(6, 0, [x.id for x in move.procurement_id.property_ids])]
+            res['property_ids'] = [(6, 0, self.property_ids.ids)]
         return res
 
-    def _action_explode(self, cr, uid, move, context=None):
+    @api.model
+    def _action_explode(self, move):
         """ Explodes pickings.
         @param move: Stock moves
         @return: True
         """
-        if context is None:
-            context = {}
-        property_ids = map(int, move.procurement_id.sale_line_id.property_ids or [])
-        return super(stock_move, self)._action_explode(cr, uid, move, context=dict(context, property_ids=property_ids))
+        property_ids = move.procurement_id.sale_line_id.property_ids.ids
+        return super(StockMove, self.with_context(property_ids=property_ids))._action_explode(move)
diff --git a/addons/sale_mrp/sale_mrp_view.xml b/addons/sale_mrp/sale_mrp_view.xml
index 002a5641fc5a800bd474482cd06194d2c6363116..a30fbcf54f0538439c235cc07bd1989277413e6e 100644
--- a/addons/sale_mrp/sale_mrp_view.xml
+++ b/addons/sale_mrp/sale_mrp_view.xml
@@ -1,8 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <openerp>
     <data>
-
-        <record id="view_mrp_production_form" model="ir.ui.view">
+        <record id="mrp_production_form_view_inherit_sale_mrp" model="ir.ui.view">
             <field name="name">mrp.production.form</field>
             <field name="model">mrp.production</field>
             <field name="inherit_id" ref="mrp.mrp_production_form_view"/>
@@ -16,18 +15,16 @@
             </field>
         </record>
 
-        <record id="view_order_form_inherit_mrp" model="ir.ui.view">
+        <record id="view_order_form_inherit_sale_mrp" model="ir.ui.view">
             <field name="name">sale.order.form.sale.stock.mrp</field>
             <field name="model">sale.order</field>
             <field name="inherit_id" ref="sale.view_order_form"/>
             <field name="arch" type="xml">
-               <xpath expr="//page/field[@name='order_line']/form/group/group/field[@name='th_weight']" position="after">
+               <xpath expr="//page/field[@name='order_line']/form/group/group/field[@name='tax_id']" position="after">
                    <field name="property_ids" widget="many2many_tags"
                         groups="sale.group_mrp_properties"/>
                </xpath>
             </field>
         </record>
-
-
     </data>
 </openerp>
diff --git a/addons/sale_mrp/test/cancellation_propagated.yml b/addons/sale_mrp/test/cancellation_propagated.yml
index 0d72e3d9f3e5231c885dbfdc1bdf4871e3bbc84d..84b795b1d32d71dca871744ebef7797a484f2a19 100644
--- a/addons/sale_mrp/test/cancellation_propagated.yml
+++ b/addons/sale_mrp/test/cancellation_propagated.yml
@@ -43,14 +43,18 @@
     partner_id: base.res_partner_3
     note: Create Sales order
     warehouse_id: wh_pps
+    pricelist_id: product.list0
     order_line:
       - product_id: product_manu
+        name: "product_manu"
         product_uom_qty: 5.00
+        product_uom: product.product_uom_unit
 
 - 
   Confirm sales order
 - 
-  !workflow {model: sale.order, action: order_confirm, ref: sale_order_product_manu}
+  !python {model: sale.order}: |
+    self.action_confirm(cr, uid, ref("sale_order_product_manu"), context=context)
 -
   I run scheduler.
 -
diff --git a/addons/sale_mrp/test/sale_mrp.yml b/addons/sale_mrp/test/sale_mrp.yml
index 023bdae08f4c715e10cb3e0240641f9002df1945..eddf48a20bb98b8e73fc59e62debface3ccb3054 100644
--- a/addons/sale_mrp/test/sale_mrp.yml
+++ b/addons/sale_mrp/test/sale_mrp.yml
@@ -16,7 +16,6 @@
   !record {model: product.template, id: product_template_slidermobile0}:
     categ_id: product_category_allproductssellable0
     list_price: 200.0
-    mes_type: fixed
     name: Slider Mobile
     standard_price: 189.0
     type: product
@@ -28,7 +27,6 @@
   !record {model: product.product, id:  product_product_slidermobile0}:
     categ_id: product_category_allproductssellable0
     list_price: 200.0
-    mes_type: fixed
     name: Slider Mobile
     seller_delay: '1'
     seller_ids:
@@ -72,10 +70,8 @@
         product_uom: product.product_uom_unit
         product_uom_qty: 500.0
         state: draft
-        delay: 7.0
+        customer_lead: 7.0
         product_id: product_product_slidermobile0
-        product_uos_qty: 500.0
-    order_policy: manual
     partner_id: base.res_partner_4
     partner_invoice_id: base.res_partner_address_7
     partner_shipping_id: base.res_partner_address_7
@@ -84,7 +80,8 @@
 -
   I confirm the sale order
 -
-  !workflow {model: sale.order, action: order_confirm, ref: sale_order_so0}
+  !python {model: sale.order}: |
+    self.action_confirm(cr, uid, ref("sale_order_so0"), context=context)
 -
   I verify that a procurement has been generated for sale order
 -
@@ -120,5 +117,5 @@
     mnf_id = mnf_obj.search(cr, uid, [('origin','like',so.name)])
     assert mnf_id, 'Manufacturing order has not been generated'
     mo = mnf_obj.browse(cr, uid, mnf_id)[0]
-    assert mo.sale_name == so.name, 'Wrong Name for the Manufacturing Order. Expected %s, Got %s' % (so.name, mo.name)
+    assert mo.sale_name == so.name, 'Wrong Name for the Manufacturing Order. Expected %s, Got %s' % (so.name, mo.sale_name)
     assert mo.sale_ref == so.client_order_ref, 'Wrong Sale Reference for the Manufacturing Order'
diff --git a/addons/sale_mrp/tests/test_move_explode.py b/addons/sale_mrp/tests/test_move_explode.py
index c5f803408e081b15c4ecd0370ca02bacdc25e185..a7e3bdea946b80f769afd26fde73edd82b430f05 100644
--- a/addons/sale_mrp/tests/test_move_explode.py
+++ b/addons/sale_mrp/tests/test_move_explode.py
@@ -8,66 +8,71 @@ class TestMoveExplode(common.TransactionCase):
 
     def setUp(self):
         super(TestMoveExplode, self).setUp()
-        cr, uid = self.cr, self.uid
-
         # Usefull models
-        self.ir_model_data = self.registry('ir.model.data')
-        self.sale_order_line = self.registry('sale.order.line')
-        self.sale_order = self.registry('sale.order')
-        self.mrp_bom = self.registry('mrp.bom')
-        self.product = self.registry('product.product')
+        self.SaleOrderLine = self.env['sale.order.line']
+        self.SaleOrder = self.env['sale.order']
+        self.MrpBom = self.env['mrp.bom']
+        self.Product = self.env['product.product']
 
         #product that has a phantom bom
-        self.product_bom_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'product_product_3')[1]
+        self.product_bom = self.env.ref('product.product_product_3')
         #bom with that product
-        self.bom_id = self.ir_model_data.get_object_reference(cr, uid, 'mrp', 'mrp_bom_9')[1]
+        self.bom = self.env.ref('mrp.mrp_bom_9')
         #partner agrolait
-        self.partner_id = self.ir_model_data.get_object_reference(cr, uid, 'base', 'res_partner_1')[1]
+        self.partner = self.env.ref('base.res_partner_1')
         #bom: PC Assemble (with property: DDR 512MB)
-        self.bom_prop_id = self.ir_model_data.get_object_reference(cr, uid, 'mrp', 'mrp_bom_property_0')[1]
+        self.bom_prop = self.env.ref('mrp.mrp_bom_property_0')
 
-        self.template_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'product_product_3_product_template')[1]
+        self.template = self.env.ref('product.product_product_3_product_template')
         #property: DDR 512MB
-        self.mrp_property_id = self.ir_model_data.get_object_reference(cr, uid, 'mrp', 'mrp_property_0')[1]
+        self.mrp_property = self.env.ref('mrp.mrp_property_0')
         #product: RAM SR2
-        self.product_bom_prop_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'product_product_14')[1]
+        self.product_bom_prop = self.env.ref('product.product_product_14')
         #phantom bom for RAM SR2 with three lines containing properties
-        self.bom_prop_line_id = self.ir_model_data.get_object_reference(cr, uid, 'mrp', 'mrp_bom_property_line')[1]
+        self.bom_prop_line = self.env.ref('mrp.mrp_bom_property_line')
         #product: iPod included in the phantom bom
-        self.product_A_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'product_product_11')[1]
+        self.product_A = self.env.ref('product.product_product_11')
         #product: Mouse, Wireless included in the phantom bom
-        self.product_B_id = self.ir_model_data.get_object_reference(cr, uid, 'product', 'product_product_12')[1]
+        self.product_B = self.env.ref('product.product_product_12')
+        #pricelist
+        self.pricelist = self.env.ref('product.list0')
 
 
     def test_00_sale_move_explode(self):
         """check that when creating a sale order with a product that has a phantom BoM, move explode into content of the
             BoM"""
-        cr, uid, context = self.cr, self.uid, {}
         #create sale order with one sale order line containing product with a phantom bom
-        so_id = self.sale_order.create(cr, uid, vals={'partner_id': self.partner_id}, context=context)
-        self.sale_order_line.create(cr, uid, values={'order_id': so_id, 'product_id': self.product_bom_id, 'product_uom_qty': 1}, context=context)
+        so_vals = {
+            'partner_id': self.partner.id,
+            'partner_invoice_id': self.partner.id,
+            'partner_shipping_id': self.partner.id,
+            'pricelist_id': self.pricelist.id,
+        }
+        self.so = self.SaleOrder.create(vals=so_vals)
+        sol_vals = {
+            'order_id': self.so.id,
+            'name': self.product_bom.name,
+            'product_id': self.product_bom.id,
+            'product_uom': self.product_bom.uom_id.id,
+            'product_uom_qty': 1.0,
+        }
+        self.SaleOrderLine.create(values=sol_vals)
         #confirm sale order
-        self.sale_order.action_button_confirm(cr, uid, [so_id], context=context)
+        self.so.action_confirm()
         #get all move associated to that sale_order
-        browse_move_ids = self.sale_order.browse(cr, uid, so_id, context=context).picking_ids[0].move_lines
-        move_ids = [x.id for x in browse_move_ids]
+        move_ids = self.so.picking_ids.mapped('move_lines').ids
         #we should have same amount of move as the component in the phatom bom
-        bom = self.mrp_bom.browse(cr, uid, self.bom_id, context=context)
-        bom_component_length = self.mrp_bom._bom_explode(cr, uid, bom, self.product_bom_id, 1, [])
+        bom_component_length = self.MrpBom._bom_explode(self.bom, self.product_bom, 1.0, [])
         self.assertEqual(len(move_ids), len(bom_component_length[0]))
 
     def test_00_bom_find(self):
         """Check that _bom_find searches the bom corresponding to the properties passed or takes the bom with the smallest
             sequence."""
-        cr, uid, context = self.cr, self.uid, {}
-        res_id = self.mrp_bom._bom_find(cr, uid, product_tmpl_id=self.template_id, product_id=None, properties=[self.mrp_property_id], context=context)
-        self.assertEqual(res_id, self.bom_prop_id)
+        res_id = self.MrpBom._bom_find(product_tmpl_id=self.template.id, product_id=None, properties=[self.mrp_property.id])
+        self.assertEqual(res_id, self.bom_prop.id)
 
     def test_00_bom_explode(self):
         """Check that _bom_explode only takes the lines with the right properties."""
-        cr, uid, context = self.cr, self.uid, {}
-        bom = self.mrp_bom.browse(cr, uid, self.bom_prop_line_id)
-        product = self.product.browse(cr, uid, self.product_bom_prop_id)
-        res = self.mrp_bom._bom_explode(cr, uid, bom, product, 1, properties=[self.mrp_property_id], context=context)
+        res = self.MrpBom._bom_explode(self.bom_prop_line, self.product_bom_prop, 1, properties=[self.mrp_property.id])
         res = set([p['product_id'] for p in res[0]])
-        self.assertEqual(res, set([self.product_A_id, self.product_B_id]))
+        self.assertEqual(res, set([self.product_A.id, self.product_B.id]))
diff --git a/addons/sale_mrp/tests/test_sale_mrp_flow.py b/addons/sale_mrp/tests/test_sale_mrp_flow.py
index 91696286168c5551d53fd38ff8ccc37756a32dda..d8c703a6ba3af8168c33f287af292ead50024f3f 100644
--- a/addons/sale_mrp/tests/test_sale_mrp_flow.py
+++ b/addons/sale_mrp/tests/test_sale_mrp_flow.py
@@ -8,7 +8,7 @@ class TestSaleMrpFlow(common.TransactionCase):
 
     def setUp(self):
         super(TestSaleMrpFlow, self).setUp()
-        # Usefull models
+        # Useful models
         self.SaleOrderLine = self.env['sale.order.line']
         self.SaleOrder = self.env['sale.order']
         self.MrpBom = self.env['mrp.bom']
@@ -116,16 +116,20 @@ class TestSaleMrpFlow(common.TransactionCase):
 
         order = self.SaleOrder.create({
             'partner_id': self.partner_agrolite.id,
+            'partner_invoice_id': self.partner_agrolite.id,
+            'partner_shipping_id': self.partner_agrolite.id,
             'date_order': datetime.today(),
+            'pricelist_id': self.env.ref('product.list0').id,
         })
         self.SaleOrderLine.create({
+            'name': product_a.name,
             'order_id': order.id,
             'product_id': product_a.id,
             'product_uom_qty': 10,
             'product_uom': self.uom_dozen.id
         })
         self.assertTrue(order, "Sale order not created.")
-        order.action_button_confirm()
+        order.action_confirm()
 
         # ===============================================================================
         #  Sale order of 10 Dozen product A should create production order
@@ -346,3 +350,48 @@ class TestSaleMrpFlow(common.TransactionCase):
         self.assertEqual(mnf_product_a.state, 'done', 'Manufacturing order should be done.')
         # Check product A avaialble quantity should be 120.
         self.assertEqual(product_a.qty_available, 120, 'Wrong quantity available of product A.')
+
+    def test_01_sale_mrp_delivery_kit(self):
+        """ Test delivered quantity on SO based on delivered quantity in pickings."""
+        # intial so
+        self.partner = self.env.ref('base.res_partner_1')
+        self.product = self.env.ref('product.product_product_3')
+        so_vals = {
+            'partner_id': self.partner.id,
+            'partner_invoice_id': self.partner.id,
+            'partner_shipping_id': self.partner.id,
+            'order_line': [(0, 0, {'name': self.product.name, 'product_id': self.product.id, 'product_uom_qty': 5, 'product_uom': self.product.uom_id.id, 'price_unit': self.product.list_price})],
+            'pricelist_id': self.env.ref('product.list0').id,
+        }
+        self.so = self.SaleOrder.create(so_vals)
+
+        # confirm our standard so, check the picking
+        self.so.action_confirm()
+        self.assertTrue(self.so.picking_ids, 'Sale MRP: no picking created for "invoice on delivery" stockable products')
+
+        # invoice in on delivery, nothing should be invoiced
+        self.so.action_invoice_create()
+        self.assertEqual(self.so.invoice_status, 'no', 'Sale MRP: so invoice_status should be "nothing to invoice" after invoicing')
+
+        # deliver partially (1 of each instead of 5), check the so's invoice_status and delivered quantities
+        pick = self.so.picking_ids
+        pick.force_assign()
+        pick.pack_operation_product_ids.write({'qty_done': 1})
+        wiz_act = pick.do_new_transfer()
+        wiz = self.env[wiz_act['res_model']].browse(wiz_act['res_id'])
+        wiz.process()
+
+        self.assertEqual(self.so.invoice_status, 'no', 'Sale MRP: so invoice_status should be "no" after partial delivery of a kit')
+        del_qty = sum(sol.qty_delivered for sol in self.so.order_line)
+        self.assertEqual(del_qty, 0.0, 'Sale MRP: delivered quantity should be zero after partial delivery of a kit')
+
+        # deliver remaining products, check the so's invoice_status and delivered quantities
+        self.assertEqual(len(self.so.picking_ids), 2, 'Sale MRP: number of pickings should be 2')
+        pick_2 = self.so.picking_ids[0]
+        pick_2.force_assign()
+        pick_2.pack_operation_product_ids.write({'qty_done': 4})
+        pick_2.do_new_transfer()
+
+        del_qty = sum(sol.qty_delivered for sol in self.so.order_line)
+        self.assertEqual(del_qty, 5.0, 'Sale MRP: delivered quantity should be 5.0 after complete delivery of a kit')
+        self.assertEqual(self.so.invoice_status, 'to invoice', 'Sale MRP: so invoice_status should be "to invoice" after complete delivery of a kit')