Skip to content

Commit

Permalink
add query and migrations for checkout flow (#1953)
Browse files Browse the repository at this point in the history
  • Loading branch information
mtgriego committed Feb 21, 2024
1 parent 8207db8 commit 81d14a6
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 6 deletions.
21 changes: 19 additions & 2 deletions app/src/main/graphql/checkout.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,25 @@ mutation CreateCheckout($projectId: ID!, $amount: String!, $rewardIds: [ID!], $l
}
}

mutation CreatePaymentIntent($projectId: ID!, $amountDollars: String!) {
createPaymentIntent(input: { projectId: $projectId, amount: $amountDollars } ) {
mutation CreatePaymentIntent($projectId: ID!, $amount: String!) {
createPaymentIntent(input: { projectId: $projectId, amount: $amount } ) {
clientSecret
}
}

query ValidateCheckout($checkoutId:ID!, $paymentSourceId:String!, $paymentIntentClientSecret:String!) {
checkout(id: $checkoutId) {
isValidForOnSessionCheckout(stripePaymentMethodId: $paymentSourceId, paymentIntentClientSecret: $paymentIntentClientSecret) {
valid
messages
}
}
}

mutation CompleteOnSessionCheckout($checkoutId: ID!, $paymentIntentClientSecret: String!, $paymentSourceId: String) {
completeOnSessionCheckout(input:{ checkoutId: $checkoutId, paymentIntentClientSecret: $paymentIntentClientSecret, paymentSourceId: $paymentSourceId } ) {
checkout {
id
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import com.kickstarter.models.CreatePaymentIntentInput
import com.kickstarter.models.CreatorDetails
import com.kickstarter.models.ErroredBacking
import com.kickstarter.models.Location
import com.kickstarter.models.PaymentValidationResponse
import com.kickstarter.models.Project
import com.kickstarter.models.Reward
import com.kickstarter.models.StoredCard
Expand Down Expand Up @@ -275,6 +276,22 @@ open class MockApolloClientV2 : ApolloClientTypeV2 {
override fun createPaymentIntent(createPaymentIntentInput: CreatePaymentIntentInput): io.reactivex.Observable<String> {
return io.reactivex.Observable.empty()
}

override fun validateCheckout(
checkoutId: String,
paymentIntentClientSecret: String,
paymentSourceId: String
): io.reactivex.Observable<PaymentValidationResponse> {
return io.reactivex.Observable.empty()
}

override fun completeOnSessionCheckout(
checkoutId: String,
paymentIntentClientSecret: String,
paymentSourceId: String
): io.reactivex.Observable<String> {
return io.reactivex.Observable.empty()
}
}

open class MockApolloClient : ApolloClientType {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package com.kickstarter.models

data class CreatePaymentIntentInput(val project: Project, val amountDollars: String)
data class CreatePaymentIntentInput(val project: Project, val amount: String)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.kickstarter.models

data class PaymentValidationResponse(val isValid: Boolean, val messages: List<String>)
95 changes: 92 additions & 3 deletions app/src/main/java/com/kickstarter/services/KSApolloClientV2.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.kickstarter.services

import CompleteOnSessionCheckoutMutation
import CreatePaymentIntentMutation
import ValidateCheckoutQuery
import android.util.Pair
import com.apollographql.apollo.ApolloCall
import com.apollographql.apollo.ApolloClient
Expand All @@ -16,6 +18,7 @@ import com.kickstarter.models.CreatePaymentIntentInput
import com.kickstarter.models.CreatorDetails
import com.kickstarter.models.ErroredBacking
import com.kickstarter.models.Location
import com.kickstarter.models.PaymentValidationResponse
import com.kickstarter.models.Project
import com.kickstarter.models.Reward
import com.kickstarter.models.StoredCard
Expand Down Expand Up @@ -132,6 +135,18 @@ interface ApolloClientTypeV2 {
fun createCheckout(createCheckoutData: CreateCheckoutData): Observable<CheckoutPayment>

fun createPaymentIntent(createPaymentIntentInput: CreatePaymentIntentInput): Observable<String>

fun validateCheckout(
checkoutId: String,
paymentIntentClientSecret: String,
paymentSourceId: String
): Observable<PaymentValidationResponse>

fun completeOnSessionCheckout(
checkoutId: String,
paymentIntentClientSecret: String,
paymentSourceId: String
): Observable<String>
}

private const val PAGE_SIZE = 25
Expand Down Expand Up @@ -1418,11 +1433,11 @@ class KSApolloClientV2(val service: ApolloClient) : ApolloClientTypeV2 {
checkoutObj.paymentUrl()
)
ps.onNext(checkout)
ps.onComplete()
} ?: ps.onError(Exception("CreateCheckout could not decode ID"))
}
}
}
ps.onComplete()
}
})
return@defer ps
Expand All @@ -1436,7 +1451,7 @@ class KSApolloClientV2(val service: ApolloClient) : ApolloClientTypeV2 {
this.service.mutate(
CreatePaymentIntentMutation.builder()
.projectId(encodeRelayId(createPaymentIntentInput.project))
.amountDollars(createPaymentIntentInput.amountDollars)
.amount(createPaymentIntentInput.amount)
.build()
).enqueue(object : ApolloCall.Callback<CreatePaymentIntentMutation.Data>() {
override fun onFailure(e: ApolloException) {
Expand All @@ -1447,7 +1462,81 @@ class KSApolloClientV2(val service: ApolloClient) : ApolloClientTypeV2 {
if (response.hasErrors()) {
ps.onError(Exception(response.errors?.first()?.message))
} else {
ps.onNext(response.data?.createPaymentIntent()?.clientSecret() ?: "")
response.data?.createPaymentIntent()?.clientSecret()?.let {
ps.onNext(it)
} ?: ps.onError(Exception("Client Secret was Null"))
}
ps.onComplete()
}
})
return@defer ps
}
}

