Skip to content

Commit

Permalink
Implemented direct account debit
Browse files Browse the repository at this point in the history
  • Loading branch information
wilburx9 committed Oct 22, 2019
1 parent ecbfc50 commit e9653f8
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 123 deletions.
30 changes: 15 additions & 15 deletions lib/src/common/strings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,21 @@ class Strings {
static const ugandaMobileMoney = 'Uganda Mobile Money';
static const pay = 'Pay';
static const invalidCVV = 'Enter a valid cvv';
static String invalidExpiry = 'Enter a valid expiry date';
static var invalidCardNumber = 'Enter a valid card number';
static var invalidPhoneNumber = 'Enter a valid phone number';
static var invalidAccountNumber = 'Enter a valid account number';
static var invalidAmount = 'Enter a valid amount';
static var invalidEmail = 'Enter a valid email';
static var invalidBVN = 'Enter a valid BVN';
static var invalidVoucher = 'Enter a valid voucher code';
static var invalidDOB = 'Enter a valid date of birth';
static var demo = 'Demo';
static var youCancelled = 'You cancelled';
static var sthWentWrong = 'Something went wrong';
static var noResponseData = 'No response data was returned';
static var unknownAuthModel = 'Unknown auth model';
static var enterOtp = 'Enter your one time password (OTP)';
static const invalidExpiry = 'Enter a valid expiry date';
static const invalidCardNumber = 'Enter a valid card number';
static const invalidPhoneNumber = 'Enter a valid phone number';
static const invalidAccountNumber = 'Enter a valid account number';
static const invalidAmount = 'Enter a valid amount';
static const invalidEmail = 'Enter a valid email';
static const invalidBVN = 'Enter a valid BVN';
static const invalidVoucher = 'Enter a valid voucher code';
static const invalidDOB = 'Enter a valid date of birth';
static const demo = 'Demo';
static const youCancelled = 'You cancelled';
static const sthWentWrong = 'Something went wrong';
static const noResponseData = 'No response data was returned';
static const unknownAuthModel = 'Unknown auth model';
static const enterOtp = 'Enter your one time password (OTP)';

static cannotBeNull(String name) => '$name cannot be null';

Expand Down
6 changes: 6 additions & 0 deletions lib/src/common/validator_utills.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ class ValidatorUtils {
return true;
}

static bool isUrlValid(String url) {
final source =
r'^(https?|ftp|file|http)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]';
return RegExp(source).hasMatch(url);
}

/// Checks if the card has expired.
/// Returns true if the card has expired; false otherwise
static bool validExpiryDate(int expiryMonth, int expiryYear) {
Expand Down
8 changes: 5 additions & 3 deletions lib/src/dto/charge_request_body.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:convert';

import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';
import 'package:rave_flutter/src/common/rave_utils.dart';
import 'package:rave_flutter/src/dto/payload.dart';
import 'package:rave_flutter/src/repository/repository.dart';
Expand All @@ -16,10 +17,11 @@ class ChargeRequestBody extends Equatable {
this.alg,
});

ChargeRequestBody.fromPayload(Payload p)
: this.pBFPubKey = p.pbfPubKey,
ChargeRequestBody.fromPayload({@required Payload payload, String type})
: this.pBFPubKey = payload.pbfPubKey,
this.alg = "3DES-24",
this.client = RaveUtils.getEncryptedData(json.encode(p.toJson()),
this.client = RaveUtils.getEncryptedData(
json.encode(payload.toJson(type)),
Repository.instance.initializer.encryptionKey);

Map<String, dynamic> toJson() => {
Expand Down
12 changes: 8 additions & 4 deletions lib/src/dto/payload.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class Payload {
String billingState;
String billingCountry;
String redirectUrl;
String paymentType;

Payload.initFrmInitializer(RavePayInitializer i)
: this.amount = i.amount.toString(),
Expand Down Expand Up @@ -81,25 +82,26 @@ class Payload {
this.txRef,
this.cardBIN});

Map<String, dynamic> toJson() {
Map<String, dynamic> toJson(String paymentType) {
var json = <String, dynamic>{
"narration": narration,
"expirymonth": expiryMonth,
"PBFPubKey": pbfPubKey,
"lastname": lastName,
"firstname": firstName,
"currency": currency,
"country": country,
"amount": amount,
"email": email,
"expiryyear": expiryYear,
"txRef": txRef,
"redirect_url": redirectUrl,
};

putIfNotNull(map: json, key: "payment_type", value: paymentType);
putIfNotNull(map: json, key: "expirymonth", value: expiryMonth);
putIfNotNull(map: json, key: "expiryyear", value: expiryYear);
putIfNotNull(map: json, key: "cvv", value: cvv);
putIfNotNull(map: json, key: "cardno", value: cardNo);
putIfNotNull(map: json, key: "accountbank", value: bank.code);
putIfNotNull(map: json, key: "accountbank", value: bank?.code);
putIfNotNull(map: json, key: "bvn", value: bvn);
putIfNotNull(map: json, key: "accountnumber", value: accountNumber);
putIfNotNull(map: json, key: "passcode", value: passCode);
Expand Down Expand Up @@ -134,6 +136,8 @@ class Payload {
? null
: subAccounts.map((a) => a.toJson()).toList());

print("Json = $json");

return json;
}
}
25 changes: 22 additions & 3 deletions lib/src/manager/account_transaction_manager.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart' hide ConnectionState;
import 'package:rave_flutter/src/blocs/connection_bloc.dart';
import 'package:rave_flutter/src/common/validator_utills.dart';
import 'package:rave_flutter/src/dto/charge_request_body.dart';
import 'package:rave_flutter/src/exception/exception.dart';
import 'package:rave_flutter/src/manager/base_transaction_manager.dart';
Expand All @@ -14,10 +15,28 @@ class AccountTransactionManager extends BaseTransactionManager {
charge() async {
setConnectionState(ConnectionState.waiting);
try {
var response =
await service.charge(ChargeRequestBody.fromPayload(payload));

var response = await service.charge(
ChargeRequestBody.fromPayload(payload: payload, type: "account"),
);
setConnectionState(ConnectionState.done);

flwRef = response.flwRef;

if (response.hasData) {
final authUrl = response.authUrl;
final authUrlIsValid = ValidatorUtils.isUrlValid(authUrl);
if (authUrlIsValid) {
showWebAuthorization(authUrl);
} else {
if (response.validateInstruction != null) {
onOtpRequested(response.validateInstruction);
} else if (response.validateInstructions != null) {
onOtpRequested(response.validateInstructions);
} else {
onOtpRequested();
}
}
}
} on RaveException catch (e) {
handleError(e: e);
}
Expand Down
52 changes: 52 additions & 0 deletions lib/src/manager/base_transaction_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ import 'package:flutter/material.dart' hide State, ConnectionState;
import 'package:rave_flutter/src/blocs/connection_bloc.dart';
import 'package:rave_flutter/src/blocs/transaction_bloc.dart';
import 'package:rave_flutter/src/common/rave_pay_initializer.dart';
import 'package:rave_flutter/src/common/strings.dart';
import 'package:rave_flutter/src/dto/fee_check_request_body.dart';
import 'package:rave_flutter/src/dto/payload.dart';
import 'package:rave_flutter/src/dto/validate_charge_request_body.dart';
import 'package:rave_flutter/src/exception/exception.dart';
import 'package:rave_flutter/src/models/fee_check_model.dart';
import 'package:rave_flutter/src/models/requery_model.dart';
import 'package:rave_flutter/src/rave_result.dart';
import 'package:rave_flutter/src/repository/repository.dart';
import 'package:rave_flutter/src/services/transaction_service.dart';
import 'package:rave_flutter/src/ui/common/webview_widget.dart';

abstract class BaseTransactionManager {
final TransactionService service = TransactionService.instance;
Expand Down Expand Up @@ -60,6 +63,55 @@ abstract class BaseTransactionManager {
}
}

onOtpRequested([String message = Strings.enterOtp]) {
transactionBloc.setState(TransactionState(
state: State.otp,
data: message,
callback: (otp) {
_validateCharge(otp);
}));
}

showWebAuthorization(String authUrl) async {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => WebViewWidget(
authUrl: authUrl,
callbackUrl: payload.redirectUrl,
),
),
);
reQueryTransaction();
}

_validateCharge(otp) async {
try {
setConnectionState(ConnectionState.waiting);
var response = await service.validateCardCharge(ValidateChargeRequestBody(
transactionReference: flwRef,
otp: otp,
pBFPubKey: payload.pbfPubKey));
setConnectionState(ConnectionState.done);

var status = response.status;
if (status == null) {
reQueryTransaction();
return;
}

if (status.toLowerCase() == "success") {
reQueryTransaction();
} else {
onTransactionComplete(RaveResult(
status: RaveStatus.error,
message: response.message,
));
}
} catch (e) {
reQueryTransaction();
}
}

displayFeeDialog(FeeCheckResponseModel model) {
closeDialog() {
Navigator.of(context).pop();
Expand Down
61 changes: 5 additions & 56 deletions lib/src/manager/card_transaction_manager.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import 'package:flutter/cupertino.dart' hide State, ConnectionState;
import 'package:flutter/material.dart' hide State, ConnectionState;
import 'package:rave_flutter/rave_flutter.dart';
import 'package:rave_flutter/src/blocs/connection_bloc.dart';
import 'package:rave_flutter/src/blocs/transaction_bloc.dart';
import 'package:rave_flutter/src/common/rave_constants.dart';
import 'package:rave_flutter/src/common/strings.dart';
import 'package:rave_flutter/src/dto/charge_request_body.dart';
import 'package:rave_flutter/src/dto/validate_charge_request_body.dart';
import 'package:rave_flutter/src/exception/exception.dart';
import 'package:rave_flutter/src/manager/base_transaction_manager.dart';
import 'package:rave_flutter/src/ui/common/webview_widget.dart';

class CardTransactionManager extends BaseTransactionManager {
CardTransactionManager(
Expand All @@ -25,7 +22,7 @@ class CardTransactionManager extends BaseTransactionManager {
setConnectionState(ConnectionState.waiting);
try {
var response =
await service.charge(ChargeRequestBody.fromPayload(payload));
await service.charge(ChargeRequestBody.fromPayload(payload: payload));

setConnectionState(ConnectionState.done);

Expand Down Expand Up @@ -54,8 +51,7 @@ class CardTransactionManager extends BaseTransactionManager {
} else if (authModelUsed == RaveConstants.GTB_OTP ||
authModelUsed == RaveConstants.ACCESS_OTP ||
authModelUsed.contains("OTP")) {
_onOtpRequested(
response.chargeResponseMessage ?? Strings.enterOtp);
onOtpRequested(response.chargeResponseMessage);
} else if (authModelUsed == RaveConstants.NO_AUTH) {
_onNoAuthUsed();
}
Expand Down Expand Up @@ -112,35 +108,16 @@ class CardTransactionManager extends BaseTransactionManager {

_onVBVAuthModelUsed(String authUrl) => _onAVSVBVSecureCodeModelUsed(authUrl);

_onOtpRequested(String message) {
transactionBloc.setState(TransactionState(
state: State.otp,
data: message,
callback: (otp) {
_validateCharge(otp);
}));
}

_onNoAuthUsed() => reQueryTransaction();

_onAVSVBVSecureCodeModelUsed(String authUrl) async {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => WebViewWidget(
authUrl: authUrl,
callbackUrl: payload.redirectUrl,
),
),
);
reQueryTransaction();
}
_onAVSVBVSecureCodeModelUsed(String authUrl) => showWebAuthorization(authUrl);

_handlePinOrBillingInput() async {
setConnectionState(ConnectionState.waiting);

try {
var response =
await service.charge(ChargeRequestBody.fromPayload(payload));
await service.charge(ChargeRequestBody.fromPayload(payload: payload));
setConnectionState(ConnectionState.done);

flwRef = response.flwRef;
Expand All @@ -153,7 +130,7 @@ class CardTransactionManager extends BaseTransactionManager {
} else if (responseCode == "02") {
var authModel = response.authModelUsed?.toUpperCase();
if (authModel == RaveConstants.PIN) {
_onOtpRequested(response.chargeResponseMessage);
onOtpRequested(response.chargeResponseMessage);
} else if (authModel == RaveConstants.AVS_VBVSECURECODE ||
authModel == RaveConstants.VBV) {
_onAVSVBVSecureCodeModelUsed(response.authUrl);
Expand All @@ -179,32 +156,4 @@ class CardTransactionManager extends BaseTransactionManager {
handleError(e: e);
}
}

_validateCharge(otp) async {
try {
setConnectionState(ConnectionState.waiting);
var response = await service.validateCardCharge(ValidateChargeRequestBody(
transactionReference: flwRef,
otp: otp,
pBFPubKey: payload.pbfPubKey));
setConnectionState(ConnectionState.done);

var status = response.status;
if (status == null) {
reQueryTransaction();
return;
}

if (status.toLowerCase() == "success") {
reQueryTransaction();
} else {
onTransactionComplete(RaveResult(
status: RaveStatus.error,
message: response.message,
));
}
} catch (e) {
reQueryTransaction();
}
}
}
3 changes: 3 additions & 0 deletions lib/src/models/charge_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class ChargeResponseModel extends Equatable {
final String status;
final String message;
final String validateInstructions;
final String validateInstruction;
final String suggestedAuth;
final String chargeResponseCode;
final String authModelUsed;
Expand Down Expand Up @@ -36,6 +37,7 @@ class ChargeResponseModel extends Equatable {
@required this.redirectUrl,
@required this.hasData,
@required this.rawResponse,
@required this.validateInstruction,
});

factory ChargeResponseModel.fromJson(Map<String, dynamic> json) {
Expand All @@ -48,6 +50,7 @@ class ChargeResponseModel extends Equatable {
chargeResponseCode: data["chargeResponseCode"],
authModelUsed: data["authModelUsed"],
flwRef: data["flwRef"],
validateInstruction: data["validateInstruction"],
validateInstructions: data.containsKey("validateInstructions")
? data["validateInstructions"]["instruction"]
: null,
Expand Down
Loading

0 comments on commit e9653f8

Please sign in to comment.