""" Dell asset lookup service. Two modes (chosen automatically): 1. **No credentials** – Returns a partial pre-fill (brand=Dell, OS default, service_tag). Model and warranty must be filled in manually; a link to Dell's support page is provided. Dell's public website is protected by Akamai and cannot be scraped reliably. 2. **TechDirect API** – Full data including model, warranty dates, serial number. Register free at https://tdm.dell.com → API Services → Create an API key pair. Set DELL_CLIENT_ID and DELL_CLIENT_SECRET in your .env file. """ import logging from datetime import datetime import requests from flask import current_app log = logging.getLogger(__name__) _TOKEN_URL = "https://apigtwb2c.us.dell.com/auth/oauth/v2/token" _ASSET_URL = "https://apigtwb2c.us.dell.com/PROD/sbil/eapi/v5/asset-entitlements" _SUPPORT_PAGE = "https://www.dell.com/support/home/en-us/product-support/servicetag/{tag}/overview" _TYPE_MAP = [ (["latitude", "inspiron", "xps", "vostro", "precision 5", "precision 7"], "Laptop"), (["optiplex", "precision tower", "precision 3", "precision 9", "optiplex micro", "optiplex small"], "Desktop"), (["poweredge", "server"], "Server"), (["wyse", "thin client"], "Other"), (["monitor", "display", "screen", "s24", "s27", "p24", "u27"], "Monitor"), ] def _detect_type(description: str) -> str: desc = description.lower() for keywords, asset_type in _TYPE_MAP: if any(kw in desc for kw in keywords): return asset_type return "Laptop" # sensible default for Dell business hardware # ------------------------------------------------------------------ # Partial pre-fill (no credentials) # ------------------------------------------------------------------ def _partial_prefill(tag: str) -> dict: """ Return a minimal pre-fill dict using only what we know without querying Dell. Includes a link to Dell's support page so the user can look up the rest. """ return { "service_tag": tag, "serial_number": "", "brand": "Dell", "model": "", "asset_type": "Laptop", "operating_system": "Windows 11 Pro", "warranty_expiry": "", "purchase_date": "", "source": "partial", "support_url": _SUPPORT_PAGE.format(tag=tag), } # ------------------------------------------------------------------ # Official TechDirect API (requires credentials) # ------------------------------------------------------------------ def _get_token(client_id: str, client_secret: str) -> str: resp = requests.post( _TOKEN_URL, data={ "grant_type": "client_credentials", "client_id": client_id, "client_secret": client_secret, }, timeout=10, ) resp.raise_for_status() return resp.json()["access_token"] def _lookup_api(tag: str, client_id: str, client_secret: str) -> dict: try: token = _get_token(client_id, client_secret) except Exception as exc: raise RuntimeError(f"Failed to obtain Dell API token: {exc}") from exc try: resp = requests.get( _ASSET_URL, params={"servicetags": tag}, headers={"Authorization": f"Bearer {token}"}, timeout=15, ) resp.raise_for_status() data = resp.json() except Exception as exc: raise RuntimeError(f"Dell API request failed: {exc}") from exc if not data: raise RuntimeError(f"No data returned for service tag '{tag}'.") item = data[0] if isinstance(data, list) else data system_desc = item.get("productLineDescription") or item.get("systemDescription") or "" model = system_desc.strip() serial_number = (item.get("serviceTag") or tag).upper() warranty_expiry = None for ent in (item.get("entitlements") or []): end_str = ent.get("endDate") or "" if end_str: try: dt = datetime.fromisoformat(end_str[:10]) if warranty_expiry is None or dt > warranty_expiry: warranty_expiry = dt except ValueError: pass ship_date = item.get("shipDate") or "" purchase_date = None if ship_date: try: purchase_date = datetime.fromisoformat(ship_date[:10]) except ValueError: pass return { "service_tag": tag, "serial_number": serial_number, "brand": "Dell", "model": model, "asset_type": _detect_type(f"{system_desc} {item.get('productFamily', '')}"), "operating_system": "Windows 11 Pro", "warranty_expiry": warranty_expiry.strftime("%Y-%m-%d") if warranty_expiry else "", "purchase_date": purchase_date.strftime("%Y-%m-%d") if purchase_date else "", "source": "techdirect_api", "support_url": _SUPPORT_PAGE.format(tag=tag), } # ------------------------------------------------------------------ # Public entry point # ------------------------------------------------------------------ def lookup_service_tag(service_tag: str) -> dict: """ Look up a Dell service tag. Uses TechDirect API when DELL_CLIENT_ID + DELL_CLIENT_SECRET are configured; otherwise returns a partial pre-fill with a link to Dell's support page. """ tag = service_tag.strip().upper() client_id = current_app.config.get("DELL_CLIENT_ID", "") client_secret = current_app.config.get("DELL_CLIENT_SECRET", "") if client_id and client_secret: log.debug("Dell lookup via TechDirect API for %s", tag) return _lookup_api(tag, client_id, client_secret) log.debug("Dell lookup returning partial pre-fill for %s (no API credentials)", tag) return _partial_prefill(tag)