[13.0][OU-FIX] hr_contract: fill contract_id for every employee, not just one - #5957
Open
muhammadali124 wants to merge 1 commit into
Open
Conversation
fill_employee_contract_id() built the backfill values in a non-correlated subquery with LIMIT 1 and no ORDER BY. Postgres evaluates that subquery once, independent of the outer UPDATE, so LIMIT 1 returned a single arbitrary (employee_id, contract_id) pair across the whole database instead of one per employee. Every other employee with a genuinely 'open' contract was left with contract_id = NULL, which then falsely triggers hr.employee.contract_warning post-migration. Replace the non-correlated LIMIT 1 with DISTINCT ON (employee_id) ORDER BY employee_id, id so exactly one contract per employee is picked deterministically and every qualifying employee row is updated.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What's wrong
fill_employee_contract_id()inaddons/hr_contract/migrations/13.0.1.0/post-migration.pyis meant to backfill the new (in 13.0)hr.employee.contract_idfield for every employee holding a contract instate = 'open', since it's a plainMany2oneand has no way to be populated by the schema migration itself.The current query:
The inner
SELECTis a non-correlated subquery — its ownhe/hcaliases are scoped entirely to itself and never reference the outerUPDATE hr_employee herow. In PostgreSQL,UPDATE ... FROM (subquery) ...evaluates the subquery once, as an independent derived table (this would require aLATERALjoin to be evaluated per outer row, which it isn't).Combined with
LIMIT 1and noORDER BY, the subquery returns at most one row, globally, across the entire database — one arbitrary(employee_id, contract_id)pair, picked by whatever order the query planner happens to produce.The outer
UPDATE's join (sub.employee_id = he.id) can then only ever match the singlehr_employeerow whose id equals that one arbitraryemployee_id. Every other employee with a genuinelyopencontract is left withcontract_id = NULL.Impact
In any database with more than one employee holding an
opencontract at migration time — the normal case for any live company — this script links exactly one employee, chosen arbitrarily, and silently leaves every other employee'scontract_idunset.Downstream effect:
hr.employee.contract_warningis a stored computed field (@api.depends('contract_id', 'contract_id.state', 'contract_id.kanban_state')) that evaluatesnot employee.contract_idasTruefor every employee this script failed to link, surfacing a persistent, incorrect "there is something wrong with the contract" warning on the employee's card even though the contract itself is genuinelyopenand correct.Why this went unnoticed in small-scale testing
If a test database happens to have exactly one employee with an
opencontract, the non-correlatedLIMIT 1subquery has no competing row to arbitrarily drop — it deterministically returns that one row, and the bug produces a correct-looking result by coincidence. The failure only becomes visible once more than one employee genuinely qualifies.The fix
Replace the non-correlated
LIMIT 1withDISTINCT ON (employee_id) ... ORDER BY employee_id, id, which correlates one contract per employee deterministically and updates every qualifying employee, not just one:How this was found
Found while manually verifying a 12.0 → 13.0 upgrade rehearsal. A single test contract was deliberately set to
openpre-migration; post-migration, the employee's card showed a contract warning despite the contract being genuinelyopen. Tracing the cause led to this migration script, and SQL semantic analysis of the non-correlatedLIMIT 1subquery confirmed the defect described above.