diff --git a/loko/assets/tests.py b/loko/assets/tests.py index 66507eb..e87a965 100644 --- a/loko/assets/tests.py +++ b/loko/assets/tests.py @@ -2060,6 +2060,49 @@ class TrafficLightCrossPlanImportTest(TestCase): if os.path.exists(tmp_path): os.remove(tmp_path) + def test_parse_cross_plan_cable_header_any_column(self): + import openpyxl + import tempfile + from assets.utils.cross_plan_parser import parse_cross_plan + + wb = openpyxl.Workbook() + ws = wb.active + ws.title = "kruisjesplan" + ws.cell(row=1, column=3, value="sleutel:") + ws.cell(row=1, column=4, value="SAT110") + # Cable header in column 7 + ws.cell(row=2, column=7, value="Câble 01 SVAVB 30x1,5mm²") + ws.cell(row=4, column=1, value="Klem controller") + ws.cell(row=4, column=2, value="Klemnummer") + ws.cell(row=4, column=3, value="Richting") + ws.cell(row=4, column=4, value="Kringen") + ws.cell(row=5, column=5, value="A01") + ws.cell(row=5, column=6, value="A02") + + # Row 6: Phase B + ws.cell(row=6, column=2, value=1) + ws.cell(row=6, column=3, value="B") + ws.cell(row=6, column=4, value="RS1") + ws.cell(row=6, column=5, value="X") + ws.cell(row=6, column=6, value="X") + + with tempfile.NamedTemporaryFile(suffix=".xlsx", delete=False) as tmp: + tmp_path = tmp.name + wb.save(tmp_path) + + try: + deduced = parse_cross_plan(tmp_path) + self.assertEqual(deduced["intersection_code"], "SAT110") + self.assertEqual(len(deduced["poles"]), 2) + self.assertEqual(len(deduced["cables"]), 1) + self.assertEqual(deduced["cables"][0]["strands"], 30) + self.assertEqual(deduced["cables"][0]["code"], "SAT110_CAB01") + self.assertEqual(len(deduced["lanterns"]), 2) + finally: + import os + if os.path.exists(tmp_path): + os.remove(tmp_path) + class AssetDefaultPositionTest(TestCase): def test_assign_default_position_hierarchy(self): diff --git a/loko/assets/utils/cross_plan_parser.py b/loko/assets/utils/cross_plan_parser.py index 9c8d4c1..af06e04 100644 --- a/loko/assets/utils/cross_plan_parser.py +++ b/loko/assets/utils/cross_plan_parser.py @@ -64,15 +64,17 @@ def parse_cross_plan(excel_path): # 2. Scan sheet to identify cable sections - # Cable sections start at rows containing 'Câble' or 'Cable' in the first columns + # Cable sections start at rows containing 'Câble' or 'Cable' in any column cable_sections = [] max_row = sheet.max_row max_col = sheet.max_column for r in range(1, max_row + 1): - val = sheet.cell(row=r, column=1).value - if val and isinstance(val, str) and ("câble" in val.lower() or "cable" in val.lower()): - cable_sections.append((r, val.strip())) + for c in range(1, max_col + 1): + val = sheet.cell(row=r, column=c).value + if val and isinstance(val, str) and ("câble" in val.lower() or "cable" in val.lower()): + cable_sections.append((r, val.strip())) + break # Parse each cable section deduced_poles = {} # pole_header -> {code, type} @@ -184,14 +186,18 @@ def parse_cross_plan(excel_path): cable_num = int(m.group(1)) if m else (idx + 1) cable_model_name = m.group(2).strip() if m else "SVAVB 61x1,5mm²" - # Count number of strands - strands = 61 - if "10x2x0,8" in cable_model_name: - strands = 20 - elif "61x1,5" in cable_model_name: + # Count number of strands dynamically + m_double = re.search(r'(\d+)\s*x\s*(\d+)\s*x\s*[\d,.]+', cable_model_name, re.IGNORECASE) + m_multi = re.search(r'(\d+)\s*x[^\d]+(\d+)\s*x\s*[\d,.]+', cable_model_name, re.IGNORECASE) + m_single = re.search(r'(\d+)\s*x\s*[\d,.]+', cable_model_name, re.IGNORECASE) + if m_double: + strands = int(m_double.group(1)) * int(m_double.group(2)) + elif m_multi: + strands = int(m_multi.group(1)) * int(m_multi.group(2)) + elif m_single: + strands = int(m_single.group(1)) + else: strands = 61 - elif "14x1,5" in cable_model_name: - strands = 14 # Find which poles are associated with this cable_label connected_poles = sorted(list(set([ @@ -283,7 +289,7 @@ def parse_cross_plan(excel_path): if conn.get("is_detector", False): is_detector = True - elif normalized_upper in ("RA", "RAB", "RB", "RC", "RD", "VD", "VC", "VT1", "VT2") or normalized_upper.startswith(("RM", "RP")): + elif normalized_upper in ("RA", "RAB", "RB", "RC", "RD", "VD", "VC", "VT1", "VT2") or normalized_upper.startswith(("RM", "RP", "RA", "RB", "RC", "RD", "VD", "VC", "VT")): is_detector = True if is_detector: