Skip to content

Support DEFERRED mode#985

Merged
MarkVillacampa merged 23 commits into
mainfrom
support-deferred
May 24, 2023
Merged

Support DEFERRED mode#985
MarkVillacampa merged 23 commits into
mainfrom
support-deferred

Conversation

@swehner

@swehner swehner commented Apr 26, 2023

Copy link
Copy Markdown
Contributor

Support DEFERRED Proration mode.
One problem is that the returned purchase is for the old product, not the new one, so all the callback need to use the replaced productId.

Checklist

  • If applicable, unit tests
  • If applicable, create follow-up issues for purchases-ios and hybrids

Description

Use old productId in callbacks for when proration mode is deferred.

Base automatically changed from add_proration_modes to main April 26, 2023 16:59
@swehner swehner added the pr:feat A new feature label Apr 26, 2023

@dalshamaa dalshamaa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to my non-expert eye!

Comment thread feature/google/src/main/java/com/revenuecat/purchases/google/BillingWrapper.kt Outdated
Comment thread public/src/main/java/com/revenuecat/purchases/models/GoogleProrationMode.kt Outdated
Comment thread purchases/src/test/java/com/revenuecat/purchases/PurchasesTest.kt Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this true? Wouldn't the onPurchasesUpdated callback always get called with the old transaction, even if we're using the deprecated flow?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For deferred purchases the purchases list will be empty. For regular purchases or other upgrades, the purchases will contain the new purchase

Comment thread feature/google/src/main/java/com/revenuecat/purchases/google/BillingWrapper.kt Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For deferred purchases the purchases list will be empty. For regular purchases or other upgrades, the purchases will contain the new purchase

Comment thread purchases/src/main/kotlin/com/revenuecat/purchases/Purchases.kt Outdated
@vegaro

vegaro commented May 4, 2023

Copy link
Copy Markdown
Member

Actually tests are failing 😄

@MarkVillacampa

MarkVillacampa commented May 5, 2023

Copy link
Copy Markdown
Member

I was getting suspicious by the behaviour of the DEFERRED purchase listener so I dug a bit deeper.

Looks like the behavior for PurchasesUpdatedListener with DEFERRED purchases changed with Billing Library 5.0

According to Google's documentation as of May 23, 2022:

For the deferred replacement mode, your app receives a call to your PurchasesUpdatedListener with an empty list of purchases and a status of whether the upgrade or downgrade was successful.

Which changed to this sometime before July 5, 2022:

For the deferred replacement mode, your app receives a call to your PurchasesUpdatedListener with the purchase of the original subscription plan and a status of whether the upgrade or downgrade was successful.

I could not find an explicit mention of this in the BL5 release notes, but the docs change coincides more or less with the official release of Billing Library 5.0 on May 11, 2022

I'm going to review the places where we may be making the old assumption and make changes accordingly.

@MarkVillacampa MarkVillacampa May 6, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Entirely removed the special handling for the case where purchases are empty:

  • It was only being handled when using the deprecated purchase methods.
  • In the new purchase method callback, StoreTransaction is not nullable.
  • Since Billing Library 5, the transactions list will contain the transaction for the old product. See comment.

We could make the new purchase method callback have a nullable transaction parameter, and handle the case where purchases.isEmpty() for both old and new purchase methods. But supposedly that should not be happening in BL5.

Thoughts?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm in the BillingWrapper class we are still forwarding an empty list of purchases, even though it shouldn't happen in BC5. If that unexpected situation happened, we wouldn't call the callbacks after removing this if I'm not wrong, so it would basically get stuck.

I think we should call the error callback when this happens, at least until we are certain that this won't happen, and at that point, we should remove that code from BillingWrapper

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We had 4 separate but very similar tests for DEFERRED mode, which I'm not entirely sure were even working properly (e.g. ProrationMode.DEFERRED was not even passed).

I simplified them into two tests, each using the old and the new purchase methods respectively.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the same comment in both pieces of code where we do special handling for DEFERRED mode product id. Open to suggestions.

