-
Notifications
You must be signed in to change notification settings - Fork 319
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
TransactionPoster
: don't finish transactions for non-subscriptions if they're not processed
#2841
TransactionPoster
: don't finish transactions for non-subscriptions if they're not processed
#2841
Conversation
|
||
func containsNonSubscription(_ transation: StoreTransactionType) -> Bool { | ||
return self.nonSubscriptions.contains { | ||
$0.transactionIdentifier == transation.transactionIdentifier |
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.
@tonycosentini this is ready. Just gotta change to use the real store transaction ID not the RC ID.
Also I wonder if we should restrict this by sandbox and store too /cc @aboedo
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.
Does non subscription here mean both a consumable and a non-consumable? 🤔
Can the answer to this be added as a comment to this function?
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.
@NachoSoto is your comment here still true? Or is this ready to go? I think the khepri PR has been merged, not sure whether it's been deployed
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.
Also...
We might wanna do it for non-renewing subscriptions as well, since they have the same characteristics as consumables in that they disappear from the receipt forever.
And lastly, non-consumables don't actually need this, do they get the same treatment?
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.
TODO: we discovered that they're included, so test those too:
- Integration test
- Sandbox test.
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.
I updated the PR, logs, and code to make this more clear. I was mixing consumables with non-subscriptions everywhere.
We might wanna do it for non-renewing subscriptions as well, since they have the same characteristics as consumables in that they disappear from the receipt forever.
And lastly, non-consumables don't actually need this, do they get the same treatment?
See TransactionPoster.shouldFinish(transaction:for:customerInfo:)
. That new logic is based on StoreProduct.productCategory
(subscription / non-subscriptions).
We can't use ProductType
because we can't determine that for SK1
products (see SK1StoreProduct.productType
).
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.
Just a note that we could in theory distinguish between non-renewing and auto-renewing subs by mixing in the subs vs non subs distinction + expiration date != nil, but it's a non-trivial change that feels a bit more risky, and it isn't worth the effort.
Tests/BackendIntegrationTests/BaseStoreKitIntegrationTests.swift
Outdated
Show resolved
Hide resolved
Waiting on @tonycosentini to change transaction identifiers for StoreKit tests so we can verify this in integration tests. |
1def557
to
1e0ad6e
Compare
70ee846
to
b6c08ab
Compare
This should be ready. |
b6c08ab
to
00215b7
Compare
Codecov Report
@@ Coverage Diff @@
## main #2841 +/- ##
==========================================
+ Coverage 86.74% 86.79% +0.04%
==========================================
Files 219 220 +1
Lines 15650 15701 +51
==========================================
+ Hits 13576 13627 +51
Misses 2074 2074
|
00215b7
to
556d11e
Compare
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.
This makes sense to me! I think I really have questions about if and how consumables and non-consumables are being treated here 🤷♂️ The title of the PR mentions consumables but the code refers to non-subscriptions.
|
||
func containsNonSubscription(_ transation: StoreTransactionType) -> Bool { | ||
return self.nonSubscriptions.contains { | ||
$0.transactionIdentifier == transation.transactionIdentifier |
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.
Does non subscription here mean both a consumable and a non-consumable? 🤔
Can the answer to this be added as a comment to this function?
case .nonSubscription: | ||
// Only finish consumables if the server actually processed it. | ||
let shouldFinish = ( | ||
!transaction.hasKnownTransactionIdentifier || | ||
customerInfo.nonSubscriptions.contains { | ||
$0.storeTransactionIdentifier == transaction.transactionIdentifier | ||
} | ||
) |
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.
My head is still getting stuck here if nonSubscription
means consumable or non-consumable and if they should be treated the same 🤷♂️
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.
yeah... I think ideal behavior is:
- auto-renewing subscriptions and non-consumables: business as usual
- consumables and non-renewing subscriptions: finish only if part of response
Current is:
- auto-renewing subscriptions and non-renewing subscriptions: business as usual
- consumables and non-consumables: finish only if part of the response
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.
But we should make sure the backend behaves in the same way
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.
Answer to this (will test to make sure), non_subscriptions
include:
- Consumables
- Non-consumables
- Non-renewing subscriptions
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.
Updating on this comment for folks who haven't been following as closely - I believe we do now have integration tests with non-consumables and non-subscriptions, and have used them to confirm that the backend indeed sends them as the same thing, and they're safe to treat the same way.
@objc public let transactionIdentifier: String | ||
|
||
/// The unique identifier for the transaction created by the store. | ||
@objc public let storeTransactionIdentifier: String |
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.
Should we add this to the PR description as well?
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.
I extracted this to #3009 so we can make that a feat
ure and keep this as a fix
.
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.
I'm a bit worried about the storeTransactionIdentifier
vs transactionIdentifier
nomenclature and their differences between subscriptions and non-subscriptions... Other than that, I think this is good
556d11e
to
008002b
Compare
b744267
to
d867701
Compare
@joshdholtz I updated the log, PR description, and code to make that more clear. |
This will be used for #2841, but it can be useful for users as well.
d867701
to
49ed141
Compare
This is ready now. |
…if they're not processed
49ed141
to
3940482
Compare
This test was added in #2841, but iOS 12 can't detect offline `CustomerInfo`s because those aren't available, so this test isn't relevant there. Fixes https://app.circleci.com/pipelines/github/RevenueCat/purchases-ios/14193/workflows/a3836667-878c-4bdd-939a-e809e9f0ac5a/jobs/107291/tests
**This is an automatic release.** ### Bugfixes * `PurchasesOrchestrator`: fixed callback not invoked regression during downgrades (#3028) via NachoSoto (@NachoSoto) * `TransactionPoster`: don't finish transactions for non-subscriptions if they're not processed (#2841) via NachoSoto (@NachoSoto) ### Performance Improvements * `StoreKit 2`: only listen to `StoreKit.Transaction.updates` when SK2 is enabled (#3032) via NachoSoto (@NachoSoto) * `CustomerInfoManager`: post transactions in parallel to POST receipts only once (#2954) via NachoSoto (@NachoSoto) ### Other Changes * `PostedTransactionCache`: remove implementation (#3030) via NachoSoto (@NachoSoto) * `Integration Tests`: improved `testCanPurchaseMultipleSubscriptions` (#3025) via NachoSoto (@NachoSoto) * `GitHub`: improved `ISSUE_TEMPLATE` (#3022) via NachoSoto (@NachoSoto) * `TransactionPoster`: added transaction ID and Date to log (#3026) via NachoSoto (@NachoSoto) * `TransactionPoster`: fix iOS 12 test (#3018) via NachoSoto (@NachoSoto) * `SystemInfo`: added `ClockType` (#3014) via NachoSoto (@NachoSoto) * `Integration Tests`: begin tests with `UIApplication.willEnterForegroundNotification` to simulate a real app (#3015) via NachoSoto (@NachoSoto) * `Integration Tests`: add tests to verify `CustomerInfo`+`Offerings` request de-dupping (#3013) via NachoSoto (@NachoSoto) * `SwiftLint`: disable `unneeded_synthesized_initializer` (#3010) via NachoSoto (@NachoSoto) * Added `internal` `NonSubscriptionTransaction.storeTransactionIdentifier` (#3009) via NachoSoto (@NachoSoto) * `Integration Tests`: added tests for non-renewing and non-consumable packages (#3008) via NachoSoto (@NachoSoto) * Expanded `EnsureNonEmptyArrayDecodable` to `EnsureNonEmptyCollectionDecodable` (#3002) via NachoSoto (@NachoSoto)
…if they're not processed (#2841)
**This is an automatic release.** ### Bugfixes * `PurchasesOrchestrator`: fixed callback not invoked regression during downgrades (#3028) via NachoSoto (@NachoSoto) * `TransactionPoster`: don't finish transactions for non-subscriptions if they're not processed (#2841) via NachoSoto (@NachoSoto) ### Performance Improvements * `StoreKit 2`: only listen to `StoreKit.Transaction.updates` when SK2 is enabled (#3032) via NachoSoto (@NachoSoto) * `CustomerInfoManager`: post transactions in parallel to POST receipts only once (#2954) via NachoSoto (@NachoSoto) ### Other Changes * `PostedTransactionCache`: remove implementation (#3030) via NachoSoto (@NachoSoto) * `Integration Tests`: improved `testCanPurchaseMultipleSubscriptions` (#3025) via NachoSoto (@NachoSoto) * `GitHub`: improved `ISSUE_TEMPLATE` (#3022) via NachoSoto (@NachoSoto) * `TransactionPoster`: added transaction ID and Date to log (#3026) via NachoSoto (@NachoSoto) * `TransactionPoster`: fix iOS 12 test (#3018) via NachoSoto (@NachoSoto) * `SystemInfo`: added `ClockType` (#3014) via NachoSoto (@NachoSoto) * `Integration Tests`: begin tests with `UIApplication.willEnterForegroundNotification` to simulate a real app (#3015) via NachoSoto (@NachoSoto) * `Integration Tests`: add tests to verify `CustomerInfo`+`Offerings` request de-dupping (#3013) via NachoSoto (@NachoSoto) * `SwiftLint`: disable `unneeded_synthesized_initializer` (#3010) via NachoSoto (@NachoSoto) * Added `internal` `NonSubscriptionTransaction.storeTransactionIdentifier` (#3009) via NachoSoto (@NachoSoto) * `Integration Tests`: added tests for non-renewing and non-consumable packages (#3008) via NachoSoto (@NachoSoto) * Expanded `EnsureNonEmptyArrayDecodable` to `EnsureNonEmptyCollectionDecodable` (#3002) via NachoSoto (@NachoSoto)
This ensures that if the server returns a 200, but didn't actually process the transaction, we don't lose it forever.
When this happens, a warning will be logged:
Dependencies:
Integration Tests
: added tests for non-renewing and non-consumable packages #3008internal
NonSubscriptionTransaction.storeTransactionIdentifier
#3009