[Installments] - Add winback and trial offers#5000
Conversation
Generated by 🚫 Danger |
There was a problem hiding this comment.
Pull request overview
This PR adds support for promotional offers (Trial and Winback) on installment subscription plans, specifically for the Plus Yearly Installment plan. Previously, installment plans only supported base plans without offers, but this change enables the system to apply trial periods and winback offers to installment payment plans.
Changes:
- Extended the subscription plan data model to support offers on installment plans by adding
isInstallmentparameter toSubscriptionPlan.WithOfferandfindOfferPlanmethod - Added comprehensive test coverage for installment offer functionality including trial and winback offers
- Updated analytics tracking across multiple features to include installment status
- Enhanced UI components to properly display installment plans with offers, including custom display names and correct price calculations
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| modules/services/payment/src/main/kotlin/au/com/shiftyjelly/pocketcasts/payment/Data.kt | Extended data model to support offers on installment plans by adding isInstallment parameter to SubscriptionPlan.WithOffer, findOfferPlan, and SubscriptionOffer.offerId methods |
| modules/services/payment/src/test/kotlin/au/com/shiftyjelly/pocketcasts/payment/SubscriptionPlansTest.kt | Added test data for installment plans with offers and comprehensive test cases validating offer ID generation, plan finding, and unsupported offer types |
| modules/features/profile/src/main/java/au/com/shiftyjelly/pocketcasts/profile/winback/WinbackViewModel.kt | Updated winback flow to support installment offers by checking both installment and non-installment variants and adding installment tracking to analytics |
| modules/features/profile/src/test/kotlin/au/com/shiftyjelly/pocketcasts/profile/winback/WinbackViewModelTest.kt | Updated test expectations to include isInstallment parameter in winback offer assertions and analytics verification |
| modules/features/profile/src/main/java/au/com/shiftyjelly/pocketcasts/profile/winback/WinbackOfferPage.kt | Updated Compose preview parameters to include isInstallment field for proper preview rendering |
| modules/features/account/src/main/java/au/com/shiftyjelly/pocketcasts/account/viewmodel/OnboardingUpgradeFeaturesViewModel.kt | Modified to support finding offer plans for installment subscriptions when feature flag is enabled and added installment tracking to analytics |
| modules/features/account/src/main/java/au/com/shiftyjelly/pocketcasts/account/onboarding/components/SubscriptionPlanRow.kt | Enhanced UI to handle installment offers including custom display names, correct price-per-period calculations, and savings percentage logic |
| modules/services/localization/src/main/res/values/strings.xml | Added new string resource for Plus yearly trial installments display name |
|
|
|
| App Name | ⌚ Wear | |
| Build Type | DebugProd | |
| Build Number | 9406 | |
| Version | 8.5-rc-2 | |
| Application ID | au.com.shiftyjelly.pocketcasts | |
| Commit | 3e120eb | |
| Direct Download | pocketcasts-wear-prototype-build-pr5000-3e120eb.apk | |
| Installation URL | 7jial4hllipr0 |
📲 You can test the changes from this Pull Request in 🚗 Automotive by scanning the QR code below to install the corresponding build.
| App Name | 🚗 Automotive | |
| Build Type | DebugProd | |
| Build Number | 9406 | |
| Version | 8.5-rc-2 | |
| Application ID | au.com.shiftyjelly.pocketcasts | |
| Commit | 3e120eb | |
| Direct Download | pocketcasts-automotive-prototype-build-pr5000-3e120eb.apk | |
| Installation URL | 7jial4hllipr0 |
3e120eb to
a207e55
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated 5 comments.
Comments suppressed due to low confidence (1)
modules/features/profile/src/test/kotlin/au/com/shiftyjelly/pocketcasts/profile/winback/WinbackViewModelTest.kt:710
- Missing test coverage for analytics tracking when claiming an installment winback offer. The existing tests only verify
is_installment = "false"scenarios. Consider adding a test that verifies the analytics event when a user claims an installment winback offer (e.g., Plus Yearly Installment with a winback offer), to ensureis_installment = "true"is correctly tracked.
@Test
fun `track claim patron yearly offer tapped`() = runTest {
paymentDataSource.loadedPurchases = listOf(
createPurchase(productIds = listOf(SubscriptionPlan.PATRON_YEARLY_PRODUCT_ID)),
)
viewModel.loadWinbackData()
viewModel.claimOffer(mock<Activity>())
val event = tracker.events.single()
assertEquals(
TrackedEvent(
AnalyticsEvent.WINBACK_MAIN_SCREEN_ROW_TAP,
mapOf(
"row" to "claim_offer",
"tier" to "patron",
"frequency" to "yearly",
"is_installment" to "false",
),
),
event,
)
}
...res/profile/src/main/java/au/com/shiftyjelly/pocketcasts/profile/winback/WinbackViewModel.kt
Outdated
Show resolved
Hide resolved
...res/profile/src/main/java/au/com/shiftyjelly/pocketcasts/profile/winback/WinbackViewModel.kt
Outdated
Show resolved
Hide resolved
...res/profile/src/main/java/au/com/shiftyjelly/pocketcasts/profile/winback/WinbackViewModel.kt
Show resolved
Hide resolved
...ures/profile/src/main/java/au/com/shiftyjelly/pocketcasts/profile/winback/WinbackFragment.kt
Outdated
Show resolved
Hide resolved
...res/profile/src/main/java/au/com/shiftyjelly/pocketcasts/profile/winback/WinbackOfferPage.kt
Outdated
Show resolved
Hide resolved
MiSikora
left a comment
There was a problem hiding this comment.
The implementation looks good. The only thing that needs changing is mapping of Product to SubscriptionPlan that doesn't use installment data for validation.
I also found one issue that needs to be addressed before releasing but it can be addressed in a separate PR. During the Winback flow the plan change isn't aware of installements.
.../java/au/com/shiftyjelly/pocketcasts/account/viewmodel/OnboardingUpgradeFeaturesViewModel.kt
Outdated
Show resolved
Hide resolved
...ain/java/au/com/shiftyjelly/pocketcasts/account/onboarding/components/SubscriptionPlanRow.kt
Outdated
Show resolved
Hide resolved
...res/profile/src/main/java/au/com/shiftyjelly/pocketcasts/profile/winback/OfferClaimedPage.kt
Outdated
Show resolved
Hide resolved
...res/profile/src/main/java/au/com/shiftyjelly/pocketcasts/profile/winback/WinbackViewModel.kt
Outdated
Show resolved
Hide resolved
...ofile/src/test/kotlin/au/com/shiftyjelly/pocketcasts/profile/winback/WinbackViewModelTest.kt
Show resolved
Hide resolved
modules/services/payment/src/main/kotlin/au/com/shiftyjelly/pocketcasts/payment/Data.kt
Outdated
Show resolved
Hide resolved
|
@MiSikora i've updated the code in sync with your comments, please have another look. i'll address the plan change issue you noticed in an upcoming PR. |

Description
This PR adds the two new offers under the installment plan.
We now support installment trials:
plus-yearly-installments-trial-30daysand winbacks:plus-yearly-installments-winbackI also had to update the upgrade screen to properly display the name of the installments plan alongside with the price and discount calculations.
The winback screen has been also adjusted to accomodate installments, now the text are clearer.
p2: pdeCcb-aGD-p2
slack: p1771529147990719-slack-C0A0PJSLGBT
Fixes PCDROID-425
Testing Instructions
A - Trial
Caveat: you can only claim trial once per pocket casts accounts
B - Winback
Screenshots or Screencast
Checklist
./gradlew spotlessApplyto automatically apply formatting/linting)modules/services/localization/src/main/res/values/strings.xml