Money Handling Architecture: - Store all monetary values as integer cents (€105.91 = 10591) - Add app/utils/money.py with Money class and conversion helpers - Add static/shared/js/money.js for frontend formatting - Update all database models to use _cents columns (Product, Order, etc.) - Update CSV processor to convert prices to cents on import - Add Alembic migration for Float to Integer conversion - Create .architecture-rules/money.yaml with 7 validation rules - Add docs/architecture/money-handling.md documentation Order Details Page Fixes: - Fix customer name showing 'undefined undefined' - use flat field names - Fix vendor info empty - add vendor_name/vendor_code to OrderDetailResponse - Fix shipping address using wrong nested object structure - Enrich order detail API response with vendor info Vendor Filter Persistence Fixes: - Fix orders.js: restoreSavedVendor now sets selectedVendor and filters - Fix orders.js: init() only loads orders if no saved vendor to restore - Fix marketplace-letzshop.js: restoreSavedVendor calls selectVendor() - Fix marketplace-letzshop.js: clearVendorSelection clears TomSelect dropdown - Align vendor selector placeholder text between pages 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
202 lines
6.1 KiB
Python
202 lines
6.1 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Quick script to check Letzshop tracking schema and test tracking query.
|
|
|
|
Usage:
|
|
python scripts/check_tracking_schema.py YOUR_API_KEY
|
|
"""
|
|
|
|
import sys
|
|
import json
|
|
import requests
|
|
|
|
ENDPOINT = "https://letzshop.lu/graphql"
|
|
|
|
|
|
def run_query(api_key: str, query: str, variables: dict = None) -> dict:
|
|
"""Execute a GraphQL query."""
|
|
headers = {
|
|
"Authorization": f"Bearer {api_key}",
|
|
"Content-Type": "application/json",
|
|
}
|
|
payload = {"query": query}
|
|
if variables:
|
|
payload["variables"] = variables
|
|
response = requests.post(ENDPOINT, json=payload, headers=headers, timeout=30)
|
|
return response.json()
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) < 2:
|
|
print("Usage: python scripts/check_tracking_schema.py YOUR_API_KEY")
|
|
sys.exit(1)
|
|
|
|
api_key = sys.argv[1]
|
|
|
|
print("=" * 60)
|
|
print("Letzshop Tracking Schema Investigation")
|
|
print("=" * 60)
|
|
|
|
# 1. Introspect Tracking type
|
|
print("\n1. Checking Tracking type schema...")
|
|
tracking_query = """
|
|
{
|
|
__type(name: "Tracking") {
|
|
name
|
|
kind
|
|
fields {
|
|
name
|
|
type {
|
|
name
|
|
kind
|
|
ofType { name kind }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
"""
|
|
result = run_query(api_key, tracking_query)
|
|
if "errors" in result:
|
|
print(f" Error: {result['errors']}")
|
|
else:
|
|
type_data = result.get("data", {}).get("__type")
|
|
if type_data and type_data.get("fields"):
|
|
print(" Tracking type fields:")
|
|
for field in type_data["fields"]:
|
|
type_info = field.get("type", {})
|
|
type_name = type_info.get("name") or type_info.get("ofType", {}).get("name", "?")
|
|
print(f" - {field['name']}: {type_name}")
|
|
else:
|
|
print(" Tracking type not found or has no fields")
|
|
|
|
# 2. Check Shipment tracking-related fields
|
|
print("\n2. Checking Shipment type for tracking fields...")
|
|
shipment_query = """
|
|
{
|
|
__type(name: "Shipment") {
|
|
name
|
|
fields {
|
|
name
|
|
type {
|
|
name
|
|
kind
|
|
ofType { name kind }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
"""
|
|
result = run_query(api_key, shipment_query)
|
|
if "errors" in result:
|
|
print(f" Error: {result['errors']}")
|
|
else:
|
|
type_data = result.get("data", {}).get("__type")
|
|
if type_data and type_data.get("fields"):
|
|
tracking_fields = [
|
|
f for f in type_data["fields"]
|
|
if any(term in f["name"].lower() for term in ["track", "carrier", "number"])
|
|
]
|
|
print(" Tracking-related fields on Shipment:")
|
|
for field in tracking_fields:
|
|
type_info = field.get("type", {})
|
|
type_name = type_info.get("name") or type_info.get("ofType", {}).get("name", "?")
|
|
print(f" - {field['name']}: {type_name}")
|
|
|
|
# 3. Test querying tracking on a confirmed shipment
|
|
print("\n3. Testing tracking query on confirmed shipments...")
|
|
test_query = """
|
|
query {
|
|
shipments(state: confirmed, first: 1) {
|
|
nodes {
|
|
id
|
|
number
|
|
state
|
|
tracking {
|
|
code
|
|
provider
|
|
}
|
|
}
|
|
}
|
|
}
|
|
"""
|
|
result = run_query(api_key, test_query)
|
|
if "errors" in result:
|
|
print(f" Error querying tracking: {result['errors'][0].get('message', 'Unknown')}")
|
|
else:
|
|
nodes = result.get("data", {}).get("shipments", {}).get("nodes", [])
|
|
if nodes:
|
|
shipment = nodes[0]
|
|
tracking = shipment.get("tracking")
|
|
print(f" Shipment {shipment.get('number')}:")
|
|
if tracking:
|
|
print(f" Tracking code: {tracking.get('code')}")
|
|
print(f" Tracking provider: {tracking.get('provider')}")
|
|
else:
|
|
print(" No tracking data returned")
|
|
else:
|
|
print(" No confirmed shipments found")
|
|
|
|
# 4. Try alternative field names
|
|
print("\n4. Testing alternative tracking field names...")
|
|
alt_query = """
|
|
query {
|
|
shipments(state: confirmed, first: 1) {
|
|
nodes {
|
|
id
|
|
number
|
|
}
|
|
}
|
|
}
|
|
"""
|
|
result = run_query(api_key, alt_query)
|
|
if "errors" not in result:
|
|
nodes = result.get("data", {}).get("shipments", {}).get("nodes", [])
|
|
if nodes:
|
|
shipment_id = nodes[0].get("id")
|
|
print(f" Found shipment: {shipment_id}")
|
|
|
|
# Try node query with tracking
|
|
node_query = """
|
|
query GetShipment($id: ID!) {
|
|
node(id: $id) {
|
|
... on Shipment {
|
|
id
|
|
number
|
|
tracking {
|
|
code
|
|
provider
|
|
}
|
|
}
|
|
}
|
|
}
|
|
"""
|
|
result = run_query(api_key, node_query, {"id": shipment_id})
|
|
if "errors" in result:
|
|
print(f" Node query error: {result['errors'][0].get('message', 'Unknown')}")
|
|
else:
|
|
node = result.get("data", {}).get("node", {})
|
|
tracking = node.get("tracking")
|
|
if tracking:
|
|
print(f" Tracking via node query:")
|
|
print(f" Code: {tracking.get('code')}")
|
|
print(f" Provider: {tracking.get('provider')}")
|
|
else:
|
|
print(" No tracking in node query response")
|
|
|
|
print("\n" + "=" * 60)
|
|
print("Summary")
|
|
print("=" * 60)
|
|
print("""
|
|
Based on the tests above:
|
|
- If tracking fields exist but return null: tracking may not be set for this shipment
|
|
- If errors occur: the API may have issues with tracking field
|
|
- The shipment number (H74683403433) you see is different from tracking code
|
|
|
|
Note: The 'number' field on Shipment is the shipment number (H74683403433),
|
|
NOT the tracking code. The tracking code should be in tracking.code field.
|
|
""")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|