diff --git a/RevenueCatUI/CustomerCenter/ViewModels/CustomerCenterViewModel.swift b/RevenueCatUI/CustomerCenter/ViewModels/CustomerCenterViewModel.swift index 14e1c20079..10e8684fab 100644 --- a/RevenueCatUI/CustomerCenter/ViewModels/CustomerCenterViewModel.swift +++ b/RevenueCatUI/CustomerCenter/ViewModels/CustomerCenterViewModel.swift @@ -208,21 +208,29 @@ private extension CustomerCenterViewModel { func createPurchaseInformation(for transaction: Transaction, entitlement: EntitlementInfo?) async throws -> PurchaseInformation { if transaction.store == .appStore { - guard let product = await purchasesProvider.products([transaction.productIdentifier]).first else { - Logger.warning(Strings.could_not_find_subscription_information) - throw CustomerCenterError.couldNotFindSubscriptionInformation + if let product = await purchasesProvider.products([transaction.productIdentifier]).first { + return PurchaseInformation( + entitlement: entitlement, + subscribedProduct: product, + transaction: transaction + ) + } else { + Logger.warning( + Strings.could_not_find_product_loading_without_product_information(transaction.productIdentifier) + ) + + return PurchaseInformation( + entitlement: entitlement, + transaction: transaction + ) } - return PurchaseInformation( - entitlement: entitlement, - subscribedProduct: product, - transaction: transaction - ) - } else { - return PurchaseInformation( - entitlement: entitlement, - transaction: transaction - ) } + Logger.warning(Strings.active_product_is_not_apple_loading_without_product_information(transaction.store)) + + return PurchaseInformation( + entitlement: entitlement, + transaction: transaction + ) } } diff --git a/RevenueCatUI/Data/Strings.swift b/RevenueCatUI/Data/Strings.swift index 0facdade6d..a3c4952029 100644 --- a/RevenueCatUI/Data/Strings.swift +++ b/RevenueCatUI/Data/Strings.swift @@ -68,6 +68,8 @@ enum Strings { case error_fetching_promotional_offer(Error) case promo_offer_not_loaded case could_not_determine_type_of_custom_url + case active_product_is_not_apple_loading_without_product_information(Store) + case could_not_find_product_loading_without_product_information(String) } @@ -211,6 +213,13 @@ extension Strings: CustomStringConvertible { case .could_not_determine_type_of_custom_url: return "Could not determine the type of custom URL, the URL will be opened externally." + case .active_product_is_not_apple_loading_without_product_information(let store): + return "Active product for user is not an Apple subscription (\(store))." + + " Loading without product information." + + case .could_not_find_product_loading_without_product_information(let product): + return "Could not find product with id \(product). Loading without product information." + } } diff --git a/Tests/RevenueCatUITests/CustomerCenter/CustomerCenterViewModelTests.swift b/Tests/RevenueCatUITests/CustomerCenter/CustomerCenterViewModelTests.swift index 91b6c9c042..02e2c679ed 100644 --- a/Tests/RevenueCatUITests/CustomerCenter/CustomerCenterViewModelTests.swift +++ b/Tests/RevenueCatUITests/CustomerCenter/CustomerCenterViewModelTests.swift @@ -635,6 +635,56 @@ class CustomerCenterViewModelTests: TestCase { } } + func testShouldShowActiveSubscription_withoutProductInformation() async throws { + // If product can't load because maybe it's from another app in same project + + let productId = "com.revenuecat.product" + let purchaseDate = "2022-04-12T00:03:28Z" + let expirationDate = "2062-04-12T00:03:35Z" + + let customerInfo = CustomerInfoFixtures.customerInfo( + subscriptions: [ + CustomerInfoFixtures.Subscription( + id: productId, + store: "app_store", + purchaseDate: purchaseDate, + expirationDate: expirationDate + ) + ], + entitlements: [ + CustomerInfoFixtures.Entitlement( + entitlementId: "premium", + productId: productId, + purchaseDate: purchaseDate, + expirationDate: expirationDate + ) + ] + ) + + let viewModel = CustomerCenterViewModel(customerCenterActionHandler: nil, + purchasesProvider: MockCustomerCenterPurchases( + customerInfo: customerInfo, + products: [] + )) + + await viewModel.loadScreen() + + expect(viewModel.state) == .success + + let purchaseInformation = try XCTUnwrap(viewModel.purchaseInformation) + expect(purchaseInformation.title).to(beNil()) + expect(purchaseInformation.durationTitle).to(beNil()) + expect(purchaseInformation.explanation) == .earliestRenewal + expect(purchaseInformation.store) == .appStore + expect(purchaseInformation.price) == .unknown + + let expirationOrRenewal = try XCTUnwrap(purchaseInformation.expirationOrRenewal) + expect(expirationOrRenewal.label) == .nextBillingDate + expect(expirationOrRenewal.date) == .date(reformat(ISO8601Date: expirationDate)) + + expect(purchaseInformation.productIdentifier) == productId + } + func testLoadScreenNoActiveSubscription() async throws { let customerInfo = CustomerInfoFixtures.customerInfoWithExpiredAppleSubscriptions let mockPurchases = MockCustomerCenterPurchases(customerInfo: customerInfo)