override fun validateCheckout(
checkoutId: String,
paymentIntentClientSecret: String,
paymentSourceId: String
): Observable<PaymentValidationResponse> {
return Observable.defer {
val ps = PublishSubject.create<PaymentValidationResponse>()

this.service.query(
ValidateCheckoutQuery.builder()
.checkoutId(checkoutId)
.paymentIntentClientSecret(paymentIntentClientSecret)
.paymentSourceId(paymentSourceId)
.build()
).enqueue(object : ApolloCall.Callback<ValidateCheckoutQuery.Data>() {
override fun onFailure(e: ApolloException) {
ps.onError(e)
}

override fun onResponse(response: Response<ValidateCheckoutQuery.Data>) {
if (response.hasErrors()) {
ps.onError(Exception(response.errors?.first()?.message))
} else {
response.data?.let { data ->
val validation = PaymentValidationResponse(
data.checkout()?.isValidForOnSessionCheckout?.valid() ?: false,
data.checkout()?.isValidForOnSessionCheckout?.messages() ?: listOf()
)
ps.onNext(validation)
}
ps.onComplete()
}
}
})
return@defer ps
}
}

override fun completeOnSessionCheckout(
checkoutId: String,
paymentIntentClientSecret: String,
paymentSourceId: String
): Observable<String> {
return Observable.defer {
val ps = PublishSubject.create<String>()

this.service.mutate(
CompleteOnSessionCheckoutMutation.builder()
.checkoutId(checkoutId)
.paymentIntentClientSecret(paymentIntentClientSecret)
.paymentSourceId(paymentSourceId)
.build()
).enqueue(object : ApolloCall.Callback<CompleteOnSessionCheckoutMutation.Data>() {
override fun onFailure(e: ApolloException) {
ps.onError(e)
}

override fun onResponse(response: Response<CompleteOnSessionCheckoutMutation.Data>) {
if (response.hasErrors()) {
ps.onError(Exception(response.errors?.first()?.message))
} else {
response.data?.completeOnSessionCheckout()?.checkout()?.id()?.let {
ps.onNext(it)
} ?: ps.onError(Exception("Checkout ID was null"))
}
ps.onComplete()
}
Expand Down

0 comments on commit 81d14a6

Please sign in to comment.