-
Notifications
You must be signed in to change notification settings - Fork 338
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for product_mapping
in promotional offers
#4489
Changes from all commits
38980f0
e843b55
df9ac60
67b522c
53575f9
a13ce3f
bd5dc7c
eed2722
600c3b1
ec0b7ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -43,41 +43,20 @@ class LoadPromotionalOfferUseCase: LoadPromotionalOfferUseCaseType { | |||||||||||||
do { | ||||||||||||||
let customerInfo = try await self.purchasesProvider.customerInfo() | ||||||||||||||
|
||||||||||||||
guard let productIdentifier = customerInfo.earliestExpiringAppStoreEntitlement()?.productIdentifier, | ||||||||||||||
let subscribedProduct = await self.purchasesProvider.products([productIdentifier]).first else { | ||||||||||||||
Logger.warning(Strings.could_not_offer_for_any_active_subscriptions) | ||||||||||||||
return .failure(CustomerCenterError.couldNotFindSubscriptionInformation) | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
let exactMatch = subscribedProduct.discounts.first { discount in | ||||||||||||||
discount.offerIdentifier == promoOfferDetails.iosOfferId | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
let discount: StoreProductDiscount? | ||||||||||||||
if let exactMatch = exactMatch { | ||||||||||||||
discount = exactMatch | ||||||||||||||
} else { | ||||||||||||||
discount = subscribedProduct.discounts.first { discount in | ||||||||||||||
guard let offerIdentifier = discount.offerIdentifier else { | ||||||||||||||
return false | ||||||||||||||
} | ||||||||||||||
return offerIdentifier.hasSuffix("_\(promoOfferDetails.iosOfferId)") | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
guard let discount = discount else { | ||||||||||||||
let message = | ||||||||||||||
Strings.could_not_offer_for_active_subscriptions(promoOfferDetails.iosOfferId, productIdentifier) | ||||||||||||||
Logger.debug(message) | ||||||||||||||
return .failure(CustomerCenterError.couldNotFindSubscriptionInformation) | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
let promotionalOffer = try await self.purchasesProvider.promotionalOffer(forProductDiscount: discount, | ||||||||||||||
product: subscribedProduct) | ||||||||||||||
let promotionalOfferData = PromotionalOfferData(promotionalOffer: promotionalOffer, | ||||||||||||||
product: subscribedProduct, | ||||||||||||||
promoOfferDetails: promoOfferDetails) | ||||||||||||||
return .success(promotionalOfferData) | ||||||||||||||
let subscribedProduct = try await getActiveSubscription(customerInfo) | ||||||||||||||
let discount = try findDiscount(for: subscribedProduct, | ||||||||||||||
productIdentifier: subscribedProduct.productIdentifier, | ||||||||||||||
promoOfferDetails: promoOfferDetails) | ||||||||||||||
|
||||||||||||||
let promotionalOffer = try await self.purchasesProvider.promotionalOffer( | ||||||||||||||
forProductDiscount: discount, | ||||||||||||||
product: subscribedProduct | ||||||||||||||
) | ||||||||||||||
return .success(PromotionalOfferData( | ||||||||||||||
promotionalOffer: promotionalOffer, | ||||||||||||||
product: subscribedProduct, | ||||||||||||||
promoOfferDetails: promoOfferDetails | ||||||||||||||
)) | ||||||||||||||
} catch { | ||||||||||||||
Logger.warning(Strings.error_fetching_promotional_offer(error)) | ||||||||||||||
return .failure(CustomerCenterError.couldNotFindOfferForActiveProducts) | ||||||||||||||
|
@@ -86,4 +65,83 @@ class LoadPromotionalOfferUseCase: LoadPromotionalOfferUseCaseType { | |||||||||||||
|
||||||||||||||
} | ||||||||||||||
|
||||||||||||||
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) | ||||||||||||||
@available(macOS, unavailable) | ||||||||||||||
@available(tvOS, unavailable) | ||||||||||||||
@available(watchOS, unavailable) | ||||||||||||||
private extension LoadPromotionalOfferUseCase { | ||||||||||||||
|
||||||||||||||
private func getActiveSubscription(_ customerInfo: CustomerInfo) async throws -> StoreProduct { | ||||||||||||||
guard let productIdentifier = customerInfo.earliestExpiringAppStoreEntitlement()?.productIdentifier, | ||||||||||||||
let subscribedProduct = await self.purchasesProvider.products([productIdentifier]).first else { | ||||||||||||||
Logger.warning(Strings.could_not_offer_for_any_active_subscriptions) | ||||||||||||||
throw CustomerCenterError.couldNotFindSubscriptionInformation | ||||||||||||||
} | ||||||||||||||
return subscribedProduct | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
private func findDiscount( | ||||||||||||||
for product: StoreProduct, | ||||||||||||||
productIdentifier: String, | ||||||||||||||
promoOfferDetails: CustomerCenterConfigData.HelpPath.PromotionalOffer | ||||||||||||||
) throws -> StoreProductDiscount { | ||||||||||||||
let discount = if !promoOfferDetails.productMapping.isEmpty { | ||||||||||||||
findMappedDiscount(for: product, | ||||||||||||||
productIdentifier: productIdentifier, | ||||||||||||||
promoOfferDetails: promoOfferDetails) | ||||||||||||||
} else { | ||||||||||||||
findLegacyDiscount(for: product, promoOfferDetails: promoOfferDetails) | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
guard let discount = discount else { | ||||||||||||||
logDiscountError(productIdentifier: productIdentifier, promoOfferDetails: promoOfferDetails) | ||||||||||||||
throw CustomerCenterError.couldNotFindSubscriptionInformation | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
return discount | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
private func findMappedDiscount( | ||||||||||||||
for product: StoreProduct, | ||||||||||||||
productIdentifier: String, | ||||||||||||||
promoOfferDetails: CustomerCenterConfigData.HelpPath.PromotionalOffer | ||||||||||||||
) -> StoreProductDiscount? { | ||||||||||||||
product.discounts.first { $0.offerIdentifier == promoOfferDetails.productMapping[productIdentifier] } | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
private func findLegacyDiscount( | ||||||||||||||
for product: StoreProduct, | ||||||||||||||
promoOfferDetails: CustomerCenterConfigData.HelpPath.PromotionalOffer | ||||||||||||||
) -> StoreProductDiscount? { | ||||||||||||||
// Try exact match first | ||||||||||||||
if let exactMatch = product.discounts.first(where: { | ||||||||||||||
$0.offerIdentifier == promoOfferDetails.iosOfferId | ||||||||||||||
}) { | ||||||||||||||
Comment on lines
+117
to
+119
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FFTI, but you can also do it like this
Suggested change
Then again maybe the brackets add some clarity since it ends in a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It actually fails because of the ending There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh, then nevermind |
||||||||||||||
return exactMatch | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
// Fall back to suffix matching | ||||||||||||||
return product.discounts.first { $0.offerIdentifier?.hasSuffix("_\(promoOfferDetails.iosOfferId)") == true } | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
private func logDiscountError( | ||||||||||||||
productIdentifier: String, | ||||||||||||||
promoOfferDetails: CustomerCenterConfigData.HelpPath.PromotionalOffer | ||||||||||||||
) { | ||||||||||||||
let message = if !promoOfferDetails.productMapping.isEmpty { | ||||||||||||||
Strings.could_not_offer_for_active_subscriptions( | ||||||||||||||
promoOfferDetails.productMapping[productIdentifier] ?? "nil", | ||||||||||||||
productIdentifier | ||||||||||||||
) | ||||||||||||||
} else { | ||||||||||||||
Strings.could_not_offer_for_active_subscriptions( | ||||||||||||||
promoOfferDetails.iosOfferId, | ||||||||||||||
productIdentifier | ||||||||||||||
) | ||||||||||||||
} | ||||||||||||||
Logger.debug(message) | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
} | ||||||||||||||
|
||||||||||||||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL let foo = if ... else works. I would have used a ternary but I feel like this might be more readable