|
32 | 32 | _get_unique_indexes_with,
|
33 | 33 | _validate_table,
|
34 | 34 | column_exists,
|
| 35 | + column_nullable, |
35 | 36 | column_type,
|
36 | 37 | column_updatable,
|
37 | 38 | explode_execute,
|
@@ -309,6 +310,82 @@ def remove_asset(cr, name):
|
309 | 310 | remove_view(cr, name, silent=True)
|
310 | 311 | # fmt:on
|
311 | 312 |
|
| 313 | +def get_models_inheriting_actions_actions(cr): |
| 314 | + cr.execute( |
| 315 | + """ |
| 316 | + SELECT child_model.model |
| 317 | + FROM ir_model AS child_model |
| 318 | + JOIN ir_model_inherit |
| 319 | + ON child_model.id = ir_model_inherit.model_id |
| 320 | + JOIN ir_model AS base_model |
| 321 | + ON ir_model_inherit.parent_id = base_model.id |
| 322 | + WHERE base_model.model = 'ir.actions.actions' |
| 323 | + """ |
| 324 | + ) |
| 325 | + return cr.fetchall() |
| 326 | + |
| 327 | +def remove_action(cr, xml_id=None, action_id=None): |
| 328 | + assert bool(xml_id) ^ bool(action_id) |
| 329 | + |
| 330 | + if xml_id: |
| 331 | + action_id = ref(cr, xml_id) |
| 332 | + |
| 333 | + action_model = None |
| 334 | + if action_id: |
| 335 | + module, _, name = xml_id.partition(".") |
| 336 | + cr.execute("SELECT model FROM ir_model_data WHERE module=%s AND name=%s", [module, name]) |
| 337 | + [action_model] = cr.fetchone() |
| 338 | + if not action_model in get_models_inheriting_actions_actions(cr): |
| 339 | + raise ValueError( |
| 340 | + "%r should point to a model inheriting from 'ir.actions.actions', not a %r" % (xml_id, action_model) |
| 341 | + ) |
| 342 | + |
| 343 | + if version_gte("11.0"): |
| 344 | + cr.execute( |
| 345 | + """ |
| 346 | + SELECT name, |
| 347 | + model, |
| 348 | + on_delete |
| 349 | + FROM ir_model_fields |
| 350 | + WHERE relation = 'ir.actions.actions' |
| 351 | + AND on_delete IN ( 'cascade', 'set null' ) |
| 352 | + AND ttype = 'many2one' |
| 353 | + """ |
| 354 | + ) |
| 355 | + |
| 356 | + for column_name, model, on_delete in cr.fetchall(): |
| 357 | + model_table = table_of_model(cr, model) |
| 358 | + if on_delete == 'cascade': |
| 359 | + query = format_query(cr, "DELETE FROM {} WHERE {} = %s", model_table, column_name) |
| 360 | + else: |
| 361 | + query = format_query(cr, "UPDATE {} SET {} = NULL WHERE {} = %s", model_table, column_name, column_name) |
| 362 | + cr.execute(query, (action_id,)) |
| 363 | + else: |
| 364 | + # Before V11, we did not have `on_delete` on `ir_model_fields`. |
| 365 | + # However, we can infer the intended behaviour by checking if the column containing the deleted action's id is |
| 366 | + # nullable or not: |
| 367 | + # if not nullable, the record containing the deleted action should also be deleted (cascade); |
| 368 | + # else, we just set the column to NULL (set null) |
| 369 | + cr.execute( |
| 370 | + """ |
| 371 | + SELECT name, |
| 372 | + model |
| 373 | + FROM ir_model_fields |
| 374 | + WHERE relation = 'ir.actions.actions' |
| 375 | + AND ttype = 'many2one' |
| 376 | + """ |
| 377 | + ) |
| 378 | + |
| 379 | + for column_name, model in cr.fetchall(): |
| 380 | + model_table = table_of_model(cr, model) |
| 381 | + if not column_nullable(cr, model_of_table, column_name): |
| 382 | + query = format_query(cr, "DELETE FROM {} WHERE {} = %s", model_table, column_name) |
| 383 | + else: |
| 384 | + query = format_query(cr, "UPDATE {} SET {} = NULL WHERE {} = %s", model_table, column_name, column_name) |
| 385 | + cr.execute(query, (action_id,)) |
| 386 | + |
| 387 | + remove_records(cr, action_model, [action_id]) |
| 388 | + |
312 | 389 |
|
313 | 390 | def remove_record(cr, name):
|
314 | 391 | """
|
@@ -351,10 +428,13 @@ def remove_record(cr, name):
|
351 | 428 | if model == "res.groups":
|
352 | 429 | _logger.log(NEARLYWARN, "Removing group %r", name)
|
353 | 430 | return remove_group(cr, group_id=res_id)
|
| 431 | + |
| 432 | + if model in get_models_inheriting_actions_actions(cr): |
| 433 | + _logger.log(NEARLYWARN, "Removing action %r", name) |
| 434 | + return remove_action(cr, action_id=res_id) |
354 | 435 |
|
355 | 436 | return remove_records(cr, model, [res_id])
|
356 | 437 |
|
357 |
| - |
358 | 438 | def remove_records(cr, model, ids):
|
359 | 439 | if not ids:
|
360 | 440 | return
|
|
0 commit comments