feat: wire Google Wallet into loyalty enrollment, stamps, and points flows
Connect the fully-implemented Google Wallet service to the loyalty module: - Create wallet class/object on customer enrollment - Sync wallet passes on stamp and points operations - Expose wallet URLs in storefront API responses - Add conditional "Add to Google Wallet" buttons on dashboard and enroll-success pages - Use platform-wide env var config (not per-merchant DB column) - Add Google service account patterns to .gitignore - Add LOYALTY_GOOGLE_* fields to app Settings - Update deployment docs and add local testing guide Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -24,7 +24,7 @@ from app.modules.loyalty.schemas import (
|
||||
CardResponse,
|
||||
ProgramResponse,
|
||||
)
|
||||
from app.modules.loyalty.services import card_service, program_service
|
||||
from app.modules.loyalty.services import card_service, program_service, wallet_service
|
||||
from app.modules.tenancy.exceptions import StoreNotFoundException
|
||||
|
||||
storefront_router = APIRouter()
|
||||
@@ -89,8 +89,32 @@ def self_enroll(
|
||||
logger.info(f"Self-enrollment for customer {customer_id} at store {store.subdomain}")
|
||||
|
||||
card = card_service.enroll_customer_for_store(db, customer_id, store.id)
|
||||
program = card.program
|
||||
wallet_urls = wallet_service.get_add_to_wallet_urls(db, card)
|
||||
|
||||
return CardResponse.model_validate(card)
|
||||
return {
|
||||
"card": CardResponse(
|
||||
id=card.id,
|
||||
card_number=card.card_number,
|
||||
customer_id=card.customer_id,
|
||||
merchant_id=card.merchant_id,
|
||||
program_id=card.program_id,
|
||||
enrolled_at_store_id=card.enrolled_at_store_id,
|
||||
stamp_count=card.stamp_count,
|
||||
stamps_target=program.stamps_target,
|
||||
stamps_until_reward=max(0, program.stamps_target - card.stamp_count),
|
||||
total_stamps_earned=card.total_stamps_earned,
|
||||
stamps_redeemed=card.stamps_redeemed,
|
||||
points_balance=card.points_balance,
|
||||
total_points_earned=card.total_points_earned,
|
||||
points_redeemed=card.points_redeemed,
|
||||
is_active=card.is_active,
|
||||
created_at=card.created_at,
|
||||
has_google_wallet=bool(card.google_object_id),
|
||||
has_apple_wallet=bool(card.apple_serial_number),
|
||||
),
|
||||
"wallet_urls": wallet_urls,
|
||||
}
|
||||
|
||||
|
||||
# =============================================================================
|
||||
@@ -137,10 +161,32 @@ def get_my_card(
|
||||
program_response.is_points_enabled = program.is_points_enabled
|
||||
program_response.display_name = program.display_name
|
||||
|
||||
wallet_urls = wallet_service.get_add_to_wallet_urls(db, card)
|
||||
|
||||
return {
|
||||
"card": CardResponse.model_validate(card),
|
||||
"card": CardResponse(
|
||||
id=card.id,
|
||||
card_number=card.card_number,
|
||||
customer_id=card.customer_id,
|
||||
merchant_id=card.merchant_id,
|
||||
program_id=card.program_id,
|
||||
enrolled_at_store_id=card.enrolled_at_store_id,
|
||||
stamp_count=card.stamp_count,
|
||||
stamps_target=program.stamps_target,
|
||||
stamps_until_reward=max(0, program.stamps_target - card.stamp_count),
|
||||
total_stamps_earned=card.total_stamps_earned,
|
||||
stamps_redeemed=card.stamps_redeemed,
|
||||
points_balance=card.points_balance,
|
||||
total_points_earned=card.total_points_earned,
|
||||
points_redeemed=card.points_redeemed,
|
||||
is_active=card.is_active,
|
||||
created_at=card.created_at,
|
||||
has_google_wallet=bool(card.google_object_id),
|
||||
has_apple_wallet=bool(card.apple_serial_number),
|
||||
),
|
||||
"program": program_response,
|
||||
"locations": [{"id": v.id, "name": v.name} for v in locations],
|
||||
"wallet_urls": wallet_urls,
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user