RevenueCat / react-native-purchases

React Native in-app purchases and subscriptions made easy. Support for iOS and Android.
https://www.revenuecat.com
MIT License
691 stars 77 forks source link

restorePurchases returns unexpected transactionIdentifier #991

Open TobiDevloft opened 1 month ago

TobiDevloft commented 1 month ago

Describe the bug When purchasing a package (consumable product), I'm storing the returned productIdentifier, purchaseDate and transactionIdentifier in my DB. I now want to implement restore logic using restorePurchases the following way:

const { nonSubscriptionTransactions } = await Purchases.restorePurchases()

My goal is to compare the restored transactions to the ones in my DB. However, the transactionId differs in the restored transactions from the original transaction.

E.g., when the original transaction for purchasePackage looks like this:

{
   "productId":"product_id",
   "productIdentifier":"product_id",
   "purchaseDate":"2024-04-30T16:16:32Z",
   "purchaseDateMillis":1714493792000,
   "revenueCatId":"2000000585921649",
   "transactionIdentifier":"2000000585921649"
}

The corresponding restored transaction looks like this:

{
   "productId":"product_id",
   "productIdentifier":"product_id",
   "purchaseDate":"2024-04-30T16:16:32Z",
   "purchaseDateMillis":1714493792000,
   "revenueCatId":"eb6f56e377",
   "transactionIdentifier":"eb6f56e377"
}

I could just link these transactions using the timestamp, but that does not seem like a clean approach. Am I misunderstanding something here?

I also noticed that the returned properties do not match the PurchasesStoreTransaction interface like specified, but that seems to be another issue.

Thanks for your help!

  1. Environment
    1. Platform: iOS & Android
    2. SDK version: 7.27.0
    3. OS version: MacOS 14.0
    4. Xcode/Android Studio version: Xcode 15.0.1
    5. React Native version: 0.72.5
    6. SDK installation (CocoaPods + version or manual): I don't understand what that is
    7. How widespread is the issue. Percentage of devices affected: All of them
  2. Debug logs that reproduce the issue
  3. Steps to reproduce, with a description of expected vs. actual behavior: Make a purchase, restore that purchase.
RCGitBot commented 1 month ago

👀 We've just linked this issue to our internal tracker and notified the team. Thank you for reporting, we're checking this out!

WesleyClarkRC commented 1 month ago

Hi! Thank you for raising this issue. We may need to escalate this further. Could you share the debug logs that reproduce this issue?

TobiDevloft commented 1 month ago

Hi @WesleyClarkRC, thanks for getting back to me. Here are the Debug logs:

APP START

