Merge pull request #18 from yaso-meth/Claim-Document-Generation

Claim-Document-Generation
This commit is contained in:
yaso-meth
2024-12-04 14:06:43 +02:00
committed by GitHub
22 changed files with 2110 additions and 245 deletions

View File

@@ -35,7 +35,8 @@ COPY . /app/
WORKDIR /app
RUN flutter upgrade
RUN flutter build web --release --web-renderer canvaskit -t ./lib/main_prod.dart
RUN flutter build web --release -t ./lib/main_prod.dart
# RUN flutter build web --release --web-renderer canvaskit -t ./lib/main_prod.dart
# RUN cd ..

View File

@@ -0,0 +1,256 @@
import 'dart:convert';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/arguments.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/claim_statement_file.dart';
import 'package:flutter/material.dart';
import 'package:supertokens_flutter/http.dart' as http;
import '../mih_components/mih_pop_up_messages/mih_error_message.dart';
import '../mih_components/mih_pop_up_messages/mih_success_message.dart';
import '../mih_env/env.dart';
class MIHClaimStatementGenerationApi {
final baseAPI = AppEnviroment.baseApiUrl;
/// This function is used to generate and store a claim/ statement.
///
/// Patameters: TBC .
///
/// Returns TBC.
Future<void> generateClaimStatement(
ClaimStatementGenerationArguments data,
PatientViewArguments args,
BuildContext context,
) async {
//start loading circle
showDialog(
context: context,
builder: (context) {
return const Mihloadingcircle();
},
);
var response1 = await http.post(
Uri.parse("${AppEnviroment.baseApiUrl}/minio/generate/claim-statement/"),
headers: <String, String>{
"Content-Type": "application/json; charset=UTF-8"
},
body: jsonEncode(<String, dynamic>{
"document_type": data.document_type,
"patient_app_id": data.patient_app_id,
"patient_full_name": data.patient_full_name,
"patient_id_no": data.patient_id_no,
"has_med_aid": data.has_med_aid,
"med_aid_no": data.med_aid_no,
"med_aid_code": data.med_aid_code,
"med_aid_name": data.med_aid_name,
"med_aid_scheme": data.med_aid_scheme,
"busName": data.busName,
"busAddr": data.busAddr,
"busNo": data.busNo,
"busEmail": data.busEmail,
"provider_name": data.provider_name,
"practice_no": data.practice_no,
"vat_no": data.vat_no,
"service_date": data.service_date,
"service_desc": data.service_desc,
"service_desc_option": data.service_desc_option,
"procedure_name": data.procedure_name,
"procedure_additional_info": data.procedure_additional_info,
"icd10_code": data.icd10_code,
"amount": data.amount,
"pre_auth_no": data.pre_auth_no,
"logo_path": data.logo_path,
"sig_path": data.sig_path,
}),
);
//print(response1.statusCode);
DateTime now = new DateTime.now();
DateTime date = new DateTime(now.year, now.month, now.day);
String fileName =
"${data.document_type}-${data.patient_full_name}-${date.toString().substring(0, 10)}.pdf";
if (response1.statusCode == 200) {
//Update this API
var response2 = await http.post(
Uri.parse("${AppEnviroment.baseApiUrl}/files/claim-statement/insert/"),
headers: <String, String>{
"Content-Type": "application/json; charset=UTF-8"
},
body: jsonEncode(<String, dynamic>{
"app_id": data.patient_app_id,
"business_id": args.business!.business_id,
"file_path": "${data.patient_app_id}/claims-statements/$fileName",
"file_name": fileName
}),
);
if (response2.statusCode == 201) {
// end loading circle
Navigator.of(context).pop();
Navigator.of(context).pop();
Navigator.of(context).pop();
Navigator.of(context)
.pushNamed('/patient-manager/patient', arguments: args);
String message =
"The ${data.document_type}: $fileName has been successfully generated and added to ${data.patient_full_name}'s record. You can now access and download it for their use.";
successPopUp(message, context);
} else {
internetConnectionPopUp(context);
}
} else {
internetConnectionPopUp(context);
}
}
/// This function is used to fetch a list of claim/ statement files for a ptient.
///
/// Patameters: app_id .
///
/// Returns List<ClaimStatementFile>.
static Future<List<ClaimStatementFile>> getClaimStatementFilesByPatient(
String app_id,
) async {
//print("Patien manager page: $endpoint");
final response = await http.get(Uri.parse(
"${AppEnviroment.baseApiUrl}/files/claim-statement/patient/$app_id"));
// print("Here");
// print("Body: ${response.body}");
// print("Code: ${response.statusCode}");
// errorCode = response.statusCode.toString();
// errorBody = response.body;
if (response.statusCode == 200) {
//print("Here1");
Iterable l = jsonDecode(response.body);
//print("Here2");
List<ClaimStatementFile> docList = List<ClaimStatementFile>.from(
l.map((model) => ClaimStatementFile.fromJson(model)));
//print("Here3");
//print(patientQueue);
return docList;
} else {
throw Exception(
'failed to fatch patient claims statement files with api');
}
}
/// This function is used to fetch a list of claim/ statement files for a business.
///
/// Patameters: business_id .
///
/// Returns List<ClaimStatementFile>.
static Future<List<ClaimStatementFile>> getClaimStatementFilesByBusiness(
String business_id,
) async {
//print("Patien manager page: $endpoint");
final response = await http.get(Uri.parse(
"${AppEnviroment.baseApiUrl}/files/claim-statement/business/$business_id"));
// print("Here");
// print("Body: ${response.body}");
// print("Code: ${response.statusCode}");
// errorCode = response.statusCode.toString();
// errorBody = response.body;
if (response.statusCode == 200) {
//print("Here1");
Iterable l = jsonDecode(response.body);
//print("Here2");
List<ClaimStatementFile> docList = List<ClaimStatementFile>.from(
l.map((model) => ClaimStatementFile.fromJson(model)));
//print("Here3");
//print(patientQueue);
return docList;
} else {
throw Exception(
'failed to fatch business claims statement files with api');
}
}
/// This function is used to Delete loyalty card from users mzansi wallet.
///
/// Patameters:-
/// AppUser signedInUser,
/// int idloyalty_cards,
/// BuildContext context,
///
/// Returns VOID (TRIGGERS NOTIGICATIOPN ON SUCCESS)
static Future<void> deleteClaimStatementFilesByFileID(
PatientViewArguments args,
String filePath,
int fileID,
BuildContext context,
) async {
showDialog(
context: context,
builder: (context) {
return const Mihloadingcircle();
},
);
// delete file from minio
var response = await http.delete(
Uri.parse("${AppEnviroment.baseApiUrl}/minio/delete/file/"),
headers: <String, String>{
"Content-Type": "application/json; charset=UTF-8"
},
body: jsonEncode(<String, dynamic>{"file_path": filePath}),
);
//print("Here4");
//print(response.statusCode);
if (response.statusCode == 200) {
//SQL delete
var response2 = await http.delete(
Uri.parse("${AppEnviroment.baseApiUrl}/files/claim-statement/delete"),
headers: <String, String>{
"Content-Type": "application/json; charset=UTF-8"
},
body: jsonEncode(<String, dynamic>{"idclaim_statement_file": fileID}),
);
if (response2.statusCode == 200) {
Navigator.of(context).pop();
Navigator.of(context).pop();
Navigator.of(context).pop();
Navigator.of(context).pop();
//print(widget.business);
Navigator.of(context)
.pushNamed('/patient-manager/patient', arguments: args);
// Navigator.of(context)
// .pushNamed('/patient-profile', arguments: widget.signedInUser);
// setState(() {});
String message =
"The File has been deleted successfully. This means it will no longer be visible on your and cannot be used for future appointments.";
successPopUp(message, context);
} else {
internetConnectionPopUp(context);
}
} else {
internetConnectionPopUp(context);
}
}
//================== POP UPS ==========================================================================
static void internetConnectionPopUp(BuildContext context) {
showDialog(
context: context,
builder: (context) {
return const MIHErrorMessage(
errorType: "Internet Connection",
);
},
);
}
static void successPopUp(String message, BuildContext context) {
showDialog(
context: context,
builder: (context) {
return MIHSuccessMessage(
successType: "Success",
successMessage: message,
);
},
);
}
}

View File

@@ -0,0 +1,55 @@
import 'dart:convert';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_pop_up_messages/mih_loading_circle.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/icd10_code.dart.dart';
import 'package:flutter/material.dart';
import 'package:supertokens_flutter/http.dart' as http;
import '../mih_env/env.dart';
class MIHIcd10CodeApis {
final baseAPI = AppEnviroment.baseApiUrl;
/// This function is used to fetch a list of icd 10 codes based on a search .
///
/// Patameters: String search, BuildContext context
///
/// Returns List<ICD10Code>.
static Future<List<ICD10Code>> getIcd10Codes(
String search, BuildContext context) async {
//print("Patien manager page: $endpoint");
mihLoadingPopUp(context);
final response = await http
.get(Uri.parse("${AppEnviroment.baseApiUrl}/icd10-codes/$search"));
// print("Here");
// print("Body: ${response.body}");
// print("Code: ${response.statusCode}");
// errorCode = response.statusCode.toString();
// errorBody = response.body;
if (response.statusCode == 200) {
//print("Here1");
Iterable l = jsonDecode(response.body);
//print("Here2");
List<ICD10Code> icd10Codes =
List<ICD10Code>.from(l.map((model) => ICD10Code.fromJson(model)));
//print("Here3");
//print(patientQueue);
Navigator.of(context).pop();
return icd10Codes;
} else {
Navigator.of(context).pop();
throw Exception('failed to fetch icd-10 codes with api');
}
}
static void mihLoadingPopUp(BuildContext context) {
showDialog(
context: context,
builder: (context) {
return const Mihloadingcircle();
},
);
}
}

View File

