diff --git a/app/modules/loyalty/services/google_wallet_service.py b/app/modules/loyalty/services/google_wallet_service.py index 5c0d104a..63936fe9 100644 --- a/app/modules/loyalty/services/google_wallet_service.py +++ b/app/modules/loyalty/services/google_wallet_service.py @@ -472,34 +472,60 @@ class GoogleWalletService: if not self.is_configured: raise GoogleWalletNotConfiguredException() + # Try to create the object via API. If it fails (e.g. demo mode + # where DRAFT classes reject object creation), fall back to + # embedding the full object data in the JWT ("fat JWT"). if not card.google_object_id: - self.create_object(db, card) + try: + self.create_object(db, card) + except WalletIntegrationException: + logger.info( + "Object creation failed for card %s, using fat JWT", + card.id, + ) try: import jwt credentials = self._get_credentials() - signer = self._get_signer() now = datetime.now(tz=UTC) origins = settings.loyalty_google_wallet_origins or [] + issuer_id = settings.loyalty_google_issuer_id + object_id = card.google_object_id or f"{issuer_id}.loyalty_card_{card.id}" + + if card.google_object_id: + # Object exists in Google — reference by ID only + payload = { + "loyaltyObjects": [{"id": card.google_object_id}], + } + else: + # Object not created — embed full object data in JWT + object_data = self._build_object_data(card, object_id) + payload = { + "loyaltyObjects": [object_data], + } + claims = { "iss": credentials.service_account_email, "aud": "google", "origins": origins, "typ": "savetowallet", - "payload": { - "loyaltyObjects": [{"id": card.google_object_id}], - }, + "payload": payload, "iat": now, "exp": now + timedelta(hours=1), } - # Sign using the RSASigner's key_id and key bytes (public API) + # Load the private key directly from the service account file + # (RSASigner doesn't expose .key; PyJWT needs the PEM string) + with open(settings.loyalty_google_service_account_json) as f: + sa_data = json.load(f) + private_key = sa_data["private_key"] + token = jwt.encode( claims, - signer.key, + private_key, algorithm="RS256", ) @@ -507,7 +533,7 @@ class GoogleWalletService: db.commit() return f"https://pay.google.com/gp/v/save/{token}" - except (AttributeError, ValueError, KeyError) as exc: + except (AttributeError, ValueError, KeyError, OSError) as exc: logger.error( "Failed to generate Google Wallet save URL: %s", exc )