-
Notifications
You must be signed in to change notification settings - Fork 137
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
Feature/8182 iap single subcription requirement #8206
Feature/8182 iap single subcription requirement #8206
Conversation
You can test the changes on this Pull Request by downloading an installable build, or scanning this QR code: |
Generated by 🚫 dangerJS |
is IAPError.Billing.ServiceUnavailable, | ||
is IAPError.Billing.ItemNotOwned, | ||
is IAPError.Billing.UserCancelled, | ||
is IAPError.RemoteCommunication.Network -> R.string.store_creation_iap_eligibility_check_generic_error |
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.
Would it make sense to use offline_error
string for the RemoteCommunication.Network
error? To be a bit more specific?
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.
Hmm, I'm not sure about displaying any non-generic message here.
From what I've seen in the code is that IAPError.RemoteCommunication.Network
is returned when BaseRequest.GenericErrorType.TIMEOUT
is returned. But that doesn't necessarily mean the user is offline. In fact there is another type of error for that BaseRequest.GenericErrorType.NO_CONNECTION,
which is mapped to CreateOrderErrorType.API_ERROR
private fun WPComGsonRequest.WPComGsonNetworkError.toCreateOrderError() =
when (type) {
BaseRequest.GenericErrorType.TIMEOUT -> CreateOrderErrorType.TIMEOUT
BaseRequest.GenericErrorType.NO_CONNECTION,
BaseRequest.GenericErrorType.SERVER_ERROR,
BaseRequest.GenericErrorType.INVALID_SSL_CERTIFICATE,
BaseRequest.GenericErrorType.NETWORK_ERROR -> CreateOrderErrorType.API_ERROR
BaseRequest.GenericErrorType.PARSE_ERROR,
BaseRequest.GenericErrorType.NOT_FOUND,
BaseRequest.GenericErrorType.CENSORED,
BaseRequest.GenericErrorType.INVALID_RESPONSE -> CreateOrderErrorType.INVALID_RESPONSE
BaseRequest.GenericErrorType.HTTP_AUTH_ERROR,
BaseRequest.GenericErrorType.AUTHORIZATION_REQUIRED,
BaseRequest.GenericErrorType.NOT_AUTHENTICATED -> CreateOrderErrorType.AUTH_ERROR
BaseRequest.GenericErrorType.UNKNOWN -> CreateOrderErrorType.GENERIC_ERROR
null -> CreateOrderErrorType.GENERIC_ERROR
}
I wonder if ``BaseRequest.GenericErrorType.NO_CONNECTION, should be mapped instead to CreateOrderErrorType.TIMEOUT
? Wdyt?
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 judging by Volley's naming of the errors:
NoConnectionError
Error indicating that no connection could be established when performing a Volley request.
It might refer to the case when a TCP handshake could not be established. This can happen when the device is offline, some package loss, or any connection-related issue
TimeoutError
Indicates that the connection or the socket timed out.
The request was sent, but the response didn't come back during the timeout period. The reason can be exactly the same as the first error + the backend may just didn't answer on time
But that doesn't necessarily mean the user is offline.
True, but I guess the probability that something with a connection is high in these cases
I wonder if ``BaseRequest.GenericErrorType.NO_CONNECTION, should be mapped instead to CreateOrderErrorType.TIMEOUT? Wdyt?
Yeah, seems to be a bug in the implementation there. I'll create for myself a ticket to fix that
We might use less assertive message
<string name="error_generic_network">A network error occurred. Please check your connection and try again.</string>
in this case, wdyt?
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.
Thank you for this improvement! It looks and works well.
I left a comment which I think is worth thinking about. Please let me know your ideas regarding this
is WPComIsPurchasedResult.Success -> { | ||
when (result.purchaseStatus) { | ||
PurchaseStatus.PURCHASED_AND_ACKNOWLEDGED, | ||
PurchaseStatus.PURCHASED -> onUserNotEligibleForIAP( |
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 was thinking about this case. So the item is purchased but not acknowledged by our backend, which means that the WP plan is not given to a user as well. We could call purchaseWPComPlan
and it internally will call the backend and the backend should acknowledge the purchase on the GP side, but at this moment we actually not sure if this is the same site a user wanted to purchase a subscription to at the begging 🤔
On other hand, it's the user's decision and we should hope that they know what they are doing, so maybe we still should purchaseWPComPlan
in this case? I am not saying to call it here, but let a user go further, and then when the website is picked use an existing GP subscription in order to give a WP plan to the picked site
Another option would be to at least show to a user that yes we have your purchase, please contact support so they will link the GP subscription to a site that needs an upgrade
Wdyt?
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.
Hey @kidinov I'm not sure we can do what you suggest. First of all I'd like to ask under which circumstance the purchase can be placed but not acknowledged?
Regarding this:
We could call purchaseWPComPlan and it internally will call the backend and the backend should acknowledge the purchase on the GP side, but at this moment we actually not sure if this is the same site a user wanted to purchase a subscription to at the begging
We do not have a siteId
available at this point and we have no clue about the site that has the active IAP WooCommerce subscription, as this subscription is tied to Google account. Keep in mind these checks run when user clicks on "create a new store", so the user hasn't even entered a site name or anything yet.
I agree we could redirect them to support to troubleshoot the problem. I'll submit a curated message for that scenario with the appropriate CTA to create a Zendesk ticket
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.
First of all I'd like to ask under which circumstance the purchase can be placed but not acknowledged?
The IAP becomes purchased
after the user from the app makes a purchase. It gets acknowledged by the backend after we do the create_order
call. So any network issue between the mobile and the backend, or between the backend and google play will lead to the purchased
and not acknowledged state. Also, any error on the backend or the user kills the app at a specific moment will lead to the same result. So there are many places where it can go wrong.
Having said that, after some time not acknowledged purchase will get refunded, so it's not the end of the world
We do not have a siteId available at this point and we have no clue about the site that has the active IAP WooCommerce subscription, as this subscription is tied to Google account.
Yep, that's why I mentioned:
I am not saying to call it here, but let a user go further, and then when the website is picked use an existing GP subscription in order to give a WP plan to the picked site
So you could just let a user go further, and let them click the "purchase" button and then the library will do the rest of the work, but thinking about this now, it would feel weird for a user, to buy the same thing for the second time. It's not like the "try again" button, so I guess it is not something that people will do, and saying that to talk to support is probably the best approach in this case
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.
Thanks for clarifying the scenarios when purchase is done but couldn't be acknoledged.
but thinking about this now, it would feel weird for a user, to buy the same thing for the second time
I agree with that. The user would be taken through a flow that expects a new site at all times. So it would be super confusing for them to have to enter all the same information again (in some cases they wouldn't be able to do this as the domain for example would be already assigned to their previous site), and then be requested to pay again for something they had already paid. Offer a "Retry" option for this case would require an entirely different flow where we request the site address the site they have purchased an eCommerce subscription for but is not acknowledged.
Once more question on this. Do HE have an straightforward way to check if users have an active IAP eCommerce, and if they do, link the subscription to their site?
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.
Adding this for reference @kidinov
If the purchase fails to be acknowledged it won't matter if we retry to confirm the purchase as the associated purchaseToken
expires.
Full context on this discussion p1674662344895449/1673441948.587159-slack-C025A8VV728
@@ -2766,7 +2766,9 @@ | |||
<string name="store_creation_iap_eligibility_loading_title">We are getting ready for your store creation</string> | |||
<string name="store_creation_iap_eligibility_loading_subtitle">Please remain connected.</string> | |||
<string name="store_creation_iap_eligibility_check_error_title">Store Creation Unavailable </string> | |||
<string name="store_creation_iap_eligibility_check_error_description">Store creation from the mobile app is currently unavailable for your country.</string> | |||
<string name="store_creation_iap_eligibility_check_error_not_available_for_country">Store creation from the mobile app is currently unavailable for your country.</string> | |||
<string name="store_creation_iap_eligibility_check_error_existing_subscription">You have an active WooCommerce subscription linked to your Google account. Only one WooCommerce subscription per Google account is allowed.</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.
What if we will give an option for what to do next to a user, something like:
Currently you are only able to purchase one eCommerce plan from the mobile app. For additional options, please visit our website
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, makes sense. I've updated the message. However we can't provide a link to the actual store creation flow as that would not be compliant with Google Play terms.
Codecov ReportBase: 43.45% // Head: 43.50% // Increases project coverage by
Additional details and impacted files@@ Coverage Diff @@
## trunk #8206 +/- ##
============================================
+ Coverage 43.45% 43.50% +0.05%
- Complexity 3532 3535 +3
============================================
Files 712 711 -1
Lines 37933 37958 +25
Branches 5010 5018 +8
============================================
+ Hits 16482 16513 +31
+ Misses 19980 19962 -18
- Partials 1471 1483 +12
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. ☔ View full report at Codecov. |
…ment # Conflicts: # build.gradle
Hey @kidinov thank you for the review and all the great feedback. I'll summarize the latest changes applied after you last comments.
contectSuppportIAP.mp4Ready for another round of review. |
…ment # Conflicts: # build.gradle
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.
LGTM!
Before merging, maybe we should integrate this fluxc change though?
…ment # Conflicts: # WooCommerce/src/debug/kotlin/com.woocommerce.android/iapshowcase/purchase/IAPShowcaseMobilePayAPIProvider.kt # build.gradle
Closes: #8182 and #8148
Description
Adds a check before triggering store creation flow, to verify that the user doesn't have an active IAP subscription to WooCommerce.
Testing instructions
vanila debug
flavour for this, and have a Google Play account located in the US)You are welcome to provide any feedback for a better error message.
RELEASE-NOTES.txt
if necessary.