More email SKU shenanigans, now with more TEST labels!

This commit is contained in:
2026-09-14 11:41:27 -05:00
parent a6f60408ff
commit b5570d39f0
12 changed files with 815 additions and 139 deletions
+43 -9
View File
@@ -49,9 +49,9 @@ def _is_shipping_item(item_name: str) -> bool:
return item_name.strip().lower().startswith("shipping")
def check_company_mismatch(skus: List[str]) -> Optional[TicketIssue]:
settings = config.load_settings()
sku_map = parse_mapping(settings.get("COMPANY_SKU_MAP", ""))
def check_company_mismatch(skus: List[str], sku_map: Optional[dict] = None) -> Optional[TicketIssue]:
if sku_map is None:
sku_map = parse_mapping(config.load_settings().get("COMPANY_SKU_MAP", ""))
companies = set()
for sku in skus or []:
@@ -67,7 +67,11 @@ def check_company_mismatch(skus: List[str]) -> Optional[TicketIssue]:
return None
def check_return_device_mismatch(line_items: List[dict]) -> List[TicketIssue]:
def check_return_device_mismatch(
line_items: List[dict],
keyword_map: Optional[dict] = None,
exempt_keywords: Optional[list] = None,
) -> List[TicketIssue]:
"""
A return SKU's implied device type needs to match SOMETHING else on the
ticket - either an actual device line item (break-fix: send the asset,
@@ -78,8 +82,10 @@ def check_return_device_mismatch(line_items: List[dict]) -> List[TicketIssue]:
mismatch - confirmed against real examples: SH002/SH011, OK001/OK006,
OK011/OK013).
"""
keyword_map = get_device_field_suggestions() # {keyword: [serial fields]} - keys only, here
exempt_keywords = get_return_device_exempt_keywords()
if keyword_map is None:
keyword_map = get_device_field_suggestions() # {keyword: [serial fields]} - keys only, here
if exempt_keywords is None:
exempt_keywords = get_return_device_exempt_keywords()
issues: List[TicketIssue] = []
device_items = [item for item in (line_items or []) if not _is_shipping_item(item.get("item_name", ""))]
@@ -120,10 +126,38 @@ def check_return_device_mismatch(line_items: List[dict]) -> List[TicketIssue]:
return issues
def validate_ticket(skus: List[str], line_items: List[dict]) -> List[TicketIssue]:
def validate_ticket(
skus: List[str],
line_items: List[dict],
sku_map: Optional[dict] = None,
keyword_map: Optional[dict] = None,
exempt_keywords: Optional[list] = None,
) -> List[TicketIssue]:
"""
Validates a single ticket. The optional pre-fetched params exist so a
caller validating MANY tickets at once (the orders table, refreshing
on every Import/Pull Tracking/etc.) can read these settings from disk
ONCE for the whole batch, rather than once per ticket - each of these
is itself a full .env read, and doing that per-ticket rather than
per-batch was a real, measured performance bug (2.7s for 300 tickets,
now ~0.1s - see make_validation_context()).
"""
issues: List[TicketIssue] = []
company_issue = check_company_mismatch(skus)
company_issue = check_company_mismatch(skus, sku_map)
if company_issue:
issues.append(company_issue)
issues.extend(check_return_device_mismatch(line_items))
issues.extend(check_return_device_mismatch(line_items, keyword_map, exempt_keywords))
return issues
def make_validation_context() -> dict:
"""Fetches everything validate_ticket() needs from Settings ONCE, for
passing into repeated validate_ticket() calls across a batch (e.g.
every order in the table on a refresh) instead of re-reading .env for
every single ticket."""
settings = config.load_settings()
return {
"sku_map": parse_mapping(settings.get("COMPANY_SKU_MAP", "")),
"keyword_map": get_device_field_suggestions(),
"exempt_keywords": get_return_device_exempt_keywords(),
}