@@ -85,7 +85,7 @@ class MIHMzansiWalletApis {
arguments: signedInUser,
);
String message =
"The note has been deleted successfully. This means it will no longer be visible on your and cannot be used for future appointments.";
"The loyalty card has been deleted successfully. This means it will no longer be visible in your Mzansi Wallet.";
successPopUp(message, context);
} else {
internetConnectionPopUp(context);
@@ -125,7 +125,7 @@ class MIHMzansiWalletApis {
// Navigator.pushNamed(context, '/patient-manager/patient',
// arguments: widget.signedInUser);
String message =
"Your $shop_name Loyalty Card was successfully added to you Mzansi Wallet.";
"Your $shop_name Loyalty Card was successfully added to your Mzansi Wallet.";
Navigator.pop(context);
Navigator.pop(context);
Navigator.of(context).pushNamed(

View File

@@ -99,3 +99,61 @@ class PatientEditArguments {
this.selectedPatient,
);
}
class ClaimStatementGenerationArguments {
final String document_type;
final String patient_app_id;
final String patient_full_name;
final String patient_id_no;
final String has_med_aid;
final String med_aid_no;
final String med_aid_code;
final String med_aid_name;
final String med_aid_scheme;
final String busName;
final String busAddr;
final String busNo;
final String busEmail;
final String provider_name;
final String practice_no;
final String vat_no;
final String service_date;
final String service_desc;
final String service_desc_option;
final String procedure_name;
final String procedure_additional_info;
final String icd10_code;
final String amount;
final String pre_auth_no;
final String logo_path;
final String sig_path;
ClaimStatementGenerationArguments(
this.document_type,
this.patient_app_id,
this.patient_full_name,
this.patient_id_no,
this.has_med_aid,
this.med_aid_no,
this.med_aid_code,
this.med_aid_name,
this.med_aid_scheme,
this.busName,
this.busAddr,
this.busNo,
this.busEmail,
this.provider_name,
this.practice_no,
this.vat_no,
this.service_date,
this.service_desc,
this.service_desc_option,
this.procedure_name,
this.procedure_additional_info,
this.icd10_code,
this.amount,
this.pre_auth_no,
this.logo_path,
this.sig_path,
);
}

View File

@@ -10,6 +10,8 @@ class Business {
final String bus_email;
final String app_id;
final String gps_location;
final String practice_no;
final String vat_no;
const Business(
this.business_id,
@@ -22,6 +24,8 @@ class Business {
this.bus_email,
this.app_id,
this.gps_location,
this.practice_no,
this.vat_no,
);
factory Business.fromJson(dynamic json) {
@@ -36,6 +40,8 @@ class Business {
json['bus_email'],
json['app_id'],
json['gps_location'],
json['practice_no'],
json['vat_no'],
);
}
}

View File

@@ -0,0 +1,40 @@
class ClaimStatementFile {
final int idclaim_statement_file;
final String app_id;
final String business_id;
final String insert_date;
final String file_path;
final String file_name;
const ClaimStatementFile({
required this.idclaim_statement_file,
required this.app_id,
required this.business_id,
required this.insert_date,
required this.file_path,
required this.file_name,
});
factory ClaimStatementFile.fromJson(Map<String, dynamic> json) {
return switch (json) {
{
"idclaim_statement_file": int idclaim_statement_file,
'app_id': String app_id,
'business_id': String business_id,
'insert_date': String insert_date,
'file_path': String file_path,
'file_name': String file_name,
} =>
ClaimStatementFile(
idclaim_statement_file: idclaim_statement_file,
app_id: app_id,
business_id: business_id,
insert_date: insert_date,
file_path: file_path,
file_name: file_name,
),
_ =>
throw const FormatException('Failed to load Claim Statement Object.'),
};
}
}

View File

@@ -0,0 +1,23 @@
class ICD10Code {
final String icd10;
final String description;
const ICD10Code({
required this.icd10,
required this.description,
});
factory ICD10Code.fromJson(Map<String, dynamic> json) {
return switch (json) {
{
"icd10": String icd10,
'description': String description,
} =>
ICD10Code(
icd10: icd10,
description: description,
),
_ => throw const FormatException('Failed to load icd10 code object.'),
};
}
}

View File

@@ -48,14 +48,13 @@ class _BusinessDetailsState extends State<BusinessDetails> {
final contactController = TextEditingController();
final emailController = TextEditingController();
final locationController = TextEditingController();
final practiceNoController = TextEditingController();
final vatNoController = TextEditingController();
late PlatformFile? selectedLogo = null;
late PlatformFile? selectedSignature = null;
// late Future<BusinessUser?> futureBusinessUser;
// BusinessUser? businessUser;
// late Future<Business?> futureBusiness;
// Business? business;
final ValueNotifier<String> busType = ValueNotifier("");
late String business_id;
late String oldLogoPath;
@@ -79,32 +78,6 @@ class _BusinessDetailsState extends State<BusinessDetails> {
}
}
// Future<BusinessUser?> getBusinessUserDetails() async {
// var response = await http
// .get(Uri.parse("$baseAPI/business-user/${widget.signedInUser.app_id}"));
// if (response.statusCode == 200) {
// String body = response.body;
// var decodedData = jsonDecode(body);
// BusinessUser business_User = BusinessUser.fromJson(decodedData);
// return business_User;
// } else {
// return null;
// }
// }
// Future<Business?> getBusinessDetails() async {
// var response = await http.get(
// Uri.parse("$baseAPI/business/app_id/${widget.signedInUser.app_id}"));
// if (response.statusCode == 200) {
// String body = response.body;
// var decodedData = jsonDecode(body);
// Business business = Business.fromJson(decodedData);
// return business;
// } else {
// return null;
// }
// }
Future<void> uploadSelectedFile(
PlatformFile? file, TextEditingController controller) async {
//to-do delete file when changed
@@ -183,6 +156,8 @@ class _BusinessDetailsState extends State<BusinessDetails> {
"contact_no": contactController.text,
"bus_email": emailController.text,
"gps_location": locationController.text,
"practice_no": practiceNoController.text,
"vat_no": vatNoController.text,
}),
);
if (response.statusCode == 200) {
@@ -275,6 +250,14 @@ class _BusinessDetailsState extends State<BusinessDetails> {
}
}
void typeSelected() {
if (typeController.text.isNotEmpty) {
busType.value = typeController.text;
} else {
busType.value = "";
}
}
@override
void dispose() {
nameController.dispose();
@@ -289,12 +272,15 @@ class _BusinessDetailsState extends State<BusinessDetails> {
contactController.dispose();
emailController.dispose();
locationController.dispose();
practiceNoController.dispose();
vatNoController.dispose();
_focusNode.dispose();
super.dispose();
}
@override
void initState() {
typeController.addListener(typeSelected);
setState(() {
//businessUser = results;
titleController.text = widget.arguments.businessUser!.title;
@@ -316,6 +302,8 @@ class _BusinessDetailsState extends State<BusinessDetails> {
contactController.text = widget.arguments.business!.contact_no;
emailController.text = widget.arguments.business!.bus_email;
locationController.text = widget.arguments.business!.gps_location;
practiceNoController.text = widget.arguments.business!.practice_no;
vatNoController.text = widget.arguments.business!.vat_no;
});
super.initState();
@@ -374,6 +362,29 @@ class _BusinessDetailsState extends State<BusinessDetails> {
editable: true,
),
const SizedBox(height: 10.0),
ValueListenableBuilder(
valueListenable: busType,
builder:
(BuildContext context, String value, Widget? child) {
return Visibility(
visible: value == "Doctors Office",
child: MIHTextField(
controller: practiceNoController,
hintText: "Practice Number",
editable: true,
required: true,
),
);
},
),
const SizedBox(height: 10.0),
MIHTextField(
controller: vatNoController,
hintText: "VAT Number",
editable: true,
required: true,
),
const SizedBox(height: 10.0),
MIHTextField(
controller: contactController,
hintText: "Contact Number",

View File

@@ -52,10 +52,14 @@ class _ProfileBusinessAddState extends State<ProfileBusinessAdd> {
final contactController = TextEditingController();
final emailController = TextEditingController();
final locationController = TextEditingController();
final practiceNoController = TextEditingController();
final vatNoController = TextEditingController();
late PlatformFile selectedLogo;
late PlatformFile selectedSignature;
final ValueNotifier<String> busType = ValueNotifier("");
Future<void> uploadSelectedFile(
PlatformFile file, TextEditingController controller) async {
var token = await SuperTokens.getAccessToken();
@@ -125,6 +129,8 @@ class _ProfileBusinessAddState extends State<ProfileBusinessAdd> {
"contact_no": contactController.text,
"bus_email": emailController.text,
"gps_location": locationController.text,
"practice_no": practiceNoController.text,
"vat_no": vatNoController.text,
}),
);
if (response.statusCode == 201) {
@@ -205,6 +211,14 @@ class _ProfileBusinessAddState extends State<ProfileBusinessAdd> {
return regex.hasMatch(text);
}
void typeSelected() {
if (typeController.text.isNotEmpty) {
busType.value = typeController.text;
} else {
busType.value = "";
}
}
MIHAction getActionButton() {
return MIHAction(
icon: const Icon(Icons.arrow_back),
@@ -281,6 +295,28 @@ class _ProfileBusinessAddState extends State<ProfileBusinessAdd> {
editable: true,
),
const SizedBox(height: 10.0),
ValueListenableBuilder(
valueListenable: busType,
builder: (BuildContext context, String value, Widget? child) {
return Visibility(
visible: value == "Doctors Office",
child: MIHTextField(
controller: practiceNoController,
hintText: "Practice Number",
editable: true,
required: true,
),
);
},
),
const SizedBox(height: 10.0),
MIHTextField(
controller: vatNoController,
hintText: "VAT Number",
editable: true,
required: true,
),
const SizedBox(height: 10.0),
MIHTextField(
controller: contactController,
hintText: "Contact Number",
@@ -462,12 +498,15 @@ class _ProfileBusinessAddState extends State<ProfileBusinessAdd> {
contactController.dispose();
emailController.dispose();
locationController.dispose();
practiceNoController.dispose();
vatNoController.dispose();
_focusNode.dispose();
super.dispose();
}
@override
void initState() {
typeController.addListener(typeSelected);
setState(() {
fnameController.text = widget.signedInUser.fname;
lnameController.text = widget.signedInUser.lname;
@@ -489,197 +528,5 @@ class _ProfileBusinessAddState extends State<ProfileBusinessAdd> {
pullDownToRefresh: false,
onPullDown: () async {},
);
// return Scaffold(
// // appBar: const MIHAppBar(
// // barTitle: "Add Business",
// // propicFile: null,
// // ),
// //drawer: MIHAppDrawer(signedInUser: widget.signedInUser),
// body: SafeArea(
// child: Stack(
// children: [
// KeyboardListener(
// focusNode: _focusNode,
// autofocus: true,
// onKeyEvent: (event) async {
// if (event is KeyDownEvent &&
// event.logicalKey == LogicalKeyboardKey.enter) {
// submitForm();
// }
// },
// child: SingleChildScrollView(
// padding: const EdgeInsets.all(15),
// child: Column(
// children: [
// //const SizedBox(height: 15),
// const Text(
// "Add Business Profile",
// style: TextStyle(
// fontWeight: FontWeight.bold,
// fontSize: 25,
// ),
// ),
// const SizedBox(height: 25.0),
// MIHTextField(
// controller: regController,
// hintText: "Registration No.",
// editable: true,
// required: true,
// ),
// const SizedBox(height: 10.0),
// MIHTextField(
// controller: nameController,
// hintText: "Business Name",
// editable: true,
// required: true,
// ),
// const SizedBox(height: 10.0),
// MIHDropdownField(
// controller: typeController,
// hintText: "Business Type",
// dropdownOptions: const ["Doctors Office", "Other"],
// required: true,
// editable: true,
// ),
// const SizedBox(height: 10.0),
// MIHTextField(
// controller: contactController,
// hintText: "Contact Number",
// editable: true,
// required: true,
// ),
// const SizedBox(height: 10.0),
// MIHTextField(
// controller: emailController,
// hintText: "Email",
// editable: true,
// required: true,
// ),
// const SizedBox(height: 10.0),
// MIHFileField(
// controller: logonameController,
// hintText: "Logo",
// editable: false,
// required: true,
// onPressed: () async {
// FilePickerResult? result =
// await FilePicker.platform.pickFiles(
// type: FileType.custom,
// allowedExtensions: ['jpg', 'png', 'pdf'],
// );
// if (result == null) return;
// final selectedFile = result.files.first;
// setState(() {
// selectedLogo = selectedFile;
// });
// setState(() {
// logonameController.text = selectedFile.name;
// });
// },
// ),
// const SizedBox(height: 15.0),
// Divider(
// color: MzanziInnovationHub.of(context)
// ?.theme
// .secondaryColor(),
// ),
// //const SizedBox(height: 15.0),
// const Text(
// "My Business User",
// style: TextStyle(
// fontWeight: FontWeight.bold,
// fontSize: 25,
// ),
// ),
// const SizedBox(height: 25.0),
// MIHDropdownField(
// controller: titleController,
// hintText: "Title",
// dropdownOptions: const ["Doctor", "Assistant"],
// required: true,
// editable: true,
// ),
// const SizedBox(height: 10.0),
// MIHTextField(
// controller: fnameController,
// hintText: "Name",
// editable: false,
// required: true,
// ),
// const SizedBox(height: 10.0),
// MIHTextField(
// controller: lnameController,
// hintText: "Surname",
// editable: false,
// required: true,
// ),
// const SizedBox(height: 10.0),
// MIHFileField(
// controller: signtureController,
// hintText: "Signature",
// editable: false,
// required: true,
// onPressed: () async {
// FilePickerResult? result =
// await FilePicker.platform.pickFiles(
// type: FileType.custom,
// allowedExtensions: ['jpg', 'png', 'pdf'],
// );
// if (result == null) return;
// final selectedFile = result.files.first;
// setState(() {
// selectedSignature = selectedFile;
// });
// setState(() {
// signtureController.text = selectedFile.name;
// });
// },
// ),
// const SizedBox(height: 15.0),
// MIHDropdownField(
// controller: accessController,
// hintText: "Access",
// dropdownOptions: const ["Full", "Partial"],
// required: true,
// editable: false,
// ),
// const SizedBox(height: 30.0),
// SizedBox(
// width: 500.0,
// height: 50.0,
// child: MIHButton(
// buttonText: "Add",
// buttonColor: MzanziInnovationHub.of(context)!
// .theme
// .secondaryColor(),
// textColor: MzanziInnovationHub.of(context)!
// .theme
// .primaryColor(),
// onTap: () {
// submitForm();
// },
// ),
// ),
// ],
// ),
// ),
// ),
// Positioned(
// top: 10,
// left: 5,
// width: 50,
// height: 50,
// child: IconButton(
// onPressed: () {
// Navigator.of(context).pop();
// },
// icon: const Icon(Icons.arrow_back),
// ),
// )
// ],
// ),
// ),
// );
}
}

View File

@@ -0,0 +1,508 @@
import 'package:Mzansi_Innovation_Hub/main.dart';
import 'package:Mzansi_Innovation_Hub/mih_apis/mih_claim_statement_generation_api.dart';
import 'package:Mzansi_Innovation_Hub/mih_apis/mih_icd10_code_api.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_inputs_and_buttons/mih_button.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_inputs_and_buttons/mih_date_input.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_inputs_and_buttons/mih_dropdown_input.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_inputs_and_buttons/mih_search_input.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_inputs_and_buttons/mih_text_input.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_layout/mih_window.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_pop_up_messages/mih_error_message.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/app_user.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/arguments.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/business.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/business_user.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/icd10_code.dart.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/patients.dart';
import 'package:Mzansi_Innovation_Hub/mih_packages/patient_profile/icd10_search_window.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
class ClaimStatementWindow extends StatefulWidget {
final Patient selectedPatient;
final AppUser signedInUser;
final Business? business;
final BusinessUser? businessUser;
const ClaimStatementWindow({
super.key,
required this.selectedPatient,
required this.signedInUser,
required this.business,
required this.businessUser,
});
@override
State<ClaimStatementWindow> createState() => _ClaimStatementWindowState();
}
class _ClaimStatementWindowState extends State<ClaimStatementWindow> {
final TextEditingController _docTypeController = TextEditingController();
final TextEditingController _fullNameController = TextEditingController();
final TextEditingController _idController = TextEditingController();
final TextEditingController _medAidController = TextEditingController();
final TextEditingController _medAidNoController = TextEditingController();
final TextEditingController _medAidCodeController = TextEditingController();
final TextEditingController _medAidNameController = TextEditingController();
final TextEditingController _medAidSchemeController = TextEditingController();
final TextEditingController _providerNameController = TextEditingController();
final TextEditingController _practiceNoController = TextEditingController();
final TextEditingController _vatNoController = TextEditingController();
final TextEditingController _serviceDateController = TextEditingController();
final TextEditingController _serviceDescController = TextEditingController();
final TextEditingController _serviceDescOptionsController =
TextEditingController();
final TextEditingController _prcedureNameController = TextEditingController();
// final TextEditingController _procedureDateController =
// TextEditingController();
final TextEditingController _proceedureAdditionalInfoController =
TextEditingController();
final TextEditingController _icd10CodeController = TextEditingController();
final TextEditingController _amountController = TextEditingController();
final TextEditingController _preauthNoController = TextEditingController();
final ValueNotifier<String> serviceDesc = ValueNotifier("");
final ValueNotifier<String> medAid = ValueNotifier("");
List<ICD10Code> icd10codeList = [];
void icd10SearchWindow(List<ICD10Code> codeList) {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => ICD10SearchWindow(
icd10CodeController: _icd10CodeController,
icd10codeList: codeList,
),
);
}
Widget getWindowBody() {
return Column(
children: [
MIHDropdownField(
controller: _docTypeController,
hintText: "Document Type",
dropdownOptions: const ["Claim", "Statement"],
required: true,
editable: true,
),
const SizedBox(height: 10),
// Text(
// "Patient Details",
// textAlign: TextAlign.center,
// style: TextStyle(
// fontSize: 20,
// fontWeight: FontWeight.bold,
// color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
// ),
// ),
// Divider(color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
// const SizedBox(height: 10),
// MIHTextField(
// controller: _fullNameController,
// hintText: "Full Name",
// editable: false,
// required: true,
// ),
// const SizedBox(height: 10),
// MIHTextField(
// controller: _idController,
// hintText: "ID No.",
// editable: false,
// required: true,
// ),
// const SizedBox(height: 10),
// MIHTextField(
// controller: _medAidController,
// hintText: "Has Medical Aid",
// editable: false,
// required: true,
// ),
// const SizedBox(height: 10),
// ValueListenableBuilder(
// valueListenable: serviceDesc,
// builder: (BuildContext context, String value, Widget? child) {
// return Visibility(
// visible: value == "Yes",
// child: Column(
// children: [
// MIHTextField(
// controller: _medAidNoController,
// hintText: "Medical Aid No.",
// editable: false,
// required: true,
// ),
// const SizedBox(height: 10),
// MIHTextField(
// controller: _medAidCodeController,
// hintText: "Medical Aid Code",
// editable: false,
// required: true,
// ),
// const SizedBox(height: 10),
// MIHTextField(
// controller: _medAidNameController,
// hintText: "Medical Aid Name",
// editable: false,
// required: true,
// ),
// const SizedBox(height: 10),
// MIHTextField(
// controller: _medAidSchemeController,
// hintText: "Medical Aid Scheme",
// editable: false,
// required: true,
// ),
// const SizedBox(height: 10),
// ],
// ),
// );
// },
// ),
// Text(
// "Provider Details",
// textAlign: TextAlign.center,
// style: TextStyle(
// fontSize: 20,
// fontWeight: FontWeight.bold,
// color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
// ),
// ),
// Divider(color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
// const SizedBox(height: 10),
// MIHTextField(
// controller: _providerNameController,
// hintText: "Provider Name",
// editable: false,
// required: true,
// ),
// const SizedBox(height: 10),
// MIHTextField(
// controller: _practiceNoController,
// hintText: "Practice No.",
// editable: false,
// required: true,
// ),
// const SizedBox(height: 10),
// MIHTextField(
// controller: _vatNoController,
// hintText: "VAT No.",
// editable: false,
// required: true,
// ),
// const SizedBox(height: 10),
Text(
"Service Details",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
),
Divider(color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
const SizedBox(height: 10),
MIHDateField(
controller: _serviceDateController,
lableText: "Date of Service",
required: true,
),
const SizedBox(height: 10),
MIHDropdownField(
controller: _serviceDescController,
hintText: "Service Decription",
dropdownOptions: const [
"Consultation",
"Procedure",
"Other",
],
required: true,
editable: true,
),
const SizedBox(height: 10),
ValueListenableBuilder(
valueListenable: serviceDesc,
builder: (BuildContext context, String value, Widget? child) {
Widget returnWidget;
switch (value) {
case 'Consultation':
returnWidget = Column(
children: [
MIHDropdownField(
controller: _serviceDescOptionsController,
hintText: "Service Decription Options",
dropdownOptions: const [
"General Consultation",
"Follow-Up Consultation",
"Specialist Consultation",
"Emergency Consultation",
],
required: true,
editable: true,
),
const SizedBox(height: 10),
],
);
case 'Procedure':
returnWidget = Column(
children: [
MIHTextField(
controller: _prcedureNameController,
hintText: "Procedure Name",
editable: true,
required: true,
),
const SizedBox(height: 10),
// MIHDateField(
// controller: _procedureDateController,
// lableText: "Procedure Date",
// required: true,
// ),
// const SizedBox(height: 10),
MIHTextField(
controller: _proceedureAdditionalInfoController,
hintText: "Additional Information",
editable: true,
required: true,
),
const SizedBox(height: 10),
],
);
case 'Other':
returnWidget = Column(
children: [
MIHTextField(
controller: _serviceDescOptionsController,
hintText: "Service Decription text",
editable: false,
required: true,
),
const SizedBox(height: 10),
],
);
default:
returnWidget = const SizedBox();
}
return returnWidget;
},
),
//const SizedBox(height: 10),
MIHSearchField(
controller: _icd10CodeController,
hintText: "ICD-10 Code & Description",
required: true,
editable: true,
onTap: () {
//api
MIHIcd10CodeApis.getIcd10Codes(_icd10CodeController.text, context)
.then((result) {
icd10SearchWindow(result);
});
},
),
const SizedBox(height: 10),
MIHTextField(
controller: _amountController,
hintText: "Amount",
editable: true,
required: true,
),
Text(
"Additional Infomation",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
),
Divider(color: MzanziInnovationHub.of(context)!.theme.secondaryColor()),
const SizedBox(height: 10),
MIHTextField(
controller: _preauthNoController,
hintText: "Pre-authorisation No.",
editable: true,
required: false,
),
const SizedBox(height: 15),
SizedBox(
width: 500,
height: 50,
child: MIHButton(
onTap: () {
//generate document and uploud it
if (isInputValid()) {
MIHClaimStatementGenerationApi().generateClaimStatement(
ClaimStatementGenerationArguments(
_docTypeController.text,
widget.selectedPatient.app_id,
_fullNameController.text,
_idController.text,
_medAidController.text,
_medAidNoController.text,
_medAidCodeController.text,
_medAidNameController.text,
_medAidSchemeController.text,
widget.business!.Name,
"*To-Be Added*",
widget.business!.contact_no,
widget.business!.bus_email,
_providerNameController.text,
_practiceNoController.text,
_vatNoController.text,
_serviceDateController.text,
_serviceDescController.text,
_serviceDescOptionsController.text,
_prcedureNameController.text,
_proceedureAdditionalInfoController.text,
_icd10CodeController.text,
_amountController.text,
_preauthNoController.text,
widget.business!.logo_path,
widget.businessUser!.sig_path,
),
PatientViewArguments(
widget.signedInUser,
widget.selectedPatient,
widget.businessUser,
widget.business,
"business",
),
context);
} else {
showDialog(
context: context,
builder: (context) {
return const MIHErrorMessage(errorType: "Input Error");
},
);
}
},
buttonText: "Generate",
buttonColor:
MzanziInnovationHub.of(context)!.theme.secondaryColor(),
textColor: MzanziInnovationHub.of(context)!.theme.primaryColor(),
),
)
],
);
}
void serviceDescriptionSelected() {
if (_serviceDescController.text.isNotEmpty) {
serviceDesc.value = _serviceDescController.text;
} else {
serviceDesc.value = "";
}
}
void hasMedAid() {
if (_medAidController.text.isNotEmpty) {
medAid.value = _medAidController.text;
} else {
medAid.value = "";
}
}
bool isInputValid() {
switch (_serviceDescController.text) {
case 'Procedure':
if (_docTypeController.text.isEmpty ||
_serviceDateController.text.isEmpty ||
_icd10CodeController.text.isEmpty ||
_amountController.text.isEmpty ||
_prcedureNameController.text.isEmpty ||
_proceedureAdditionalInfoController.text.isEmpty) {
return false;
} else {
return true;
}
default:
if (_docTypeController.text.isEmpty ||
_serviceDateController.text.isEmpty ||
_icd10CodeController.text.isEmpty ||
_amountController.text.isEmpty ||
_serviceDescOptionsController.text.isEmpty) {
return false;
} else {
return true;
}
}
}
String getUserTitle() {
if (widget.businessUser!.title == "Doctor") {
return "Dr.";
} else {
return widget.businessUser!.title;
}
}
String getTodayDate() {
DateTime today = DateTime.now();
return DateFormat('yyyy-MM-dd').format(today);
}
@override
void dispose() {
_docTypeController.dispose();
_fullNameController.dispose();
_idController.dispose();
_medAidController.dispose();
_medAidNoController.dispose();
_medAidCodeController.dispose();
_medAidNameController.dispose();
_medAidSchemeController.dispose();
_providerNameController.dispose();
_practiceNoController.dispose();
_vatNoController.dispose();
_serviceDateController.dispose();
_serviceDescController.dispose();
_serviceDescOptionsController.dispose();
_prcedureNameController.dispose();
// _procedureDateController.dispose();
_proceedureAdditionalInfoController.dispose();
_icd10CodeController.dispose();
_preauthNoController.dispose();
super.dispose();
}
@override
void initState() {
_serviceDescController.addListener(serviceDescriptionSelected);
_medAidController.addListener(hasMedAid);
_fullNameController.text =
"${widget.selectedPatient.first_name} ${widget.selectedPatient.last_name}";
_idController.text = widget.selectedPatient.id_no;
_medAidController.text = widget.selectedPatient.medical_aid;
_medAidNameController.text = widget.selectedPatient.medical_aid_name;
_medAidCodeController.text = widget.selectedPatient.medical_aid_code;
_medAidNoController.text = widget.selectedPatient.medical_aid_no;
_medAidSchemeController.text = widget.selectedPatient.medical_aid_scheme;
_serviceDateController.text = getTodayDate();
_providerNameController.text =
"${getUserTitle()} ${widget.signedInUser.fname} ${widget.signedInUser.lname}";
_practiceNoController.text = widget.business!.practice_no;
_vatNoController.text = widget.business!.vat_no;
super.initState();
}
@override
Widget build(BuildContext context) {
return MIHWindow(
fullscreen: false,
windowTitle: "Generate Claim/ Statement Document",
windowTools: const [],
onWindowTapClose: () {
// medicineController.clear();
// quantityController.clear();
// dosageController.clear();
// timesDailyController.clear();
// noDaysController.clear();
// noRepeatsController.clear();
Navigator.pop(context);
},
windowBody: [
getWindowBody(),
],
);
}
}

View File

@@ -0,0 +1,228 @@
import 'dart:convert';
import 'package:Mzansi_Innovation_Hub/mih_apis/mih_claim_statement_generation_api.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/arguments.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/claim_statement_file.dart';
import 'package:flutter/material.dart';
import 'package:supertokens_flutter/http.dart' as http;
import '../../../main.dart';
import '../../../mih_components/mih_layout/mih_window.dart';
import '../../../mih_components/mih_pop_up_messages/mih_delete_message.dart';
import '../../../mih_components/mih_pop_up_messages/mih_error_message.dart';
import '../../../mih_components/mih_pop_up_messages/mih_success_message.dart';
import '../../../mih_env/env.dart';
import '../../../mih_objects/app_user.dart';
import '../../../mih_objects/business.dart';
import '../../../mih_objects/business_user.dart';
import '../../../mih_objects/patients.dart';
import 'build_file_view.dart';
class BuildClaimStatementFileList extends StatefulWidget {
final AppUser signedInUser;
final List<ClaimStatementFile> files;
final Patient selectedPatient;
final Business? business;
final BusinessUser? businessUser;
final String type;
const BuildClaimStatementFileList({
super.key,
required this.files,
required this.signedInUser,
required this.selectedPatient,
required this.business,
required this.businessUser,
required this.type,
});
@override
State<BuildClaimStatementFileList> createState() =>
_BuildClaimStatementFileListState();
}
class _BuildClaimStatementFileListState
extends State<BuildClaimStatementFileList> {
int indexOn = 0;
final baseAPI = AppEnviroment.baseApiUrl;
final basefile = AppEnviroment.baseFileUrl;
String fileUrl = "";
Future<String> getFileUrlApiCall(String filePath) async {
var url = "$baseAPI/minio/pull/file/${AppEnviroment.getEnv()}/$filePath";
//print(url);
var response = await http.get(Uri.parse(url));
// print("here1");
//print(response.statusCode);
if (response.statusCode == 200) {
//print("here2");
String body = response.body;
//print(body);
//print("here3");
var decodedData = jsonDecode(body);
//print("Dedoced: ${decodedData['minioURL']}");
return decodedData['minioURL'];
//AppUser u = AppUser.fromJson(decodedData);
// print(u.email);
//return "AlometThere";
} else {
throw Exception("Error: GetUserData status code ${response.statusCode}");
}
}
void internetConnectionPopUp() {
showDialog(
context: context,
builder: (context) {
return const MIHErrorMessage(errorType: "Internet Connection");
},
);
}
void successPopUp(String message) {
showDialog(
context: context,
builder: (context) {
return MIHSuccessMessage(
successType: "Success",
successMessage: message,
);
},
);
}
void deleteFilePopUp(String filePath, int fileID) {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => MIHDeleteMessage(
deleteType: "File",
onTap: () async {
//API Call here
await MIHClaimStatementGenerationApi
.deleteClaimStatementFilesByFileID(
PatientViewArguments(
widget.signedInUser,
widget.selectedPatient,
widget.businessUser,
widget.business,
"business",
),
filePath,
fileID,
context,
);
},
),
);
}
void viewFilePopUp(String fileName, String filePath, int fileID, String url) {
bool hasAccessToDelete = false;
if (widget.type == "business") {
hasAccessToDelete = true;
}
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => MIHWindow(
fullscreen: true,
windowTitle: fileName,
windowBody: [
BuildFileView(
link: url,
path: filePath,
//pdfLink: '${AppEnviroment.baseFileUrl}/mih/$filePath',
),
const SizedBox(
height: 10,
)
],
windowTools: [
Visibility(
visible: hasAccessToDelete,
child: IconButton(
onPressed: () {
deleteFilePopUp(filePath, fileID);
},
icon: Icon(
size: 35,
Icons.delete,
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
),
),
],
onWindowTapClose: () {
Navigator.pop(context);
},
),
);
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
}
@override
Widget build(BuildContext context) {
if (widget.files.isNotEmpty) {
return ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
separatorBuilder: (BuildContext context, int index) {
return Divider(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
);
},
itemCount: widget.files.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(
widget.files[index].file_name,
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
),
subtitle: Text(
widget.files[index].insert_date,
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
),
// trailing: Icon(
// Icons.arrow_forward,
// color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
// ),
onTap: () async {
await getFileUrlApiCall(widget.files[index].file_path)
.then((urlHere) {
//print(url);
setState(() {
fileUrl = urlHere;
});
});
viewFilePopUp(
widget.files[index].file_name,
widget.files[index].file_path,
widget.files[index].idclaim_statement_file,
fileUrl);
},
);
},
);
} else {
return const Center(
child: Text(
"No Documents Available",
style: TextStyle(fontSize: 25, color: Colors.grey),
textAlign: TextAlign.center,
),
);
}
}
}

View File

@@ -0,0 +1,76 @@
import 'package:Mzansi_Innovation_Hub/mih_objects/icd10_code.dart.dart';
import 'package:flutter/material.dart';
import '../../../main.dart';
import '../../../mih_env/env.dart';
class BuildICD10CodeList extends StatefulWidget {
final TextEditingController icd10CodeController;
final List<ICD10Code> icd10codeList;
const BuildICD10CodeList({
super.key,
required this.icd10CodeController,
required this.icd10codeList,
});
@override
State<BuildICD10CodeList> createState() => _BuildPatientsListState();
}
class _BuildPatientsListState extends State<BuildICD10CodeList> {
String baseAPI = AppEnviroment.baseApiUrl;
int counter = 0;
Widget displayCode(int index) {
String title = "ICD-10 Code: ${widget.icd10codeList[index].icd10}";
String description =
"Description: ${widget.icd10codeList[index].description}";
return ListTile(
title: Text(
title,
style: TextStyle(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
),
subtitle: RichText(
text: TextSpan(
text: description,
style: DefaultTextStyle.of(context).style,
),
),
onTap: () {
//select code
setState(() {
widget.icd10CodeController.text =
"${widget.icd10codeList[index].icd10} - ${widget.icd10codeList[index].description}";
});
Navigator.of(context).pop();
},
);
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return ListView.separated(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
separatorBuilder: (BuildContext context, index) {
return Divider(
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
);
},
itemCount: widget.icd10codeList.length,
itemBuilder: (context, index) {
//final patient = widget.patients[index].id_no.contains(widget.searchString);
//print(index);
return displayCode(index);
},
);
}
}

View File

@@ -0,0 +1,58 @@
import 'package:Mzansi_Innovation_Hub/mih_components/mih_inputs_and_buttons/mih_text_input.dart';
import 'package:Mzansi_Innovation_Hub/mih_components/mih_layout/mih_window.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/icd10_code.dart.dart';
import 'package:Mzansi_Innovation_Hub/mih_packages/patient_profile/builder/build_icd10_code_list.dart';
import 'package:flutter/material.dart';
class ICD10SearchWindow extends StatefulWidget {
final TextEditingController icd10CodeController;
final List<ICD10Code> icd10codeList;
const ICD10SearchWindow({
super.key,
required this.icd10CodeController,
required this.icd10codeList,
});
@override
State<ICD10SearchWindow> createState() => _ICD10SearchWindowState();
}
class _ICD10SearchWindowState extends State<ICD10SearchWindow> {
Widget getWindowBody() {
return Column(
children: [
MIHTextField(
controller: widget.icd10CodeController,
hintText: "Search Text",
editable: false,
required: false,
),
BuildICD10CodeList(
icd10CodeController: widget.icd10CodeController,
icd10codeList: widget.icd10codeList,
),
],
);
}
@override
Widget build(BuildContext context) {
return MIHWindow(
fullscreen: false,
windowTitle: "ICD-10 Search",
windowTools: const [],
onWindowTapClose: () {
// medicineController.clear();
// quantityController.clear();
// dosageController.clear();
// timesDailyController.clear();
// noDaysController.clear();
// noRepeatsController.clear();
Navigator.pop(context);
},
windowBody: [
getWindowBody(),
],
);
}
}

View File

@@ -0,0 +1,272 @@
import 'dart:async';
import 'dart:convert';
import 'package:Mzansi_Innovation_Hub/mih_apis/mih_claim_statement_generation_api.dart';
import 'package:Mzansi_Innovation_Hub/mih_objects/claim_statement_file.dart';
import 'package:Mzansi_Innovation_Hub/mih_packages/patient_profile/Claim_Statement_Window.dart';
import 'package:Mzansi_Innovation_Hub/mih_packages/patient_profile/builder/build_claim_statement_files_list.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import '../../main.dart';
import 'package:supertokens_flutter/http.dart' as http;
import '../../mih_components/mih_pop_up_messages/mih_error_message.dart';
import '../../mih_components/mih_pop_up_messages/mih_loading_circle.dart';
import '../../mih_components/mih_pop_up_messages/mih_success_message.dart';
import '../../mih_env/env.dart';
import '../../mih_objects/app_user.dart';
import '../../mih_objects/business.dart';
import '../../mih_objects/business_user.dart';
import '../../mih_objects/files.dart';
import '../../mih_objects/patients.dart';
// import 'builder/build_files_list.dart';
class PatientClaimsOrStatements extends StatefulWidget {
final int patientIndex;
final Patient selectedPatient;
final AppUser signedInUser;
final Business? business;
final BusinessUser? businessUser;
final String type;
const PatientClaimsOrStatements({
super.key,
required this.patientIndex,
required this.selectedPatient,
required this.signedInUser,
required this.business,
required this.businessUser,
required this.type,
});
@override
State<PatientClaimsOrStatements> createState() =>
_PatientClaimsOrStatementsState();
}
class _PatientClaimsOrStatementsState extends State<PatientClaimsOrStatements> {
String endpointFiles = "${AppEnviroment.baseApiUrl}/files/patients/";
String endpointUser = "${AppEnviroment.baseApiUrl}/users/profile/";
String endpointGenFiles =
"${AppEnviroment.baseApiUrl}/files/generate/med-cert/";
String endpointFileUpload = "${AppEnviroment.baseApiUrl}/files/upload/file/";
String endpointInsertFiles = "${AppEnviroment.baseApiUrl}/files/insert/";
final startDateController = TextEditingController();
final endDateTextController = TextEditingController();
final retDateTextController = TextEditingController();
final selectedFileController = TextEditingController();
final medicineController = TextEditingController();
final quantityController = TextEditingController();
final dosageController = TextEditingController();
final timesDailyController = TextEditingController();
final noDaysController = TextEditingController();
final noRepeatsController = TextEditingController();
final outputController = TextEditingController();
late Future<List<ClaimStatementFile>> futueFiles;
late String userEmail = "";
late PlatformFile selected;
final baseAPI = AppEnviroment.baseApiUrl;
Future<List<PFile>> fetchFiles() async {
final response = await http.get(Uri.parse(
"${AppEnviroment.baseApiUrl}/files/patients/${widget.selectedPatient.app_id}"));
//print(response.statusCode);
//print(response.body);
if (response.statusCode == 200) {
Iterable l = jsonDecode(response.body);
List<PFile> files =
List<PFile>.from(l.map((model) => PFile.fromJson(model)));
return files;
} else {
internetConnectionPopUp();
throw Exception('failed to load patients');
}
}
void successPopUp(String message) {
showDialog(
context: context,
builder: (context) {
return MIHSuccessMessage(
successType: "Success",
successMessage: message,
);
},
);
}
void messagePopUp(error) {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(error),
);
},
);
}
void claimOrStatementWindow() {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => ClaimStatementWindow(
selectedPatient: widget.selectedPatient,
signedInUser: widget.signedInUser,
business: widget.business,
businessUser: widget.businessUser,
),
);
}
void internetConnectionPopUp() {
showDialog(
context: context,
builder: (context) {
return const MIHErrorMessage(errorType: "Internet Connection");
},
);
}
bool isMedCertFieldsFilled() {
if (startDateController.text.isEmpty ||
endDateTextController.text.isEmpty ||
retDateTextController.text.isEmpty) {
return false;
} else {
return true;
}
}
bool isFileFieldsFilled() {
if (selectedFileController.text.isEmpty) {
return false;
} else {
return true;
}
}
List<Widget> setIcons() {
if (widget.type == "personal") {
return [
Text(
"Claims/ Statements",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
),
// IconButton(
// onPressed: () {
// uploudFilePopUp();
// },
// icon: Icon(
// Icons.add,
// color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
// ),
// )
];
} else {
return [
Text(
"Claims/ Statements",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
),
IconButton(
onPressed: () {
// new window to input fields for claim/ statements
claimOrStatementWindow();
},
icon: Icon(
Icons.add,
color: MzanziInnovationHub.of(context)!.theme.secondaryColor(),
),
)
];
}
}
@override
void dispose() {
startDateController.dispose();
endDateTextController.dispose();
retDateTextController.dispose();
selectedFileController.dispose();
medicineController.dispose();
quantityController.dispose();
dosageController.dispose();
timesDailyController.dispose();
noDaysController.dispose();
noRepeatsController.dispose();
outputController.dispose();
super.dispose();
}
@override
void initState() {
if (widget.business == null) {
futueFiles =
MIHClaimStatementGenerationApi.getClaimStatementFilesByPatient(
widget.signedInUser.app_id);
} else {
futueFiles =
MIHClaimStatementGenerationApi.getClaimStatementFilesByBusiness(
widget.business!.business_id);
}
//patientDetails = getPatientDetails() as Patient;
//getUserDetails();
super.initState();
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: futueFiles,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: Mihloadingcircle(),
);
} else if (snapshot.hasData) {
final filesList = snapshot.data!;
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: setIcons(),
),
Divider(
color:
MzanziInnovationHub.of(context)!.theme.secondaryColor()),
const SizedBox(height: 10),
//const Placeholder(),
BuildClaimStatementFileList(
files: filesList,
signedInUser: widget.signedInUser,
selectedPatient: widget.selectedPatient,
business: widget.business,
businessUser: widget.businessUser,
type: widget.type,
),
],
);
} else {
return const Center(
child: Text("Error Loading Notes"),
);
}
},
);
}
}

