My invoices implemented

pull/142/head
haroon amjad 2 weeks ago
parent 93979707e4
commit 6f067d92d6

@ -34,6 +34,8 @@ 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/appointment_via_region_viewmodel.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart'; import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_repo.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.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_repo.dart';
import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_view_model.dart';
import 'package:hmg_patient_app_new/features/payfort/payfort_repo.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/payfort/payfort_view_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_repo.dart'; import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_repo.dart';
@ -138,6 +140,7 @@ class AppDependencies {
getIt.registerLazySingleton<SymptomsCheckerRepo>(() => SymptomsCheckerRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt())); getIt.registerLazySingleton<SymptomsCheckerRepo>(() => SymptomsCheckerRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<BloodDonationRepo>(() => BloodDonationRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt())); getIt.registerLazySingleton<BloodDonationRepo>(() => BloodDonationRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<WaterMonitorRepo>(() => WaterMonitorRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt())); getIt.registerLazySingleton<WaterMonitorRepo>(() => WaterMonitorRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
getIt.registerLazySingleton<MyInvoicesRepo>(() => MyInvoicesRepoImp(loggerService: getIt<LoggerService>(), apiClient: getIt()));
// ViewModels // ViewModels
// Global/shared VMs LazySingleton // Global/shared VMs LazySingleton
@ -271,5 +274,7 @@ class AppDependencies {
getIt.registerLazySingleton<HealthProvider>(() => HealthProvider()); getIt.registerLazySingleton<HealthProvider>(() => HealthProvider());
getIt.registerLazySingleton<WaterMonitorViewModel>(() => WaterMonitorViewModel(waterMonitorRepo: getIt())); getIt.registerLazySingleton<WaterMonitorViewModel>(() => WaterMonitorViewModel(waterMonitorRepo: getIt()));
getIt.registerLazySingleton<MyInvoicesViewModel>(() => MyInvoicesViewModel(myInvoicesRepo: getIt(), errorHandlerService: getIt(), navServices: getIt()));
} }
} }

