Hi everyone,
I’ve come across what appears to be an inconsistency in how Odoo evaluates record rules, and it might be a bug. Specifically, when attempting to confirm a purchase order from "draft" to "purchase," it seems like Odoo checks permissions for both the current state and the target state at the same time. This results in an access error, even though the rules should allow the transition.
Example Rules:
Here are the two record rules applied to the user’s group:
{ "id": 386, "name": "All Purchase Orders", "model_id": [759, "Purchase Order"], "groups": [79], "domain_force": "[('state', 'not in', ('purchase', 'cancel', 'done'))]", "perm_read": true, "perm_write": true, "perm_create": true, "perm_unlink": false }, { "id": 387, "name": "Prevent Purchase Orders Cancel", "model_id": [759, "Purchase Order"], "groups": [79], "domain_force": "[('state', 'in', ('purchase', 'cancel', 'done'))]", "perm_read": true, "perm_write": false, "perm_create": false, "perm_unlink": false }
Expected Behavior:
- Rule 386 allows write access for purchase orders in "draft" state.
- Rule 387 restricts write access only in the "purchase," "cancel," and "done" states.
Since the user is in the "draft" state, they should have permission to confirm the order, moving it to the "purchase" state.
Observed Behavior:
It seems Odoo requires write permissions for both the "draft" (current) and "purchase" (target) states simultaneously, resulting in an access error due to the restrictions in Rule 387. This doesn’t align with expected behavior, where only the current state’s permissions should apply during the action.
Question:
Is this simultaneous evaluation of current and target states intended in Odoo’s rule logic, or might this be a bug? Any insights or workarounds would be helpful!
Thanks in advance for any guidance.
Have your ruled out that confirm doesn't need two write calls in the database where you are seeing this?
I'm seeing this issue with sale orders as well and I could only see a single write operation in the `action_confirm` method: https://github.com/odoo/odoo/blob/b560ba3897c764220663b9ac19f556573a4c9e2a/addons/sale/models/sale_order.py#L1110
Each of these modules is potentially calling WRITE on Purchase Orders: account_budget, mrp_mps, mrp_subcontracting_dropshipping, mrp_subcontracting_purchase, partner_commission, project_purchase, project_purchase_stock, purchase, purchase_edi_ubl_bis3, purchase_intrastat, purchase_mrp, purchase_product_matrix, purchase_repair, purchase_requisition, purchase_requisition_stock, purchase_stock, sale_purchase, sale_purchase_inter_company_rules, sale_purchase_stock, sale_purchase_stock_inter_company_rules, stock_dropshipping.
I just tested and write is called 7 times during PO confirmation with all of the modules above loaded.
This list shows you what fields are being updated during each call:
OLD: {'state': 'draft', 'date_approve': False} - NEW: {'state': 'purchase', 'date_approve': datetime.datetime(2024, 11, 8, 15, 30, 37)}
OLD: {'group_id': procurement.group()} - NEW: {'group_id': procurement.group(68,)}
OLD: {'invoice_status': 'no'} - NEW: {'invoice_status': 'no'}
OLD: {'date_calendar_start': datetime.datetime(2024, 11, 8, 11, 50, 44)} - NEW: {'date_calendar_start': datetime.datetime(2024, 11, 8, 15, 30, 37)}
OLD: {'picking_ids': stock.picking()} - NEW: {'picking_ids': stock.picking(67,)}
OLD: {'effective_date': False} - NEW: {'effective_date': False}
OLD: {'receipt_status': False} - NEW: {'receipt_status': 'pending'}
Thanks for looking into this. Are all of these write operations performed on the PO model? How are you getting this list of updated fields? Even if multiple write operations are being executed on the PO model, I’m not observing the PO order transitioning to a different state or getting stuck between states. Instead, the access error is raised, and the order remains in draft.