Warranty phase 2: real Dell provider + settings UI + PC hero badge
- DellProvider: real Dell TechDirect lookup. OAuth2 via HTTP Basic auth, asset-entitlements under /PROD/sbil/eapi/v5 (the device.warranty path 404s for this account), map latest dated entitlement to service level + dates. Cache the token process-wide; Dell rate-limits the token endpoint and a fresh request per refresh trips a 401 cooldown. Verified against live Dell. - Lenovo/HP stay config-shaped stubs. - Settings: warranty_dell_* keys (category integrations); Dell Warranty Lookup block in System Settings > Integrations (enable + client id/secret masked + optional token/API URL overrides). - WarrantyPanel takes optional pre-fetched items; PCDetail fetches once and feeds both the panel and a new hero warranty-status/end-date badge. - tools/mock_dell.py for offline testing of the provider flow. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
57
tools/mock_dell.py
Normal file
57
tools/mock_dell.py
Normal file
@@ -0,0 +1,57 @@
|
||||
"""Minimal mock of the Dell TechDirect Warranty API for local testing.
|
||||
|
||||
POST /token -> {access_token, expires_in}
|
||||
GET /asset-entitlements?servicetags=TAG -> one asset with two entitlements
|
||||
|
||||
Run: venv/bin/python tools/mock_dell.py 8899
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||
from urllib.parse import urlparse, parse_qs
|
||||
|
||||
|
||||
class Handler(BaseHTTPRequestHandler):
|
||||
def _send(self, payload, code=200):
|
||||
body = json.dumps(payload).encode()
|
||||
self.send_response(code)
|
||||
self.send_header('Content-Type', 'application/json')
|
||||
self.send_header('Content-Length', str(len(body)))
|
||||
self.end_headers()
|
||||
self.wfile.write(body)
|
||||
|
||||
def do_POST(self):
|
||||
if urlparse(self.path).path.rstrip('/').endswith('token'):
|
||||
self._send({'access_token': 'mock-access-token', 'expires_in': 3600})
|
||||
else:
|
||||
self._send({'error': 'not found'}, 404)
|
||||
|
||||
def do_GET(self):
|
||||
parsed = urlparse(self.path)
|
||||
if 'asset-entitlements' in parsed.path:
|
||||
tag = (parse_qs(parsed.query).get('servicetags') or ['UNKNOWN'])[0]
|
||||
if self.headers.get('Authorization') != 'Bearer mock-access-token':
|
||||
self._send({'error': 'unauthorized'}, 401)
|
||||
return
|
||||
self._send([{
|
||||
'serviceTag': tag,
|
||||
'productLineDescription': 'LATITUDE 5540',
|
||||
'shipDate': '2024-01-10T00:00:00Z',
|
||||
'entitlements': [
|
||||
{'serviceLevelDescription': 'Basic Onsite',
|
||||
'startDate': '2024-01-15T00:00:00Z', 'endDate': '2025-01-15T00:00:00Z'},
|
||||
{'serviceLevelDescription': 'ProSupport Plus',
|
||||
'startDate': '2024-01-15T00:00:00Z', 'endDate': '2027-01-15T00:00:00Z'},
|
||||
],
|
||||
}])
|
||||
else:
|
||||
self._send({'error': 'not found'}, 404)
|
||||
|
||||
def log_message(self, *args):
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
port = int(sys.argv[1]) if len(sys.argv) > 1 else 8899
|
||||
HTTPServer(('127.0.0.1', port), Handler).serve_forever()
|
||||
Reference in New Issue
Block a user