Files
orion/scripts/check_letzshop_shipment.py
Samir Boulahtit f20266167d
Some checks failed
CI / ruff (push) Failing after 7s
CI / pytest (push) Failing after 1s
CI / architecture (push) Failing after 9s
CI / dependency-scanning (push) Successful in 27s
CI / audit (push) Successful in 8s
CI / docs (push) Has been skipped
fix(lint): auto-fix ruff violations and tune lint rules
- Auto-fixed 4,496 lint issues (import sorting, modern syntax, etc.)
- Added ignore rules for patterns intentional in this codebase:
  E402 (late imports), E712 (SQLAlchemy filters), B904 (raise from),
  SIM108/SIM105/SIM117 (readability preferences)
- Added per-file ignores for tests and scripts
- Excluded broken scripts/rename_terminology.py (has curly quotes)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 23:10:42 +01:00

204 lines
6.7 KiB
Python

#!/usr/bin/env python3
"""
Check shipment status directly from Letzshop API.
Usage:
python scripts/check_letzshop_shipment.py YOUR_API_KEY [SHIPMENT_ID_OR_ORDER_NUMBER]
Example:
python scripts/check_letzshop_shipment.py abc123 nvDv5RQEmCwbjo
python scripts/check_letzshop_shipment.py abc123 R532332163
"""
import json
import sys
import requests
ENDPOINT = "https://letzshop.lu/graphql"
# Query template - state is interpolated since Letzshop has enum issues
QUERY_SHIPMENTS_TEMPLATE = """
query GetShipmentsPaginated($first: Int!, $after: String) {{
shipments(state: {state}, first: $first, after: $after) {{
pageInfo {{
hasNextPage
endCursor
}}
nodes {{
id
number
state
order {{
id
number
email
total
completedAt
locale
shipAddress {{
firstName
lastName
merchant
streetName
streetNumber
city
zipCode
phone
country {{
iso
}}
}}
}}
inventoryUnits {{
id
state
variant {{
id
sku
mpn
price
tradeId {{
number
parser
}}
product {{
name {{
en
fr
de
}}
}}
}}
}}
}}
}}
}}
"""
def search_shipment(api_key: str, search_term: str):
"""Search for a shipment across all states."""
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}",
}
# States to search through
states = ["shipped", "confirmed", "unconfirmed", "declined"]
print(f"Searching for: {search_term}")
print("=" * 60)
for state in states:
print(f"\nSearching in state: {state}...")
query = QUERY_SHIPMENTS_TEMPLATE.format(state=state)
# Paginate through results
has_next = True
after = None
page = 0
while has_next and page < 20: # Max 20 pages to avoid infinite loop
page += 1
variables = {"first": 50, "after": after}
response = requests.post(
ENDPOINT,
headers=headers,
json={"query": query, "variables": variables},
)
if response.status_code != 200:
print(f" Error: HTTP {response.status_code}")
break
data = response.json()
if "errors" in data:
print(f" GraphQL errors: {data['errors']}")
break
result = data.get("data", {}).get("shipments", {})
nodes = result.get("nodes", [])
page_info = result.get("pageInfo", {})
# Search for matching shipment
for shipment in nodes:
shipment_id = shipment.get("id", "")
shipment_number = shipment.get("number", "")
order = shipment.get("order", {})
order_number = order.get("number", "")
# Check if this matches our search term
if (search_term in (shipment_id, order_number) or search_term in shipment_id or search_term in shipment_number or search_term in order_number):
print(f"\n{'=' * 60}")
print("FOUND SHIPMENT!")
print(f"{'=' * 60}")
print("\n--- Shipment Info ---")
print(f" ID: {shipment.get('id')}")
print(f" Number: {shipment.get('number')}")
print(f" State: {shipment.get('state')}")
print("\n--- Order Info ---")
print(f" Order ID: {order.get('id')}")
print(f" Order Number: {order.get('number')}")
print(f" Email: {order.get('email')}")
print(f" Total: {order.get('total')}")
print(f" Completed At: {order.get('completedAt')}")
ship_addr = order.get("shipAddress", {})
if ship_addr:
print("\n--- Shipping Address ---")
print(f" Name: {ship_addr.get('firstName')} {ship_addr.get('lastName')}")
print(f" Street: {ship_addr.get('streetName')} {ship_addr.get('streetNumber')}")
print(f" City: {ship_addr.get('zipCode')} {ship_addr.get('city')}")
country = ship_addr.get("country", {})
print(f" Country: {country.get('iso')}")
print("\n--- Inventory Units ---")
units = shipment.get("inventoryUnits", [])
for i, unit in enumerate(units, 1):
print(f" Unit {i}:")
print(f" ID: {unit.get('id')}")
print(f" State: {unit.get('state')}")
variant = unit.get("variant", {})
print(f" SKU: {variant.get('sku')}")
trade_id = variant.get("tradeId", {})
print(f" GTIN: {trade_id.get('number')}")
product = variant.get("product", {})
name = product.get("name", {})
print(f" Product: {name.get('en')}")
print("\n--- Raw Response ---")
print(json.dumps(shipment, indent=2, default=str))
return shipment
has_next = page_info.get("hasNextPage", False)
after = page_info.get("endCursor")
if not has_next:
print(f" Searched {page} page(s), {len(nodes)} shipments in last page")
print(f"\nShipment not found for: {search_term}")
return None
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python scripts/check_letzshop_shipment.py YOUR_API_KEY [SHIPMENT_ID_OR_ORDER_NUMBER]")
print("\nExample:")
print(" python scripts/check_letzshop_shipment.py abc123 nvDv5RQEmCwbjo")
print(" python scripts/check_letzshop_shipment.py abc123 R532332163")
sys.exit(1)
api_key = sys.argv[1]
# Default to the order number R532332163
search_term = sys.argv[2] if len(sys.argv) > 2 else "R532332163"
search_shipment(api_key, search_term)