DEBUG: ℹ️ Configuring SDK using RevenueCat's UserDefaults suite.
DEBUG: 👤 Identifying App User ID
DEBUG: ℹ️ Debug logging enabled
DEBUG: ℹ️ SDK Version - 4.41.0
DEBUG: ℹ️ Bundle ID - app.bundle
DEBUG: ℹ️ System Version - Version 17.4.1 (Build 21E236)
DEBUG: ℹ️ Not using a simulator.
DEBUG: 👤 No initial App User ID
DEBUG: ℹ️ Purchases is configured with response verification disabled
DEBUG: ℹ️ Delegate set
DEBUG: ℹ️ No cached Offerings, fetching from network
DEBUG: ℹ️ Offerings cache is stale, updating from network in foreground
DEBUG: ℹ️ GetOfferingsOperation: Started
DEBUG: ℹ️ Network operation 'GetOfferingsOperation' found with the same cache key 'GetOfferingsOpe…'. Skipping request.
DEBUG: ℹ️ There are no requests currently running, starting request GET /v1/subscribers/$RCAnonymousID%3A348a78f9ea4543fb9dc62110489b1742/offerings
DEBUG: ℹ️ API request started: GET '/v1/subscribers/$RCAnonymousID%3A348a78f9ea4543fb9dc62110489b1742/offerings'
DEBUG: ℹ️ API request completed: GET '/v1/subscribers/$RCAnonymousID%3A348a78f9ea4543fb9dc62110489b1742/offerings' (304)
DEBUG: ℹ️ No existing products cached, starting store products request for: ["escape_single_2999", "escape_group_3999"]
DEBUG: ℹ️ Found an existing request for products: ["escape_single_2999", "escape_group_3999"], appending to completion
DEBUG: ℹ️ GetOfferingsOperation: Finished
DEBUG: ℹ️ Serial request done: GET /v1/subscribers/$RCAnonymousID%3A348a78f9ea4543fb9dc62110489b1742/offerings, 0 requests left in the queue
DEBUG: ℹ️ GetCustomerInfoOperation: Started
DEBUG: ℹ️ There are no requests currently running, starting request GET /v1/subscribers/$RCAnonymousID%3A348a78f9ea4543fb9dc62110489b1742
DEBUG: ℹ️ API request started: GET '/v1/subscribers/$RCAnonymousID%3A348a78f9ea4543fb9dc62110489b1742'
DEBUG: 😻 Store products request received response
DEBUG: 😻 Store products request finished
DEBUG: 😻 Offerings updated from network.
DEBUG: 😻 Offerings updated from network.
DEBUG: ℹ️ This StoreProduct represents an SK1 product, the type of product cannot be determined, the value will be undefined. Use `StoreProduct.productCategory` instead.
DEBUG: ℹ️ This StoreProduct represents an SK1 product, the type of product cannot be determined, the value will be undefined. Use `StoreProduct.productCategory` instead.
DEBUG: ℹ️ This StoreProduct represents an SK1 product, the type of product cannot be determined, the value will be undefined. Use `StoreProduct.productCategory` instead.
DEBUG: ℹ️ This StoreProduct represents an SK1 product, the type of product cannot be determined, the value will be undefined. Use `StoreProduct.productCategory` instead.
[GET] - player/information
DEBUG: ℹ️ API request completed: GET '/v1/subscribers/$RCAnonymousID%3A348a78f9ea4543fb9dc62110489b1742' (304)
DEBUG: 😻 CustomerInfo updated from network.
DEBUG: ℹ️ GetCustomerInfoOperation: Finished
DEBUG: ℹ️ Serial request done: GET /v1/subscribers/$RCAnonymousID%3A348a78f9ea4543fb9dc62110489b1742, 0 requests left in the queue

PURCHASE PROCESS:

