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
« 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
18def copy_flowsheet_data(flowsheet: Flowsheet, user: User):
19 try:
20 with transaction.atomic():
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)
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.
39 # Update everything to point to the new flowsheet.
40 update_primary_keys(model_lookups)
42 new_flowsheet.save()
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)
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.
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():
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)
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)
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
89 update_foreign_keys(model_lookups)
90 update_many_to_many_relationships(many_to_many_lookup, model_lookups)
91 update_formulas(model_lookups)
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)
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()
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]
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
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)
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)
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