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:
Syed Mujeer Hashmi
2021-08-24 18:35:59 +05:30
committed by GitHub
parent 27fad29ad6
commit 1604b6cc63
11 changed files with 80 additions and 47 deletions

View File

@@ -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)

View File

@@ -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))

View File

@@ -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) {

View File

@@ -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",

View File

@@ -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)

View File

@@ -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):

View File

@@ -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

View File

@@ -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')

View File

@@ -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)

View File

@@ -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

View File

@@ -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")