From 1604b6cc63449b81619ca1f66182b46b0fd48b1b Mon Sep 17 00:00:00 2001 From: Syed Mujeer Hashmi Date: Tue, 24 Aug 2021 18:35:59 +0530 Subject: [PATCH] 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 * fix: Sider issues and test cases related to this patch Signed-off-by: Syed Mujeer Hashmi Co-authored-by: Rucha Mahabal Co-authored-by: Jannat Patel <31363128+pateljannat@users.noreply.github.com> --- .../test_inpatient_medication_entry.py | 4 +- .../test_inpatient_medication_order.py | 8 ++-- .../inpatient_record/inpatient_record.js | 37 ++++++++++++++----- .../inpatient_record/inpatient_record.json | 20 +++++----- .../inpatient_record/inpatient_record.py | 21 +++++++---- .../inpatient_record/test_inpatient_record.py | 10 ++--- .../test_patient_appointment.py | 8 ++-- .../patient_encounter/patient_encounter.js | 4 +- .../test_inpatient_medication_orders.py | 4 +- erpnext/patches.txt | 3 +- ...ame_discharge_ordered_date_in_ip_record.py | 8 ++++ 11 files changed, 80 insertions(+), 47 deletions(-) create mode 100644 erpnext/patches/v13_0/rename_discharge_ordered_date_in_ip_record.py diff --git a/erpnext/healthcare/doctype/inpatient_medication_entry/test_inpatient_medication_entry.py b/erpnext/healthcare/doctype/inpatient_medication_entry/test_inpatient_medication_entry.py index ff9e21252a1..0c463ddc029 100644 --- a/erpnext/healthcare/doctype/inpatient_medication_entry/test_inpatient_medication_entry.py +++ b/erpnext/healthcare/doctype/inpatient_medication_entry/test_inpatient_medication_entry.py @@ -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) diff --git a/erpnext/healthcare/doctype/inpatient_medication_order/test_inpatient_medication_order.py b/erpnext/healthcare/doctype/inpatient_medication_order/test_inpatient_medication_order.py index 798976283b3..ec1a28034e3 100644 --- a/erpnext/healthcare/doctype/inpatient_medication_order/test_inpatient_medication_order.py +++ b/erpnext/healthcare/doctype/inpatient_medication_order/test_inpatient_medication_order.py @@ -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)) diff --git a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.js b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.js index 60f0f9d56d6..750279e348b 100644 --- a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.js +++ b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.js @@ -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) { diff --git a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.json b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.json index 0e1c2ba7664..03ecf4fb018 100644 --- a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.json +++ b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.json @@ -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", diff --git a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py index f4d1eaf2e3f..2cdfa04d5c0 100644 --- a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py +++ b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py @@ -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) diff --git a/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py b/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py index b4a961264f2..9b5cd717a0c 100644 --- a/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py +++ b/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py @@ -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): diff --git a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py index 39c7ece285b..18dc5bd5cea 100644 --- a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py +++ b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py @@ -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 diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js index aaeaa692e63..5b950a8809e 100644 --- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js +++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js @@ -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') diff --git a/erpnext/healthcare/report/inpatient_medication_orders/test_inpatient_medication_orders.py b/erpnext/healthcare/report/inpatient_medication_orders/test_inpatient_medication_orders.py index fae5ecef843..0a538fdff0d 100644 --- a/erpnext/healthcare/report/inpatient_medication_orders/test_inpatient_medication_orders.py +++ b/erpnext/healthcare/report/inpatient_medication_orders/test_inpatient_medication_orders.py @@ -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) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 484d6e1e601..73667561904 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -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 \ No newline at end of file +erpnext.patches.v13_0.shopify_deprecation_warning +erpnext.patches.v13_0.rename_discharge_ordered_date_in_ip_record diff --git a/erpnext/patches/v13_0/rename_discharge_ordered_date_in_ip_record.py b/erpnext/patches/v13_0/rename_discharge_ordered_date_in_ip_record.py new file mode 100644 index 00000000000..52a5885fc2f --- /dev/null +++ b/erpnext/patches/v13_0/rename_discharge_ordered_date_in_ip_record.py @@ -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")