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:
146
scripts/check_letzshop_tracking.py
Normal file
146
scripts/check_letzshop_tracking.py
Normal file
@@ -0,0 +1,146 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Check tracking info for a specific shipment from Letzshop API.
|
||||
|
||||
Usage:
|
||||
python scripts/check_letzshop_tracking.py YOUR_API_KEY SHIPMENT_ID
|
||||
|
||||
Example:
|
||||
python scripts/check_letzshop_tracking.py abc123 nvDv5RQEmCwbjo
|
||||
"""
|
||||
|
||||
import sys
|
||||
import json
|
||||
import requests
|
||||
|
||||
ENDPOINT = "https://letzshop.lu/graphql"
|
||||
|
||||
# Query with tracking field included
|
||||
QUERY_SHIPMENT_WITH_TRACKING = """
|
||||
query GetShipmentsPaginated($first: Int!, $after: String) {
|
||||
shipments(state: confirmed, first: $first, after: $after) {
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
nodes {
|
||||
id
|
||||
number
|
||||
state
|
||||
tracking {
|
||||
number
|
||||
url
|
||||
carrier {
|
||||
name
|
||||
code
|
||||
}
|
||||
}
|
||||
order {
|
||||
id
|
||||
number
|
||||
email
|
||||
total
|
||||
}
|
||||
inventoryUnits {
|
||||
id
|
||||
state
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def get_tracking_info(api_key: str, target_shipment_id: str):
|
||||
"""Get tracking info for a specific shipment."""
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {api_key}",
|
||||
}
|
||||
|
||||
print(f"Looking for shipment: {target_shipment_id}")
|
||||
print("=" * 60)
|
||||
|
||||
# Paginate through confirmed shipments
|
||||
has_next = True
|
||||
after = None
|
||||
page = 0
|
||||
|
||||
while has_next and page < 20:
|
||||
page += 1
|
||||
variables = {"first": 50, "after": after}
|
||||
|
||||
response = requests.post(
|
||||
ENDPOINT,
|
||||
headers=headers,
|
||||
json={"query": QUERY_SHIPMENT_WITH_TRACKING, "variables": variables},
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
print(f"Error: HTTP {response.status_code}")
|
||||
print(response.text)
|
||||
return
|
||||
|
||||
data = response.json()
|
||||
|
||||
if "errors" in data:
|
||||
print(f"GraphQL errors: {json.dumps(data['errors'], indent=2)}")
|
||||
return
|
||||
|
||||
result = data.get("data", {}).get("shipments", {})
|
||||
nodes = result.get("nodes", [])
|
||||
page_info = result.get("pageInfo", {})
|
||||
|
||||
print(f"Page {page}: {len(nodes)} shipments")
|
||||
|
||||
for shipment in nodes:
|
||||
if shipment.get("id") == target_shipment_id:
|
||||
print(f"\n{'=' * 60}")
|
||||
print("FOUND SHIPMENT!")
|
||||
print(f"{'=' * 60}")
|
||||
|
||||
print(f"\n--- Shipment Info ---")
|
||||
print(f" ID: {shipment.get('id')}")
|
||||
print(f" Number: {shipment.get('number')}")
|
||||
print(f" State: {shipment.get('state')}")
|
||||
|
||||
print(f"\n--- Tracking Info ---")
|
||||
tracking = shipment.get('tracking')
|
||||
if tracking:
|
||||
print(f" Tracking Number: {tracking.get('number')}")
|
||||
print(f" Tracking URL: {tracking.get('url')}")
|
||||
carrier = tracking.get('carrier', {})
|
||||
if carrier:
|
||||
print(f" Carrier Name: {carrier.get('name')}")
|
||||
print(f" Carrier Code: {carrier.get('code')}")
|
||||
else:
|
||||
print(" No tracking object returned")
|
||||
|
||||
print(f"\n--- Order Info ---")
|
||||
order = shipment.get('order', {})
|
||||
print(f" Order Number: {order.get('number')}")
|
||||
print(f" Email: {order.get('email')}")
|
||||
|
||||
print(f"\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")
|
||||
|
||||
print(f"\nShipment {target_shipment_id} not found in confirmed shipments")
|
||||
return None
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 3:
|
||||
print("Usage: python scripts/check_letzshop_tracking.py YOUR_API_KEY SHIPMENT_ID")
|
||||
print("\nExample:")
|
||||
print(" python scripts/check_letzshop_tracking.py abc123 nvDv5RQEmCwbjo")
|
||||
sys.exit(1)
|
||||
|
||||
api_key = sys.argv[1]
|
||||
shipment_id = sys.argv[2]
|
||||
|
||||
get_tracking_info(api_key, shipment_id)
|
||||
Reference in New Issue
Block a user