fix: stop creating local qet terminals

dev
Zhaowenlong 4 weeks ago
parent f61e84b03d
commit 2dba711bb3

@ -148,11 +148,30 @@ def _selected_point():
def _selected_terminal():
for obj in _selection():
if TerminalObjects.is_terminal_object(obj):
if TerminalObjects.is_terminal_object(obj) and _is_qet_bound_terminal(obj):
return obj
return None
def _selected_local_terminal():
for obj in _selection():
if TerminalObjects.is_terminal_object(obj) and not _is_qet_bound_terminal(obj):
return obj
return None
def _is_qet_bound_terminal(obj):
terminal_uuid = getattr(obj, "QetTerminalUuid", "").strip()
binding_mode = getattr(obj, "QetTerminalBindingMode", "").strip().lower()
if not terminal_uuid:
return False
if TerminalObjects.is_local_terminal_uuid(terminal_uuid):
return False
if binding_mode == TerminalObjects.TERMINAL_BINDING_MODE_LOCAL:
return False
return True
def _is_wire_task_object(obj):
if obj is None:
return False
@ -201,6 +220,8 @@ def _find_terminal_by_uuid(doc, terminal_uuid, element_uuid=""):
target_element = (element_uuid or "").strip()
fallback = None
for terminal in _iter_terminal_objects(doc):
if not _is_qet_bound_terminal(terminal):
continue
if getattr(terminal, "QetTerminalUuid", "").strip() != target:
continue
if not target_element:
@ -863,6 +884,10 @@ class ManualWiringController:
def set_start_from_selection(self):
terminal = _selected_terminal()
if terminal is None:
if _selected_local_terminal() is not None:
raise ManualWiringPanelError(
"所选端子是 FreeCAD 本地端子,请选择 QET 绑定工程端子。"
)
raise ManualWiringPanelError("请先选择一个工程端子,再点击“设为起点”。")
self._reset_route_state()
self.start_terminal = terminal
@ -966,8 +991,12 @@ class ManualWiringController:
wire_kwargs = _task_wire_kwargs(self.current_task)
else:
end_terminal = _selected_terminal()
if end_terminal is None:
raise ManualWiringPanelError("请先选择一个工程端子,再点击“设为终点并生成”。")
if end_terminal is None:
if _selected_local_terminal() is not None:
raise ManualWiringPanelError(
"所选端子是 FreeCAD 本地端子,请选择 QET 绑定工程端子。"
)
raise ManualWiringPanelError("请先选择一个工程端子,再点击“设为终点并生成”。")
opened = _open_transaction(doc, "生成手动导线")
try:

