fix: Allow backdated discharge for inpatient (#25124)
* fix: Allow backdated discharge for inpatient The system is not flexible enough to allow backdated patient discharge. Signed-off-by: Syed Mujeer Hashmi <mujeerhashmi@4csolutions.in> * fix: Sider issues and test cases related to this patch Signed-off-by: Syed Mujeer Hashmi <mujeerhashmi@4csolutions.in> Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com> Co-authored-by: Jannat Patel <31363128+pateljannat@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
27fad29ad6
commit
1604b6cc63
@@ -118,12 +118,12 @@ class TestInpatientMedicationEntry(unittest.TestCase):
|
||||
|
||||
def tearDown(self):
|
||||
# cleanup - Discharge
|
||||
schedule_discharge(frappe.as_json({'patient': self.patient}))
|
||||
schedule_discharge(frappe.as_json({'patient': self.patient, 'discharge_ordered_datetime': now_datetime()}))
|
||||
self.ip_record.reload()
|
||||
mark_invoiced_inpatient_occupancy(self.ip_record)
|
||||
|
||||
self.ip_record.reload()
|
||||
discharge_patient(self.ip_record)
|
||||
discharge_patient(self.ip_record, now_datetime())
|
||||
|
||||
for entry in frappe.get_all('Inpatient Medication Entry'):
|
||||
doc = frappe.get_doc('Inpatient Medication Entry', entry.name)
|
||||
|
||||
@@ -40,13 +40,13 @@ class TestInpatientMedicationOrder(unittest.TestCase):
|
||||
|
||||
def test_inpatient_validation(self):
|
||||
# Discharge
|
||||
schedule_discharge(frappe.as_json({'patient': self.patient}))
|
||||
schedule_discharge(frappe.as_json({'patient': self.patient, 'discharge_ordered_datetime': now_datetime()}))
|
||||
|
||||
self.ip_record.reload()
|
||||
mark_invoiced_inpatient_occupancy(self.ip_record)
|
||||
|
||||
self.ip_record.reload()
|
||||
discharge_patient(self.ip_record)
|
||||
discharge_patient(self.ip_record, now_datetime())
|
||||
|
||||
ipmo = create_ipmo(self.patient)
|
||||
# inpatient validation
|
||||
@@ -74,12 +74,12 @@ class TestInpatientMedicationOrder(unittest.TestCase):
|
||||
def tearDown(self):
|
||||
if frappe.db.get_value('Patient', self.patient, 'inpatient_record'):
|
||||
# cleanup - Discharge
|
||||
schedule_discharge(frappe.as_json({'patient': self.patient}))
|
||||
schedule_discharge(frappe.as_json({'patient': self.patient, 'discharge_ordered_datetime': now_datetime()}))
|
||||
self.ip_record.reload()
|
||||
mark_invoiced_inpatient_occupancy(self.ip_record)
|
||||
|
||||
self.ip_record.reload()
|
||||
discharge_patient(self.ip_record)
|
||||
discharge_patient(self.ip_record, now_datetime())
|
||||
|
||||
for doctype in ["Inpatient Medication Entry", "Inpatient Medication Order"]:
|
||||
frappe.db.sql("delete from `tab{doctype}`".format(doctype=doctype))
|
||||
|
||||
@@ -41,17 +41,36 @@ frappe.ui.form.on('Inpatient Record', {
|
||||
});
|
||||
|
||||
let discharge_patient = function(frm) {
|
||||
frappe.call({
|
||||
doc: frm.doc,
|
||||
method: 'discharge',
|
||||
callback: function(data) {
|
||||
if (!data.exc) {
|
||||
frm.reload_doc();
|
||||
let dialog = new frappe.ui.Dialog({
|
||||
title: 'Discharge Patient',
|
||||
width: 100,
|
||||
fields: [
|
||||
{fieldtype: 'Datetime', label: 'Discharge Datetime', fieldname: 'check_out',
|
||||
reqd: 1, default: frappe.datetime.now_datetime()
|
||||
}
|
||||
},
|
||||
freeze: true,
|
||||
freeze_message: __('Processing Inpatient Discharge')
|
||||
],
|
||||
primary_action_label: __('Discharge'),
|
||||
primary_action: function() {
|
||||
let check_out = dialog.get_value('check_out');
|
||||
frappe.call({
|
||||
doc: frm.doc,
|
||||
method: 'discharge',
|
||||
args: {
|
||||
'check_out': check_out
|
||||
},
|
||||
callback: function(data) {
|
||||
if (!data.exc) {
|
||||
frm.reload_doc();
|
||||
}
|
||||
},
|
||||
freeze: true,
|
||||
freeze_message: __('Processing Inpatient Discharge')
|
||||
});
|
||||
frm.refresh_fields();
|
||||
dialog.hide();
|
||||
}
|
||||
});
|
||||
dialog.show();
|
||||
};
|
||||
|
||||
let admit_patient_dialog = function(frm) {
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
"inpatient_occupancies",
|
||||
"btn_transfer",
|
||||
"sb_discharge_details",
|
||||
"discharge_ordered_date",
|
||||
"discharge_ordered_datetime",
|
||||
"discharge_practitioner",
|
||||
"discharge_encounter",
|
||||
"discharge_datetime",
|
||||
@@ -374,13 +374,6 @@
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Discharge Instructions"
|
||||
},
|
||||
{
|
||||
"fieldname": "discharge_ordered_date",
|
||||
"fieldtype": "Date",
|
||||
"in_list_view": 1,
|
||||
"label": "Discharge Ordered Date",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"fieldname": "rehabilitation_section",
|
||||
@@ -406,13 +399,20 @@
|
||||
{
|
||||
"fieldname": "discharge_datetime",
|
||||
"fieldtype": "Datetime",
|
||||
"label": "Discharge Date",
|
||||
"label": "Discharge Datetime",
|
||||
"permlevel": 2
|
||||
},
|
||||
{
|
||||
"fieldname": "discharge_ordered_datetime",
|
||||
"fieldtype": "Datetime",
|
||||
"in_list_view": 1,
|
||||
"label": "Discharge Ordered Datetime",
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-03-18 15:59:17.318988",
|
||||
"modified": "2021-08-09 22:49:07.419692",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Healthcare",
|
||||
"name": "Inpatient Record",
|
||||
|
||||
@@ -27,7 +27,7 @@ class InpatientRecord(Document):
|
||||
|
||||
def validate_dates(self):
|
||||
if (getdate(self.expected_discharge) < getdate(self.scheduled_date)) or \
|
||||
(getdate(self.discharge_ordered_date) < getdate(self.scheduled_date)):
|
||||
(getdate(self.discharge_ordered_datetime) < getdate(self.scheduled_date)):
|
||||
frappe.throw(_('Expected and Discharge dates cannot be less than Admission Schedule date'))
|
||||
|
||||
for entry in self.inpatient_occupancies:
|
||||
@@ -58,8 +58,10 @@ class InpatientRecord(Document):
|
||||
admit_patient(self, service_unit, check_in, expected_discharge)
|
||||
|
||||
@frappe.whitelist()
|
||||
def discharge(self):
|
||||
discharge_patient(self)
|
||||
def discharge(self, check_out=now_datetime()):
|
||||
if (getdate(check_out) < getdate(self.admitted_datetime)):
|
||||
frappe.throw(_('Discharge date cannot be less than Admission date'))
|
||||
discharge_patient(self, check_out)
|
||||
|
||||
@frappe.whitelist()
|
||||
def transfer(self, service_unit, check_in, leave_from):
|
||||
@@ -120,10 +122,13 @@ def schedule_inpatient(args):
|
||||
@frappe.whitelist()
|
||||
def schedule_discharge(args):
|
||||
discharge_order = json.loads(args)
|
||||
if not discharge_order or not discharge_order['patient'] or not discharge_order['discharge_ordered_datetime']:
|
||||
frappe.throw(_('Missing required details, did not create schedule discharge'))
|
||||
|
||||
inpatient_record_id = frappe.db.get_value('Patient', discharge_order['patient'], 'inpatient_record')
|
||||
if inpatient_record_id:
|
||||
inpatient_record = frappe.get_doc('Inpatient Record', inpatient_record_id)
|
||||
check_out_inpatient(inpatient_record)
|
||||
check_out_inpatient(inpatient_record, discharge_order['discharge_ordered_datetime'])
|
||||
set_details_from_ip_order(inpatient_record, discharge_order)
|
||||
inpatient_record.status = 'Discharge Scheduled'
|
||||
inpatient_record.save(ignore_permissions = True)
|
||||
@@ -143,18 +148,18 @@ def set_ip_child_records(inpatient_record, inpatient_record_child, encounter_chi
|
||||
table.set(df.fieldname, item.get(df.fieldname))
|
||||
|
||||
|
||||
def check_out_inpatient(inpatient_record):
|
||||
def check_out_inpatient(inpatient_record, discharge_ordered_datetime):
|
||||
if inpatient_record.inpatient_occupancies:
|
||||
for inpatient_occupancy in inpatient_record.inpatient_occupancies:
|
||||
if inpatient_occupancy.left != 1:
|
||||
inpatient_occupancy.left = True
|
||||
inpatient_occupancy.check_out = now_datetime()
|
||||
inpatient_occupancy.check_out = discharge_ordered_datetime
|
||||
frappe.db.set_value("Healthcare Service Unit", inpatient_occupancy.service_unit, "occupancy_status", "Vacant")
|
||||
|
||||
|
||||
def discharge_patient(inpatient_record):
|
||||
def discharge_patient(inpatient_record, check_out):
|
||||
validate_inpatient_invoicing(inpatient_record)
|
||||
inpatient_record.discharge_datetime = now_datetime()
|
||||
inpatient_record.discharge_datetime = check_out
|
||||
inpatient_record.status = "Discharged"
|
||||
|
||||
inpatient_record.save(ignore_permissions = True)
|
||||
|
||||
@@ -29,7 +29,7 @@ class TestInpatientRecord(unittest.TestCase):
|
||||
self.assertEqual("Occupied", frappe.db.get_value("Healthcare Service Unit", service_unit, "occupancy_status"))
|
||||
|
||||
# Discharge
|
||||
schedule_discharge(frappe.as_json({'patient': patient}))
|
||||
schedule_discharge(frappe.as_json({'patient': patient, 'discharge_ordered_datetime': now_datetime()}))
|
||||
self.assertEqual("Vacant", frappe.db.get_value("Healthcare Service Unit", service_unit, "occupancy_status"))
|
||||
|
||||
ip_record1 = frappe.get_doc("Inpatient Record", ip_record.name)
|
||||
@@ -37,7 +37,7 @@ class TestInpatientRecord(unittest.TestCase):
|
||||
self.assertRaises(frappe.ValidationError, ip_record.discharge)
|
||||
mark_invoiced_inpatient_occupancy(ip_record1)
|
||||
|
||||
discharge_patient(ip_record1)
|
||||
discharge_patient(ip_record1, now_datetime())
|
||||
|
||||
self.assertEqual(None, frappe.db.get_value("Patient", patient, "inpatient_record"))
|
||||
self.assertEqual(None, frappe.db.get_value("Patient", patient, "inpatient_status"))
|
||||
@@ -56,7 +56,7 @@ class TestInpatientRecord(unittest.TestCase):
|
||||
admit_patient(ip_record, service_unit, now_datetime())
|
||||
|
||||
# Discharge
|
||||
schedule_discharge(frappe.as_json({"patient": patient}))
|
||||
schedule_discharge(frappe.as_json({"patient": patient, 'discharge_ordered_datetime': now_datetime()}))
|
||||
self.assertEqual("Vacant", frappe.db.get_value("Healthcare Service Unit", service_unit, "occupancy_status"))
|
||||
|
||||
ip_record = frappe.get_doc("Inpatient Record", ip_record.name)
|
||||
@@ -88,12 +88,12 @@ class TestInpatientRecord(unittest.TestCase):
|
||||
self.assertFalse(patient_encounter.name in encounter_ids)
|
||||
|
||||
# Discharge
|
||||
schedule_discharge(frappe.as_json({"patient": patient}))
|
||||
schedule_discharge(frappe.as_json({"patient": patient, 'discharge_ordered_datetime': now_datetime()}))
|
||||
self.assertEqual("Vacant", frappe.db.get_value("Healthcare Service Unit", service_unit, "occupancy_status"))
|
||||
|
||||
ip_record = frappe.get_doc("Inpatient Record", ip_record.name)
|
||||
mark_invoiced_inpatient_occupancy(ip_record)
|
||||
discharge_patient(ip_record)
|
||||
discharge_patient(ip_record, now_datetime())
|
||||
setup_inpatient_settings(key="do_not_bill_inpatient_encounters", value=0)
|
||||
|
||||
def test_validate_overlap_admission(self):
|
||||
|
||||
@@ -147,10 +147,10 @@ class TestPatientAppointment(unittest.TestCase):
|
||||
self.assertEqual(appointment.service_unit, service_unit)
|
||||
|
||||
# Discharge
|
||||
schedule_discharge(frappe.as_json({'patient': patient}))
|
||||
schedule_discharge(frappe.as_json({'patient': patient, 'discharge_ordered_datetime': now_datetime()}))
|
||||
ip_record1 = frappe.get_doc("Inpatient Record", ip_record.name)
|
||||
mark_invoiced_inpatient_occupancy(ip_record1)
|
||||
discharge_patient(ip_record1)
|
||||
discharge_patient(ip_record1, now_datetime())
|
||||
|
||||
def test_invalid_healthcare_service_unit_validation(self):
|
||||
from erpnext.healthcare.doctype.inpatient_record.inpatient_record import admit_patient, discharge_patient, schedule_discharge
|
||||
@@ -174,10 +174,10 @@ class TestPatientAppointment(unittest.TestCase):
|
||||
self.assertRaises(frappe.exceptions.ValidationError, appointment.save)
|
||||
|
||||
# Discharge
|
||||
schedule_discharge(frappe.as_json({'patient': patient}))
|
||||
schedule_discharge(frappe.as_json({'patient': patient, 'discharge_ordered_datetime': now_datetime()}))
|
||||
ip_record1 = frappe.get_doc("Inpatient Record", ip_record.name)
|
||||
mark_invoiced_inpatient_occupancy(ip_record1)
|
||||
discharge_patient(ip_record1)
|
||||
discharge_patient(ip_record1, now_datetime())
|
||||
|
||||
def test_overlap_appointment(self):
|
||||
from erpnext.healthcare.doctype.patient_appointment.patient_appointment import OverlapError
|
||||
|
||||
@@ -257,7 +257,7 @@ var schedule_discharge = function(frm) {
|
||||
var dialog = new frappe.ui.Dialog ({
|
||||
title: 'Inpatient Discharge',
|
||||
fields: [
|
||||
{fieldtype: 'Date', label: 'Discharge Ordered Date', fieldname: 'discharge_ordered_date', default: 'Today', read_only: 1},
|
||||
{fieldtype: 'Datetime', label: 'Discharge Ordered DateTime', fieldname: 'discharge_ordered_datetime', default: frappe.datetime.now_datetime()},
|
||||
{fieldtype: 'Date', label: 'Followup Date', fieldname: 'followup_date'},
|
||||
{fieldtype: 'Column Break'},
|
||||
{fieldtype: 'Small Text', label: 'Discharge Instructions', fieldname: 'discharge_instructions'},
|
||||
@@ -270,7 +270,7 @@ var schedule_discharge = function(frm) {
|
||||
patient: frm.doc.patient,
|
||||
discharge_encounter: frm.doc.name,
|
||||
discharge_practitioner: frm.doc.practitioner,
|
||||
discharge_ordered_date: dialog.get_value('discharge_ordered_date'),
|
||||
discharge_ordered_datetime: dialog.get_value('discharge_ordered_datetime'),
|
||||
followup_date: dialog.get_value('followup_date'),
|
||||
discharge_instructions: dialog.get_value('discharge_instructions'),
|
||||
discharge_note: dialog.get_value('discharge_note')
|
||||
|
||||
@@ -93,12 +93,12 @@ class TestInpatientMedicationOrders(unittest.TestCase):
|
||||
def tearDown(self):
|
||||
if frappe.db.get_value('Patient', self.patient, 'inpatient_record'):
|
||||
# cleanup - Discharge
|
||||
schedule_discharge(frappe.as_json({'patient': self.patient}))
|
||||
schedule_discharge(frappe.as_json({'patient': self.patient, 'discharge_ordered_datetime': now_datetime()}))
|
||||
self.ip_record.reload()
|
||||
mark_invoiced_inpatient_occupancy(self.ip_record)
|
||||
|
||||
self.ip_record.reload()
|
||||
discharge_patient(self.ip_record)
|
||||
discharge_patient(self.ip_record, now_datetime())
|
||||
|
||||
for entry in frappe.get_all('Inpatient Medication Entry'):
|
||||
doc = frappe.get_doc('Inpatient Medication Entry', entry.name)
|
||||
|
||||
@@ -299,4 +299,5 @@ erpnext.patches.v13_0.delete_orphaned_tables
|
||||
erpnext.patches.v13_0.update_export_type_for_gst #2021-08-16
|
||||
erpnext.patches.v13_0.update_tds_check_field #3
|
||||
erpnext.patches.v13_0.update_recipient_email_digest
|
||||
erpnext.patches.v13_0.shopify_deprecation_warning
|
||||
erpnext.patches.v13_0.shopify_deprecation_warning
|
||||
erpnext.patches.v13_0.rename_discharge_ordered_date_in_ip_record
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe.model.utils.rename_field import rename_field
|
||||
|
||||
def execute():
|
||||
frappe.reload_doc("Healthcare", "doctype", "Inpatient Record")
|
||||
if frappe.db.has_column("Inpatient Record", "discharge_ordered_date"):
|
||||
rename_field("Inpatient Record", "discharge_ordered_date", "discharge_ordered_datetime")
|
||||
Reference in New Issue
Block a user