diff --git a/android/app/libs/PenNavUI.aar b/android/app/libs/PenNavUI.aar
index a5658605..2ded149e 100644
Binary files a/android/app/libs/PenNavUI.aar and b/android/app/libs/PenNavUI.aar differ
diff --git a/android/app/libs/Penguin.aar b/android/app/libs/Penguin.aar
index a769c7a2..41ea58d1 100644
Binary files a/android/app/libs/Penguin.aar and b/android/app/libs/Penguin.aar differ
diff --git a/android/app/libs/PenguinRenderer.aar b/android/app/libs/PenguinRenderer.aar
index b498726f..cc5ac36d 100644
Binary files a/android/app/libs/PenguinRenderer.aar and b/android/app/libs/PenguinRenderer.aar differ
diff --git a/assets/images/png/lakum_logo_white.png b/assets/images/png/lakum_logo_white.png
new file mode 100644
index 00000000..db45e5a9
Binary files /dev/null and b/assets/images/png/lakum_logo_white.png differ
diff --git a/assets/images/svg/expired_icon.svg b/assets/images/svg/expired_icon.svg
new file mode 100644
index 00000000..490cc412
--- /dev/null
+++ b/assets/images/svg/expired_icon.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/images/svg/hmg_pharmacy_logo.svg b/assets/images/svg/hmg_pharmacy_logo.svg
new file mode 100644
index 00000000..e069d513
--- /dev/null
+++ b/assets/images/svg/hmg_pharmacy_logo.svg
@@ -0,0 +1,32 @@
+
diff --git a/assets/images/svg/redeem_icon.svg b/assets/images/svg/redeem_icon.svg
new file mode 100644
index 00000000..52eb8815
--- /dev/null
+++ b/assets/images/svg/redeem_icon.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json
index dab50baa..e0faf4e5 100644
--- a/assets/langs/ar-SA.json
+++ b/assets/langs/ar-SA.json
@@ -220,7 +220,7 @@
"request": "الطلبات",
"memberName": "اسم العضو",
"switchLogin": "عرض الملف",
- "removeMember": "إزالة",
+ "removeMember": "حذف",
"allowView": "السماح",
"rejectView": "رفض",
"deleteView": "حذف",
@@ -1845,5 +1845,10 @@
"maxOneFileAllowed": "يمكن رفع ملف واحد فقط",
"fileSizeExceedsLimit": "يجب ألا يتجاوز حجم الملف 1 ميغابايت",
"completedPrescriptionOrder": "تمت الخدمة",
- "submitEReferral": "تقديم الطلب"
+ "submitEReferral": "تقديم الطلب",
+ "redeem": "استبدال",
+ "points": "نقاط",
+ "transactions": "المعاملات",
+ "pharmacy": "الصيدلية",
+ "visitsOrders": "الزيارات/الطلبات"
}
diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json
index 58d49f30..e8409260 100644
--- a/assets/langs/en-US.json
+++ b/assets/langs/en-US.json
@@ -576,7 +576,7 @@
"active": "Active",
"inactive": "InActive",
"balance": "Balance",
- "gained": "GAINED",
+ "gained": "Gained",
"consumed": "Consumed",
"transferred": "Transferred",
"riyal": "RIYAL",
@@ -1835,7 +1835,12 @@
"maxOneFileAllowed": "Only 1 file can be uploaded",
"fileSizeExceedsLimit": "File size must not exceed 1 MB",
"completedPrescriptionOrder": "Completed",
- "submitEReferral": "Submit"
+ "submitEReferral": "Submit",
+ "redeem": "Redeem",
+ "points": "Points",
+ "transactions": "Transactions",
+ "pharmacy": "Pharmacy",
+ "visitsOrders": "Visits/Orders"
}
diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart
index e46de55c..8dbc9ce3 100644
--- a/lib/core/api_consts.dart
+++ b/lib/core/api_consts.dart
@@ -281,7 +281,7 @@ class ApiConsts {
static String googleCloudStorageENTranslationFileBaseURL = "https://storage.googleapis.com/hmg-patientapp-translations";
// ************ static values for Api ****************
- static final double appVersionID = 21.1;
+ static final double appVersionID = 21.2;
// static final double appVersionID = 50.7;
static final int appChannelId = 3;
@@ -872,6 +872,7 @@ var GET_DOCTOR_LIST_CALCULATION = "Services/Doctors.svc/REST/GetCallculationDoct
// var GET_ALL_APPOINTMENTS_FOR_DENTAL_CLINIC = "Services/Patients.svc/REST/GetDentalAppointments";
var GET_ALL_APPOINTMENTS_FOR_DENTAL_CLINIC = 'Services/Patients.svc/REST/GetAllInvoices';
+var GET_ALL_PHARMACY_INVOICES = 'Services/Patients.svc/REST/GetAllPharmacyInvoices';
var GET_DENTAL_APPOINTMENT_INVOICE = "Services/Patients.svc/REST/HIS_eInvoiceForDentalByAppointmentNo";
var SEND_DENTAL_APPOINTMENT_INVOICE_EMAIL = "Services/Notifications.svc/REST/SendInvoiceForDental";
@@ -995,6 +996,8 @@ const UPLOAD_PROFILE_IMAGE = 'Services/Patients.svc/REST/Patient_InsertProfileIm
const DOWNLOAD_INVOICE_PDF = 'Services/Notifications.svc/REST/DownloadInvoiceReport';
+const DOWNLOAD_PHARMACY_INVOICE_PDF = 'Services/Notifications.svc/REST/DownloadInvoiceReport';
+
class ApiKeyConstants {
static final String googleMapsApiKey = 'AIzaSyB6TERnxIr0yJ3qG4ULBZbu0sAD4tGqtng';
}
diff --git a/lib/core/app_assets.dart b/lib/core/app_assets.dart
index 3c80296d..d6e041da 100644
--- a/lib/core/app_assets.dart
+++ b/lib/core/app_assets.dart
@@ -380,6 +380,9 @@ class AppAssets {
static const String gallery = '$svgBasePath/gallery.svg';
static const String files = '$svgBasePath/files.svg';
static const String online_checkin_icon = '$svgBasePath/online_checkin_icon.svg';
+ static const String hmg_pharmacy_logo = '$svgBasePath/hmg_pharmacy_logo.svg';
+ static const String redeem_icon = '$svgBasePath/redeem_icon.svg';
+ static const String expired_icon = '$svgBasePath/expired_icon.svg';
//Health Calculators
static const String bodyfatcalc = '$svgBasePath/bfc.svg';
@@ -421,6 +424,7 @@ class AppAssets {
static const String maleIcon = '$pngBasePath/male_icon.png';
static const String femaleIcon = '$pngBasePath/female_icon.png';
static const String lakumLogo = '$pngBasePath/lakum_logo.png';
+ static const String lakumLogoWhite = '$pngBasePath/lakum_logo_white.png';
static const String fullBodyFrontMale = '$pngBasePath/full_body_front_male.png';
static const String fullBodyBackMale = '$pngBasePath/full_body_back_male.png';
@@ -430,8 +434,6 @@ class AppAssets {
static const String bmiFullBodyFemale = '$pngBasePath/female_bmi.png';
static const String defaultMEP = '$pngBasePath/default_MEP.png';
-
-
static const String ambulance_section = '$pngBasePath/ambulance_section.png';
static const String rrt_section = '$pngBasePath/rrt_section.png';
static const String er_checkin = '$pngBasePath/er_checkin.png';
diff --git a/lib/core/app_state.dart b/lib/core/app_state.dart
index 21f93eed..5eb7a05d 100644
--- a/lib/core/app_state.dart
+++ b/lib/core/app_state.dart
@@ -44,6 +44,8 @@ class AppState {
AuthenticatedUser? _authenticatedRootUser;
AuthenticatedUser? _authenticatedChildUser;
+ bool isPaytabsEnabled = false;
+
int? _superUserID;
bool isChildLoggedIn = false;
bool isGMSAvailable = true;
diff --git a/lib/core/dependencies.dart b/lib/core/dependencies.dart
index 0380a9a3..a45e9e6d 100644
--- a/lib/core/dependencies.dart
+++ b/lib/core/dependencies.dart
@@ -50,6 +50,7 @@ import 'package:hmg_patient_app_new/features/offers_and_discounts/offers_and_dis
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_repo.dart';
import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart';
+import 'package:hmg_patient_app_new/features/paytabs/paytabs_view_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_repo.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/profile_picture/profile_picture_view_model.dart';
@@ -342,5 +343,7 @@ class AppDependencies {
getIt.registerLazySingleton(() => OffersAndDiscountsViewModel(offersAndDiscountsRepo: getIt(), errorHandlerService: getIt()));
getIt.registerLazySingleton(() => DateRangCalenderModel(appState: getIt(), navigationService: getIt(), dialogService: getIt()));
+
+ getIt.registerLazySingleton(() => PayTabsViewModel(appState: getIt()));
}
}
diff --git a/lib/core/paytabs_config.dart b/lib/core/paytabs_config.dart
new file mode 100644
index 00000000..4d90ee8f
--- /dev/null
+++ b/lib/core/paytabs_config.dart
@@ -0,0 +1,12 @@
+/// Default configuration values for PayTabs Payment SDK
+class PaymentSdkDefaultConfig {
+ static const String profileID = "119730";
+ static const String serverKey = "SWJ9LD22MT-JLJZLBKTLK-WGWTLWGTWR";
+ static const String clientKey = "C7K2DQ-PDDN6B-69B2K7-P9GB9T";
+ static const String defaultCurrency = "SAR";
+ static const double defaultAmount = 10.0;
+ static const String defaultMerchantCountryCode = "SA";
+ static const String defaultMerchantName = "Sulaiman Al Habib Medical Group";
+ static const String defaultMerchantAppleBundleID = "merchant.com.hmgwebservices";
+ static const String defaultMerchantAppleBundleIDUAT = "merchant.com.hmgwebservices.uat";
+}
diff --git a/lib/core/utils/penguin_method_channel.dart b/lib/core/utils/penguin_method_channel.dart
index c3da7242..939b98a9 100644
--- a/lib/core/utils/penguin_method_channel.dart
+++ b/lib/core/utils/penguin_method_channel.dart
@@ -22,7 +22,6 @@ class PenguinMethodChannel {
"baseURL": "https://eagleiq.hmg.com",
"dataURL": "https://eagleiq.hmg.com",
"positionURL": "https://eagleiq.hmg.com",
-
"dataServiceName": "api",
"positionServiceName": "pe",
"clientID": "HMG",
diff --git a/lib/core/utils/utils.dart b/lib/core/utils/utils.dart
index 1cf8094d..ef83cb9f 100644
--- a/lib/core/utils/utils.dart
+++ b/lib/core/utils/utils.dart
@@ -99,7 +99,11 @@ class Utils {
static bool isArabicText(String inputText) {
bool isArabicText = false;
- final arabic = RegExp(r'^[\u0621-\u064A]+');
+ // Updated regex to include:
+ // - Arabic letters: \u0621-\u064A
+ // - Arabic numerals: \u0660-\u0669 (٠-٩)
+ // - Persian numerals: \u06F0-\u06F9 (۰-۹)
+ final arabic = RegExp(r'[\u0621-\u064A\u0660-\u0669\u06F0-\u06F9]');
if (arabic.hasMatch(inputText)) {
isArabicText = true;
} else {
@@ -872,25 +876,25 @@ class Utils {
);
}
- static Widget getPaymentMethods() {
+ static Widget getPaymentMethods({num spacing = 3, num width = 35, num height = 35}) {
return Row(
- spacing: 6.w,
+ spacing: spacing.w,
mainAxisSize: MainAxisSize.max,
children: [
- Image.asset(AppAssets.mada, width: 35.h, height: 35.h),
+ Image.asset(AppAssets.mada, width: width.h, height: height.h),
Image.asset(
AppAssets.tamaraEng,
- width: 35.h,
- height: 35.h,
+ width: width.h,
+ height: height.h,
fit: BoxFit.contain,
errorBuilder: (context, error, stackTrace) {
debugPrint('Failed to load Tamara PNG in payment methods: $error');
return Utils.buildSvgWithAssets(icon: AppAssets.tamara, width: 35.h, height: 35.h, fit: BoxFit.contain);
},
),
- Image.asset(AppAssets.visa, width: 35.h, height: 35.h),
- Image.asset(AppAssets.mastercard, width: 35.h, height: 25.h),
- Image.asset(AppAssets.applePay, width: 35.h, height: 35.h),
+ Image.asset(AppAssets.visa, width: width.h, height: height.h),
+ Image.asset(AppAssets.mastercard, width: width.h, height: height.h),
+ Platform.isIOS ? Image.asset(AppAssets.applePay, width: width.h, height: height.h) : SizedBox.shrink(),
],
);
}
diff --git a/lib/features/authentication/widgets/otp_verification_screen.dart b/lib/features/authentication/widgets/otp_verification_screen.dart
index 737df465..41ca087a 100644
--- a/lib/features/authentication/widgets/otp_verification_screen.dart
+++ b/lib/features/authentication/widgets/otp_verification_screen.dart
@@ -1,4 +1,5 @@
import 'dart:async';
+import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart';
@@ -451,7 +452,9 @@ class _OTPVerificationScreenState extends State {
super.initState();
_otpController = TextEditingController();
_startResendTimer();
- checkSignature();
+ if(Platform.isAndroid) {
+ checkSignature();
+ }
}
@override
diff --git a/lib/features/book_appointments/book_appointments_view_model.dart b/lib/features/book_appointments/book_appointments_view_model.dart
index 7ac09686..e6cfa6c2 100644
--- a/lib/features/book_appointments/book_appointments_view_model.dart
+++ b/lib/features/book_appointments/book_appointments_view_model.dart
@@ -866,6 +866,7 @@ class BookAppointmentsViewModel extends ChangeNotifier {
initialSlotDuration = apiResponse.data["InitialSlotDuration"];
freeSlotsResponse = apiResponse.data['FreeTimeSlots'];
isWaitingAppointmentAvailable = apiResponse.data["IsAllowToBookWaitingAppointment"];
+
// isWaitingAppointmentAvailable = true;
freeSlotsResponse.forEach((element) {
@@ -1479,6 +1480,9 @@ class BookAppointmentsViewModel extends ChangeNotifier {
result.fold(
(failure) async {
+ if(onError != null) {
+ onError(failure.message);
+ }
onError!(LocaleKeys.noDoctorFound.tr());
},
(apiResponse) {
diff --git a/lib/features/contact_us/contact_us_view_model.dart b/lib/features/contact_us/contact_us_view_model.dart
index 00ef8dbc..648fab6b 100644
--- a/lib/features/contact_us/contact_us_view_model.dart
+++ b/lib/features/contact_us/contact_us_view_model.dart
@@ -345,7 +345,7 @@ class ContactUsViewModel extends ChangeNotifier {
}
} else if (apiResponse.messageStatus == 1) {
cocItemsList = apiResponse.data!;
- cocItemsList.sort((a, b) => a.date!.compareTo(b.date!));
+ cocItemsList.sort((a, b) => b.date!.compareTo(a.date!));
isCOCItemsListLoading = false;
notifyListeners();
if (onSuccess != null) {
diff --git a/lib/features/habib_wallet/habib_wallet_repo.dart b/lib/features/habib_wallet/habib_wallet_repo.dart
index c89a85be..57d5af20 100644
--- a/lib/features/habib_wallet/habib_wallet_repo.dart
+++ b/lib/features/habib_wallet/habib_wallet_repo.dart
@@ -18,6 +18,10 @@ abstract class HabibWalletRepo {
Future>> addAdvanceNumberRequest({required String advanceNumber, required String paymentReference});
Future>> getPatientInfoByPatientID({required String patientID});
+
+ Future>> getLakumAccountInformation({required String identificationNumber});
+
+ Future>> getLakumAccountInquiryInformation({required String lakumAccountNumber});
}
class HabibWalletRepoImp implements HabibWalletRepo {
@@ -231,4 +235,75 @@ class HabibWalletRepoImp implements HabibWalletRepo {
return Left(UnknownFailure(e.toString()));
}
}
+
+ @override
+ Future> getLakumAccountInformation({required String identificationNumber}) async {
+ Map requestBody = {"IdentificationNo": identificationNumber};
+
+ try {
+ GenericApiModel? apiResponse;
+ Failure? failure;
+ await apiClient.post(
+ GET_LACUM_ACCOUNT_INFORMATION,
+ body: requestBody,
+ onFailure: (error, statusCode, {messageStatus, failureType}) {
+ failure = failureType;
+ },
+ onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
+ try {
+ apiResponse = GenericApiModel(
+ messageStatus: messageStatus,
+ statusCode: statusCode,
+ errorMessage: null,
+ data: response,
+ );
+ } catch (e) {
+ failure = DataParsingFailure(e.toString());
+ }
+ },
+ );
+ if (failure != null) return Left(failure!);
+ if (apiResponse == null) return Left(ServerFailure("Unknown error"));
+ return Right(apiResponse!);
+ } catch (e) {
+ return Left(UnknownFailure(e.toString()));
+ }
+ }
+
+ @override
+ Future> getLakumAccountInquiryInformation({required String lakumAccountNumber}) async {
+ Map requestBody = {
+ "AccountNumber": lakumAccountNumber,
+ "IsDetailsRequired": true,
+ };
+
+ try {
+ GenericApiModel? apiResponse;
+ Failure? failure;
+ await apiClient.post(
+ GET_LACUM_GROUP_INFORMATION,
+ body: requestBody,
+ onFailure: (error, statusCode, {messageStatus, failureType}) {
+ failure = failureType;
+ },
+ onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
+ try {
+ apiResponse = GenericApiModel(
+ messageStatus: messageStatus,
+ statusCode: statusCode,
+ errorMessage: null,
+ data: response,
+ );
+ } catch (e) {
+ failure = DataParsingFailure(e.toString());
+ }
+ },
+ );
+ if (failure != null) return Left(failure!);
+ if (apiResponse == null) return Left(ServerFailure("Unknown error"));
+ return Right(apiResponse!);
+ } catch (e) {
+ return Left(UnknownFailure(e.toString()));
+ }
+ }
}
diff --git a/lib/features/habib_wallet/habib_wallet_view_model.dart b/lib/features/habib_wallet/habib_wallet_view_model.dart
index 01dc2357..21139c80 100644
--- a/lib/features/habib_wallet/habib_wallet_view_model.dart
+++ b/lib/features/habib_wallet/habib_wallet_view_model.dart
@@ -1,6 +1,10 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
+import 'package:hmg_patient_app_new/core/app_state.dart';
+import 'package:hmg_patient_app_new/core/dependencies.dart';
+import 'package:hmg_patient_app_new/core/utils/date_util.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_repo.dart';
+import 'package:hmg_patient_app_new/features/habib_wallet/models/lakum_inquiry_information_response_model.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/models/patient_advance_balance_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/hospital_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
@@ -43,6 +47,54 @@ class HabibWalletViewModel extends ChangeNotifier {
String? get hospitalError => _hospitalError;
String yahalaAccountNumber = '';
+ bool isLakumAccountInfoLoading = false;
+ LakumInquiryInformationResponseModel? lakumAccountInfo;
+
+ // Get all flattened transactions sorted by date descending
+ List getAllLakumTransactions() {
+ if (lakumAccountInfo?.gainedPointsAmountPerYear == null) {
+ return [];
+ }
+
+ List allTransactions = [];
+
+ // Flatten the nested structure
+ for (var yearData in lakumAccountInfo!.gainedPointsAmountPerYear!) {
+ if (yearData.pointsAmountPerMonth != null) {
+ for (var monthData in yearData.pointsAmountPerMonth!) {
+ if (monthData.pointsAmountPerday != null) {
+ for (var dayData in monthData.pointsAmountPerday!) {
+ if (dayData.pointsDetails != null) {
+ allTransactions.addAll(dayData.pointsDetails!);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Sort by transaction date DESCENDING (latest/most recent transactions first, older transactions last)
+ allTransactions.sort((a, b) {
+ // Null dates go to the end
+ if (a.transactionDate == null && b.transactionDate == null) return 0;
+ if (a.transactionDate == null) return 1; // a goes after b
+ if (b.transactionDate == null) return -1; // a goes before b
+
+ try {
+ DateTime dateA = DateUtil.convertStringToDate(a.transactionDate!);
+ DateTime dateB = DateUtil.convertStringToDate(b.transactionDate!);
+
+ // Compare dateB to dateA (not dateA to dateB) for DESCENDING order
+ // This puts newer dates (larger values) at the top of the list
+ return dateB.compareTo(dateA);
+ } catch (e) {
+ // If date parsing fails, maintain current order
+ return 0;
+ }
+ });
+
+ return allTransactions;
+ }
// Clear amount error
void clearAmountError() {
@@ -103,6 +155,7 @@ class HabibWalletViewModel extends ChangeNotifier {
initHabibWalletProvider() {
isWalletAmountLoading = true;
isBottomSheetContentLoading = false;
+ isLakumAccountInfoLoading = true;
habibWalletAmount = 0;
walletRechargeAmount = 0;
selectedRechargeType = 1;
@@ -112,6 +165,7 @@ class HabibWalletViewModel extends ChangeNotifier {
fileNumber = '';
depositorName = '';
mobileNumber = '';
+ yahalaAccountNumber = "";
notifyListeners();
}
@@ -148,6 +202,11 @@ class HabibWalletViewModel extends ChangeNotifier {
notifyListeners();
}
+ setYahalaAccountNumber(String accountNumber) {
+ yahalaAccountNumber = accountNumber;
+ notifyListeners();
+ }
+
String getSelectedRechargeTypeValue() {
switch (selectedRechargeType) {
case 1:
@@ -221,7 +280,12 @@ class HabibWalletViewModel extends ChangeNotifier {
paymentMethodName: paymentMethodName, paidAmount: paidAmount, paymentReference: paymentReference, patientID: patientID, projectID: projectID, depositorName: depositorName);
result.fold(
- (failure) async => await errorHandlerService.handleError(failure: failure),
+ // (failure) async => await errorHandlerService.handleError(failure: failure),
+ (failure) async {
+ if(onError != null) {
+ onError(failure.message);
+ }
+ },
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
@@ -277,4 +341,46 @@ class HabibWalletViewModel extends ChangeNotifier {
},
);
}
+
+ Future getLakumAccountInformation({Function(dynamic)? onSuccess, Function(String)? onError}) async {
+ isLakumAccountInfoLoading = true;
+ lakumAccountInfo = LakumInquiryInformationResponseModel();
+ notifyListeners();
+
+ final result = await habibWalletRepo.getLakumAccountInformation(identificationNumber: getIt.get().getAuthenticatedUser()!.patientIdentificationNo ?? "");
+
+ result.fold(
+ (failure) async => await errorHandlerService.handleError(failure: failure),
+ (apiResponse) async {
+ if (apiResponse.messageStatus == 2) {
+ yahalaAccountNumber = "0";
+ isLakumAccountInfoLoading = false;
+ notifyListeners();
+ } else if (apiResponse.messageStatus == 1) {
+ if (apiResponse.data["YahalaAccountNo"] == 0 || apiResponse.data["YahalaAccountNo"] == "0") {
+ yahalaAccountNumber = "0";
+ } else {
+ yahalaAccountNumber = apiResponse.data["YahalaAccountNo"].toString();
+
+ final lakumAccountResult = await habibWalletRepo.getLakumAccountInquiryInformation(lakumAccountNumber: yahalaAccountNumber);
+ lakumAccountResult.fold(
+ (failure) async => await errorHandlerService.handleError(failure: failure),
+ (lakumApiResponse) async {
+ if (lakumApiResponse.messageStatus == 2) {
+ lakumAccountInfo = LakumInquiryInformationResponseModel();
+ } else if (lakumApiResponse.messageStatus == 1) {
+ lakumAccountInfo = LakumInquiryInformationResponseModel.fromJson(lakumApiResponse.data["LakumInquiryInformationObjVersion"]);
+ }
+ },
+ );
+ }
+ isLakumAccountInfoLoading = false;
+ notifyListeners();
+ if (onSuccess != null) {
+ onSuccess(apiResponse);
+ }
+ }
+ },
+ );
+ }
}
diff --git a/lib/features/habib_wallet/models/lakum_inquiry_information_response_model.dart b/lib/features/habib_wallet/models/lakum_inquiry_information_response_model.dart
new file mode 100644
index 00000000..621434fe
--- /dev/null
+++ b/lib/features/habib_wallet/models/lakum_inquiry_information_response_model.dart
@@ -0,0 +1,318 @@
+class LakumInquiryInformationResponseModel {
+ int? accountNumber;
+ String? accountStatus;
+ String? barCode;
+ num? consumedPoints;
+ dynamic consumedPointsAmount;
+ dynamic consumedPointsAmountPerYear;
+
+ // List? consumedPointsDetails;
+ String? createdDate;
+ num? expiredPoints;
+ String? expiryDate;
+ num? gainedPoints;
+ num? gainedPointsAmount;
+ List? gainedPointsAmountPerYear;
+
+ // List? gainedPointsDetails;
+ String? lakumMessageStatus;
+ String? memberName;
+ String? memberUniversalId;
+ String? mobileNumber;
+ num? pointsBalance;
+ num? pointsBalanceAmount;
+ num? pointsWillBeExpired;
+ String? prefLang;
+ num? statusCode;
+ num? transferPoints;
+ dynamic transferPointsAmountPerYear;
+
+ // List? transferPointsDetails;
+ num? waitingPoints;
+ num? loyalityAmount;
+ num? loyalityPoints;
+ num? purchaseRate;
+
+ LakumInquiryInformationResponseModel(
+ {this.accountNumber,
+ this.accountStatus,
+ this.barCode,
+ this.consumedPoints,
+ this.consumedPointsAmount,
+ this.consumedPointsAmountPerYear,
+ // this.consumedPointsDetails,
+ this.createdDate,
+ this.expiredPoints,
+ this.expiryDate,
+ this.gainedPoints,
+ this.gainedPointsAmount,
+ this.gainedPointsAmountPerYear,
+ // this.gainedPointsDetails,
+ this.lakumMessageStatus,
+ this.memberName,
+ this.memberUniversalId,
+ this.mobileNumber,
+ this.pointsBalance,
+ this.pointsBalanceAmount,
+ this.pointsWillBeExpired,
+ this.prefLang,
+ this.statusCode,
+ this.transferPoints,
+ this.transferPointsAmountPerYear,
+ // this.transferPointsDetails,
+ this.waitingPoints,
+ this.loyalityAmount,
+ this.loyalityPoints,
+ this.purchaseRate});
+
+ LakumInquiryInformationResponseModel.fromJson(Map json) {
+ accountNumber = json['AccountNumber'];
+ accountStatus = json['AccountStatus'];
+ barCode = json['BarCode'];
+ consumedPoints = json['ConsumedPoints'];
+ consumedPointsAmount = json['ConsumedPointsAmount'];
+ consumedPointsAmountPerYear = json['ConsumedPointsAmountPerYear'];
+ // if (json['ConsumedPointsDetails'] != null) {
+ // consumedPointsDetails = [];
+ // json['ConsumedPointsDetails'].forEach((v) {
+ // consumedPointsDetails!.add(new Null.fromJson(v));
+ // });
+ // }
+ createdDate = json['CreatedDate'];
+ expiredPoints = json['ExpiredPoints'];
+ expiryDate = json['ExpiryDate'];
+ gainedPoints = json['GainedPoints'];
+ gainedPointsAmount = json['GainedPointsAmount'];
+ if (json['GainedPointsAmountPerYear'] != null) {
+ gainedPointsAmountPerYear = [];
+ json['GainedPointsAmountPerYear'].forEach((v) {
+ gainedPointsAmountPerYear!.add(new GainedPointsAmountPerYear.fromJson(v));
+ });
+ }
+ // if (json['GainedPointsDetails'] != null) {
+ // gainedPointsDetails = [];
+ // json['GainedPointsDetails'].forEach((v) {
+ // gainedPointsDetails!.add(new Null.fromJson(v));
+ // });
+ // }
+ lakumMessageStatus = json['LakumMessageStatus'];
+ memberName = json['MemberName'];
+ memberUniversalId = json['MemberUniversalId'];
+ mobileNumber = json['MobileNumber'];
+ pointsBalance = json['PointsBalance'];
+ pointsBalanceAmount = json['PointsBalanceAmount'];
+ pointsWillBeExpired = json['PointsWillBeExpired'];
+ prefLang = json['PrefLang'];
+ statusCode = json['StatusCode'];
+ transferPoints = json['TransferPoints'];
+ transferPointsAmountPerYear = json['TransferPointsAmountPerYear'];
+ // if (json['TransferPointsDetails'] != null) {
+ // transferPointsDetails = [];
+ // json['TransferPointsDetails'].forEach((v) {
+ // transferPointsDetails!.add(new Null.fromJson(v));
+ // });
+ // }
+ waitingPoints = json['WaitingPoints'];
+ loyalityAmount = json['loyalityAmount'];
+ loyalityPoints = json['loyalityPoints'];
+ purchaseRate = json['purchaseRate'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['AccountNumber'] = this.accountNumber;
+ data['AccountStatus'] = this.accountStatus;
+ data['BarCode'] = this.barCode;
+ data['ConsumedPoints'] = this.consumedPoints;
+ data['ConsumedPointsAmount'] = this.consumedPointsAmount;
+ data['ConsumedPointsAmountPerYear'] = this.consumedPointsAmountPerYear;
+ // if (this.consumedPointsDetails != null) {
+ // data['ConsumedPointsDetails'] = this.consumedPointsDetails!.map((v) => v.toJson()).toList();
+ // }
+ data['CreatedDate'] = this.createdDate;
+ data['ExpiredPoints'] = this.expiredPoints;
+ data['ExpiryDate'] = this.expiryDate;
+ data['GainedPoints'] = this.gainedPoints;
+ data['GainedPointsAmount'] = this.gainedPointsAmount;
+ if (this.gainedPointsAmountPerYear != null) {
+ data['GainedPointsAmountPerYear'] = this.gainedPointsAmountPerYear!.map((v) => v.toJson()).toList();
+ }
+ // if (this.gainedPointsDetails != null) {
+ // data['GainedPointsDetails'] = this.gainedPointsDetails!.map((v) => v.toJson()).toList();
+ // }
+ data['LakumMessageStatus'] = this.lakumMessageStatus;
+ data['MemberName'] = this.memberName;
+ data['MemberUniversalId'] = this.memberUniversalId;
+ data['MobileNumber'] = this.mobileNumber;
+ data['PointsBalance'] = this.pointsBalance;
+ data['PointsBalanceAmount'] = this.pointsBalanceAmount;
+ data['PointsWillBeExpired'] = this.pointsWillBeExpired;
+ data['PrefLang'] = this.prefLang;
+ data['StatusCode'] = this.statusCode;
+ data['TransferPoints'] = this.transferPoints;
+ data['TransferPointsAmountPerYear'] = this.transferPointsAmountPerYear;
+ // if (this.transferPointsDetails != null) {
+ // data['TransferPointsDetails'] = this.transferPointsDetails!.map((v) => v.toJson()).toList();
+ // }
+ data['WaitingPoints'] = this.waitingPoints;
+ data['loyalityAmount'] = this.loyalityAmount;
+ data['loyalityPoints'] = this.loyalityPoints;
+ data['purchaseRate'] = this.purchaseRate;
+ return data;
+ }
+}
+
+class GainedPointsAmountPerYear {
+ num? amountPerYear;
+ List? pointsAmountPerMonth;
+ num? pointsPerYear;
+ int? year;
+
+ GainedPointsAmountPerYear({this.amountPerYear, this.pointsAmountPerMonth, this.pointsPerYear, this.year});
+
+ GainedPointsAmountPerYear.fromJson(Map json) {
+ amountPerYear = json['AmountPerYear'];
+ if (json['PointsAmountPerMonth'] != null) {
+ pointsAmountPerMonth = [];
+ json['PointsAmountPerMonth'].forEach((v) {
+ pointsAmountPerMonth!.add(new PointsAmountPerMonth.fromJson(v));
+ });
+ }
+ pointsPerYear = json['PointsPerYear'];
+ year = json['Year'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['AmountPerYear'] = this.amountPerYear;
+ if (this.pointsAmountPerMonth != null) {
+ data['PointsAmountPerMonth'] = this.pointsAmountPerMonth!.map((v) => v.toJson()).toList();
+ }
+ data['PointsPerYear'] = this.pointsPerYear;
+ data['Year'] = this.year;
+ return data;
+ }
+}
+
+class PointsAmountPerMonth {
+ num? amountPerMonth;
+ String? month;
+ num? monthNumber;
+ List? pointsAmountPerday;
+ num? pointsPerMonth;
+
+ PointsAmountPerMonth({this.amountPerMonth, this.month, this.monthNumber, this.pointsAmountPerday, this.pointsPerMonth});
+
+ PointsAmountPerMonth.fromJson(Map json) {
+ amountPerMonth = json['AmountPerMonth'];
+ month = json['Month'];
+ monthNumber = json['MonthNumber'];
+ if (json['PointsAmountPerday'] != null) {
+ pointsAmountPerday = [];
+ json['PointsAmountPerday'].forEach((v) {
+ pointsAmountPerday!.add(new PointsAmountPerday.fromJson(v));
+ });
+ }
+ pointsPerMonth = json['PointsPerMonth'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['AmountPerMonth'] = this.amountPerMonth;
+ data['Month'] = this.month;
+ data['MonthNumber'] = this.monthNumber;
+ if (this.pointsAmountPerday != null) {
+ data['PointsAmountPerday'] = this.pointsAmountPerday!.map((v) => v.toJson()).toList();
+ }
+ data['PointsPerMonth'] = this.pointsPerMonth;
+ return data;
+ }
+}
+
+class PointsAmountPerday {
+ num? amountPerDay;
+ String? day;
+ List? pointsDetails;
+ num? pointsPerDay;
+ String? transationDate;
+
+ PointsAmountPerday({this.amountPerDay, this.day, this.pointsDetails, this.pointsPerDay, this.transationDate});
+
+ PointsAmountPerday.fromJson(Map json) {
+ amountPerDay = json['AmountPerDay'];
+ day = json['Day'];
+ if (json['PointsDetails'] != null) {
+ pointsDetails = [];
+ json['PointsDetails'].forEach((v) {
+ pointsDetails!.add(new PointsDetails.fromJson(v));
+ });
+ }
+ pointsPerDay = json['PointsPerDay'];
+ transationDate = json['TransationDate'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['AmountPerDay'] = this.amountPerDay;
+ data['Day'] = this.day;
+ if (this.pointsDetails != null) {
+ data['PointsDetails'] = this.pointsDetails!.map((v) => v.toJson()).toList();
+ }
+ data['PointsPerDay'] = this.pointsPerDay;
+ data['TransationDate'] = this.transationDate;
+ return data;
+ }
+}
+
+class PointsDetails {
+ int? accNumber;
+ String? accountStatus;
+ num? amount;
+ int? lineItemNo;
+ String? operationType;
+ num? points;
+ num? purchasePoints;
+ int? subTransactionType;
+ String? subTransactionTypeDescription;
+ String? transactionDate;
+
+ PointsDetails(
+ {this.accNumber,
+ this.accountStatus,
+ this.amount,
+ this.lineItemNo,
+ this.operationType,
+ this.points,
+ this.purchasePoints,
+ this.subTransactionType,
+ this.subTransactionTypeDescription,
+ this.transactionDate});
+
+ PointsDetails.fromJson(Map json) {
+ accNumber = json['AccNumber'];
+ accountStatus = json['AccountStatus'];
+ amount = json['Amount'];
+ lineItemNo = json['LineItemNo'];
+ operationType = json['OperationType'];
+ points = json['Points'];
+ purchasePoints = json['PurchasePoints'];
+ subTransactionType = json['SubTransactionType'];
+ subTransactionTypeDescription = json['SubTransactionTypeDescription'];
+ transactionDate = json['TransactionDate'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['AccNumber'] = this.accNumber;
+ data['AccountStatus'] = this.accountStatus;
+ data['Amount'] = this.amount;
+ data['LineItemNo'] = this.lineItemNo;
+ data['OperationType'] = this.operationType;
+ data['Points'] = this.points;
+ data['PurchasePoints'] = this.purchasePoints;
+ data['SubTransactionType'] = this.subTransactionType;
+ data['SubTransactionTypeDescription'] = this.subTransactionTypeDescription;
+ data['TransactionDate'] = this.transactionDate;
+ return data;
+ }
+}
diff --git a/lib/features/my_invoices/models/get_pharmacy_invoices_response_model.dart b/lib/features/my_invoices/models/get_pharmacy_invoices_response_model.dart
new file mode 100644
index 00000000..cfa19900
--- /dev/null
+++ b/lib/features/my_invoices/models/get_pharmacy_invoices_response_model.dart
@@ -0,0 +1,99 @@
+class GetPharmacyInvoicesResponseModel {
+ String? setupId;
+ int? projectID;
+ int? pharmacyProjectID;
+ int? patientID;
+ int? appointmentNo;
+ String? appointmentDate;
+ dynamic appointmentDateN;
+ int? clinicID;
+ int? doctorID;
+ int? invoiceNo;
+ int? status;
+ String? arrivedOn;
+ String? doctorName;
+ String? doctorNameN;
+ String? displayInvoiceNo;
+ String? clinicName;
+ num? decimalDoctorRate;
+ String? doctorImageURL;
+ num? doctorRate;
+ num? patientNumber;
+ String? projectName;
+ dynamic locationID;
+
+ GetPharmacyInvoicesResponseModel(
+ {this.setupId,
+ this.projectID,
+ this.pharmacyProjectID,
+ this.patientID,
+ this.appointmentNo,
+ this.appointmentDate,
+ this.appointmentDateN,
+ this.clinicID,
+ this.doctorID,
+ this.invoiceNo,
+ this.status,
+ this.arrivedOn,
+ this.doctorName,
+ this.doctorNameN,
+ this.displayInvoiceNo,
+ this.clinicName,
+ this.decimalDoctorRate,
+ this.doctorImageURL,
+ this.doctorRate,
+ this.patientNumber,
+ this.projectName, this.locationID});
+
+ GetPharmacyInvoicesResponseModel.fromJson(Map json) {
+ setupId = json['SetupId'];
+ projectID = json['ProjectID'];
+ pharmacyProjectID = json['PharmacyProjectID'];
+ patientID = json['PatientID'];
+ appointmentNo = json['AppointmentNo'];
+ appointmentDate = json['AppointmentDate'];
+ appointmentDateN = json['AppointmentDateN'];
+ clinicID = json['ClinicID'];
+ doctorID = json['DoctorID'];
+ invoiceNo = json['InvoiceNo'];
+ status = json['Status'];
+ arrivedOn = json['ArrivedOn'];
+ doctorName = json['DoctorName'];
+ doctorNameN = json['DoctorNameN'];
+ displayInvoiceNo = json['DisplayInvoiceNo'];
+ clinicName = json['ClinicName'];
+ decimalDoctorRate = json['DecimalDoctorRate'];
+ doctorImageURL = json['DoctorImageURL'];
+ doctorRate = json['DoctorRate'];
+ patientNumber = json['PatientNumber'];
+ projectName = json['ProjectName'];
+ locationID = json['LocationId'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['SetupId'] = this.setupId;
+ data['ProjectID'] = this.projectID;
+ data['PharmacyProjectID'] = this.pharmacyProjectID;
+ data['PatientID'] = this.patientID;
+ data['AppointmentNo'] = this.appointmentNo;
+ data['AppointmentDate'] = this.appointmentDate;
+ data['AppointmentDateN'] = this.appointmentDateN;
+ data['ClinicID'] = this.clinicID;
+ data['DoctorID'] = this.doctorID;
+ data['InvoiceNo'] = this.invoiceNo;
+ data['Status'] = this.status;
+ data['ArrivedOn'] = this.arrivedOn;
+ data['DoctorName'] = this.doctorName;
+ data['DoctorNameN'] = this.doctorNameN;
+ data['DisplayInvoiceNo'] = this.displayInvoiceNo;
+ data['ClinicName'] = this.clinicName;
+ data['DecimalDoctorRate'] = this.decimalDoctorRate;
+ data['DoctorImageURL'] = this.doctorImageURL;
+ data['DoctorRate'] = this.doctorRate;
+ data['PatientNumber'] = this.patientNumber;
+ data['ProjectName'] = this.projectName;
+ data['LocationId'] = this.locationID;
+ return data;
+ }
+}
diff --git a/lib/features/my_invoices/my_invoices_repo.dart b/lib/features/my_invoices/my_invoices_repo.dart
index 486fdc2a..23f5d06a 100644
--- a/lib/features/my_invoices/my_invoices_repo.dart
+++ b/lib/features/my_invoices/my_invoices_repo.dart
@@ -5,16 +5,21 @@ import 'package:hmg_patient_app_new/core/common_models/generic_api_model.dart';
import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
import 'package:hmg_patient_app_new/features/my_invoices/models/get_invoice_details_response_model.dart';
import 'package:hmg_patient_app_new/features/my_invoices/models/get_invoices_list_response_model.dart';
+import 'package:hmg_patient_app_new/features/my_invoices/models/get_pharmacy_invoices_response_model.dart';
import 'package:hmg_patient_app_new/services/logger_service.dart';
abstract class MyInvoicesRepo {
Future>>> getAllInvoicesList();
+ Future>>> getAllPharmacyInvoices();
+
Future>> getInvoiceDetails({required num appointmentNo, required num invoiceNo, required int projectID});
Future>> sendInvoiceEmail({required num appointmentNo, required int projectID});
Future>> downloadInvoice({required String setupId, required int invoiceNo, required int projectID});
+
+ Future>> downloadPharmacyInvoice({required String setupId, required int invoiceNo, required int projectID, required dynamic locationID});
}
class MyInvoicesRepoImp implements MyInvoicesRepo {
@@ -61,6 +66,47 @@ class MyInvoicesRepoImp implements MyInvoicesRepo {
}
}
+ @override
+ Future>>> getAllPharmacyInvoices() async {
+ Map mapDevice = {};
+
+ try {
+ GenericApiModel>? apiResponse;
+ Failure? failure;
+ await apiClient.post(
+ GET_ALL_PHARMACY_INVOICES,
+ body: mapDevice,
+ onFailure: (error, statusCode, {messageStatus, failureType}) {
+ failure = failureType;
+ },
+ onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
+ try {
+ final list = response['List_AllPharmacyInvoices'] ?? response['PharmacyInvoicesList'] ?? [];
+
+ final invoicesList = list
+ .map((item) => GetPharmacyInvoicesResponseModel.fromJson(item as Map))
+ .toList()
+ .cast();
+
+ apiResponse = GenericApiModel>(
+ messageStatus: messageStatus,
+ statusCode: statusCode,
+ errorMessage: null,
+ data: invoicesList,
+ );
+ } catch (e) {
+ failure = DataParsingFailure(e.toString());
+ }
+ },
+ );
+ if (failure != null) return Left(failure!);
+ if (apiResponse == null) return Left(ServerFailure("Unknown error"));
+ return Right(apiResponse!);
+ } catch (e) {
+ return Left(UnknownFailure(e.toString()));
+ }
+ }
+
@override
Future>> getInvoiceDetails({required num appointmentNo, required num invoiceNo, required int projectID}) async {
Map mapDevice = {
@@ -178,4 +224,43 @@ class MyInvoicesRepoImp implements MyInvoicesRepo {
return Left(UnknownFailure(e.toString()));
}
}
+
+ @override
+ Future> downloadPharmacyInvoice({required String setupId, required int invoiceNo, required int projectID, required dynamic locationID}) async {
+ Map mapDevice = {
+ "SetupID": setupId,
+ "ProjectID": projectID,
+ "InvoiceNo": invoiceNo,
+ "LocationID": locationID,
+ };
+
+ try {
+ GenericApiModel? apiResponse;
+ Failure? failure;
+ await apiClient.post(
+ DOWNLOAD_PHARMACY_INVOICE_PDF,
+ body: mapDevice,
+ onFailure: (error, statusCode, {messageStatus, failureType}) {
+ failure = failureType;
+ },
+ onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
+ try {
+ apiResponse = GenericApiModel(
+ messageStatus: messageStatus,
+ statusCode: statusCode,
+ errorMessage: null,
+ data: response["InvoiceReportPDFContent"],
+ );
+ } catch (e) {
+ failure = DataParsingFailure(e.toString());
+ }
+ },
+ );
+ if (failure != null) return Left(failure!);
+ if (apiResponse == null) return Left(ServerFailure("Unknown error"));
+ return Right(apiResponse!);
+ } catch (e) {
+ return Left(UnknownFailure(e.toString()));
+ }
+ }
}
diff --git a/lib/features/my_invoices/my_invoices_view_model.dart b/lib/features/my_invoices/my_invoices_view_model.dart
index e191b24d..49d37927 100644
--- a/lib/features/my_invoices/my_invoices_view_model.dart
+++ b/lib/features/my_invoices/my_invoices_view_model.dart
@@ -3,6 +3,7 @@ import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/core/dependencies.dart';
import 'package:hmg_patient_app_new/features/my_invoices/models/get_invoice_details_response_model.dart';
import 'package:hmg_patient_app_new/features/my_invoices/models/get_invoices_list_response_model.dart';
+import 'package:hmg_patient_app_new/features/my_invoices/models/get_pharmacy_invoices_response_model.dart';
import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_repo.dart';
import 'package:hmg_patient_app_new/services/error_handler_service.dart';
import 'package:hmg_patient_app_new/services/navigation_service.dart';
@@ -12,6 +13,7 @@ enum InvoiceFilterType { all, hospital, clinic, doctor }
class MyInvoicesViewModel extends ChangeNotifier {
bool isInvoicesListLoading = false;
bool isInvoiceDetailsLoading = false;
+ bool isPharmacyInvoicesLoading = false;
MyInvoicesRepo myInvoicesRepo;
ErrorHandlerService errorHandlerService;
@@ -19,6 +21,8 @@ class MyInvoicesViewModel extends ChangeNotifier {
List allInvoicesList = [];
List _originalInvoicesList = [];
+ List allPharmacyInvoicesList = [];
+ List _originalPharmacyInvoicesList = [];
InvoiceFilterType currentFilter = InvoiceFilterType.all;
late GetInvoiceDetailsResponseModel invoiceDetailsResponseModel;
@@ -29,14 +33,20 @@ class MyInvoicesViewModel extends ChangeNotifier {
String? selectedFilterItem;
String? downloadInvoicePDFBase64 = "";
+ String? downloadPharmacyInvoicePDFBase64 = "";
+
+ int selectedTabIndex = 0;
MyInvoicesViewModel({required this.myInvoicesRepo, required this.errorHandlerService, required this.navServices});
setInvoicesListLoading() {
isInvoicesListLoading = true;
+ isPharmacyInvoicesLoading = true;
allInvoicesList.clear();
+ allPharmacyInvoicesList.clear();
_originalInvoicesList.clear();
currentFilter = InvoiceFilterType.all;
+ onTabChanged(0);
notifyListeners();
}
@@ -45,6 +55,11 @@ class MyInvoicesViewModel extends ChangeNotifier {
notifyListeners();
}
+ void onTabChanged(int index) {
+ selectedTabIndex = index;
+ notifyListeners();
+ }
+
Future getAllInvoicesList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await myInvoicesRepo.getAllInvoicesList();
@@ -72,6 +87,40 @@ class MyInvoicesViewModel extends ChangeNotifier {
);
}
+ Future getAllPharmacyInvoices({Function(dynamic)? onSuccess, Function(String)? onError}) async {
+ isPharmacyInvoicesLoading = true;
+ allPharmacyInvoicesList.clear();
+ notifyListeners();
+
+ final result = await myInvoicesRepo.getAllPharmacyInvoices();
+
+ result.fold(
+ (failure) async {
+ isPharmacyInvoicesLoading = false;
+ notifyListeners();
+ if (onError != null) {
+ onError(failure.message);
+ }
+ },
+ (apiResponse) {
+ _originalPharmacyInvoicesList = [];
+ allPharmacyInvoicesList = [];
+ if (apiResponse.messageStatus == 2) {
+ // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
+ } else if (apiResponse.messageStatus == 1) {
+ _originalPharmacyInvoicesList = apiResponse.data ?? [];
+ _originalPharmacyInvoicesList.sort((a, b) => (b.appointmentDate ?? '').compareTo(a.appointmentDate ?? ''));
+ allPharmacyInvoicesList = List.from(_originalPharmacyInvoicesList);
+ isPharmacyInvoicesLoading = false;
+ notifyListeners();
+ if (onSuccess != null) {
+ onSuccess(apiResponse);
+ }
+ }
+ },
+ );
+ }
+
Future getInvoiceDetails({required num appointmentNo, required num invoiceNo, required int projectID, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await myInvoicesRepo.getInvoiceDetails(appointmentNo: appointmentNo, invoiceNo: invoiceNo, projectID: projectID);
result.fold(
@@ -144,6 +193,32 @@ class MyInvoicesViewModel extends ChangeNotifier {
);
}
+ Future downloadPharmacyInvoicePDF({required String setupId, required int invoiceNo, required int projectID, required dynamic locationID, Function(dynamic)? onSuccess, Function(String)? onError}) async {
+ final result = await myInvoicesRepo.downloadPharmacyInvoice(setupId: setupId, invoiceNo: invoiceNo, projectID: projectID, locationID: locationID);
+
+ result.fold(
+ (failure) async {
+ if (onError != null) {
+ onError(failure.message);
+ }
+ },
+ (apiResponse) {
+ if (apiResponse.messageStatus == 2) {
+ // dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
+ } else if (apiResponse.messageStatus == 1) {
+ if (apiResponse.data != null && apiResponse.data!.isNotEmpty) {
+ downloadPharmacyInvoicePDFBase64 = apiResponse.data!;
+ } else {
+ downloadPharmacyInvoicePDFBase64 = "";
+ }
+ if (onSuccess != null) {
+ onSuccess(apiResponse);
+ }
+ }
+ },
+ );
+ }
+
void filterInvoices(InvoiceFilterType filterType) {
currentFilter = filterType;
diff --git a/lib/features/paytabs/models/paytabs_transaction_response_model.dart b/lib/features/paytabs/models/paytabs_transaction_response_model.dart
new file mode 100644
index 00000000..57d23349
--- /dev/null
+++ b/lib/features/paytabs/models/paytabs_transaction_response_model.dart
@@ -0,0 +1,133 @@
+class PaytabsTransactionResponseModel {
+ int? tranTotal;
+ String? transactionReference;
+ String? cartCurrency;
+ String? cartDescription;
+ String? cartID;
+ String? tranCurrency;
+ String? payResponseReturn;
+ bool? isPending;
+ bool? isOnHold;
+ String? token;
+ String? transactionType;
+ bool? isAuthorized;
+ String? trace;
+ dynamic cartAmount;
+ int? merchantId;
+ int? profileId;
+ bool? isProcessed;
+ int? serviceId;
+ PaymentInfo? paymentInfo;
+ bool? isSuccess;
+
+ PaytabsTransactionResponseModel(
+ {this.tranTotal,
+ this.transactionReference,
+ this.cartCurrency,
+ this.cartDescription,
+ this.cartID,
+ this.tranCurrency,
+ this.payResponseReturn,
+ this.isPending,
+ this.isOnHold,
+ this.token,
+ this.transactionType,
+ this.isAuthorized,
+ this.trace,
+ this.cartAmount,
+ this.merchantId,
+ this.profileId,
+ this.isProcessed,
+ this.serviceId,
+ this.paymentInfo,
+ this.isSuccess});
+
+ PaytabsTransactionResponseModel.fromJson(Map json) {
+ tranTotal = json['tran_total'];
+ transactionReference = json['transactionReference'];
+ cartCurrency = json['cartCurrency'];
+ cartDescription = json['cartDescription'];
+ cartID = json['cartID'];
+ tranCurrency = json['tran_currency'];
+ payResponseReturn = json['payResponseReturn'];
+ isPending = json['isPending'];
+ isOnHold = json['isOnHold'];
+ token = json['token'];
+ transactionType = json['transactionType'];
+ isAuthorized = json['isAuthorized'];
+ trace = json['trace'];
+ cartAmount = json['cartAmount'];
+ merchantId = json['merchantId'];
+ profileId = json['profileId'];
+ isProcessed = json['isProcessed'];
+ serviceId = json['serviceId'];
+ paymentInfo = json['paymentInfo'] != null
+ ? PaymentInfo.fromJson(Map.from(json['paymentInfo'] as Map))
+ : null;
+ isSuccess = json['isSuccess'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['tran_total'] = this.tranTotal;
+ data['transactionReference'] = this.transactionReference;
+ data['cartCurrency'] = this.cartCurrency;
+ data['cartDescription'] = this.cartDescription;
+ data['cartID'] = this.cartID;
+ data['tran_currency'] = this.tranCurrency;
+ data['payResponseReturn'] = this.payResponseReturn;
+ data['isPending'] = this.isPending;
+ data['isOnHold'] = this.isOnHold;
+ data['token'] = this.token;
+ data['transactionType'] = this.transactionType;
+ data['isAuthorized'] = this.isAuthorized;
+ data['trace'] = this.trace;
+ data['cartAmount'] = this.cartAmount;
+ data['merchantId'] = this.merchantId;
+ data['profileId'] = this.profileId;
+ data['isProcessed'] = this.isProcessed;
+ data['serviceId'] = this.serviceId;
+ if (this.paymentInfo != null) {
+ data['paymentInfo'] = this.paymentInfo!.toJson();
+ }
+ data['isSuccess'] = this.isSuccess;
+ return data;
+ }
+}
+
+class PaymentInfo {
+ String? cardScheme;
+ String? cardType;
+ int? expiryMonth;
+ int? expiryYear;
+ String? paymentDescription;
+ String? paymentMethod;
+
+ PaymentInfo(
+ {this.cardScheme,
+ this.cardType,
+ this.expiryMonth,
+ this.expiryYear,
+ this.paymentDescription,
+ this.paymentMethod});
+
+ PaymentInfo.fromJson(Map json) {
+ cardScheme = json['cardScheme'];
+ cardType = json['cardType'];
+ expiryMonth = json['expiryMonth'];
+ expiryYear = json['expiryYear'];
+ paymentDescription = json['paymentDescription'];
+ paymentMethod = json['payment_method'];
+ }
+
+ Map toJson() {
+ final Map data = new Map();
+ data['cardScheme'] = this.cardScheme;
+ data['cardType'] = this.cardType;
+ data['expiryMonth'] = this.expiryMonth;
+ data['expiryYear'] = this.expiryYear;
+ data['paymentDescription'] = this.paymentDescription;
+ data['payment_method'] = this.paymentMethod;
+ return data;
+ }
+}
diff --git a/lib/features/paytabs/paytabs_service.dart b/lib/features/paytabs/paytabs_service.dart
new file mode 100644
index 00000000..6877389f
--- /dev/null
+++ b/lib/features/paytabs/paytabs_service.dart
@@ -0,0 +1,23 @@
+import 'package:dartz/dartz.dart';
+import 'package:hmg_patient_app_new/core/exceptions/api_failure.dart';
+
+abstract class PaytabsService {
+ Future> getAskDoctorAppointmentsList();
+
+ Future> getDoctorResponse();
+}
+
+class PaytabsServiceImp implements PaytabsService {
+ @override
+ Future> getAskDoctorAppointmentsList() {
+ // TODO: implement getAskDoctorAppointmentsList
+ throw UnimplementedError();
+ }
+
+ @override
+ Future> getDoctorResponse() {
+ // TODO: implement getDoctorResponse
+ throw UnimplementedError();
+ }
+
+}
diff --git a/lib/features/paytabs/paytabs_view_model.dart b/lib/features/paytabs/paytabs_view_model.dart
new file mode 100644
index 00000000..c922c752
--- /dev/null
+++ b/lib/features/paytabs/paytabs_view_model.dart
@@ -0,0 +1,136 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_paytabs_bridge/BaseBillingShippingInfo.dart';
+import 'package:flutter_paytabs_bridge/IOSThemeConfiguration.dart';
+import 'package:flutter_paytabs_bridge/PaymentSdkConfigurationDetails.dart';
+import 'package:flutter_paytabs_bridge/PaymentSdkLocale.dart';
+import 'package:flutter_paytabs_bridge/PaymentSdkTokeniseType.dart';
+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/enums.dart';
+import 'package:hmg_patient_app_new/core/paytabs_config.dart';
+import 'package:hmg_patient_app_new/features/paytabs/models/paytabs_transaction_response_model.dart';
+import 'package:hmg_patient_app_new/theme/colors.dart';
+
+class PayTabsViewModel extends ChangeNotifier {
+ late PaymentSdkConfigurationDetails paymentConfiguration;
+ final AppState appState;
+ late PaytabsTransactionResponseModel paytabsTransactionResponseModel;
+
+ PayTabsViewModel({
+ required this.appState,
+ });
+
+ setPaymentConfiguration(String paymentDescription, num amount) {
+ String cartID = DateTime.now().millisecondsSinceEpoch.toString();
+ paymentConfiguration = PaymentSdkConfigurationDetails(
+ profileId: PaymentSdkDefaultConfig.profileID,
+ serverKey: PaymentSdkDefaultConfig.serverKey,
+ clientKey: PaymentSdkDefaultConfig.clientKey,
+ transactionType: PaymentSdkTransactionType.SALE,
+ cartId: cartID.substring((cartID.length - 5), cartID.length),
+ cartDescription: paymentDescription,
+ merchantName: PaymentSdkDefaultConfig.defaultMerchantName,
+ locale: appState.isArabic() ? PaymentSdkLocale.AR : PaymentSdkLocale.EN,
+ merchantApplePayIndentifier:
+ ApiConsts.appEnvironmentType == AppEnvironmentTypeEnum.uat ? PaymentSdkDefaultConfig.defaultMerchantAppleBundleIDUAT : PaymentSdkDefaultConfig.defaultMerchantAppleBundleID,
+ // merchantApplePayIndentifier: PaymentSdkDefaultConfig.defaultMerchantAppleBundleIDUAT,
+ screentTitle: paymentDescription,
+ amount: amount.toDouble(),
+ showBillingInfo: false,
+ forceShippingInfo: false,
+ currencyCode: PaymentSdkDefaultConfig.defaultCurrency,
+ merchantCountryCode: PaymentSdkDefaultConfig.defaultMerchantCountryCode,
+ billingDetails: BillingDetails(
+ "${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}" ?? "HMG Patient", "CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com",
+ appState.getAuthenticatedUser()!.mobileNumber ?? "0000000000", "Riyadh", "SA", "Riyadh", "Riyadh", "12626"),
+ shippingDetails: ShippingDetails("${appState.getAuthenticatedUser()!.firstName} ${appState.getAuthenticatedUser()!.lastName}" ?? "HMG Patient", "CustID_${appState.getAuthenticatedUser()!.patientId.toString()}@HMG.com",
+ appState.getAuthenticatedUser()!.mobileNumber ?? "0000000000", "Riyadh", "SA", "Riyadh", "Riyadh", "12626"),
+ alternativePaymentMethods: [],
+ linkBillingNameWithCardHolderName: true,
+ simplifyApplePayValidation: true);
+
+ paymentConfiguration.iOSThemeConfigurations = IOSThemeConfigurations(
+ // logoImage: "assets/images/png/hmg_logo.png",
+ backgroundColor: "ffffff",
+ backgroundColorDark: "ffffff",
+ secondaryColor: "191919",
+ secondaryColorDark: "191919",
+ primaryColor: "ffffff",
+ primaryColorDark: "ffffff",
+ // primaryFont: "Poppins",
+ titleFontColor: "2E3039",
+ titleFontColorDark: "2E3039",
+ // titleFont: "Poppins",
+ primaryFontColor: "2E3039",
+ primaryFontColorDark: "2E3039",
+ inputFieldBackgroundColor: "ffffff",
+ inputFieldBackgroundColorDark: "ffffff",
+ placeholderColor: "2E3039",
+ placeholderColorDark: "2E3039",
+ buttonColor: "ED1C2B",
+ buttonColorDark: "ED1C2B",
+ // buttonFont: "Poppins",
+ );
+ paymentConfiguration.tokeniseType = PaymentSdkTokeniseType.MERCHANT_MANDATORY;
+
+ notifyListeners();
+ }
+
+ startApplePayPayment({Function(PaytabsTransactionResponseModel)? onSuccess, Function(String)? onError}) {
+ FlutterPaytabsBridge.startApplePayPayment(paymentConfiguration, (event) {
+ final transactionDetails = event["data"] as Map