|
|
|
|
@ -11,17 +11,29 @@ import 'package:flutter_paytabs_bridge/PaymentSdkTransactionType.dart';
|
|
|
|
|
import 'package:flutter_paytabs_bridge/flutter_paytabs_bridge.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/core/api_consts.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/core/app_state.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/core/cache_consts.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/core/dependencies.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/core/enums.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/core/paytabs_config.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/core/utils/utils.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/features/paytabs/models/paytabs_transaction_response_model.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/features/payfort/models/payfort_request_insert_model.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/features/payfort/models/payfort_response_insert_model.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/features/payfort/payfort_repo.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
|
|
|
|
|
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
|
|
|
|
|
|
|
|
|
|
class PayTabsViewModel extends ChangeNotifier {
|
|
|
|
|
late PaymentSdkConfigurationDetails paymentConfiguration;
|
|
|
|
|
final AppState appState;
|
|
|
|
|
final PayfortRepo payfortRepo;
|
|
|
|
|
final ErrorHandlerService errorHandlerService;
|
|
|
|
|
late PaytabsTransactionResponseModel paytabsTransactionResponseModel;
|
|
|
|
|
|
|
|
|
|
PayTabsViewModel({
|
|
|
|
|
required this.appState,
|
|
|
|
|
required this.payfortRepo,
|
|
|
|
|
required this.errorHandlerService,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
setPaymentConfiguration(String paymentDescription, num amount, {bool isAddCard = false}) {
|
|
|
|
|
@ -152,6 +164,42 @@ class PayTabsViewModel extends ChangeNotifier {
|
|
|
|
|
notifyListeners();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> paytabsRequestInsert({required PayfortRequestInsertModel payfortRequestInsertModel, Function(dynamic)? onSuccess, Function(String)? onError}) async {
|
|
|
|
|
final result = await payfortRepo.payfortRequestInsert(payfortRequestInsertModel: payfortRequestInsertModel);
|
|
|
|
|
|
|
|
|
|
result.fold(
|
|
|
|
|
(failure) async => await errorHandlerService.handleError(failure: failure),
|
|
|
|
|
(apiResponse) {
|
|
|
|
|
if (apiResponse.messageStatus == 2) {
|
|
|
|
|
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
|
|
|
|
|
} else if (apiResponse.messageStatus == 1) {
|
|
|
|
|
notifyListeners();
|
|
|
|
|
if (onSuccess != null) {
|
|
|
|
|
onSuccess(apiResponse);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> paytabsResponseInsert({required PayfortResponseInsertModel payfortResponseInsertModel, Function(dynamic)? onSuccess, Function(String)? onError}) async {
|
|
|
|
|
final result = await payfortRepo.payfortResponseInsert(payfortResponseInsertModel: payfortResponseInsertModel);
|
|
|
|
|
|
|
|
|
|
result.fold(
|
|
|
|
|
(failure) async => await errorHandlerService.handleError(failure: failure),
|
|
|
|
|
(apiResponse) {
|
|
|
|
|
if (apiResponse.messageStatus == 2) {
|
|
|
|
|
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
|
|
|
|
|
} else if (apiResponse.messageStatus == 1) {
|
|
|
|
|
notifyListeners();
|
|
|
|
|
if (onSuccess != null) {
|
|
|
|
|
onSuccess(apiResponse);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
startApplePayPayment({Function(PaytabsTransactionResponseModel)? onSuccess, Function(String)? onError}) async {
|
|
|
|
|
bool _callbackFired = false; // prevent duplicate callback invocations
|
|
|
|
|
|
|
|
|
|
@ -189,41 +237,132 @@ class PayTabsViewModel extends ChangeNotifier {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
startCardPayment({Function(PaytabsTransactionResponseModel)? onSuccess, Function(String)? onError}) {
|
|
|
|
|
startCardPayment({
|
|
|
|
|
required String paymentOption,
|
|
|
|
|
required String liveServiceID,
|
|
|
|
|
required String isScheduleLiveCare,
|
|
|
|
|
required String appointmentDate,
|
|
|
|
|
required String appointmentNo,
|
|
|
|
|
required String doctorID,
|
|
|
|
|
required String transactionID,
|
|
|
|
|
required String amount,
|
|
|
|
|
required String fileNumber,
|
|
|
|
|
required String orderDescription,
|
|
|
|
|
required String serviceID,
|
|
|
|
|
required String projectID,
|
|
|
|
|
Function(PaytabsTransactionResponseModel)? onSuccess,
|
|
|
|
|
Function(String)? onError,
|
|
|
|
|
}) async {
|
|
|
|
|
bool _callbackFired = false; // prevent duplicate callback invocations
|
|
|
|
|
|
|
|
|
|
FlutterPaytabsBridge.startCardPayment(paymentConfiguration, (event) {
|
|
|
|
|
if (_callbackFired) return; // ignore any subsequent callback calls
|
|
|
|
|
try {
|
|
|
|
|
LoaderBottomSheet.showLoader();
|
|
|
|
|
|
|
|
|
|
final transactionDetails = event["data"] as Map<Object?, Object?>?;
|
|
|
|
|
if (event["status"] == "success") {
|
|
|
|
|
_callbackFired = true;
|
|
|
|
|
// Cast Map<Object?, Object?> to Map<String, dynamic>
|
|
|
|
|
final data = Map<String, dynamic>.from(event["data"] as Map);
|
|
|
|
|
paytabsTransactionResponseModel = PaytabsTransactionResponseModel.fromJson(data);
|
|
|
|
|
if (paytabsTransactionResponseModel.isSuccess!) {
|
|
|
|
|
onSuccess!(paytabsTransactionResponseModel);
|
|
|
|
|
} else {
|
|
|
|
|
// Transaction was processed but failed
|
|
|
|
|
final reason =
|
|
|
|
|
transactionDetails?["payResponseReturn"] ?? transactionDetails?["responseMessage"] ?? transactionDetails?["message"] ?? "Unknown error";
|
|
|
|
|
final responseCode = transactionDetails?["responseCode"] ?? "";
|
|
|
|
|
final errorMessage =
|
|
|
|
|
responseCode.toString().isNotEmpty ? "Transaction failed (Code: $responseCode): $reason" : "Transaction failed: $reason";
|
|
|
|
|
onError!(errorMessage);
|
|
|
|
|
// Create PayfortRequestInsertModel (same as Payfort implementation)
|
|
|
|
|
PayfortRequestInsertModel payfortRequestInsertModel = PayfortRequestInsertModel();
|
|
|
|
|
|
|
|
|
|
payfortRequestInsertModel.commandType = "SALE";
|
|
|
|
|
payfortRequestInsertModel.amount = num.parse(amount);
|
|
|
|
|
payfortRequestInsertModel.customerEmail = getIt.get<AppState>().getAuthenticatedUser()!.emailAddress;
|
|
|
|
|
payfortRequestInsertModel.orderDescription = orderDescription;
|
|
|
|
|
payfortRequestInsertModel.serviceID = serviceID;
|
|
|
|
|
payfortRequestInsertModel.paymentOption = paymentOption;
|
|
|
|
|
payfortRequestInsertModel.clientRequestID = transactionID;
|
|
|
|
|
payfortRequestInsertModel.projectID = projectID;
|
|
|
|
|
payfortRequestInsertModel.fileNumber = getIt.get<AppState>().getAuthenticatedUser()!.patientId.toString();
|
|
|
|
|
payfortRequestInsertModel.customerName = "${getIt.get<AppState>().getAuthenticatedUser()!.firstName} ${getIt.get<AppState>().getAuthenticatedUser()!.lastName}";
|
|
|
|
|
payfortRequestInsertModel.currency = getIt.get<AppState>().getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED";
|
|
|
|
|
payfortRequestInsertModel.liveServiceID = liveServiceID;
|
|
|
|
|
payfortRequestInsertModel.latitude = getIt.get<AppState>().userLat.toString();
|
|
|
|
|
payfortRequestInsertModel.longitude = getIt.get<AppState>().userLong.toString();
|
|
|
|
|
payfortRequestInsertModel.merchantReference = transactionID;
|
|
|
|
|
payfortRequestInsertModel.deviceToken = await Utils.getStringFromPrefs(CacheConst.pushToken);
|
|
|
|
|
payfortRequestInsertModel.language = getIt.get<AppState>().isArabic() ? "ar" : "en";
|
|
|
|
|
payfortRequestInsertModel.integrationId = "2"; // PayTabs integration ID
|
|
|
|
|
payfortRequestInsertModel.isSchedule = isScheduleLiveCare;
|
|
|
|
|
payfortRequestInsertModel.appointmentDate = appointmentDate;
|
|
|
|
|
payfortRequestInsertModel.appointmentNo = appointmentNo;
|
|
|
|
|
payfortRequestInsertModel.doctorID = doctorID;
|
|
|
|
|
|
|
|
|
|
// Call request insert API before payment
|
|
|
|
|
await paytabsRequestInsert(payfortRequestInsertModel: payfortRequestInsertModel);
|
|
|
|
|
|
|
|
|
|
LoaderBottomSheet.hideLoader();
|
|
|
|
|
|
|
|
|
|
// Start PayTabs payment
|
|
|
|
|
FlutterPaytabsBridge.startCardPayment(paymentConfiguration, (event) async {
|
|
|
|
|
if (_callbackFired) return; // ignore any subsequent callback calls
|
|
|
|
|
|
|
|
|
|
final transactionDetails = event["data"] as Map<Object?, Object?>?;
|
|
|
|
|
if (event["status"] == "success") {
|
|
|
|
|
_callbackFired = true;
|
|
|
|
|
|
|
|
|
|
LoaderBottomSheet.showLoader();
|
|
|
|
|
|
|
|
|
|
// Cast Map<Object?, Object?> to Map<String, dynamic>
|
|
|
|
|
final data = Map<String, dynamic>.from(event["data"] as Map);
|
|
|
|
|
paytabsTransactionResponseModel = PaytabsTransactionResponseModel.fromJson(data);
|
|
|
|
|
|
|
|
|
|
// Create PayfortResponseInsertModel (same as Payfort implementation)
|
|
|
|
|
PayfortResponseInsertModel payfortResponseInsertModel = PayfortResponseInsertModel();
|
|
|
|
|
|
|
|
|
|
payfortResponseInsertModel.fortId = paytabsTransactionResponseModel.transactionReference ?? "";
|
|
|
|
|
payfortResponseInsertModel.commandType = paytabsTransactionResponseModel.transactionType ?? "SALE";
|
|
|
|
|
// payfortResponseInsertModel.amount = paytabsTransactionResponseModel.tranTotal ?? 0;
|
|
|
|
|
payfortResponseInsertModel.amount = num.parse(amount);
|
|
|
|
|
payfortResponseInsertModel.sadadOLP = "";
|
|
|
|
|
payfortResponseInsertModel.paymentOption = paytabsTransactionResponseModel.paymentInfo?.paymentMethod ?? "";
|
|
|
|
|
payfortResponseInsertModel.customerIP = "";
|
|
|
|
|
payfortResponseInsertModel.eCI = "";
|
|
|
|
|
payfortResponseInsertModel.responseMessage = paytabsTransactionResponseModel.payResponseReturn ?? "";
|
|
|
|
|
payfortResponseInsertModel.cardNumber = paytabsTransactionResponseModel.paymentInfo!.paymentDescription;
|
|
|
|
|
payfortResponseInsertModel.cardBin = "";
|
|
|
|
|
payfortResponseInsertModel.installmentsNumber = 0;
|
|
|
|
|
payfortResponseInsertModel.status = paytabsTransactionResponseModel.isSuccess! ? "success" : "failed";
|
|
|
|
|
payfortResponseInsertModel.merchantRef = transactionID;
|
|
|
|
|
payfortResponseInsertModel.isRefund = false;
|
|
|
|
|
payfortResponseInsertModel.remmeberMe = true;
|
|
|
|
|
payfortResponseInsertModel.reconciliationReference = "";
|
|
|
|
|
|
|
|
|
|
// Call response insert API after payment
|
|
|
|
|
await paytabsResponseInsert(payfortResponseInsertModel: payfortResponseInsertModel);
|
|
|
|
|
|
|
|
|
|
LoaderBottomSheet.hideLoader();
|
|
|
|
|
|
|
|
|
|
if (paytabsTransactionResponseModel.isSuccess!) {
|
|
|
|
|
if (onSuccess != null) {
|
|
|
|
|
onSuccess(paytabsTransactionResponseModel);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Transaction was processed but failed
|
|
|
|
|
final reason = transactionDetails?["payResponseReturn"] ?? transactionDetails?["responseMessage"] ?? transactionDetails?["message"] ?? "Unknown error";
|
|
|
|
|
final responseCode = transactionDetails?["responseCode"] ?? "";
|
|
|
|
|
final errorMessage = responseCode.toString().isNotEmpty ? "Transaction failed (Code: $responseCode): $reason" : "Transaction failed: $reason";
|
|
|
|
|
if (onError != null) {
|
|
|
|
|
onError(errorMessage);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (event["status"] == "error") {
|
|
|
|
|
_callbackFired = true;
|
|
|
|
|
final errorMessage = event["message"] ?? "An error occurred";
|
|
|
|
|
debugPrint("Error occurred in transaction: $errorMessage");
|
|
|
|
|
debugPrint("Full error event: $event");
|
|
|
|
|
if (onError != null) {
|
|
|
|
|
onError(errorMessage);
|
|
|
|
|
}
|
|
|
|
|
} else if (event["status"] == "event") {
|
|
|
|
|
// Intermediate SDK events – do NOT mark _callbackFired, just log
|
|
|
|
|
final eventMessage = event["message"] ?? "Event occurred";
|
|
|
|
|
debugPrint("Event occurred: $eventMessage");
|
|
|
|
|
}
|
|
|
|
|
} else if (event["status"] == "error") {
|
|
|
|
|
_callbackFired = true;
|
|
|
|
|
final errorMessage = event["message"] ?? "An error occurred";
|
|
|
|
|
debugPrint("Error occurred in transaction: $errorMessage");
|
|
|
|
|
debugPrint("Full error event: $event");
|
|
|
|
|
onError!(errorMessage);
|
|
|
|
|
} else if (event["status"] == "event") {
|
|
|
|
|
// Intermediate SDK events – do NOT mark _callbackFired, just log
|
|
|
|
|
final eventMessage = event["message"] ?? "Event occurred";
|
|
|
|
|
debugPrint("Event occurred: $eventMessage");
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
debugPrint("PayTabs Payment Error: $error");
|
|
|
|
|
LoaderBottomSheet.hideLoader();
|
|
|
|
|
if (onError != null) {
|
|
|
|
|
onError("Payment initialization failed: $error");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
startAlternatePayment({Function(PaytabsTransactionResponseModel)? onSuccess, Function(String)? onError}) {
|
|
|
|
|
|