@ -0,0 +1,489 @@
class GetInvoiceDetailsResponseModel {
int? projectID;
int? doctorID;
num? grandTotal;
num? quantity;
num? total;
num? discount;
num? subTotal;
int? invoiceNo;
String? createdOn;
String? procedureID;
String? procedureName;
String? procedureNameN;
num? procedurePrice;
num? patientShare;
num? companyShare;
num? totalPatientShare;
num? totalCompanyShare;
num? totalShare;
num? discountAmount;
num? vATPercentage;
num? patientVATAmount;
num? companyVATAmount;
num? totalVATAmount;
num? price;
int? patientID;
String? patientIdentificationNo;
String? patientName;
String? patientNameN;
String? nationalityID;
String? doctorName;
String? doctorNameN;
int? clinicID;
String? clinicDescription;
String? clinicDescriptionN;
String? appointmentDate;
int? appointmentNo;
String? insuranceID;
int? companyID;
String? companyName;
String? companyNameN;
String? companyAddress;
String? companyAddressN;
String? companyGroupAddress;
String? groupName;
String? groupNameN;
String? patientAddress;
String? vATNo;
String? paymentDate;
String? projectName;
num? totalDiscount;
num? totalPatientShareWithQuantity;
String? legalName;
String? legalNameN;
num? advanceAdjustment;
String? patientCityName;
String? patientCityNameN;
String? doctorImageURL;
List<ListConsultation>? listConsultation;
GetInvoiceDetailsResponseModel(
{this.projectID,
this.doctorID,
this.grandTotal,
this.quantity,
this.total,
this.discount,
this.subTotal,
this.invoiceNo,
this.createdOn,
this.procedureID,
this.procedureName,
this.procedureNameN,
this.procedurePrice,
this.patientShare,
this.companyShare,
this.totalPatientShare,
this.totalCompanyShare,
this.totalShare,
this.discountAmount,
this.vATPercentage,
this.patientVATAmount,
this.companyVATAmount,
this.totalVATAmount,
this.price,
this.patientID,
this.patientIdentificationNo,
this.patientName,
this.patientNameN,
this.nationalityID,
this.doctorName,
this.doctorNameN,
this.clinicID,
this.clinicDescription,
this.clinicDescriptionN,
this.appointmentDate,
this.appointmentNo,
this.insuranceID,
this.companyID,
this.companyName,
this.companyNameN,
this.companyAddress,
this.companyAddressN,
this.companyGroupAddress,
this.groupName,
this.groupNameN,
this.patientAddress,
this.vATNo,
this.paymentDate,
this.projectName,
this.totalDiscount,
this.totalPatientShareWithQuantity,
this.legalName,
this.legalNameN,
this.advanceAdjustment,
this.patientCityName,
this.patientCityNameN,
this.doctorImageURL,
this.listConsultation});
GetInvoiceDetailsResponseModel.fromJson(Map<String, dynamic> json) {
projectID = json['ProjectID'];
doctorID = json['DoctorID'];
grandTotal = json['GrandTotal'];
quantity = json['Quantity'];
total = json['Total'];
discount = json['Discount'];
subTotal = json['SubTotal'];
invoiceNo = json['InvoiceNo'];
createdOn = json['CreatedOn'];
procedureID = json['ProcedureID'];
procedureName = json['ProcedureName'];
procedureNameN = json['ProcedureNameN'];
procedurePrice = json['ProcedurePrice'];
patientShare = json['PatientShare'];
companyShare = json['CompanyShare'];
totalPatientShare = json['TotalPatientShare'];
totalCompanyShare = json['TotalCompanyShare'];
totalShare = json['TotalShare'];
discountAmount = json['DiscountAmount'];
vATPercentage = json['VATPercentage'];
patientVATAmount = json['PatientVATAmount'];
companyVATAmount = json['CompanyVATAmount'];
totalVATAmount = json['TotalVATAmount'];
price = json['Price'];
patientID = json['PatientID'];
patientIdentificationNo = json['PatientIdentificationNo'];
patientName = json['PatientName'];
patientNameN = json['PatientNameN'];
nationalityID = json['NationalityID'];
doctorName = json['DoctorName'];
doctorNameN = json['DoctorNameN'];
clinicID = json['ClinicID'];
clinicDescription = json['ClinicDescription'];
clinicDescriptionN = json['ClinicDescriptionN'];
appointmentDate = json['AppointmentDate'];
appointmentNo = json['AppointmentNo'];
insuranceID = json['InsuranceID'];
companyID = json['CompanyID'];
companyName = json['CompanyName'];
companyNameN = json['CompanyNameN'];
companyAddress = json['CompanyAddress'];
companyAddressN = json['CompanyAddressN'];
companyGroupAddress = json['CompanyGroupAddress'];
groupName = json['GroupName'];
groupNameN = json['GroupNameN'];
patientAddress = json['PatientAddress'];
vATNo = json['VATNo'];
paymentDate = json['PaymentDate'];
projectName = json['ProjectName'];
totalDiscount = json['TotalDiscount'];
totalPatientShareWithQuantity = json['TotalPatientShareWithQuantity'];
legalName = json['LegalName'];
legalNameN = json['LegalNameN'];
advanceAdjustment = json['AdvanceAdjustment'];
patientCityName = json['PatientCityName'];
patientCityNameN = json['PatientCityNameN'];
doctorImageURL = json['DoctorImageURL'];
if (json['listConsultation'] != null) {
listConsultation = <ListConsultation>[];
json['listConsultation'].forEach((v) {
listConsultation!.add(new ListConsultation.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['ProjectID'] = this.projectID;
data['DoctorID'] = this.doctorID;
data['GrandTotal'] = this.grandTotal;
data['Quantity'] = this.quantity;
data['Total'] = this.total;
data['Discount'] = this.discount;
data['SubTotal'] = this.subTotal;
data['InvoiceNo'] = this.invoiceNo;
data['CreatedOn'] = this.createdOn;
data['ProcedureID'] = this.procedureID;
data['ProcedureName'] = this.procedureName;
data['ProcedureNameN'] = this.procedureNameN;
data['ProcedurePrice'] = this.procedurePrice;
data['PatientShare'] = this.patientShare;
data['CompanyShare'] = this.companyShare;
data['TotalPatientShare'] = this.totalPatientShare;
data['TotalCompanyShare'] = this.totalCompanyShare;
data['TotalShare'] = this.totalShare;
data['DiscountAmount'] = this.discountAmount;
data['VATPercentage'] = this.vATPercentage;
data['PatientVATAmount'] = this.patientVATAmount;
data['CompanyVATAmount'] = this.companyVATAmount;
data['TotalVATAmount'] = this.totalVATAmount;
data['Price'] = this.price;
data['PatientID'] = this.patientID;
data['PatientIdentificationNo'] = this.patientIdentificationNo;
data['PatientName'] = this.patientName;
data['PatientNameN'] = this.patientNameN;
data['NationalityID'] = this.nationalityID;
data['DoctorName'] = this.doctorName;
data['DoctorNameN'] = this.doctorNameN;
data['ClinicID'] = this.clinicID;
data['ClinicDescription'] = this.clinicDescription;
data['ClinicDescriptionN'] = this.clinicDescriptionN;
data['AppointmentDate'] = this.appointmentDate;
data['AppointmentNo'] = this.appointmentNo;
data['InsuranceID'] = this.insuranceID;
data['CompanyID'] = this.companyID;
data['CompanyName'] = this.companyName;
data['CompanyNameN'] = this.companyNameN;
data['CompanyAddress'] = this.companyAddress;
data['CompanyAddressN'] = this.companyAddressN;
data['CompanyGroupAddress'] = this.companyGroupAddress;
data['GroupName'] = this.groupName;
data['GroupNameN'] = this.groupNameN;
data['PatientAddress'] = this.patientAddress;
data['VATNo'] = this.vATNo;
data['PaymentDate'] = this.paymentDate;
data['ProjectName'] = this.projectName;
data['TotalDiscount'] = this.totalDiscount;
data['TotalPatientShareWithQuantity'] = this.totalPatientShareWithQuantity;
data['LegalName'] = this.legalName;
data['LegalNameN'] = this.legalNameN;
data['AdvanceAdjustment'] = this.advanceAdjustment;
data['PatientCityName'] = this.patientCityName;
data['PatientCityNameN'] = this.patientCityNameN;
data['DoctorImageURL'] = this.doctorImageURL;
if (this.listConsultation != null) {
data['listConsultation'] =
this.listConsultation!.map((v) => v.toJson()).toList();
}
return data;
}
}
class ListConsultation {
int? projectID;
int? doctorID;
num? grandTotal;
int? quantity;
num? total;
num? discount;
num? subTotal;
int? invoiceNo;
String? createdOn;
String? procedureID;
String? procedureName;
String? procedureNameN;
num? procedurePrice;
num? patientShare;
num? companyShare;
num? totalPatientShare;
num? totalCompanyShare;
num? totalShare;
num? discountAmount;
num? vATPercentage;
num? patientVATAmount;
num? companyVATAmount;
num? totalVATAmount;
num? price;
int? patientID;
int? patientIdentificationNo;
String? patientName;
String? patientNameN;
String? nationalityID;
String? doctorName;
String? doctorNameN;
int? clinicID;
String? clinicDescription;
String? clinicDescriptionN;
String? appointmentDate;
dynamic appointmentNo;
dynamic insuranceID;
dynamic companyID;
String? companyName;
String? companyNameN;
String? companyAddress;
String? companyAddressN;
String? companyGroupAddress;
String? groupName;
String? groupNameN;
String? patientAddress;
String? vATNo;
String? paymentDate;
String? projectName;
num? totalDiscount;
num? totalPatientShareWithQuantity;
String? legalName;
String? legalNameN;
num? advanceAdjustment;
String? patientCityName;
String? patientCityNameN;
ListConsultation(
{this.projectID,
this.doctorID,
this.grandTotal,
this.quantity,
this.total,
this.discount,
this.subTotal,
this.invoiceNo,
this.createdOn,
this.procedureID,
this.procedureName,
this.procedureNameN,
this.procedurePrice,
this.patientShare,
this.companyShare,
this.totalPatientShare,
this.totalCompanyShare,
this.totalShare,
this.discountAmount,
this.vATPercentage,
this.patientVATAmount,
this.companyVATAmount,
this.totalVATAmount,
this.price,
this.patientID,
this.patientIdentificationNo,
this.patientName,
this.patientNameN,
this.nationalityID,
this.doctorName,
this.doctorNameN,
this.clinicID,
this.clinicDescription,
this.clinicDescriptionN,
this.appointmentDate,
this.appointmentNo,
this.insuranceID,
this.companyID,
this.companyName,
this.companyNameN,
this.companyAddress,
this.companyAddressN,
this.companyGroupAddress,
this.groupName,
this.groupNameN,
this.patientAddress,
this.vATNo,
this.paymentDate,
this.projectName,
this.totalDiscount,
this.totalPatientShareWithQuantity,
this.legalName,
this.legalNameN,
this.advanceAdjustment,
this.patientCityName,
this.patientCityNameN});
ListConsultation.fromJson(Map<String, dynamic> json) {
projectID = json['ProjectID'];
doctorID = json['DoctorID'];
grandTotal = json['GrandTotal'];
quantity = json['Quantity'];
total = json['Total'];
discount = json['Discount'];
subTotal = json['SubTotal'];
invoiceNo = json['InvoiceNo'];
createdOn = json['CreatedOn'];
procedureID = json['ProcedureID'];
procedureName = json['ProcedureName'];
procedureNameN = json['ProcedureNameN'];
procedurePrice = json['ProcedurePrice'];
patientShare = json['PatientShare'];
companyShare = json['CompanyShare'];
totalPatientShare = json['TotalPatientShare'];
totalCompanyShare = json['TotalCompanyShare'];
totalShare = json['TotalShare'];
discountAmount = json['DiscountAmount'];
vATPercentage = json['VATPercentage'];
patientVATAmount = json['PatientVATAmount'];
companyVATAmount = json['CompanyVATAmount'];
totalVATAmount = json['TotalVATAmount'];
price = json['Price'];
patientID = json['PatientID'];
patientIdentificationNo = json['PatientIdentificationNo'];
patientName = json['PatientName'];
patientNameN = json['PatientNameN'];
nationalityID = json['NationalityID'];
doctorName = json['DoctorName'];
doctorNameN = json['DoctorNameN'];
clinicID = json['ClinicID'];
clinicDescription = json['ClinicDescription'];
clinicDescriptionN = json['ClinicDescriptionN'];
appointmentDate = json['AppointmentDate'];
appointmentNo = json['AppointmentNo'];
insuranceID = json['InsuranceID'];
companyID = json['CompanyID'];
companyName = json['CompanyName'];
companyNameN = json['CompanyNameN'];
companyAddress = json['CompanyAddress'];
companyAddressN = json['CompanyAddressN'];
companyGroupAddress = json['CompanyGroupAddress'];
groupName = json['GroupName'];
groupNameN = json['GroupNameN'];
patientAddress = json['PatientAddress'];
vATNo = json['VATNo'];
paymentDate = json['PaymentDate'];
projectName = json['ProjectName'];
totalDiscount = json['TotalDiscount'];
totalPatientShareWithQuantity = json['TotalPatientShareWithQuantity'];
legalName = json['LegalName'];
legalNameN = json['LegalNameN'];
advanceAdjustment = json['AdvanceAdjustment'];
patientCityName = json['PatientCityName'];
patientCityNameN = json['PatientCityNameN'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['ProjectID'] = this.projectID;
data['DoctorID'] = this.doctorID;
data['GrandTotal'] = this.grandTotal;
data['Quantity'] = this.quantity;
data['Total'] = this.total;
data['Discount'] = this.discount;
data['SubTotal'] = this.subTotal;
data['InvoiceNo'] = this.invoiceNo;
data['CreatedOn'] = this.createdOn;
data['ProcedureID'] = this.procedureID;
data['ProcedureName'] = this.procedureName;
data['ProcedureNameN'] = this.procedureNameN;
data['ProcedurePrice'] = this.procedurePrice;
data['PatientShare'] = this.patientShare;
data['CompanyShare'] = this.companyShare;
data['TotalPatientShare'] = this.totalPatientShare;
data['TotalCompanyShare'] = this.totalCompanyShare;
data['TotalShare'] = this.totalShare;
data['DiscountAmount'] = this.discountAmount;
data['VATPercentage'] = this.vATPercentage;
data['PatientVATAmount'] = this.patientVATAmount;
data['CompanyVATAmount'] = this.companyVATAmount;
data['TotalVATAmount'] = this.totalVATAmount;
data['Price'] = this.price;
data['PatientID'] = this.patientID;
data['PatientIdentificationNo'] = this.patientIdentificationNo;
data['PatientName'] = this.patientName;
data['PatientNameN'] = this.patientNameN;
data['NationalityID'] = this.nationalityID;
data['DoctorName'] = this.doctorName;
data['DoctorNameN'] = this.doctorNameN;
data['ClinicID'] = this.clinicID;
data['ClinicDescription'] = this.clinicDescription;
data['ClinicDescriptionN'] = this.clinicDescriptionN;
data['AppointmentDate'] = this.appointmentDate;
data['AppointmentNo'] = this.appointmentNo;
data['InsuranceID'] = this.insuranceID;
data['CompanyID'] = this.companyID;
data['CompanyName'] = this.companyName;
data['CompanyNameN'] = this.companyNameN;
data['CompanyAddress'] = this.companyAddress;
data['CompanyAddressN'] = this.companyAddressN;
data['CompanyGroupAddress'] = this.companyGroupAddress;
data['GroupName'] = this.groupName;
data['GroupNameN'] = this.groupNameN;
data['PatientAddress'] = this.patientAddress;
data['VATNo'] = this.vATNo;
data['PaymentDate'] = this.paymentDate;
data['ProjectName'] = this.projectName;
data['TotalDiscount'] = this.totalDiscount;
data['TotalPatientShareWithQuantity'] = this.totalPatientShareWithQuantity;
data['LegalName'] = this.legalName;
data['LegalNameN'] = this.legalNameN;
data['AdvanceAdjustment'] = this.advanceAdjustment;
data['PatientCityName'] = this.patientCityName;
data['PatientCityNameN'] = this.patientCityNameN;
return data;
}
}

@ -0,0 +1,88 @@
class GetInvoicesListResponseModel {
String? setupId;
int? projectID;
int? patientID;
int? appointmentNo;
String? appointmentDate;
String? appointmentDateN;
int? clinicID;
int? doctorID;
int? invoiceNo;
int? status;
String? arrivedOn;
String? doctorName;
String? doctorNameN;
String? clinicName;
double? decimalDoctorRate;
String? doctorImageURL;
int? doctorRate;
int? patientNumber;
String? projectName;
GetInvoicesListResponseModel(
{this.setupId,
this.projectID,
this.patientID,
this.appointmentNo,
this.appointmentDate,
this.appointmentDateN,
this.clinicID,
this.doctorID,
this.invoiceNo,
this.status,
this.arrivedOn,
this.doctorName,
this.doctorNameN,
this.clinicName,
this.decimalDoctorRate,
this.doctorImageURL,
this.doctorRate,
this.patientNumber,
this.projectName});
GetInvoicesListResponseModel.fromJson(Map<String, dynamic> json) {
setupId = json['SetupId'];
projectID = json['ProjectID'];
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'];
clinicName = json['ClinicName'];
decimalDoctorRate = json['DecimalDoctorRate'];
doctorImageURL = json['DoctorImageURL'];
doctorRate = json['DoctorRate'];
patientNumber = json['PatientNumber'];
projectName = json['ProjectName'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['SetupId'] = this.setupId;
data['ProjectID'] = this.projectID;
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['ClinicName'] = this.clinicName;
data['DecimalDoctorRate'] = this.decimalDoctorRate;
data['DoctorImageURL'] = this.doctorImageURL;
data['DoctorRate'] = this.doctorRate;
data['PatientNumber'] = this.patientNumber;
data['ProjectName'] = this.projectName;
return data;
}
}

@ -0,0 +1,141 @@
import 'package:dartz/dartz.dart';
import 'package:hmg_patient_app_new/core/api/api_client.dart';
import 'package:hmg_patient_app_new/core/api_consts.dart';
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/services/logger_service.dart';
abstract class MyInvoicesRepo {
Future<Either<Failure, GenericApiModel<List<GetInvoicesListResponseModel>>>> getAllInvoicesList();
Future<Either<Failure, GenericApiModel<GetInvoiceDetailsResponseModel>>> getInvoiceDetails({required num appointmentNo, required num invoiceNo, required int projectID});
Future<Either<Failure, GenericApiModel<dynamic>>> sendInvoiceEmail({required num appointmentNo, required int projectID});
}
class MyInvoicesRepoImp implements MyInvoicesRepo {
final ApiClient apiClient;
final LoggerService loggerService;
MyInvoicesRepoImp({required this.loggerService, required this.apiClient});
@override
Future<Either<Failure, GenericApiModel<List<GetInvoicesListResponseModel>>>> getAllInvoicesList() async {
Map<String, dynamic> mapDevice = {};
try {
GenericApiModel<List<GetInvoicesListResponseModel>>? apiResponse;
Failure? failure;
await apiClient.post(
GET_ALL_APPOINTMENTS_FOR_DENTAL_CLINIC,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['List_DentalAppointments'];
final invoicesList = list.map((item) => GetInvoicesListResponseModel.fromJson(item as Map<String, dynamic>)).toList().cast<GetInvoicesListResponseModel>();
apiResponse = GenericApiModel<List<GetInvoicesListResponseModel>>(
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<Either<Failure, GenericApiModel<GetInvoiceDetailsResponseModel>>> getInvoiceDetails({required num appointmentNo, required num invoiceNo, required int projectID}) async {
Map<String, dynamic> mapDevice = {
"AppointmentNo": appointmentNo,
"InvoiceNo": invoiceNo,
"IsRegistered": true,
"ProjectID": projectID,
};
try {
GenericApiModel<GetInvoiceDetailsResponseModel>? apiResponse;
Failure? failure;
await apiClient.post(
GET_DENTAL_APPOINTMENT_INVOICE,
body: mapDevice,
onFailure: (error, statusCode, {messageStatus, failureType}) {
failure = failureType;
},
onSuccess: (response, statusCode, {messageStatus, errorMessage}) {
try {
final list = response['List_eInvoiceForDental'];
final invoicesList = GetInvoiceDetailsResponseModel.fromJson(list[0]);
apiResponse = GenericApiModel<GetInvoiceDetailsResponseModel>(
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<Either<Failure, GenericApiModel>> sendInvoiceEmail({required num appointmentNo, required int projectID}) async {
Map<String, dynamic> mapDevice = {
"AppointmentNo": appointmentNo,
"IsRegistered": true,
"ProjectID": projectID,
};
try {
GenericApiModel<GetInvoiceDetailsResponseModel>? apiResponse;
Failure? failure;
await apiClient.post(
SEND_DENTAL_APPOINTMENT_INVOICE_EMAIL,
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,
);
} 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()));
}
}
}

@ -0,0 +1,99 @@
import 'package:flutter/material.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/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';
class MyInvoicesViewModel extends ChangeNotifier {
bool isInvoicesListLoading = false;
bool isInvoiceDetailsLoading = false;
MyInvoicesRepo myInvoicesRepo;
ErrorHandlerService errorHandlerService;
NavigationService navServices;
List<GetInvoicesListResponseModel> allInvoicesList = [];
late GetInvoiceDetailsResponseModel invoiceDetailsResponseModel;
MyInvoicesViewModel({required this.myInvoicesRepo, required this.errorHandlerService, required this.navServices});
setInvoicesListLoading() {
isInvoicesListLoading = true;
allInvoicesList.clear();
notifyListeners();
}
setInvoiceDetailLoading() {
isInvoiceDetailsLoading = true;
notifyListeners();
}
Future<void> getAllInvoicesList({Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await myInvoicesRepo.getAllInvoicesList();
result.fold(
(failure) async {
isInvoicesListLoading = false;
notifyListeners();
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
allInvoicesList = apiResponse.data!;
isInvoicesListLoading = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
Future<void> 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(
(failure) async {
isInvoiceDetailsLoading = false;
notifyListeners();
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
invoiceDetailsResponseModel = apiResponse.data!;
isInvoiceDetailsLoading = false;
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
Future<void> sendInvoiceEmail({required num appointmentNo, required int projectID, Function(dynamic)? onSuccess, Function(String)? onError}) async {
final result = await myInvoicesRepo.sendInvoiceEmail(appointmentNo: appointmentNo, projectID: projectID);
result.fold(
(failure) async {
notifyListeners();
},
(apiResponse) {
if (apiResponse.messageStatus == 2) {
// dialogService.showErrorDialog(message: apiResponse.errorMessage!, onOkPressed: () {});
} else if (apiResponse.messageStatus == 1) {
notifyListeners();
if (onSuccess != null) {
onSuccess(apiResponse);
}
}
},
);
}
}

@ -25,6 +25,7 @@ import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_mode
import 'package:hmg_patient_app_new/features/my_appointments/appointment_rating_view_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/appointment_rating_view_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/appointment_via_region_viewmodel.dart'; 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_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/payfort/payfort_view_model.dart'; import 'package:hmg_patient_app_new/features/payfort/payfort_view_model.dart';
import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart'; import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart'; import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart';
@ -169,6 +170,9 @@ void main() async {
), ),
ChangeNotifierProvider<WaterMonitorViewModel>( ChangeNotifierProvider<WaterMonitorViewModel>(
create: (_) => getIt.get<WaterMonitorViewModel>(), create: (_) => getIt.get<WaterMonitorViewModel>(),
),
ChangeNotifierProvider<MyInvoicesViewModel>(
create: (_) => getIt.get<MyInvoicesViewModel>(),
) )
], child: MyApp()), ], child: MyApp()),
), ),

@ -10,6 +10,7 @@ import 'package:hmg_patient_app_new/extensions/route_extensions.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart'; import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart'; import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/blood_donation/blood_donation_view_model.dart'; import 'package:hmg_patient_app_new/features/blood_donation/blood_donation_view_model.dart';
import 'package:hmg_patient_app_new/features/emergency_services/emergency_services_view_model.dart';
import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.dart'; import 'package:hmg_patient_app_new/features/habib_wallet/habib_wallet_view_model.dart';
import 'package:hmg_patient_app_new/features/hmg_services/models/ui_models/hmg_services_component_model.dart'; import 'package:hmg_patient_app_new/features/hmg_services/models/ui_models/hmg_services_component_model.dart';
import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart'; import 'package:hmg_patient_app_new/features/medical_file/medical_file_view_model.dart';
@ -17,6 +18,7 @@ import 'package:hmg_patient_app_new/features/water_monitor/water_monitor_view_mo
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/blood_donation/blood_donation_page.dart'; import 'package:hmg_patient_app_new/presentation/blood_donation/blood_donation_page.dart';
import 'package:hmg_patient_app_new/presentation/contact_us/contact_us.dart'; import 'package:hmg_patient_app_new/presentation/contact_us/contact_us.dart';
import 'package:hmg_patient_app_new/presentation/emergency_services/emergency_services_page.dart';
import 'package:hmg_patient_app_new/presentation/habib_wallet/habib_wallet_page.dart'; import 'package:hmg_patient_app_new/presentation/habib_wallet/habib_wallet_page.dart';
import 'package:hmg_patient_app_new/presentation/habib_wallet/recharge_wallet_page.dart'; import 'package:hmg_patient_app_new/presentation/habib_wallet/recharge_wallet_page.dart';
import 'package:hmg_patient_app_new/presentation/hmg_services/services_view.dart'; import 'package:hmg_patient_app_new/presentation/hmg_services/services_view.dart';
@ -48,9 +50,21 @@ class ServicesPage extends StatelessWidget {
"".needTranslation, "".needTranslation,
AppAssets.emergency_services_icon, AppAssets.emergency_services_icon,
bgColor: AppColors.primaryRedColor, bgColor: AppColors.primaryRedColor,
true, true, route: null, onTap: () {
route: AppRoutes.eReferralPage, getIt.get<EmergencyServicesViewModel>().flushData();
), getIt.get<EmergencyServicesViewModel>().getTransportationOrders(
showLoader: false,
);
getIt.get<EmergencyServicesViewModel>().getRRTOrders(
showLoader: false,
);
Navigator.of(GetIt.instance<NavigationService>().navigatorKey.currentContext!).push(
CustomPageRoute(
page: EmergencyServicesPage(),
settings: const RouteSettings(name: '/EmergencyServicesPage'),
),
);
}),
HmgServicesComponentModel( HmgServicesComponentModel(
11, 11,
"Book\nAppointment".needTranslation, "Book\nAppointment".needTranslation,
@ -58,7 +72,7 @@ class ServicesPage extends StatelessWidget {
AppAssets.appointment_calendar_icon, AppAssets.appointment_calendar_icon,
bgColor: AppColors.bookAppointment, bgColor: AppColors.bookAppointment,
true, true,
route: AppRoutes.eReferralPage, route: AppRoutes.bookAppointmentPage,
), ),
HmgServicesComponentModel( HmgServicesComponentModel(
5, 5,

@ -22,6 +22,7 @@ import 'package:hmg_patient_app_new/features/medical_file/models/family_file_res
import 'package:hmg_patient_app_new/features/medical_file/models/patient_sickleave_response_model.dart'; import 'package:hmg_patient_app_new/features/medical_file/models/patient_sickleave_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart'; import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_appointments/my_appointments_view_model.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/prescriptions/prescriptions_view_model.dart'; import 'package:hmg_patient_app_new/features/prescriptions/prescriptions_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart'; import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/allergies/allergies_list_page.dart'; import 'package:hmg_patient_app_new/presentation/allergies/allergies_list_page.dart';
@ -46,6 +47,7 @@ import 'package:hmg_patient_app_new/presentation/medical_file/widgets/medical_fi
import 'package:hmg_patient_app_new/presentation/medical_file/widgets/patient_sick_leave_card.dart'; import 'package:hmg_patient_app_new/presentation/medical_file/widgets/patient_sick_leave_card.dart';
import 'package:hmg_patient_app_new/presentation/medical_report/medical_reports_page.dart'; import 'package:hmg_patient_app_new/presentation/medical_report/medical_reports_page.dart';
import 'package:hmg_patient_app_new/presentation/my_family/my_family.dart'; import 'package:hmg_patient_app_new/presentation/my_family/my_family.dart';
import 'package:hmg_patient_app_new/presentation/my_invoices/my_invoices_list.dart';
import 'package:hmg_patient_app_new/presentation/prescriptions/prescriptions_list_page.dart'; import 'package:hmg_patient_app_new/presentation/prescriptions/prescriptions_list_page.dart';
import 'package:hmg_patient_app_new/presentation/radiology/radiology_orders_page.dart'; import 'package:hmg_patient_app_new/presentation/radiology/radiology_orders_page.dart';
import 'package:hmg_patient_app_new/services/dialog_service.dart'; import 'package:hmg_patient_app_new/services/dialog_service.dart';
@ -79,6 +81,7 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
late MedicalFileViewModel medicalFileViewModel; late MedicalFileViewModel medicalFileViewModel;
late BookAppointmentsViewModel bookAppointmentsViewModel; late BookAppointmentsViewModel bookAppointmentsViewModel;
late LabViewModel labViewModel; late LabViewModel labViewModel;
late MyInvoicesViewModel myInvoicesViewModel;
int currentIndex = 0; int currentIndex = 0;
@ -104,9 +107,11 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
myAppointmentsViewModel = Provider.of<MyAppointmentsViewModel>(context, listen: false); myAppointmentsViewModel = Provider.of<MyAppointmentsViewModel>(context, listen: false);
medicalFileViewModel = Provider.of<MedicalFileViewModel>(context, listen: false); medicalFileViewModel = Provider.of<MedicalFileViewModel>(context, listen: false);
bookAppointmentsViewModel = Provider.of<BookAppointmentsViewModel>(context, listen: false); bookAppointmentsViewModel = Provider.of<BookAppointmentsViewModel>(context, listen: false);
myInvoicesViewModel = Provider.of<MyInvoicesViewModel>(context, listen: false);
NavigationService navigationService = getIt.get<NavigationService>(); NavigationService navigationService = getIt.get<NavigationService>();
return CollapsingListView( return CollapsingListView(
title: "Medical File".needTranslation, // title: "Medical File".needTranslation,
title: LocaleKeys.medicalFile.tr(context: context),
trailing: Row( trailing: Row(
children: [ children: [
Wrap( Wrap(
@ -998,7 +1003,13 @@ class _MedicalFilePageState extends State<MedicalFilePage> {
svgIcon: AppAssets.invoices_list_icon, svgIcon: AppAssets.invoices_list_icon,
isLargeText: true, isLargeText: true,
iconSize: 36.w, iconSize: 36.w,
), ).onPress(() {
Navigator.of(context).push(
CustomPageRoute(
page: MyInvoicesList(),
),
);
}),
MedicalFileCard( MedicalFileCard(
label: "Ancillary Orders List".needTranslation, label: "Ancillary Orders List".needTranslation,
textColor: AppColors.blackColor, textColor: AppColors.blackColor,

@ -0,0 +1,272 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.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/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.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/my_invoices_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.dart';
import 'package:hmg_patient_app_new/widgets/loader/bottomsheet_loader.dart';
import 'package:provider/provider.dart';
class MyInvoicesDetailsPage extends StatefulWidget {
GetInvoiceDetailsResponseModel getInvoiceDetailsResponseModel;
MyInvoicesDetailsPage({super.key, required this.getInvoiceDetailsResponseModel});
@override
State<MyInvoicesDetailsPage> createState() => _MyInvoicesDetailsPageState();
}
class _MyInvoicesDetailsPageState extends State<MyInvoicesDetailsPage> {
late MyInvoicesViewModel myInvoicesViewModel;
@override
Widget build(BuildContext context) {
myInvoicesViewModel = Provider.of<MyInvoicesViewModel>(context, listen: false);
return Scaffold(
backgroundColor: AppColors.bgScaffoldColor,
body: Column(
children: [
Expanded(
child: CollapsingListView(
title: "Invoice Details".needTranslation,
sendEmail: () async {
LoaderBottomSheet.showLoader(loadingText: "Sending email, Please wait...".needTranslation);
await myInvoicesViewModel.sendInvoiceEmail(
appointmentNo: widget.getInvoiceDetailsResponseModel.appointmentNo!,
projectID: widget.getInvoiceDetailsResponseModel.projectID!,
onSuccess: (val) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getSuccessWidget(loadingText: "Email sent successfully.".needTranslation),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
},
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(24.h),
child: Column(
children: [
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: true,
),
child: Padding(
padding: EdgeInsets.all(14.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
children: [
Image.network(
widget.getInvoiceDetailsResponseModel.doctorImageURL!,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,
).circle(100.r),
],
),
SizedBox(width: 16.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(getIt<AppState>().isArabic() ? widget.getInvoiceDetailsResponseModel.doctorNameN! : widget.getInvoiceDetailsResponseModel.doctorName!).toText16(isBold: true),
SizedBox(height: 8.h),
Wrap(
direction: Axis.horizontal,
spacing: 6.w,
runSpacing: 6.h,
children: [
AppCustomChipWidget(
labelText: "${LocaleKeys.invoiceNo}: ${widget.getInvoiceDetailsResponseModel.invoiceNo!}",
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
),
AppCustomChipWidget(
labelText: (widget.getInvoiceDetailsResponseModel.clinicDescription!.length > 15
? '${widget.getInvoiceDetailsResponseModel.clinicDescription!.substring(0, 12)}...'
: widget.getInvoiceDetailsResponseModel.clinicDescription!),
labelPadding: EdgeInsetsDirectional.only(start: 4.w, end: 4.w),
),
AppCustomChipWidget(
labelText: widget.getInvoiceDetailsResponseModel.projectName!,
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
),
AppCustomChipWidget(
labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w),
icon: AppAssets.doctor_calendar_icon,
labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(widget.getInvoiceDetailsResponseModel.appointmentDate), false),
),
],
),
],
),
),
],
),
],
),
),
),
SizedBox(height: 16.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: true,
),
child: Padding(
padding: EdgeInsets.all(14.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
widget.getInvoiceDetailsResponseModel.listConsultation!.first.procedureName!.toText16(isBold: true),
SizedBox(height: 16.h),
Wrap(
direction: Axis.horizontal,
spacing: 6.w,
runSpacing: 6.h,
children: [
AppCustomChipWidget(
labelText: "${LocaleKeys.quantity.tr()}: ${widget.getInvoiceDetailsResponseModel.listConsultation!.first.quantity!}",
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
),
AppCustomChipWidget(
labelText: "${LocaleKeys.price.tr()}: ${widget.getInvoiceDetailsResponseModel.listConsultation!.first.price!} ${LocaleKeys.sar.tr()}",
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
),
AppCustomChipWidget(
labelText: "${LocaleKeys.total.tr()}: ${widget.getInvoiceDetailsResponseModel.listConsultation!.first.total!} ${LocaleKeys.sar.tr()}",
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
),
],
),
],
),
),
),
SizedBox(height: 16.h),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: true,
),
child: Padding(
padding: EdgeInsets.all(14.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
"Insurance Details".toText16(isBold: true),
SizedBox(height: 16.h),
widget.getInvoiceDetailsResponseModel.groupName!.toText14(isBold: true),
Row(
children: [
Expanded(child: widget.getInvoiceDetailsResponseModel.companyName!.toText14(isBold: true)),
],
),
SizedBox(height: 12.h),
Row(
children: [
AppCustomChipWidget(
labelText: "Insurance ID: ${widget.getInvoiceDetailsResponseModel.insuranceID ?? "-"}",
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
),
],
),
],
),
),
),
],
),
),
),
),
),
Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 24.h,
hasShadow: false,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 24.h),
"Total Balance".needTranslation.toText18(isBold: true).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 17.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Amount before tax".needTranslation.toText14(isBold: true),
Utils.getPaymentAmountWithSymbol(widget.getInvoiceDetailsResponseModel.listConsultation!.first.totalShare.toString().toText16(isBold: true), AppColors.blackColor, 13,
isSaudiCurrency: true),
],
).paddingSymmetrical(24.h, 0.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"VAT 15%".needTranslation.toText14(isBold: true, color: AppColors.greyTextColor),
Utils.getPaymentAmountWithSymbol(
widget.getInvoiceDetailsResponseModel.listConsultation!.first.totalVATAmount!.toString().toText14(isBold: true, color: AppColors.greyTextColor), AppColors.greyTextColor, 13,
isSaudiCurrency: true),
],
).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 16.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Discount".needTranslation.toText14(isBold: true),
Utils.getPaymentAmountWithSymbol(widget.getInvoiceDetailsResponseModel.listConsultation!.first.discountAmount!.toString().toText14(isBold: true, color: AppColors.primaryRedColor),
AppColors.primaryRedColor, 13,
isSaudiCurrency: true),
],
).paddingSymmetrical(24.h, 0.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
"Paid".needTranslation.toText14(isBold: true),
Utils.getPaymentAmountWithSymbol(
widget.getInvoiceDetailsResponseModel.listConsultation!.first.grandTotal!.toString().toText14(isBold: true, color: AppColors.textColor), AppColors.textColor, 13,
isSaudiCurrency: true),
],
).paddingSymmetrical(24.h, 0.h),
SizedBox(height: 24.h),
],
),
),
],
),
);
}
}

