Skip to content

Commit 11b88af

Browse files
author
taiwoadebayo
committed
check card is allowed before charging card
Allowed cards are cards issued in the user's country, user cannot fund with a foreign card. Feature enabled for direct inputting of card and saved cards
1 parent dda5426 commit 11b88af

File tree

10 files changed

+387
-13
lines changed

10 files changed

+387
-13
lines changed

app/src/main/res/layout/activity_main.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@
306306
android:layout_height="wrap_content"
307307
android:layout_marginBottom="10dp"
308308
android:hint="@string/email"
309+
android:text="mikelis135@gmail.com"
309310
android:inputType="textEmailAddress"
310311
android:textSize="14sp" />
311312

@@ -314,6 +315,7 @@
314315
android:layout_width="match_parent"
315316
android:layout_height="wrap_content"
316317
android:layout_marginBottom="10dp"
318+
android:text="20"
317319
android:hint="@string/amount_to_charge_required"
318320
android:inputType="number"
319321
android:textSize="14sp" />
@@ -341,6 +343,7 @@
341343
android:layout_width="match_parent"
342344
android:layout_height="wrap_content"
343345
android:layout_marginBottom="10dp"
346+
android:text="sdfsdfdfdfs"
344347
android:hint="@string/txref_required"
345348
android:textSize="14sp" />
346349

@@ -350,13 +353,15 @@
350353
android:layout_width="match_parent"
351354
android:layout_height="wrap_content"
352355
android:layout_marginBottom="10dp"
356+
android:text="adfwdfd"
353357
android:hint="@string/narration"
354358
android:textSize="14sp" />
355359

356360
<EditText
357361
android:id="@+id/currencyEt"
358362
android:layout_width="match_parent"
359363
android:layout_height="wrap_content"
364+
android:text="NGN"
360365
android:layout_marginBottom="10dp"
361366
android:hint="@string/currency_code_e_g_ngn"
362367
android:textSize="14sp" />
@@ -366,6 +371,7 @@
366371
android:layout_width="match_parent"
367372
android:layout_height="wrap_content"
368373
android:layout_marginBottom="10dp"
374+
android:text="NG"
369375
android:hint="@string/country_code_e_g_ng"
370376
android:textSize="14sp"
371377
android:visibility="gone" />
@@ -375,6 +381,7 @@
375381
android:id="@+id/fNameEt"
376382
android:layout_width="match_parent"
377383
android:layout_height="wrap_content"
384+
android:text="taiwo"
378385
android:layout_marginBottom="10dp"
379386
android:hint="@string/first_name"
380387
android:textSize="14sp" />
@@ -383,6 +390,7 @@
383390
android:id="@+id/lnameEt"
384391
android:layout_width="match_parent"
385392
android:layout_height="wrap_content"
393+
android:text="adebayo"
386394
android:layout_marginBottom="10dp"
387395
android:hint="@string/last_name"
388396
android:textSize="14sp" />
@@ -391,6 +399,7 @@
391399
android:id="@+id/phoneNumberEt"
392400
android:layout_width="match_parent"
393401
android:layout_height="wrap_content"
402+
android:text="08132383284"
394403
android:layout_marginBottom="10dp"
395404
android:hint="@string/phone_number"
396405
android:inputType="phone"

rave_android/src/main/java/com/flutterwave/raveandroid/card/CardUiPresenter.java

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,10 @@ public void processTransaction(HashMap<String, ViewObject> dataHashMap, RavePayI
209209

210210
String deviceID = deviceIdGetter.getDeviceId();
211211

212+
String cardFirstSix = "";
213+
if (dataHashMap.get(fieldcardNoStripped).getData().length() > 6) {
214+
cardFirstSix = dataHashMap.get(fieldcardNoStripped).getData().substring(0, 6);
215+
}
212216

213217
PayloadBuilder builder = new PayloadBuilder();
214218
builder.setAmount(String.valueOf(ravePayInitializer.getAmount()))
@@ -234,11 +238,8 @@ public void processTransaction(HashMap<String, ViewObject> dataHashMap, RavePayI
234238

235239
Payload body = builder.createPayload();
236240

237-
if (ravePayInitializer.getIsDisplayFee()) {
238-
fetchFee(body);
239-
} else {
240-
chargeCard(body, ravePayInitializer.getEncryptionKey());
241-
}
241+
checkCard(cardFirstSix, body, ravePayInitializer.getIsDisplayFee(), ravePayInitializer.getEncryptionKey());
242+
242243
}
243244
}
244245

