3131 resolve_model_fields_path ,
3232 table_of_model ,
3333)
34+ from .inconsistencies import break_recursive_loops
3435from .indirect_references import indirect_references
3536from .inherit import direct_inherit_parents , for_each_inherit
3637from .misc import Sentinel , chunks , parse_version , version_gte
@@ -1423,7 +1424,7 @@ def delete_unused(cr, *xmlids, **kwargs):
14231424 return deleted
14241425
14251426
1426- def replace_record_references (cr , old , new , replace_xmlid = True ):
1427+ def replace_record_references (cr , old , new , replace_xmlid = True , parent_field = "parent_id" ):
14271428 """
14281429 Replace all (in)direct references of a record by another.
14291430
@@ -1436,10 +1437,12 @@ def replace_record_references(cr, old, new, replace_xmlid=True):
14361437 if not old [1 ]:
14371438 return None
14381439
1439- return replace_record_references_batch (cr , {old [1 ]: new [1 ]}, old [0 ], new [0 ], replace_xmlid )
1440+ return replace_record_references_batch (cr , {old [1 ]: new [1 ]}, old [0 ], new [0 ], replace_xmlid , parent_field )
14401441
14411442
1442- def replace_record_references_batch (cr , id_mapping , model_src , model_dst = None , replace_xmlid = True , ignores = ()):
1443+ def replace_record_references_batch (
1444+ cr , id_mapping , model_src , model_dst = None , replace_xmlid = True , ignores = (), parent_field = "parent_id"
1445+ ):
14431446 """
14441447 Replace all references to records.
14451448
@@ -1456,6 +1459,9 @@ def replace_record_references_batch(cr, id_mapping, model_src, model_dst=None, r
14561459 the source records
14571460 :param list(str) ignores: list of **table** names to skip when updating the referenced
14581461 values
1462+ :paream str parent_field: when the target and source model are the same, and the model
1463+ table has `parent_path` column, this field will be used to
1464+ update it.
14591465 """
14601466 _validate_model (model_src )
14611467 if model_dst is None :
@@ -1781,6 +1787,20 @@ def replace_record_references_batch(cr, id_mapping, model_src, model_dst=None, r
17811787 )
17821788
17831789 cr .execute ("DROP TABLE _upgrade_rrr" )
1790+ if parent_field and model_dst == model_src :
1791+ if column_exists (cr , model_src_table , "parent_path" ):
1792+ fk_target = target_of (cr , model_src_table , parent_field )
1793+ if fk_target :
1794+ if fk_target [0 ] != model_src_table :
1795+ _logger .warning (
1796+ "`%s` has a `parent_path` but `%s` is not a self-referencing FK" , model_src_table , parent_field
1797+ )
1798+ else :
1799+ update_parent_path (cr , model_src , parent_field )
1800+ elif parent_field != "parent_id" : # check non-default value
1801+ _logger .error ("`%s` in `%s` is not a self-referencing FK" , parent_field , model_src_table )
1802+ elif column_exists (cr , model_src_table , "parent_left" ):
1803+ _logger .warning ("Possibly missing update of parent_left/right in `%s`" , model_src_table )
17841804
17851805
17861806def replace_in_all_jsonb_values (cr , table , column , old , new , extra_filter = None ):
@@ -1935,3 +1955,43 @@ def _remove_redundant_tcalls(cr, match):
19351955 vid ,
19361956 match ,
19371957 )
1958+
1959+
1960+ def update_parent_path (cr , model , parent_field = "parent_id" ):
1961+ """
1962+ Trigger the update of parent paths in a model.
1963+
1964+ :meta private: exclude from online docs
1965+ """
1966+ if not version_gte ("saas~11.3" ):
1967+ _logger .error ("parent_left and parent_right must be computed via the ORM" )
1968+ return
1969+ table = table_of_model (cr , model )
1970+ name_field = "name" if column_exists (cr , table , "name" ) else "id"
1971+ break_recursive_loops (cr , model , parent_field , name_field )
1972+ query = format_query (
1973+ cr ,
1974+ """
1975+ WITH RECURSIVE __parent_store_compute(id, parent_path) AS (
1976+ SELECT row.id,
1977+ concat(row.id, '/')
1978+ FROM {table} row
1979+ WHERE row.{parent_field} IS NULL
1980+
1981+ UNION
1982+
1983+ SELECT row.id,
1984+ concat(comp.parent_path, row.id, '/')
1985+ FROM {table} row
1986+ JOIN __parent_store_compute comp
1987+ ON row.{parent_field} = comp.id
1988+ )
1989+ UPDATE {table} row
1990+ SET parent_path = comp.parent_path
1991+ FROM __parent_store_compute comp
1992+ WHERE row.id = comp.id
1993+ """ ,
1994+ table = table ,
1995+ parent_field = parent_field ,
1996+ )
1997+ cr .execute (query )
0 commit comments