diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 2ac175e9..526b9ffe 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -1968,11 +1968,7 @@ "cashRefundLimitExceeded": "يمكنك فقط التقدم بطلب استرداد نقدي إذا كان المبلغ أقل من 5000. لمزيد من المعلومات يرجى زيارتنا.", "cashRefundInstructions": "بمجرد الموافقة على الطلب، يرجى زيارة صراف مستشفى الحبيب الطبي أو الحبيب للرعاية الأولية لاستلام النقد. عند نافذة الصراف، سوف تتلقى رمز التحقق على رقم هاتفك المسجل. قدم الرمز للصراف للتحقق منه. سيتم صرف النقد فقط بعد التحقق الناجح.", "cashRefundApprovalInstructions": "بمجرد الموافقة على الطلب،\nيرجى زيارة صراف مستشفى الحبيب الطبي أو الحبيب للرعاية الأولية لاستلام النقد.\nعند نافذة الصراف، سوف تتلقى رمز التحقق على رقم هاتفك المسجل. قدم الرمز للصراف للتحقق منه. سيتم صرف النقد فقط بعد التحقق الناجح.", - "packageRefundValidationMessage": "طلب استرداد الباقة الخاص بك يتطلب التحقق بسبب استخدام الباقة والفواتير الفرعية ذات الصلة. سنقوم بمراجعة ومعالجة الطلب ضمن اتفاقية مستوى الخدمة المعتمدة بعد تأكيد الأهلية." - "invoiceHistory": "سجل الفواتير", - "refund": "استرداد", - "invoiceHistory": "سجل الفواتير", - "refund": "استرداد", + "packageRefundValidationMessage": "طلب استرداد الباقة الخاص بك يتطلب التحقق بسبب استخدام الباقة والفواتير الفرعية ذات الصلة. سنقوم بمراجعة ومعالجة الطلب ضمن اتفاقية مستوى الخدمة المعتمدة بعد تأكيد الأهلية.", "parkingQR": "رمز الاستجابة السريعة لوقوف السيارات", "parkingQRDesc": "امسح رمز الاستجابة السريعة (QR Code) أدناه عند بوابة الخروج من موقف السيارات:" } diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index 2dcfe244..d74da82a 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -1958,11 +1958,10 @@ "cashRefundLimitExceeded": "You can only apply for cash refund if the amount is less than 5000. For more information please visit us.", "cashRefundInstructions": "Once the request is approved, Please visit HMG Hospital or HMG Primary Care cashier to receive cash. At the cashier counter, you will receive an OTP on your registered mobile number. Provide the OTP to the cashier for validation. Cash will be released only after successful validation.", "cashRefundApprovalInstructions": "Once the request is approved,\nPlease visit HMG Hospital or HMG Primary Care cashier to receive cash.\nAt the cashier counter, you will receive an OTP on your registered mobile number. Provide the OTP to the cashier for validation. Cash will be released only after successful validation.", - "packageRefundValidationMessage": "Your package refund request required validation because of package use and related child invoices. We will review the process the request within the approved SLA after confirming eligibility." - - "invoiceHistory": "Invoice History", + "packageRefundValidationMessage": "Your package refund request required validation because of package use and related child invoices. We will review the process the request within the approved SLA after confirming eligibility.", "parkingQR": "Parking QR Code", "parkingQRDesc": "Scan the below QR Code at the exit parking gate:" } + diff --git a/lib/core/api/api_client.dart b/lib/core/api/api_client.dart index ed52b416..e0c3c41c 100644 --- a/lib/core/api/api_client.dart +++ b/lib/core/api/api_client.dart @@ -212,8 +212,8 @@ class ApiClientImp implements ApiClient { body['TokenID'] = "@dm!n"; // body['PatientID'] = 6424682; - // body['PatientID'] = 4770714; - body['PatientID'] = 4771727; + body['PatientID'] = 4770714; + // body['PatientID'] = 4771727; // body['PatientID'] = 89754444; // body['PatientTypeID'] = 1; // body['PatientOutSA'] = 0; diff --git a/lib/core/api_consts.dart b/lib/core/api_consts.dart index e89841d2..9397a795 100644 --- a/lib/core/api_consts.dart +++ b/lib/core/api_consts.dart @@ -288,6 +288,7 @@ class ApiConsts { static String getRefundInvoices = "Services/COCWS.svc/REST/GetRefundInvoices"; static String submitRefund = "Services/COCWS.svc/REST/SubmitRefund"; static String isRefundableInvoice = "Services/Outps.svc/REST/isRefundableInvoice"; + static String getThresholdAmount = "Services/OUTPs.svc/REST/HIS_getThresholdAmount"; static String getAiAnalysisURL = "https://api.labpredict.com"; static String getAiRadiologyAnalysis = "$getAiAnalysisURL/radiology"; diff --git a/lib/features/habib_wallet/habib_wallet_view_model.dart b/lib/features/habib_wallet/habib_wallet_view_model.dart index 2586d862..9afc65d8 100644 --- a/lib/features/habib_wallet/habib_wallet_view_model.dart +++ b/lib/features/habib_wallet/habib_wallet_view_model.dart @@ -11,6 +11,7 @@ import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/ import 'package:hmg_patient_app_new/features/refund_request/models/req_models/submit_refund_request_model.dart'; import 'package:hmg_patient_app_new/features/refund_request/models/resp_models/refund_request_list_response_model.dart'; import 'package:hmg_patient_app_new/features/refund_request/models/resp_models/refundable_invoices_response_model.dart'; +import 'package:hmg_patient_app_new/features/refund_request/models/resp_models/threshold_amount_response_model.dart'; import 'package:hmg_patient_app_new/features/refund_request/refund_request_repo.dart'; import 'package:hmg_patient_app_new/features/refund_request/refund_request_view_model.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; @@ -712,4 +713,48 @@ class HabibWalletViewModel extends ChangeNotifier { }, ); } + + // ── Threshold Amount ────────────────────────────────────────────────────── + double thresholdAmount = 5000.0; + bool isThresholdAmountLoading = false; + + Future getThresholdAmount({ + required int projectId, + Function(double)? onSuccess, + Function(String)? onError, + }) async { + isThresholdAmountLoading = true; + notifyListeners(); + + final result = await refundRequestRepo.getThresholdAmount(projectId: projectId); + + result.fold( + (failure) { + isThresholdAmountLoading = false; + thresholdAmount = 5000.0; + notifyListeners(); + if (onError != null) { + onError(failure.message); + } + }, + (apiResponse) { + isThresholdAmountLoading = false; + if (apiResponse.messageStatus == 1 && apiResponse.data != null && apiResponse.data!.thresholdAmountList != null) { + final thresholdItem = apiResponse.data!.thresholdAmountList!.firstWhere( + (item) => item.projectID == projectId, + orElse: () => ThresholdAmountItem(thresholdAvailableAmountByProject: 5000.0), + ); + thresholdAmount = thresholdItem.thresholdAvailableAmountByProject ?? 5000.0; + notifyListeners(); + if (onSuccess != null) onSuccess(thresholdAmount); + } else { + thresholdAmount = 5000.0; + notifyListeners(); + if (onError != null) { + onError(apiResponse.errorMessage ?? "Failed to get threshold amount"); + } + } + }, + ); + } } diff --git a/lib/features/refund_request/models/resp_models/threshold_amount_response_model.dart b/lib/features/refund_request/models/resp_models/threshold_amount_response_model.dart new file mode 100644 index 00000000..698e6b01 --- /dev/null +++ b/lib/features/refund_request/models/resp_models/threshold_amount_response_model.dart @@ -0,0 +1,50 @@ +class ThresholdAmountResponseModel { + final List? thresholdAmountList; + + ThresholdAmountResponseModel({this.thresholdAmountList}); + + factory ThresholdAmountResponseModel.fromJson(Map json) { + return ThresholdAmountResponseModel( + thresholdAmountList: json['ThresholdAmountList'] != null + ? (json['ThresholdAmountList'] as List) + .map((item) => ThresholdAmountItem.fromJson(item as Map)) + .toList() + : null, + ); + } + + Map toJson() { + return { + 'ThresholdAmountList': thresholdAmountList?.map((item) => item.toJson()).toList(), + }; + } +} + +class ThresholdAmountItem { + final int? projectID; + final double? thresholdAvailableAmountByProject; + + ThresholdAmountItem({ + this.projectID, + this.thresholdAvailableAmountByProject, + }); + + factory ThresholdAmountItem.fromJson(Map json) { + return ThresholdAmountItem( + projectID: json['ProjectID'] as int?, + thresholdAvailableAmountByProject: json['ThresholdAvailableAmountByProject'] != null + ? (json['ThresholdAvailableAmountByProject'] is int + ? (json['ThresholdAvailableAmountByProject'] as int).toDouble() + : json['ThresholdAvailableAmountByProject'] as double) + : null, + ); + } + + Map toJson() { + return { + 'ProjectID': projectID, + 'ThresholdAvailableAmountByProject': thresholdAvailableAmountByProject, + }; + } +} + diff --git a/lib/features/refund_request/refund_request_repo.dart b/lib/features/refund_request/refund_request_repo.dart index eaf7d9e0..cd07a25e 100644 --- a/lib/features/refund_request/refund_request_repo.dart +++ b/lib/features/refund_request/refund_request_repo.dart @@ -7,6 +7,7 @@ import 'package:hmg_patient_app_new/features/refund_request/models/req_models/su import 'package:hmg_patient_app_new/features/refund_request/models/resp_models/is_refundable_invoice_response_model.dart'; import 'package:hmg_patient_app_new/features/refund_request/models/resp_models/refund_request_list_response_model.dart'; import 'package:hmg_patient_app_new/features/refund_request/models/resp_models/refundable_invoices_response_model.dart'; +import 'package:hmg_patient_app_new/features/refund_request/models/resp_models/threshold_amount_response_model.dart'; import 'package:hmg_patient_app_new/services/logger_service.dart'; abstract class RefundRequestRepo { @@ -33,6 +34,8 @@ abstract class RefundRequestRepo { required int invoiceNo, required int projectId, }); + + Future>> getThresholdAmount({required int projectId}); } class RefundRequestRepoImp implements RefundRequestRepo { @@ -357,4 +360,46 @@ class RefundRequestRepoImp implements RefundRequestRepo { return Left(UnknownFailure(e.toString())); } } + + @override + Future>> getThresholdAmount({required int projectId}) async { + final Map body = { + "ProjectID": projectId, + }; + + try { + GenericApiModel? apiResponse; + Failure? failure; + + await apiClient.post( + ApiConsts.getThresholdAmount, + body: body, + onFailure: (error, statusCode, {messageStatus, failureType}) { + failure = failureType; + }, + onSuccess: (response, statusCode, {messageStatus, errorMessage}) { + try { + final ThresholdAmountResponseModel model = ThresholdAmountResponseModel.fromJson(response); + + apiResponse = GenericApiModel( + messageStatus: messageStatus, + statusCode: statusCode, + errorMessage: errorMessage, + data: model, + ); + } catch (e) { + loggerService.logError("getThresholdAmount parsing error: $e"); + failure = DataParsingFailure(e.toString()); + } + }, + ); + + if (failure != null) return Left(failure!); + if (apiResponse == null) return Left(ServerFailure("Unknown error")); + return Right(apiResponse!); + } catch (e) { + loggerService.logError("getThresholdAmount exception: $e"); + return Left(UnknownFailure(e.toString())); + } + } } diff --git a/lib/features/refund_request/refund_request_view_model.dart b/lib/features/refund_request/refund_request_view_model.dart index 1b77c007..e19ee464 100644 --- a/lib/features/refund_request/refund_request_view_model.dart +++ b/lib/features/refund_request/refund_request_view_model.dart @@ -7,6 +7,7 @@ import 'package:hmg_patient_app_new/features/refund_request/models/req_models/su import 'package:hmg_patient_app_new/features/refund_request/models/resp_models/is_refundable_invoice_response_model.dart'; import 'package:hmg_patient_app_new/features/refund_request/models/resp_models/refund_request_list_response_model.dart'; import 'package:hmg_patient_app_new/features/refund_request/models/resp_models/refundable_invoices_response_model.dart'; +import 'package:hmg_patient_app_new/features/refund_request/models/resp_models/threshold_amount_response_model.dart'; import 'package:hmg_patient_app_new/features/refund_request/refund_request_repo.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/services/error_handler_service.dart'; @@ -624,4 +625,48 @@ class RefundRequestViewModel extends ChangeNotifier { }, ); } + + // ── Threshold Amount ────────────────────────────────────────────────────── + double thresholdAmount = 5000.0; + bool isThresholdAmountLoading = false; + + Future getThresholdAmount({ + required int projectId, + Function(double)? onSuccess, + Function(String)? onError, + }) async { + isThresholdAmountLoading = true; + notifyListeners(); + + final result = await refundRequestRepo.getThresholdAmount(projectId: projectId); + + result.fold( + (failure) { + isThresholdAmountLoading = false; + thresholdAmount = 5000.0; + notifyListeners(); + if (onError != null) { + onError(failure.message); + } + }, + (apiResponse) { + isThresholdAmountLoading = false; + if (apiResponse.messageStatus == 1 && apiResponse.data != null && apiResponse.data!.thresholdAmountList != null) { + final thresholdItem = apiResponse.data!.thresholdAmountList!.firstWhere( + (item) => item.projectID == projectId, + orElse: () => ThresholdAmountItem(thresholdAvailableAmountByProject: 5000.0), + ); + thresholdAmount = thresholdItem.thresholdAvailableAmountByProject ?? 5000.0; + notifyListeners(); + if (onSuccess != null) onSuccess(thresholdAmount); + } else { + thresholdAmount = 5000.0; + notifyListeners(); + if (onError != null) { + onError(apiResponse.errorMessage ?? "Failed to get threshold amount"); + } + } + }, + ); + } } diff --git a/lib/presentation/habib_wallet/withdraw_request_create_page.dart b/lib/presentation/habib_wallet/withdraw_request_create_page.dart index 04abda32..808fdda3 100644 --- a/lib/presentation/habib_wallet/withdraw_request_create_page.dart +++ b/lib/presentation/habib_wallet/withdraw_request_create_page.dart @@ -461,6 +461,12 @@ class _WithdrawRequestCreatePageState extends State { onHospitalSelected: (hospital) { habibWalletViewModel.setSelectedHospital(hospital); habibWalletViewModel.fetchAdvancesForHospital(); + if (hospital.iD != null) { + final projectId = hospital.iD is int ? hospital.iD as int : int.tryParse(hospital.iD.toString()); + if (projectId != null) { + habibWalletViewModel.getThresholdAmount(projectId: projectId); + } + } }, ), callBackFunc: () {}, diff --git a/lib/presentation/refund_request/refund_request_create_page.dart b/lib/presentation/refund_request/refund_request_create_page.dart index 5c27a908..5f9ddb53 100644 --- a/lib/presentation/refund_request/refund_request_create_page.dart +++ b/lib/presentation/refund_request/refund_request_create_page.dart @@ -64,6 +64,7 @@ class _RefundRequestCreatePageState extends State { _ibanController.addListener(() => _refundRequestViewModel.triggerRebuild()); _descriptionController.addListener(() => _refundRequestViewModel.triggerRebuild()); _loadInvoiceDetails(); + _loadThresholdAmount(); }); } @@ -122,6 +123,13 @@ class _RefundRequestCreatePageState extends State { ); } + void _loadThresholdAmount() { + final projectId = widget.invoice.projectId; + if (projectId == null) return; + + _refundRequestViewModel.getThresholdAmount(projectId: projectId); + } + // ── Stepper ─────────────────────────────────────────────────────────────── Widget _buildStepper(RefundRequestViewModel vm) {