@@ -273,11 +274,13 @@ public void processSavedCardTransaction(SavedCard savedCard, RavePayInitializer
273274

274275
Payload body = builder.createSavedCardChargePayload();
275276

276-
if (ravePayInitializer.getIsDisplayFee()) {
277-
fetchFee(body);
278-
} else {
279-
chargeSavedCard(body, ravePayInitializer.getEncryptionKey());
277+
String cardFirstSix = "";
278+
if (savedCard.getMasked_pan().length() >= 6) {
279+
cardFirstSix = savedCard.getMasked_pan().substring(0, 6);
280280
}
281+
282+
checkCard(cardFirstSix, body, ravePayInitializer.getIsDisplayFee(), ravePayInitializer.getEncryptionKey());
283+
281284
}
282285
}
283286

@@ -298,7 +301,7 @@ public void checkForSavedCardsInMemory(RavePayInitializer ravePayInitializer) {
298301
savedCards = new ArrayList<>();
299302
}
300303

301-
if(ravePayInitializer.getPhoneNumber().equals(sharedManager.fetchPhoneNumber())){
304+
if (ravePayInitializer.getPhoneNumber().equals(sharedManager.fetchPhoneNumber())) {
302305
retrieveSavedCardsFromMemory(ravePayInitializer.getPhoneNumber(), ravePayInitializer.getPublicKey());
303306
}
304307

rave_java_commons/src/main/java/com/flutterwave/raveandroid/rave_java_commons/RaveConstants.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ public class RaveConstants {
3232
// public static String LIVE_URL = "https://raveapi.azurewebsites.net";
3333
public static String STAGING_URL = "https://ravesandboxapi.flutterwave.com";
3434
public static String LIVE_URL = "https://api.ravepay.co";
35+
public static String BARTER_STAGING_URL = "https://pilot-barter-staging.azurewebsites.net";
36+
public static String UserId = "4444444444";
37+
public static String MerchSecret = "5555555555";
3538
public static String EVENT_LOGGING_URL = "https://kgelfdz7mf.execute-api.us-east-1.amazonaws.com/";
3639
public static String FLUTTERWAVE_UK_ACCOUNT = "43271228";
3740
public static String FLUTTERWAVE_UK_SORT_CODE = "04-00-53";
@@ -78,6 +81,7 @@ public class RaveConstants {
7881

7982
public static String success = "success";
8083
public static String noResponse = "No response data was returned";
84+
public static String cardNotAllowed = "Card not allowed, please use a card issued in your country";
8185
public static String invalidAccountNoMessage = "Enter a valid account number";
8286
public static String invalidDateOfBirthMessage = "Enter a valid date of birth";
8387
public static String invalidBvnMessage = "Enter a valid BVN";

rave_presentation/src/main/java/com/flutterwave/raveandroid/rave_presentation/card/CardContract.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ interface CardPaymentHandler {
161161

162162
void chargeCard(Payload payload, String encryptionKey);
163163

164+
void checkCard(String cardFirstSix, Payload body, Boolean isDisplayFee, String encryptionKey);
165+
164166
void validateCardCharge(String flwRef, String otp, String publicKey);
165167

166168
void requeryTx(String flwRef, String publicKey);

rave_presentation/src/main/java/com/flutterwave/raveandroid/rave_presentation/card/CardPaymentHandler.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import com.flutterwave.raveandroid.rave_remote.requests.SendOtpRequestBody;
2828
import com.flutterwave.raveandroid.rave_remote.requests.ValidateChargeBody;
2929
import com.flutterwave.raveandroid.rave_remote.responses.ChargeResponse;
30+
import com.flutterwave.raveandroid.rave_remote.responses.CheckCardResponse;
3031
import com.flutterwave.raveandroid.rave_remote.responses.FeeCheckResponse;
3132
import com.flutterwave.raveandroid.rave_remote.responses.LookupSavedCardsResponse;
3233
import com.flutterwave.raveandroid.rave_remote.responses.RequeryResponse;
@@ -48,6 +49,7 @@
4849
import static com.flutterwave.raveandroid.rave_java_commons.RaveConstants.PIN;
4950
import static com.flutterwave.raveandroid.rave_java_commons.RaveConstants.RAVEPAY;
5051
import static com.flutterwave.raveandroid.rave_java_commons.RaveConstants.VBV;
52+
import static com.flutterwave.raveandroid.rave_java_commons.RaveConstants.cardNotAllowed;
5153
import static com.flutterwave.raveandroid.rave_java_commons.RaveConstants.enterOTP;
5254
import static com.flutterwave.raveandroid.rave_java_commons.RaveConstants.noResponse;
5355
import static com.flutterwave.raveandroid.rave_java_commons.RaveConstants.success;
@@ -186,6 +188,39 @@ public void onError(String message) {
186188
});
187189
}
188190

191+
@Override
192+
public void checkCard(String cardFirstSix, final Payload body, final Boolean isDisplayFee, final String encryptionKey) {
193+
194+
mCardInteractor.showProgressIndicator(true);
195+
196+
networkRequest.checkCard(cardFirstSix, new ResultCallback<CheckCardResponse>() {
197+
@Override
198+
public void onSuccess(CheckCardResponse response) {
199+
mCardInteractor.showProgressIndicator(false);
200+
201+
if (response.getData().getCountry().getCurrency().equalsIgnoreCase(body.getCurrency())){
202+
203+
if (isDisplayFee) {
204+
fetchFee(body);
205+
} else {
206+
chargeCard(body, encryptionKey);
207+
}
208+
209+
}else{
210+
mCardInteractor.onPaymentError(cardNotAllowed);
211+
}
212+
213+
}
214+
215+
@Override
216+
public void onError(String message) {
217+
mCardInteractor.showProgressIndicator(false);
218+
mCardInteractor.onPaymentError(message);
219+
}
220+
});
221+
222+
}
223+
189224
@Override
190225
public void chargeSavedCard(Payload payload, String encryptionKey) {
191226
if (payload.getOtp() == null || payload.getOtp() == "") {

rave_remote/src/main/java/com/flutterwave/raveandroid/rave_remote/ApiService.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@
1010
import com.flutterwave.raveandroid.rave_remote.requests.SaveCardRequestBody;
1111
import com.flutterwave.raveandroid.rave_remote.requests.SendOtpRequestBody;
1212
import com.flutterwave.raveandroid.rave_remote.requests.ValidateChargeBody;
13+
import com.flutterwave.raveandroid.rave_remote.responses.CheckCardResponse;
1314

1415
import retrofit2.Call;
1516
import retrofit2.http.Body;
1617
import retrofit2.http.GET;
18+
import retrofit2.http.Header;
1719
import retrofit2.http.POST;
20+
import retrofit2.http.Path;
1821
import retrofit2.http.Url;
1922

2023
/**
@@ -27,6 +30,12 @@ public interface ApiService {
2730
// Call<ChargeResponse> charge(@Body ChargeRequestBody body);
2831
Call<String> charge(@Body ChargeRequestBody body);
2932

33+
@GET("/api/v1/barter/cards/get-details-by-bin/{card-first-six}")
34+
Call<String> checkCard(@Path("card-first-six") String cardFirstSix,
35+
@Header("CustomerReference") String CustomerReference,
36+
@Header("UserId") String UserId,
37+
@Header("Hash")String Hash);
38+
3039
@POST("/flwv3-pug/getpaidx/api/charge?use_polling=1")
3140
// Call<ChargeResponse> charge(@Body ChargeRequestBody body);
3241
Call<String> chargeWithPolling(@Body ChargeRequestBody body);
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.flutterwave.raveandroid.rave_remote;
2+
3+
import java.nio.charset.StandardCharsets;
4+
import java.security.MessageDigest;
5+
import java.security.NoSuchAlgorithmException;
6+
7+
public class Hasher {
8+
9+
public static String sha(String input, String type) {
10+
return hashString(type, input);
11+
}
12+
13+
private static String hashString(String type, String input) {
14+
15+
try {
16+
// byte[] b = input.getBytes();
17+
// String HEX_CHARS = "0123456789ABCDEF";
18+
// byte[] bytes = MessageDigest.getInstance(type).digest(b);
19+
//
20+
// StringBuilder result = new StringBuilder(bytes.length * 2);
21+
//
22+
// for (int i = 0; i < bytes.length; i++) {
23+
//
24+
// int eachByte = (int) i;
25+
// result.append(HEX_CHARS.charAt(eachByte >> 4 & 0x0f));
26+
// result.append(HEX_CHARS.charAt(eachByte & 0x0f));
27+
// }
28+
29+
// try{
30+
MessageDigest digest = MessageDigest.getInstance("SHA-256");
31+
byte[] hash = digest.digest(input.getBytes("UTF-8"));
32+
StringBuffer hexString = new StringBuffer();
33+
34+
for (int i = 0; i < hash.length; i++) {
35+
String hex = Integer.toHexString(0xff & hash[i]);
36+
if(hex.length() == 1) hexString.append('0');
37+
hexString.append(hex);
38+
}
39+
40+
return hexString.toString();
41+
} catch(Exception ex){
42+
return "";
43+
}
44+
// return result.toString();
45+
// } catch (NoSuchAlgorithmException exception) {
46+
// return "";
47+
// }
48+
49+
}
50+
}

rave_remote/src/main/java/com/flutterwave/raveandroid/rave_remote/RemoteRepository.java

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.flutterwave.raveandroid.rave_java_commons.ExecutorCallback;
77
import com.flutterwave.raveandroid.rave_java_commons.NetworkRequestExecutor;
88
import com.flutterwave.raveandroid.rave_java_commons.Payload;
9+
import com.flutterwave.raveandroid.rave_java_commons.RaveConstants;
910
import com.flutterwave.raveandroid.rave_remote.requests.ChargeRequestBody;
1011
import com.flutterwave.raveandroid.rave_remote.requests.LookupSavedCardsRequestBody;
1112
import com.flutterwave.raveandroid.rave_remote.requests.RemoveSavedCardRequestBody;
@@ -14,6 +15,7 @@
1415
import com.flutterwave.raveandroid.rave_remote.requests.SendOtpRequestBody;
1516
import com.flutterwave.raveandroid.rave_remote.requests.ValidateChargeBody;
1617
import com.flutterwave.raveandroid.rave_remote.responses.ChargeResponse;
18+
import com.flutterwave.raveandroid.rave_remote.responses.CheckCardResponse;
1719
import com.flutterwave.raveandroid.rave_remote.responses.FeeCheckResponse;
1820
import com.flutterwave.raveandroid.rave_remote.responses.LookupSavedCardsResponse;
1921
import com.flutterwave.raveandroid.rave_remote.responses.MobileMoneyChargeResponse;
@@ -49,18 +51,24 @@
4951
public class RemoteRepository {
5052

5153
private Retrofit mainRetrofit;
54+
private Retrofit barterRetrofit;
5255
private ApiService service;
56+
private ApiService barterService;
5357
private Gson gson;
5458
private NetworkRequestExecutor executor;
5559
private String errorParsingError = "An error occurred parsing the error response";
5660

5761
@Inject
5862
public RemoteRepository(@Named("mainRetrofit") Retrofit mainRetrofit,
59-
ApiService service,
63+
@Named("barterRetrofit") Retrofit barterRetrofit,
64+
@Named("mainApiService") ApiService service,
65+
@Named("barterApiService") ApiService barterService,
6066
Gson gson,
6167
NetworkRequestExecutor executor) {
6268
this.mainRetrofit = mainRetrofit;
69+
this.barterRetrofit = barterRetrofit;
6370
this.service = service;
71+
this.barterService = barterService;
6472
this.gson = gson;
6573
this.executor = executor;
6674
}
@@ -74,6 +82,18 @@ public void charge(ChargeRequestBody body, final ResultCallback callback) {
7482
);
7583
}
7684

85+
public void checkCard(String cardFirstSix, final ResultCallback callback) {
86+
87+
AuthCredValue authCredValue = fetchAuthCred();
88+
89+
executor.execute(barterService.checkCard(cardFirstSix, authCredValue.authCred.customerRef,
90+
authCredValue.authCred.userId, authCredValue.authCred.hash),
91+
new TypeToken<CheckCardResponse>() {
92+
}.getType(),
93+
new GenericNetworkCallback<CheckCardResponse>(callback)
94+
);
95+
}
96+
7797
public void chargeWithPolling(ChargeRequestBody body, final ResultCallback callback) {
7898

7999
Call<String> call = service.chargeWithPolling(body);
@@ -424,4 +444,44 @@ public void onCallFailure(String exceptionMessage) {
424444
callback.onError(exceptionMessage, exceptionMessage);
425445
}
426446
}
447+
448+
private AuthCredValue fetchAuthCred() {
449+
AuthCred authCred = generateAuthCred();
450+
Token tokens = new Token();
451+
AuthCredValue authCredValue = new AuthCredValue();
452+
authCredValue.authCred = authCred;
453+
authCredValue.token = tokens;
454+
return authCredValue;
455+
}
456+
457+
private AuthCred generateAuthCred() {
458+
String customerRef = fetchCustomerRef();
459+
String valueToHash = customerRef + RaveConstants.UserId + RaveConstants.MerchSecret;
460+
String hashValue = Hasher.sha(valueToHash, "SHA-256");
461+
462+
AuthCred authCred = new AuthCred();
463+
authCred.customerRef = customerRef;
464+
authCred.userId = RaveConstants.UserId;
465+
authCred.hash = hashValue;
466+
return authCred;
467+
}
468+
469+
private static String fetchCustomerRef() {
470+
long random = Double.valueOf(Math.random()).longValue();
471+
return "ML_ANDROID_" + "deviceId" + System.currentTimeMillis() + random;
472+
}
473+
474+
static class AuthCred {
475+
String customerRef;
476+
String userId;
477+
String hash;
478+
}
479+
480+
static class Token {
481+
}
482+
483+
static class AuthCredValue {
484+
AuthCred authCred;
485+
Token token;
486+
}
427487
}

0 commit comments

Comments
 (0)