refactor: rebrand project to HartOMat

This commit is contained in:
2026-04-06 12:45:47 +02:00
parent fa7093307a
commit b795f0e6d6
95 changed files with 608 additions and 497 deletions
+1 -1
View File
@@ -17,7 +17,7 @@ class Material(Base):
name: Mapped[str] = mapped_column(String(200), nullable=False, unique=True)
description: Mapped[str] = mapped_column(Text, nullable=True)
source: Mapped[str] = mapped_column(String(20), nullable=False, default="manual")
schaeffler_code: Mapped[int | None] = mapped_column(Integer, nullable=True)
hartomat_code: Mapped[int | None] = mapped_column(Integer, nullable=True)
created_by: Mapped[uuid.UUID | None] = mapped_column(
UUID(as_uuid=True), ForeignKey("users.id", ondelete="SET NULL"), nullable=True
)
+8 -8
View File
@@ -1,7 +1,7 @@
"""Material alias resolution service.
Used from Celery tasks (sync context) to resolve raw material names
(from Excel / user input) to SCHAEFFLER library material names via aliases.
(from Excel / user input) to HARTOMAT library material names via aliases.
Resolution chain:
1. Alias lookup (case-insensitive) → use alias.material.name
@@ -31,7 +31,7 @@ def _get_engine():
def resolve_material_map(raw_map: dict[str, str]) -> dict[str, str]:
"""Resolve raw material names to SCHAEFFLER library names via aliases.
"""Resolve raw material names to HARTOMAT library names via aliases.
For each value in raw_map:
1. Alias lookup (case-insensitive) → return alias.material.name
@@ -66,7 +66,7 @@ def resolve_material_map(raw_map: dict[str, str]) -> dict[str, str]:
raw_lower = raw_material.lower()
# 1. Alias lookup first — aliases explicitly map intermediate/display names
# to the canonical SCHAEFFLER library names
# to the canonical HARTOMAT library names
if raw_lower in alias_lookup:
target = alias_lookup[raw_lower]
logger.info("resolved '%s''%s' (alias match)", raw_material, target)
@@ -147,7 +147,7 @@ async def find_unmapped_materials(
"""Find material names that have no alias or library match.
Returns a list of {"raw_name": str, "suggestions": [...]} for each
unmapped name. Suggestions are the top 5 SCHAEFFLER library materials
unmapped name. Suggestions are the top 5 HARTOMAT library materials
by string similarity.
"""
if not material_names:
@@ -159,8 +159,8 @@ async def find_unmapped_materials(
# Load all materials
mat_rows = (await db.execute(select(Material))).scalars().all()
# Library materials have a schaeffler_code
library_mats = [m for m in mat_rows if m.schaeffler_code is not None]
# Library materials have a hartomat_code
library_mats = [m for m in mat_rows if m.hartomat_code is not None]
# All material names (case-insensitive) for exact-match check
name_lookup: dict[str, Material] = {m.name.lower(): m for m in mat_rows}
@@ -179,7 +179,7 @@ async def find_unmapped_materials(
# 2. Exact name match with a library material → mapped
matched_mat = name_lookup.get(raw_lower)
if matched_mat and matched_mat.schaeffler_code is not None:
if matched_mat and matched_mat.hartomat_code is not None:
continue
# Unmapped — compute suggestions from library materials
@@ -194,7 +194,7 @@ async def find_unmapped_materials(
{
"id": str(m.id),
"name": m.name,
"schaeffler_code": str(m.schaeffler_code),
"hartomat_code": str(m.hartomat_code),
}
for _, m in scored[:5]
]
+1 -1
View File
@@ -235,7 +235,7 @@ def send_email_notification_stub(
from email.mime.text import MIMEText
msg = MIMEText(body, "plain", "utf-8")
msg["Subject"] = subject
msg["From"] = cfg.get("smtp_from_address") or cfg.get("smtp_user", "noreply@schaeffler.com")
msg["From"] = cfg.get("smtp_from_address") or cfg.get("smtp_user", "noreply@hartomat.com")
msg["To"] = to_address
port = int(cfg.get("smtp_port", "587"))
with smtplib.SMTP(smtp_host, port) as smtp:
@@ -330,7 +330,7 @@ def generate_usd_master_task(self, cad_file_id: str) -> dict:
if part_name and raw_material:
raw_mat_map[part_name] = raw_material
# Resolve raw material names to SCHAEFFLER library names via aliases
# Resolve raw material names to HARTOMAT library names via aliases
material_map: dict[str, str] = {}
if raw_mat_map:
material_map = resolve_material_map(raw_mat_map)
@@ -244,7 +244,7 @@ def render_order_line_task(self, order_line_id: str):
if m.get("part_name") and m.get("material")
}
# Resolve raw material names to SCHAEFFLER library names via aliases
# Resolve raw material names to HARTOMAT library names via aliases
from app.services.material_service import resolve_material_map
material_map = resolve_material_map(material_map)
@@ -61,7 +61,7 @@ _STEP_DESCRIPTIONS: dict[StepName, str] = {
StepName.OCC_OBJECT_EXTRACT: "Extract part objects and metadata from the STEP file using cadquery/OCC",
StepName.OCC_GLB_EXPORT: "Convert STEP geometry to glTF/GLB via cadquery",
StepName.GLB_BBOX: "Compute bounding-box from the exported GLB for camera framing",
StepName.MATERIAL_MAP_RESOLVE: "Resolve raw part-material names to SCHAEFFLER library materials via alias table",
StepName.MATERIAL_MAP_RESOLVE: "Resolve raw part-material names to HARTOMAT library materials via alias table",
StepName.AUTO_POPULATE_MATERIALS: "Auto-create Material records for any newly discovered part names",
StepName.BLENDER_RENDER: "Render a thumbnail PNG using Blender (Cycles or EEVEE)",
StepName.THREEJS_RENDER: "Render a thumbnail PNG using Three.js / Playwright headless browser",
+1 -1
View File
@@ -9,7 +9,7 @@ _DEFAULT_TENANT_CONFIG = {
"max_concurrent_renders": 3,
"render_engines_allowed": ["cycles", "eevee"],
"max_order_size": 500,
"fallback_material": "SCHAEFFLER_059999_FailedMaterial",
"fallback_material": "HARTOMAT_059999_FailedMaterial",
"notifications_enabled": True,
"invoice_prefix": "INV",
# Azure AI validation (per-tenant)