Skip to content

Commit 2c7c3e0

Browse files
committed
Refactored to facilitate testing
1 parent 4a8c78a commit 2c7c3e0

20 files changed

+196
-149
lines changed

lib/src/api/request/bank_charge_request_body.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'package:flutter_paystack/src/api/request/base_request_body.dart';
2+
import 'package:flutter_paystack/src/models/bank.dart';
23
import 'package:flutter_paystack/src/models/charge.dart';
3-
import 'package:flutter_paystack/src/widgets/checkout/bank_checkout.dart';
44

55
class BankChargeRequestBody extends BaseRequestBody {
66
String _accessCode;

lib/src/api/service/bank_service.dart

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,18 @@ import 'dart:async';
22
import 'dart:convert';
33
import 'dart:io';
44

5+
import 'package:async/async.dart';
56
import 'package:flutter_paystack/src/api/model/transaction_api_response.dart';
67
import 'package:flutter_paystack/src/api/request/bank_charge_request_body.dart';
78
import 'package:flutter_paystack/src/api/service/base_service.dart';
9+
import 'package:flutter_paystack/src/api/service/contracts/banks_service_contract.dart';
810
import 'package:flutter_paystack/src/common/exceptions.dart';
911
import 'package:flutter_paystack/src/common/my_strings.dart';
12+
import 'package:flutter_paystack/src/models/bank.dart';
1013
import 'package:http/http.dart' as http;
1114

12-
class BankService extends BaseApiService {
15+
class BankService with BaseApiService implements BankServiceContract {
16+
@override
1317
Future<String> getTransactionId(String accessCode) async {
1418
var url =
1519
'https://api.paystack.co/transaction/verify_access_code/$accessCode';
@@ -24,13 +28,15 @@ class BankService extends BaseApiService {
2428
return null;
2529
}
2630

31+
@override
2732
Future<TransactionApiResponse> chargeBank(
2833
BankChargeRequestBody requestBody) async {
2934
var url =
3035
'$baseUrl/bank/charge_account/${requestBody.account.bank.id}/${requestBody.transactionId}';
3136
return _getChargeFuture(url, fields: requestBody.paramsMap());
3237
}
3338

39+
@override
3440
Future<TransactionApiResponse> validateToken(
3541
BankChargeRequestBody requestBody, Map<String, String> fields) async {
3642
var url =
@@ -58,4 +64,29 @@ class BankService extends BaseApiService {
5864
throw new ChargeException(Strings.unKnownResponse);
5965
}
6066
}
67+
68+
@override
69+
Future<List<Bank>> fetchSupportedBanks() async {
70+
return banksMemo.runOnce(() async {
71+
return await _fetchSupportedBanks();
72+
});
73+
}
74+
75+
Future<List<Bank>> _fetchSupportedBanks() async {
76+
const url =
77+
'https://api.paystack.co/bank?gateway=emandate&pay_with_bank=true';
78+
try {
79+
http.Response response = await http.get(url);
80+
Map<String, dynamic> body = json.decode(response.body);
81+
var data = body['data'];
82+
List<Bank> banks = [];
83+
for (var bank in data) {
84+
banks.add(new Bank(bank['name'], bank['id']));
85+
}
86+
return banks;
87+
} catch (e) {}
88+
return null;
89+
}
6190
}
91+
92+
var banksMemo = new AsyncMemoizer<List<Bank>>();

lib/src/api/service/base_service.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import 'dart:io';
33

44
import 'package:flutter_paystack/src/common/platform_info.dart';
55

6-
class BaseApiService {
6+
mixin BaseApiService {
77
final Map<String, String> headers = {
88
HttpHeaders.contentTypeHeader: 'application/x-www-form-urlencoded',
99
HttpHeaders.userAgentHeader: PlatformInfo().userAgent,

lib/src/api/service/card_service.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ import 'dart:io';
44

55
import 'package:flutter_paystack/src/api/model/transaction_api_response.dart';
66
import 'package:flutter_paystack/src/api/service/base_service.dart';
7+
import 'package:flutter_paystack/src/api/service/contracts/cards_service_contract.dart';
78
import 'package:flutter_paystack/src/common/exceptions.dart';
89
import 'package:flutter_paystack/src/common/my_strings.dart';
910
import 'package:http/http.dart' as http;
1011

11-
class CardService extends BaseApiService {
12+
class CardService with BaseApiService implements CardServiceContract {
13+
@override
1214
Future<TransactionApiResponse> chargeCard(Map<String, String> fields) async {
1315
var url = '$baseUrl/charge/mobile_charge';
1416

@@ -32,6 +34,7 @@ class CardService extends BaseApiService {
3234
}
3335
}
3436

37+
@override
3538
Future<TransactionApiResponse> validateCharge(
3639
Map<String, String> fields) async {
3740
var url = '$baseUrl/charge/validate';
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import 'package:flutter_paystack/src/api/model/transaction_api_response.dart';
2+
import 'package:flutter_paystack/src/api/request/bank_charge_request_body.dart';
3+
import 'package:flutter_paystack/src/models/bank.dart';
4+
5+
abstract class BankServiceContract {
6+
Future<String> getTransactionId(String accessCode);
7+
8+
Future<TransactionApiResponse> chargeBank(BankChargeRequestBody requestBody);
9+
10+
Future<TransactionApiResponse> validateToken(
11+
BankChargeRequestBody requestBody, Map<String, String> fields);
12+
13+
Future<List<Bank>> fetchSupportedBanks();
14+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import 'package:flutter_paystack/src/api/model/transaction_api_response.dart';
2+
3+
abstract class CardServiceContract {
4+
Future<TransactionApiResponse> chargeCard(Map<String, String> fields);
5+
6+
Future<TransactionApiResponse> validateCharge(Map<String, String> fields);
7+
8+
Future<TransactionApiResponse> reQueryTransaction(String trans);
9+
}

lib/src/common/paystack.dart

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import 'dart:async';
33
import 'package:flutter/foundation.dart';
44
import 'package:flutter/material.dart';
55
import 'package:flutter/services.dart';
6+
import 'package:flutter_paystack/src/api/service/bank_service.dart';
7+
import 'package:flutter_paystack/src/api/service/card_service.dart';
68
import 'package:flutter_paystack/src/common/exceptions.dart';
79
import 'package:flutter_paystack/src/common/my_strings.dart';
810
import 'package:flutter_paystack/src/common/platform_info.dart';
@@ -37,19 +39,12 @@ class PaystackPlugin {
3739
return true;
3840
}());
3941

40-
// do all the init work here
41-
4242
//check if sdk is actually initialized
4343
if (sdkInitialized) {
4444
return PaystackPlugin._();
4545
} else {
4646
_publicKey = publicKey;
4747

48-
// If private key is not null, it implies that checkout will be used.
49-
// Hence, let's get the list of supported banks. We won't wait for the result. If it
50-
// completes successfully, fine. If it fails, we'll retry in BankCheckout
51-
Utils.getSupportedBanks();
52-
5348
// Using cascade notation to build the platform specific info
5449
try {
5550
String userAgent = await Utils.channel.invokeMethod('getUserAgent');
@@ -198,6 +193,7 @@ class _Paystack {
198193
}
199194

200195
new CardTransactionManager(
196+
service: CardService(),
201197
charge: charge,
202198
context: context,
203199
beforeValidate: beforeValidate,
@@ -244,6 +240,8 @@ class _Paystack {
244240
barrierDismissible: false,
245241
context: context,
246242
builder: (BuildContext context) => new CheckoutWidget(
243+
bankService: BankService(),
244+
cardsService: CardService(),
247245
method: method,
248246
charge: charge,
249247
fullscreen: fullscreen,

lib/src/common/utils.dart

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,13 @@
1-
import 'dart:async';
2-
import 'dart:convert';
3-
4-
import 'package:async/async.dart';
51
import 'package:flutter/services.dart';
62
import 'package:flutter_paystack/src/common/exceptions.dart';
73
import 'package:flutter_paystack/src/common/paystack.dart';
84
import 'package:flutter_paystack/src/common/string_utils.dart';
95
import 'package:flutter_paystack/src/models/charge.dart';
10-
import 'package:flutter_paystack/src/widgets/checkout/bank_checkout.dart';
11-
import 'package:http/http.dart' as http;
126
import 'package:intl/intl.dart';
137

148
class Utils {
159
static const MethodChannel channel = const MethodChannel('flutter_paystack');
1610

17-
static AsyncMemoizer banksMemo = new AsyncMemoizer();
18-
19-
static Future getSupportedBanks() => Utils.banksMemo.runOnce(() async {
20-
const url =
21-
'https://api.paystack.co/bank?gateway=emandate&pay_with_bank=true';
22-
try {
23-
http.Response response = await http.get(url);
24-
Map<String, dynamic> body = json.decode(response.body);
25-
var data = body['data'];
26-
List<Bank> banks = [];
27-
for (var bank in data) {
28-
banks.add(new Bank(bank['name'], bank['id']));
29-
}
30-
return banks;
31-
} catch (e) {}
32-
return null;
33-
});
34-
3511
static validateSdkInitialized() {
3612
if (!PaystackPlugin.sdkInitialized) {
3713
throw new PaystackSdkNotInitializedException(

lib/src/models/bank.dart

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
class Bank {
2+
String name;
3+
int id;
4+
5+
Bank(this.name, this.id);
6+
7+
@override
8+
String toString() {
9+
return 'Bank{name: $name, id: $id}';
10+
}
11+
}
12+
13+
class BankAccount {
14+
Bank bank;
15+
String number;
16+
17+
BankAccount(this.bank, this.number);
18+
19+
bool isValid() {
20+
if (number == null || number.length < 10) {
21+
return false;
22+
}
23+
24+
if (bank == null || bank.id == null) {
25+
return false;
26+
}
27+
return true;
28+
}
29+
30+
@override
31+
String toString() {
32+
return 'BankAccount{bank: $bank, number: $number}';
33+
}
34+
}

lib/src/models/charge.dart

Lines changed: 16 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
import 'package:flutter_paystack/src/common/exceptions.dart';
22
import 'package:flutter_paystack/src/common/my_strings.dart';
3+
import 'package:flutter_paystack/src/models/bank.dart';
34
import 'package:flutter_paystack/src/models/card.dart';
4-
import 'package:flutter_paystack/src/widgets/checkout/bank_checkout.dart';
55

66
class Charge {
77
PaymentCard card;
88

99
/// The email of the customer
1010
String email;
11-
String _accessCode;
1211
BankAccount _account;
1312

1413
/// Amount to pay in base currency. Must be a valid positive number
@@ -17,17 +16,23 @@ class Charge {
1716
List<Map<String, dynamic>> _customFields;
1817
bool _hasMeta = false;
1918
Map<String, String> _additionalParameters;
20-
int _transactionCharge = 0;
21-
String _subAccount;
22-
String _reference;
23-
Bearer _bearer;
24-
String _currency;
25-
String _plan;
26-
bool _localStarted = false;
27-
bool _remoteStarted = false;
2819

2920
/// The locale used for formatting amount in the UI prompt. Defaults to [Strings.nigerianLocale]
3021
String locale;
22+
String accessCode;
23+
String plan;
24+
String reference;
25+
26+
/// ISO 4217 payment currency code (e.g USD). Defaults to [Strings.ngn].
27+
///
28+
/// If you're setting this value, also set [locale] for better formatting.
29+
String currency;
30+
int transactionCharge;
31+
32+
/// Who bears Paystack charges? [Bearer.Account] or [Bearer.SubAccount]
33+
Bearer bearer;
34+
35+
String subAccount;
3136

3237
Charge() {
3338
this._metadata = {};
@@ -36,7 +41,7 @@ class Charge {
3641
this._customFields = [];
3742
this._metadata['custom_fields'] = this._customFields;
3843
this.locale = Strings.nigerianLocale;
39-
this._currency = Strings.ngn;
44+
this.currency = Strings.ngn;
4045
}
4146

4247
addParameter(String key, String value) {
@@ -45,52 +50,6 @@ class Charge {
4550

4651
Map<String, String> get additionalParameters => _additionalParameters;
4752

48-
String get accessCode => _accessCode;
49-
50-
set accessCode(String value) {
51-
_accessCode = value;
52-
}
53-
54-
String get plan => _plan;
55-
56-
set plan(String value) {
57-
_plan = value;
58-
}
59-
60-
String get currency => _currency;
61-
62-
/// ISO 4217 payment currency code (e.g USD). Defaults to [Strings.ngn].
63-
///
64-
/// If you're setting this value, also set [locale] for better formatting.
65-
set currency(String value) {
66-
_currency = value;
67-
}
68-
69-
String get reference => _reference;
70-
71-
set reference(String value) {
72-
_reference = value;
73-
}
74-
75-
int get transactionCharge => _transactionCharge;
76-
77-
set transactionCharge(int value) {
78-
_transactionCharge = value;
79-
}
80-
81-
Bearer get bearer => _bearer;
82-
83-
/// Who bears Paystack charges? [Bearer.Account] or [Bearer.SubAccount]
84-
set bearer(Bearer value) {
85-
_bearer = value;
86-
}
87-
88-
String get subAccount => _subAccount;
89-
90-
set subAccount(String value) {
91-
_subAccount = value;
92-
}
93-
9453
BankAccount get account => _account;
9554

9655
set account(BankAccount value) {

0 commit comments

Comments
 (0)