From 445d4d938502aff21b1dbce1eeb97703b47ff540 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 20 Sep 2026 10:01:57 +0300 Subject: [PATCH 1/6] Updates --- pubspec.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pubspec.yaml b/pubspec.yaml index 82ae76ac..c030a1f4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,8 +2,8 @@ name: hmg_patient_app_new description: "New HMG Patient App" publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 0.0.48+49 -#version: 0.0.16+1 +version: 0.0.49+50 +#version: 0.0.17+1 environment: sdk: ">=3.6.0 <4.0.0" @@ -113,6 +113,7 @@ dependencies: cloudflare_turnstile: ^3.7.2 freerasp: ^8.2.1 safe_device: ^1.4.1 + myfatoorah_flutter: ^3.3.2 dev_dependencies: flutter_test: From a4e1ec4459cb947cdc72dcad6ff74c1b8a275f0e Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 20 Sep 2026 10:02:38 +0300 Subject: [PATCH 2/6] updates --- lib/core/api_consts.dart | 17 ++++++++++++++++- lib/core/app_state.dart | 6 ++++++ .../my_appointments_view_model.dart | 6 +++--- .../book_appointment/widgets/doctor_card.dart | 3 +++ 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index 45d6f48c..712866af 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -1,6 +1,7 @@ import 'package:amazon_payfort/amazon_payfort.dart'; import 'package:flutter_amazonpaymentservices/environment_type.dart'; import 'package:hmg_patient_app_new/core/enums.dart'; +import 'package:myfatoorah_flutter/myfatoorah_flutter.dart'; class ApiConsts { static const maxSmallScreen = 660; @@ -44,12 +45,17 @@ class ApiConsts { // var payFortEnvironment = FortEnvironment.test; // var applePayMerchantId = "merchant.com.hmgwebservices.uat"; + static var myFatoorahEnvironmentType = MFEnvironment.TEST; + static var myFatoorahCountry = MFCountry.SAUDIARABIA; + static setBackendURLs() { switch (appEnvironmentType) { case AppEnvironmentTypeEnum.prod: baseUrl = "https://hmgwebservices.com/"; payFortEnvironment = FortEnvironment.production; payFortEnvironmentType = EnvironmentType.production; + myFatoorahEnvironmentType = MFEnvironment.LIVE; + myFatoorahCountry = MFCountry.SAUDIARABIA; applePayMerchantId = "merchant.com.hmgwebservices"; SERVICE_URL = "https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx"; TAMARA_URL = "https://mdlaboratories.com/tamaralive/Home/Checkout"; @@ -66,6 +72,8 @@ class ApiConsts { baseUrl = "https://uat.hmgwebservices.com/"; payFortEnvironment = FortEnvironment.test; payFortEnvironmentType = EnvironmentType.sandbox; + myFatoorahEnvironmentType = MFEnvironment.TEST; + myFatoorahCountry = MFCountry.KUWAIT; applePayMerchantId = "merchant.com.hmgwebservices.uat"; SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx'; TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; @@ -77,12 +85,13 @@ class ApiConsts { symptomsCheckerApi = symptomsCheckerApiUAT; symptomsCheckerUsername = 'guest_user'; symptomsCheckerPassword = '123456'; - break; case AppEnvironmentTypeEnum.uat: baseUrl = "https://uat.hmgwebservices.com/"; payFortEnvironment = FortEnvironment.test; payFortEnvironmentType = EnvironmentType.sandbox; + myFatoorahEnvironmentType = MFEnvironment.TEST; + myFatoorahCountry = MFCountry.KUWAIT; applePayMerchantId = "merchant.com.hmgwebservices.uat"; SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx'; TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; @@ -100,6 +109,8 @@ class ApiConsts { baseUrl = "https://webservices.hmg.com/"; payFortEnvironment = FortEnvironment.production; payFortEnvironmentType = EnvironmentType.production; + myFatoorahEnvironmentType = MFEnvironment.LIVE; + myFatoorahCountry = MFCountry.SAUDIARABIA; applePayMerchantId = "merchant.com.hmgwebservices"; SERVICE_URL = "https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx"; TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; @@ -117,6 +128,8 @@ class ApiConsts { baseUrl = "https://uat.hmgwebservices.com/"; payFortEnvironment = FortEnvironment.test; payFortEnvironmentType = EnvironmentType.sandbox; + myFatoorahEnvironmentType = MFEnvironment.TEST; + myFatoorahCountry = MFCountry.KUWAIT; applePayMerchantId = "merchant.com.hmgwebservices.uat"; SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx'; TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; @@ -134,6 +147,8 @@ class ApiConsts { baseUrl = "https://uat.hmgwebservices.com/"; payFortEnvironment = FortEnvironment.test; payFortEnvironmentType = EnvironmentType.sandbox; + myFatoorahEnvironmentType = MFEnvironment.TEST; + myFatoorahCountry = MFCountry.KUWAIT; applePayMerchantId = "merchant.com.hmgwebservices.uat"; SERVICE_URL = 'https://uat.hmgwebservices.com/HMGPayment/pages/SendPayFortRequest.aspx'; TAMARA_URL = "https://epharmacy.hmg.com/tamara/Home/Checkout"; diff --git a/lib/core/app_state.dart b/lib/core/app_state.dart index 0d015922..ef5e306b 100644 --- a/lib/core/app_state.dart +++ b/lib/core/app_state.dart @@ -48,12 +48,18 @@ class AppState { bool isPaytabsEnabled = false; bool isPayfortHostedPageEnabled = true; + bool isMyFatoorahEnabled = false; void setIsPaytabsEnabled(bool value) { isPaytabsEnabled = value; // isPaytabsEnabled = true; } + void setIsMyFatoorahEnabled(bool value) { + isMyFatoorahEnabled = value; + // isMyFatoorahEnabled = true; + } + void setIsPayfortHostedPageEnabled(bool value) { isPayfortHostedPageEnabled = value; // isPayfortHostedPageEnabled = false; diff --git a/lib/features/my_appointments/my_appointments_view_model.dart b/lib/features/my_appointments/my_appointments_view_model.dart index b153c556..b2b990db 100644 --- a/lib/features/my_appointments/my_appointments_view_model.dart +++ b/lib/features/my_appointments/my_appointments_view_model.dart @@ -772,9 +772,9 @@ class MyAppointmentsViewModel extends ChangeNotifier { patientMyDoctorsList = apiResponse.data!; isPatientMyDoctorsLoading = false; - if (!isTop8) { - isMyDoctorsDataToBeLoaded = false; - } + // if (!isTop8) { + isMyDoctorsDataToBeLoaded = false; + // } notifyListeners(); if (onSuccess != null) { diff --git a/lib/presentation/book_appointment/widgets/doctor_card.dart b/lib/presentation/book_appointment/widgets/doctor_card.dart index 23a9cbcd..b14a3822 100644 --- a/lib/presentation/book_appointment/widgets/doctor_card.dart +++ b/lib/presentation/book_appointment/widgets/doctor_card.dart @@ -219,6 +219,9 @@ class DoctorCard extends StatelessWidget { ); } else { bookAppointmentsViewModel.setSelectedDoctor(doctorsListResponseModel); + GetClinicsListResponseModel selectedClinic = GetClinicsListResponseModel( + clinicID: doctorsListResponseModel.clinicID, clinicDescription: doctorsListResponseModel.clinicName, isLiveCareClinicAndOnline: false, liveCareServiceID: 0, liveCareClinicID: 0); + bookAppointmentsViewModel.setSelectedClinic(selectedClinic); LoaderBottomSheet.showLoader(); bookAppointmentsViewModel.isLiveCareSchedule ? await bookAppointmentsViewModel.getLiveCareDoctorFreeSlots( From b78c83a32dce471b81418e8fc15fb59f8b8ce889 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 20 Sep 2026 11:02:29 +0300 Subject: [PATCH 3/6] updates --- lib/core/api/api_client.dart | 2 +- lib/features/lab/lab_view_model.dart | 12 ++++++------ lib/features/myfatoorah/myfatoorah_view_model.dart | 13 +++++++++++++ 3 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 lib/features/myfatoorah/myfatoorah_view_model.dart diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index 4c961843..f9cf2fa2 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -211,7 +211,7 @@ class ApiClientImp implements ApiClient { } // body['TokenID'] = "@dm!n"; - // body['PatientID'] = 5422188; + // body['PatientID'] = 1987471; // body['PatientID'] = 53320; // body['PatientTypeID'] = 1; // body['PatientOutSA'] = 0; diff --git a/lib/features/lab/lab_view_model.dart b/lib/features/lab/lab_view_model.dart index 1c25ef9d..d7f5bb62 100644 --- a/lib/features/lab/lab_view_model.dart +++ b/lib/features/lab/lab_view_model.dart @@ -209,12 +209,12 @@ class LabViewModel extends ChangeNotifier { final result = await labRepo.getLabResultReportPDF(labOrder: labOrder); result.fold( - (failure) async => await errorHandlerService.handleError( - failure: failure, - onOkPressed: () { - onError!(failure.message); - }, - ), + // (failure) async => await errorHandlerService.handleError( + (failure) async { + if (onError != null) { + onError(failure.message); + } + }, (apiResponse) { if (apiResponse.messageStatus == 2) { onError!(apiResponse.errorMessage!); diff --git a/lib/features/myfatoorah/myfatoorah_view_model.dart b/lib/features/myfatoorah/myfatoorah_view_model.dart new file mode 100644 index 00000000..8a4160e9 --- /dev/null +++ b/lib/features/myfatoorah/myfatoorah_view_model.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import 'package:hmg_patient_app_new/core/app_state.dart'; +import 'package:hmg_patient_app_new/services/error_handler_service.dart'; + +class MyFatoorahViewModel extends ChangeNotifier { + final AppState appState; + final ErrorHandlerService errorHandlerService; + + MyFatoorahViewModel({ + required this.appState, + required this.errorHandlerService, + }); +} From d43022bbb4ece625d945723bc1f000c19d1f4f42 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Sun, 20 Sep 2026 17:07:21 +0300 Subject: [PATCH 4/6] MyFatoorah Payment integration in progress --- lib/core/api/api_client.dart | 2 +- lib/core/api_consts.dart | 2 +- lib/core/app_state.dart | 5 ++- lib/core/dependencies.dart | 6 +++ lib/core/myFatoorah_config.dart | 5 +++ .../authentication_view_model.dart | 2 + .../myfatoorah/myfatoorah_view_model.dart | 42 +++++++++++++++++++ lib/main.dart | 4 ++ .../immediate_livecare_payment_page.dart | 25 ++++++++++- 9 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 lib/core/myFatoorah_config.dart diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index f9cf2fa2..d6448e8f 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -210,7 +210,7 @@ class ApiClientImp implements ApiClient { body['TokenID'] = "@dm!n"; } - // body['TokenID'] = "@dm!n"; + body['TokenID'] = "@dm!n"; // body['PatientID'] = 1987471; // body['PatientID'] = 53320; // body['PatientTypeID'] = 1; diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index 712866af..588be9ec 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -6,7 +6,7 @@ import 'package:myfatoorah_flutter/myfatoorah_flutter.dart'; class ApiConsts { static const maxSmallScreen = 660; - static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.prod; + static AppEnvironmentTypeEnum appEnvironmentType = AppEnvironmentTypeEnum.uat; // static String baseUrl = 'https://uat.hmgwebservices.com/'; // HIS API URL UAT diff --git a/lib/core/app_state.dart b/lib/core/app_state.dart index ef5e306b..78432b23 100644 --- a/lib/core/app_state.dart +++ b/lib/core/app_state.dart @@ -49,6 +49,7 @@ class AppState { bool isPaytabsEnabled = false; bool isPayfortHostedPageEnabled = true; bool isMyFatoorahEnabled = false; + // bool isMyFatoorahEnabled = true; void setIsPaytabsEnabled(bool value) { isPaytabsEnabled = value; @@ -56,8 +57,8 @@ class AppState { } void setIsMyFatoorahEnabled(bool value) { - isMyFatoorahEnabled = value; - // isMyFatoorahEnabled = true; + // isMyFatoorahEnabled = value; + isMyFatoorahEnabled = true; } void setIsPayfortHostedPageEnabled(bool value) { diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart index b6c7fb38..a5093815 100644 --- a/lib/core/dependencies.dart +++ b/lib/core/dependencies.dart @@ -44,6 +44,7 @@ import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_rep import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_repo.dart'; import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_view_model.dart'; +import 'package:hmg_patient_app_new/features/myfatoorah/myfatoorah_view_model.dart'; import 'package:hmg_patient_app_new/features/notifications/notifications_repo.dart'; import 'package:hmg_patient_app_new/features/notifications/notifications_view_model.dart'; import 'package:hmg_patient_app_new/features/offers_and_discounts/offers_and_discounts_repo.dart'; @@ -380,6 +381,11 @@ class AppDependencies { errorHandlerService: getIt(), )); + getIt.registerLazySingleton(() => MyFatoorahViewModel( + appState: getIt(), + errorHandlerService: getIt(), + )); + getIt.registerLazySingleton( () => ClarityService(appState: getIt.get()), ); diff --git a/lib/core/myFatoorah_config.dart b/lib/core/myFatoorah_config.dart new file mode 100644 index 00000000..582ced3c --- /dev/null +++ b/lib/core/myFatoorah_config.dart @@ -0,0 +1,5 @@ +class MyFatoorahConfig { + + static const String configAPIKey = "SK_KWT_0auB76h3Frhj7aUBSZa6H5ei792eZoGAPh0bBxKsrgtyjqKgf38MPnZqzGqagErb"; + +} \ No newline at end of file diff --git a/lib/features/authentication/authentication_view_model.dart b/lib/features/authentication/authentication_view_model.dart index a8719f29..271c628d 100644 --- a/lib/features/authentication/authentication_view_model.dart +++ b/lib/features/authentication/authentication_view_model.dart @@ -1248,6 +1248,7 @@ class AuthenticationViewModel extends ChangeNotifier { _appState.setUserBloodGroup = activation.patientBlodType ?? "N/A"; _appState.setIsPaytabsEnabled(Utils.havePrivilege(120)); _appState.setIsPayfortHostedPageEnabled(Utils.havePrivilege(121)); + _appState.setIsMyFatoorahEnabled(Utils.havePrivilege(123)); // Refresh privileges after user switching to ensure correct privileges are loaded if (isSwitchUser) { @@ -1796,6 +1797,7 @@ class AuthenticationViewModel extends ChangeNotifier { _appState.setProjectsDetailList(projectDetailListModel); _appState.setIsPaytabsEnabled(Utils.havePrivilege(120)); _appState.setIsPayfortHostedPageEnabled(Utils.havePrivilege(121)); + _appState.setIsMyFatoorahEnabled(Utils.havePrivilege(123)); } }, ); diff --git a/lib/features/myfatoorah/myfatoorah_view_model.dart b/lib/features/myfatoorah/myfatoorah_view_model.dart index 8a4160e9..4e91f094 100644 --- a/lib/features/myfatoorah/myfatoorah_view_model.dart +++ b/lib/features/myfatoorah/myfatoorah_view_model.dart @@ -1,6 +1,12 @@ import 'package:flutter/material.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/enums.dart'; +import 'package:hmg_patient_app_new/core/myFatoorah_config.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart'; +import 'package:hmg_patient_app_new/theme/colors.dart'; +import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; +import 'package:myfatoorah_flutter/myfatoorah_flutter.dart'; class MyFatoorahViewModel extends ChangeNotifier { final AppState appState; @@ -10,4 +16,40 @@ class MyFatoorahViewModel extends ChangeNotifier { required this.appState, required this.errorHandlerService, }); + + // Payment Method ID + // 2: Credit/Debit Card + // 6: Mada + + initiateCardPayment({ + num amount = 10.0, + paymentDescription = "", + String displayCurrencyIso = MFCurrencyISO.KUWAIT_KWD, + Function(MFGetPaymentStatusResponse)? onSuccess, + Function(String)? onError, + }) async { + LoaderBottomSheet.showLoader(); + + await MFSDK.init(MyFatoorahConfig.configAPIKey, ApiConsts.myFatoorahCountry, ApiConsts.myFatoorahEnvironmentType); + + MFSDK.setUpActionBar(toolBarTitle: paymentDescription, toolBarTitleColor: "#ffffff", toolBarBackgroundColor: '#ED1C2B', isShowToolBar: true); + + var request = MFExecutePaymentRequest(paymentMethodId: 2, invoiceValue: amount); + request.displayCurrencyIso = displayCurrencyIso; + request.customerName = ApiConsts.appEnvironmentType == AppEnvironmentTypeEnum.uat ? "Test test" : "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}"; + request.customerEmail = "CustID_${appState.getAuthenticatedUser()!.patientId}@HMG.com"; + + await MFSDK.executePayment(request, appState.isArabic() ? MFLanguage.ARABIC : MFLanguage.ENGLISH, (invoiceId) { + LoaderBottomSheet.hideLoader(); + print(invoiceId); + }).then((value) { + if (onSuccess != null) { + onSuccess(value); + } + }).catchError((error) { + if (onError != null) { + onError(error.message); + } + }); + } } diff --git a/lib/main.dart b/lib/main.dart index 4e60c2a0..0fb6f773 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -35,6 +35,7 @@ import 'package:hmg_patient_app_new/features/my_appointments/appointment_rating_ import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.dart'; import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_view_model.dart'; +import 'package:hmg_patient_app_new/features/myfatoorah/myfatoorah_view_model.dart'; import 'package:hmg_patient_app_new/features/notifications/notifications_view_model.dart'; import 'package:hmg_patient_app_new/features/offers_and_discounts/offers_and_discounts_view_model.dart'; import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart'; @@ -303,6 +304,9 @@ void main() async { ChangeNotifierProvider( create: (_) => getIt.get(), ), + ChangeNotifierProvider( + create: (_) => getIt.get(), + ), ChangeNotifierProvider( create: (_) => getIt.get(), ) diff --git a/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart b/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart index 31defa56..dfb7497c 100644 --- a/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart +++ b/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart @@ -13,6 +13,7 @@ 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/utils/date_util.dart'; import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart'; +import 'package:hmg_patient_app_new/features/myfatoorah/myfatoorah_view_model.dart'; import 'package:hmg_patient_app_new/features/payfort/models/apple_pay_request_insert_model.dart'; import 'package:hmg_patient_app_new/core/utils/size_utils.dart'; import 'package:hmg_patient_app_new/core/utils/utils.dart'; @@ -33,6 +34,7 @@ import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart'; import 'package:hmg_patient_app_new/widgets/in_app_browser/InAppBrowser.dart'; import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; +import 'package:myfatoorah_flutter/MFEnums.dart'; import 'package:provider/provider.dart'; import 'package:smooth_corner/smooth_corner.dart'; @@ -49,6 +51,7 @@ class _ImmediateLiveCarePaymentPageState extends State(context, listen: false); payfortViewModel = Provider.of(context, listen: false); paytabsViewModel = Provider.of(context, listen: false); + myFatoorahViewModel = Provider.of(context, listen: false); return Scaffold( backgroundColor: AppColors.bgScaffoldColor, body: Consumer(builder: (context, myAppointmentsVM, child) { @@ -298,7 +302,26 @@ class _ImmediateLiveCarePaymentPageState extends State Date: Mon, 21 Sep 2026 17:35:38 +0300 Subject: [PATCH 5/6] MyFatoorah implementation contd. --- lib/core/api/api_client.dart | 2 +- lib/core/dependencies.dart | 1 + .../myfatoorah/myfatoorah_view_model.dart | 150 +++++++++++++++++- .../immediate_livecare_payment_page.dart | 133 ++++++++++++++-- 4 files changed, 268 insertions(+), 18 deletions(-) diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index d6448e8f..da0954d4 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -211,7 +211,7 @@ class ApiClientImp implements ApiClient { } body['TokenID'] = "@dm!n"; - // body['PatientID'] = 1987471; + // body['PatientID'] = 7000792; // body['PatientID'] = 53320; // body['PatientTypeID'] = 1; // body['PatientOutSA'] = 0; diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart index a5093815..37fd936b 100644 --- a/lib/core/dependencies.dart +++ b/lib/core/dependencies.dart @@ -384,6 +384,7 @@ class AppDependencies { getIt.registerLazySingleton(() => MyFatoorahViewModel( appState: getIt(), errorHandlerService: getIt(), + payfortRepo: getIt(), )); getIt.registerLazySingleton( diff --git a/lib/features/myfatoorah/myfatoorah_view_model.dart b/lib/features/myfatoorah/myfatoorah_view_model.dart index 4e91f094..fb7a23fa 100644 --- a/lib/features/myfatoorah/myfatoorah_view_model.dart +++ b/lib/features/myfatoorah/myfatoorah_view_model.dart @@ -1,8 +1,18 @@ +import 'dart:developer'; + +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.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/myFatoorah_config.dart'; +import 'package:hmg_patient_app_new/core/utils/utils.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/generated/codegen_loader.g.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart'; import 'package:hmg_patient_app_new/theme/colors.dart'; import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; @@ -11,10 +21,12 @@ import 'package:myfatoorah_flutter/myfatoorah_flutter.dart'; class MyFatoorahViewModel extends ChangeNotifier { final AppState appState; final ErrorHandlerService errorHandlerService; + final PayfortRepo payfortRepo; MyFatoorahViewModel({ required this.appState, required this.errorHandlerService, + required this.payfortRepo, }); // Payment Method ID @@ -25,26 +37,94 @@ class MyFatoorahViewModel extends ChangeNotifier { num amount = 10.0, paymentDescription = "", String displayCurrencyIso = MFCurrencyISO.KUWAIT_KWD, + required String paymentOption, + required String liveServiceID, + required String isScheduleLiveCare, + required String appointmentDate, + required String appointmentNo, + required String doctorID, + required String fileNumber, + required String serviceID, + required String projectID, Function(MFGetPaymentStatusResponse)? onSuccess, Function(String)? onError, }) async { LoaderBottomSheet.showLoader(); - await MFSDK.init(MyFatoorahConfig.configAPIKey, ApiConsts.myFatoorahCountry, ApiConsts.myFatoorahEnvironmentType); MFSDK.setUpActionBar(toolBarTitle: paymentDescription, toolBarTitleColor: "#ffffff", toolBarBackgroundColor: '#ED1C2B', isShowToolBar: true); - var request = MFExecutePaymentRequest(paymentMethodId: 2, invoiceValue: amount); + var request = MFExecutePaymentRequest(paymentMethodId: paymentOption.toLowerCase() == "mada" ? 6 : 2, invoiceValue: amount); request.displayCurrencyIso = displayCurrencyIso; request.customerName = ApiConsts.appEnvironmentType == AppEnvironmentTypeEnum.uat ? "Test test" : "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}"; request.customerEmail = "CustID_${appState.getAuthenticatedUser()!.patientId}@HMG.com"; - await MFSDK.executePayment(request, appState.isArabic() ? MFLanguage.ARABIC : MFLanguage.ENGLISH, (invoiceId) { + await MFSDK.executePayment(request, appState.isArabic() ? MFLanguage.ARABIC : MFLanguage.ENGLISH, (invoiceId) async { + PayfortRequestInsertModel payfortRequestInsertModel = PayfortRequestInsertModel(); + + payfortRequestInsertModel.commandType = "SALE"; + payfortRequestInsertModel.amount = amount; + payfortRequestInsertModel.customerEmail = getIt.get().getAuthenticatedUser()!.emailAddress; + payfortRequestInsertModel.orderDescription = paymentDescription; + payfortRequestInsertModel.serviceID = serviceID; + payfortRequestInsertModel.paymentOption = paymentOption; + payfortRequestInsertModel.clientRequestID = invoiceId; + payfortRequestInsertModel.projectID = projectID; + payfortRequestInsertModel.fileNumber = getIt.get().getAuthenticatedUser()!.patientId.toString(); + payfortRequestInsertModel.customerName = "${getIt.get().getAuthenticatedUser()!.firstName} ${getIt.get().getAuthenticatedUser()!.lastName}"; + payfortRequestInsertModel.currency = getIt.get().getAuthenticatedUser()!.outSa! == 0 ? "SAR" : "AED"; + payfortRequestInsertModel.liveServiceID = liveServiceID; + payfortRequestInsertModel.latitude = getIt.get().userLat.toString(); + payfortRequestInsertModel.longitude = getIt.get().userLong.toString(); + payfortRequestInsertModel.merchantReference = invoiceId; + payfortRequestInsertModel.deviceToken = await Utils.getStringFromPrefs(CacheConst.pushToken); + payfortRequestInsertModel.language = getIt.get().isArabic() ? "ar" : "en"; + payfortRequestInsertModel.integrationId = "6"; // 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(); - print(invoiceId); - }).then((value) { - if (onSuccess != null) { - onSuccess(value); + }).then((value) async { + var valJson = value.toString(); + print(valJson); + + // // Create PayfortResponseInsertModel (same as Payfort implementation) + PayfortResponseInsertModel payfortResponseInsertModel = PayfortResponseInsertModel(); + + payfortResponseInsertModel.fortId = value.invoiceTransactions!.first.transactionId ?? ""; + payfortResponseInsertModel.commandType = "SALE"; + // payfortResponseInsertModel.amount = paytabsTransactionResponseModel.tranTotal ?? 0; + payfortResponseInsertModel.amount = amount; + payfortResponseInsertModel.sadadOLP = ""; + payfortResponseInsertModel.paymentOption = value.invoiceTransactions!.first.paymentGateway ?? ""; + payfortResponseInsertModel.customerIP = ""; + payfortResponseInsertModel.eCI = ""; + payfortResponseInsertModel.responseMessage = value.invoiceTransactions!.first.transactionStatus ?? ""; + payfortResponseInsertModel.cardNumber = value.invoiceTransactions!.first.cardNumber ?? ""; + payfortResponseInsertModel.cardBin = ""; + payfortResponseInsertModel.installmentsNumber = 0; + payfortResponseInsertModel.status = (value.invoiceStatus ?? "").toLowerCase() == "paid" ? "14" : "00"; + payfortResponseInsertModel.merchantRef = value.invoiceId.toString(); + payfortResponseInsertModel.isRefund = false; + payfortResponseInsertModel.remmeberMe = true; + payfortResponseInsertModel.reconciliationReference = ""; + + // Call response insert API after payment + await paytabsResponseInsert(payfortResponseInsertModel: payfortResponseInsertModel); + + if ((value.invoiceStatus ?? "").toLowerCase() == "paid") { + if (onSuccess != null) { + onSuccess(value); + } + } else { + if (onError != null) { + onError(LocaleKeys.paymentFailedPleaseTryAgain.tr()); + } } }).catchError((error) { if (onError != null) { @@ -52,4 +132,60 @@ class MyFatoorahViewModel extends ChangeNotifier { } }); } + + initApplePayPayment(num invoiceValue, MFApplePayButton mfApplePayButton) async { + await MFSDK.init(MyFatoorahConfig.configAPIKey, ApiConsts.myFatoorahCountry, ApiConsts.myFatoorahEnvironmentType); + + await MFSDK.initSession(MFInitiateSessionRequest(), MFLanguage.ENGLISH).then((value) async { + var executePaymentRequest = MFExecutePaymentRequest(invoiceValue: 121, displayCurrencyIso: MFCurrencyISO.KUWAIT_KWD); + + await mfApplePayButton.executeApplePayButton( + executePaymentRequest, + (String invoiceId) { + print("Payment Success! Invoice ID: $invoiceId"); + }, + ).catchError((error) { + // If initialized properly, this error won't occur + print("Apple Pay Error: ${error.message}"); + }); + }).catchError((error) { + log(error.message); + }); + } + + Future 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 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); + } + } + }, + ); + } } diff --git a/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart b/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart index dfb7497c..40a79370 100644 --- a/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart +++ b/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart @@ -11,6 +11,7 @@ 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/myFatoorah_config.dart'; import 'package:hmg_patient_app_new/core/utils/date_util.dart'; import 'package:hmg_patient_app_new/features/immediate_livecare/immediate_livecare_view_model.dart'; import 'package:hmg_patient_app_new/features/myfatoorah/myfatoorah_view_model.dart'; @@ -35,6 +36,7 @@ import 'package:hmg_patient_app_new/widgets/in_app_browser/InAppBrowser.dart'; import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart'; import 'package:hmg_patient_app_new/widgets/routes/custom_page_route.dart'; import 'package:myfatoorah_flutter/MFEnums.dart'; +import 'package:myfatoorah_flutter/myfatoorah_flutter.dart'; import 'package:provider/provider.dart'; import 'package:smooth_corner/smooth_corner.dart'; @@ -53,6 +55,8 @@ class _ImmediateLiveCarePaymentPageState extends State(); myAppointmentsViewModel = Provider.of(context, listen: false); immediateLiveCareViewModel = Provider.of(context, listen: false); @@ -135,7 +142,62 @@ class _ImmediateLiveCarePaymentPageState extends State false); + Navigator.of(context).push( + CustomPageRoute( + page: ImmediateLiveCarePendingRequestPage(), + ), + ); + } else { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: "Unknown error occurred..."), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } + }, + onError: (errMessage) { + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: errMessage.toString()), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + }); + } else if (appState.isPaytabsEnabled) { transID = Utils.getAppointmentTransID( immediateLiveCareViewModel.immediateLiveCareSelectedClinic.serviceID!, ApiConsts.appEnvironmentType == AppEnvironmentTypeEnum.uat ? 15 : 12, @@ -311,7 +373,43 @@ class _ImmediateLiveCarePaymentPageState extends State false); + Navigator.of(context).push( + CustomPageRoute( + page: ImmediateLiveCarePendingRequestPage(), + ), + ); + } else { + LoaderBottomSheet.hideLoader(); + showCommonBottomSheetWithoutHeight( + context, + child: Utils.getErrorWidget(loadingText: "Unknown error occurred..."), + callBackFunc: () {}, + isFullScreen: false, + isCloseButtonVisible: true, + ); + } + }, onError: (errMessage) { showCommonBottomSheetWithoutHeight( context, @@ -633,16 +731,31 @@ class _ImmediateLiveCarePaymentPageState extends State Date: Tue, 22 Sep 2026 16:57:42 +0300 Subject: [PATCH 6/6] Updates --- .../myfatoorah/myfatoorah_view_model.dart | 30 +++++++++++-------- .../immediate_livecare_payment_page.dart | 7 ++++- .../home/widgets/habib_wallet_card.dart | 2 +- .../home/widgets/lakum_wallet_card.dart | 2 +- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/lib/features/myfatoorah/myfatoorah_view_model.dart b/lib/features/myfatoorah/myfatoorah_view_model.dart index fb7a23fa..b76b251e 100644 --- a/lib/features/myfatoorah/myfatoorah_view_model.dart +++ b/lib/features/myfatoorah/myfatoorah_view_model.dart @@ -133,21 +133,27 @@ class MyFatoorahViewModel extends ChangeNotifier { }); } - initApplePayPayment(num invoiceValue, MFApplePayButton mfApplePayButton) async { + executeApplePayPayment() { + MFApplepay.executeApplePayPayment(onInvoiceCreated: (invoiceID) { + log( + invoiceID.toString(), + ); + }).then((value) { + log( + value.toString(), + ); + }).catchError((error) { + log(error.message); + }); + } + + initApplePayPayment(num invoiceValue) async { await MFSDK.init(MyFatoorahConfig.configAPIKey, ApiConsts.myFatoorahCountry, ApiConsts.myFatoorahEnvironmentType); await MFSDK.initSession(MFInitiateSessionRequest(), MFLanguage.ENGLISH).then((value) async { - var executePaymentRequest = MFExecutePaymentRequest(invoiceValue: 121, displayCurrencyIso: MFCurrencyISO.KUWAIT_KWD); - - await mfApplePayButton.executeApplePayButton( - executePaymentRequest, - (String invoiceId) { - print("Payment Success! Invoice ID: $invoiceId"); - }, - ).catchError((error) { - // If initialized properly, this error won't occur - print("Apple Pay Error: ${error.message}"); - }); + var executePaymentRequest = MFExecutePaymentRequest(invoiceValue: invoiceValue, sessionId: value.sessionId, displayCurrencyIso: MFCurrencyISO.SAUDIARABIA_SAR); + + MFApplepay.setupApplePay(value, executePaymentRequest, MFLanguage.ENGLISH, merchantName: "Dr Sulaiman Al Habib"); }).catchError((error) { log(error.message); }); diff --git a/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart b/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart index 40a79370..2147cbd6 100644 --- a/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart +++ b/lib/presentation/book_appointment/livecare/immediate_livecare_payment_page.dart @@ -71,6 +71,11 @@ class _ImmediateLiveCarePaymentPageState extends State= myAppointmentsViewModel.getTamaraInstallmentsDetailsResponseModel!.minLimit!.amount! && @@ -755,7 +760,7 @@ class _ImmediateLiveCarePaymentPageState extends State