in in_app_purchases/complete/firebase-backend/functions/src/google-play.purchase-handler.ts [92:159]
async handleSubscription(
userId: string | null,
productData: ProductData,
token: string,
): Promise<boolean> {
try {
// Verify the purchase with Google
const response = await this.androidPublisher.purchases.subscriptions.get(
{
packageName: ANDROID_PACKAGE_ID,
subscriptionId: productData.productId,
token,
},
);
// Make sure an order id exists
if (!response.data.orderId) {
console.error("Could not handle purchase without order id");
return false;
}
// If a subscription suffix is present (..#) extract the orderId.
let orderId = response.data.orderId;
const orderIdMatch = /^(.+)?[.]{2}[0-9]+$/g.exec(orderId);
if (orderIdMatch) {
orderId = orderIdMatch[1];
}
console.log({
rawOrderId: response.data.orderId,
newOrderId: orderId,
});
// Construct purchase data for db updates
const purchaseData: Omit<SubscriptionPurchase, "userId"> = {
type: "SUBSCRIPTION",
iapSource: "google_play",
orderId: orderId,
productId: productData.productId,
purchaseDate: firestore.Timestamp.fromMillis(parseInt(response.data.startTimeMillis ?? "0", 10)),
expiryDate: firestore.Timestamp.fromMillis(parseInt(response.data.expiryTimeMillis ?? "0", 10)),
status: [
"PENDING", // Payment pending
"ACTIVE", // Payment received
"ACTIVE", // Free trial
"PENDING", // Pending deferred upgrade/downgrade
"EXPIRED", // Expired or cancelled
][response.data.paymentState ?? 4] as SubscriptionStatus,
};
try {
if (userId) {
// If we know the userId,
// update the existing purchase or create it if it does not exist.
await this.iapRepository
.createOrUpdatePurchase({
...purchaseData,
userId,
} as Purchase);
} else {
// If we do not know the user id, a previous entry must already
// exist, and thus we'll only update it.
await this.iapRepository.updatePurchase(purchaseData);
}
} catch (e) {
console.log("Could not create or update purchase", {orderId, productId: productData.productId});
}
return true;
} catch (e) {
console.error(e);
return false;
}
}