Skip to content
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

Venmo Result Objects Refactor #828

Merged
merged 8 commits into from
Nov 27, 2023
Merged

Venmo Result Objects Refactor #828

merged 8 commits into from
Nov 27, 2023

Conversation

sarahkoop
Copy link
Contributor

Summary of changes

  • Refactor Venmo results into 3 result object classes and updated callbacks to return single non-null result object

VenmoClient#isReadyToPay -> VenmoPaymentReadinessResult
VenmoClient#createPaymentAuthRequest -> VenmoPaymentAuthRequest
VenmoClient#tokenize -> VenmoResult

The naming schemes with the second two result objects will be used across modules so please weigh in if we want to make changes to those!

Checklist

  • Added a changelog entry

Authors

@sarahkoop sarahkoop requested a review from a team as a code owner November 13, 2023 20:55
handleError(authError);
return;
venmoClient.createPaymentAuthRequest(requireActivity(), venmoRequest, (paymentAuthRequest) -> {
if (paymentAuthRequest instanceof VenmoPaymentAuthRequest.Failure) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do we still think VenmoPaymentAuthRequest is the best naming or is it too wordy for the Java integration?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it's fine unless you had ideas on another name, though we probably would want to update everything not just Venmo if so.

* Callback for receiving result of
* {@link VenmoClient#tokenize(VenmoPaymentAuthResult, VenmoTokenizeCallback)}.
*/
interface VenmoInternalCallback {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Internal and external methods shared the same callback for delivering (nonce, exception) results - I opted to only refactor the public facing callbacks for now, so kept this one and renamed it to internal. Future code cleanup will be to migrate all internal code to use the single result object pattern too.

*/
void onResult(boolean isReadyToPay, @Nullable Exception error);
void onVenmoReadinessResult(@NonNull VenmoReadinessResult venmoReadinessResult);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This PR changes all public callbacks to follow the result method naming pattern of on<ObjectBeingReturned>Result. It can provide some code clarity if merchants are creating multiple callbacks (rather than all having the same onResult method), but it also feels pretty verbose. What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah it feels a bit verbose but imo not too bad. We do have SEPADirectDebit all over so not sure anything can top that with verbosity 🙃

Copy link
Contributor

Choose a reason for hiding this comment

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

In most cases I assume it'll be reduced to a lambda (venmoReadinessResult) -> {}. At the same time, it does offer flexibility to merchants who aren't using lambdas.

/**
* There was an [error] creating the request
*/
class Failure(val error: Exception) : VenmoPaymentAuthRequest()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure if Failure feels right for returning a Request object - it might give the impression that the request itself failed, but in this case it's that the creating of the request failed. Is this naming pattern clear or is there a better way?

/**
* An [error] occurred when determining if the user is ready to pay with Venmo.
*/
class Failure(val error: Exception) : VenmoReadinessResult()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do we prefer three result options here (explicitly ready, explicitly not ready, or error), or would it be better to combine not ready and failure? The failure is only if there's an error fetching the config so we can't determine readiness. In that case it would be ReadyToPay() or NotReadyToPay(error?) with an optional error.

Merchants likely will handle not ready and failure in the same way. But, they do have the option if a user is not ready to pay, to call showVenmoInCGooglePayStore. They might not want to call that on the failure case though.

Copy link
Contributor

Choose a reason for hiding this comment

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

🤔 do we think merchants would call showVenmoInGooglePayStore with the result or when instantiating the GooglePayClient if they have a failure here? If it's with the GooglePayClient I would expect we could handle them both in 1 (ready and failure) result as they would want to parse the result in either case. That would give them time to set showVenmoInGooglePayStore in either case if desired.

But this is also assuming showVenmoInGooglePayStore is somewhere in the Google module and not here so I may be misunderstanding.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah no showVenmoInGooglePlayStore is a method on VenmoClient (confusing but it's unrelated to Google Pay - it just brings the user to the Venmo app in the app store

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh! Lol that makes way more sense. Thanks for the explanation. 🙏

/**
* Result of tokenizing a Venmo account
*/
sealed class VenmoResult {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I dropped the Payment from this result object naming - open to opinions if it should be VenmoPaymentResult instead

/**
* A request used to launch the Venmo app for continuation of the Venmo payment flow.
*/
sealed class VenmoPaymentAuthRequest {
Copy link
Contributor

@sshropshire sshropshire Nov 15, 2023

Choose a reason for hiding this comment

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

nit: There's some interesting interop cases between Kotlin and Java with sealed classes.

assertEquals(
"Cannot collect customer data when ECD is disabled. Enable this feature in the Control Panel to collect this data.",
captor.getValue().getMessage());
((VenmoPaymentAuthRequest.Failure) paymentAuthRequest).getError().getMessage());
Copy link
Contributor

Choose a reason for hiding this comment

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

Seeing now that the class interop works well in the Java unit test. I'd only heard about the interop before, never seen it in action. 👍

@sarahkoop sarahkoop merged commit fd4ee4a into v5 Nov 27, 2023
2 checks passed
@sarahkoop sarahkoop deleted the venmo_result_object branch November 27, 2023 17:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants