Add non-subscriptions support to offline customer info#958
Conversation
|
Oops tests are not passing |
| val subscriptions = JSONObject() | ||
|
|
||
| purchasedProducts.filter { it.storeTransaction.type == ProductType.SUBS }.forEach { product -> | ||
| purchasedProducts.forEach { product -> |
There was a problem hiding this comment.
Hmm I'm not sure I understand this change. So this will add inapps to the subscriptions section of the response. Is that correct? This is independent of the entitlements section of the response.
There was a problem hiding this comment.
As mentioned by @aboedo here #885 (comment), the load shedder sends the non_subscriptions in the subscriptions array. For example, a consumable product would be sent like this by the load shedder:
{
"request_date":"2023-03-24T19:43:25Z",
"request_date_ms":1679687005900,
"subscriber":{
"entitlements":{
"another_pro_1":{
"expires_date":"2023-03-25T19:43:25Z",
"grace_period_expires_date":null,
"product_identifier":"consumable",
"purchase_date":"2023-03-24T19:43:25Z"
}
},
"first_seen":"2023-03-24T19:43:25Z",
"last_seen":"2023-03-24T19:43:25Z",
"management_url":"https:\/\/play.google.com\/store\/account\/subscriptions",
"non_subscriptions":{
},
"original_app_user_id":"$RCAnonymousID:e142926d24dc49c1989e575448bc54db",
"original_application_version":"1",
"original_purchase_date":"2023-03-24T19:43:25Z",
"other_purchases":{
"consumable":{
"purchase_date":"2023-03-24T19:43:25Z"
}
},
"subscriptions":{
"consumable":{
"auto_resume_date":null,
"billing_issues_detected_at":null,
"expires_date":"2023-03-25T19:43:25Z",
"grace_period_expires_date":null,
"is_sandbox":false,
"original_purchase_date":"2023-03-24T19:43:25Z",
"ownership_type":"PURCHASED",
"period_type":"normal",
"purchase_date":"2023-03-24T19:43:25Z",
"refunded_at":null,
"store":"play_store",
"unsubscribe_detected_at":null
}
}
}
}
instead of being sent in the non_subscriptions:
"non_subscriptions": {
"consumable": [
{
"id": "72c26cc69c",
"is_sandbox": false,
"original_purchase_date": "12023-03-24T19:43:25Z",
"purchase_date": "2023-03-24T19:43:25Z",
"store": "play_store"
}
],
...
The problem we have in the SDK is that we don't know what to set as id.
Thinking about it a bit more, I don't think the id is critical information in the SDK. I consider more critical to show it as a non_subscription instead. So maybe we should set the non_subscriptions correctly with maybe an empty or a random id?
What do you think? I believe the load shedder sets these as subscriptions because it can't determine the type of product, but we can.
There was a problem hiding this comment.
Yeah, to me, adding this information to the subscriptions section when we can figure out that it's not, is not our best option. I understand the load shedder does this since it doesn't have a way to differentiate between types, but I think we should separate them for offline entitlements since that info is available.
I don't think the id is critical information in the SDK
I agree, I would say it's not a critical piece of information for the clients (let us know if we're wrong @aboedo). So I think having an empty id might be the best option? Also, we might want to document this behavior, if we end up going this route...
There was a problem hiding this comment.
Yeah, the id is the biggest blocker here... As for how critical it is: how would you tell apart 2 consumable purchases without it? Genuine question.
Like, I go in and buy 1 pack of 50 coins, and then 2 days later I go buy another one. How do you distinguish them? Just 2 entries? How do I know which one I've already granted to the user?
There was a problem hiding this comment.
Note that ideally this will only be enabled for a very short time. So I don't think it should be a problem if they buy multiple consumables in the span of a few days. If the user buys multiple of the same consumable while offline entitlements is enabled it could be a problem indeed... And I'm also concerned about giving an arbitrary or empty id, since devs might use it on their system to avoid double-granting, but if we change it later, it could lead to double-granting...
Honestly, I'm just thinking about not supporting consumables while offline entitlements is on... We can still grant the entitlements, but feels like the non-subscriptions section of the customer info could remain empty. As for making it part of the subscriptions section, I don't think that makes sense... What do you think @aboedo @vegaro ?
There was a problem hiding this comment.
I think the overall perfect solution is to design a system where the SDK can generate an ID when needed, and then pass that to the backend. It's not trivial because we need to figure out how to handle collisions, though.
As for whether to treat one-times as subscriptions temporarily vs returning an error... I think an argument can be made for either.
What we can't do is return a success and not grant anything. So if we didn't have this as a subscription, we'd have to return an error (assuming we don't have unique IDs yet)
But... once we return an error, we need to return errors for all transactions going forward until the server is back up, right? Otherwise, we have no way to guarantee that we return all the things a user has paid for.
And there we start getting into tricky territory. So for now I'd vote to just show something as a subscription temporarily, like the load shedder does, and start thinking about a system for unique IDs
There was a problem hiding this comment.
as for "this will be enabled for a very short time", well... ideally. But realistically, a user could fake the 5xxs, so we need a system that can run sustainably.
There was a problem hiding this comment.
Just wanted to add that both queryAllPurchases and queryPurchases will only return the latest purchase for a particular consumable. So there will never be more than one purchase for a non_subscription right now, until we start merging with a cached customer info.
There was a problem hiding this comment.
Right, considering we won't have the exploit we could have in iOS and that it's not something new since it's what the load shedder does, I think we can go with this for now. We can revisit the logic later, doesn't need to be perfect for V1 👍
| val subscriptions = JSONObject() | ||
|
|
||
| purchasedProducts.filter { it.storeTransaction.type == ProductType.SUBS }.forEach { product -> | ||
| purchasedProducts.forEach { product -> |
There was a problem hiding this comment.
Right, considering we won't have the exploit we could have in iOS and that it's not something new since it's what the load shedder does, I think we can go with this for now. We can revisit the logic later, doesn't need to be perfect for V1 👍
**This is an automatic release.** ### New Features * CAT-859 Expose whether or not a SubscriptionOption is Prepaid in the SDK (#1005) via Deema AlShamaa (@dalshamaa) ### Bugfixes * [CF-1324] Fix personalizedPrice defaulting to false (#952) via beylmk (@beylmk) ### Performance Improvements * Store and return ETag last refresh time header (#978) via Toni Rico (@tonidero) ### Dependency Updates * Bump fastlane-plugin-revenuecat_internal from `3b03efa` to `fe45299` (#991) via dependabot[bot] (@dependabot[bot]) * Bump danger from 9.2.0 to 9.3.0 (#981) via dependabot[bot] (@dependabot[bot]) * Bump fastlane-plugin-revenuecat_internal from `8482a43` to `3b03efa` (#974) via dependabot[bot] (@dependabot[bot]) * Bump fastlane from 2.212.1 to 2.212.2 (#973) via dependabot[bot] (@dependabot[bot]) * Bump fastlane-plugin-revenuecat_internal from `9255366` to `8482a43` (#961) via dependabot[bot] (@dependabot[bot]) ### Other Changes * Add proration modes to post to backend (#977) via swehner (@swehner) * Added ENTITLEMENTS_COMPUTED_ON_DEVICE (#939) via Cesar de la Vega (@vegaro) * Fix flaky test in OfflineCustomerInfoCalculatorTest (#997) via Cesar de la Vega (@vegaro) * Fix `OfflineCustomerInfoCalculatorTest` `Unresolved reference: ProducType` (#995) via Cesar de la Vega (@vegaro) * Add support for product_plan_identifier for offline customer info (#959) via Cesar de la Vega (@vegaro) * Add non-subscriptions support to offline customer info (#958) via Cesar de la Vega (@vegaro) * Query only active purchases when generating offline entitlements customer info (#1003) via Toni Rico (@tonidero) * Fix `PurchasesIntegrationTest` building issue (#996 into main) (#998) via Cesar de la Vega (@vegaro) * Fail offline entitlements computation if product entitlement mapping not available (#999) via Toni Rico (@tonidero) * Fix build_magic_weather lane (#993) via Cesar de la Vega (@vegaro) * Add backend integration tests and test product entitlement mapping endpoint (#988) via Toni Rico (@tonidero) * Fix purchases integration tests (#980) via Toni Rico (@tonidero) * Disable offline entitlements if active inapp purchases exist (#983) via Toni Rico (@tonidero) * Clear cached customer info upon entering offline entitlements mode (#989) via Toni Rico (@tonidero) * Update product entitlement mapping request to new format (#976) via Toni Rico (@tonidero) * Support enabling/disabling offline entitlements (#964) via Toni Rico (@tonidero) * Add back integration tests automation (#972) via Toni Rico (@tonidero) * Upgrade to AGP 8.0 (#975) via Toni Rico (@tonidero) * Extract post receipt logic to PostReceiptHelper (#967) via Toni Rico (@tonidero) * Add isServerDown to error callback for postReceipt and getCustomerInfo requests (#963) via Toni Rico (@tonidero) * Add back integration test flavors (#962) via Toni Rico (@tonidero) * Fix storing test results (#966) via Cesar de la Vega (@vegaro) * Extract detekt job from test job (#965) via Cesar de la Vega (@vegaro) [CF-1324]: https://revenuecats.atlassian.net/browse/CF-1324?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ --------- Co-authored-by: revenuecat-ops <ops@revenuecat.com> Co-authored-by: Toni Rico <antonio.rico.diez@revenuecat.com>
Since we don't have the RevenueCat ID and we are doing this mainly for entitlement granting purposes, I mimicked what the backend does, which is add the non-subscriptions to the subscriptions array.