Files
Order-Manager/app/serial_suggestions.py

71 lines
2.8 KiB
Python

"""
Suggests which serial-number fields are probably relevant for a ticket,
based on keywords in its line items (e.g. an item name containing
"Laptop" suggests Laptop Serial Number + Laptop Asset Tag). This is a
starting point staff can edit, not a hard schema - device types and
their field sets vary by company and grow over time, so the mapping
lives in a setting (DEVICE_FIELD_SUGGESTIONS), not code.
If a ticket has two line items that both match "phone" (e.g. a
termination processing two lines), the second gets numbered - "Phone
IMEI (2)" - rather than colliding with the first.
"""
from __future__ import annotations
from typing import List
from app import config
def parse_device_field_suggestions(raw: str) -> dict[str, list[str]]:
"""'keyword:Field One|Field Two,keyword2:Field Three' -> {keyword: [fields]}"""
mapping: dict[str, list[str]] = {}
for group in (raw or "").split(","):
group = group.strip()
if not group or ":" not in group:
continue
keyword, _, fields_str = group.partition(":")
keyword = keyword.strip().lower()
fields = [f.strip() for f in fields_str.split("|") if f.strip()]
if keyword and fields:
mapping[keyword] = fields
return mapping
def get_device_field_suggestions() -> dict[str, list[str]]:
return parse_device_field_suggestions(
config.get("DEVICE_FIELD_SUGGESTIONS", config.DEFAULT_DEVICE_FIELD_SUGGESTIONS)
)
def suggest_serial_fields(line_items: List[dict]) -> List[str]:
"""
line_items: [{"sku": "OK401", "item_name": "Laptop - Dell Latitude..."}]
Returns suggested field labels, in the order their matching keyword
was found, numbered on repeat matches (e.g. two phone line items ->
"Phone IMEI (1)", "Phone IMEI (2)", ...).
Line items describing a shipping/return-label deliverable (e.g.
"Shipping - Return Label Laptop") are skipped - they name a device
type in passing but aren't an actual physical device to serialize,
and would otherwise double-count against the real device line item.
"""
keyword_map = get_device_field_suggestions()
suggestions: List[str] = []
match_counts: dict[str, int] = {}
for item in line_items or []:
item_name = item.get("item_name", "") or ""
if item_name.strip().lower().startswith("shipping"):
continue
haystack = f"{item_name} {item.get('sku', '')}".lower()
for keyword, fields in keyword_map.items():
if keyword in haystack:
match_counts[keyword] = match_counts.get(keyword, 0) + 1
occurrence = match_counts[keyword]
suffix = f" ({occurrence})" if occurrence > 1 else ""
suggestions.extend(f"{field}{suffix}" for field in fields)
return suggestions