@tonidero tonidero left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a comment but looking good!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could add a log if this is an unexpected situation now?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After more carefully reading the code, I realized we were already handling this case in the error handling code at the bottom of the method. Simply removing the special case handling means we'll call the error handler as expected.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm in the BillingWrapper class we are still forwarding an empty list of purchases, even though it shouldn't happen in BC5. If that unexpected situation happened, we wouldn't call the callbacks after removing this if I'm not wrong, so it would basically get stuck.

I think we should call the error callback when this happens, at least until we are certain that this won't happen, and at that point, we should remove that code from BillingWrapper

@Test
fun `purchasesUpdatedCalls are forwarded with empty list if result is ok but with a null purchase`() {
val slot = slot<List<StoreTransaction>>()
fun `purchasesUpdatedCalls call the error callback if result is ok but with a null purchase`() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated test to reflect the new expected behavior.

@tonidero tonidero left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Just left a comment to try to improve the error message in the case we receive a null/empty list of purchases.

Comment thread feature/google/src/main/java/com/revenuecat/purchases/google/BillingWrapper.kt Outdated
@codecov

codecov Bot commented May 23, 2023

Copy link
Copy Markdown

Codecov Report

Merging #985 (40e797c) into main (78cd322) will increase coverage by 0.06%.
The diff coverage is 100.00%.

@@            Coverage Diff             @@
##             main     #985      +/-   ##
==========================================
+ Coverage   85.34%   85.41%   +0.06%     
==========================================
  Files         168      168              
  Lines        5984     5977       -7     
  Branches      835      832       -3     
==========================================
- Hits         5107     5105       -2     
+ Misses        546      544       -2     
+ Partials      331      328       -3     
Impacted Files Coverage Δ
...om/revenuecat/purchases/strings/PurchaseStrings.kt 0.00% <ø> (ø)
.../com/revenuecat/purchases/google/BillingWrapper.kt 80.74% <100.00%> (+0.78%) ⬆️
...revenuecat/purchases/models/GoogleProrationMode.kt 71.42% <100.00%> (+9.89%) ⬆️
.../main/kotlin/com/revenuecat/purchases/Purchases.kt 82.89% <100.00%> (-0.10%) ⬇️

... and 2 files with indirect coverage changes

@MarkVillacampa MarkVillacampa merged commit 7cb1fc3 into main May 24, 2023
@MarkVillacampa MarkVillacampa deleted the support-deferred branch May 24, 2023 17:13
This was referenced May 24, 2023
tonidero added a commit that referenced this pull request May 25, 2023
**This is an automatic release.**

### New Features
* Support DEFERRED mode (#985) via swehner (@swehner)
* Add completion callback to syncPurchases API (#1002) via Toni Rico
(@tonidero)
### Bugfixes
* Workaround bug in android 4 for JSON objects with List<String> (#942)
via Andy Boedo (@aboedo)
### Dependency Updates
* Bump fastlane-plugin-revenuecat_internal from `fe45299` to `13773d2`
(#1015) via dependabot[bot] (@dependabot[bot])
### Other Changes
* Bump dokka to 1.8.10 to support Gradle 8 (#1009) via Toni Rico
(@tonidero)
* Disable offline entitlements temporarily (#1023) via Toni Rico
(@tonidero)
* Fix integration tests in CI (#1019) via Toni Rico (@tonidero)
* Add offline entitlements integration tests (#1006) via Toni Rico
(@tonidero)
* Disable offline entitlements in observer mode (#1014) via Toni Rico
(@tonidero)
* Extracts setup and teardown to BasePurchasesTest (#1011) via Cesar de
la Vega (@vegaro)
* Support forcing server errors for tests (#1008) via Toni Rico
(@tonidero)

---------

Co-authored-by: revenuecat-ops <ops@revenuecat.com>
Co-authored-by: Toni Rico <antonio.rico.diez@revenuecat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:feat A new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants