-
Notifications
You must be signed in to change notification settings - Fork 308
/
paystack.dart
233 lines (204 loc) · 7.73 KB
/
paystack.dart
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_paystack/src/common/exceptions.dart';
import 'package:flutter_paystack/src/common/my_strings.dart';
import 'package:flutter_paystack/src/common/platform_info.dart';
import 'package:flutter_paystack/src/common/transaction.dart';
import 'package:flutter_paystack/src/common/utils.dart';
import 'package:flutter_paystack/src/model/card.dart';
import 'package:flutter_paystack/src/model/charge.dart';
import 'package:flutter_paystack/src/model/checkout_response.dart';
import 'package:flutter_paystack/src/transaction/mobile_transaction_manager.dart';
import 'package:flutter_paystack/src/widgets/checkout/checkout_widget.dart';
class PaystackPlugin {
static bool _sdkInitialized = false;
static String _publicKey;
PaystackPlugin._();
/// Initialize the Paystack object. It should be called as early as possible
/// (preferably in initState() of the Widget.
///
/// [publicKey] - your paystack public key. This is mandatory
///
/// use [checkout] and you want this plugin to initialize the transaction for you.
/// Please check [checkout] for more information
///
static Future<PaystackPlugin> initialize({@required String publicKey}) async {
assert(() {
if (publicKey == null || publicKey.isEmpty) {
throw new PaystackException('publicKey cannot be null or empty');
}
return true;
}());
// do all the init work here
var completer = Completer<PaystackPlugin>();
//check if sdk is actually initialized
if (sdkInitialized) {
completer.complete(PaystackPlugin._());
} else {
_publicKey = publicKey;
// We're supposed to get the list of supported banks here but bank payment
// requires the secret key which is a security issue. So have removed support for
// bank payment
// Utils.getSupportedBanks();
// Using cascade notation to build the platform specific info
try {
String userAgent = await Utils.channel.invokeMethod('getUserAgent');
String paystackBuild =
await Utils.channel.invokeMethod('getVersionCode');
String deviceId = await Utils.channel.invokeMethod('getDeviceId');
PlatformInfo()
..userAgent = userAgent
..paystackBuild = paystackBuild
..deviceId = deviceId;
_sdkInitialized = true;
completer.complete(PaystackPlugin._());
} on PlatformException catch (e, stacktrace) {
completer.completeError(e, stacktrace);
}
}
return completer.future;
}
static bool get sdkInitialized => _sdkInitialized;
static String get publicKey {
// Validate that the sdk has been initialized
Utils.validateSdkInitialized();
return _publicKey;
}
static void _performChecks() {
//validate that sdk has been initialized
Utils.validateSdkInitialized();
//validate public keys
Utils.hasPublicKey();
}
/// Make payment by chargingg the user's card
///
/// [context] - the widgets BuildContext
///
/// [charge] - the charge object.
///
/// [beforeValidate] - Called before validation
///
/// [onSuccess] - Called when the payment is completes successfully
///
/// [onError] - Called when the payment completes with an unrecoverable error
static chargeCard(BuildContext context,
{@required Charge charge,
@required OnTransactionChange<Transaction> beforeValidate,
@required OnTransactionChange<Transaction> onSuccess,
@required OnTransactionError<Object, Transaction> onError}) {
assert(context != null, 'context must not be null');
_performChecks();
Paystack.withPublicKey(publicKey).chargeCard(
context: context,
charge: charge,
beforeValidate: beforeValidate,
onSuccess: onSuccess,
onError: onError);
}
/// Make payment using Paystack's checkout form. The plugin will handle the whole
/// processes involved.
///
/// [context] - the widgets BuildContext
///
/// [charge] - the charge object. You must pass the amount (in kobo) to it. If you
/// want to use CheckoutMethod.card/CheckoutMethod.selectable, you must also
/// pass either an access code or payment reference to the charge object.
///
/// Notes:
///
/// * When you pass an access code, the plugin won't
/// initialize the transaction and payment is made immediately
/// * When you pass the reference, the plugin will initialize the transaction
/// (via https://api.paystack.co/transaction/initialize) with the passed reference.
/// * You can also pass the [PaymentCard] object and we'll use it to prepopulate the
/// card fields if card payment is being used
///
/// [onSuccess] - Called when the payment completes successfully
///
/// [onValidated] - Called when the payment completes with an unrecoverable error
///
/// [method] - The payment payment method to use(card, bank). It defaults to
/// [CheckoutMethod.selectable] to allow the user to select. Please note that this is
/// just redundant pending when bank payment returns
static Future<CheckoutResponse> checkout(
BuildContext context, {
@required Charge charge,
CheckoutMethod method = CheckoutMethod.selectable,
bool fullscreen = false,
}) async {
assert(context != null, 'context must not be null');
assert(
method != null,
'method must not be null. You can pass CheckoutMethod.selectable if you want '
'the user '
'to select the checkout option');
assert(fullscreen != null, 'fillscreen must not be null');
return Paystack.withPublicKey(publicKey).checkout(context,
charge: charge, method: method, fullscreen: fullscreen);
}
}
class Paystack {
String _publicKey;
Paystack() {
// Validate sdk initialized
Utils.validateSdkInitialized();
}
Paystack.withPublicKey(this._publicKey);
chargeCard(
{@required BuildContext context,
@required Charge charge,
@required OnTransactionChange<Transaction> beforeValidate,
@required OnTransactionChange<Transaction> onSuccess,
@required OnTransactionError<Object, Transaction> onError}) {
try {
//check for null value, and length and starts with pk_
if (_publicKey == null ||
_publicKey.isEmpty ||
!_publicKey.startsWith("pk_")) {
throw new AuthenticationException(Utils.getKeyErrorMsg('public'));
}
new MobileTransactionManager(
charge: charge,
context: context,
beforeValidate: beforeValidate,
onSuccess: onSuccess,
onError: onError)
.chargeCard();
} catch (e) {
if (e is AuthenticationException) {
rethrow;
}
assert(onError != null);
onError(e, null);
}
}
Future<CheckoutResponse> checkout(
BuildContext context, {
@required Charge charge,
@required CheckoutMethod method,
@required bool fullscreen,
}) async {
assert(() {
Utils.validateChargeAndKey(charge);
if (charge.accessCode == null && charge.reference == null) {
throw new ChargeException(Strings.noAccessCodeReference);
}
return true;
}());
CheckoutResponse response = await showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) => new CheckoutWidget(
method: method,
charge: charge,
fullscreen: fullscreen,
));
return response == null ? CheckoutResponse.defaults() : response;
}
}
typedef void OnTransactionChange<Transaction>(Transaction transaction);
typedef void OnTransactionError<Object, Transaction>(
Object e, Transaction transaction);
enum CheckoutMethod { card, bank, selectable }