From 427afe52958bcc54e0e4f8fea9be7b7cb63d35a9 Mon Sep 17 00:00:00 2001
From: av-dev2
Date: Tue, 9 Jan 2024 19:22:58 +0300
Subject: [PATCH 1/8] feat: show admission ward on inpatient reecord, show
admission ward on patient encounter and add button to view last/current
patient encounter from inpatient record
---
.../patient_encounter_list.js | 11 ++++++-
hms_tz/hooks.py | 1 +
hms_tz/nhif/api/inpatient_record.js | 27 +++++++++++++++-
hms_tz/nhif/api/inpatient_record.py | 29 ++++++++++++++++-
hms_tz/nhif/api/patient_encounter.js | 31 ++++++++++++-------
hms_tz/nhif/api/patient_encounter.py | 13 ++++++++
hms_tz/patches.txt | 1 +
...dmission_service_unit_type_custom_field.py | 20 ++++++++++++
8 files changed, 118 insertions(+), 15 deletions(-)
create mode 100644 hms_tz/patches/custom_fields/add_admission_service_unit_type_custom_field.py
diff --git a/hms_tz/hms_tz/doctype/patient_encounter/patient_encounter_list.js b/hms_tz/hms_tz/doctype/patient_encounter/patient_encounter_list.js
index 38620ff8..e72975a7 100644
--- a/hms_tz/hms_tz/doctype/patient_encounter/patient_encounter_list.js
+++ b/hms_tz/hms_tz/doctype/patient_encounter/patient_encounter_list.js
@@ -2,5 +2,14 @@
(c) ESS 2015-16
*/
frappe.listview_settings['Patient Encounter'] = {
- filters: [["docstatus", "!=", "2"], ["duplicated", "==", "0"]]
+ filters: [["docstatus", "!=", "2"], ["duplicated", "==", "0"]],
+ onload: function (listview) {
+ listview.page.fields_dict['admission_service_unit_type'].get_query = function () {
+ return {
+ filters: {
+ inpatient_occupancy: 1
+ }
+ };
+ };
+ }
};
diff --git a/hms_tz/hooks.py b/hms_tz/hooks.py
index d9bcb4dd..7cea7b68 100644
--- a/hms_tz/hooks.py
+++ b/hms_tz/hooks.py
@@ -194,6 +194,7 @@
},
"Inpatient Record": {
"validate": "hms_tz.nhif.api.inpatient_record.validate",
+ "before_save": "hms_tz.nhif.api.inpatient_record.before_save",
"after_insert": "hms_tz.nhif.api.inpatient_record.after_insert",
},
"Prescription Dosage": {
diff --git a/hms_tz/nhif/api/inpatient_record.js b/hms_tz/nhif/api/inpatient_record.js
index 8dafb720..db9e6633 100644
--- a/hms_tz/nhif/api/inpatient_record.js
+++ b/hms_tz/nhif/api/inpatient_record.js
@@ -24,6 +24,7 @@ frappe.ui.form.on('Inpatient Record', {
make_deposit(frm);
}).addClass("font-weight-bold");
}
+ view_current_encounter(frm);
},
onload(frm) {
frm.get_field("inpatient_occupancies").grid.cannot_add_rows = true;
@@ -197,7 +198,7 @@ var isConfirmed = (frm, fieldname) => {
}
var validate_inpatient_balance_vs_inpatient_cost = (frm) => {
- if (!frm.doc.insurance_subscription){
+ if (!frm.doc.insurance_subscription) {
frappe.call({
method: 'hms_tz.nhif.api.inpatient_record.validate_inpatient_balance_vs_inpatient_cost',
args: {
@@ -213,4 +214,28 @@ var validate_inpatient_balance_vs_inpatient_cost = (frm) => {
}
});
}
+}
+
+var view_current_encounter = (frm) => {
+ if (!frm.page.fields_dict.view__encounter) {
+ frm.page.add_field({
+ label: __("View Encounter"),
+ fieldname: "view__encounter",
+ fieldtype: "Button",
+ click: function () {
+ frappe.call({
+ method: 'hms_tz.nhif.api.inpatient_record.get_last_encounter',
+ args: {
+ patient: frm.doc.patient,
+ inpatient_record: frm.doc.name,
+ },
+ callback: function (r) {
+ if (r.message) {
+ frappe.set_route('Form', 'Patient Encounter', r.message);
+ }
+ }
+ });
+ }
+ }).$input.addClass("btn-sm font-weight-bold");
+ }
}
\ No newline at end of file
diff --git a/hms_tz/nhif/api/inpatient_record.py b/hms_tz/nhif/api/inpatient_record.py
index 2da3c32c..e21820cb 100644
--- a/hms_tz/nhif/api/inpatient_record.py
+++ b/hms_tz/nhif/api/inpatient_record.py
@@ -27,7 +27,19 @@
def validate(doc, method):
set_beds_price(doc)
validate_inpatient_occupancies(doc)
- validate_inpatient_balance_vs_inpatient_cost(doc.patient, doc.patient_appointment, doc.name)
+ validate_inpatient_balance_vs_inpatient_cost(
+ doc.patient, doc.patient_appointment, doc.name
+ )
+
+
+def before_save(doc, method):
+ last_row = doc.inpatient_occupancies[len(doc.inpatient_occupancies) - 1]
+ if last_row.service_unit:
+ service_unit_type = frappe.get_cached_value(
+ "Healthcare Service Unit", last_row.service_unit, "service_unit_type"
+ )
+ if doc.admission_service_unit_type != service_unit_type:
+ doc.admission_service_unit_type = service_unit_type
def validate_inpatient_occupancies(doc):
@@ -370,3 +382,18 @@ def validate_inpatient_balance_vs_inpatient_cost(
encounter_doc, encounters=patient_encounters
)
return True
+
+
+@frappe.whitelist()
+def get_last_encounter(patient, inpatient_record):
+ pe = frappe.qb.DocType("Patient Encounter")
+ encounters = (
+ frappe.qb.from_(pe)
+ .select(pe.name)
+ .where(
+ (pe.patient == patient)
+ & (pe.inpatient_record == inpatient_record)
+ & (pe.duplicated == 0)
+ )
+ ).run(as_dict=True)
+ return encounters[0].name if len(encounters) > 0 else None
diff --git a/hms_tz/nhif/api/patient_encounter.js b/hms_tz/nhif/api/patient_encounter.js
index b461de73..06380f3b 100755
--- a/hms_tz/nhif/api/patient_encounter.js
+++ b/hms_tz/nhif/api/patient_encounter.js
@@ -10,7 +10,7 @@ frappe.ui.form.on('Patient Encounter', {
// validate: function (frm) {
// validate_medical_code(frm);
// },
-
+
onload: function (frm) {
control_practitioners_to_submit_others_encounters(frm);
add_btn_final(frm);
@@ -69,7 +69,7 @@ frappe.ui.form.on('Patient Encounter', {
}
};
});
-
+
// filter medication based on company
filter_drug_prescriptions(frm);
@@ -106,7 +106,14 @@ frappe.ui.form.on('Patient Encounter', {
validate_healthcare_package_order_items(frm);
set_btn_properties(frm);
// set_delete_button_in_child_table(frm);
-
+ frm.set_query('admission_service_unit_type', function () {
+ return {
+ filters: {
+ inpatieint_occupancy: 1
+ }
+ };
+ });
+
},
clear_history: function (frm) {
@@ -251,7 +258,7 @@ frappe.ui.form.on('Patient Encounter', {
},
add_chronic_medications: (frm) => {
if (frm.doc.docstatus == 0) {
- let items = frm.get_field('drug_prescription').grid.get_selected_children();
+ let items = frm.get_field('drug_prescription').grid.get_selected_children();
frappe.call('hms_tz.nhif.api.patient_encounter.add_chronic_medications', {
patient: frm.doc.patient,
encounter: frm.doc.name,
@@ -598,7 +605,7 @@ function validate_medical_code(frm) {
"drug_prescription": "drug_code",
"therapies": "therapy_type",
};
-
+
for (const [from_table, fields] of Object.entries(medical_code_mapping)) {
const options = get_diagnosis_list(frm, from_table);
@@ -926,12 +933,12 @@ frappe.ui.form.on('Therapy Plan Detail', {
let row = frappe.get_doc(cdt, cdn);
if (row.override_subscription) {
frappe.model.set_value(cdt, cdn, "prescribe", 0);
- }
+ }
},
});
-const validate_stock_item = function (frm, healthcare_service, prescribe=0, qty = 1, healthcare_service_unit = "", caller = "Unknown") {
+const validate_stock_item = function (frm, healthcare_service, prescribe = 0, qty = 1, healthcare_service_unit = "", caller = "Unknown") {
if (healthcare_service_unit == "") {
healthcare_service_unit = frm.doc.healthcare_service_unit;
}
@@ -1088,7 +1095,7 @@ var reuse_lrpmt_items = (frm, doctype, fields, value_dict, item_category, caller
description: $(this).find("#description").attr("data-description"),
mtuha: $(this).find("#mtuha").attr("data-mtuha"),
});
- } else if (caller == "Medication") {
+ } else if (caller == "Medication") {
items.push({
item: $(this).find("#item").attr("data-item"),
item_name: $(this).find("#item_name").attr("data-item_name"),
@@ -1120,7 +1127,7 @@ var reuse_lrpmt_items = (frm, doctype, fields, value_dict, item_category, caller
} else {
if (doctype == "Drug Prescription") {
items.forEach((item) => {
- if (item.medical_code) {
+ if (item.medical_code) {
let diagnosis_codes = frm.doc.patient_encounter_final_diagnosis.map(d => d.medical_code);
let medical_code = item.medical_code.split("\n");
if (!diagnosis_codes.includes(medical_code[0])) {
@@ -1171,7 +1178,7 @@ var reuse_lrpmt_items = (frm, doctype, fields, value_dict, item_category, caller
});
d.$body.find("button[data-fieldtype='Button']").removeClass("btn-default").addClass("btn-info");
- d.$body.on('change', '#th', function() {
+ d.$body.on('change', '#th', function () {
var isChecked = $(this).prop('checked');
wrapper.find('input[type="checkbox"]').prop('checked', isChecked);
});
@@ -1192,7 +1199,7 @@ var reuse_lrpmt_items = (frm, doctype, fields, value_dict, item_category, caller
caller: caller
},
freeze: true,
- freeze_message: __(''),
+ freeze_message: __(''),
}).then(r => {
let records = r.message;
if (records.length > 0) {
@@ -1374,7 +1381,7 @@ var control_practitioners_to_submit_others_encounters = (frm) => {
}
});
}
- };
+};
var validate_medication_class = (frm, drug_item) => {
frappe.call({
diff --git a/hms_tz/nhif/api/patient_encounter.py b/hms_tz/nhif/api/patient_encounter.py
index 2e4523b1..e2869703 100644
--- a/hms_tz/nhif/api/patient_encounter.py
+++ b/hms_tz/nhif/api/patient_encounter.py
@@ -62,6 +62,7 @@ def before_insert(doc, method):
validate_nhif_patient_claim_status(
"Patient Encounter", doc.company, doc.appointment, doc.insurance_company
)
+ set_admission_service_type(doc)
# regency rock: 95
@@ -1439,6 +1440,7 @@ def before_submit(doc, method):
if doc.inpatient_record:
validate_patient_balance_vs_patient_costs(doc)
+ set_admission_service_type(doc)
encounter_create_sales_invoice = frappe.get_cached_value(
"Encounter Category", doc.encounter_category, "create_sales_invoice"
@@ -2510,3 +2512,14 @@ def get_filtered_dosage(doctype, txt, searchfield, start, page_len, filters):
fields=[searchfield],
as_list=1,
)
+
+
+def set_admission_service_type(doc):
+ """Set admission service type based on service unit type of inpatient record"""
+
+ if doc.inpatient_record:
+ admission_service_unit_type = frappe.get_value(
+ "Inpatient Record", doc.inpatient_record, "admission_service_unit_type"
+ )
+ if admission_service_unit_type and doc.admission_service_unit_type != admission_service_unit_type:
+ doc.admission_service_unit_type = admission_service_unit_type
diff --git a/hms_tz/patches.txt b/hms_tz/patches.txt
index b5d9fdd7..d16bc54e 100644
--- a/hms_tz/patches.txt
+++ b/hms_tz/patches.txt
@@ -54,3 +54,4 @@ hms_tz.patches.custom_fields.additional_custom_fields_for_hms_tz
hms_tz.patches.custom_fields.has_restricted_qty_for_dosage_form_and_prescription_dosage
hms_tz.patches.custom_fields.stop_change_of_lrpmt_items_after_claim_submission
hms_tz.patches.property_setter.set_only_once_appointment_property
+hms_tz.patches.custom_fields.add_admission_service_unit_type_custom_field
\ No newline at end of file
diff --git a/hms_tz/patches/custom_fields/add_admission_service_unit_type_custom_field.py b/hms_tz/patches/custom_fields/add_admission_service_unit_type_custom_field.py
new file mode 100644
index 00000000..fd2334cb
--- /dev/null
+++ b/hms_tz/patches/custom_fields/add_admission_service_unit_type_custom_field.py
@@ -0,0 +1,20 @@
+import frappe
+from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
+
+def execute():
+ fields = {
+ "Patient Encounter": [
+ {
+ "fieldname": "admission_service_unit_type",
+ "label": "Admission Service Unit Type",
+ "fieldtype": "Link",
+ "options": "Healthcare Service Unit Type",
+ "insert_after": "inpatient_status",
+ "read_only": 1,
+ "in_standard_filter": 1,
+ },
+ ]
+ }
+
+ create_custom_fields(fields, update=True)
From bcab2ea5d7d9ef0bed6cadd0b75e1d0889cba01b Mon Sep 17 00:00:00 2001
From: av-dev2
Date: Thu, 11 Jan 2024 15:48:52 +0300
Subject: [PATCH 2/8] feat: block admission of patient of the same
authorization number whose NHIF Patient Claim is already submitted
---
hms_tz/hooks.py | 1 +
hms_tz/nhif/api/healthcare_utils.py | 1 +
hms_tz/nhif/api/inpatient_record.py | 61 ++++++++++++++++++-
.../nhif_tracking_claim_change.py | 1 +
4 files changed, 61 insertions(+), 3 deletions(-)
diff --git a/hms_tz/hooks.py b/hms_tz/hooks.py
index d9bcb4dd..242960b3 100644
--- a/hms_tz/hooks.py
+++ b/hms_tz/hooks.py
@@ -194,6 +194,7 @@
},
"Inpatient Record": {
"validate": "hms_tz.nhif.api.inpatient_record.validate",
+ "before_insert": "hms_tz.nhif.api.inpatient_record.before_insert",
"after_insert": "hms_tz.nhif.api.inpatient_record.after_insert",
},
"Prescription Dosage": {
diff --git a/hms_tz/nhif/api/healthcare_utils.py b/hms_tz/nhif/api/healthcare_utils.py
index f2e04ba5..4ecf939d 100644
--- a/hms_tz/nhif/api/healthcare_utils.py
+++ b/hms_tz/nhif/api/healthcare_utils.py
@@ -1498,6 +1498,7 @@ def validate_nhif_patient_claim_status(
if caller:
frappe.msgprint(msg)
+ return True
else:
frappe.throw(
msg,
diff --git a/hms_tz/nhif/api/inpatient_record.py b/hms_tz/nhif/api/inpatient_record.py
index 2da3c32c..5b4c56be 100644
--- a/hms_tz/nhif/api/inpatient_record.py
+++ b/hms_tz/nhif/api/inpatient_record.py
@@ -24,10 +24,17 @@
import json
+def before_insert(doc, method):
+ validate_similary_authozation_number(doc)
+
+
def validate(doc, method):
set_beds_price(doc)
validate_inpatient_occupancies(doc)
- validate_inpatient_balance_vs_inpatient_cost(doc.patient, doc.patient_appointment, doc.name)
+ if not doc.insurance_subscription:
+ validate_inpatient_balance_vs_inpatient_cost(
+ doc.patient, doc.patient_appointment, doc.name
+ )
def validate_inpatient_occupancies(doc):
@@ -85,14 +92,13 @@ def daily_update_inpatient_occupancies():
@frappe.whitelist()
def confirmed(company, appointment, insurance_company=None):
if insurance_company and "NHIF" in insurance_company:
- validate_nhif_patient_claim_status(
+ return validate_nhif_patient_claim_status(
"Inpatient Record",
company,
appointment,
insurance_company,
"inpatient_record",
)
- return True
def create_delivery_note(encounter, item_code, item_rate, warehouse, row, practitioner):
@@ -370,3 +376,52 @@ def validate_inpatient_balance_vs_inpatient_cost(
encounter_doc, encounters=patient_encounters
)
return True
+
+
+def validate_similary_authozation_number(doc):
+ """Validate if NHIF Patient Claim for this AuthorizationNo is already submitted."""
+
+ if not doc.insurance_subscription:
+ return
+
+ insurance_company = doc.insurance_company
+
+ if not insurance_company:
+ insurance_company = frappe.get_value(
+ "Healthcare Insurance Subscription",
+ doc.insurance_subscription,
+ "insurance_company",
+ )
+
+ if insurance_company and "NHIF" in insurance_company:
+ auth_no = frappe.get_value(
+ "Patient Appointment", doc.patient_appointment, "authorization_number"
+ )
+ claims = frappe.get_all(
+ "NHIF Patient Claim",
+ filters={"patient": doc.patient, "authorization_no": auth_no},
+ fields=["name", "docstatus"],
+ )
+ if len(claims) > 0:
+ is_submitted = False
+ submitted_claim = None
+ for row in claims:
+ if row.docstatus == 1:
+ is_submitted = True
+ submitted_claim = row.name
+ break
+
+ if is_submitted:
+ claim_url = get_url_to_form("NHIF Patient Claim", submitted_claim)
+ app_url = get_url_to_form(
+ "Patient Appointment", doc.patient_appointment
+ )
+ msg = f"""
+ NHIF Patient Claim:
{submitted_claim} for this AuthorizationNo:
{auth_no} and Appointment:
{doc.patient_appointment} is already submitted.
+
Please do not Admit this patient, Let patient ask for a new AuthorizationNo from NHIF.
+
"""
+ frappe.throw(
+ title=f"NHIF Patient Claim: {submitted_claim} Already Submitted",
+ msg=msg,
+ exc=frappe.ValidationError,
+ )
diff --git a/hms_tz/nhif/doctype/nhif_tracking_claim_change/nhif_tracking_claim_change.py b/hms_tz/nhif/doctype/nhif_tracking_claim_change/nhif_tracking_claim_change.py
index 0f3ec660..5980be96 100644
--- a/hms_tz/nhif/doctype/nhif_tracking_claim_change/nhif_tracking_claim_change.py
+++ b/hms_tz/nhif/doctype/nhif_tracking_claim_change/nhif_tracking_claim_change.py
@@ -346,6 +346,7 @@ def reconcile_original_nhif_patient_claim_items(claim_doc):
for record in repeated_items:
if record.docstatus == 1:
+ record.flags.ignore_permissions = True
record.cancel()
record.delete(ignore_permissions=True, force=True, delete_permanently=True)
From 4c04720f5b0c3bffc283ecdc88507efdfc1b4f1a Mon Sep 17 00:00:00 2001
From: av-dev2
Date: Wed, 24 Jan 2024 17:30:28 +0300
Subject: [PATCH 3/8] fix: setting follow up for cash appointment with
consideration of previous insurance appointment date
---
hms_tz/nhif/api/patient_appointment.js | 3 ++-
hms_tz/nhif/api/patient_appointment.py | 13 +++++++++++--
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/hms_tz/nhif/api/patient_appointment.js b/hms_tz/nhif/api/patient_appointment.js
index e3fdf94e..3d7d1b35 100644
--- a/hms_tz/nhif/api/patient_appointment.js
+++ b/hms_tz/nhif/api/patient_appointment.js
@@ -822,12 +822,13 @@ const add_btns = (frm) => {
}
if (frm.doc.insurance_subscription) {
filters.insurance_subscription = frm.doc.insurance_subscription;
+ } else {
+ filters.mode_of_payment = ["!=", ""]
}
const appointment = get_previous_appointment(frm, filters);
if (typeof appointment != "undefined") {
const last_appointment_date = appointment.appointment_date;
const diff = frappe.datetime.get_day_diff(frm.doc.appointment_date, last_appointment_date);
- console.log(diff)
if (diff >= 0 && diff <= valid_days) {
vitals_btn_required = true;
if (!frm.doc.invoiced) {
diff --git a/hms_tz/nhif/api/patient_appointment.py b/hms_tz/nhif/api/patient_appointment.py
index ee47e7c6..2c9b5b3c 100644
--- a/hms_tz/nhif/api/patient_appointment.py
+++ b/hms_tz/nhif/api/patient_appointment.py
@@ -442,7 +442,9 @@ def update_insurance_subscription(insurance_subscription, card, company):
if coverage_plan:
card["CoveragePlanName"] = coverage_plan
- plan_doc = frappe.get_cached_doc("Healthcare Insurance Coverage Plan", coverage_plan)
+ plan_doc = frappe.get_cached_doc(
+ "Healthcare Insurance Coverage Plan", coverage_plan
+ )
if plan_doc:
subscription_doc.insurance_company = plan_doc.insurance_company
@@ -451,7 +453,7 @@ def update_insurance_subscription(insurance_subscription, card, company):
subscription_doc.hms_tz_product_code = card["ProductCode"]
subscription_doc.hms_tz_product_name = card["ProductName"]
-
+
subscription_doc.hms_tz_scheme_id = card["SchemeID"]
subscription_doc.hms_tz_scheme_name = card["SchemeName"]
@@ -504,6 +506,8 @@ def set_follow_up(appointment_doc, method):
}
if appointment_doc.insurance_subscription:
filters["insurance_subscription"] = appointment_doc.insurance_subscription
+ else:
+ filters["mode_of_payment"] = ["!=", ""]
appointment = get_previous_appointment(appointment_doc.patient, filters)
if appointment and appointment_doc.appointment_date:
@@ -626,6 +630,11 @@ def make_next_doc(doc, method, from_hook=True):
# do not create vital sign or encounter if appointment is already cancelled
if doc.status == "Cancelled":
return
+
+ # do not create vital sign or encounter if appointment is already invoiced
+ if doc.mode_of_payment and not doc.invoiced:
+ return
+
if frappe.get_cached_value(
"Healthcare Practitioner", doc.practitioner, "bypass_vitals"
):
From 0d8253ed40c7a120fc38fb9810b809775d1d6c7f Mon Sep 17 00:00:00 2001
From: av-dev2
Date: Sat, 27 Jan 2024 13:20:26 +0300
Subject: [PATCH 4/8] perf: optimize finalize patient encounter
---
hms_tz/nhif/api/patient_encounter.py | 25 ++++++++++---------
.../nhif_patient_claim/nhif_patient_claim.py | 2 +-
2 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/hms_tz/nhif/api/patient_encounter.py b/hms_tz/nhif/api/patient_encounter.py
index 2e4523b1..7fab724d 100644
--- a/hms_tz/nhif/api/patient_encounter.py
+++ b/hms_tz/nhif/api/patient_encounter.py
@@ -1257,30 +1257,31 @@ def unmark_limit_exceeded(doc):
@frappe.whitelist()
def finalized_encounter(cur_encounter, ref_encounter=None):
- cur_encounter_doc = frappe.get_doc("Patient Encounter", cur_encounter)
+ patient, cur_inpatient_record = frappe.get_value(
+ "Patient Encounter", cur_encounter, ["patient", "inpatient_record"]
+ )
inpatient_status, inpatient_record = frappe.get_cached_value(
- "Patient", cur_encounter_doc.patient, ["inpatient_status", "inpatient_record"]
+ "Patient", patient, ["inpatient_status", "inpatient_record"]
)
- if inpatient_status and cur_encounter_doc.inpatient_record == inpatient_record:
+ if inpatient_status and cur_inpatient_record == inpatient_record:
frappe.throw(
_(
- "The patient {0} has inpatient status {1}. Please process the discharge before proceeding to finalize the encounter.".format(
- cur_encounter_doc.patient, inpatient_status
- )
+ f"The patient {patient} has inpatient status {inpatient_status}.\
+ Please process the discharge before proceeding to finalize the encounter."
)
)
+ frappe.db.set_value("Patient Encounter", cur_encounter, "encounter_type", "Final")
+ if not ref_encounter:
+ frappe.db.set_value("Patient Encounter", cur_encounter, "finalized", 1)
+ return
+
encounters_list = frappe.get_all(
"Patient Encounter",
filters={"docstatus": 1, "reference_encounter": ref_encounter},
)
for element in encounters_list:
- frappe.set_value("Patient Encounter", element.name, "finalized", 1)
-
- frappe.set_value("Patient Encounter", cur_encounter, "encounter_type", "Final")
- if not ref_encounter:
- frappe.set_value("Patient Encounter", cur_encounter, "finalized", 1)
- return
+ frappe.db.set_value("Patient Encounter", element.name, "finalized", 1)
@frappe.whitelist()
diff --git a/hms_tz/nhif/doctype/nhif_patient_claim/nhif_patient_claim.py b/hms_tz/nhif/doctype/nhif_patient_claim/nhif_patient_claim.py
index 502d733b..224bd2da 100644
--- a/hms_tz/nhif/doctype/nhif_patient_claim/nhif_patient_claim.py
+++ b/hms_tz/nhif/doctype/nhif_patient_claim/nhif_patient_claim.py
@@ -1071,7 +1071,7 @@ def validate_hold_card_status(
frappe.msgprint("Release Patient Card")
else:
msg += f"
with same authorization no: {self.authorization_no}
\
- Please Hold patient card until claims for all {appointment_documents} appointments to be created.
"
+ Please Hold patient card until claims for all {len(appointment_documents)} appointments to be created."
frappe.msgprint("Please Hold Card", 20, alert=True)
frappe.msgprint(str(msg))
From 233ed27f663c8686f2e48810394d611fb6bef103 Mon Sep 17 00:00:00 2001
From: av-dev2
Date: Mon, 29 Jan 2024 09:54:00 +0300
Subject: [PATCH 5/8] chore: enhance validation of patient deposit/balance vs
patient costs on patient encounter and inpatient record
---
.../ipd_billing_report/ipd_billing_report.js | 178 ++++++++-------
hms_tz/nhif/api/inpatient_record.js | 57 ++++-
hms_tz/nhif/api/inpatient_record.py | 43 ++--
hms_tz/nhif/api/patient_encounter.py | 214 +++++++++++-------
4 files changed, 302 insertions(+), 190 deletions(-)
diff --git a/hms_tz/hms_tz/report/ipd_billing_report/ipd_billing_report.js b/hms_tz/hms_tz/report/ipd_billing_report/ipd_billing_report.js
index d497adc8..83dff652 100644
--- a/hms_tz/hms_tz/report/ipd_billing_report/ipd_billing_report.js
+++ b/hms_tz/hms_tz/report/ipd_billing_report/ipd_billing_report.js
@@ -3,83 +3,89 @@
/* eslint-disable */
frappe.query_reports["IPD Billing Report"] = {
- onload: (report) => {
- report.page.add_inner_button(__("Make Deposit"), () => {
- let filters = report.get_values();
- make_deposit(filters.inpatient_record);
- }).addClass("font-weight-bold");
- },
+ onload: (report) => {
+ report.page.add_inner_button(__("Make Deposit"), () => {
+ let filters = report.get_values();
+ make_deposit(filters.inpatient_record);
+ }).addClass("font-weight-bold");
- "filters": [
- {
- "fieldname": "inpatient_record",
- "fieldtype": "Link",
- "label": __("Inpatient Record"),
- "options": "Inpatient Record",
- "reqd": 1
- },
- {
- "fieldname": "patient",
- "fieldtype": "Link",
- "label": __("Patient"),
- "options": "Patient",
- "reqd": 1
- },
- {
- "fieldname": "appointment_no",
- "fieldtype": "Data",
- "label": __("AppointmentNo"),
- "reqd": 1
- },
- {
- "fieldname": "company",
- "fieldtype": "Link",
- "label": __("Company"),
- "options": "Company",
- "reqd": 1
- },
- {
- fieldname: 'patient_type',
- label: __('Patient Type'),
- fieldtype: 'Select',
- // options: ["", 'Out-Patient', 'In-Patient'],
- options: ['In-Patient'],
- default: 'In-Patient',
- reqd: 1,
- },
- {
- fieldname: "from_date",
- label: __("From Date"),
- fieldtype: "Date",
- reqd: 0,
- },
- {
- fieldname: "to_date",
- label: __("To Date"),
- fieldtype: "Date",
- reqd: 0,
- },
- {
- "fieldname": "summarized_view",
- "fieldtype": "Check",
- "label": __("Summarized View")
- },
- ],
- 'formatter': (value, row, column, data, default_formatter) => {
- value = default_formatter(value, row, column, data);
- if (column.fieldtype == 'Currency' && data[column.fieldname] > 0) {
- value = `${value}`;
- }
- if (column.fieldtype == 'Currency' && data[column.fieldname] == 0) {
- value = `${value}`;
- }
- if (data && row[1].content == 'Total') {
- value = $(`${value}`);
- var $value = $(value).css("font-weight", "bold");
- value = $value.wrap("").parent().html();
- }
- return value
- }
+ report.page.add_inner_button(__("Create Invoice"), () => {
+ let args = report.get_values();
+ create_sales_invoice(args);
+
+ }).addClass("font-weight-bold");
+ },
+
+ "filters": [
+ {
+ "fieldname": "inpatient_record",
+ "fieldtype": "Link",
+ "label": __("Inpatient Record"),
+ "options": "Inpatient Record",
+ "reqd": 1
+ },
+ {
+ "fieldname": "patient",
+ "fieldtype": "Link",
+ "label": __("Patient"),
+ "options": "Patient",
+ "reqd": 1
+ },
+ {
+ "fieldname": "appointment_no",
+ "fieldtype": "Data",
+ "label": __("AppointmentNo"),
+ "reqd": 1
+ },
+ {
+ "fieldname": "company",
+ "fieldtype": "Link",
+ "label": __("Company"),
+ "options": "Company",
+ "reqd": 1
+ },
+ {
+ fieldname: 'patient_type',
+ label: __('Patient Type'),
+ fieldtype: 'Select',
+ // options: ["", 'Out-Patient', 'In-Patient'],
+ options: ['In-Patient'],
+ default: 'In-Patient',
+ reqd: 1,
+ },
+ {
+ fieldname: "from_date",
+ label: __("From Date"),
+ fieldtype: "Date",
+ reqd: 0,
+ },
+ {
+ fieldname: "to_date",
+ label: __("To Date"),
+ fieldtype: "Date",
+ reqd: 0,
+ },
+ {
+ "fieldname": "summarized_view",
+ "fieldtype": "Check",
+ "label": __("Summarized View")
+ },
+ ],
+ 'formatter': (value, row, column, data, default_formatter) => {
+ value = default_formatter(value, row, column, data);
+ if (column.fieldtype == 'Currency' && data[column.fieldname] > 0) {
+ value = `${value}`;
+ }
+ if (column.fieldtype == 'Currency' && data[column.fieldname] == 0) {
+ value = `${value}`;
+ }
+ if (data && row[1].content == 'Total') {
+ value = $(`${value}`);
+ var $value = $(value).css("font-weight", "bold");
+ value = $value.wrap("").parent().html();
+ }
+ return value
+ }
};
var make_deposit = (inpatient_record) => {
@@ -166,4 +172,24 @@ var make_deposit = (inpatient_record) => {
});
d.show();
+}
+
+var create_sales_invoice = (args) => {
+ frappe.call({
+ method: "hms_tz.nhif.api.inpatient_record.create_sales_invoice",
+ args: {
+ args: {
+ "patient": args.patient,
+ "appointment_no": args.appointment_no,
+ "inpatient_record": args.inpatient_record,
+ "company": args.company,
+ }
+ },
+ freeze: true,
+ freeze_message: __(''),
+ }).then((r) => {
+ if (r.message) {
+ frappe.set_route("Form", "Sales Invoice", r.message);
+ }
+ });
}
\ No newline at end of file
diff --git a/hms_tz/nhif/api/inpatient_record.js b/hms_tz/nhif/api/inpatient_record.js
index db9e6633..900b75c0 100644
--- a/hms_tz/nhif/api/inpatient_record.js
+++ b/hms_tz/nhif/api/inpatient_record.js
@@ -19,7 +19,8 @@ frappe.ui.form.on('Inpatient Record', {
if (!frm.doc.insurance_subscription) {
frm.add_custom_button(__("Create Invoice"), () => {
create_sales_invoice(frm);
- });
+ }).addClass("font-weight-bold");
+
frm.add_custom_button(__("Make Deposit"), () => {
make_deposit(frm);
}).addClass("font-weight-bold");
@@ -29,7 +30,12 @@ frappe.ui.form.on('Inpatient Record', {
onload(frm) {
frm.get_field("inpatient_occupancies").grid.cannot_add_rows = true;
frm.get_field("inpatient_consultancy").grid.cannot_add_rows = true;
- }
+ },
+ validate: (frm) => {
+ if (!frm.doc.insurance_subscription) {
+ validate_inpatient_balance_vs_inpatient_cost(frm)
+ }
+ },
});
frappe.ui.form.on('Inpatient Occupancy', {
@@ -45,8 +51,11 @@ frappe.ui.form.on('Inpatient Occupancy', {
control_inpatient_record_move(frm, cdt, cdn);
},
is_confirmed: (frm, cdt, cdn) => {
- isConfirmed(frm, "inpatient_occupancies");
- validate_inpatient_balance_vs_inpatient_cost(frm);
+ let row = locals[cdt][cdn];
+ if (row.is_confirmed == 1) {
+ isConfirmed(frm, "inpatient_occupancies");
+ validate_inpatient_balance_vs_inpatient_cost(frm, row, "inpatient_occupancies", "Inpatient Record");
+ }
},
});
@@ -68,8 +77,11 @@ frappe.ui.form.on('Inpatient Consultancy', {
},
is_confirmed: (frm, cdt, cdn) => {
- isConfirmed(frm, "inpatient_consultancy");
- validate_inpatient_balance_vs_inpatient_cost(frm);
+ let row = locals[cdt][cdn];
+ if (row.is_confirmed == 1) {
+ isConfirmed(frm, "inpatient_consultancy");
+ validate_inpatient_balance_vs_inpatient_cost(frm, row, "inpatient_consultancy", "Inpatient Record");
+ }
},
});
@@ -197,18 +209,43 @@ var isConfirmed = (frm, fieldname) => {
});
}
-var validate_inpatient_balance_vs_inpatient_cost = (frm) => {
+var validate_inpatient_balance_vs_inpatient_cost = (frm, row = null, fieldname = "", caller = "") => {
if (!frm.doc.insurance_subscription) {
+ let total_cost = 0;
+ let occupancies = frm.doc.inpatient_occupancies;
+ for (let i in occupancies) {
+ let row = occupancies[i];
+ if (row.is_confirmed == 1 && row.invoiced == 0) {
+ total_cost += row.amount
+ }
+ }
+ let consultancies = frm.doc.inpatient_consultancy;
+ for (let d in consultancies) {
+ let row = consultancies[d];
+ if (row.is_confirmed == 1 && row.hms_tz_invoiced == 0) {
+ total_cost += row.rate
+ }
+ }
frappe.call({
method: 'hms_tz.nhif.api.inpatient_record.validate_inpatient_balance_vs_inpatient_cost',
args: {
patient: frm.doc.patient,
+ patient_name: frm.doc.patient_name,
+ appointment: frm.doc.patient_appointment,
inpatient_record: frm.doc.name,
- patient_appointment: frm.doc.patient_appointment,
+ company: frm.doc.company,
+ inpatient_cost: total_cost,
+ cash_limit: frm.doc.cash_limit,
+ caller: caller
},
callback: function (r) {
- if (!r.message) {
- frm.refresh_field("inpatient_consultancies");
+ if (r.message) {
+ if (row) {
+ row.is_confirmed = 0
+ }
+ if (fieldname) {
+ frm.refresh_field(fieldname)
+ }
frm.reload_doc();
}
}
diff --git a/hms_tz/nhif/api/inpatient_record.py b/hms_tz/nhif/api/inpatient_record.py
index 94e4b9a9..3000321b 100644
--- a/hms_tz/nhif/api/inpatient_record.py
+++ b/hms_tz/nhif/api/inpatient_record.py
@@ -31,10 +31,6 @@ def before_insert(doc, method):
def validate(doc, method):
set_beds_price(doc)
validate_inpatient_occupancies(doc)
- if not doc.insurance_subscription:
- validate_inpatient_balance_vs_inpatient_cost(
- doc.patient, doc.patient_appointment, doc.name
- )
def before_save(doc, method):
@@ -365,32 +361,30 @@ def create_sales_invoice(args):
@frappe.whitelist()
def validate_inpatient_balance_vs_inpatient_cost(
- patient, patient_appointment, inpatient_record
+ patient,
+ patient_name,
+ appointment,
+ inpatient_record,
+ company,
+ inpatient_cost,
+ cash_limit,
+ caller=None,
):
- patient_encounters = frappe.get_all(
- "Patient Encounter",
- filters={
- "patient": patient,
- "appointment": patient_appointment,
- "inpatient_record": inpatient_record,
- },
- fields=["name"],
- order_by="encounter_date desc",
- pluck="name",
+ return validate_patient_balance_vs_patient_costs(
+ patient,
+ patient_name,
+ appointment,
+ inpatient_record,
+ company,
+ inpatient_cost=inpatient_cost,
+ cash_limit=cash_limit,
+ caller=caller,
)
- if not patient_encounters or len(patient_encounters) == 0:
- return
-
- encounter_doc = frappe.get_doc("Patient Encounter", patient_encounters[0])
- validate_patient_balance_vs_patient_costs(
- encounter_doc, encounters=patient_encounters
- )
- return True
def validate_similary_authozation_number(doc):
"""Validate if NHIF Patient Claim for this AuthorizationNo is already submitted."""
-
+
if not doc.insurance_subscription:
return
@@ -436,6 +430,7 @@ def validate_similary_authozation_number(doc):
exc=frappe.ValidationError,
)
+
@frappe.whitelist()
def get_last_encounter(patient, inpatient_record):
pe = frappe.qb.DocType("Patient Encounter")
diff --git a/hms_tz/nhif/api/patient_encounter.py b/hms_tz/nhif/api/patient_encounter.py
index 4463e303..80bd2d4d 100644
--- a/hms_tz/nhif/api/patient_encounter.py
+++ b/hms_tz/nhif/api/patient_encounter.py
@@ -14,6 +14,7 @@
cstr,
flt,
date_diff,
+ fmt_money,
)
from hms_tz.nhif.api.healthcare_utils import (
get_item_rate,
@@ -671,6 +672,14 @@ def on_submit(doc, method):
and doc.inpatient_record
and not doc.healthcare_package_order
): # Cash inpatient billing
+ if doc.mode_of_payment:
+ validate_patient_balance_vs_patient_costs(
+ doc.patient,
+ doc.patient_name,
+ doc.appointment,
+ doc.inpatient_record,
+ doc.company,
+ )
inpatient_billing(doc, method)
else: # insurance patient
on_submit_validation(doc, method)
@@ -1440,7 +1449,6 @@ def before_submit(doc, method):
set_practitioner_name(doc, method)
if doc.inpatient_record:
- validate_patient_balance_vs_patient_costs(doc)
set_admission_service_type(doc)
encounter_create_sales_invoice = frappe.get_cached_value(
@@ -1469,16 +1477,17 @@ def before_submit(doc, method):
@frappe.whitelist()
def undo_finalized_encounter(cur_encounter, ref_encounter=None):
+ frappe.set_value("Patient Encounter", cur_encounter, "encounter_type", "Ongoing")
+ if not ref_encounter:
+ frappe.set_value("Patient Encounter", cur_encounter, "finalized", 0)
+ return
+
encounters_list = frappe.get_all(
"Patient Encounter",
filters={"docstatus": 1, "reference_encounter": ref_encounter},
)
for element in encounters_list:
frappe.set_value("Patient Encounter", element.name, "finalized", 0)
- if not ref_encounter:
- frappe.set_value("Patient Encounter", cur_encounter, "finalized", 0)
- return
- frappe.set_value("Patient Encounter", cur_encounter, "encounter_type", "Ongoing")
def set_amounts(doc):
@@ -1735,88 +1744,117 @@ def update_drug_prescription(patient_encounter_doc, name):
)
-def validate_patient_balance_vs_patient_costs(doc, encounters=None):
- if not encounters or len(encounters) == 0:
- encounters = get_patient_encounters(doc)
+def validate_patient_balance_vs_patient_costs(
+ patient,
+ patient_name,
+ appointment,
+ inpatient_record,
+ company,
+ inpatient_cost=0,
+ cash_limit=0,
+ caller="",
+ encounters=[],
+):
+ def get_encounter_costs(encounters):
+ encounter_cost = 0
+ child_map = [
+ {"child_table": "lab_test_prescription"},
+ {"child_table": "radiology_procedure_prescription"},
+ {"child_table": "procedure_prescription"},
+ {"child_table": "drug_prescription"},
+ {"child_table": "therapies"},
+ ]
+ for enc in encounters:
+ encounter_doc = frappe.get_doc("Patient Encounter", enc)
- if not encounters or len(encounters) == 0:
- return
+ for row in child_map:
+ for child in encounter_doc.get(row.get("child_table")):
+ if (
+ child.prescribe == 0
+ or child.is_not_available_inhouse == 1
+ or child.invoiced == 1
+ or child.is_cancelled == 1
+ ):
+ continue
+
+ if child.doctype == "Drug Prescription":
+ encounter_cost += (
+ child.quantity - child.quantity_returned
+ ) * child.amount
+ else:
+ encounter_cost += child.amount
+ return encounter_cost
+
+ def get_inpatient_costs(inpatient_record):
+ inpatient_cost = 0
+ inpatient_record_doc = frappe.get_doc("Inpatient Record", inpatient_record)
+ cash_limit = inpatient_record_doc.cash_limit
+ for record in inpatient_record_doc.inpatient_occupancies:
+ if not record.is_confirmed:
+ continue
- total_amount_billed = 0
+ inpatient_cost += record.amount
- child_map = [
- {"child_table": "lab_test_prescription"},
- {"child_table": "radiology_procedure_prescription"},
- {"child_table": "procedure_prescription"},
- {"child_table": "drug_prescription"},
- {"child_table": "therapies"},
- ]
- for enc in encounters:
- encounter_doc = frappe.get_doc("Patient Encounter", enc)
+ for record in inpatient_record_doc.inpatient_consultancy:
+ if not record.is_confirmed:
+ continue
- for row in child_map:
- for child in encounter_doc.get(row.get("child_table")):
- if (
- child.prescribe == 0
- or child.is_not_available_inhouse == 1
- or child.invoiced == 1
- or child.is_cancelled == 1
- ):
- continue
+ inpatient_cost += record.rate
- if child.doctype == "Drug Prescription":
- total_amount_billed += (
- child.quantity - child.quantity_returned
- ) * child.amount
- else:
- total_amount_billed += child.amount
+ return inpatient_cost, cash_limit
- inpatient_record_doc = frappe.get_doc("Inpatient Record", doc.inpatient_record)
+ cash_limit_details = frappe.get_value(
+ "Company",
+ {"name": company, "hms_tz_has_cash_limit_alert": 1},
+ [
+ "hms_tz_minimum_cash_limit_percent",
+ "hms_tz_limit_exceed_action",
+ "hms_tz_limit_under_minimum_percent_action",
+ ],
+ as_dict=1,
+ )
+ if not cash_limit_details:
+ return
- cash_limit = inpatient_record_doc.cash_limit
+ total_amount_billed = 0
+ if not encounters or len(encounters) == 0:
+ encounters = get_patient_encounters(patient, appointment, inpatient_record)
- for record in inpatient_record_doc.inpatient_occupancies:
- if not record.is_confirmed:
- continue
+ if not encounters or len(encounters) == 0:
+ return
- total_amount_billed += record.amount
+ total_amount_billed += get_encounter_costs(encounters)
- for record in inpatient_record_doc.inpatient_consultancy:
- if not record.is_confirmed:
- continue
+ if inpatient_cost == 0 and cash_limit == 0:
+ inpatient_cost, cash_limit = get_inpatient_costs(inpatient_record)
- total_amount_billed += record.rate
+ total_amount_billed += flt(inpatient_cost)
# get balance from payment entry after patient has deposit advances
deposit_balance = get_balance_on(
- party_type="Customer", party=doc.patient_name, company=doc.company
+ party_type="Customer", party=patient_name, company=company
)
- patient_balance = (-1 * deposit_balance) + cash_limit
+ patient_balance = (-1 * deposit_balance) + flt(cash_limit)
+ cost_diff = fmt_money(total_amount_billed - patient_balance)
cash_limit_percent = 100 - ((total_amount_billed / patient_balance) * 100)
- cash_limit_details = frappe.get_value(
- "Company",
- {"name": doc.company, "hms_tz_has_cash_limit_alert": 1},
- [
- "hms_tz_minimum_cash_limit_percent",
- "hms_tz_limit_exceed_action",
- "hms_tz_limit_under_minimum_percent_action",
- ],
- as_dict=1,
- )
- make_cash_limit_alert(doc, cash_limit_percent, cash_limit_details)
+ return make_cash_limit_alert(
+ patient, patient_name, cash_limit_percent, cash_limit_details, cost_diff, caller
+ )
-def make_cash_limit_alert(doc, cash_limit_percent, cash_limit_details):
+def make_cash_limit_alert(
+ patient, patient_name, cash_limit_percent, cash_limit_details, cost_diff, caller
+):
if cash_limit_percent > 0 and cash_limit_percent <= cash_limit_details.get(
"hms_tz_minimum_cash_limit_percent"
):
msg_per = f"""
-
The patient: {doc.patient} - {doc.patient_name}\
+
The patient: {patient} - {patient_name}\
has reached {100 - flt(cash_limit_percent, 2)}% of his/her cash limit.
-
please request patient to deposit advances or request patient cash limit adjustment
+
please request patient to deposit advances or ask patient to request cash limit adjustment
"""
if (
@@ -1832,44 +1870,57 @@ def make_cash_limit_alert(doc, cash_limit_percent, cash_limit_details):
cash_limit_details.get("hms_tz_limit_under_minimum_percent_action")
== "Stop"
):
+ if caller == "Inpatient Record":
+ frappe.msgprint(
+ title="Cash Limit Exceeded",
+ msg=msg_per,
+ )
+ return True
+
frappe.throw(
title="Cash Limit Exceeded",
msg=msg_per,
)
- elif cash_limit_percent <= 0:
+ elif cash_limit_percent < 0:
msg = f"""
-
The deposit balance of this patient: {doc.patient} - {doc.patient_name}\
+
The deposit balance of this patient: {patient} - {patient_name}\
is not enough or Patient has reached the cash limit.
-
please request patient to deposit advances or request patient cash limit adjustment
+
please request patient to deposit advances or ask patient to request cash limit adjustment
"""
if cash_limit_details.get("hms_tz_limit_exceed_action") == "Warn":
frappe.msgprint(
- title="Cash Limit Exceeded",
+ title=f"Cash Limit Exceeded by: {cost_diff}",
msg=msg,
)
if cash_limit_details.get("hms_tz_limit_exceed_action") == "Stop":
+ if caller == "Inpatient Record":
+ frappe.msgprint(
+ title=f"Cash Limit Exceeded by: {cost_diff}",
+ msg=msg,
+ )
+ return True
+
frappe.throw(
- title="Cash Limit Exceeded",
+ title=f"Cash Limit Exceeded by: {cost_diff}",
msg=msg,
)
-def get_patient_encounters(doc):
- if doc.mode_of_payment != "" and doc.inpatient_record != "":
- patient_encounters = frappe.get_all(
- "Patient Encounter",
- filters={
- "patient": doc.patient,
- "appointment": doc.appointment,
- "inpatient_record": doc.inpatient_record,
- },
- fields=["name"],
- pluck="name",
- )
- return patient_encounters
+def get_patient_encounters(patient, appointment, inpatient_record):
+ patient_encounters = frappe.get_all(
+ "Patient Encounter",
+ filters={
+ "patient": patient,
+ "appointment": appointment,
+ "inpatient_record": inpatient_record,
+ },
+ fields=["name"],
+ pluck="name",
+ )
+ return patient_encounters
def show_last_prescribed_for_lrpt(doc, method):
@@ -2522,5 +2573,8 @@ def set_admission_service_type(doc):
admission_service_unit_type = frappe.get_value(
"Inpatient Record", doc.inpatient_record, "admission_service_unit_type"
)
- if admission_service_unit_type and doc.admission_service_unit_type != admission_service_unit_type:
+ if (
+ admission_service_unit_type
+ and doc.admission_service_unit_type != admission_service_unit_type
+ ):
doc.admission_service_unit_type = admission_service_unit_type
From 7ba9d7183ab7cb6a05f03c86ec15b958efe7a712 Mon Sep 17 00:00:00 2001
From: av-dev2
Date: Tue, 30 Jan 2024 18:16:00 +0300
Subject: [PATCH 6/8] feat: Withholding Tax functionality on visiting
consultancy report
---
.../visiting_consultant_charges_report.py | 592 +++++++++++-------
.../vc_lrpmt_submitter.json | 19 +-
.../nhif/doctype/vc_practitioner/__init__.py | 0
.../vc_practitioner/vc_practitioner.json | 40 ++
.../vc_practitioner/vc_practitioner.py | 8 +
.../visiting_comission.json | 43 +-
6 files changed, 464 insertions(+), 238 deletions(-)
create mode 100644 hms_tz/nhif/doctype/vc_practitioner/__init__.py
create mode 100644 hms_tz/nhif/doctype/vc_practitioner/vc_practitioner.json
create mode 100644 hms_tz/nhif/doctype/vc_practitioner/vc_practitioner.py
diff --git a/hms_tz/hms_tz/report/visiting_consultant_charges_report/visiting_consultant_charges_report.py b/hms_tz/hms_tz/report/visiting_consultant_charges_report/visiting_consultant_charges_report.py
index 1f4dfcd5..90692c3c 100644
--- a/hms_tz/hms_tz/report/visiting_consultant_charges_report/visiting_consultant_charges_report.py
+++ b/hms_tz/hms_tz/report/visiting_consultant_charges_report/visiting_consultant_charges_report.py
@@ -1,4 +1,3 @@
-
import frappe
from frappe import _
from frappe.utils import cint, flt
@@ -18,16 +17,23 @@ def execute(filters=None):
excluded_services_map,
vc_lab_users,
vc_radiology_users,
+ vc_practitioners,
) = get_commission_doc_details(filters)
data += get_opd_commissions(
- filters, commission_doc.cash_rates, commission_doc.insurance_rates
+ filters,
+ commission_doc.cash_rates,
+ commission_doc.insurance_rates,
+ vc_practitioners,
+ commission_doc.practitioners,
)
data += get_procedure_commissions(
filters,
commission_doc.cash_rates,
commission_doc.insurance_rates,
excluded_services_map,
+ vc_practitioners,
+ commission_doc.practitioners,
)
data += get_lab_commissions(
filters,
@@ -35,6 +41,7 @@ def execute(filters=None):
commission_doc.insurance_rates,
excluded_services_map,
vc_lab_users,
+ commission_doc.lab_users,
)
data += get_radiology_commissions(
filters,
@@ -42,6 +49,7 @@ def execute(filters=None):
commission_doc.insurance_rates,
excluded_services_map,
vc_radiology_users,
+ commission_doc.radiology_users,
)
if len(data) == 0:
frappe.msgprint("No records found")
@@ -50,7 +58,6 @@ def execute(filters=None):
columns = get_columns(filters)
dashboard = get_report_summary(filters, data)
- # return columns, data
return columns, data, None, None, dashboard
@@ -62,7 +69,7 @@ def get_columns(filters):
"fieldname": "practitioner",
"fieldtype": "Data",
"label": _("Healthcare Practitioner"),
- "width": "160px",
+ "width": "150px",
}
)
elif filters.get("vc_technician") and not filters.get("practitioner"):
@@ -71,7 +78,7 @@ def get_columns(filters):
"fieldname": "vc_technician",
"fieldtype": "Data",
"label": _("VC Technician"),
- "width": "160px",
+ "width": "150px",
}
)
else:
@@ -80,13 +87,13 @@ def get_columns(filters):
"fieldname": "practitioner",
"fieldtype": "Data",
"label": _("Healthcare Practitioner"),
- "width": "160px",
+ "width": "150px",
},
{
"fieldname": "vc_technician",
"fieldtype": "Data",
"label": _("VC Technician"),
- "width": "160px",
+ "width": "150px",
},
]
columns += [
@@ -94,25 +101,25 @@ def get_columns(filters):
"fieldname": "billing_item",
"fieldtype": "Data",
"label": _("Item"),
- "width": "160px",
+ "width": "150px",
},
{
"fieldname": "patient_count",
"fieldtype": "Int",
"label": _("Patient Count"),
- "width": "100px",
+ "width": "90px",
},
{
"fieldname": "item_count",
"fieldtype": "Int",
"label": _("Item Count"),
- "width": "100px",
+ "width": "90px",
},
{
"fieldname": "mode",
"fieldtype": "Data",
"label": _("Mode"),
- "width": "160px",
+ "width": "150px",
},
{
"fieldname": "paid_amount",
@@ -120,6 +127,12 @@ def get_columns(filters):
"label": _("Paid Amount"),
"width": "120px",
},
+ {
+ "fieldname": "company_amount",
+ "fieldtype": "Currency",
+ "label": _("Company Amount"),
+ "width": "120px",
+ },
{
"fieldname": "vc_amount",
"fieldtype": "Currency",
@@ -127,9 +140,15 @@ def get_columns(filters):
"width": "120px",
},
{
- "fieldname": "company_amount",
+ "fieldname": "vc_wtax_amount",
"fieldtype": "Currency",
- "label": _("Company Amount"),
+ "label": _("Vc Wtax Amount"),
+ "width": "120px",
+ },
+ {
+ "fieldname": "vc_net_amount",
+ "fieldtype": "Currency",
+ "label": _("Vc Net Amount"),
"width": "120px",
},
]
@@ -139,6 +158,7 @@ def get_columns(filters):
def get_commission_doc_details(filters):
vc_lab_users = []
vc_radiology_users = []
+ vc_practitioners = []
commission_list = frappe.get_all(
"Visiting Comission",
@@ -157,11 +177,22 @@ def get_commission_doc_details(filters):
vc_lab_users = [row.user_field for row in commission_doc.lab_users]
vc_radiology_users = [row.user_field for row in commission_doc.radiology_users]
+ vc_practitioners = [
+ row.healathcare_practitioner for row in commission_doc.practitioners
+ ]
- return commission_doc, excluded_services_map, vc_lab_users, vc_radiology_users
+ return (
+ commission_doc,
+ excluded_services_map,
+ vc_lab_users,
+ vc_radiology_users,
+ vc_practitioners,
+ )
-def get_opd_commissions(filters, cash_rates, insurance_rates):
+def get_opd_commissions(
+ filters, cash_rates, insurance_rates, vc_practitioners, practitioner_list
+):
if filters.get("vc_technician"):
return []
@@ -205,6 +236,7 @@ def get_opd_commissions(filters, cash_rates, insurance_rates):
(appointment.appointment_date >= filters.get("from_date"))
& (appointment.appointment_date <= filters.get("to_date"))
& (appointment.company == filters.get("company"))
+ & (appointment.practitioner == encounter.practitioner)
& case_wh
)
)
@@ -222,24 +254,34 @@ def get_opd_commissions(filters, cash_rates, insurance_rates):
appointment_list = []
for row in appointment_records:
+ if row.practitioner not in vc_practitioners:
+ continue
+
if row.mode == "CASH":
for rate_row in cash_rates:
if rate_row.document_type == "Patient Appointment":
- appointment_list.append(
- {
- "practitioner": row.practitioner,
- "vc_technician": "",
- "billing_item": row.billing_item,
- "patient_count": row.patient_count,
- "item_count": row.item_count,
- "mode": row.mode,
- "paid_amount": row.amount,
- "vc_amount": flt(row.amount * flt(rate_row.vc_rate / 100)),
- "company_amount": flt(
- row.amount * flt(rate_row.company_rate / 100)
- ),
- }
- )
+ for prac in practitioner_list:
+ if row.practitioner == prac.healathcare_practitioner:
+ vc_amount = flt(row.amount * flt(rate_row.vc_rate / 100))
+ vc_wtax_amount = vc_amount * (prac.wtax / 100)
+ appointment_list.append(
+ {
+ "practitioner": row.practitioner,
+ "vc_technician": "",
+ "billing_item": row.billing_item,
+ "patient_count": row.patient_count,
+ "item_count": row.item_count,
+ "mode": row.mode,
+ "paid_amount": row.amount,
+ "vc_amount": vc_amount,
+ "vc_wtax_amount": vc_wtax_amount,
+ "vc_net_amount": vc_amount - vc_wtax_amount,
+ "company_amount": flt(
+ row.amount * flt(rate_row.company_rate / 100)
+ ),
+ }
+ )
+
elif row.mode != "CASH":
coverage_plan = frappe.get_cached_value(
"Healthcare Insurance Coverage Plan",
@@ -251,26 +293,38 @@ def get_opd_commissions(filters, cash_rates, insurance_rates):
rate_row.coverage_plan == coverage_plan
and rate_row.document_type == "Patient Appointment"
):
- appointment_list.append(
- {
- "practitioner": row.practitioner,
- "vc_technician": "",
- "billing_item": row.billing_item,
- "patient_count": row.patient_count,
- "item_count": row.item_count,
- "mode": row.mode,
- "paid_amount": row.amount,
- "vc_amount": flt(row.amount * flt(rate_row.vc_rate / 100)),
- "company_amount": flt(
- row.amount * flt(rate_row.company_rate / 100)
- ),
- }
- )
+ for prac in practitioner_list:
+ if row.practitioner == prac.healathcare_practitioner:
+ vc_amount = flt(row.amount * flt(rate_row.vc_rate / 100))
+ vc_wtax_amount = vc_amount * (prac.wtax / 100)
+ appointment_list.append(
+ {
+ "practitioner": row.practitioner,
+ "vc_technician": "",
+ "billing_item": row.billing_item,
+ "patient_count": row.patient_count,
+ "item_count": row.item_count,
+ "mode": row.mode,
+ "paid_amount": row.amount,
+ "vc_amount": vc_amount,
+ "vc_wtax_amount": vc_wtax_amount,
+ "vc_net_amount": vc_amount - vc_wtax_amount,
+ "company_amount": flt(
+ row.amount * flt(rate_row.company_rate / 100)
+ ),
+ }
+ )
+
return appointment_list
def get_lab_commissions(
- filters, cash_rates, insurance_rates, excluded_services_map, vc_lab_users
+ filters,
+ cash_rates,
+ insurance_rates,
+ excluded_services_map,
+ vc_lab_users,
+ lab_tech_list,
):
if filters.get("practitioner"):
return []
@@ -308,16 +362,12 @@ def get_lab_commissions(
(lab.ref_doctype == "Patient Encounter")
& (lab.ref_docname == prescription.parent)
& (lab.hms_tz_ref_childname == prescription.name)
+ & (lab.submitted_date >= filters.get("from_date"))
+ & (lab.submitted_date <= filters.get("to_date"))
+ & (lab.company == filters.get("company"))
+ & (prescription.is_cancelled == 0)
& (lab.docstatus == 1)
- )
- .where(
- (
- (lab.submitted_date >= filters.get("from_date"))
- & (lab.submitted_date <= filters.get("to_date"))
- & (lab.company == filters.get("company"))
- & (lab.workflow_state == "Lab Results Reviewed")
- & case_wh
- )
+ & case_wh
)
.groupby(
Case()
@@ -340,42 +390,56 @@ def get_lab_commissions(
if row.template in lab_test_templates:
for excluded_lab_test in excluded_lab_tests:
if row.template == excluded_lab_test.healthcare_service:
- lab_list.append(
- {
- "practitioner": "",
- "vc_technician": row.hms_tz_submitted_by,
- "billing_item": row.template,
- "patient_count": row.patient_count,
- "item_count": row.item_count,
- "mode": row.mode,
- "paid_amount": row.amount,
- "vc_amount": flt(
+ for lab_tech in lab_tech_list:
+ if row.hms_tz_user_id == lab_tech.user_field:
+ vc_amount = flt(
row.amount * flt(excluded_lab_test.vc_rate / 100)
- ),
- "company_amount": flt(
- row.amount * flt(excluded_lab_test.company_rate / 100)
- ),
- }
- )
+ )
+ vc_wtax_amount = vc_amount * (lab_tech.wtax / 100)
+ lab_list.append(
+ {
+ "practitioner": "",
+ "vc_technician": row.hms_tz_submitted_by,
+ "billing_item": row.template,
+ "patient_count": row.patient_count,
+ "item_count": row.item_count,
+ "mode": row.mode,
+ "paid_amount": row.amount,
+ "vc_amount": vc_amount,
+ "vc_wtax_amount": vc_wtax_amount,
+ "vc_net_amount": vc_amount - vc_wtax_amount,
+ "company_amount": flt(
+ row.amount
+ * flt(excluded_lab_test.company_rate / 100)
+ ),
+ }
+ )
elif row.prescribe == 1 and row.mode == "CASH":
for rate_row in cash_rates:
if rate_row.document_type == "Lab Test":
- lab_list.append(
- {
- "practitioner": "",
- "vc_technician": row.hms_tz_submitted_by,
- "billing_item": row.template,
- "patient_count": row.patient_count,
- "item_count": row.item_count,
- "mode": row.mode,
- "paid_amount": row.amount,
- "vc_amount": flt(row.amount * flt(rate_row.vc_rate / 100)),
- "company_amount": flt(
- row.amount * flt(rate_row.company_rate / 100)
- ),
- }
- )
+ for lab_tech in lab_tech_list:
+ if row.hms_tz_user_id == lab_tech.user_field:
+ vc_amount = flt(row.amount * flt(rate_row.vc_rate / 100))
+ vc_wtax_amount = vc_amount * (lab_tech.wtax / 100)
+ lab_list.append(
+ {
+ "practitioner": "",
+ "vc_technician": row.hms_tz_submitted_by,
+ "billing_item": row.template,
+ "patient_count": row.patient_count,
+ "item_count": row.item_count,
+ "mode": row.mode,
+ "paid_amount": row.amount,
+ "vc_amount": vc_amount,
+ "vc_wtax_amount": vc_wtax_amount,
+ "vc_net_amount": vc_amount - vc_wtax_amount,
+ "company_amount": flt(
+ row.amount * flt(rate_row.company_rate / 100)
+ ),
+ }
+ )
+
elif row.prescribe == 0 and row.mode != "CASH":
coverage_plan_name = None
if row.mode == "NH001~":
@@ -389,28 +453,42 @@ def get_lab_commissions(
rate_row.coverage_plan == row.mode
and rate_row.document_type == "Lab Test"
):
- lab_list.append(
- {
- "practitioner": "",
- "vc_technician": row.hms_tz_submitted_by,
- "billing_item": row.template,
- "patient_count": row.patient_count,
- "item_count": row.item_count,
- "mode": (
- coverage_plan_name if coverage_plan_name else row.mode
- ),
- "paid_amount": row.amount,
- "vc_amount": flt(row.amount * flt(rate_row.vc_rate / 100)),
- "company_amount": flt(
- row.amount * flt(rate_row.company_rate / 100)
- ),
- }
- )
+ for lab_tech in lab_tech_list:
+ if row.hms_tz_user_id == lab_tech.user_field:
+ vc_amount = flt(row.amount * flt(rate_row.vc_rate / 100))
+ vc_wtax_amount = vc_amount * (lab_tech.wtax / 100)
+ lab_list.append(
+ {
+ "practitioner": "",
+ "vc_technician": row.hms_tz_submitted_by,
+ "billing_item": row.template,
+ "patient_count": row.patient_count,
+ "item_count": row.item_count,
+ "mode": (
+ coverage_plan_name
+ if coverage_plan_name
+ else row.mode
+ ),
+ "paid_amount": row.amount,
+ "vc_amount": vc_amount,
+ "vc_wtax_amount": vc_wtax_amount,
+ "vc_net_amount": vc_amount - vc_wtax_amount,
+ "company_amount": flt(
+ row.amount * flt(rate_row.company_rate / 100)
+ ),
+ }
+ )
+
return lab_list
def get_radiology_commissions(
- filters, cash_rates, insurance_rates, excluded_services_map, vc_radiology_users
+ filters,
+ cash_rates,
+ insurance_rates,
+ excluded_services_map,
+ vc_radiology_users,
+ rad_tech_list,
):
if filters.get("practitioner"):
return []
@@ -449,16 +527,12 @@ def get_radiology_commissions(
(radiology.ref_doctype == "Patient Encounter")
& (radiology.ref_docname == prescription.parent)
& (radiology.hms_tz_ref_childname == prescription.name)
+ & (radiology.hms_tz_submitted_date >= filters.get("from_date"))
+ & (radiology.hms_tz_submitted_date <= filters.get("to_date"))
+ & (radiology.company == filters.get("company"))
+ & (prescription.is_cancelled == 0)
& (radiology.docstatus == 1)
- )
- .where(
- (
- (radiology.hms_tz_submitted_date >= filters.get("from_date"))
- & (radiology.hms_tz_submitted_date <= filters.get("to_date"))
- & (radiology.company == filters.get("company"))
- & (radiology.workflow_state == "Submitted")
- & case_wh
- )
+ & case_wh
)
.groupby(
Case()
@@ -486,42 +560,56 @@ def get_radiology_commissions(
row.radiology_examination_template
== excluded_radiology.healthcare_service
):
- radiology_list.append(
- {
- "practitioner": "",
- "vc_technician": row.hms_tz_submitted_by,
- "billing_item": row.radiology_examination_template,
- "patient_count": row.patient_count,
- "item_count": row.item_count,
- "mode": row.mode,
- "paid_amount": row.amount,
- "vc_amount": flt(
+ for rad_tech in rad_tech_list:
+ if row.hms_tz_user_id == rad_tech.user_field:
+ vc_amount = flt(
row.amount * flt(excluded_radiology.vc_rate / 100)
- ),
- "company_amount": flt(
- row.amount * flt(excluded_radiology.company_rate / 100)
- ),
- }
- )
+ )
+ vc_wtax_amount = vc_amount * (rad_tech.wtax / 100)
+ radiology_list.append(
+ {
+ "practitioner": "",
+ "vc_technician": row.hms_tz_submitted_by,
+ "billing_item": row.radiology_examination_template,
+ "patient_count": row.patient_count,
+ "item_count": row.item_count,
+ "mode": row.mode,
+ "paid_amount": row.amount,
+ "vc_amount": vc_amount,
+ "vc_wtax_amount": vc_wtax_amount,
+ "vc_net_amount": vc_amount - vc_wtax_amount,
+ "company_amount": flt(
+ row.amount
+ * flt(excluded_radiology.company_rate / 100)
+ ),
+ }
+ )
elif row.prescribe == 1 and row.mode == "CASH":
for rate_row in cash_rates:
if rate_row.document_type == "Radiology Examination":
- radiology_list.append(
- {
- "practitioner": "",
- "vc_technician": row.hms_tz_submitted_by,
- "billing_item": row.radiology_examination_template,
- "patient_count": row.patient_count,
- "item_count": row.item_count,
- "mode": row.mode,
- "paid_amount": row.amount,
- "vc_amount": flt(row.amount * flt(rate_row.vc_rate / 100)),
- "company_amount": flt(
- row.amount * flt(rate_row.company_rate / 100)
- ),
- }
- )
+ for rad_tech in rad_tech_list:
+ if row.hms_tz_user_id == rad_tech.user_field:
+ vc_amount = flt(row.amount * flt(rate_row.vc_rate / 100))
+ vc_wtax_amount = vc_amount * (rad_tech.wtax / 100)
+ radiology_list.append(
+ {
+ "practitioner": "",
+ "vc_technician": row.hms_tz_submitted_by,
+ "billing_item": row.radiology_examination_template,
+ "patient_count": row.patient_count,
+ "item_count": row.item_count,
+ "mode": row.mode,
+ "paid_amount": row.amount,
+ "vc_amount": vc_amount,
+ "vc_wtax_amount": vc_wtax_amount,
+ "vc_net_amount": vc_amount - vc_wtax_amount,
+ "company_amount": flt(
+ row.amount * flt(rate_row.company_rate / 100)
+ ),
+ }
+ )
+
elif row.prescribe == 0 and row.mode != "CASH":
coverage_plan_name = None
if row.mode == "NH001~":
@@ -535,28 +623,42 @@ def get_radiology_commissions(
rate_row.coverage_plan == row.mode
and rate_row.document_type == "Radiology Examination"
):
- radiology_list.append(
- {
- "practitioner": "",
- "vc_technician": row.hms_tz_submitted_by,
- "billing_item": row.radiology_examination_template,
- "patient_count": row.patient_count,
- "item_count": row.item_count,
- "mode": (
- coverage_plan_name if coverage_plan_name else row.mode
- ),
- "paid_amount": row.amount,
- "vc_amount": flt(row.amount * flt(rate_row.vc_rate / 100)),
- "company_amount": flt(
- row.amount * flt(rate_row.company_rate / 100)
- ),
- }
- )
+ for rad_tech in rad_tech_list:
+ if row.hms_tz_user_id == rad_tech.user_field:
+ vc_amount = flt(row.amount * flt(rate_row.vc_rate / 100))
+ vc_wtax_amount = vc_amount * (rad_tech.wtax / 100)
+ radiology_list.append(
+ {
+ "practitioner": "",
+ "vc_technician": row.hms_tz_submitted_by,
+ "billing_item": row.radiology_examination_template,
+ "patient_count": row.patient_count,
+ "item_count": row.item_count,
+ "mode": (
+ coverage_plan_name
+ if coverage_plan_name
+ else row.mode
+ ),
+ "paid_amount": row.amount,
+ "vc_amount": vc_amount,
+ "vc_wtax_amount": vc_wtax_amount,
+ "vc_net_amount": vc_amount - vc_wtax_amount,
+ "company_amount": flt(
+ row.amount * flt(rate_row.company_rate / 100)
+ ),
+ }
+ )
+
return radiology_list
def get_procedure_commissions(
- filters, cash_rates, insurance_rates, excluded_services_map
+ filters,
+ cash_rates,
+ insurance_rates,
+ excluded_services_map,
+ vc_practitioners,
+ practitioner_list,
):
if filters.get("vc_technician"):
return []
@@ -593,16 +695,12 @@ def get_procedure_commissions(
(procedure.ref_doctype == "Patient Encounter")
& (procedure.ref_docname == prescription.parent)
& (procedure.hms_tz_ref_childname == prescription.name)
+ & (procedure.hms_tz_submitted_date >= filters.get("from_date"))
+ & (procedure.hms_tz_submitted_date <= filters.get("to_date"))
+ & (procedure.company == filters.get("company"))
+ & (prescription.is_cancelled == 0)
& (procedure.docstatus == 1)
- )
- .where(
- (
- (procedure.hms_tz_submitted_date >= filters.get("from_date"))
- & (procedure.hms_tz_submitted_date <= filters.get("to_date"))
- & (procedure.company == filters.get("company"))
- & (procedure.workflow_state == "Completed")
- & case_wh
- )
+ & case_wh
)
.groupby(
Case()
@@ -621,45 +719,62 @@ def get_procedure_commissions(
]
for row in procedure_records:
+ if row.practitioner not in vc_practitioners:
+ continue
+
if row.procedure_template in excluded_procedure_templates:
for excluded_procedure in excluded_procedures:
if row.procedure_template == excluded_procedure.healthcare_service:
- procedure_list.append(
- {
- "practitioner": row.practitioner,
- "vc_technician": "",
- "billing_item": row.procedure_template,
- "patient_count": row.patient_count,
- "item_count": row.item_count,
- "mode": row.mode,
- "paid_amount": row.amount,
- "vc_amount": flt(
+ for prac in practitioner_list:
+ if row.practitioner == prac.healathcare_practitioner:
+ vc_amount = flt(
row.amount * flt(excluded_procedure.vc_rate / 100)
- ),
- "company_amount": flt(
- row.amount * flt(excluded_procedure.company_rate / 100)
- ),
- }
- )
+ )
+ vc_wtax_amount = vc_amount * (prac.wtax / 100)
+ procedure_list.append(
+ {
+ "practitioner": row.practitioner,
+ "vc_technician": "",
+ "billing_item": row.procedure_template,
+ "patient_count": row.patient_count,
+ "item_count": row.item_count,
+ "mode": row.mode,
+ "paid_amount": row.amount,
+ "vc_amount": vc_amount,
+ "vc_wtax_amount": vc_wtax_amount,
+ "vc_net_amount": vc_amount - vc_wtax_amount,
+ "company_amount": flt(
+ row.amount
+ * flt(excluded_procedure.company_rate / 100)
+ ),
+ }
+ )
elif row.prescribe == 1 and row.mode == "CASH":
for rate_row in cash_rates:
if rate_row.document_type == "Clinical Procedure":
- procedure_list.append(
- {
- "practitioner": row.practitioner,
- "vc_technician": "",
- "billing_item": row.procedure_template,
- "patient_count": row.patient_count,
- "item_count": row.item_count,
- "mode": row.mode,
- "paid_amount": row.amount,
- "vc_amount": flt(row.amount * flt(rate_row.vc_rate / 100)),
- "company_amount": flt(
- row.amount * flt(rate_row.company_rate / 100)
- ),
- }
- )
+ for prac in practitioner_list:
+ if row.practitioner == prac.healathcare_practitioner:
+ vc_amount = flt(row.amount * flt(rate_row.vc_rate / 100))
+ vc_wtax_amount = vc_amount * (prac.wtax / 100)
+ procedure_list.append(
+ {
+ "practitioner": row.practitioner,
+ "vc_technician": "",
+ "billing_item": row.procedure_template,
+ "patient_count": row.patient_count,
+ "item_count": row.item_count,
+ "mode": row.mode,
+ "paid_amount": row.amount,
+ "vc_amount": vc_amount,
+ "vc_wtax_amount": vc_wtax_amount,
+ "vc_net_amount": vc_amount - vc_wtax_amount,
+ "company_amount": flt(
+ row.amount * flt(rate_row.company_rate / 100)
+ ),
+ }
+ )
+
elif row.prescribe == 0 and row.mode != "CASH":
coverage_plan_name = None
if row.mode == "NH001~":
@@ -673,23 +788,32 @@ def get_procedure_commissions(
rate_row.coverage_plan == row.mode
and rate_row.document_type == "Clinical Procedure"
):
- procedure_list.append(
- {
- "practitioner": row.practitioner,
- "vc_technician": "",
- "billing_item": row.procedure_template,
- "patient_count": row.patient_count,
- "item_count": row.item_count,
- "mode": (
- coverage_plan_name if coverage_plan_name else row.mode
- ),
- "paid_amount": row.amount,
- "vc_amount": flt(row.amount * flt(rate_row.vc_rate / 100)),
- "company_amount": flt(
- row.amount * flt(rate_row.company_rate / 100)
- ),
- }
- )
+ for prac in practitioner_list:
+ if row.practitioner == prac.healathcare_practitioner:
+ vc_amount = flt(row.amount * flt(rate_row.vc_rate / 100))
+ vc_wtax_amount = vc_amount * (prac.wtax / 100)
+ procedure_list.append(
+ {
+ "practitioner": row.practitioner,
+ "vc_technician": "",
+ "billing_item": row.procedure_template,
+ "patient_count": row.patient_count,
+ "item_count": row.item_count,
+ "mode": (
+ coverage_plan_name
+ if coverage_plan_name
+ else row.mode
+ ),
+ "paid_amount": row.amount,
+ "vc_amount": vc_amount,
+ "vc_wtax_amount": vc_wtax_amount,
+ "vc_net_amount": vc_amount - vc_wtax_amount,
+ "company_amount": flt(
+ row.amount * flt(rate_row.company_rate / 100)
+ ),
+ }
+ )
+
return procedure_list
@@ -707,6 +831,20 @@ def get_report_summary(args, summary_data):
if row.get("company_amount")
]
)
+ total_vc_wtax_amount = sum(
+ [
+ flt(row.get("vc_wtax_amount"))
+ for row in summary_data
+ if row.get("vc_wtax_amount")
+ ]
+ )
+ total_vc_net_amount = sum(
+ [
+ flt(row.get("vc_net_amount"))
+ for row in summary_data
+ if row.get("vc_net_amount")
+ ]
+ )
currency = frappe.get_cached_value("Company", args.company, "default_currency")
return [
@@ -716,6 +854,12 @@ def get_report_summary(args, summary_data):
"datatype": "Currency",
"currency": currency,
},
+ {
+ "value": total_company_amount,
+ "label": _("Total Company Amount"),
+ "datatype": "Currency",
+ "currency": currency,
+ },
{
"value": total_vc_amount,
"label": _("Total VC Amount"),
@@ -723,8 +867,14 @@ def get_report_summary(args, summary_data):
"currency": currency,
},
{
- "value": total_company_amount,
- "label": _("Total Company Amount"),
+ "value": total_vc_wtax_amount,
+ "label": _("Total VC w/Tax"),
+ "datatype": "Currency",
+ "currency": currency,
+ },
+ {
+ "value": total_vc_net_amount,
+ "label": _("Total VC Net Amount"),
"datatype": "Currency",
"currency": currency,
},
diff --git a/hms_tz/nhif/doctype/vc_lrpmt_submitter/vc_lrpmt_submitter.json b/hms_tz/nhif/doctype/vc_lrpmt_submitter/vc_lrpmt_submitter.json
index 0d60c4a9..03bb1704 100644
--- a/hms_tz/nhif/doctype/vc_lrpmt_submitter/vc_lrpmt_submitter.json
+++ b/hms_tz/nhif/doctype/vc_lrpmt_submitter/vc_lrpmt_submitter.json
@@ -6,26 +6,35 @@
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
- "user_field"
+ "user_field",
+ "wtax"
],
"fields": [
{
"fieldname": "user_field",
"fieldtype": "Link",
"in_list_view": 1,
- "label": "User",
- "options": "User"
+ "label": "VC User",
+ "options": "User",
+ "reqd": 1
+ },
+ {
+ "fieldname": "wtax",
+ "fieldtype": "Percent",
+ "in_list_view": 1,
+ "label": "Wtax"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
- "modified": "2023-08-01 16:56:34.693580",
+ "modified": "2024-01-30 10:55:32.191177",
"modified_by": "Administrator",
"module": "NHIF",
"name": "VC LRPMT Submitter",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
- "sort_order": "DESC"
+ "sort_order": "DESC",
+ "states": []
}
\ No newline at end of file
diff --git a/hms_tz/nhif/doctype/vc_practitioner/__init__.py b/hms_tz/nhif/doctype/vc_practitioner/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/hms_tz/nhif/doctype/vc_practitioner/vc_practitioner.json b/hms_tz/nhif/doctype/vc_practitioner/vc_practitioner.json
new file mode 100644
index 00000000..248ad3f2
--- /dev/null
+++ b/hms_tz/nhif/doctype/vc_practitioner/vc_practitioner.json
@@ -0,0 +1,40 @@
+{
+ "actions": [],
+ "allow_rename": 1,
+ "creation": "2024-01-30 10:35:44.585441",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "healathcare_practitioner",
+ "wtax"
+ ],
+ "fields": [
+ {
+ "fieldname": "healathcare_practitioner",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Healathcare Practitioner",
+ "options": "Healthcare Practitioner",
+ "reqd": 1
+ },
+ {
+ "fieldname": "wtax",
+ "fieldtype": "Percent",
+ "in_list_view": 1,
+ "label": "WTax"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2024-01-30 10:35:44.585441",
+ "modified_by": "Administrator",
+ "module": "NHIF",
+ "name": "VC Practitioner",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": []
+}
\ No newline at end of file
diff --git a/hms_tz/nhif/doctype/vc_practitioner/vc_practitioner.py b/hms_tz/nhif/doctype/vc_practitioner/vc_practitioner.py
new file mode 100644
index 00000000..c7996916
--- /dev/null
+++ b/hms_tz/nhif/doctype/vc_practitioner/vc_practitioner.py
@@ -0,0 +1,8 @@
+# Copyright (c) 2024, Aakvatech and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+class VCPractitioner(Document):
+ pass
diff --git a/hms_tz/nhif/doctype/visiting_comission/visiting_comission.json b/hms_tz/nhif/doctype/visiting_comission/visiting_comission.json
index e39d4b26..8130e588 100644
--- a/hms_tz/nhif/doctype/visiting_comission/visiting_comission.json
+++ b/hms_tz/nhif/doctype/visiting_comission/visiting_comission.json
@@ -16,6 +16,8 @@
"cash_rates",
"section_break_2",
"excluded_service_rates",
+ "vc_practitioners_tab",
+ "practitioners",
"vc_users_for_lrpmt_docs_section",
"lab_users",
"column_break_edsot",
@@ -45,7 +47,7 @@
{
"collapsible": 1,
"fieldname": "insurance_sec",
- "fieldtype": "Section Break",
+ "fieldtype": "Tab Break",
"label": "Insurance Commission Rates"
},
{
@@ -56,7 +58,7 @@
{
"collapsible": 1,
"fieldname": "cash_sec",
- "fieldtype": "Section Break",
+ "fieldtype": "Tab Break",
"label": "Cash Commission Rates"
},
{
@@ -67,7 +69,7 @@
{
"collapsible": 1,
"fieldname": "section_break_2",
- "fieldtype": "Section Break",
+ "fieldtype": "Tab Break",
"label": "Excluded Service Rates"
},
{
@@ -78,14 +80,15 @@
{
"collapsible": 1,
"fieldname": "vc_users_for_lrpmt_docs_section",
- "fieldtype": "Section Break",
- "label": "VC Users for LRPMT Docs"
+ "fieldtype": "Tab Break",
+ "label": "VC Technicians"
},
{
- "description": "List of VC users who are eligible to get commission after submitting lab tests",
+ "bold": 1,
+ "description": "List of VC technicians who are eligible to get commissions after submitting lab tests. If VC technician is not in this list, means that VC technician won't get VC commission",
"fieldname": "lab_users",
- "fieldtype": "Table MultiSelect",
- "label": "VC Lab Users",
+ "fieldtype": "Table",
+ "label": "VC Lab Technicians",
"options": "VC LRPMT Submitter"
},
{
@@ -93,10 +96,11 @@
"fieldtype": "Column Break"
},
{
- "description": "List of VC users who are eligible to get commission after submitting Radiology Examinations",
+ "bold": 1,
+ "description": "List of VC technicians who are eligible to get commissions after submitting radiology. If VC technician is not on this list, means that VC technician won't get VC commission",
"fieldname": "radiology_users",
- "fieldtype": "Table MultiSelect",
- "label": "VC Radiology Users",
+ "fieldtype": "Table",
+ "label": "VC Radiology Technicians",
"options": "VC LRPMT Submitter"
},
{
@@ -105,14 +109,28 @@
"label": "Series",
"options": "HLC-VC-.YYYY.-",
"read_only": 1
+ },
+ {
+ "collapsible": 1,
+ "fieldname": "vc_practitioners_tab",
+ "fieldtype": "Tab Break",
+ "label": "VC Practitioners"
+ },
+ {
+ "description": "List of healthcare practitioners eligible to get a visiting commission. If VC practitioner is not on this list, then that practitioner won't get visiting commission",
+ "fieldname": "practitioners",
+ "fieldtype": "Table",
+ "label": "Vc Practitioners",
+ "options": "VC Practitioner"
}
],
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2023-08-02 09:40:46.004211",
+ "modified": "2024-01-30 17:35:41.761456",
"modified_by": "Administrator",
"module": "NHIF",
"name": "Visiting Comission",
+ "naming_rule": "By \"Naming Series\" field",
"owner": "Administrator",
"permissions": [
{
@@ -130,5 +148,6 @@
],
"sort_field": "modified",
"sort_order": "DESC",
+ "states": [],
"track_changes": 1
}
\ No newline at end of file
From 1e2ae1a775e4edec5d9c859f69acfcf921ec3da7 Mon Sep 17 00:00:00 2001
From: av-dev2
Date: Mon, 12 Feb 2024 14:41:22 +0300
Subject: [PATCH 7/8] chore: change fieldtype of some of fields from Data to
Link on Itemwise Hospital Revenue report
---
.../itemwise_hospital_revenue.py | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/hms_tz/nhif/report/itemwise_hospital_revenue/itemwise_hospital_revenue.py b/hms_tz/nhif/report/itemwise_hospital_revenue/itemwise_hospital_revenue.py
index 7f10091b..de72d366 100644
--- a/hms_tz/nhif/report/itemwise_hospital_revenue/itemwise_hospital_revenue.py
+++ b/hms_tz/nhif/report/itemwise_hospital_revenue/itemwise_hospital_revenue.py
@@ -65,7 +65,8 @@ def get_columns(filters):
{
"fieldname": "appointment_no",
"label": "AppointmentNo",
- "fieldtype": "Data",
+ "fieldtype": "Link",
+ "options": "Patient Appointment",
"width": 120,
},
]
@@ -123,13 +124,15 @@ def get_columns(filters):
{
"fieldnaeme": "practitioner",
"label": "Practitioner",
- "fieldtype": "Data",
+ "fieldtype": "Link",
+ "options": "Healthcare Practitioner",
"width": 120,
},
{
"fieldname": "service_unit",
"label": "Service Unit",
- "fieldtype": "Data",
+ "fieldtype": "Link",
+ "options": "Healthcare Service Unit",
"width": 120,
},
{
@@ -151,7 +154,8 @@ def get_columns(filters):
{
"fieldname": "encounter_no",
"label": "Encounter No",
- "fieldtype": "Data",
+ "fieldtype": "Link",
+ "options": "Patient Encounter",
"width": 120,
},
{
From 3f6d526c2c642c816de35d101beab85f30751083 Mon Sep 17 00:00:00 2001
From: aakvatech <35020381+aakvatech@users.noreply.github.com>
Date: Mon, 12 Feb 2024 20:57:15 +0300
Subject: [PATCH 8/8] Bumped to v14.13.1
---
hms_tz/__init__.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hms_tz/__init__.py b/hms_tz/__init__.py
index 6308a2cf..3bed1866 100644
--- a/hms_tz/__init__.py
+++ b/hms_tz/__init__.py
@@ -1,4 +1,4 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
-__version__ = "14.12.0"
+__version__ = "14.13.1"