Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package com.futo.futopay
import android.util.Log
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import com.google.gson.JsonObject
import com.google.gson.JsonParser
import com.stripe.android.PaymentConfiguration
import com.stripe.android.paymentsheet.PaymentSheet
import com.stripe.android.paymentsheet.PaymentSheetResult
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.BufferedReader
import java.io.InputStreamReader
import java.net.HttpURLConnection
import java.net.URL
class PaymentManager {
private val _fragment: Fragment;
private val _overlayContainer: ViewGroup;
private val _sheet: PaymentSheet;
private val _paymentState: PaymentState;
constructor(paymentState: PaymentState, fragment: Fragment, overlayContainer: ViewGroup, onCompleted: (success: Boolean, exception: Throwable?)->Unit) {
_fragment = fragment;
_paymentState = paymentState;
_overlayContainer = overlayContainer;
_sheet = PaymentSheet(_fragment) { paymentSheetResult ->
when(paymentSheetResult) {
is PaymentSheetResult.Canceled -> {
}
is PaymentSheetResult.Failed -> {
onCompleted(false, paymentSheetResult.error)
}
is PaymentSheetResult.Completed -> {
onCompleted(true, null);
}
}
};
}
fun startPayment(paymentState: PaymentState, scope: CoroutineScope, productId: String) {
scope.launch(Dispatchers.IO){
try{
val availableCurrencies = _paymentState.getAvailableCurrencies(productId);
val country = getCountryFromIP()?.let { c -> PaymentConfigurations.COUNTRIES.find { it.id.equals(c, ignoreCase = true) } };
withContext(Dispatchers.Main) {
SlideUpPayment.startPayment(paymentState, _overlayContainer, productId, country, availableCurrencies) { method, request ->
when(method) {
"stripe" -> startPaymentStripe(productId, request.currency, request.mail, request.country, request.zipcode);
}
};
}
}
catch(ex: Throwable) {
Log.e(TAG, "startPayment failed", ex);
scope.launch(Dispatchers.Main){
UIDialogs.showGeneralErrorDialog(_fragment.requireContext(), "Failed to get required payment data", ex);
}
}
}
}
private fun startPaymentStripe(productId: String, currency: String, email: String, country: String? = null, zipcode: String? = null) {
_fragment.lifecycleScope.launch(Dispatchers.IO) {
try {
Log.i("BuyFragment", "Starting payment");
val paymentIntentResult = _paymentState.getPaymentIntent(productId, currency, email, country, zipcode);
val customerConfig = if(paymentIntentResult.customer != null && paymentIntentResult.ephemeralKey != null)
PaymentSheet.CustomerConfiguration(paymentIntentResult.customer, paymentIntentResult.ephemeralKey);
else null;
PaymentConfiguration.init(_fragment.requireContext(), paymentIntentResult.publishableKey);
withContext(Dispatchers.Main) {
_sheet.presentWithPaymentIntent(
paymentIntentResult.paymentIntent, PaymentSheet.Configuration(
merchantDisplayName = "FUTO",
customer = customerConfig,
allowsDelayedPaymentMethods = true,
defaultBillingDetails = PaymentSheet.BillingDetails(PaymentSheet.Address(country = country, postalCode = zipcode), email),
billingDetailsCollectionConfiguration = PaymentSheet.BillingDetailsCollectionConfiguration(
email = PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Always
)
)
);
}
}
catch(ex: Throwable) {
Log.e(TAG, "Payment failed: ${ex.message}", ex);
withContext(Dispatchers.Main) {
UIDialogs.showGeneralErrorDialog(_fragment.requireContext(), "Payment failed\nIf you are charged you should always receive the key in your mail.", ex);
}
}
}
}
//TODO: Determine a good provider
private fun getCountryFromIP(): String? {
val urlString = "https://freeipapi.com/api/json"
val url = URL(urlString)
val connection = url.openConnection() as HttpURLConnection
connection.requestMethod = "GET"
val reader = BufferedReader(InputStreamReader(connection.inputStream))
val response = StringBuilder()
var line: String?
while (reader.readLine().also { line = it } != null) {
response.append(line)
}
reader.close()
val json = response.toString();
val ipInfoObj = JsonParser.parseString(json) as JsonObject;
if(ipInfoObj.has("countryCode"))
return ipInfoObj.get("countryCode").asString;
return null;
}
data class PaymentRequest(
val productId: String,
val currency: String,
val mail: String,
val country: String? = null,
val zipcode: String? = null
);
companion object {
private const val TAG = "PaymentManager"
}
}