@ -0,0 +1,116 @@
import 'dart:async';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:hmg_patient_app_new/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/my_appointments/models/resp_models/patient_appointment_history_response_model.dart';
import 'package:hmg_patient_app_new/features/my_invoices/my_invoices_view_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/presentation/appointments/widgets/appointment_card.dart';
import 'package:hmg_patient_app_new/presentation/lab/lab_result_item_view.dart';
import 'package:hmg_patient_app_new/presentation/my_invoices/my_invoices_details_page.dart';
import 'package:hmg_patient_app_new/presentation/my_invoices/widgets/invoice_list_card.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/appbar/collapsing_list_view.dart';
import 'package:hmg_patient_app_new/widgets/common_bottom_sheet.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:provider/provider.dart';
class MyInvoicesList extends StatefulWidget {
const MyInvoicesList({super.key});
@override
State<MyInvoicesList> createState() => _MyInvoicesListState();
}
class _MyInvoicesListState extends State<MyInvoicesList> {
late MyInvoicesViewModel myInvoicesViewModel;
@override
void initState() {
scheduleMicrotask(() {
myInvoicesViewModel.setInvoicesListLoading();
myInvoicesViewModel.getAllInvoicesList();
});
super.initState();
}
@override
Widget build(BuildContext context) {
myInvoicesViewModel = Provider.of<MyInvoicesViewModel>(context, listen: false);
return CollapsingListView(
title: LocaleKeys.invoiceList.tr(context: context),
child: SingleChildScrollView(
child: Consumer<MyInvoicesViewModel>(builder: (context, myInvoicesVM, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 24.h),
ListView.builder(
itemCount: myInvoicesVM.isInvoicesListLoading ? 4 : myInvoicesVM.allInvoicesList.length,
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsetsGeometry.zero,
itemBuilder: (context, index) {
return myInvoicesVM.isInvoicesListLoading
? LabResultItemView(
onTap: () {},
labOrder: null,
index: index,
isLoading: true,
)
: AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 500),
child: SlideAnimation(
verticalOffset: 100.0,
child: FadeInAnimation(
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
curve: Curves.easeInOut,
child: InvoiceListCard(
getInvoicesListResponseModel: myInvoicesVM.allInvoicesList[index],
onTap: () async {
myInvoicesVM.setInvoiceDetailLoading();
LoaderBottomSheet.showLoader(loadingText: "Fetching invoice details, Please wait...".needTranslation);
await myInvoicesVM.getInvoiceDetails(
appointmentNo: myInvoicesVM.allInvoicesList[index].appointmentNo!,
invoiceNo: myInvoicesVM.allInvoicesList[index].invoiceNo!,
projectID: myInvoicesVM.allInvoicesList[index].projectID!,
onSuccess: (val) {
LoaderBottomSheet.hideLoader();
Navigator.of(context).push(
CustomPageRoute(
page: MyInvoicesDetailsPage(getInvoiceDetailsResponseModel: myInvoicesVM.invoiceDetailsResponseModel),
),
);
},
onError: (err) {
LoaderBottomSheet.hideLoader();
showCommonBottomSheetWithoutHeight(
context,
child: Utils.getErrorWidget(loadingText: err),
callBackFunc: () {},
isFullScreen: false,
isCloseButtonVisible: true,
);
});
},
),
),
),
),
);
}).paddingSymmetrical(24.w, 0.h),
],
);
}),
),
);
}
}