View File

@@ -1,5 +1,6 @@
import 'dart:convert';
import 'package:Mzansi_Innovation_Hub/mih_packages/patient_profile/patient_claims_statements.dart';
import 'package:flutter/material.dart';
import 'package:flutter_swipe_detector/flutter_swipe_detector.dart';
import '../../main.dart';
@@ -94,7 +95,7 @@ class _PatientViewState extends State<PatientView> {
businessUser: widget.arguments.businessUser,
type: widget.arguments.type,
);
} else {
} else if (index == 2) {
return PatientFiles(
patientIndex: widget.arguments.selectedPatient!.idpatients,
selectedPatient: widget.arguments.selectedPatient!,
@@ -103,6 +104,15 @@ class _PatientViewState extends State<PatientView> {
businessUser: widget.arguments.businessUser,
type: widget.arguments.type,
);
} else {
return PatientClaimsOrStatements(
patientIndex: widget.arguments.selectedPatient!.idpatients,
selectedPatient: widget.arguments.selectedPatient!,
signedInUser: widget.arguments.signedInUser,
business: widget.arguments.business,
businessUser: widget.arguments.businessUser,
type: widget.arguments.type,
);
}
}
@@ -221,6 +231,35 @@ class _PatientViewState extends State<PatientView> {
),
),
),
//============ Claims/ Statements ================
Visibility(
visible: _selectedIndex != 3,
child: IconButton(
onPressed: () {
setState(() {
_selectedIndex = 3;
});
},
icon: const Icon(
Icons.file_open_outlined,
size: 35,
),
),
),
Visibility(
visible: _selectedIndex == 3,
child: IconButton.filled(
onPressed: () {
setState(() {
_selectedIndex = 3;
});
},
icon: const Icon(
Icons.file_open_outlined,
size: 35,
),
),
),
],
);
}

