diff --git a/src/bambuddy_inventree_sync/filament.py b/src/bambuddy_inventree_sync/filament.py index 19bd8a2..39d905c 100644 --- a/src/bambuddy_inventree_sync/filament.py +++ b/src/bambuddy_inventree_sync/filament.py @@ -512,7 +512,7 @@ class FilamentTrackingService: def _spool_payload_for_stock(self, stock_item: dict[str, Any]) -> dict[str, Any]: part = stock_item.get("part_detail") or {} part_name = str(part.get("full_name") or part.get("name") or f"InvenTree stock {stock_item.get('pk')}") - material, color_name, brand = self._parse_part_name(part_name) + material, color_name, brand, subtype = self._parse_part_name(part_name) remaining = self._stock_quantity(stock_item) label_weight = self._label_weight_for_stock(remaining) weight_used = max(label_weight - remaining, 0) @@ -522,6 +522,7 @@ class FilamentTrackingService: "material": material[:50] or self.settings.filament_default_material, "color_name": color_name, "brand": brand, + "subtype": subtype, "label_weight": label_weight, "core_weight": self.settings.filament_default_core_weight, "weight_used": round(weight_used, 3), @@ -540,6 +541,7 @@ class FilamentTrackingService: "material", "color_name", "brand", + "subtype", "label_weight", "core_weight", "weight_used", @@ -624,13 +626,46 @@ class FilamentTrackingService: return default_weight return int(((remaining + 99) // 100) * 100) - def _parse_part_name(self, part_name: str) -> tuple[str, str | None, str | None]: - tokens = [token for token in re.split(r"[_\-\s]+", part_name.strip()) if token] - material = tokens[0] if tokens else self.settings.filament_default_material - brand = tokens[-1] if len(tokens) >= 3 else None - color_tokens = tokens[1:-1] if brand else tokens[1:] + def _parse_part_name(self, part_name: str) -> tuple[str, str | None, str | None, str | None]: + tokens = [token for token in re.split(r"[_\-\s|]+", part_name.strip()) if token] + material_index = self._material_token_index(tokens) + if material_index is None: + material = tokens[0] if tokens else self.settings.filament_default_material + content_tokens = tokens[1:] + else: + material = tokens[material_index] + content_tokens = tokens[material_index + 1 :] + + subtype = None + if content_tokens and content_tokens[-1].upper() in {"REFIL", "REFILL"}: + subtype = content_tokens.pop(-1).upper() + + brand = content_tokens[-1] if len(content_tokens) >= 2 else None + color_tokens = content_tokens[:-1] if brand else content_tokens color_name = " ".join(color_tokens).title() if color_tokens else None - return material[:50], color_name, brand + return material[:50], color_name, brand, subtype + + @staticmethod + def _material_token_index(tokens: list[str]) -> int | None: + known_materials = { + "ABS", + "ABS+", + "ASA", + "HIPS", + "NYLON", + "PA", + "PBT", + "PC", + "PET", + "PETG", + "PLA", + "PVA", + "TPU", + } + for index, token in enumerate(tokens): + if token.upper() in known_materials: + return index + return None @staticmethod def _values_differ(current: Any, expected: Any) -> bool: