Coverage for backend/core/auxiliary/methods/CopyFlowsheet.py: 40%

73 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2025-11-06 23:27 +0000

1from django.db import transaction 

2from authentication.user.models import User 

3from core.auxiliary.enums import ConType 

4from core.auxiliary.models.Flowsheet import Flowsheet 

5from flowsheetInternals.graphicData.models.groupingModel import Grouping 

6from flowsheetInternals.graphicData.logic.make_group import propagate_streams, propagate_intermediate_streams 

7from flowsheetInternals.unitops.models.SimulationObject import SimulationObject 

8from django.utils import timezone 

9from authentication.user.AccessTable import AccessTable 

10from core.validation import flowsheet_ctx 

11from .copy_flowsheet.copy_caching import ModelLookup 

12from .copy_flowsheet.copy_primary_keys import update_primary_keys 

13from .copy_flowsheet.copy_foreign_keys import create_foreign_key_lookups, create_foreign_key_lookups_for_modules, update_foreign_keys 

14from .copy_flowsheet.copy_many_to_many import create_many_to_many_lookups, update_many_to_many_relationships 

15from .copy_flowsheet.copy_formulas import update_formulas 

16 

17 

18def copy_flowsheet_data(flowsheet: Flowsheet, user: User): 

19 try: 

20 with transaction.atomic(): 

21 

22 model_lookups = create_foreign_key_lookups(flowsheet) 

23 # Manually add the flowsheet to the model lookups. 

24 new_flowsheet = Flowsheet( 

25 pk=flowsheet.pk, # We need the old primary key for now, so the ModelLookup can use it. update_primary_keys will set it later. 

26 name=f"{flowsheet.name} (copy)"[:32], # Ensure name is not too long, 

27 owner=user, 

28 created_at=flowsheet.created_at, 

29 rootGrouping=flowsheet.rootGrouping, # This will be updated later to be the cloned version, because it doesn't exist yet. 

30 savedDate= timezone.now(), 

31 ) 

32 model_lookups[Flowsheet] = ModelLookup([new_flowsheet]) 

33 many_to_many_lookup = create_many_to_many_lookups(model_lookups) 

34 

35 # Normally, bulk_create will automatically set the flowsheet ID, because of 

36 # our access control Manager. 

37 # So we need to escape that behavior to allow us to set the flowsheet ID manually. 

38 

39 # Update everything to point to the new flowsheet. 

40 update_primary_keys(model_lookups) 

41 

42 new_flowsheet.save() 

43 

44 AccessTable.objects.create( 

45 user=user, 

46 flowsheet=new_flowsheet, 

47 ) 

48 update_foreign_keys(model_lookups) 

49 update_many_to_many_relationships(many_to_many_lookup, model_lookups) 

50 update_formulas(model_lookups) 

51 

52 root_group_pk = new_flowsheet.rootGrouping.pk 

53 new_flowsheet.rootGrouping = model_lookups[Grouping].get_model(root_group_pk) 

54 new_flowsheet.created_at = timezone.now() 

55 new_flowsheet.save() 

56 return new_flowsheet 

57 # Bulk update the models with the new foreign keys. 

58 # for Model_Type, models in model_lookups.items(): 

59 except Exception as e: 

60 import traceback 

61 print(f"Error copying flowsheet: {e}") 

62 print(traceback.format_exc()) 

63 raise Exception( 

64 f"Error copying flowsheet: {e} " + traceback.format_exc() 

65 ) # Re-raise the exception to be handled by the caller. 

66 

67 

68 

69def create_module_from_template_logic(template_flowsheet: Flowsheet, target_flowsheet: Flowsheet, 

70 user, current_group: Grouping, x=None, y=None) -> Grouping: 

71 """ 

72 Create a module (grouping) from a template flowsheet within an existing flowsheet 

73 """ 

74 with transaction.atomic(): 

75 

76 # This maps old PKs to new model instances 

77 model_lookups = create_foreign_key_lookups_for_modules(template_flowsheet) 

78 many_to_many_lookup = create_many_to_many_lookups(model_lookups) 

79 

80 # Generate new primary keys for all copied models 

81 # Sets pk=None so Django creates new PKs when saving 

82 update_primary_keys(model_lookups) 

83 

84 # Map template flowsheet to target flowsheet 

85 # All copied models will now reference the target flowsheet instead of template 

86 model_lookups[Flowsheet] = ModelLookup([]) 

87 model_lookups[Flowsheet].model_map[template_flowsheet.pk] = target_flowsheet 

88 

89 update_foreign_keys(model_lookups) 

90 update_many_to_many_relationships(many_to_many_lookup, model_lookups) 

91 update_formulas(model_lookups) 

92 

93 # Find the copied root group from the template 

94 template_root_group_pk = template_flowsheet.rootGrouping.pk 

95 module_root_group: Grouping = model_lookups[Grouping].get_model(template_root_group_pk) 

96 

97 # Set the copied root group's parent to current group 

98 # This "inserts" the template module into the target flowsheet hierarchy 

99 module_graphic_object = module_root_group.get_graphic_object() 

100 module_graphic_object.group = current_group 

101 if x is not None: 

102 module_graphic_object.x = x 

103 if y is not None: 

104 module_graphic_object.y = y 

105 module_graphic_object.save() 

106 

107 # Get all copied simulation objects 

108 copied_simulation_objects = list(model_lookups[SimulationObject]) 

109 contained_objects_id = [sim_obj.pk for sim_obj in copied_simulation_objects] 

110 

111 # Handle streams for all copied simulation objects 

112 inlet_streams = [] 

113 outlet_streams = [] 

114 for simulation_object in copied_simulation_objects: 

115 ports_mgr = simulation_object.connectedPorts # RelatedManager 

116 

117 # Propagate streams connected to one port 

118 if simulation_object.is_stream() and ports_mgr.count() == 1: 

119 port = ports_mgr.first() 

120 if port and port.direction == ConType.Inlet: 

121 inlet_streams.append(simulation_object) 

122 else: 

123 outlet_streams.append(simulation_object) 

124 

125 # Handle intermediate streams connected to the module 

126 if simulation_object.is_stream() and ports_mgr.count() == 2: 

127 propagate_intermediate_streams(simulation_object, contained_objects_id) 

128 

129 # Return the new module group for further use 

130 propagate_streams(inlet_streams, ConType.Inlet) 

131 propagate_streams(outlet_streams, ConType.Outlet) 

132 return module_root_group