Merge pull request #21817 from akurungadam/develop-13

refactor(Healthcare): IP Admission and Discharge, Minor fixes
This commit is contained in:
Rucha Mahabal 2020-05-21 10:12:38 +05:30 committed by GitHub
commit 3bbb9a2958
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 556 additions and 162 deletions

View File

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

View File

@ -22,10 +22,16 @@ class HealthcareServiceUnit(NestedSet):
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

View File

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

View File

@ -10,6 +10,22 @@ from frappe.model.rename_doc import rename_doc
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)

View File

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

View File

@ -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
},
{
"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": "expected_discharge",
"fieldtype": "Date",
"in_list_view": 1,
"label": "Expected Discharge"
},
{
"fieldname": "discharge_date",
"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",

View File

@ -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 @@ from frappe.desk.reportview import get_match_cond
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 @@ class InpatientRecord(Document):
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 @@ class InpatientRecord(Document):
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', {})

View File

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

View File

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

View File

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

View File

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