feat: integer cents money handling, order page fixes, and vendor filter persistence
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>
This commit is contained in:
201
scripts/check_tracking_schema.py
Normal file
201
scripts/check_tracking_schema.py
Normal file
@@ -0,0 +1,201 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user