mirror of
https://github.com/google-wallet/rest-samples.git
synced 2026-01-08 21:18:00 -05:00
786 lines
27 KiB
Python
786 lines
27 KiB
Python
#
|
|
# Copyright 2022 Google Inc. All rights reserved.
|
|
#
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
# use this file except in compliance with the License. You may obtain a copy of
|
|
# the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations under
|
|
# the License.
|
|
#
|
|
|
|
# [START setup]
|
|
# [START imports]
|
|
import json
|
|
import os
|
|
import uuid
|
|
|
|
from googleapiclient.discovery import build
|
|
from googleapiclient.errors import HttpError
|
|
from google.oauth2.service_account import Credentials
|
|
from google.auth import jwt, crypt
|
|
# [END imports]
|
|
|
|
|
|
class DemoGeneric:
|
|
"""Demo class for creating and managing Generic passes in Google Wallet.
|
|
|
|
Attributes:
|
|
key_file_path: Path to service account key file from Google Cloud
|
|
Console. Environment variable: GOOGLE_APPLICATION_CREDENTIALS.
|
|
base_url: Base URL for Google Wallet API requests.
|
|
"""
|
|
|
|
def __init__(self):
|
|
self.key_file_path = os.environ.get('GOOGLE_APPLICATION_CREDENTIALS',
|
|
'/path/to/key.json')
|
|
# Set up authenticated client
|
|
self.auth()
|
|
|
|
# [END setup]
|
|
|
|
# [START auth]
|
|
def auth(self):
|
|
"""Create authenticated HTTP client using a service account file."""
|
|
self.credentials = Credentials.from_service_account_file(
|
|
self.key_file_path,
|
|
scopes=['https://www.googleapis.com/auth/wallet_object.issuer'])
|
|
|
|
self.client = build('walletobjects', 'v1', credentials=self.credentials)
|
|
|
|
# [END auth]
|
|
|
|
# [START createClass]
|
|
def create_class(self, issuer_id: str, class_suffix: str) -> str:
|
|
"""Create a class.
|
|
|
|
Args:
|
|
issuer_id (str): The issuer ID being used for this request.
|
|
class_suffix (str): Developer-defined unique ID for this pass class.
|
|
|
|
Returns:
|
|
The pass class ID: f"{issuer_id}.{class_suffix}"
|
|
"""
|
|
|
|
# Check if the class exists
|
|
try:
|
|
self.client.genericclass().get(resourceId=f'{issuer_id}.{class_suffix}').execute()
|
|
except HttpError as e:
|
|
if e.status_code != 404:
|
|
# Something else went wrong...
|
|
print(e.error_details)
|
|
return f'{issuer_id}.{class_suffix}'
|
|
else:
|
|
print(f'Class {issuer_id}.{class_suffix} already exists!')
|
|
return f'{issuer_id}.{class_suffix}'
|
|
|
|
# See link below for more information on required properties
|
|
# https://developers.google.com/wallet/generic/rest/v1/genericclass
|
|
new_class = {'id': f'{issuer_id}.{class_suffix}'}
|
|
|
|
response = self.client.genericclass().insert(body=new_class).execute()
|
|
|
|
print('Class insert response')
|
|
print(response)
|
|
|
|
return f'{issuer_id}.{class_suffix}'
|
|
|
|
# [END createClass]
|
|
|
|
# [START updateClass]
|
|
def update_class(self, issuer_id: str, class_suffix: str) -> str:
|
|
"""Update a class.
|
|
|
|
**Warning:** This replaces all existing class attributes!
|
|
|
|
Args:
|
|
issuer_id (str): The issuer ID being used for this request.
|
|
class_suffix (str): Developer-defined unique ID for this pass class.
|
|
|
|
Returns:
|
|
The pass class ID: f"{issuer_id}.{class_suffix}"
|
|
"""
|
|
|
|
# Check if the class exists
|
|
try:
|
|
response = self.client.genericclass().get(resourceId=f'{issuer_id}.{class_suffix}').execute()
|
|
except HttpError as e:
|
|
if e.status_code == 404:
|
|
print(f'Class {issuer_id}.{class_suffix} not found!')
|
|
return f'{issuer_id}.{class_suffix}'
|
|
else:
|
|
# Something else went wrong...
|
|
print(e.error_details)
|
|
return f'{issuer_id}.{class_suffix}'
|
|
|
|
# Class exists
|
|
updated_class = response
|
|
|
|
# Update the class by adding a link
|
|
new_link = {
|
|
'uri': 'https://developers.google.com/wallet',
|
|
'description': 'Homepage description'
|
|
}
|
|
if not updated_class.get('linksModuleData'):
|
|
updated_class['linksModuleData'] = {'uris': []}
|
|
updated_class['linksModuleData']['uris'].append(new_link)
|
|
|
|
# Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for updates
|
|
updated_class['reviewStatus'] = 'UNDER_REVIEW'
|
|
|
|
response = self.client.genericclass().update(
|
|
resourceId=f'{issuer_id}.{class_suffix}',
|
|
body=updated_class).execute()
|
|
|
|
print('Class update response')
|
|
print(response)
|
|
|
|
return f'{issuer_id}.{class_suffix}'
|
|
|
|
# [END updateClass]
|
|
|
|
# [START patchClass]
|
|
def patch_class(self, issuer_id: str, class_suffix: str) -> str:
|
|
"""Patch a class.
|
|
|
|
The PATCH method supports patch semantics.
|
|
|
|
Args:
|
|
issuer_id (str): The issuer ID being used for this request.
|
|
class_suffix (str): Developer-defined unique ID for this pass class.
|
|
|
|
Returns:
|
|
The pass class ID: f"{issuer_id}.{class_suffix}"
|
|
"""
|
|
|
|
# Check if the class exists
|
|
try:
|
|
response = self.client.genericclass().get(resourceId=f'{issuer_id}.{class_suffix}').execute()
|
|
except HttpError as e:
|
|
if e.status_code == 404:
|
|
print(f'Class {issuer_id}.{class_suffix} not found!')
|
|
return f'{issuer_id}.{class_suffix}'
|
|
else:
|
|
# Something else went wrong...
|
|
print(e.error_details)
|
|
return f'{issuer_id}.{class_suffix}'
|
|
|
|
# Class exists
|
|
existing_class = response
|
|
|
|
# Patch the class by adding a link
|
|
patch_body = {}
|
|
new_link = {
|
|
'uri': 'https://developers.google.com/wallet',
|
|
'description': 'Homepage description'
|
|
}
|
|
|
|
if existing_class.get('linksModuleData'):
|
|
patch_body['linksModuleData'] = existing_class.get(
|
|
'linksModuleData')
|
|
else:
|
|
patch_body['linksModuleData'] = {'uris': []}
|
|
patch_body['linksModuleData']['uris'].append(new_link)
|
|
|
|
# Note: reviewStatus must be 'UNDER_REVIEW' or 'DRAFT' for patches
|
|
patch_body['reviewStatus'] = 'UNDER_REVIEW'
|
|
|
|
response = self.client.genericclass().patch(
|
|
resourceId=f'{issuer_id}.{class_suffix}',
|
|
body=patch_body).execute()
|
|
|
|
print('Class patch response')
|
|
print(response)
|
|
|
|
return f'{issuer_id}.{class_suffix}'
|
|
|
|
# [END patchClass]
|
|
|
|
# [START createObject]
|
|
def create_object(self, issuer_id: str, class_suffix: str,
|
|
object_suffix: str) -> str:
|
|
"""Create an object.
|
|
|
|
Args:
|
|
issuer_id (str): The issuer ID being used for this request.
|
|
class_suffix (str): Developer-defined unique ID for the pass class.
|
|
object_suffix (str): Developer-defined unique ID for the pass object.
|
|
|
|
Returns:
|
|
The pass object ID: f"{issuer_id}.{object_suffix}"
|
|
"""
|
|
|
|
# Check if the object exists
|
|
try:
|
|
self.client.genericobject().get(resourceId=f'{issuer_id}.{object_suffix}').execute()
|
|
except HttpError as e:
|
|
if e.status_code != 404:
|
|
# Something else went wrong...
|
|
print(e.error_details)
|
|
return f'{issuer_id}.{object_suffix}'
|
|
else:
|
|
print(f'Object {issuer_id}.{object_suffix} already exists!')
|
|
return f'{issuer_id}.{object_suffix}'
|
|
|
|
# See link below for more information on required properties
|
|
# https://developers.google.com/wallet/generic/rest/v1/genericobject
|
|
new_object = {
|
|
'id': f'{issuer_id}.{object_suffix}',
|
|
'classId': f'{issuer_id}.{class_suffix}',
|
|
'state': 'ACTIVE',
|
|
'heroImage': {
|
|
'sourceUri': {
|
|
'uri':
|
|
'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
|
|
},
|
|
'contentDescription': {
|
|
'defaultValue': {
|
|
'language': 'en-US',
|
|
'value': 'Hero image description'
|
|
}
|
|
}
|
|
},
|
|
'textModulesData': [{
|
|
'header': 'Text module header',
|
|
'body': 'Text module body',
|
|
'id': 'TEXT_MODULE_ID'
|
|
}],
|
|
'linksModuleData': {
|
|
'uris': [{
|
|
'uri': 'http://maps.google.com/',
|
|
'description': 'Link module URI description',
|
|
'id': 'LINK_MODULE_URI_ID'
|
|
}, {
|
|
'uri': 'tel:6505555555',
|
|
'description': 'Link module tel description',
|
|
'id': 'LINK_MODULE_TEL_ID'
|
|
}]
|
|
},
|
|
'imageModulesData': [{
|
|
'mainImage': {
|
|
'sourceUri': {
|
|
'uri':
|
|
'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
|
|
},
|
|
'contentDescription': {
|
|
'defaultValue': {
|
|
'language': 'en-US',
|
|
'value': 'Image module description'
|
|
}
|
|
}
|
|
},
|
|
'id': 'IMAGE_MODULE_ID'
|
|
}],
|
|
'barcode': {
|
|
'type': 'QR_CODE',
|
|
'value': 'QR code'
|
|
},
|
|
'cardTitle': {
|
|
'defaultValue': {
|
|
'language': 'en-US',
|
|
'value': 'Generic card title'
|
|
}
|
|
},
|
|
'header': {
|
|
'defaultValue': {
|
|
'language': 'en-US',
|
|
'value': 'Generic header'
|
|
}
|
|
},
|
|
'hexBackgroundColor': '#4285f4',
|
|
'logo': {
|
|
'sourceUri': {
|
|
'uri':
|
|
'https://developers.google.com/static/wallet/site-assets/images/pass-builder/pass_google_logo.jpg'
|
|
},
|
|
'contentDescription': {
|
|
'defaultValue': {
|
|
'language': 'en-US',
|
|
'value': 'Generic card logo'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Create the object
|
|
response = self.client.genericobject().insert(body=new_object).execute()
|
|
|
|
print('Object insert response')
|
|
print(response)
|
|
|
|
return f'{issuer_id}.{object_suffix}'
|
|
|
|
# [END createObject]
|
|
|
|
# [START updateObject]
|
|
def update_object(self, issuer_id: str, object_suffix: str) -> str:
|
|
"""Update an object.
|
|
|
|
**Warning:** This replaces all existing object attributes!
|
|
|
|
Args:
|
|
issuer_id (str): The issuer ID being used for this request.
|
|
object_suffix (str): Developer-defined unique ID for the pass object.
|
|
|
|
Returns:
|
|
The pass object ID: f"{issuer_id}.{object_suffix}"
|
|
"""
|
|
|
|
# Check if the object exists
|
|
try:
|
|
response = self.client.genericobject().get(resourceId=f'{issuer_id}.{object_suffix}').execute()
|
|
except HttpError as e:
|
|
if e.status_code == 404:
|
|
print(f'Object {issuer_id}.{object_suffix} not found!')
|
|
return f'{issuer_id}.{object_suffix}'
|
|
else:
|
|
# Something else went wrong...
|
|
print(e.error_details)
|
|
return f'{issuer_id}.{object_suffix}'
|
|
|
|
# Object exists
|
|
updated_object = response
|
|
|
|
# Update the object by adding a link
|
|
new_link = {
|
|
'uri': 'https://developers.google.com/wallet',
|
|
'description': 'New link description'
|
|
}
|
|
if not updated_object.get('linksModuleData'):
|
|
updated_object['linksModuleData'] = {'uris': []}
|
|
updated_object['linksModuleData']['uris'].append(new_link)
|
|
|
|
response = self.client.genericobject().update(
|
|
resourceId=f'{issuer_id}.{object_suffix}',
|
|
body=updated_object).execute()
|
|
|
|
print('Object update response')
|
|
print(response)
|
|
|
|
return f'{issuer_id}.{object_suffix}'
|
|
|
|
# [END updateObject]
|
|
|
|
# [START patchObject]
|
|
def patch_object(self, issuer_id: str, object_suffix: str) -> str:
|
|
"""Patch an object.
|
|
|
|
Args:
|
|
issuer_id (str): The issuer ID being used for this request.
|
|
object_suffix (str): Developer-defined unique ID for the pass object.
|
|
|
|
Returns:
|
|
The pass object ID: f"{issuer_id}.{object_suffix}"
|
|
"""
|
|
|
|
# Check if the object exists
|
|
try:
|
|
response = self.client.genericobject().get(resourceId=f'{issuer_id}.{object_suffix}').execute()
|
|
except HttpError as e:
|
|
if e.status_code == 404:
|
|
print(f'Object {issuer_id}.{object_suffix} not found!')
|
|
return f'{issuer_id}.{object_suffix}'
|
|
else:
|
|
# Something else went wrong...
|
|
print(e.error_details)
|
|
return f'{issuer_id}.{object_suffix}'
|
|
|
|
# Object exists
|
|
existing_object = response
|
|
|
|
# Patch the object by adding a link
|
|
patch_body = {}
|
|
new_link = {
|
|
'uri': 'https://developers.google.com/wallet',
|
|
'description': 'New link description'
|
|
}
|
|
|
|
if existing_object.get('linksModuleData'):
|
|
patch_body['linksModuleData'] = existing_object['linksModuleData']
|
|
else:
|
|
patch_body['linksModuleData'] = {'uris': []}
|
|
patch_body['linksModuleData']['uris'].append(new_link)
|
|
|
|
response = self.client.genericobject().patch(
|
|
resourceId=f'{issuer_id}.{object_suffix}',
|
|
body=patch_body).execute()
|
|
|
|
print('Object patch response')
|
|
print(response)
|
|
|
|
return f'{issuer_id}.{object_suffix}'
|
|
|
|
# [END patchObject]
|
|
|
|
# [START expireObject]
|
|
def expire_object(self, issuer_id: str, object_suffix: str) -> str:
|
|
"""Expire an object.
|
|
|
|
Sets the object's state to Expired. If the valid time interval is
|
|
already set, the pass will expire automatically up to 24 hours after.
|
|
|
|
Args:
|
|
issuer_id (str): The issuer ID being used for this request.
|
|
object_suffix (str): Developer-defined unique ID for the pass object.
|
|
|
|
Returns:
|
|
The pass object ID: f"{issuer_id}.{object_suffix}"
|
|
"""
|
|
|
|
# Check if the object exists
|
|
try:
|
|
response = self.client.genericobject().get(resourceId=f'{issuer_id}.{object_suffix}').execute()
|
|
except HttpError as e:
|
|
if e.status_code == 404:
|
|
print(f'Object {issuer_id}.{object_suffix} not found!')
|
|
return f'{issuer_id}.{object_suffix}'
|
|
else:
|
|
# Something else went wrong...
|
|
print(e.error_details)
|
|
return f'{issuer_id}.{object_suffix}'
|
|
|
|
# Patch the object, setting the pass as expired
|
|
patch_body = {'state': 'EXPIRED'}
|
|
|
|
response = self.client.genericobject().patch(
|
|
resourceId=f'{issuer_id}.{object_suffix}',
|
|
body=patch_body).execute()
|
|
|
|
print('Object expiration response')
|
|
print(response)
|
|
|
|
return f'{issuer_id}.{object_suffix}'
|
|
|
|
# [END expireObject]
|
|
|
|
# [START jwtNew]
|
|
def create_jwt_new_objects(self, issuer_id: str, class_suffix: str,
|
|
object_suffix: str) -> str:
|
|
"""Generate a signed JWT that creates a new pass class and object.
|
|
|
|
When the user opens the "Add to Google Wallet" URL and saves the pass to
|
|
their wallet, the pass class and object defined in the JWT are
|
|
created. This allows you to create multiple pass classes and objects in
|
|
one API call when the user saves the pass to their wallet.
|
|
|
|
Args:
|
|
issuer_id (str): The issuer ID being used for this request.
|
|
class_suffix (str): Developer-defined unique ID for the pass class.
|
|
object_suffix (str): Developer-defined unique ID for the pass object.
|
|
|
|
Returns:
|
|
An "Add to Google Wallet" link.
|
|
"""
|
|
|
|
# See link below for more information on required properties
|
|
# https://developers.google.com/wallet/generic/rest/v1/genericclass
|
|
new_class = {'id': f'{issuer_id}.{class_suffix}'}
|
|
|
|
# See link below for more information on required properties
|
|
# https://developers.google.com/wallet/generic/rest/v1/genericobject
|
|
new_object = {
|
|
'id': f'{issuer_id}.{object_suffix}',
|
|
'classId': f'{issuer_id}.{class_suffix}',
|
|
'state': 'ACTIVE',
|
|
'heroImage': {
|
|
'sourceUri': {
|
|
'uri':
|
|
'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
|
|
},
|
|
'contentDescription': {
|
|
'defaultValue': {
|
|
'language': 'en-US',
|
|
'value': 'Hero image description'
|
|
}
|
|
}
|
|
},
|
|
'textModulesData': [{
|
|
'header': 'Text module header',
|
|
'body': 'Text module body',
|
|
'id': 'TEXT_MODULE_ID'
|
|
}],
|
|
'linksModuleData': {
|
|
'uris': [{
|
|
'uri': 'http://maps.google.com/',
|
|
'description': 'Link module URI description',
|
|
'id': 'LINK_MODULE_URI_ID'
|
|
}, {
|
|
'uri': 'tel:6505555555',
|
|
'description': 'Link module tel description',
|
|
'id': 'LINK_MODULE_TEL_ID'
|
|
}]
|
|
},
|
|
'imageModulesData': [{
|
|
'mainImage': {
|
|
'sourceUri': {
|
|
'uri':
|
|
'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
|
|
},
|
|
'contentDescription': {
|
|
'defaultValue': {
|
|
'language': 'en-US',
|
|
'value': 'Image module description'
|
|
}
|
|
}
|
|
},
|
|
'id': 'IMAGE_MODULE_ID'
|
|
}],
|
|
'barcode': {
|
|
'type': 'QR_CODE',
|
|
'value': 'QR code'
|
|
},
|
|
'cardTitle': {
|
|
'defaultValue': {
|
|
'language': 'en-US',
|
|
'value': 'Generic card title'
|
|
}
|
|
},
|
|
'header': {
|
|
'defaultValue': {
|
|
'language': 'en-US',
|
|
'value': 'Generic header'
|
|
}
|
|
},
|
|
'hexBackgroundColor': '#4285f4',
|
|
'logo': {
|
|
'sourceUri': {
|
|
'uri':
|
|
'https://developers.google.com/static/wallet/site-assets/images/pass-builder/pass_google_logo.jpg'
|
|
},
|
|
'contentDescription': {
|
|
'defaultValue': {
|
|
'language': 'en-US',
|
|
'value': 'Generic card logo'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Create the JWT claims
|
|
claims = {
|
|
'iss': self.credentials.service_account_email,
|
|
'aud': 'google',
|
|
'origins': ['www.example.com'],
|
|
'typ': 'savetowallet',
|
|
'payload': {
|
|
# The listed classes and objects will be created
|
|
'genericClasses': [new_class],
|
|
'genericObjects': [new_object]
|
|
}
|
|
}
|
|
|
|
# The service account credentials are used to sign the JWT
|
|
signer = crypt.RSASigner.from_service_account_file(self.key_file_path)
|
|
token = jwt.encode(signer, claims).decode('utf-8')
|
|
|
|
print('Add to Google Wallet link')
|
|
print(f'https://pay.google.com/gp/v/save/{token}')
|
|
|
|
return f'https://pay.google.com/gp/v/save/{token}'
|
|
|
|
# [END jwtNew]
|
|
|
|
# [START jwtExisting]
|
|
def create_jwt_existing_objects(self, issuer_id: str) -> str:
|
|
"""Generate a signed JWT that references an existing pass object.
|
|
|
|
When the user opens the "Add to Google Wallet" URL and saves the pass to
|
|
their wallet, the pass objects defined in the JWT are added to the
|
|
user's Google Wallet app. This allows the user to save multiple pass
|
|
objects in one API call.
|
|
|
|
The objects to add must follow the below format:
|
|
|
|
{
|
|
'id': 'ISSUER_ID.OBJECT_SUFFIX',
|
|
'classId': 'ISSUER_ID.CLASS_SUFFIX'
|
|
}
|
|
|
|
Args:
|
|
issuer_id (str): The issuer ID being used for this request.
|
|
|
|
Returns:
|
|
An "Add to Google Wallet" link
|
|
"""
|
|
|
|
# Multiple pass types can be added at the same time
|
|
# At least one type must be specified in the JWT claims
|
|
# Note: Make sure to replace the placeholder class and object suffixes
|
|
objects_to_add = {
|
|
# Event tickets
|
|
'eventTicketObjects': [{
|
|
'id': f'{issuer_id}.EVENT_OBJECT_SUFFIX',
|
|
'classId': f'{issuer_id}.EVENT_CLASS_SUFFIX'
|
|
}],
|
|
|
|
# Boarding passes
|
|
'flightObjects': [{
|
|
'id': f'{issuer_id}.FLIGHT_OBJECT_SUFFIX',
|
|
'classId': f'{issuer_id}.FLIGHT_CLASS_SUFFIX'
|
|
}],
|
|
|
|
# Generic passes
|
|
'genericObjects': [{
|
|
'id': f'{issuer_id}.GENERIC_OBJECT_SUFFIX',
|
|
'classId': f'{issuer_id}.GENERIC_CLASS_SUFFIX'
|
|
}],
|
|
|
|
# Gift cards
|
|
'giftCardObjects': [{
|
|
'id': f'{issuer_id}.GIFT_CARD_OBJECT_SUFFIX',
|
|
'classId': f'{issuer_id}.GIFT_CARD_CLASS_SUFFIX'
|
|
}],
|
|
|
|
# Loyalty cards
|
|
'loyaltyObjects': [{
|
|
'id': f'{issuer_id}.LOYALTY_OBJECT_SUFFIX',
|
|
'classId': f'{issuer_id}.LOYALTY_CLASS_SUFFIX'
|
|
}],
|
|
|
|
# Offers
|
|
'offerObjects': [{
|
|
'id': f'{issuer_id}.OFFER_OBJECT_SUFFIX',
|
|
'classId': f'{issuer_id}.OFFER_CLASS_SUFFIX'
|
|
}],
|
|
|
|
# Transit passes
|
|
'transitObjects': [{
|
|
'id': f'{issuer_id}.TRANSIT_OBJECT_SUFFIX',
|
|
'classId': f'{issuer_id}.TRANSIT_CLASS_SUFFIX'
|
|
}]
|
|
}
|
|
|
|
# Create the JWT claims
|
|
claims = {
|
|
'iss': self.credentials.service_account_email,
|
|
'aud': 'google',
|
|
'origins': ['www.example.com'],
|
|
'typ': 'savetowallet',
|
|
'payload': objects_to_add
|
|
}
|
|
|
|
# The service account credentials are used to sign the JWT
|
|
signer = crypt.RSASigner.from_service_account_file(self.key_file_path)
|
|
token = jwt.encode(signer, claims).decode('utf-8')
|
|
|
|
print('Add to Google Wallet link')
|
|
print(f'https://pay.google.com/gp/v/save/{token}')
|
|
|
|
return f'https://pay.google.com/gp/v/save/{token}'
|
|
|
|
# [END jwtExisting]
|
|
|
|
# [START batch]
|
|
def batch_create_objects(self, issuer_id: str, class_suffix: str):
|
|
"""Batch create Google Wallet objects from an existing class.
|
|
|
|
The request body will be a multiline string. See below for information.
|
|
|
|
https://cloud.google.com/compute/docs/api/how-tos/batch#example
|
|
|
|
Args:
|
|
issuer_id (str): The issuer ID being used for this request.
|
|
class_suffix (str): Developer-defined unique ID for this pass class.
|
|
"""
|
|
batch = self.client.new_batch_http_request()
|
|
|
|
# Example: Generate three new pass objects
|
|
for _ in range(3):
|
|
# Generate a random object suffix
|
|
object_suffix = str(uuid.uuid4()).replace('[^\\w.-]', '_')
|
|
|
|
# See link below for more information on required properties
|
|
# https://developers.google.com/wallet/generic/rest/v1/genericobject
|
|
batch_object = {
|
|
'id': f'{issuer_id}.{object_suffix}',
|
|
'classId': f'{issuer_id}.{class_suffix}',
|
|
'state': 'ACTIVE',
|
|
'heroImage': {
|
|
'sourceUri': {
|
|
'uri':
|
|
'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg'
|
|
},
|
|
'contentDescription': {
|
|
'defaultValue': {
|
|
'language': 'en-US',
|
|
'value': 'Hero image description'
|
|
}
|
|
}
|
|
},
|
|
'textModulesData': [{
|
|
'header': 'Text module header',
|
|
'body': 'Text module body',
|
|
'id': 'TEXT_MODULE_ID'
|
|
}],
|
|
'linksModuleData': {
|
|
'uris': [{
|
|
'uri': 'http://maps.google.com/',
|
|
'description': 'Link module URI description',
|
|
'id': 'LINK_MODULE_URI_ID'
|
|
}, {
|
|
'uri': 'tel:6505555555',
|
|
'description': 'Link module tel description',
|
|
'id': 'LINK_MODULE_TEL_ID'
|
|
}]
|
|
},
|
|
'imageModulesData': [{
|
|
'mainImage': {
|
|
'sourceUri': {
|
|
'uri':
|
|
'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg'
|
|
},
|
|
'contentDescription': {
|
|
'defaultValue': {
|
|
'language': 'en-US',
|
|
'value': 'Image module description'
|
|
}
|
|
}
|
|
},
|
|
'id': 'IMAGE_MODULE_ID'
|
|
}],
|
|
'barcode': {
|
|
'type': 'QR_CODE',
|
|
'value': 'QR code'
|
|
},
|
|
'cardTitle': {
|
|
'defaultValue': {
|
|
'language': 'en-US',
|
|
'value': 'Generic card title'
|
|
}
|
|
},
|
|
'header': {
|
|
'defaultValue': {
|
|
'language': 'en-US',
|
|
'value': 'Generic header'
|
|
}
|
|
},
|
|
'hexBackgroundColor': '#4285f4',
|
|
'logo': {
|
|
'sourceUri': {
|
|
'uri':
|
|
'https://developers.google.com/static/wallet/site-assets/images/pass-builder/pass_google_logo.jpg'
|
|
},
|
|
'contentDescription': {
|
|
'defaultValue': {
|
|
'language': 'en-US',
|
|
'value': 'Generic card logo'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
batch.add(self.client.genericobject().insert(body=batch_object))
|
|
|
|
# Invoke the batch API calls
|
|
response = batch.execute()
|
|
|
|
print('Batch complete')
|
|
|
|
# [END batch]
|