@ -0,0 +1,151 @@
import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_assets.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/core/utils/size_utils.dart';
import 'package:hmg_patient_app_new/core/utils/utils.dart';
import 'package:hmg_patient_app_new/extensions/string_extensions.dart';
import 'package:hmg_patient_app_new/extensions/widget_extensions.dart';
import 'package:hmg_patient_app_new/features/my_invoices/models/get_invoices_list_response_model.dart';
import 'package:hmg_patient_app_new/generated/locale_keys.g.dart';
import 'package:hmg_patient_app_new/theme/colors.dart';
import 'package:hmg_patient_app_new/widgets/buttons/custom_button.dart';
import 'package:hmg_patient_app_new/widgets/chip/app_custom_chip_widget.dart';
class InvoiceListCard extends StatelessWidget {
final GetInvoicesListResponseModel getInvoicesListResponseModel;
Function? onTap;
InvoiceListCard({super.key, required this.getInvoicesListResponseModel, required this.onTap});
@override
Widget build(BuildContext context) {
return Container(
decoration: RoundedRectangleBorder().toSmoothCornerDecoration(
color: AppColors.whiteColor,
borderRadius: 20.h,
hasShadow: true,
),
child: Padding(
padding: EdgeInsets.all(14.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Wrap(
alignment: WrapAlignment.start,
direction: Axis.horizontal,
spacing: 6.w,
runSpacing: 6.h,
children: [
AppCustomChipWidget(
icon: AppAssets.walkin_appointment_icon,
iconColor: AppColors.textColor,
labelText: 'Walk In'.needTranslation,
textColor: AppColors.textColor,
),
AppCustomChipWidget(
labelText: 'OutPatient'.needTranslation,
backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.1),
textColor: AppColors.primaryRedColor,
),
],
),
SizedBox(height: 16.h),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
children: [
Image.network(
getInvoicesListResponseModel.doctorImageURL!,
width: 63.h,
height: 63.h,
fit: BoxFit.cover,
).circle(100.r),
Transform.translate(
offset: Offset(0.0, -20.h),
child: Container(
width: 40.w,
height: 40.h,
decoration: BoxDecoration(
color: AppColors.whiteColor,
shape: BoxShape.circle, // Makes the container circular
border: Border.all(
color: AppColors.scaffoldBgColor, // Color of the border
width: 1.5.w, // Width of the border
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Utils.buildSvgWithAssets(icon: AppAssets.rating_icon, width: 15.w, height: 15.h),
SizedBox(height: 2.h),
"${getInvoicesListResponseModel.decimalDoctorRate}".toText11(isBold: true, color: AppColors.textColor),
],
),
).circle(100),
),
],
),
SizedBox(width: 16.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(getIt<AppState>().isArabic() ? getInvoicesListResponseModel.doctorNameN! : getInvoicesListResponseModel.doctorName!).toText16(isBold: true),
SizedBox(height: 8.h),
Wrap(
direction: Axis.horizontal,
spacing: 6.w,
runSpacing: 6.h,
children: [
AppCustomChipWidget(
labelText: "${LocaleKeys.invoiceNo}: ${getInvoicesListResponseModel.invoiceNo!}",
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
),
AppCustomChipWidget(
labelText:
(getInvoicesListResponseModel.clinicName!.length > 15 ? '${getInvoicesListResponseModel.clinicName!.substring(0, 12)}...' : getInvoicesListResponseModel.clinicName!),
labelPadding: EdgeInsetsDirectional.only(start: 4.w, end: 4.w),
),
AppCustomChipWidget(
labelText: getInvoicesListResponseModel.projectName!,
labelPadding: EdgeInsetsDirectional.only(start: 6.w, end: 6.w),
),
AppCustomChipWidget(
labelPadding: EdgeInsetsDirectional.only(start: -4.w, end: 6.w),
icon: AppAssets.doctor_calendar_icon,
labelText: DateUtil.formatDateToDate(DateUtil.convertStringToDate(getInvoicesListResponseModel.appointmentDate), false),
),
],
),
],
),
),
],
),
SizedBox(height: 16.h),
CustomButton(
text: "View invoice details".needTranslation,
onPressed: () {
if (onTap != null) {
onTap!();
}
},
backgroundColor: AppColors.primaryRedColor.withValues(alpha: 0.1),
borderColor: AppColors.primaryRedColor.withValues(alpha: 0.01),
textColor: AppColors.primaryRedColor,
fontSize: 14.f,
fontWeight: FontWeight.w500,
borderRadius: 12.r,
padding: EdgeInsets.symmetric(horizontal: 10.w),
height: 40.h,
iconSize: 14.h,
),
],
),
),
).paddingOnly(bottom: 16.h);
}
}

