@@ -1337,6 +1337,99 @@ def test_replace_record_references_batch__uniqueness(self):
13371337 [count ] = self .env .cr .fetchone ()
13381338 self .assertEqual (count , 1 )
13391339
1340+ def _prepare_test_delete_unused (self ):
1341+ def create_cat ():
1342+ name = f"test_{ uuid .uuid4 ().hex } "
1343+ cat = self .env ["res.partner.category" ].create ({"name" : name })
1344+ self .env ["ir.model.data" ].create (
1345+ {"name" : name , "module" : "base" , "model" : "res.partner.category" , "res_id" : cat .id }
1346+ )
1347+ return cat
1348+
1349+ cat_1 = create_cat ()
1350+ cat_2 = create_cat ()
1351+ cat_3 = create_cat ()
1352+
1353+ # `category_id` is a m2m, so in ON DELETE CASCADE. We need a m2o.
1354+ self .env .cr .execute (
1355+ "ALTER TABLE res_partner ADD COLUMN _cat_id integer REFERENCES res_partner_category(id) ON DELETE SET NULL"
1356+ )
1357+ p1 = self .env ["res.partner" ].create ({"name" : "test delete_unused" })
1358+
1359+ # set the `_cat_id` value in SQL as it is not know by the ORM
1360+ self .env .cr .execute ("UPDATE res_partner SET _cat_id=%s WHERE id=%s" , [cat_1 .id , p1 .id ])
1361+
1362+ if hasattr (self , "_savepoint_id" ):
1363+ self .addCleanup (self .env .cr .execute , f"SAVEPOINT test_{ self ._savepoint_id } " )
1364+ self .addCleanup (cat_1 .unlink )
1365+ self .addCleanup (cat_2 .unlink )
1366+ self .addCleanup (cat_3 .unlink )
1367+ self .addCleanup (p1 .unlink )
1368+
1369+ self .addCleanup (self .env .cr .execute , "ALTER TABLE res_partner DROP COLUMN _cat_id" )
1370+
1371+ return cat_1 , cat_2 , cat_3
1372+
1373+ def test_delete_unused_base (self ):
1374+ tx = self .env ["res.currency" ].create ({"name" : "TX1" , "symbol" : "TX1" })
1375+ self .env ["ir.model.data" ].create ({"name" : "TX1" , "module" : "base" , "model" : "res.currency" , "res_id" : tx .id })
1376+
1377+ deleted = util .delete_unused (self .env .cr , "base.TX1" )
1378+ self .assertEqual (deleted , ["base.TX1" ])
1379+ self .assertFalse (tx .exists ())
1380+
1381+ def test_delete_unused_cascade (self ):
1382+ cat_1 , cat_2 , cat_3 = self ._prepare_test_delete_unused ()
1383+ deleted = util .delete_unused (self .env .cr , f"base.{ cat_1 .name } " , f"base.{ cat_2 .name } " , f"base.{ cat_3 .name } " )
1384+
1385+ self .assertEqual (set (deleted ), {f"base.{ cat_2 .name } " , f"base.{ cat_3 .name } " })
1386+ self .assertTrue (cat_1 .exists ())
1387+ self .assertFalse (cat_2 .exists ())
1388+ self .assertFalse (cat_3 .exists ())
1389+
1390+ def test_delete_unused_tree (self ):
1391+ cat_1 , cat_2 , cat_3 = self ._prepare_test_delete_unused ()
1392+
1393+ cat_1 .parent_id = cat_2 .id
1394+ cat_2 .parent_id = cat_3 .id
1395+ util .flush (cat_1 )
1396+ util .flush (cat_2 )
1397+
1398+ deleted = util .delete_unused (self .env .cr , f"base.{ cat_3 .name } " )
1399+
1400+ self .assertEqual (deleted , [])
1401+ self .assertTrue (cat_1 .exists ())
1402+ self .assertTrue (cat_2 .exists ())
1403+ self .assertTrue (cat_3 .exists ())
1404+
1405+ def test_delete_unused_multi_cascade_fk (self ):
1406+ """
1407+ When there are multiple children, the hierarchy can be build from different columns
1408+
1409+ cat_3
1410+ | via `_test_id`
1411+ cat_2
1412+ | via `parent_id`
1413+ cat_1
1414+ """
1415+ cat_1 , cat_2 , cat_3 = self ._prepare_test_delete_unused ()
1416+
1417+ self .env .cr .execute (
1418+ "ALTER TABLE res_partner_category ADD COLUMN _test_id integer REFERENCES res_partner_category(id) ON DELETE CASCADE"
1419+ )
1420+ self .addCleanup (self .env .cr .execute , "ALTER TABLE res_partner_category DROP COLUMN _test_id" )
1421+
1422+ cat_1 .parent_id = cat_2 .id
1423+ util .flush (cat_1 )
1424+ self .env .cr .execute ("UPDATE res_partner_category SET _test_id = %s WHERE id = %s" , [cat_3 .id , cat_2 .id ])
1425+
1426+ deleted = util .delete_unused (self .env .cr , f"base.{ cat_3 .name } " )
1427+
1428+ self .assertEqual (deleted , [])
1429+ self .assertTrue (cat_1 .exists ())
1430+ self .assertTrue (cat_2 .exists ())
1431+ self .assertTrue (cat_3 .exists ())
1432+
13401433
13411434class TestEditView (UnitTestCase ):
13421435 @parametrize (
0 commit comments