@ -58,12 +58,6 @@ def _project_uuid_for_document(doc):
return project_uuid
def _local_terminal_uuid(instance_id, element_uuid, slot_name):
owner = (instance_id or "").strip() or (element_uuid or "").strip() or "device"
slot = (slot_name or "").strip() or "slot"
return "local:{0}:{1}".format(owner, slot)
def _existing_terminal_by_slot(terminal_group):
result = {}
for obj in TerminalObjects.collect_terminal_objects(terminal_group):
@ -73,6 +67,18 @@ def _existing_terminal_by_slot(terminal_group):
return result
def _is_qet_bound_terminal(obj):
terminal_uuid = getattr(obj, "QetTerminalUuid", "").strip()
binding_mode = getattr(obj, "QetTerminalBindingMode", "").strip().lower()
if not terminal_uuid:
return False
if TerminalObjects.is_local_terminal_uuid(terminal_uuid):
return False
if binding_mode == TerminalObjects.TERMINAL_BINDING_MODE_LOCAL:
return False
return True
def _terminal_group_for_device(doc, device_group, project_uuid):
instance_id = getattr(device_group, "QetInstanceId", "").strip()
return TerminalObjects.ensure_terminal_group(
@ -138,6 +144,7 @@ def ensure_engineering_terminals_for_device(doc, device_group):
"created_terminals": 0,
"updated_terminals": 0,
"skipped_slots": 0,
"skipped_unbound_slots": 0,
"skipped_devices_without_template_slots": 0,
"local_terminals": 0,
"warnings": [],
@ -161,17 +168,26 @@ def ensure_engineering_terminals_for_device(doc, device_group):
terminal_obj = existing_by_slot.get(slot_name)
if terminal_obj is None:
terminal_obj = TerminalObjects.create_lcs_object(
doc,
"QETTerminal_{0}_{1}".format(
TerminalObjects.safe_token(instance_id or element_uuid),
TerminalObjects.safe_token(slot_name),
),
placement=_slot_placement(slot),
label=_slot_label(slot, slot_name),
report["skipped_unbound_slots"] += 1
report["warnings"].append(
"设备 {0} 的模板槽位 {1} 没有 QET 端子绑定,未生成本地工程端子。".format(
getattr(device_group, "Label", "") or getattr(device_group, "Name", ""),
slot_name,
)
)
_debug(report["warnings"][-1])
continue
if not _is_qet_bound_terminal(terminal_obj):
report["local_terminals"] += 1
report["warnings"].append(
"设备 {0} 的模板槽位 {1} 已存在本地端子,已保留但不作为 QET 工程端子更新。".format(
getattr(device_group, "Label", "") or getattr(device_group, "Name", ""),
slot_name,
)
)
terminal_group.addObject(terminal_obj)
report["created_terminals"] += 1
_debug(report["warnings"][-1])
continue
else:
try:
terminal_obj.Placement = _slot_placement(slot)
@ -180,10 +196,6 @@ def ensure_engineering_terminals_for_device(doc, device_group):
report["updated_terminals"] += 1
terminal_uuid = getattr(terminal_obj, "QetTerminalUuid", "").strip()
if not terminal_uuid:
terminal_uuid = _local_terminal_uuid(instance_id, element_uuid, slot_name)
if TerminalObjects.is_local_terminal_uuid(terminal_uuid):
report["local_terminals"] += 1
TerminalObjects.set_terminal_semantics(
terminal_obj,
@ -254,6 +266,7 @@ def ensure_engineering_terminals_for_selection_or_all(doc=None):
"skipped_devices_without_template_slots": sum(
item.get("skipped_devices_without_template_slots", 0) for item in reports
),
"skipped_unbound_slots": sum(item.get("skipped_unbound_slots", 0) for item in reports),
"local_terminals": sum(item.get("local_terminals", 0) for item in reports),
"warnings": [
warning
@ -362,10 +375,11 @@ class CommandCreateEngineeringTerminals:
report = ensure_engineering_terminals_for_selection_or_all(App.ActiveDocument)
try:
App.Console.PrintMessage(
"[FreeCADExchange] 工程端子生成完成:设备 {0} 个,新增 {1} 个,更新 {2} 个,本地端子 {3} 个,跳过无模板设备 {4} 个。\n".format(
"[FreeCADExchange] 工程端子生成完成:设备 {0} 个,新增 {1} 个,更新 {2} 个,跳过未绑定槽位 {3} 个,已有本地端子 {4} 个,跳过无模板设备 {5} 个。\n".format(
report["devices"],
report["created_terminals"],
report["updated_terminals"],
report["skipped_unbound_slots"],
report["local_terminals"],
report["skipped_devices_without_template_slots"],
)

@ -198,6 +198,30 @@ def _reload_modules():
class ManualWiringPanelTest(unittest.TestCase):
def test_controller_rejects_local_terminal_as_manual_wiring_start(self):
selection_state = _install_fake_freecad()
terminal_objects, panel = _reload_modules()
app = sys.modules["FreeCAD"]
doc = FakeDocument()
app.ActiveDocument = doc
terminal_objects.ensure_root_group(doc, "project-1")
local_terminal = doc.addObject("Part::LocalCoordinateSystem", "TerminalLocal")
terminal_objects.set_terminal_semantics(
local_terminal,
"project-1",
"device-a",
"local:instance-a:P1",
"instance-a",
label="P1",
)
selection_state["selection"] = [local_terminal]
with self.assertRaisesRegex(panel.ManualWiringPanelError, "QET 绑定工程端子"):
panel.ManualWiringController().set_start_from_selection()
def test_controller_creates_preview_point_and_records_face_anchor(self):
selection_state = _install_fake_freecad()
terminal_objects, panel = _reload_modules()

@ -123,7 +123,7 @@ def _reload_modules():
class TemplateInstantiationTest(unittest.TestCase):
def test_template_lcs_slots_become_engineering_terminals(self):
def test_template_lcs_slots_without_qet_binding_do_not_create_local_terminals(self):
_install_fake_freecad()
template_instantiation, terminal_objects = _reload_modules()
app = sys.modules["FreeCAD"]
@ -154,14 +154,63 @@ class TemplateInstantiationTest(unittest.TestCase):
)
terminals = terminal_objects.collect_terminal_objects(terminal_group)
self.assertEqual(1, report["created_terminals"])
self.assertEqual(0, report["created_terminals"])
self.assertEqual(1, report["skipped_unbound_slots"])
self.assertEqual(0, report["local_terminals"])
self.assertIn("没有 QET 端子绑定", report["warnings"][0])
self.assertEqual([], terminals)
self.assertTrue(p1.ViewObject.Visibility)
def test_template_lcs_slots_update_existing_qet_terminals(self):
_install_fake_freecad()
template_instantiation, terminal_objects = _reload_modules()
app = sys.modules["FreeCAD"]
doc = FakeDocument()
root = terminal_objects.ensure_root_group(doc, "project-1")
device = doc.addObject("App::Part", "QETDevice_ct_1")
root.addObject(device)
terminal_objects.ensure_string_property(device, "QetElementUuid", "QET Exchange", "", "ct-1")
terminal_objects.ensure_string_property(device, "QetInstanceId", "QET Exchange", "", "inst-1")
terminal_objects.ensure_string_property(device, "QetProjectUuid", "QET Exchange", "", "project-1")
p1 = doc.addObject("Part::LocalCoordinateSystem", "P1")
p1.Placement = app.Placement(app.Vector(10, 20, 30), app.Rotation())
p1.addProperty("App::PropertyString", "Role", "QET Template", "")
p1.Role = "Terminal"
p1.addProperty("App::PropertyBool", "CanWire", "QET Template", "")
p1.CanWire = True
p1.addProperty("App::PropertyString", "QetTemplateSlotName", "QET Template", "")
p1.QetTemplateSlotName = "P1"
device.addObject(p1)
terminal_group = terminal_objects.ensure_terminal_group(
doc,
device,
project_uuid="project-1",
instance_id="inst-1",
)
qet_terminal = terminal_objects.create_lcs_object(doc, "QETTerminal_P1")
terminal_group.addObject(qet_terminal)
terminal_objects.set_terminal_semantics(
qet_terminal,
"project-1",
"ct-1",
"terminal-p1",
"inst-1",
label="P1",
slot_name="P1",
)
report = template_instantiation.ensure_engineering_terminals_for_device(doc, device)
terminals = terminal_objects.collect_terminal_objects(terminal_group)
self.assertEqual(0, report["created_terminals"])
self.assertEqual(1, report["updated_terminals"])
self.assertEqual(0, report["skipped_unbound_slots"])
self.assertEqual(1, len(terminals))
self.assertEqual("local:inst-1:P1", terminals[0].QetTerminalUuid)
self.assertEqual("inst-1", terminals[0].QetInstanceId)
self.assertEqual("ct-1", terminals[0].QetElementUuid)
self.assertEqual("P1", terminals[0].QetTemplateSlotName)
self.assertEqual("local", terminals[0].QetTerminalBindingMode)
self.assertTrue(terminals[0].CanWire)
self.assertEqual("terminal-p1", terminals[0].QetTerminalUuid)
self.assertEqual("qet", terminals[0].QetTerminalBindingMode)
self.assertFalse(p1.ViewObject.Visibility)
def test_device_without_template_slots_reports_no_created_terminals(self):

Loading…
Cancel
Save