Files
orion/scripts/google_wallet_status.py
Samir Boulahtit f89c0382f0
Some checks failed
CI / ruff (push) Successful in 12s
CI / validate (push) Successful in 27s
CI / dependency-scanning (push) Successful in 32s
CI / pytest (push) Failing after 1h13m39s
CI / docs (push) Has been cancelled
CI / deploy (push) Has been cancelled
feat(loyalty): wallet debug page, Google Wallet fixes, and module config env_file standardization
- Add wallet diagnostics page at /admin/loyalty/wallet-debug (super admin only)
  with explorer-sidebar pattern: config validation, class status, card inspector,
  save URL tester, recent enrollments, and Apple Wallet status panels
- Fix Google Wallet fat JWT: include both loyaltyClasses and loyaltyObjects in
  payload, use UNDER_REVIEW instead of DRAFT for class reviewStatus
- Fix StorefrontProgramResponse schema: accept google_class_id values while
  keeping exclude=True (was rejecting non-None values)
- Standardize all module configs to read from .env file directly
  (env_file=".env", extra="ignore") matching core Settings pattern
- Add MOD-026 architecture rule enforcing env_file in module configs
- Add SVC-005 noqa support in architecture validator
- Add test files for dev_tools domain_health and isolation_audit services
- Add google_wallet_status.py script for querying Google Wallet API
- Use table_wrapper macro in wallet-debug.html (FE-005 compliance)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 22:18:39 +01:00

137 lines
4.3 KiB
Python

#!/usr/bin/env python3
"""
Query Google Wallet API for class and object status.
Usage:
python scripts/google_wallet_status.py # List all classes
python scripts/google_wallet_status.py --class-id ID # Check specific class
python scripts/google_wallet_status.py --object-id ID # Check specific object
python scripts/google_wallet_status.py --fix-draft # Patch DRAFT classes to UNDER_REVIEW
"""
import argparse
import json
import sys
from dotenv import load_dotenv
load_dotenv()
from app.modules.loyalty.config import config
from app.modules.loyalty.services.google_wallet_service import GoogleWalletService
def main():
parser = argparse.ArgumentParser(description="Query Google Wallet API")
parser.add_argument("--class-id", help="Check a specific class ID")
parser.add_argument("--object-id", help="Check a specific object ID")
parser.add_argument(
"--fix-draft",
action="store_true",
help="Patch all DRAFT classes to UNDER_REVIEW for approval",
)
args = parser.parse_args()
svc = GoogleWalletService()
if not svc.is_configured:
print("Google Wallet is not configured.")
print(f" LOYALTY_GOOGLE_ISSUER_ID: {config.google_issuer_id or 'NOT SET'}")
print(f" LOYALTY_GOOGLE_SERVICE_ACCOUNT_JSON: {config.google_service_account_json or 'NOT SET'}")
sys.exit(1)
http = svc._get_http_client()
issuer_id = config.google_issuer_id
print(f"Issuer ID: {issuer_id}")
print()
if args.object_id:
_check_object(http, args.object_id)
return
if args.class_id:
_check_class(http, args.class_id)
return
# List all classes for this issuer
print("=== Loyalty Classes ===")
response = http.get(
"https://walletobjects.googleapis.com/walletobjects/v1/loyaltyClass",
params={"issuerId": issuer_id},
)
if response.status_code != 200:
print(f"Error: {response.status_code} - {response.text}")
sys.exit(1)
data = response.json()
classes = data.get("resources", [])
if not classes:
print("No loyalty classes found.")
return
for cls in classes:
status = cls.get("reviewStatus", "UNKNOWN")
class_id = cls.get("id")
program_name = cls.get("programName", "")
issuer_name = cls.get("issuerName", "")
color = cls.get("hexBackgroundColor", "")
status_icon = {
"approved": "",
"draft": "⚠️",
"rejected": "",
"underReview": "🔄",
}.get(status, "")
print(f" {status_icon} {class_id}")
print(f" Program: {program_name}")
print(f" Issuer: {issuer_name}")
print(f" Status: {status}")
print(f" Color: {color}")
print()
if args.fix_draft and status == "draft":
print(" Patching to UNDER_REVIEW...")
patch_resp = http.patch(
f"https://walletobjects.googleapis.com/walletobjects/v1/loyaltyClass/{class_id}",
json={"reviewStatus": "UNDER_REVIEW"},
)
if patch_resp.status_code == 200:
new_status = patch_resp.json().get("reviewStatus", "unknown")
print(f" ✅ Updated! New status: {new_status}")
else:
print(f" ❌ Failed: {patch_resp.status_code} - {patch_resp.text}")
print()
def _check_class(http, class_id):
print(f"=== Class: {class_id} ===")
response = http.get(
f"https://walletobjects.googleapis.com/walletobjects/v1/loyaltyClass/{class_id}",
)
if response.status_code == 200:
print(json.dumps(response.json(), indent=2))
elif response.status_code == 404:
print("Class not found.")
else:
print(f"Error: {response.status_code} - {response.text}")
def _check_object(http, object_id):
print(f"=== Object: {object_id} ===")
response = http.get(
f"https://walletobjects.googleapis.com/walletobjects/v1/loyaltyObject/{object_id}",
)
if response.status_code == 200:
print(json.dumps(response.json(), indent=2))
elif response.status_code == 404:
print("Object not found.")
else:
print(f"Error: {response.status_code} - {response.text}")
if __name__ == "__main__":
main()