diff --git a/addons/purchase_stock/models/purchase.py b/addons/purchase_stock/models/purchase.py
index ba886f1e7cbc4869f809c1204b2937c08486d86a..9c47841fdcc3f868e350811245fa2fe808dcf390 100644
--- a/addons/purchase_stock/models/purchase.py
+++ b/addons/purchase_stock/models/purchase.py
@@ -29,7 +29,7 @@ class PurchaseOrder(models.Model):
     is_shipped = fields.Boolean(compute="_compute_is_shipped")
     effective_date = fields.Datetime("Effective Date", compute='_compute_effective_date', store=True, copy=False,
         help="Completion date of the first receipt order.")
-    on_time_rate = fields.Float(related='partner_id.on_time_rate')
+    on_time_rate = fields.Float(related='partner_id.on_time_rate', compute_sudo=False)
 
     @api.depends('order_line.move_ids.picking_id')
     def _compute_picking(self):
diff --git a/addons/purchase_stock/tests/test_purchase_order.py b/addons/purchase_stock/tests/test_purchase_order.py
index 90aae7a98d15331d17cd4944770b9c9e58cfd4bf..ddb5dd80ceb2d5c4c68d8b99b89dff30d9558c6a 100644
--- a/addons/purchase_stock/tests/test_purchase_order.py
+++ b/addons/purchase_stock/tests/test_purchase_order.py
@@ -263,3 +263,68 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon):
         self.assertEqual(po.company_id, company_a)
         self.assertEqual(po.picking_type_id.warehouse_id.company_id, company_a)
         self.assertEqual(po.currency_id, po.company_id.currency_id)
+
+    def test_06_on_time_rate(self):
+        company_a = self.env.user.company_id
+        company_b = self.env['res.company'].create({
+            "name": "Test Company",
+            "currency_id": self.env['res.currency'].with_context(active_test=False).search([
+                ('id', '!=', company_a.currency_id.id),
+            ], limit=1).id
+        })
+
+        # Create a purchase order with 90% qty received for company A
+        self.env.user.write({
+            'company_id': company_a.id,
+            'company_ids': [(6, 0, [company_a.id])],
+        })
+        po = self.env['purchase.order'].create(self.po_vals)
+        po.order_line.write({'product_qty': 10})
+        po.button_confirm()
+        picking = po.picking_ids[0]
+        # Process 9.0 out of the 10.0 ordered qty
+        picking.move_line_ids.write({'qty_done': 9.0})
+        res_dict = picking.button_validate()
+        # No backorder
+        self.env['stock.backorder.confirmation'].with_context(res_dict['context']).process_cancel_backorder()
+        # `on_time_rate` should be equals to the ratio of quantity received against quantity ordered
+        expected_rate = sum(picking.move_line_ids.mapped("qty_done")) / sum(po.order_line.mapped("product_qty")) * 100
+        self.assertEqual(expected_rate, po.on_time_rate)
+
+        # Create a purchase order with 80% qty received for company B
+        # The On-Time Delivery Rate shouldn't be shared accross multiple companies
+        self.env.user.write({
+            'company_id': company_b.id,
+            'company_ids': [(6, 0, [company_b.id])],
+        })
+        po = self.env['purchase.order'].create(self.po_vals)
+        po.order_line.write({'product_qty': 10})
+        po.button_confirm()
+        picking = po.picking_ids[0]
+        # Process 8.0 out of the 10.0 ordered qty
+        picking.move_line_ids.write({'qty_done': 8.0})
+        res_dict = picking.button_validate()
+        # No backorder
+        self.env['stock.backorder.confirmation'].with_context(res_dict['context']).process_cancel_backorder()
+        # `on_time_rate` should be equal to the ratio of quantity received against quantity ordered
+        expected_rate = sum(picking.move_line_ids.mapped("qty_done")) / sum(po.order_line.mapped("product_qty")) * 100
+        self.assertEqual(expected_rate, po.on_time_rate)
+
+        # Tricky corner case
+        # As `purchase.order.on_time_rate` is a related to `partner_id.on_time_rate`
+        # `on_time_rate` on the PO should equals `on_time_rate` on the partner.
+        # Related fields are by default computed as sudo
+        # while non-stored computed fields are not computed as sudo by default
+        # If the computation of the related field (`purchase.order.on_time_rate`) was asked
+        # and `res.partner.on_time_rate` was not yet in the cache
+        # the `sudo` requested for the computation of the related `purchase.order.on_time_rate`
+        # was propagated to the computation of `res.partner.on_time_rate`
+        # and therefore the multi-company record rules were ignored.
+        # 1. Compute `res.partner.on_time_rate` regular non-stored comptued field
+        partner_on_time_rate = po.partner_id.on_time_rate
+        # 2. Invalidate the cache for that record and field, so it's not reused in the next step.
+        po.partner_id.invalidate_cache(fnames=["on_time_rate"], ids=po.partner_id.ids)
+        # 3. Compute the related field `purchase.order.on_time_rate`
+        po_on_time_rate = po.on_time_rate
+        # 4. Check both are equals.
+        self.assertEqual(partner_on_time_rate, po_on_time_rate)