diff --git a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.json b/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.json index ea4ae846f7d6..9ee865a62a45 100644 --- a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.json +++ b/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.json @@ -12,7 +12,6 @@ "engine": "InnoDB", "field_order": [ "healthcare_service_unit_name", - "parent_healthcare_service_unit", "is_group", "service_unit_type", "allow_appointments", @@ -20,8 +19,10 @@ "inpatient_occupancy", "occupancy_status", "column_break_9", - "warehouse", "company", + "warehouse", + "tree_details_section", + "parent_healthcare_service_unit", "lft", "rgt", "old_parent" @@ -51,7 +52,6 @@ "depends_on": "eval:doc.inpatient_occupancy != 1 && doc.allow_appointments != 1", "fieldname": "is_group", "fieldtype": "Check", - "in_list_view": 1, "label": "Is Group" }, { @@ -63,12 +63,12 @@ "options": "Healthcare Service Unit Type" }, { - "bold": 1, "default": "0", "depends_on": "eval:doc.is_group != 1 && doc.inpatient_occupancy != 1", "fetch_from": "service_unit_type.allow_appointments", "fieldname": "allow_appointments", "fieldtype": "Check", + "in_list_view": 1, "label": "Allow Appointments", "no_copy": 1, "read_only": 1 @@ -90,6 +90,7 @@ "fetch_from": "service_unit_type.inpatient_occupancy", "fieldname": "inpatient_occupancy", "fieldtype": "Check", + "in_list_view": 1, "label": "Inpatient Occupancy", "no_copy": 1, "read_only": 1, @@ -101,7 +102,7 @@ "fieldtype": "Select", "label": "Occupancy Status", "no_copy": 1, - "options": "\nVacant\nOccupied", + "options": "Vacant\nOccupied", "read_only": 1 }, { @@ -157,10 +158,16 @@ "options": "Healthcare Service Unit", "print_hide": 1, "report_hide": 1 + }, + { + "collapsible": 1, + "fieldname": "tree_details_section", + "fieldtype": "Section Break", + "label": "Tree Details" } ], "links": [], - "modified": "2020-03-26 16:13:08.675952", + "modified": "2020-05-20 18:26:56.065543", "modified_by": "Administrator", "module": "Healthcare", "name": "Healthcare Service Unit", diff --git a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.py b/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.py index 13cc43d2be49..9e0417a2bef2 100644 --- a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.py +++ b/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.py @@ -22,10 +22,16 @@ def on_update(self): super(HealthcareServiceUnit, self).on_update() self.validate_one_root() - def validate(self): + def after_insert(self): if self.is_group: self.allow_appointments = 0 self.overlap_appointments = 0 self.inpatient_occupancy = 0 - elif not self.allow_appointments: - self.overlap_appointments = 0 + elif self.service_unit_type: + service_unit_type = frappe.get_doc('Healthcare Service Unit Type', self.service_unit_type) + self.allow_appointments = service_unit_type.allow_appointments + self.overlap_appointments = service_unit_type.overlap_appointments + self.inpatient_occupancy = service_unit_type.inpatient_occupancy + if self.inpatient_occupancy: + self.occupancy_status = 'Vacant' + self.overlap_appointments = 0 diff --git a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.json b/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.json index 5fa47d91bc29..4b8503d02869 100644 --- a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.json +++ b/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.json @@ -31,6 +31,7 @@ "fieldtype": "Data", "in_list_view": 1, "label": "Service Unit Type", + "no_copy": 1, "reqd": 1, "unique": 1 }, @@ -40,8 +41,7 @@ "depends_on": "eval:doc.inpatient_occupancy != 1", "fieldname": "allow_appointments", "fieldtype": "Check", - "label": "Allow Appointments", - "no_copy": 1 + "label": "Allow Appointments" }, { "bold": 1, @@ -49,8 +49,7 @@ "depends_on": "eval:doc.allow_appointments == 1 && doc.inpatient_occupany != 1", "fieldname": "overlap_appointments", "fieldtype": "Check", - "label": "Allow Overlap", - "no_copy": 1 + "label": "Allow Overlap" }, { "bold": 1, @@ -58,8 +57,7 @@ "depends_on": "eval:doc.allow_appointments != 1", "fieldname": "inpatient_occupancy", "fieldtype": "Check", - "label": "Inpatient Occupancy", - "no_copy": 1 + "label": "Inpatient Occupancy" }, { "bold": 1, @@ -79,6 +77,7 @@ "fieldname": "item", "fieldtype": "Link", "label": "Item", + "no_copy": 1, "options": "Item", "read_only": 1 }, @@ -86,7 +85,8 @@ "fieldname": "item_code", "fieldtype": "Data", "label": "Item Code", - "mandatory_depends_on": "eval: doc.is_billable == 1" + "mandatory_depends_on": "eval: doc.is_billable == 1", + "no_copy": 1 }, { "fieldname": "item_group", @@ -138,7 +138,7 @@ } ], "links": [], - "modified": "2020-01-30 16:06:00.624496", + "modified": "2020-05-20 15:31:09.627516", "modified_by": "Administrator", "module": "Healthcare", "name": "Healthcare Service Unit Type", diff --git a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.py b/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.py index 286ecc0ff8e3..bb86eaacc40f 100644 --- a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.py +++ b/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.py @@ -10,6 +10,22 @@ class HealthcareServiceUnitType(Document): def validate(self): + if self.allow_appointments and self.inpatient_occupancy: + frappe.msgprint( + _('Healthcare Service Unit Type cannot have both {0} and {1}').format( + frappe.bold('Allow Appointments'), frappe.bold('Inpatient Occupancy')), + raise_exception=1, title=_('Validation Error'), indicator='red' + ) + elif not self.allow_appointments and not self.inpatient_occupancy: + frappe.msgprint( + _('Healthcare Service Unit Type must allow atleast one among {0} and {1}').format( + frappe.bold('Allow Appointments'), frappe.bold('Inpatient Occupancy')), + raise_exception=1, title=_('Validation Error'), indicator='red' + ) + + if not self.allow_appointments: + self.overlap_appointments = 0 + if self.is_billable: if self.disabled: frappe.db.set_value('Item', self.item, 'disabled', 1) diff --git a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.js b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.js index 67c12f6c14d4..971e166067e5 100644 --- a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.js +++ b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.js @@ -2,22 +2,37 @@ // For license information, please see license.txt frappe.ui.form.on('Inpatient Record', { + setup: function(frm) { + frm.get_field('drug_prescription').grid.editable_fields = [ + {fieldname: 'drug_code', columns: 2}, + {fieldname: 'drug_name', columns: 2}, + {fieldname: 'dosage', columns: 2}, + {fieldname: 'period', columns: 2} + ]; + }, refresh: function(frm) { - if(!frm.doc.__islocal && frm.doc.status == "Admission Scheduled"){ + if (!frm.doc.__islocal && (frm.doc.status == 'Admission Scheduled' || frm.doc.status == 'Admitted')) { + frm.enable_save(); + } else { + frm.disable_save(); + } + + if (!frm.doc.__islocal && frm.doc.status == 'Admission Scheduled') { frm.add_custom_button(__('Admit'), function() { admit_patient_dialog(frm); } ); - frm.set_df_property("btn_transfer", "hidden", 1); } - if(!frm.doc.__islocal && frm.doc.status == "Discharge Scheduled"){ + + if (!frm.doc.__islocal && frm.doc.status == 'Discharge Scheduled') { frm.add_custom_button(__('Discharge'), function() { discharge_patient(frm); } ); - frm.set_df_property("btn_transfer", "hidden", 0); } - if(!frm.doc.__islocal && (frm.doc.status == "Discharged" || frm.doc.status == "Discharge Scheduled")){ + if (!frm.doc.__islocal && frm.doc.status != 'Admitted') { frm.disable_save(); - frm.set_df_property("btn_transfer", "hidden", 1); + frm.set_df_property('btn_transfer', 'hidden', 1); + } else { + frm.set_df_property('btn_transfer', 'hidden', 0); } }, btn_transfer: function(frm) { @@ -25,39 +40,47 @@ frappe.ui.form.on('Inpatient Record', { } }); -var discharge_patient = function(frm) { +let discharge_patient = function(frm) { frappe.call({ doc: frm.doc, - method: "discharge", + method: 'discharge', callback: function(data) { - if(!data.exc){ + if (!data.exc) { frm.reload_doc(); } }, freeze: true, - freeze_message: "Process Discharge" + freeze_message: __('Processing Inpatient Discharge') }); }; -var admit_patient_dialog = function(frm){ - var dialog = new frappe.ui.Dialog({ +let admit_patient_dialog = function(frm) { + let dialog = new frappe.ui.Dialog({ title: 'Admit Patient', width: 100, fields: [ - {fieldtype: "Link", label: "Service Unit Type", fieldname: "service_unit_type", options: "Healthcare Service Unit Type"}, - {fieldtype: "Link", label: "Service Unit", fieldname: "service_unit", options: "Healthcare Service Unit", reqd: 1}, - {fieldtype: "Datetime", label: "Admission Datetime", fieldname: "check_in", reqd: 1}, - {fieldtype: "Date", label: "Expected Discharge", fieldname: "expected_discharge"} + {fieldtype: 'Link', label: 'Service Unit Type', fieldname: 'service_unit_type', + options: 'Healthcare Service Unit Type', default: frm.doc.admission_service_unit_type + }, + {fieldtype: 'Link', label: 'Service Unit', fieldname: 'service_unit', + options: 'Healthcare Service Unit', reqd: 1 + }, + {fieldtype: 'Datetime', label: 'Admission Datetime', fieldname: 'check_in', + reqd: 1, default: frappe.datetime.now_datetime() + }, + {fieldtype: 'Date', label: 'Expected Discharge', fieldname: 'expected_discharge', + default: frm.doc.expected_length_of_stay ? frappe.datetime.add_days(frappe.datetime.now_datetime(), frm.doc.expected_length_of_stay) : '' + } ], - primary_action_label: __("Admit"), + primary_action_label: __('Admit'), primary_action : function(){ - var service_unit = dialog.get_value('service_unit'); - var check_in = dialog.get_value('check_in'); - var expected_discharge = null; - if(dialog.get_value('expected_discharge')){ + let service_unit = dialog.get_value('service_unit'); + let check_in = dialog.get_value('check_in'); + let expected_discharge = null; + if (dialog.get_value('expected_discharge')) { expected_discharge = dialog.get_value('expected_discharge'); } - if(!service_unit && !check_in){ + if (!service_unit && !check_in) { return; } frappe.call({ @@ -69,32 +92,33 @@ var admit_patient_dialog = function(frm){ 'expected_discharge': expected_discharge }, callback: function(data) { - if(!data.exc){ + if (!data.exc) { frm.reload_doc(); } }, freeze: true, - freeze_message: "Process Admission" + freeze_message: __('Processing Patient Admission') }); frm.refresh_fields(); dialog.hide(); } }); - dialog.fields_dict["service_unit_type"].get_query = function(){ + dialog.fields_dict['service_unit_type'].get_query = function() { return { filters: { - "inpatient_occupancy": 1, - "allow_appointments": 0 + 'inpatient_occupancy': 1, + 'allow_appointments': 0 } }; }; - dialog.fields_dict["service_unit"].get_query = function(){ + dialog.fields_dict['service_unit'].get_query = function() { return { filters: { - "is_group": 0, - "service_unit_type": dialog.get_value("service_unit_type"), - "occupancy_status" : "Vacant" + 'is_group': 0, + 'company': frm.doc.company, + 'service_unit_type': dialog.get_value('service_unit_type'), + 'occupancy_status' : 'Vacant' } }; }; @@ -102,21 +126,21 @@ var admit_patient_dialog = function(frm){ dialog.show(); }; -var transfer_patient_dialog = function(frm){ - var dialog = new frappe.ui.Dialog({ +let transfer_patient_dialog = function(frm) { + let dialog = new frappe.ui.Dialog({ title: 'Transfer Patient', width: 100, fields: [ - {fieldtype: "Link", label: "Leave From", fieldname: "leave_from", options: "Healthcare Service Unit", reqd: 1, read_only:1}, - {fieldtype: "Link", label: "Service Unit Type", fieldname: "service_unit_type", options: "Healthcare Service Unit Type"}, - {fieldtype: "Link", label: "Transfer To", fieldname: "service_unit", options: "Healthcare Service Unit", reqd: 1}, - {fieldtype: "Datetime", label: "Check In", fieldname: "check_in", reqd: 1} + {fieldtype: 'Link', label: 'Leave From', fieldname: 'leave_from', options: 'Healthcare Service Unit', reqd: 1, read_only:1}, + {fieldtype: 'Link', label: 'Service Unit Type', fieldname: 'service_unit_type', options: 'Healthcare Service Unit Type'}, + {fieldtype: 'Link', label: 'Transfer To', fieldname: 'service_unit', options: 'Healthcare Service Unit', reqd: 1}, + {fieldtype: 'Datetime', label: 'Check In', fieldname: 'check_in', reqd: 1} ], - primary_action_label: __("Transfer"), - primary_action : function(){ - var service_unit = null; - var check_in = dialog.get_value('check_in'); - var leave_from = null; + primary_action_label: __('Transfer'), + primary_action : function() { + let service_unit = null; + let check_in = dialog.get_value('check_in'); + let leave_from = null; if(dialog.get_value('leave_from')){ leave_from = dialog.get_value('leave_from'); } @@ -135,47 +159,47 @@ var transfer_patient_dialog = function(frm){ 'leave_from': leave_from }, callback: function(data) { - if(!data.exc){ + if (!data.exc) { frm.reload_doc(); } }, freeze: true, - freeze_message: "Process Transfer" + freeze_message: __('Process Transfer') }); frm.refresh_fields(); dialog.hide(); } }); - dialog.fields_dict["leave_from"].get_query = function(){ + dialog.fields_dict['leave_from'].get_query = function(){ return { - query : "erpnext.healthcare.doctype.inpatient_record.inpatient_record.get_leave_from", + query : 'erpnext.healthcare.doctype.inpatient_record.inpatient_record.get_leave_from', filters: {docname:frm.doc.name} }; }; - dialog.fields_dict["service_unit_type"].get_query = function(){ + dialog.fields_dict['service_unit_type'].get_query = function(){ return { filters: { - "inpatient_occupancy": 1, - "allow_appointments": 0 + 'inpatient_occupancy': 1, + 'allow_appointments': 0 } }; }; - dialog.fields_dict["service_unit"].get_query = function(){ + dialog.fields_dict['service_unit'].get_query = function(){ return { filters: { - "is_group": 0, - "service_unit_type": dialog.get_value("service_unit_type"), - "occupancy_status" : "Vacant" + 'is_group': 0, + 'service_unit_type': dialog.get_value('service_unit_type'), + 'occupancy_status' : 'Vacant' } }; }; dialog.show(); - var not_left_service_unit = null; - for(let inpatient_occupancy in frm.doc.inpatient_occupancies){ - if(frm.doc.inpatient_occupancies[inpatient_occupancy].left != 1){ + let not_left_service_unit = null; + for (let inpatient_occupancy in frm.doc.inpatient_occupancies) { + if (frm.doc.inpatient_occupancies[inpatient_occupancy].left != 1) { not_left_service_unit = frm.doc.inpatient_occupancies[inpatient_occupancy].service_unit; } } diff --git a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.json b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.json index c1b516d53638..5ced845c1b05 100644 --- a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.json +++ b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.json @@ -22,17 +22,41 @@ "scheduled_date", "admitted_datetime", "expected_discharge", - "discharge_date", "references", - "cb_admission", - "admission_practitioner", "admission_encounter", - "cb_discharge", - "discharge_practitioner", - "discharge_encounter", + "admission_practitioner", + "medical_department", + "admission_ordered_for", + "expected_length_of_stay", + "admission_service_unit_type", + "cb_admission", + "primary_practitioner", + "secondary_practitioner", + "admission_instruction", + "encounter_details_section", + "chief_complaint", + "column_break_29", + "diagnosis", + "medication_section", + "drug_prescription", + "investigations_section", + "lab_test_prescription", + "procedures_section", + "procedure_prescription", + "rehabilitation_section", + "therapy_plan", + "therapies", "sb_inpatient_occupancy", "inpatient_occupancies", "btn_transfer", + "sb_discharge_details", + "discharge_ordered_date", + "discharge_practitioner", + "discharge_encounter", + "discharge_date", + "cb_discharge", + "discharge_instructions", + "followup_date", "sb_discharge_note", "discharge_note" ], @@ -54,7 +78,8 @@ "in_list_view": 1, "label": "Patient", "options": "Patient", - "reqd": 1 + "reqd": 1, + "set_only_once": 1 }, { "fetch_from": "patient.patient_name", @@ -108,11 +133,31 @@ "label": "Phone", "read_only": 1 }, + { + "fieldname": "medical_department", + "fieldtype": "Link", + "label": "Medical Department", + "options": "Medical Department", + "set_only_once": 1 + }, + { + "fieldname": "primary_practitioner", + "fieldtype": "Link", + "label": "Healthcare Practitioner (Primary)", + "options": "Healthcare Practitioner" + }, + { + "fieldname": "secondary_practitioner", + "fieldtype": "Link", + "label": "Healthcare Practitioner (Secondary)", + "options": "Healthcare Practitioner" + }, { "fieldname": "column_break_8", "fieldtype": "Column Break" }, { + "default": "Admission Scheduled", "fieldname": "status", "fieldtype": "Select", "in_list_view": 1, @@ -126,37 +171,45 @@ "fieldtype": "Date", "in_list_view": 1, "label": "Admission Schedule Date", + "read_only": 1, "reqd": 1 }, { - "default": "Today", + "fieldname": "admission_ordered_for", + "fieldtype": "Date", + "label": "Admission Ordered For", + "read_only": 1 + }, + { "fieldname": "admitted_datetime", "fieldtype": "Datetime", "in_list_view": 1, - "label": "Admitted Datetime" + "label": "Admitted Datetime", + "read_only": 1 }, { - "fieldname": "expected_discharge", - "fieldtype": "Date", - "in_list_view": 1, - "label": "Expected Discharge" + "depends_on": "eval:(doc.expected_length_of_stay > 0)", + "fieldname": "expected_length_of_stay", + "fieldtype": "Int", + "label": "Expected Length of Stay", + "set_only_once": 1 }, { - "fieldname": "discharge_date", + "fieldname": "expected_discharge", "fieldtype": "Date", "in_list_view": 1, - "label": "Discharge Date" + "label": "Expected Discharge", + "read_only": 1 }, { "collapsible": 1, "fieldname": "references", "fieldtype": "Section Break", - "label": "References" + "label": "Admission Order Details" }, { "fieldname": "cb_admission", - "fieldtype": "Column Break", - "label": "Admission" + "fieldtype": "Column Break" }, { "fieldname": "admission_practitioner", @@ -172,10 +225,22 @@ "options": "Patient Encounter", "read_only": 1 }, + { + "fieldname": "chief_complaint", + "fieldtype": "Table MultiSelect", + "label": "Chief Complaint", + "options": "Patient Encounter Symptom", + "permlevel": 1 + }, + { + "fieldname": "admission_instruction", + "fieldtype": "Small Text", + "label": "Admission Instruction", + "set_only_once": 1 + }, { "fieldname": "cb_discharge", - "fieldtype": "Column Break", - "label": "Discharge" + "fieldtype": "Column Break" }, { "fieldname": "discharge_practitioner", @@ -192,10 +257,57 @@ "read_only": 1 }, { + "collapsible": 1, + "fieldname": "medication_section", + "fieldtype": "Section Break", + "label": "Medications", + "permlevel": 1 + }, + { + "fieldname": "drug_prescription", + "fieldtype": "Table", + "options": "Drug Prescription", + "permlevel": 1 + }, + { + "collapsible": 1, + "fieldname": "investigations_section", + "fieldtype": "Section Break", + "label": "Investigations", + "permlevel": 1 + }, + { + "fieldname": "lab_test_prescription", + "fieldtype": "Table", + "options": "Lab Prescription", + "permlevel": 1 + }, + { + "collapsible": 1, + "fieldname": "procedures_section", + "fieldtype": "Section Break", + "label": "Procedures", + "permlevel": 1 + }, + { + "fieldname": "procedure_prescription", + "fieldtype": "Table", + "options": "Procedure Prescription", + "permlevel": 1 + }, + { + "depends_on": "eval:(doc.status != \"Admission Scheduled\")", "fieldname": "sb_inpatient_occupancy", "fieldtype": "Section Break", "label": "Inpatient Occupancy" }, + { + "fieldname": "admission_service_unit_type", + "fieldtype": "Link", + "label": "Admission Service Unit Type", + "options": "Healthcare Service Unit Type", + "read_only": 1 + }, { "fieldname": "inpatient_occupancies", "fieldtype": "Table", @@ -208,14 +320,15 @@ "label": "Transfer" }, { - "depends_on": "eval:doc.status != \"Admission Scheduled\"", + "depends_on": "eval:(doc.status == \"Discharge Scheduled\" || doc.status == \"Discharged\")", "fieldname": "sb_discharge_note", "fieldtype": "Section Break", - "label": "Discharge Note" + "label": "Discharge Notes" }, { "fieldname": "discharge_note", - "fieldtype": "Text Editor" + "fieldtype": "Text Editor", + "permlevel": 1 }, { "fetch_from": "admission_encounter.company", @@ -224,10 +337,81 @@ "in_standard_filter": 1, "label": "Company", "options": "Company" + }, + { + "collapsible": 1, + "collapsible_depends_on": "eval:(doc.status == \"Admitted\")", + "fieldname": "encounter_details_section", + "fieldtype": "Section Break", + "label": "Encounter Impression", + "permlevel": 1 + }, + { + "fieldname": "column_break_29", + "fieldtype": "Column Break" + }, + { + "fieldname": "diagnosis", + "fieldtype": "Table MultiSelect", + "label": "Diagnosis", + "options": "Patient Encounter Diagnosis", + "permlevel": 1 + }, + { + "fieldname": "followup_date", + "fieldtype": "Date", + "label": "Follow Up Date" + }, + { + "collapsible": 1, + "depends_on": "eval:(doc.status == \"Discharge Scheduled\" || doc.status == \"Discharged\")", + "fieldname": "sb_discharge_details", + "fieldtype": "Section Break", + "label": "Discharge Detials" + }, + { + "fieldname": "discharge_instructions", + "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", + "fieldtype": "Section Break", + "label": "Rehabilitation", + "permlevel": 1 + }, + { + "fieldname": "therapy_plan", + "fieldtype": "Link", + "hidden": 1, + "label": "Therapy Plan", + "options": "Therapy Plan", + "permlevel": 1, + "read_only": 1 + }, + { + "fieldname": "therapies", + "fieldtype": "Table", + "options": "Therapy Plan Detail", + "permlevel": 1 + }, + { + "fieldname": "discharge_date", + "fieldtype": "Date", + "label": "Discharge Date", + "read_only": 1 } ], "links": [], - "modified": "2020-04-07 13:13:39.351977", + "modified": "2020-05-21 02:26:22.144575", "modified_by": "Administrator", "module": "Healthcare", "name": "Inpatient Record", @@ -244,6 +428,42 @@ "role": "Healthcare Administrator", "share": 1, "write": 1 + }, + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Physician", + "share": 1, + "write": 1 + }, + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Nursing User", + "share": 1, + "write": 1 + }, + { + "permlevel": 1, + "read": 1, + "role": "Physician", + "write": 1 + }, + { + "permlevel": 1, + "read": 1, + "report": 1, + "role": "Nursing User" } ], "restrict_to_domain": "Healthcare", diff --git a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py index 835b38bedf86..cf63b65f4d68 100644 --- a/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py +++ b/erpnext/healthcare/doctype/inpatient_record/inpatient_record.py @@ -3,7 +3,7 @@ # For license information, please see license.txt from __future__ import unicode_literals -import frappe +import frappe, json from frappe import _ from frappe.utils import today, now_datetime, getdate from frappe.model.document import Document @@ -11,8 +11,12 @@ class InpatientRecord(Document): def after_insert(self): - frappe.db.set_value("Patient", self.patient, "inpatient_status", "Admission Scheduled") - frappe.db.set_value("Patient", self.patient, "inpatient_record", self.name) + frappe.db.set_value('Patient', self.patient, 'inpatient_record', self.name) + frappe.db.set_value('Patient', self.patient, 'inpatient_status', self.status) + + if self.admission_encounter: # Update encounter + frappe.db.set_value('Patient Encounter', self.admission_encounter, 'inpatient_record', self.name) + frappe.db.set_value('Patient Encounter', self.admission_encounter, 'inpatient_status', self.status) def validate(self): self.validate_dates() @@ -22,13 +26,10 @@ def validate(self): frappe.db.set_value("Patient", self.patient, "inpatient_record", None) def validate_dates(self): - if (getdate(self.scheduled_date) < getdate(today())) or \ - (getdate(self.admitted_datetime) < getdate(today())): - frappe.throw(_("Scheduled and Admitted dates can not be less than today")) if (getdate(self.expected_discharge) < getdate(self.scheduled_date)) or \ - (getdate(self.discharge_date) < getdate(self.scheduled_date)): - frappe.throw(_("Expected and Discharge dates cannot be less than Admission Schedule date")) - + (getdate(self.discharge_ordered_date) < getdate(self.scheduled_date)): + frappe.throw(_('Expected and Discharge dates cannot be less than Admission Schedule date')) + def validate_already_scheduled_or_admitted(self): query = """ select name, status @@ -59,37 +60,76 @@ def transfer(self, service_unit, check_in, leave_from): if service_unit: transfer_patient(self, service_unit, check_in) + @frappe.whitelist() -def schedule_inpatient(patient, encounter_id, practitioner): - patient_obj = frappe.get_doc('Patient', patient) +def schedule_inpatient(args): + admission_order = json.loads(args) # admission order via Encounter + if not admission_order or not admission_order['patient'] or not admission_order['admission_encounter']: + frappe.throw(_('Missing required details, did not create Inpatient Record')) + inpatient_record = frappe.new_doc('Inpatient Record') - inpatient_record.patient = patient - inpatient_record.patient_name = patient_obj.patient_name - inpatient_record.gender = patient_obj.sex - inpatient_record.blood_group = patient_obj.blood_group - inpatient_record.dob = patient_obj.dob - inpatient_record.mobile = patient_obj.mobile - inpatient_record.email = patient_obj.email - inpatient_record.phone = patient_obj.phone - inpatient_record.status = "Admission Scheduled" + + # Admission order details + set_details_from_ip_order(inpatient_record, admission_order) + + # Patient details + patient = frappe.get_doc('Patient', admission_order['patient']) + inpatient_record.patient = patient.name + inpatient_record.patient_name = patient.patient_name + inpatient_record.gender = patient.sex + inpatient_record.blood_group = patient.blood_group + inpatient_record.dob = patient.dob + inpatient_record.mobile = patient.mobile + inpatient_record.email = patient.email + inpatient_record.phone = patient.phone inpatient_record.scheduled_date = today() - inpatient_record.admission_practitioner = practitioner - inpatient_record.admission_encounter = encounter_id + + # Set encounter detials + encounter = frappe.get_doc('Patient Encounter', admission_order['admission_encounter']) + if encounter and encounter.symptoms: # Symptoms + set_ip_child_records(inpatient_record, 'chief_complaint', encounter.symptoms) + + if encounter and encounter.diagnosis: # Diagnosis + set_ip_child_records(inpatient_record, 'diagnosis', encounter.diagnosis) + + if encounter and encounter.drug_prescription: # Medication + set_ip_child_records(inpatient_record, 'drug_prescription', encounter.drug_prescription) + + if encounter and encounter.lab_test_prescription: # Lab Tests + set_ip_child_records(inpatient_record, 'lab_test_prescription', encounter.lab_test_prescription) + + if encounter and encounter.procedure_prescription: # Procedure Prescription + set_ip_child_records(inpatient_record, 'procedure_prescription', encounter.procedure_prescription) + + if encounter and encounter.therapies: # Therapies + inpatient_record.therapy_plan = encounter.therapy_plan + set_ip_child_records(inpatient_record, 'therapies', encounter.therapies) + + inpatient_record.status = 'Admission Scheduled' inpatient_record.save(ignore_permissions = True) @frappe.whitelist() -def schedule_discharge(patient, encounter_id=None, practitioner=None): - inpatient_record_id = frappe.db.get_value('Patient', patient, 'inpatient_record') +def schedule_discharge(args): + discharge_order = json.loads(args) + 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) - inpatient_record.discharge_practitioner = practitioner - inpatient_record.discharge_encounter = encounter_id - inpatient_record.status = "Discharge Scheduled" - + inpatient_record = frappe.get_doc('Inpatient Record', inpatient_record_id) check_out_inpatient(inpatient_record) - + set_details_from_ip_order(inpatient_record, discharge_order) + inpatient_record.status = 'Discharge Scheduled' inpatient_record.save(ignore_permissions = True) - frappe.db.set_value("Patient", patient, "inpatient_status", "Discharge Scheduled") + frappe.db.set_value('Patient', discharge_order['patient'], 'inpatient_status', inpatient_record.status) + frappe.db.set_value('Patient Encounter', inpatient_record.discharge_encounter, 'inpatient_status', inpatient_record.status) + +def set_details_from_ip_order(inpatient_record, ip_order): + for key in ip_order: + inpatient_record.set(key, ip_order[key]) + +def set_ip_child_records(inpatient_record, inpatient_record_child, encounter_child): + for item in encounter_child: + table = inpatient_record.append(inpatient_record_child) + for df in table.meta.get('fields'): + table.set(df.fieldname, item.get(df.fieldname)) def check_out_inpatient(inpatient_record): if inpatient_record.inpatient_occupancies: @@ -128,7 +168,7 @@ def validate_invoiced_inpatient(inpatient_record): if pending_invoices: frappe.throw(_("Can not mark Inpatient Record Discharged, there are Unbilled Invoices {0}").format(", " - .join(pending_invoices))) + .join(pending_invoices)), title=_('Unbilled Invoices')) def get_pending_doc(doc, doc_name_list, pending_invoices): if doc_name_list: @@ -144,19 +184,19 @@ def get_pending_doc(doc, doc_name_list, pending_invoices): 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}) + return frappe.db.get_list(doc, filters = {'patient': inpatient_record.patient, + 'inpatient_record': inpatient_record.name, 'docstatus': 1, 'invoiced': 0}) def admit_patient(inpatient_record, service_unit, check_in, expected_discharge=None): inpatient_record.admitted_datetime = check_in - inpatient_record.status = "Admitted" + inpatient_record.status = 'Admitted' inpatient_record.expected_discharge = expected_discharge inpatient_record.set('inpatient_occupancies', []) transfer_patient(inpatient_record, service_unit, check_in) - frappe.db.set_value("Patient", inpatient_record.patient, "inpatient_status", "Admitted") - frappe.db.set_value("Patient", inpatient_record.patient, "inpatient_record", inpatient_record.name) + frappe.db.set_value('Patient', inpatient_record.patient, 'inpatient_status', 'Admitted') + frappe.db.set_value('Patient', inpatient_record.patient, 'inpatient_record', inpatient_record.name) def transfer_patient(inpatient_record, service_unit, check_in): item_line = inpatient_record.append('inpatient_occupancies', {}) diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json index b8a400c6b7a5..ac35acc21acb 100644 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json +++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json @@ -39,9 +39,9 @@ "section_break_16", "mode_of_payment", "billing_item", + "invoiced", "column_break_2", "paid_amount", - "invoiced", "ref_sales_invoice", "section_break_3", "referring_practitioner", @@ -348,7 +348,7 @@ } ], "links": [], - "modified": "2020-04-27 21:36:06.404062", + "modified": "2020-05-21 03:04:21.400893", "modified_by": "Administrator", "module": "Healthcare", "name": "Patient Appointment", diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py index 9eb6e77c855e..512fb48360fd 100755 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py +++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py @@ -447,7 +447,7 @@ def get_prescribed_therapies(patient): """ SELECT t.therapy_type, t.name, t.parent, e.practitioner, - e.encounter_date, e.therapy_plan, e.visit_department + e.encounter_date, e.therapy_plan, e.medical_department FROM `tabPatient Encounter` e, `tabTherapy Plan Detail` t WHERE diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js index 2410f8e10dd0..edcee99d4bc3 100644 --- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js +++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js @@ -180,35 +180,114 @@ frappe.ui.form.on('Patient Encounter', { } }); -let schedule_inpatient = function(frm) { - frappe.call({ - method: 'erpnext.healthcare.doctype.inpatient_record.inpatient_record.schedule_inpatient', - args: {patient: frm.doc.patient, encounter_id: frm.doc.name, practitioner: frm.doc.practitioner}, - callback: function(data) { - if (!data.exc) { - frm.reload_doc(); +var schedule_inpatient = function(frm) { + var dialog = new frappe.ui.Dialog({ + title: 'Patient Admission', + fields: [ + {fieldtype: 'Link', label: 'Medical Department', fieldname: 'medical_department', options: 'Medical Department', reqd: 1}, + {fieldtype: 'Link', label: 'Healthcare Practitioner (Primary)', fieldname: 'primary_practitioner', options: 'Healthcare Practitioner', reqd: 1}, + {fieldtype: 'Link', label: 'Healthcare Practitioner (Secondary)', fieldname: 'secondary_practitioner', options: 'Healthcare Practitioner'}, + {fieldtype: 'Column Break'}, + {fieldtype: 'Date', label: 'Admission Ordered For', fieldname: 'admission_ordered_for', default: 'Today'}, + {fieldtype: 'Link', label: 'Service Unit Type', fieldname: 'service_unit_type', options: 'Healthcare Service Unit Type'}, + {fieldtype: 'Int', label: 'Expected Length of Stay', fieldname: 'expected_length_of_stay'}, + {fieldtype: 'Section Break'}, + {fieldtype: 'Long Text', label: 'Admission Instructions', fieldname: 'admission_instruction'} + ], + primary_action_label: __('Order Admission'), + primary_action : function() { + var args = { + patient: frm.doc.patient, + admission_encounter: frm.doc.name, + referring_practitioner: frm.doc.practitioner, + company: frm.doc.company, + medical_department: dialog.get_value('medical_department'), + primary_practitioner: dialog.get_value('primary_practitioner'), + secondary_practitioner: dialog.get_value('secondary_practitioner'), + admission_ordered_for: dialog.get_value('admission_ordered_for'), + admission_service_unit_type: dialog.get_value('service_unit_type'), + expected_length_of_stay: dialog.get_value('expected_length_of_stay'), + admission_instruction: dialog.get_value('admission_instruction') } - }, - freeze: true, - freeze_message: __('Process Inpatient Scheduling') + frappe.call({ + method: 'erpnext.healthcare.doctype.inpatient_record.inpatient_record.schedule_inpatient', + args: { + args: args + }, + callback: function(data) { + if (!data.exc) { + frm.reload_doc(); + } + }, + freeze: true, + freeze_message: 'Scheduling Patient Admission' + }); + frm.refresh_fields(); + dialog.hide(); + } + }); + + dialog.set_values({ + 'medical_department': frm.doc.medical_department, + 'primary_practitioner': frm.doc.practitioner, }); + + dialog.fields_dict['service_unit_type'].get_query = function() { + return { + filters: { + 'inpatient_occupancy': 1, + 'allow_appointments': 0 + } + }; + }; + + dialog.show(); + dialog.$wrapper.find('.modal-dialog').css('width', '800px'); }; -let schedule_discharge = function(frm) { - frappe.call({ - method: 'erpnext.healthcare.doctype.inpatient_record.inpatient_record.schedule_discharge', - args: {patient: frm.doc.patient, encounter_id: frm.doc.name, practitioner: frm.doc.practitioner}, - callback: function(data) { - if (!data.exc) { - frm.reload_doc(); +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: 'Date', label: 'Followup Date', fieldname: 'followup_date'}, + {fieldtype: 'Column Break'}, + {fieldtype: 'Small Text', label: 'Discharge Instructions', fieldname: 'discharge_instructions'}, + {fieldtype: 'Section Break', label:'Discharge Summary'}, + {fieldtype: 'Long Text', label: 'Discharge Note', fieldname: 'discharge_note'} + ], + primary_action_label: __('Order Discharge'), + primary_action : function() { + var args = { + patient: frm.doc.patient, + discharge_encounter: frm.doc.name, + discharge_practitioner: frm.doc.practitioner, + discharge_ordered_date: dialog.get_value('discharge_ordered_date'), + followup_date: dialog.get_value('followup_date'), + discharge_instructions: dialog.get_value('discharge_instructions'), + discharge_note: dialog.get_value('discharge_note') } - }, - freeze: true, - freeze_message: 'Process Discharge' + frappe.call ({ + method: 'erpnext.healthcare.doctype.inpatient_record.inpatient_record.schedule_discharge', + args: {args}, + callback: function(data) { + if(!data.exc){ + frm.reload_doc(); + } + }, + freeze: true, + freeze_message: 'Scheduling Inpatient Discharge' + }); + frm.refresh_fields(); + dialog.hide(); + } }); + + dialog.show(); + dialog.$wrapper.find('.modal-dialog').css('width', '800px'); }; -let create_medical_record = function (frm) { +let create_medical_record = function(frm) { if (!frm.doc.patient) { frappe.throw(__('Please select patient')); } @@ -221,7 +300,7 @@ let create_medical_record = function (frm) { frappe.new_doc('Patient Medical Record'); }; -let create_vital_signs = function (frm) { +let create_vital_signs = function(frm) { if (!frm.doc.patient) { frappe.throw(__('Please select patient')); } @@ -233,7 +312,7 @@ let create_vital_signs = function (frm) { frappe.new_doc('Vital Signs'); }; -let create_procedure = function (frm) { +let create_procedure = function(frm) { if (!frm.doc.patient) { frappe.throw(__('Please select patient')); } diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json index 05eec87398b9..15675f4673fc 100644 --- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json +++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json @@ -52,6 +52,7 @@ ], "fields": [ { + "allow_on_submit": 1, "fieldname": "inpatient_record", "fieldtype": "Link", "label": "Inpatient Record", @@ -296,6 +297,7 @@ "read_only": 1 }, { + "allow_on_submit": 1, "fieldname": "inpatient_status", "fieldtype": "Data", "label": "Inpatient Status", @@ -326,7 +328,7 @@ ], "is_submittable": 1, "links": [], - "modified": "2020-04-27 21:58:29.789797", + "modified": "2020-05-16 21:00:08.644531", "modified_by": "Administrator", "module": "Healthcare", "name": "Patient Encounter",