Skip to content

Commit 3d4b2c3

Browse files
authored
Subscriptions: fetch billingPeriod property from BE (#6032)
Task/Issue URL: https://app.asana.com/1/137249556945/project/488551667048375/task/1210199014409745?focus=true ### Description Parse `billingPeriod` from ConfirmResponse request and add it to Subscription Object ### Steps to test this PR _Existing PPro user_ - [x] Make sure you are PPro subscription - [x] Install from branch - [x] Go to Settings - [x] Check all PPro items in menu are showing and work as expected - [x] Check in Subscription Settings option you see the correct subscription billing period _Purchase yearly subscription_ - [x] Make sure you are PPro eligible - [x] Fresh install from branch - [x] Go to Settings > Privacy Pro - [x] Check paywall looks as expected - [x] Purchase a yearly membership - [x] Check we parse correctly `billingPeriod` and add it to the Subscription object _Purchase yearly subscription (Optional)_ - [x] Make sure you are PPro eligible - [x] Fresh install from branch - [x] Go to Settings > Privacy Pro - [x] Check paywall looks as expected - [x] Purchase a monthly membership - [x] Check we parse correctly `billingPeriod` and add it to the Subscription object ### No UI changes
1 parent 0412b8e commit 3d4b2c3

20 files changed

+137
-79
lines changed

subscriptions/subscriptions-impl/src/main/java/com/duckduckgo/subscriptions/impl/SubscriptionsConstants.kt

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@
1616

1717
package com.duckduckgo.subscriptions.impl
1818

19-
import com.duckduckgo.subscriptions.impl.SubscriptionsConstants.MONTHLY_PLAN_ROW
20-
import com.duckduckgo.subscriptions.impl.SubscriptionsConstants.MONTHLY_PLAN_US
21-
import com.duckduckgo.subscriptions.impl.SubscriptionsConstants.YEARLY_PLAN_ROW
22-
import com.duckduckgo.subscriptions.impl.SubscriptionsConstants.YEARLY_PLAN_US
23-
2419
object SubscriptionsConstants {
2520

2621
// List of subscriptions
@@ -51,8 +46,8 @@ object SubscriptionsConstants {
5146
const val PLATFORM = "android"
5247

5348
// Recurrence
54-
const val MONTHLY = "monthly"
55-
const val YEARLY = "yearly"
49+
const val MONTHLY = "Monthly"
50+
const val YEARLY = "Yearly"
5651

5752
// URLs
5853
const val BUY_URL = "https://duckduckgo.com/subscriptions"
@@ -62,11 +57,3 @@ object SubscriptionsConstants {
6257
const val PRIVACY_PRO_ETLD = "duckduckgo.com"
6358
const val PRIVACY_PRO_PATH = "pro"
6459
}
65-
66-
internal fun String.productIdToBillingPeriod(): String? {
67-
return when (this) {
68-
MONTHLY_PLAN_US, MONTHLY_PLAN_ROW -> "monthly"
69-
YEARLY_PLAN_US, YEARLY_PLAN_ROW -> "annual"
70-
else -> null
71-
}
72-
}

subscriptions/subscriptions-impl/src/main/java/com/duckduckgo/subscriptions/impl/SubscriptionsManager.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@ class RealSubscriptionsManager @Inject constructor(
450450

451451
val subscription = Subscription(
452452
productId = confirmationResponse.subscription.productId,
453+
billingPeriod = confirmationResponse.subscription.billingPeriod,
453454
startedAt = confirmationResponse.subscription.startedAt,
454455
expiresOrRenewsAt = confirmationResponse.subscription.expiresOrRenewsAt,
455456
status = confirmationResponse.subscription.status.toStatus(),
@@ -560,6 +561,7 @@ class RealSubscriptionsManager @Inject constructor(
560561
authRepository.setSubscription(
561562
Subscription(
562563
productId = subscription.productId,
564+
billingPeriod = subscription.billingPeriod,
563565
startedAt = subscription.startedAt,
564566
expiresOrRenewsAt = subscription.expiresOrRenewsAt,
565567
status = subscription.status.toStatus(),
@@ -635,6 +637,7 @@ class RealSubscriptionsManager @Inject constructor(
635637
authRepository.setSubscription(
636638
Subscription(
637639
productId = subscription.productId,
640+
billingPeriod = subscription.billingPeriod,
638641
startedAt = subscription.startedAt,
639642
expiresOrRenewsAt = subscription.expiresOrRenewsAt,
640643
status = subscription.status.toStatus(),

subscriptions/subscriptions-impl/src/main/java/com/duckduckgo/subscriptions/impl/repository/AuthRepository.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,27 +163,30 @@ internal class RealAuthRepository constructor(
163163
override suspend fun setSubscription(subscription: Subscription?) = withContext(dispatcherProvider.io()) {
164164
with(subscriptionsDataStore) {
165165
productId = subscription?.productId
166-
platform = subscription?.platform
166+
billingPeriod = subscription?.billingPeriod
167167
startedAt = subscription?.startedAt
168168
expiresOrRenewsAt = subscription?.expiresOrRenewsAt
169169
status = subscription?.status?.statusName
170+
platform = subscription?.platform
170171
freeTrialActive = subscription?.activeOffers?.contains(ActiveOfferType.TRIAL) ?: false
171172
}
172173
}
173174

174175
override suspend fun getSubscription(): Subscription? = withContext(dispatcherProvider.io()) {
175176
val productId = subscriptionsDataStore.productId ?: return@withContext null
176-
val platform = subscriptionsDataStore.platform ?: return@withContext null
177+
val billingPeriod = subscriptionsDataStore.billingPeriod ?: return@withContext null
177178
val startedAt = subscriptionsDataStore.startedAt ?: return@withContext null
178179
val expiresOrRenewsAt = subscriptionsDataStore.expiresOrRenewsAt ?: return@withContext null
179180
val status = subscriptionsDataStore.status?.toStatus() ?: return@withContext null
181+
val platform = subscriptionsDataStore.platform ?: return@withContext null
180182
val activeOffers = if (subscriptionsDataStore.freeTrialActive) listOf(ActiveOfferType.TRIAL) else listOf()
181183
Subscription(
182184
productId = productId,
183-
platform = platform,
185+
billingPeriod = billingPeriod,
184186
startedAt = startedAt,
185187
expiresOrRenewsAt = expiresOrRenewsAt,
186188
status = status,
189+
platform = platform,
187190
activeOffers = activeOffers,
188191
)
189192
}
@@ -249,6 +252,7 @@ data class Account(
249252

250253
data class Subscription(
251254
val productId: String,
255+
val billingPeriod: String,
252256
val startedAt: Long,
253257
val expiresOrRenewsAt: Long,
254258
val status: SubscriptionStatus,

subscriptions/subscriptions-impl/src/main/java/com/duckduckgo/subscriptions/impl/rmf/RMFPProBillingPeriodMatchingAttribute.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import com.duckduckgo.remote.messaging.api.JsonMatchingAttribute
2222
import com.duckduckgo.remote.messaging.api.JsonToMatchingAttributeMapper
2323
import com.duckduckgo.remote.messaging.api.MatchingAttribute
2424
import com.duckduckgo.subscriptions.impl.SubscriptionsManager
25-
import com.duckduckgo.subscriptions.impl.productIdToBillingPeriod
2625
import com.squareup.anvil.annotations.ContributesMultibinding
2726
import dagger.SingleInstanceIn
2827
import javax.inject.Inject
@@ -41,8 +40,7 @@ class RMFPProBillingPeriodMatchingAttribute @Inject constructor(
4140
) : JsonToMatchingAttributeMapper, AttributeMatcherPlugin {
4241
override suspend fun evaluate(matchingAttribute: MatchingAttribute): Boolean? {
4342
if (matchingAttribute is PProBillingPeriodMatchingAttribute) {
44-
val productId = subscriptionsManager.getSubscription()?.productId
45-
return productId != null && matchingAttribute.value == productId.productIdToBillingPeriod()
43+
return matchingAttribute.value == subscriptionsManager.getSubscription()?.billingPeriod
4644
}
4745
return null
4846
}
@@ -65,6 +63,6 @@ internal data class PProBillingPeriodMatchingAttribute(
6563
val value: String,
6664
) : MatchingAttribute {
6765
companion object {
68-
const val KEY = "privacyProBillingPeriod"
66+
const val KEY = "pproBillingPeriod"
6967
}
7068
}

subscriptions/subscriptions-impl/src/main/java/com/duckduckgo/subscriptions/impl/services/SubscriptionsService.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ data class PortalResponse(val customerPortalUrl: String)
5959

6060
data class SubscriptionResponse(
6161
val productId: String,
62+
val billingPeriod: String,
6263
val startedAt: Long,
6364
val expiresOrRenewsAt: Long,
6465
val platform: String,

subscriptions/subscriptions-impl/src/main/java/com/duckduckgo/subscriptions/impl/store/SubscriptionsDataStore.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ interface SubscriptionsDataStore {
3636

3737
// Subscription
3838
var expiresOrRenewsAt: Long?
39+
var billingPeriod: String?
3940
var startedAt: Long?
4041
var platform: String?
4142
var status: String?
@@ -52,7 +53,7 @@ interface SubscriptionsDataStore {
5253
* THINK TWICE before using this class directly.
5354
* Usages of this class should all go through [AuthRepository]
5455
*/
55-
internal class SubscriptionsEncryptedDataStore constructor(
56+
internal class SubscriptionsEncryptedDataStore(
5657
private val sharedPreferencesProvider: SharedPreferencesProvider,
5758
) : SubscriptionsDataStore {
5859
private val encryptedPreferences: SharedPreferences? by lazy { encryptedPreferences() }
@@ -196,6 +197,14 @@ internal class SubscriptionsEncryptedDataStore constructor(
196197
}
197198
}
198199

200+
override var billingPeriod: String?
201+
get() = encryptedPreferences?.getString(KEY_BILLING_PERIOD, null)
202+
set(value) {
203+
encryptedPreferences?.edit(commit = true) {
204+
putString(KEY_BILLING_PERIOD, value)
205+
}
206+
}
207+
199208
override var subscriptionFeatures: String?
200209
get() = encryptedPreferences?.getString(KEY_SUBSCRIPTION_FEATURES, null)
201210
set(value) {
@@ -222,6 +231,7 @@ internal class SubscriptionsEncryptedDataStore constructor(
222231
const val KEY_EXTERNAL_ID = "KEY_EXTERNAL_ID"
223232
const val KEY_EXPIRES_OR_RENEWS_AT = "KEY_EXPIRES_OR_RENEWS_AT"
224233
const val KEY_STARTED_AT = "KEY_STARTED_AT"
234+
const val KEY_BILLING_PERIOD = "KEY_BILLING_PERIOD"
225235
const val KEY_ENTITLEMENTS = "KEY_ENTITLEMENTS"
226236
const val KEY_STATUS = "KEY_STATUS"
227237
const val KEY_PRODUCT_ID = "KEY_PRODUCT_ID"

subscriptions/subscriptions-impl/src/main/java/com/duckduckgo/subscriptions/impl/survey/PproSurveyParameters.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package com.duckduckgo.subscriptions.impl.survey
1919
import com.duckduckgo.common.utils.CurrentTimeProvider
2020
import com.duckduckgo.di.scopes.AppScope
2121
import com.duckduckgo.subscriptions.impl.SubscriptionsManager
22-
import com.duckduckgo.subscriptions.impl.productIdToBillingPeriod
2322
import com.duckduckgo.survey.api.SurveyParameterPlugin
2423
import com.squareup.anvil.annotations.ContributesMultibinding
2524
import java.util.concurrent.TimeUnit
@@ -41,8 +40,7 @@ class PproBillingParameterPlugin @Inject constructor(
4140
override val surveyParamKey: String = "ppro_billing"
4241

4342
override suspend fun evaluate(): String {
44-
val productId = subscriptionsManager.getSubscription()?.productId
45-
return productId?.productIdToBillingPeriod() ?: ""
43+
return subscriptionsManager.getSubscription()?.billingPeriod ?: ""
4644
}
4745
}
4846

subscriptions/subscriptions-impl/src/main/java/com/duckduckgo/subscriptions/impl/ui/SubscriptionWebViewViewModel.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,8 @@ class SubscriptionWebViewViewModel @Inject constructor(
309309
): SubscriptionOptionsJson {
310310
return SubscriptionOptionsJson(
311311
options = listOf(
312-
createOptionsJson(yearlyOffer, YEARLY),
313-
createOptionsJson(monthlyOffer, MONTHLY),
312+
createOptionsJson(yearlyOffer, YEARLY.lowercase()),
313+
createOptionsJson(monthlyOffer, MONTHLY.lowercase()),
314314
),
315315
features = monthlyOffer.features.map(::FeatureJson),
316316
)

subscriptions/subscriptions-impl/src/test/java/com/duckduckgo/subscriptions/impl/RealSubscriptionsManagerTest.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1375,6 +1375,7 @@ class RealSubscriptionsManagerTest(private val authApiV2Enabled: Boolean) {
13751375

13761376
SubscriptionResponse(
13771377
productId = MONTHLY_PLAN_US,
1378+
billingPeriod = "Monthly",
13781379
startedAt = 1234,
13791380
expiresOrRenewsAt = 1234,
13801381
platform = "android",
@@ -1457,6 +1458,7 @@ class RealSubscriptionsManagerTest(private val authApiV2Enabled: Boolean) {
14571458
whenever(subscriptionsService.subscription()).thenReturn(
14581459
SubscriptionResponse(
14591460
productId = MONTHLY_PLAN_US,
1461+
billingPeriod = "Monthly",
14601462
startedAt = 1234,
14611463
expiresOrRenewsAt = 1234,
14621464
platform = "android",
@@ -1471,6 +1473,7 @@ class RealSubscriptionsManagerTest(private val authApiV2Enabled: Boolean) {
14711473
whenever(subscriptionsService.subscription()).thenReturn(
14721474
SubscriptionResponse(
14731475
productId = MONTHLY_PLAN_US,
1476+
billingPeriod = "Monthly",
14741477
startedAt = 1234,
14751478
expiresOrRenewsAt = 1234,
14761479
platform = "android",
@@ -1532,6 +1535,7 @@ class RealSubscriptionsManagerTest(private val authApiV2Enabled: Boolean) {
15321535
authDataStore.productId = "productId"
15331536
authDataStore.entitlements = """[{"product":"Network Protection", "name":"subscriber"}]"""
15341537
authDataStore.status = status.statusName
1538+
authDataStore.billingPeriod = "Monthly"
15351539
authDataStore.startedAt = 1000L
15361540
authDataStore.expiresOrRenewsAt = 1000L
15371541
}
@@ -1675,6 +1679,7 @@ class RealSubscriptionsManagerTest(private val authApiV2Enabled: Boolean) {
16751679
),
16761680
subscription = SubscriptionResponse(
16771681
productId = "id",
1682+
billingPeriod = "Monthly",
16781683
platform = "google",
16791684
status = "Auto-Renewable",
16801685
startedAt = 1000000L,

subscriptions/subscriptions-impl/src/test/java/com/duckduckgo/subscriptions/impl/messaging/SubscriptionMessagingInterfaceTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,7 @@ class SubscriptionMessagingInterfaceTest {
749749
whenever(subscriptionsManager.getSubscription()).thenReturn(
750750
Subscription(
751751
productId = "productId",
752+
billingPeriod = "Monthly",
752753
startedAt = 10000L,
753754
expiresOrRenewsAt = 10000L,
754755
status = AUTO_RENEWABLE,

0 commit comments

Comments
 (0)