View File

@@ -6,6 +6,7 @@ import routers.patients as patients
import routers.patients_files as patients_files
import routers.patients_notes as patients_notes
import routers.patients_queue as patients_queue
import routers.claim_statement_files as claim_statement_files
import routers.users as users
import routers.notifications as notifications
import routers.fileStorage as fileStorage
@@ -15,6 +16,7 @@ import routers.business as business
import routers.access_request as access_request
import routers.patient_access as patient_access
import routers.mzansi_wallet as mzansi_wallet
import routers.icd10_codes as icd10_codes
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware import Middleware
from supertokens_python import get_all_cors_headers
@@ -83,11 +85,13 @@ app.include_router(access_request.router)
app.include_router(patient_access.router)
app.include_router(users.router)
app.include_router(fileStorage.router)
app.include_router(claim_statement_files.router)
app.include_router(medicine.router)
app.include_router(business_user.router)
app.include_router(business.router)
app.include_router(notifications.router)
app.include_router(mzansi_wallet.router)
app.include_router(icd10_codes.router)
# Check if server is up
@app.get("/", tags=["Server Check"])

View File

@@ -25,6 +25,8 @@ class businessInsertRequest(BaseModel):
contact_no: str
bus_email: str
gps_location: str
practice_no: str
vat_no: str
class businessUpdateRequest(BaseModel):
business_id: str
@@ -36,6 +38,8 @@ class businessUpdateRequest(BaseModel):
contact_no: str
bus_email: str
gps_location: str
practice_no: str
vat_no: str
# Get List of all files
@@ -43,7 +47,10 @@ class businessUpdateRequest(BaseModel):
async def read_business_by_business_id(business_id: str, session: SessionContainer = Depends(verify_session())): #, session: SessionContainer = Depends(verify_session())
db = database.dbConnection.dbAppDataConnect()
cursor = db.cursor()
query = "SELECT business.business_id, business.Name, business.type, business.registration_no, business.logo_name, business.logo_path, business.contact_no, business.bus_email, business_users.app_id, business.gps_location "
query = "SELECT business.business_id, business.Name, business.type, business.registration_no, "
query += "business.logo_name, business.logo_path, business.contact_no, business.bus_email, "
query += "business_users.app_id, business.gps_location, "
query += "practice_no, vat_no "
query += "FROM business "
query += "inner join business_users "
query += "on business.business_id=business_users.business_id "
@@ -64,6 +71,8 @@ async def read_business_by_business_id(business_id: str, session: SessionContain
"bus_email": item[7],
"app_id": item[8],
"gps_location": item[9],
"practice_no": item[10],
"vat_no": item[11],
}
for item in cursor.fetchall()
]
@@ -81,7 +90,10 @@ async def read_business_by_business_id(business_id: str, session: SessionContain
async def read_business_by_app_id(app_id: str, session: SessionContainer = Depends(verify_session())): #, session: SessionContainer = Depends(verify_session())
db = database.dbConnection.dbAppDataConnect()
cursor = db.cursor()
query = "SELECT business.business_id, business.Name, business.type, business.registration_no, business.logo_name, business.logo_path, business.contact_no, business.bus_email, business_users.app_id, business.gps_location "
query = "SELECT business.business_id, business.Name, business.type, business.registration_no, "
query += "business.logo_name, business.logo_path, business.contact_no, business.bus_email, "
query += "business_users.app_id, business.gps_location, "
query += "practice_no, vat_no "
query += "FROM business "
query += "inner join business_users "
query += "on business.business_id=business_users.business_id "
@@ -102,6 +114,8 @@ async def read_business_by_app_id(app_id: str, session: SessionContainer = Depen
"bus_email": item[7],
"app_id": item[8],
"gps_location": item[9],
"practice_no": item[10],
"vat_no": item[11],
}
for item in cursor.fetchall()
]
@@ -118,8 +132,8 @@ async def insert_business_details(itemRequest : businessInsertRequest, session:
db = database.dbConnection.dbAppDataConnect()
cursor = db.cursor()
query = "insert into business "
query += "(business_id, Name, type, registration_no, logo_name, logo_path, contact_no, bus_email, gps_location) "
query += "values (%s, %s, %s, %s, %s, %s, %s, %s, %s)"
query += "(business_id, Name, type, registration_no, logo_name, logo_path, contact_no, bus_email, gps_location, practice_no, vat_no), "
query += "values (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"
uuidString = str(uuid.uuid1())
userData = (uuidString,
itemRequest.Name,
@@ -129,7 +143,9 @@ async def insert_business_details(itemRequest : businessInsertRequest, session:
itemRequest.logo_path,
itemRequest.contact_no,
itemRequest.bus_email,
itemRequest.gps_location,)
itemRequest.gps_location,
itemRequest.practice_no,
itemRequest.vat_no)
try:
cursor.execute(query, userData)
except Exception as error:
@@ -146,7 +162,7 @@ async def Update_Business_details(itemRequest : businessUpdateRequest, session:
# print(itemRequest.gps_location)
cursor = db.cursor()
query = "update business "
query += "set Name=%s, type=%s, registration_no=%s, logo_name=%s, logo_path=%s, contact_no=%s, bus_email=%s, gps_location=%s "
query += "set Name=%s, type=%s, registration_no=%s, logo_name=%s, logo_path=%s, contact_no=%s, bus_email=%s, gps_location=%s, practice_no=%s, vat_no=%s "
query += "where business_id=%s"
userData = (itemRequest.Name,
itemRequest.type,
@@ -156,6 +172,8 @@ async def Update_Business_details(itemRequest : businessUpdateRequest, session:
itemRequest.contact_no,
itemRequest.bus_email,
itemRequest.gps_location,
itemRequest.practice_no,
itemRequest.vat_no,
itemRequest.business_id,
)
try:

View File

@@ -0,0 +1,112 @@
import mysql.connector
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
#from ..database import dbConnection
import database
from datetime import date
#SuperToken Auth from front end
from supertokens_python.recipe.session.framework.fastapi import verify_session
from supertokens_python.recipe.session import SessionContainer
from fastapi import Depends
router = APIRouter()
class claimStatementDeleteRequest(BaseModel):
idclaim_statement_file: int
class claimStatementInsertRequest(BaseModel):
app_id: str
business_id: str
file_path: str
file_name: str
# Get List of all files by patient
@router.get("/files/claim-statement/patient/{app_id}", tags=["Claim Statement Files"])
async def read_all_claim_statement_files_by_app_id(app_id: str, session: SessionContainer = Depends(verify_session())):
db = database.dbConnection.dbPatientManagerConnect()
cursor = db.cursor()
query = "SELECT * FROM claim_statement_file where app_id = %s ORDER BY insert_date DESC"
cursor.execute(query, (app_id,))
items = [
{
"idclaim_statement_file": item[0],
"app_id": item[1],
"business_id": item[2],
"insert_date": item[3],
"file_path": item[4],
"file_name": item[5],
}
for item in cursor.fetchall()
]
cursor.close()
db.close()
return items
# Get List of all files by patient
@router.get("/files/claim-statement/business/{business_id}", tags=["Claim Statement Files"])
async def read_all_claim_statement_files_by_business_id(business_id: str, session: SessionContainer = Depends(verify_session())):
db = database.dbConnection.dbPatientManagerConnect()
cursor = db.cursor()
query = "SELECT * FROM claim_statement_file where business_id = %s ORDER BY insert_date DESC"
cursor.execute(query, (business_id,))
items = [
{
"idclaim_statement_file": item[0],
"app_id": item[1],
"business_id": item[2],
"insert_date": item[3],
"file_path": item[4],
"file_name": item[5],
}
for item in cursor.fetchall()
]
cursor.close()
db.close()
return items
# Delete Patient note on table
@router.delete("/files/claim-statement/delete/", tags=["Claim Statement Files"])
async def Delete_Patient_File(itemRequest : claimStatementDeleteRequest, session: SessionContainer = Depends(verify_session())): #session: SessionContainer = Depends(verify_session())
# today = date.today()
db = database.dbConnection.dbPatientManagerConnect()
cursor = db.cursor()
query = "delete from claim_statement_file "
query += "where idclaim_statement_file=%s"
# notetData = (itemRequest.idpatient_notes)
try:
cursor.execute(query, (str(itemRequest.idclaim_statement_file),))
except Exception as error:
raise HTTPException(status_code=404, detail="Failed to Delete Record")
#return {"query": query, "message": error}
db.commit()
cursor.close()
db.close()
return {"message": "Successfully deleted Record"}
# Insert Patient note into table
@router.post("/files/claim-statement/insert/", tags=["Claim Statement Files"], status_code=201)
async def insert_Patient_Files(itemRequest : claimStatementInsertRequest, session: SessionContainer = Depends(verify_session())): #, session: SessionContainer = Depends(verify_session())
today = date.today()
db = database.dbConnection.dbPatientManagerConnect()
cursor = db.cursor()
query = "insert into claim_statement_file "
query += "(app_id, business_id, file_path, file_name, insert_date) "
query += "values (%s, %s, %s, %s, %s)"
notetData = (
itemRequest.app_id,
itemRequest.business_id,
itemRequest.file_path,
itemRequest.file_name,
today,
)
try:
cursor.execute(query, notetData)
except Exception as error:
print(error)
raise HTTPException(status_code=404, detail="Failed to Create Record")
# return {"message": error}
db.commit()
cursor.close()
db.close()
return {"message": "Successfully Created file Record"}

View File

@@ -71,6 +71,35 @@ class perscriptionList(BaseModel):
sig_path: str
data: List[perscription]
class claimStatementUploud(BaseModel):
document_type: str
patient_app_id: str
patient_full_name: str
patient_id_no: str
has_med_aid: str
med_aid_no: str
med_aid_code: str
med_aid_name: str
med_aid_scheme: str
busName: str
busAddr: str
busNo: str
busEmail: str
provider_name: str
practice_no: str
vat_no: str
service_date: str
service_desc: str
service_desc_option: str
procedure_name: str
# procedure_date: str
procedure_additional_info: str
icd10_code: str
amount: str
pre_auth_no: str
logo_path: str
sig_path: str
@router.get("/minio/pull/file/{env}/{app_id}/{folder}/{file_name}", tags=["Minio"])
async def pull_File_from_user(app_id: str, folder: str, file_name: str, env: str, session: SessionContainer = Depends(verify_session())): #, session: SessionContainer = Depends(verify_session())
path = app_id + "/" + folder + "/" + file_name
@@ -93,7 +122,8 @@ async def pull_File_from_user(app_id: str, folder: str, file_name: str, env: str
# return {"message": error}
if(env == "Dev"):
return {
"minioURL": f"http://10.0.2.2:9000/mih/{app_id}/{folder}/{file_name}",
# 10.0.2.2
"minioURL": f"http://localhost:9000/mih/{app_id}/{folder}/{file_name}",
}
else:
return {
@@ -122,7 +152,7 @@ async def delete_File_of_user(requestItem: minioDeleteRequest, session: SessionC
path = requestItem.file_path
try:
# uploudFile(app_id, file.filename, extension[1], content)
client = Minio_Storage.minioConnection.minioConnect("dev")
client = Minio_Storage.minioConnection.minioConnect("Prd")
minioError = client.remove_object("mih", path)
except Exception as error:
@@ -147,6 +177,11 @@ async def upload_perscription_to_user(requestItem: perscriptionList, session: Se
uploudPerscription(requestItem)
return {"message": "Successfully Generated File"}
@router.post("/minio/generate/claim-statement/", tags=["Minio"])
async def upload_perscription_to_user(requestItem: claimStatementUploud, session: SessionContainer = Depends(verify_session())): #, session: SessionContainer = Depends(verify_session())
uploudClaimStatement(requestItem)
return {"message": "Successfully Generated File"}
def uploudFile(app_id, folder, fileName, extension, content):
client = Minio_Storage.minioConnection.minioConnect("Dev")
found = client.bucket_exists("mih")
@@ -162,9 +197,8 @@ def uploudFile(app_id, folder, fileName, extension, content):
part_size=10*1024*1024,
content_type=f"application/{extension}")
def uploudMedCert(requestItem: medCertUploud):
client = Minio_Storage.minioConnection.minioConnect("dev")
client = Minio_Storage.minioConnection.minioConnect("Prod")
generateMedCertPDF(requestItem)
today = datetime.today().strftime('%Y-%m-%d')
found = client.bucket_exists("mih")
@@ -176,7 +210,7 @@ def uploudMedCert(requestItem: medCertUploud):
client.fput_object("mih", fileName, "temp-med-cert.pdf")
def generateMedCertPDF(requestItem: medCertUploud):
client = Minio_Storage.minioConnection.minioConnect("dev")
client = Minio_Storage.minioConnection.minioConnect("Prod")
new_logo_path = requestItem.logo_path.replace(" ","-")
new_sig_path = requestItem.sig_path.replace(" ","-")
minioLogo = client.get_object("mih", new_logo_path).read()
@@ -241,7 +275,7 @@ def generateMedCertPDF(requestItem: medCertUploud):
myCanvas.save()
def uploudPerscription(requestItem: perscriptionList):
client = Minio_Storage.minioConnection.minioConnect("dev")
client = Minio_Storage.minioConnection.minioConnect("Prod")
generatePerscriptionPDF(requestItem)
today = datetime.today().strftime('%Y-%m-%d')
found = client.bucket_exists("mih")
@@ -253,7 +287,7 @@ def uploudPerscription(requestItem: perscriptionList):
client.fput_object("mih", fileName, "temp-perscription.pdf")
def generatePerscriptionPDF(requestItem: perscriptionList):
client = Minio_Storage.minioConnection.minioConnect("dev")
client = Minio_Storage.minioConnection.minioConnect("Prod")
new_logo_path = requestItem.logo_path.replace(" ","-")
new_sig_path = requestItem.sig_path.replace(" ","-")
minioLogo = client.get_object("mih", new_logo_path).read()
@@ -263,7 +297,7 @@ def generatePerscriptionPDF(requestItem: perscriptionList):
w,h = A4
myCanvas = canvas.Canvas("temp-perscription.pdf", pagesize=A4)
myCanvas = canvas.Canvas("temp-claim.pdf", pagesize=A4)
#Business Logo
myCanvas.drawImage(imageLogo, 50, h - 125,100,100, mask='auto')
@@ -341,9 +375,180 @@ def generatePerscriptionPDF(requestItem: perscriptionList):
myCanvas.save()
def byteToMb(size):
sizekb = size /1000
sizemb = sizekb / 1000
return sizemb
def uploudClaimStatement(requestItem: claimStatementUploud):
try:
client = Minio_Storage.minioConnection.minioConnect("Prod")
print("connected")
except Exception:
print("error")
generateClaimStatementPDF(requestItem)
today = datetime.today().strftime('%Y-%m-%d')
found = client.bucket_exists("mih")
if not found:
client.make_bucket("mih")
else:
print("Bucket already exists")
fileName = f"{requestItem.patient_app_id}/claims-statements/{requestItem.document_type}-{requestItem.patient_full_name}-{today}.pdf"
client.fput_object("mih", fileName, "temp-claim-statement.pdf")
# print(byteToMb(229574))
def generateClaimStatementPDF(requestItem: claimStatementUploud):
client = Minio_Storage.minioConnection.minioConnect("Prod")
# print("buckets: " + client.list_buckets)
new_logo_path = requestItem.logo_path.replace(" ","-")
new_sig_path = requestItem.sig_path.replace(" ","-")
print("Path Logo: " + new_logo_path)
minioLogo = client.get_object("mih", new_logo_path).read()
imageLogo = ImageReader(io.BytesIO(minioLogo))
minioSig = client.get_object("mih", new_sig_path).read()
imageSig = ImageReader(io.BytesIO(minioSig))
w,h = A4
myCanvas = canvas.Canvas("temp-claim-statement.pdf", pagesize=A4)
#Business Logo
myCanvas.drawImage(imageLogo, 50, h - 125,100,100, mask='auto')
#Business Details
myCanvas.setFont('Helvetica-Bold', 10)
myCanvas.drawRightString(w - 50,h - 40, f"Name: {requestItem.busName}")
myCanvas.drawRightString(w - 50,h - 55, f"Address: {requestItem.busAddr}")
myCanvas.drawRightString(w - 50,h - 70, f"Practice No.: {requestItem.practice_no}")
myCanvas.drawRightString(w - 50,h - 85, f"Contact No.: {requestItem.busNo}")
myCanvas.drawRightString(w - 50,h - 100, f"Email: {requestItem.busEmail}")
myCanvas.line(50,h-150,w-50,h-150)
#Todays Date
myCanvas.setFont('Helvetica-Bold', 12)
today = datetime.today()
issueDate = today.strftime('%d-%m-%Y')
myCanvas.drawRightString(w - 50,h - 180,f"{issueDate}")
#Title
myCanvas.setFont('Helvetica-Bold', 20)
myCanvas.drawString(w-340, h - 200, requestItem.document_type)
#Body
# Patient Details
myCanvas.setFont('Helvetica-Bold', 14)
myCanvas.drawString(50, h-230, "Patient Details")
myCanvas.line(50,h-235,w-50,h-235)
medAidNo = ""
medAidCode = ""
medAidNameAndScheme = ""
if(requestItem.has_med_aid == "Yes"):
medAidNo = requestItem.med_aid_no
medAidCode = requestItem.med_aid_code
medAidNameAndScheme = f"{requestItem.med_aid_name} - {requestItem.med_aid_scheme}"
else:
medAidNo = "n/a"
medAidCode = "n/a"
medAidNameAndScheme = "n/a"
preAuthNo = requestItem.pre_auth_no
if(preAuthNo == ""):
preAuthNo = "n/a"
# category
myCanvas.setFont('Helvetica-Bold', 12)
myCanvas.drawString(50, h-250, f"Patient Name:")
myCanvas.drawString(50, h-265, f"Patient ID:")
myCanvas.drawString(50, h-280, f"Medical Aid No.:")
myCanvas.drawString(50, h-295, f"Medical Aid Code:")
myCanvas.drawString(50, h-310, f"Medical Aid Scheme:")
myCanvas.drawString(50, h-325, f"Pre-Authorisation No:")
# content
myCanvas.setFont('Helvetica', 12)
myCanvas.drawString(225, h-250, f"{requestItem.patient_full_name}")
myCanvas.drawString(225, h-265, f"{requestItem.patient_id_no}")
myCanvas.drawString(225, h-280, f"{medAidNo}")
myCanvas.drawString(225, h-295, f"{medAidCode}")
myCanvas.drawString(225, h-310, f"{medAidNameAndScheme}")
myCanvas.drawString(225, h-325, f"{preAuthNo}")
#===============================================================================
# Provide Details
myCanvas.setFont('Helvetica-Bold', 14)
myCanvas.drawString(50, h-355, "Provider Details")
myCanvas.line(50,h-360,w-50,h-360)
myCanvas.setFont('Helvetica-Bold', 12)
myCanvas.drawString(50, h-375, f"Practice Name:")
myCanvas.drawString(50, h-390, f"Practice No.:")
myCanvas.drawString(50, h-405, f"Vat No.:")
myCanvas.drawString(50, h-420, f"Provider Name:")
myCanvas.setFont('Helvetica', 12)
myCanvas.drawString(225, h-375, f"{requestItem.busName}")
myCanvas.drawString(225, h-390, f"{requestItem.practice_no}")
myCanvas.drawString(225, h-405, f"{requestItem.vat_no}")
myCanvas.drawString(225, h-420, f"{requestItem.provider_name}")
#===============================================================================
# Service Details
myCanvas.setFont('Helvetica-Bold', 14)
myCanvas.drawString(50, h-450, "Service Details")
# myCanvas.drawRightString(w - 50, h-300, "Repeat(s)")
myCanvas.drawRightString(w - 70, h-450, "Amount")
myCanvas.line(50,h-455,w-50,h-455)
myCanvas.setFont('Helvetica-Bold', 12)
myCanvas.drawString(50, h-470, f"Service Type:")
myCanvas.drawString(50, h-485, f"Service Date:")
myCanvas.setFont('Helvetica', 12)
myCanvas.drawString(225, h-470, f"{requestItem.service_desc}")
displayAmount = ""
if("." in requestItem.amount or "," in requestItem.amount):
displayAmount = requestItem.amount.replace(",",".")
else:
displayAmount = requestItem.amount + ".00"
myCanvas.drawRightString(w - 80, h-470, displayAmount)
myCanvas.drawString(225, h-485, f"{requestItem.service_date}")
y = 0
if(requestItem.service_desc == "Precedure"):
myCanvas.setFont('Helvetica-Bold', 12)
myCanvas.drawString(50, h-500, f"Procedure Name:")
myCanvas.drawString(50, h-515, f"Additional Info:")
myCanvas.drawString(50, h-530, f"ICD-10 Code & Description:")
myCanvas.setFont('Helvetica', 12)
myCanvas.drawString(225, h-500, f"{requestItem.procedure_name}")
myCanvas.drawString(225, h-515, f"{requestItem.procedure_additional_info}")
y = 530
for line in wrap(requestItem.icd10_code, 45):
myCanvas.drawString(225, h-y, f"{line}")
y+=15
myCanvas.line(50,h-y,w-50,h-y)
else:
myCanvas.setFont('Helvetica-Bold', 12)
myCanvas.drawString(50, h-500, f"Service Description:")
myCanvas.drawString(50, h-515, f"ICD-10 Code & Description:")
myCanvas.setFont('Helvetica', 12)
myCanvas.drawString(225, h-500, f"{requestItem.service_desc_option}")
y = 515
for line in wrap(requestItem.icd10_code, 45):
myCanvas.drawString(225, h-y, f"{line}")
y+=15
# myCanvas.drawString(225, h-515, f"{requestItem.icd10_code}")
myCanvas.line(50,h-y,w-50,h-y)
#===============================================================================
#Signature
y=750
myCanvas.drawImage(imageSig, 50, h-y,100,100)
myCanvas.line(50,h-y-10,200,h-y-10)
myCanvas.drawString(50, h-y-30, requestItem.provider_name.upper())
#QR Verification
qrText = f"{requestItem.document_type} generated on {issueDate} by {requestItem.busName} for {requestItem.patient_full_name}.\nPowered by Mzansi Innovation Hub."
qrText = qrText.replace(" ","+")
url = f"https://api.qrserver.com/v1/create-qr-code/?data={qrText}&size=100x100"
response = requests.get(url)
image = ImageReader(io.BytesIO(response.content))
myCanvas.drawImage(image,w-150, h-y-10,100,100)
myCanvas.setFont('Helvetica-Bold', 15)
myCanvas.drawString(w-150,h-y-30,"Scan to verify")
myCanvas.save()

View File

@@ -0,0 +1,48 @@
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
import os
import xlrd
#SuperToken Auth from front end
from supertokens_python.recipe.session.framework.fastapi import verify_session
from supertokens_python.recipe.session import SessionContainer
from fastapi import Depends
router = APIRouter()
#get all medicines
@router.get("/icd10-codes/all", tags=["ICD10 Code"])
async def read_all_icd10_codes(session: SessionContainer = Depends(verify_session())):
return getICD10CodesData("")
#get all medicines by search
@router.get("/icd10-codes/{search}", tags=["ICD10 Code"])
async def read_icd10_codes_search(search: str, session: SessionContainer = Depends(verify_session())): #, session: SessionContainer = Depends(verify_session())
return getICD10CodesData(search)
def getICD10CodesData(search: str):
path = os.getcwd()
#print(path)
#parentDir = os.path.abspath(os.path.join(path, os.pardir))
filePath = os.path.join(path, "ICD10_Codes", "ICD-10_MIT_2021_Excel_16-March_2021.xls")
print(f'========================= %s ===============================',filePath)
book = xlrd.open_workbook_xls(filePath)
sh = book.sheet_by_index(0)
codeList = []
for rx in range(1,sh.nrows):
if(str(sh.cell_value(rx, 7)).strip() != ""
and search.lower() in str(sh.cell_value(rx, 7)).strip().lower()
or search.lower() in str(sh.cell_value(rx, 8)).strip().lower()):
codeList.append({
"icd10": str(sh.cell_value(rx, 7)).strip(),
"description": str(sh.cell_value(rx, 8)).strip(),
})
seen = set()
codeList_noDuplicates = []
for d in codeList:
t = tuple(d.items())
#print(t[0][1])
if t not in seen:
seen.add(t)
codeList_noDuplicates.append(d)
return sorted(codeList_noDuplicates, key=lambda d: d['icd10']) #qsort(medlist)