# Cognex PatMax GV 셀 주소 + DB 제품 기반 런타임 매핑 MAX_PATMAX_SLOTS = 16 # Cognex job: PatMax 블록마다 50행 간격, 첫 결과 셀 = A27 _PATMAX_FIRST_ROW = 27 _PATMAX_ROW_STEP = 50 def patmax_cell_address(slot_index: int) -> str: """0-based PatMax 슬롯 → GV 셀 주소 (A27, A77, …).""" row = _PATMAX_FIRST_ROW + slot_index * _PATMAX_ROW_STEP return f"A{row}" def build_patmax_cells(articles: list) -> dict: """ DB 제품 목록(관리자 MES 선택 순서)으로 PatMax 셀 → 제품 정보 매핑 생성. Cognex job 슬롯 순서와 mes.selected_article_ids 순서가 일치해야 함. """ cells = {} for i, article in enumerate(articles[:MAX_PATMAX_SLOTS]): cells[patmax_cell_address(i)] = article_to_model(article, slot_id=i + 1) return cells def article_to_model(article: dict, slot_id: int) -> dict: """DB article 행 → PatMax/검사용 model dict.""" return { "id": slot_id, "article_id": article["article_id"], "article": article.get("article", ""), "name": article.get("article", ""), "model": article.get("buyer_article_no", "") or "", "type": "", } def article_label(article: dict) -> str: """DB article / model dict UI 표시용.""" if article.get("article"): return article["article"] if article.get("name"): return article["name"] return str(article.get("article_id", "")) def model_display_label(model: dict) -> str: """PatMax 인식 결과 model dict 표시용.""" if model.get("article"): return model["article"] parts = [model.get("name", ""), model.get("model", "")] parts = [p for p in parts if p] if model.get("type"): parts.append(model["type"]) return " / ".join(parts) if parts else str(model.get("article_id", ""))