DEBUG: ℹ️ Vending Offerings from memory cache
INFO: 💰 Purchasing Product 'escape_single_2999' from package in Offering 'default'
DEBUG: ℹ️ Adding payment for product 'escape_single_2999'. 0 transactions already in the queue.
DEBUG: ℹ️ StoreKit1Wrapper (0x0000000300c8bc00) updatedTransaction: escape_single_2999 0
DEBUG: ℹ️ StoreKit1Wrapper (0x0000000300c8bc00) updatedTransaction: escape_single_2999 2000000587971827 1
DEBUG: ℹ️ Found 0 unsynced attributes for App User ID: $RCAnonymousID:348a78f9ea4543fb9dc62110489b1742
DEBUG: ℹ️ TransactionPoster: handling transaction '2000000587971827' for product 'escape_single_2999' (date: 2024-05-03 08:32:00 +0000) in Offering 'default'
DEBUG: ℹ️ Force refreshing the receipt to get latest transactions from Apple.
DEBUG: ℹ️ SKReceiptRefreshRequest started
<SKReceiptRefreshRequest: 0x3028e4fc0>: Finished refreshing receipt with error: Error Domain=ASDErrorDomain Code=603 "Request throttled" UserInfo={NSLocalizedDescription=Request throttled, NSLocalizedFailureReason=Unified receipt is valid and current}
DEBUG: ℹ️ SKReceiptRefreshRequest finished
DEBUG: ℹ️ Loaded receipt from url file:///private/var/mobile/Containers/Data/Application/E3E870D4-1A9B-4A54-A952-88752464018F/StoreKit/sandboxReceipt
DEBUG: ℹ️ Skipping products request for these products because they were already cached: ["escape_single_2999"]
DEBUG: ℹ️ PostReceiptDataOperation: Started
INFO: ℹ️ Parsing receipt
INFO: ℹ️ Receipt parsed successfully
DEBUG: ℹ️ PostReceiptDataOperation: Posting receipt (source: 'purchase') (note: the contents might not be up-to-date, but it will be refreshed with Apple's servers):
{"original_application_version":"1.0","opaque_value":"uz6Gg6brXC4RvVAksrm\/pg==","creation_date":"2024-05-03T08:32:00Z","environment":"ProductionSandbox","application_version":"46","sha1_hash":"ZUyNK3uM4FE2EubtE+WAgjN4KRU=","bundle_id":"app.bundle","in_app_purchases":[{"quantity":1,"product_type":1,"original_purchase_date":"2024-05-03T08:32:00Z","purchase_date":"2024-05-03T08:32:00Z","product_id":"escape_single_2999","is_in_trial_period":false,"original_transaction_id":"2000000587971827","web_order_line_item_id":0,"transaction_id":"2000000587971827"}]}
DEBUG: ℹ️ There are no requests currently running, starting request POST /v1/receipts
DEBUG: ℹ️ API request started: POST '/v1/receipts'
DEBUG: ℹ️ API request completed: POST '/v1/receipts' (200)
DEBUG: ℹ️ PostReceiptDataOperation: Finished
INFO: 💰 Finishing transaction '2000000587971827' for product 'escape_single_2999'
DEBUG: ℹ️ Serial request done: POST /v1/receipts, 0 requests left in the queue
DEBUG: ℹ️ StoreKit1Wrapper (0x0000000300c8bc00) removedTransaction: escape_single_2999 2000000587971827 1
DEBUG: ℹ️ Sending updated CustomerInfo to delegate.
DEBUG: ℹ️ Detected active subscriptions changed. Clearing trial or intro eligibility cache.
DEBUG: ℹ️ PurchasedProductsFetcher: invalidating cache
INFO: 😻💰 Purchased product - 'escape_single_2999'

RESTORE PROCESS:

DEBUG: ℹ️ Loaded receipt from url file:///private/var/mobile/Containers/Data/Application/E3E870D4-1A9B-4A54-A952-88752464018F/StoreKit/sandboxReceipt
INFO: ℹ️ Parsing receipt
INFO: ℹ️ Receipt parsed successfully
INFO: ℹ️ Parsing receipt
INFO: ℹ️ Receipt parsed successfully
DEBUG: ℹ️ PostReceiptDataOperation: Started
INFO: ℹ️ Parsing receipt
INFO: ℹ️ Receipt parsed successfully
DEBUG: ℹ️ PostReceiptDataOperation: Posting receipt (source: 'restore') (note: the contents might not be up-to-date, but it will be refreshed with Apple's servers):
{"application_version":"46","environment":"ProductionSandbox","sha1_hash":"ZUyNK3uM4FE2EubtE+WAgjN4KRU=","original_application_version":"1.0","in_app_purchases":[{"web_order_line_item_id":0,"transaction_id":"2000000587971827","quantity":1,"is_in_trial_period":false,"product_type":1,"original_transaction_id":"2000000587971827","original_purchase_date":"2024-05-03T08:32:00Z","product_id":"escape_single_2999","purchase_date":"2024-05-03T08:32:00Z"}],"opaque_value":"uz6Gg6brXC4RvVAksrm\/pg==","creation_date":"2024-05-03T08:32:00Z","bundle_id":"app.bundle"}
DEBUG: ℹ️ There are no requests currently running, starting request POST /v1/receipts
DEBUG: ℹ️ API request started: POST '/v1/receipts'
DEBUG: ℹ️ API request completed: POST '/v1/receipts' (200)
DEBUG: ℹ️ PostReceiptDataOperation: Finished
DEBUG: ℹ️ Serial request done: POST /v1/receipts, 0 requests left in the queue
WesleyClarkRC commented 3 weeks ago

Hi @TobiDevloft, I apologize for the delay. Thank you for the debug logs. This difference in what is returned is actually a result of whether the transaction ID is returned from the device or through our API. From the device, it will be the one provided by the store, while through our API, it will be the hashed version of that.