Skip to content
Snippets Groups Projects
Commit 1b729171 authored by Denis Ledoux's avatar Denis Ledoux
Browse files

[FIX] purchase_stock: `on_time_rate` in multi companies


Because of the weird behavior of the ORM regarding
related field pointing to computed fields,
`on_time_rate` was taking account of all companies
when asking it through `purchase.order.on_time_rate`
but it was single-company when asked through `res.partner.on_time_rate`.

It was observed during an upgrade request issue analysis,
and in that case the problem was not even the fact
it was miscomputed, but the fact this computed field,
computed as sudo, leaded to fill the cache for
`purchase.order.line.move_ids` with `stock.move` belonging
to other companies than the user one,
and then when attempting to read values from these stock moves
a multi-company access error was raised.

upg-8106

closes odoo/odoo#66840

Signed-off-by: default avatarDenis Ledoux (dle) <dle@odoo.com>
parent 3d401a30
No related branches found
No related tags found
No related merge requests found
......@@ -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.returned_move_ids',
'order_line.move_ids.state',
......
......@@ -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)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment