Inpatient Billing
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index daf1bfe..facfa53 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -984,7 +984,7 @@
frappe.model.set_value(si_item.doctype, si_item.name, 'reference_dn', checked_values[i]['dn']);
frappe.model.set_value(si_item.doctype, si_item.name, 'qty', 1);
if(checked_values[i]['qty'] > 1){
- frappe.model.set_value(si_item.doctype, si_item.name, 'qty', checked_values[i]['qty']);
+ frappe.model.set_value(si_item.doctype, si_item.name, 'qty', parseFloat(checked_values[i]['qty']));
}
}
frm.refresh_fields();
diff --git a/erpnext/domains/healthcare.py b/erpnext/domains/healthcare.py
index 57f30f6..ee8dc81 100644
--- a/erpnext/domains/healthcare.py
+++ b/erpnext/domains/healthcare.py
@@ -31,7 +31,7 @@
'insert_after': 'patient', 'read_only': True
},
{
- 'fieldname': 'ref_practitioner', 'label': 'Referring Practitioner', 'fieldtype': 'Link', 'options': 'Practitioner',
+ 'fieldname': 'ref_practitioner', 'label': 'Referring Practitioner', 'fieldtype': 'Link', 'options': 'Healthcare Practitioner',
'insert_after': 'customer'
}
],
diff --git a/erpnext/healthcare/doctype/inpatient_occupancy/inpatient_occupancy.json b/erpnext/healthcare/doctype/inpatient_occupancy/inpatient_occupancy.json
index 2ac498d..3e10143 100644
--- a/erpnext/healthcare/doctype/inpatient_occupancy/inpatient_occupancy.json
+++ b/erpnext/healthcare/doctype/inpatient_occupancy/inpatient_occupancy.json
@@ -140,6 +140,39 @@
"set_only_once": 0,
"translatable": 0,
"unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_in_quick_entry": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "default": "0",
+ "fieldname": "invoiced",
+ "fieldtype": "Check",
+ "hidden": 0,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Invoiced",
+ "length": 0,
+ "no_copy": 0,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "translatable": 0,
+ "unique": 0
}
],
"has_web_view": 0,
@@ -152,7 +185,7 @@
"issingle": 0,
"istable": 1,
"max_attachments": 0,
- "modified": "2018-07-17 18:26:46.009878",
+ "modified": "2018-07-18 18:26:46.009878",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Inpatient Occupancy",
@@ -167,4 +200,4 @@
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
-}
\ No newline at end of file
+}
diff --git a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py
index 07cd9e4..2ed3f8e 100644
--- a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py
+++ b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py
@@ -69,17 +69,20 @@
inpatient_record.save(ignore_permissions = True)
@frappe.whitelist()
-def schedule_discharge(patient, encounter_id, practitioner):
+def schedule_discharge(patient, encounter_id=None, practitioner=None):
inpatient_record_id = frappe.db.get_value('Patient', patient, 'inpatient_record')
if inpatient_record_id:
inpatient_record = frappe.get_doc("Inpatient Record", inpatient_record_id)
inpatient_record.discharge_practitioner = practitioner
inpatient_record.discharge_encounter = encounter_id
inpatient_record.status = "Discharge Scheduled"
+
+ check_out_inpatient(inpatient_record)
+
inpatient_record.save(ignore_permissions = True)
frappe.db.set_value("Patient", patient, "inpatient_status", "Discharge Scheduled")
-def discharge_patient(inpatient_record):
+def check_out_inpatient(inpatient_record):
if inpatient_record.inpatient_occupancies:
for inpatient_occupancy in inpatient_record.inpatient_occupancies:
if inpatient_occupancy.left != 1:
@@ -87,11 +90,54 @@
inpatient_occupancy.check_out = now_datetime()
frappe.db.set_value("Healthcare Service Unit", inpatient_occupancy.service_unit, "occupied", False)
+def discharge_patient(inpatient_record):
+ validate_invoiced_inpatient(inpatient_record)
inpatient_record.discharge_date = today()
inpatient_record.status = "Discharged"
inpatient_record.save(ignore_permissions = True)
+def validate_invoiced_inpatient(inpatient_record):
+ pending_invoices = []
+ if inpatient_record.inpatient_occupancies:
+ service_unit_names = False
+ for inpatient_occupancy in inpatient_record.inpatient_occupancies:
+ if inpatient_occupancy.invoiced != 1:
+ if service_unit_names:
+ service_unit_names += ", " + inpatient_occupancy.service_unit
+ else:
+ service_unit_names = inpatient_occupancy.service_unit
+ if service_unit_names:
+ pending_invoices.append("Inpatient Occupancy (" + service_unit_names + ")")
+
+ docs = ["Patient Appointment", "Patient Encounter", "Lab Test", "Clinical Procedure"]
+
+ for doc in docs:
+ doc_name_list = get_inpatient_docs_not_invoiced(doc, inpatient_record)
+ if doc_name_list:
+ pending_invoices = get_doc_pendig(doc, doc_name_list, pending_invoices)
+
+ if pending_invoices:
+ frappe.throw(_("Can not mark Inpatient Record Discharged, there are Unpaid Invoices {0}").format(", "
+ .join(map(lambda x: """ <b>{0}</b>""".format(x), pending_invoices))))
+
+def get_doc_pendig(doc, doc_name_list, pending_invoices):
+ if doc_name_list:
+ doc_ids = False
+ for doc_name in doc_name_list:
+ if doc_ids:
+ doc_ids += ", "+doc_name.name
+ else:
+ doc_ids = doc_name.name
+ if doc_ids:
+ pending_invoices.append(doc + " (" + doc_ids + ")")
+
+ return pending_invoices
+
+def get_inpatient_docs_not_invoiced(doc, inpatient_record):
+ return frappe.db.get_list(doc, filters = {"patient": inpatient_record.patient,
+ "inpatient_record": inpatient_record.name, "invoiced": 0})
+
def admit_patient(inpatient_record, service_unit, check_in, expected_discharge=None):
inpatient_record.admitted_datetime = check_in
inpatient_record.status = "Admitted"
diff --git a/erpnext/healthcare/utils.py b/erpnext/healthcare/utils.py
index 5a7c7e3..5145c85 100644
--- a/erpnext/healthcare/utils.py
+++ b/erpnext/healthcare/utils.py
@@ -6,6 +6,7 @@
import frappe
import datetime
from frappe import _
+from frappe.utils import date_diff, getdate
from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_income_account
from erpnext.healthcare.doctype.patient_appointment.patient_appointment import validity_exists
from erpnext.healthcare.doctype.fee_validity.fee_validity import create_fee_validity, update_fee_validity
@@ -118,6 +119,20 @@
item_to_invoice.append({'reference_type': 'Clinical Procedure Item', 'reference_name': procedure_consumable_obj.name,
'service': procedure_consumable_obj.item_code, 'qty': procedure_consumable_obj.qty})
+ inpatient_services = frappe.db.sql("""select io.name, io.parent from `tabInpatient Record` ip,
+ `tabInpatient Occupancy` io where ip.patient=%s and io.parent=ip.name and
+ io.left=1 and io.invoiced=0""", (patient.name))
+ if inpatient_services:
+ for inpatient_service in inpatient_services:
+ inpatient_occupancy = frappe.get_doc("Inpatient Occupancy", inpatient_service[0])
+ service_unit_type = frappe.get_doc("Healthcare Service Unit Type", frappe.db.get_value("Healthcare Service Unit", inpatient_occupancy.service_unit, "service_unit_type"))
+ if service_unit_type and service_unit_type.is_billable == 1:
+ qty = date_diff(getdate(inpatient_occupancy.check_out), getdate(inpatient_occupancy.check_in))
+ if qty < 1:
+ qty = 1
+ item_to_invoice.append({'reference_type': 'Inpatient Occupancy', 'reference_name': inpatient_occupancy.name,
+ 'service': service_unit_type.item, 'qty': qty})
+
return item_to_invoice
else:
frappe.throw(_("The Patient {0} do not have customer refrence to invoice").format(patient.name))