@ -21,6 +21,7 @@ class CollapsingListView extends StatelessWidget {
VoidCallback? history; VoidCallback? history;
VoidCallback? instructions; VoidCallback? instructions;
VoidCallback? requests; VoidCallback? requests;
VoidCallback? sendEmail;
Widget? bottomChild; Widget? bottomChild;
Widget? trailing; Widget? trailing;
bool isClose; bool isClose;
@ -40,6 +41,7 @@ class CollapsingListView extends StatelessWidget {
this.history, this.history,
this.instructions, this.instructions,
this.requests, this.requests,
this.sendEmail,
this.isLeading = true, this.isLeading = true,
this.trailing, this.trailing,
this.leadingCallback, this.leadingCallback,
@ -78,6 +80,7 @@ class CollapsingListView extends StatelessWidget {
history: history, history: history,
instructions: instructions, instructions: instructions,
requests: requests, requests: requests,
sendEmail: sendEmail,
bottomChild: bottomChild, bottomChild: bottomChild,
trailing: trailing, trailing: trailing,
) )
@ -108,6 +111,7 @@ class CollapsingListView extends StatelessWidget {
history: history, history: history,
instructions: instructions, instructions: instructions,
requests: requests, requests: requests,
sendEmail: sendEmail,
bottomChild: bottomChild, bottomChild: bottomChild,
trailing: trailing, trailing: trailing,
), ),
@ -181,6 +185,7 @@ class ScrollAnimatedTitle extends StatefulWidget implements PreferredSizeWidget
VoidCallback? history; VoidCallback? history;
VoidCallback? instructions; VoidCallback? instructions;
VoidCallback? requests; VoidCallback? requests;
VoidCallback? sendEmail;
Widget? bottomChild; Widget? bottomChild;
Widget? trailing; Widget? trailing;
@ -195,6 +200,7 @@ class ScrollAnimatedTitle extends StatefulWidget implements PreferredSizeWidget
this.history, this.history,
this.instructions, this.instructions,
this.requests, this.requests,
this.sendEmail,
this.bottomChild, this.bottomChild,
this.trailing, this.trailing,
}); });
@ -267,6 +273,7 @@ class _ScrollAnimatedTitleState extends State<ScrollAnimatedTitle> {
if (widget.history != null) actionButton(context, t, title: "History".needTranslation, icon: AppAssets.insurance_history_icon).onPress(widget.history!), if (widget.history != null) actionButton(context, t, title: "History".needTranslation, icon: AppAssets.insurance_history_icon).onPress(widget.history!),
if (widget.instructions != null) actionButton(context, t, title: "Instructions".needTranslation, icon: AppAssets.requests).onPress(widget.instructions!), if (widget.instructions != null) actionButton(context, t, title: "Instructions".needTranslation, icon: AppAssets.requests).onPress(widget.instructions!),
if (widget.requests != null) actionButton(context, t, title: "Requests".needTranslation, icon: AppAssets.insurance_history_icon).onPress(widget.requests!), if (widget.requests != null) actionButton(context, t, title: "Requests".needTranslation, icon: AppAssets.insurance_history_icon).onPress(widget.requests!),
if (widget.sendEmail != null) actionButton(context, t, title: "Send Email".needTranslation, icon: AppAssets.email).onPress(widget.sendEmail!),
if (widget.search != null) Utils.buildSvgWithAssets(icon: AppAssets.search_icon).onPress(widget.search!), if (widget.search != null) Utils.buildSvgWithAssets(icon: AppAssets.search_icon).onPress(widget.search!),
if (widget.trailing != null) widget.trailing!, if (widget.trailing != null) widget.trailing!,
] ]

Loading…
Cancel
Save