', {
+ therapy: y[0],
+ name: y[1], encounter: y[2], practitioner: y[3], date: y[4],
+ department: y[6] ? y[6] : '', therapy_plan: y[5]
+ })).appendTo(html_field);
row.find("a").click(function() {
frm.doc.therapy_type = $(this).attr("data-therapy");
@@ -581,13 +631,13 @@ let create_vital_signs = function(frm) {
frappe.new_doc('Vital Signs');
};
-let update_status = function(frm, status){
+let update_status = function(frm, status) {
let doc = frm.doc;
frappe.confirm(__('Are you sure you want to cancel this appointment?'),
function() {
frappe.call({
method: 'erpnext.healthcare.doctype.patient_appointment.patient_appointment.update_status',
- args: {appointment_id: doc.name, status:status},
+ args: { appointment_id: doc.name, status: status },
callback: function(data) {
if (!data.exc) {
frm.reload_doc();
diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json
index 73ec3bc325..28d3a6dadf 100644
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json
+++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json
@@ -131,7 +131,7 @@
"fieldtype": "Link",
"label": "Service Unit",
"options": "Healthcare Service Unit",
- "set_only_once": 1
+ "read_only": 1
},
{
"depends_on": "eval:doc.practitioner;",
@@ -349,7 +349,7 @@
}
],
"links": [],
- "modified": "2021-06-16 00:40:26.841794",
+ "modified": "2021-08-30 09:00:41.329387",
"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 05e2cd30df..f0d5af9341 100755
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py
+++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py
@@ -6,7 +6,7 @@ from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
import json
-from frappe.utils import getdate, get_time, flt
+from frappe.utils import getdate, get_time, flt, get_link_to_form
from frappe.model.mapper import get_mapped_doc
from frappe import _
import datetime
@@ -15,6 +15,11 @@ from erpnext.hr.doctype.employee.employee import is_holiday
from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_receivable_account, get_income_account
from erpnext.healthcare.utils import check_fee_validity, get_service_item_and_practitioner_charge, manage_fee_validity
+class MaximumCapacityError(frappe.ValidationError):
+ pass
+class OverlapError(frappe.ValidationError):
+ pass
+
class PatientAppointment(Document):
def validate(self):
self.validate_overlaps()
@@ -49,26 +54,49 @@ class PatientAppointment(Document):
end_time = datetime.datetime.combine(getdate(self.appointment_date), get_time(self.appointment_time)) \
+ datetime.timedelta(minutes=flt(self.duration))
- overlaps = frappe.db.sql("""
- select
- name, practitioner, patient, appointment_time, duration
- from
- `tabPatient Appointment`
- where
- appointment_date=%s and name!=%s and status NOT IN ("Closed", "Cancelled")
- and (practitioner=%s or patient=%s) and
- ((appointment_time<%s and appointment_time + INTERVAL duration MINUTE>%s) or
- (appointment_time>%s and appointment_time<%s) or
- (appointment_time=%s))
- """, (self.appointment_date, self.name, self.practitioner, self.patient,
- self.appointment_time, end_time.time(), self.appointment_time, end_time.time(), self.appointment_time))
+ # all appointments for both patient and practitioner overlapping the duration of this appointment
+ overlapping_appointments = frappe.db.sql("""
+ SELECT
+ name, practitioner, patient, appointment_time, duration, service_unit
+ FROM
+ `tabPatient Appointment`
+ WHERE
+ appointment_date=%(appointment_date)s AND name!=%(name)s AND status NOT IN ("Closed", "Cancelled") AND
+ (practitioner=%(practitioner)s OR patient=%(patient)s) AND
+ ((appointment_time<%(appointment_time)s AND appointment_time + INTERVAL duration MINUTE>%(appointment_time)s) OR
+ (appointment_time>%(appointment_time)s AND appointment_time<%(end_time)s) OR
+ (appointment_time=%(appointment_time)s))
+ """,
+ {
+ 'appointment_date': self.appointment_date,
+ 'name': self.name,
+ 'practitioner': self.practitioner,
+ 'patient': self.patient,
+ 'appointment_time': self.appointment_time,
+ 'end_time':end_time.time()
+ },
+ as_dict = True
+ )
+
+ if not overlapping_appointments:
+ return # No overlaps, nothing to validate!
+
+ if self.service_unit: # validate service unit capacity if overlap enabled
+ allow_overlap, service_unit_capacity = frappe.get_value('Healthcare Service Unit', self.service_unit,
+ ['overlap_appointments', 'service_unit_capacity'])
+ if allow_overlap:
+ service_unit_appointments = list(filter(lambda appointment: appointment['service_unit'] == self.service_unit and
+ appointment['patient'] != self.patient, overlapping_appointments)) # if same patient already booked, it should be an overlap
+ if len(service_unit_appointments) >= (service_unit_capacity or 1):
+ frappe.throw(_("Not allowed, {} cannot exceed maximum capacity {}")
+ .format(frappe.bold(self.service_unit), frappe.bold(service_unit_capacity or 1)), MaximumCapacityError)
+ else: # service_unit_appointments within capacity, remove from overlapping_appointments
+ overlapping_appointments = [appointment for appointment in overlapping_appointments if appointment not in service_unit_appointments]
+
+ if overlapping_appointments:
+ frappe.throw(_("Not allowed, cannot overlap appointment {}")
+ .format(frappe.bold(', '.join([appointment['name'] for appointment in overlapping_appointments]))), OverlapError)
- if overlaps:
- overlapping_details = _('Appointment overlaps with ')
- overlapping_details += "
{0}".format(overlaps[0][0])
- overlapping_details += _('{0} has appointment scheduled with {1} at {2} having {3} minute(s) duration.').format(
- overlaps[0][1], overlaps[0][2], overlaps[0][3], overlaps[0][4])
- frappe.throw(overlapping_details, title=_('Appointments Overlapping'))
def validate_service_unit(self):
if self.inpatient_record and self.service_unit:
@@ -109,9 +137,13 @@ class PatientAppointment(Document):
frappe.db.set_value('Patient Appointment', self.name, 'notes', comments)
def update_fee_validity(self):
+ if not frappe.db.get_single_value('Healthcare Settings', 'enable_free_follow_ups'):
+ return
+
fee_validity = manage_fee_validity(self)
if fee_validity:
- frappe.msgprint(_('{0} has fee validity till {1}').format(self.patient, fee_validity.valid_till))
+ frappe.msgprint(_('{0}: {1} has fee validity till {2}').format(self.patient,
+ frappe.bold(self.patient_name), fee_validity.valid_till))
@frappe.whitelist()
def get_therapy_types(self):
@@ -301,17 +333,13 @@ def check_employee_wise_availability(date, practitioner_doc):
def get_available_slots(practitioner_doc, date):
- available_slots = []
- slot_details = []
+ available_slots = slot_details = []
weekday = date.strftime('%A')
practitioner = practitioner_doc.name
for schedule_entry in practitioner_doc.practitioner_schedules:
- if schedule_entry.schedule:
- practitioner_schedule = frappe.get_doc('Practitioner Schedule', schedule_entry.schedule)
- else:
- frappe.throw(_('{0} does not have a Healthcare Practitioner Schedule. Add it in Healthcare Practitioner').format(
- frappe.bold(practitioner)), title=_('Practitioner Schedule Not Found'))
+ validate_practitioner_schedules(schedule_entry, practitioner)
+ practitioner_schedule = frappe.get_doc('Practitioner Schedule', schedule_entry.schedule)
if practitioner_schedule:
available_slots = []
@@ -321,6 +349,8 @@ def get_available_slots(practitioner_doc, date):
if available_slots:
appointments = []
+ allow_overlap = 0
+ service_unit_capacity = 0
# fetch all appointments to practitioner by service unit
filters = {
'practitioner': practitioner,
@@ -330,8 +360,8 @@ def get_available_slots(practitioner_doc, date):
}
if schedule_entry.service_unit:
- slot_name = schedule_entry.schedule + ' - ' + schedule_entry.service_unit
- allow_overlap = frappe.get_value('Healthcare Service Unit', schedule_entry.service_unit, 'overlap_appointments')
+ slot_name = f'{schedule_entry.schedule}'
+ allow_overlap, service_unit_capacity = frappe.get_value('Healthcare Service Unit', schedule_entry.service_unit, ['overlap_appointments', 'service_unit_capacity'])
if not allow_overlap:
# fetch all appointments to service unit
filters.pop('practitioner')
@@ -346,12 +376,25 @@ def get_available_slots(practitioner_doc, date):
filters=filters,
fields=['name', 'appointment_time', 'duration', 'status'])
- slot_details.append({'slot_name':slot_name, 'service_unit':schedule_entry.service_unit,
- 'avail_slot':available_slots, 'appointments': appointments})
+ slot_details.append({'slot_name': slot_name, 'service_unit': schedule_entry.service_unit, 'avail_slot': available_slots,
+ 'appointments': appointments, 'allow_overlap': allow_overlap, 'service_unit_capacity': service_unit_capacity})
return slot_details
+def validate_practitioner_schedules(schedule_entry, practitioner):
+ if schedule_entry.schedule:
+ if not schedule_entry.service_unit:
+ frappe.throw(_('Practitioner {0} does not have a Service Unit set against the Practitioner Schedule {1}.').format(
+ get_link_to_form('Healthcare Practitioner', practitioner), frappe.bold(schedule_entry.schedule)),
+ title=_('Service Unit Not Found'))
+
+ else:
+ frappe.throw(_('Practitioner {0} does not have a Practitioner Schedule assigned.').format(
+ get_link_to_form('Healthcare Practitioner', practitioner)),
+ title=_('Practitioner Schedule Not Found'))
+
+
@frappe.whitelist()
def update_status(appointment_id, status):
frappe.db.set_value('Patient Appointment', appointment_id, 'status', status)
diff --git a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.js b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.js
deleted file mode 100644
index 71fc177845..0000000000
--- a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Patient Appointment", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Patient Appointment
- () => frappe.tests.make('Patient Appointment', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
index 9c3392cd5b..36ef2d1623 100644
--- a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
+++ b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
@@ -16,9 +16,11 @@ class TestPatientAppointment(unittest.TestCase):
frappe.db.sql("""delete from `tabFee Validity`""")
frappe.db.sql("""delete from `tabPatient Encounter`""")
make_pos_profile()
+ frappe.db.sql("""delete from `tabHealthcare Service Unit` where name like '_Test %'""")
+ frappe.db.sql("""delete from `tabHealthcare Service Unit` where name like '_Test Service Unit Type%'""")
def test_status(self):
- patient, medical_department, practitioner = create_healthcare_docs()
+ patient, practitioner = create_healthcare_docs()
frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 0)
appointment = create_appointment(patient, practitioner, nowdate())
self.assertEqual(appointment.status, 'Open')
@@ -30,7 +32,7 @@ class TestPatientAppointment(unittest.TestCase):
self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Open')
def test_start_encounter(self):
- patient, medical_department, practitioner = create_healthcare_docs()
+ patient, practitioner = create_healthcare_docs()
frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1)
appointment = create_appointment(patient, practitioner, add_days(nowdate(), 4), invoice = 1)
appointment.reload()
@@ -44,7 +46,7 @@ class TestPatientAppointment(unittest.TestCase):
self.assertEqual(encounter.invoiced, frappe.db.get_value('Patient Appointment', appointment.name, 'invoiced'))
def test_auto_invoicing(self):
- patient, medical_department, practitioner = create_healthcare_docs()
+ patient, practitioner = create_healthcare_docs()
frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0)
frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 0)
appointment = create_appointment(patient, practitioner, nowdate())
@@ -60,13 +62,14 @@ class TestPatientAppointment(unittest.TestCase):
self.assertEqual(frappe.db.get_value('Sales Invoice', sales_invoice_name, 'paid_amount'), appointment.paid_amount)
def test_auto_invoicing_based_on_department(self):
- patient, medical_department, practitioner = create_healthcare_docs()
+ patient, practitioner = create_healthcare_docs()
+ medical_department = create_medical_department()
frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0)
frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1)
- appointment_type = create_appointment_type()
+ appointment_type = create_appointment_type({'medical_department': medical_department})
appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2),
- invoice=1, appointment_type=appointment_type.name, department='_Test Medical Department')
+ invoice=1, appointment_type=appointment_type.name, department=medical_department)
appointment.reload()
self.assertEqual(appointment.invoiced, 1)
@@ -78,7 +81,7 @@ class TestPatientAppointment(unittest.TestCase):
self.assertEqual(frappe.db.get_value('Sales Invoice', sales_invoice_name, 'paid_amount'), appointment.paid_amount)
def test_auto_invoicing_according_to_appointment_type_charge(self):
- patient, medical_department, practitioner = create_healthcare_docs()
+ patient, practitioner = create_healthcare_docs()
frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0)
frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1)
@@ -88,9 +91,9 @@ class TestPatientAppointment(unittest.TestCase):
'op_consulting_charge': 300
}]
appointment_type = create_appointment_type(args={
- 'name': 'Generic Appointment Type charge',
- 'items': items
- })
+ 'name': 'Generic Appointment Type charge',
+ 'items': items
+ })
appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2),
invoice=1, appointment_type=appointment_type.name)
@@ -104,21 +107,24 @@ class TestPatientAppointment(unittest.TestCase):
self.assertTrue(sales_invoice_name)
def test_appointment_cancel(self):
- patient, medical_department, practitioner = create_healthcare_docs()
+ patient, practitioner = create_healthcare_docs()
frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 1)
appointment = create_appointment(patient, practitioner, nowdate())
- fee_validity = frappe.db.get_value('Fee Validity Reference', {'appointment': appointment.name}, 'parent')
+ fee_validity = frappe.db.get_value('Fee Validity', {'patient': patient, 'practitioner': practitioner})
# fee validity created
self.assertTrue(fee_validity)
- visited = frappe.db.get_value('Fee Validity', fee_validity, 'visited')
+ # first follow up appointment
+ appointment = create_appointment(patient, practitioner, add_days(nowdate(), 1))
+ self.assertEqual(frappe.db.get_value('Fee Validity', fee_validity, 'visited'), 1)
+
update_status(appointment.name, 'Cancelled')
# check fee validity updated
- self.assertEqual(frappe.db.get_value('Fee Validity', fee_validity, 'visited'), visited - 1)
+ self.assertEqual(frappe.db.get_value('Fee Validity', fee_validity, 'visited'), 0)
frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0)
frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1)
- appointment = create_appointment(patient, practitioner, nowdate(), invoice=1)
+ appointment = create_appointment(patient, practitioner, add_days(nowdate(), 1), invoice=1)
update_status(appointment.name, 'Cancelled')
# check invoice cancelled
sales_invoice_name = frappe.db.get_value('Sales Invoice Item', {'reference_dn': appointment.name}, 'parent')
@@ -130,7 +136,7 @@ class TestPatientAppointment(unittest.TestCase):
create_inpatient, get_healthcare_service_unit, mark_invoiced_inpatient_occupancy
frappe.db.sql("""delete from `tabInpatient Record`""")
- patient, medical_department, practitioner = create_healthcare_docs()
+ patient, practitioner = create_healthcare_docs()
patient = create_patient()
# Schedule Admission
ip_record = create_inpatient(patient)
@@ -138,7 +144,7 @@ class TestPatientAppointment(unittest.TestCase):
ip_record.save(ignore_permissions = True)
# Admit
- service_unit = get_healthcare_service_unit('Test Service Unit Ip Occupancy')
+ service_unit = get_healthcare_service_unit('_Test Service Unit Ip Occupancy')
admit_patient(ip_record, service_unit, now_datetime())
appointment = create_appointment(patient, practitioner, nowdate(), service_unit=service_unit)
@@ -156,7 +162,7 @@ class TestPatientAppointment(unittest.TestCase):
create_inpatient, get_healthcare_service_unit, mark_invoiced_inpatient_occupancy
frappe.db.sql("""delete from `tabInpatient Record`""")
- patient, medical_department, practitioner = create_healthcare_docs()
+ patient, practitioner = create_healthcare_docs()
patient = create_patient()
# Schedule Admission
ip_record = create_inpatient(patient)
@@ -164,10 +170,10 @@ class TestPatientAppointment(unittest.TestCase):
ip_record.save(ignore_permissions = True)
# Admit
- service_unit = get_healthcare_service_unit('Test Service Unit Ip Occupancy')
+ service_unit = get_healthcare_service_unit('_Test Service Unit Ip Occupancy')
admit_patient(ip_record, service_unit, now_datetime())
- appointment_service_unit = get_healthcare_service_unit('Test Service Unit Ip Occupancy for Appointment')
+ appointment_service_unit = get_healthcare_service_unit('_Test Service Unit Ip Occupancy for Appointment')
appointment = create_appointment(patient, practitioner, nowdate(), service_unit=appointment_service_unit, save=0)
self.assertRaises(frappe.exceptions.ValidationError, appointment.save)
@@ -189,7 +195,7 @@ class TestPatientAppointment(unittest.TestCase):
assert payment_required is True
def test_sales_invoice_should_be_generated_for_new_patient_appointment(self):
- patient, medical_department, practitioner = create_healthcare_docs()
+ patient, practitioner = create_healthcare_docs()
frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1)
invoice_count = frappe.db.count('Sales Invoice')
@@ -200,10 +206,10 @@ class TestPatientAppointment(unittest.TestCase):
assert new_invoice_count == invoice_count + 1
def test_patient_appointment_should_consider_permissions_while_fetching_appointments(self):
- patient, medical_department, practitioner = create_healthcare_docs()
+ patient, practitioner = create_healthcare_docs()
create_appointment(patient, practitioner, nowdate())
- patient, medical_department, new_practitioner = create_healthcare_docs(practitioner_name='Dr. John')
+ patient, new_practitioner = create_healthcare_docs(id=5)
create_appointment(patient, new_practitioner, nowdate())
roles = [{"doctype": "Has Role", "role": "Physician"}]
@@ -220,41 +226,102 @@ class TestPatientAppointment(unittest.TestCase):
appointments = frappe.get_list('Patient Appointment')
assert len(appointments) == 2
-def create_healthcare_docs(practitioner_name=None):
- if not practitioner_name:
- practitioner_name = '_Test Healthcare Practitioner'
+ def test_overlap_appointment(self):
+ from erpnext.healthcare.doctype.patient_appointment.patient_appointment import OverlapError
+ patient, practitioner = create_healthcare_docs(id=1)
+ patient_1, practitioner_1 = create_healthcare_docs(id=2)
+ service_unit = create_service_unit(id=0)
+ service_unit_1 = create_service_unit(id=1)
+ appointment = create_appointment(patient, practitioner, nowdate(), service_unit=service_unit) # valid
- patient = create_patient()
- practitioner = frappe.db.exists('Healthcare Practitioner', practitioner_name)
- medical_department = frappe.db.exists('Medical Department', '_Test Medical Department')
+ # patient and practitioner cannot have overlapping appointments
+ appointment = create_appointment(patient, practitioner, nowdate(), service_unit=service_unit, save=0)
+ self.assertRaises(OverlapError, appointment.save)
+ appointment = create_appointment(patient, practitioner, nowdate(), service_unit=service_unit_1, save=0) # diff service unit
+ self.assertRaises(OverlapError, appointment.save)
+ appointment = create_appointment(patient, practitioner, nowdate(), save=0) # with no service unit link
+ self.assertRaises(OverlapError, appointment.save)
- if not medical_department:
- medical_department = frappe.new_doc('Medical Department')
- medical_department.department = '_Test Medical Department'
- medical_department.save(ignore_permissions=True)
- medical_department = medical_department.name
+ # patient cannot have overlapping appointments with other practitioners
+ appointment = create_appointment(patient, practitioner_1, nowdate(), service_unit=service_unit, save=0)
+ self.assertRaises(OverlapError, appointment.save)
+ appointment = create_appointment(patient, practitioner_1, nowdate(), service_unit=service_unit_1, save=0)
+ self.assertRaises(OverlapError, appointment.save)
+ appointment = create_appointment(patient, practitioner_1, nowdate(), save=0)
+ self.assertRaises(OverlapError, appointment.save)
- if not practitioner:
- practitioner = frappe.new_doc('Healthcare Practitioner')
- practitioner.first_name = practitioner_name
- practitioner.gender = 'Female'
- practitioner.department = medical_department
- practitioner.op_consulting_charge = 500
- practitioner.inpatient_visit_charge = 500
- practitioner.save(ignore_permissions=True)
- practitioner = practitioner.name
+ # practitioner cannot have overlapping appointments with other patients
+ appointment = create_appointment(patient_1, practitioner, nowdate(), service_unit=service_unit, save=0)
+ self.assertRaises(OverlapError, appointment.save)
+ appointment = create_appointment(patient_1, practitioner, nowdate(), service_unit=service_unit_1, save=0)
+ self.assertRaises(OverlapError, appointment.save)
+ appointment = create_appointment(patient_1, practitioner, nowdate(), save=0)
+ self.assertRaises(OverlapError, appointment.save)
- return patient, medical_department, practitioner
+ def test_service_unit_capacity(self):
+ from erpnext.healthcare.doctype.patient_appointment.patient_appointment import MaximumCapacityError, OverlapError
+ practitioner = create_practitioner()
+ capacity = 3
+ overlap_service_unit_type = create_service_unit_type(id=10, allow_appointments=1, overlap_appointments=1)
+ overlap_service_unit = create_service_unit(id=100, service_unit_type=overlap_service_unit_type, service_unit_capacity=capacity)
+
+ for i in range(0, capacity):
+ patient = create_patient(id=i)
+ create_appointment(patient, practitioner, nowdate(), service_unit=overlap_service_unit) # valid
+ appointment = create_appointment(patient, practitioner, nowdate(), service_unit=overlap_service_unit, save=0) # overlap
+ self.assertRaises(OverlapError, appointment.save)
+
+ patient = create_patient(id=capacity)
+ appointment = create_appointment(patient, practitioner, nowdate(), service_unit=overlap_service_unit, save=0)
+ self.assertRaises(MaximumCapacityError, appointment.save)
+
+
+def create_healthcare_docs(id=0):
+ patient = create_patient(id)
+ practitioner = create_practitioner(id)
+
+ return patient, practitioner
+
+
+def create_patient(id=0):
+ if frappe.db.exists('Patient', {'firstname':f'_Test Patient {str(id)}'}):
+ patient = frappe.db.get_value('Patient', {'first_name': f'_Test Patient {str(id)}'}, ['name'])
+ return patient
+
+ patient = frappe.new_doc('Patient')
+ patient.first_name = f'_Test Patient {str(id)}'
+ patient.sex = 'Female'
+ patient.save(ignore_permissions=True)
+
+ return patient.name
+
+
+def create_medical_department(id=0):
+ if frappe.db.exists('Medical Department', f'_Test Medical Department {str(id)}'):
+ return f'_Test Medical Department {str(id)}'
+
+ medical_department = frappe.new_doc('Medical Department')
+ medical_department.department = f'_Test Medical Department {str(id)}'
+ medical_department.save(ignore_permissions=True)
+
+ return medical_department.name
+
+
+def create_practitioner(id=0, medical_department=None):
+ if frappe.db.exists('Healthcare Practitioner', {'firstname':f'_Test Healthcare Practitioner {str(id)}'}):
+ practitioner = frappe.db.get_value('Healthcare Practitioner', {'firstname':f'_Test Healthcare Practitioner {str(id)}'}, ['name'])
+ return practitioner
+
+ practitioner = frappe.new_doc('Healthcare Practitioner')
+ practitioner.first_name = f'_Test Healthcare Practitioner {str(id)}'
+ practitioner.gender = 'Female'
+ practitioner.department = medical_department or create_medical_department(id)
+ practitioner.op_consulting_charge = 500
+ practitioner.inpatient_visit_charge = 500
+ practitioner.save(ignore_permissions=True)
+
+ return practitioner.name
-def create_patient():
- patient = frappe.db.exists('Patient', '_Test Patient')
- if not patient:
- patient = frappe.new_doc('Patient')
- patient.first_name = '_Test Patient'
- patient.sex = 'Female'
- patient.save(ignore_permissions=True)
- patient = patient.name
- return patient
def create_encounter(appointment):
if appointment:
@@ -267,8 +334,10 @@ def create_encounter(appointment):
encounter.company = appointment.company
encounter.save()
encounter.submit()
+
return encounter
+
def create_appointment(patient, practitioner, appointment_date, invoice=0, procedure_template=0,
service_unit=None, appointment_type=None, save=1, department=None):
item = create_healthcare_service_items()
@@ -281,6 +350,7 @@ def create_appointment(patient, practitioner, appointment_date, invoice=0, proce
appointment.appointment_date = appointment_date
appointment.company = '_Test Company'
appointment.duration = 15
+
if service_unit:
appointment.service_unit = service_unit
if invoice:
@@ -291,11 +361,14 @@ def create_appointment(patient, practitioner, appointment_date, invoice=0, proce
appointment.procedure_template = create_clinical_procedure_template().get('name')
if save:
appointment.save(ignore_permissions=True)
+
return appointment
+
def create_healthcare_service_items():
if frappe.db.exists('Item', 'HLC-SI-001'):
return 'HLC-SI-001'
+
item = frappe.new_doc('Item')
item.item_code = 'HLC-SI-001'
item.item_name = 'Consulting Charges'
@@ -303,11 +376,14 @@ def create_healthcare_service_items():
item.is_stock_item = 0
item.stock_uom = 'Nos'
item.save()
+
return item.name
+
def create_clinical_procedure_template():
if frappe.db.exists('Clinical Procedure Template', 'Knee Surgery and Rehab'):
return frappe.get_doc('Clinical Procedure Template', 'Knee Surgery and Rehab')
+
template = frappe.new_doc('Clinical Procedure Template')
template.template = 'Knee Surgery and Rehab'
template.item_code = 'Knee Surgery and Rehab'
@@ -316,8 +392,10 @@ def create_clinical_procedure_template():
template.description = 'Knee Surgery and Rehab'
template.rate = 50000
template.save()
+
return template
+
def create_appointment_type(args=None):
if not args:
args = frappe.local.form_dict
@@ -330,9 +408,9 @@ def create_appointment_type(args=None):
else:
item = create_healthcare_service_items()
items = [{
- 'medical_department': '_Test Medical Department',
- 'op_consulting_charge_item': item,
- 'op_consulting_charge': 200
+ 'medical_department': args.get('medical_department') or '_Test Medical Department',
+ 'op_consulting_charge_item': item,
+ 'op_consulting_charge': 200
}]
return frappe.get_doc({
'doctype': 'Appointment Type',
@@ -356,3 +434,30 @@ def create_user(email=None, roles=None):
"roles": roles,
}).insert()
return user
+
+
+def create_service_unit_type(id=0, allow_appointments=1, overlap_appointments=0):
+ if frappe.db.exists('Healthcare Service Unit Type', f'_Test Service Unit Type {str(id)}'):
+ return f'_Test Service Unit Type {str(id)}'
+
+ service_unit_type = frappe.new_doc('Healthcare Service Unit Type')
+ service_unit_type.service_unit_type = f'_Test Service Unit Type {str(id)}'
+ service_unit_type.allow_appointments = allow_appointments
+ service_unit_type.overlap_appointments = overlap_appointments
+ service_unit_type.save(ignore_permissions=True)
+
+ return service_unit_type.name
+
+
+def create_service_unit(id=0, service_unit_type=None, service_unit_capacity=0):
+ if frappe.db.exists('Healthcare Service Unit', f'_Test Service Unit {str(id)}'):
+ return f'_Test service_unit {str(id)}'
+
+ service_unit = frappe.new_doc('Healthcare Service Unit')
+ service_unit.is_group = 0
+ service_unit.healthcare_service_unit_name= f'_Test Service Unit {str(id)}'
+ service_unit.service_unit_type = service_unit_type or create_service_unit_type(id)
+ service_unit.service_unit_capacity = service_unit_capacity
+ service_unit.save(ignore_permissions=True)
+
+ return service_unit.name
diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js
index aaeaa692e6..c3466260d2 100644
--- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js
+++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js
@@ -185,7 +185,42 @@ frappe.ui.form.on('Patient Encounter', {
};
frm.set_value(values);
}
- }
+ },
+
+ get_applicable_treatment_plans: function(frm) {
+ frappe.call({
+ method: 'get_applicable_treatment_plans',
+ doc: frm.doc,
+ args: {'encounter': frm.doc},
+ freeze: true,
+ freeze_message: __('Fetching Treatment Plans'),
+ callback: function() {
+ new frappe.ui.form.MultiSelectDialog({
+ doctype: "Treatment Plan Template",
+ target: this.cur_frm,
+ setters: {
+ medical_department: "",
+ },
+ action(selections) {
+ frappe.call({
+ method: 'set_treatment_plans',
+ doc: frm.doc,
+ args: selections,
+ }).then(() => {
+ frm.refresh_field('drug_prescription');
+ frm.refresh_field('procedure_prescription');
+ frm.refresh_field('lab_test_prescription');
+ frm.refresh_field('therapies');
+ });
+ cur_dialog.hide();
+ }
+ });
+
+
+ }
+ });
+ },
+
});
var schedule_inpatient = function(frm) {
diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json
index b646ff9ebe..994597dca7 100644
--- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json
+++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json
@@ -31,6 +31,7 @@
"sb_symptoms",
"symptoms",
"symptoms_in_print",
+ "get_applicable_treatment_plans",
"physical_examination",
"diagnosis",
"diagnosis_in_print",
@@ -324,11 +325,17 @@
"no_copy": 1,
"print_hide": 1,
"read_only": 1
+ },
+ {
+ "depends_on": "eval:doc.patient",
+ "fieldname": "get_applicable_treatment_plans",
+ "fieldtype": "Button",
+ "label": "Get Applicable Treatment Plans"
}
],
"is_submittable": 1,
"links": [],
- "modified": "2020-11-30 10:39:00.783119",
+ "modified": "2021-07-27 11:39:12.347704",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Patient Encounter",
@@ -358,4 +365,4 @@
"title_field": "title",
"track_changes": 1,
"track_seen": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py
index 2b3029efde..7a745ae468 100644
--- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py
+++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py
@@ -10,6 +10,7 @@ from frappe.utils import cstr, getdate, add_days
from frappe import _
from frappe.model.mapper import get_mapped_doc
+
class PatientEncounter(Document):
def validate(self):
self.set_title()
@@ -33,6 +34,85 @@ class PatientEncounter(Document):
self.title = _('{0} with {1}').format(self.patient_name or self.patient,
self.practitioner_name or self.practitioner)[:100]
+ @frappe.whitelist()
+ @staticmethod
+ def get_applicable_treatment_plans(encounter):
+ patient = frappe.get_doc('Patient', encounter['patient'])
+
+ plan_filters = {}
+ plan_filters['name'] = ['in', []]
+
+ age = patient.age
+ if age:
+ plan_filters['patient_age_from'] = ['<=', age.years]
+ plan_filters['patient_age_to'] = ['>=', age.years]
+
+ gender = patient.sex
+ if gender:
+ plan_filters['gender'] = ['in', [gender, None]]
+
+ diagnosis = encounter.get('diagnosis')
+ if diagnosis:
+ diagnosis = [_diagnosis['diagnosis'] for _diagnosis in encounter['diagnosis']]
+ filters = [
+ ['diagnosis', 'in', diagnosis],
+ ['parenttype', '=', 'Treatment Plan Template'],
+ ]
+ diagnosis = frappe.get_list('Patient Encounter Diagnosis', filters=filters, fields='*')
+ plan_names = [_diagnosis['parent'] for _diagnosis in diagnosis]
+ plan_filters['name'][1].extend(plan_names)
+
+ symptoms = encounter.get('symptoms')
+ if symptoms:
+ symptoms = [symptom['complaint'] for symptom in encounter['symptoms']]
+ filters = [
+ ['complaint', 'in', symptoms],
+ ['parenttype', '=', 'Treatment Plan Template'],
+ ]
+ symptoms = frappe.get_list('Patient Encounter Symptom', filters=filters, fields='*')
+ plan_names = [symptom['parent'] for symptom in symptoms]
+ plan_filters['name'][1].extend(plan_names)
+
+ if not plan_filters['name'][1]:
+ plan_filters.pop('name')
+
+ plans = frappe.get_list('Treatment Plan Template', fields='*', filters=plan_filters)
+
+ return plans
+
+ @frappe.whitelist()
+ def set_treatment_plans(self, treatment_plans=None):
+ for treatment_plan in treatment_plans:
+ self.set_treatment_plan(treatment_plan)
+
+ def set_treatment_plan(self, plan):
+ plan_items = frappe.get_list('Treatment Plan Template Item', filters={'parent': plan}, fields='*')
+ for plan_item in plan_items:
+ self.set_treatment_plan_item(plan_item)
+
+ drugs = frappe.get_list('Drug Prescription', filters={'parent': plan}, fields='*')
+ for drug in drugs:
+ self.append('drug_prescription', drug)
+
+ self.save()
+
+ def set_treatment_plan_item(self, plan_item):
+ if plan_item.type == 'Clinical Procedure Template':
+ self.append('procedure_prescription', {
+ 'procedure': plan_item.template
+ })
+
+ if plan_item.type == 'Lab Test Template':
+ self.append('lab_test_prescription', {
+ 'lab_test_code': plan_item.template
+ })
+
+ if plan_item.type == 'Therapy Type':
+ self.append('therapies', {
+ 'therapy_type': plan_item.template
+ })
+
+
@frappe.whitelist()
def make_ip_medication_order(source_name, target_doc=None):
def set_missing_values(source, target):
diff --git a/erpnext/healthcare/doctype/patient_encounter/test_patient_encounter.js b/erpnext/healthcare/doctype/patient_encounter/test_patient_encounter.js
deleted file mode 100644
index 1baabf7eef..0000000000
--- a/erpnext/healthcare/doctype/patient_encounter/test_patient_encounter.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Patient Encounter", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Patient Encounter
- () => frappe.tests.make('Patient Encounter', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/patient_encounter/test_patient_encounter.py b/erpnext/healthcare/doctype/patient_encounter/test_patient_encounter.py
index f5df152050..96976821a7 100644
--- a/erpnext/healthcare/doctype/patient_encounter/test_patient_encounter.py
+++ b/erpnext/healthcare/doctype/patient_encounter/test_patient_encounter.py
@@ -4,5 +4,82 @@
from __future__ import unicode_literals
import unittest
+import frappe
+from erpnext.healthcare.doctype.patient_encounter.patient_encounter import PatientEncounter
+
+
class TestPatientEncounter(unittest.TestCase):
- pass
+ def setUp(self):
+ try:
+ gender_m = frappe.get_doc({
+ 'doctype': 'Gender',
+ 'gender': 'MALE'
+ }).insert()
+ gender_f = frappe.get_doc({
+ 'doctype': 'Gender',
+ 'gender': 'FEMALE'
+ }).insert()
+ except frappe.exceptions.DuplicateEntryError:
+ gender_m = frappe.get_doc({
+ 'doctype': 'Gender',
+ 'gender': 'MALE'
+ })
+ gender_f = frappe.get_doc({
+ 'doctype': 'Gender',
+ 'gender': 'FEMALE'
+ })
+
+ self.patient_male = frappe.get_doc({
+ 'doctype': 'Patient',
+ 'first_name': 'John',
+ 'sex': gender_m.gender,
+ }).insert()
+ self.patient_female = frappe.get_doc({
+ 'doctype': 'Patient',
+ 'first_name': 'Curie',
+ 'sex': gender_f.gender,
+ }).insert()
+ self.practitioner = frappe.get_doc({
+ 'doctype': 'Healthcare Practitioner',
+ 'first_name': 'Doc',
+ 'sex': 'MALE',
+ }).insert()
+ try:
+ self.care_plan_male = frappe.get_doc({
+ 'doctype': 'Treatment Plan Template',
+ 'template_name': 'test plan - m',
+ 'gender': gender_m.gender,
+ }).insert()
+ self.care_plan_female = frappe.get_doc({
+ 'doctype': 'Treatment Plan Template',
+ 'template_name': 'test plan - f',
+ 'gender': gender_f.gender,
+ }).insert()
+ except frappe.exceptions.DuplicateEntryError:
+ self.care_plan_male = frappe.get_doc({
+ 'doctype': 'Treatment Plan Template',
+ 'template_name': 'test plan - m',
+ 'gender': gender_m.gender,
+ })
+ self.care_plan_female = frappe.get_doc({
+ 'doctype': 'Treatment Plan Template',
+ 'template_name': 'test plan - f',
+ 'gender': gender_f.gender,
+ })
+
+ def test_treatment_plan_template_filter(self):
+ encounter = frappe.get_doc({
+ 'doctype': 'Patient Encounter',
+ 'patient': self.patient_male.name,
+ 'practitioner': self.practitioner.name,
+ }).insert()
+ plans = PatientEncounter.get_applicable_treatment_plans(encounter.as_dict())
+ self.assertEqual(plans[0]['name'], self.care_plan_male.template_name)
+
+ encounter = frappe.get_doc({
+ 'doctype': 'Patient Encounter',
+ 'patient': self.patient_female.name,
+ 'practitioner': self.practitioner.name,
+ }).insert()
+ plans = PatientEncounter.get_applicable_treatment_plans(encounter.as_dict())
+ self.assertEqual(plans[0]['name'], self.care_plan_female.template_name)
diff --git a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py b/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py
index 63b00859d7..9e0d3c3e27 100644
--- a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py
+++ b/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py
@@ -18,7 +18,7 @@ class PatientHistorySettings(Document):
def validate_submittable_doctypes(self):
for entry in self.custom_doctypes:
if not cint(frappe.db.get_value('DocType', entry.document_type, 'is_submittable')):
- msg = _('Row #{0}: Document Type {1} is not submittable. ').format(
+ msg = _('Row #{0}: Document Type {1} is not submittable.').format(
entry.idx, frappe.bold(entry.document_type))
msg += _('Patient Medical Record can only be created for submittable document types.')
frappe.throw(msg)
@@ -116,12 +116,12 @@ def set_subject_field(doc):
fieldname = entry.get('fieldname')
if entry.get('fieldtype') == 'Table' and doc.get(fieldname):
formatted_value = get_formatted_value_for_table_field(doc.get(fieldname), meta.get_field(fieldname))
- subject += frappe.bold(_(entry.get('label')) + ': ') + '
' + cstr(formatted_value) + '
'
+ subject += frappe.bold(_(entry.get('label')) + ':') + '
' + cstr(formatted_value) + '
'
else:
if doc.get(fieldname):
formatted_value = format_value(doc.get(fieldname), meta.get_field(fieldname), doc)
- subject += frappe.bold(_(entry.get('label')) + ': ') + cstr(formatted_value) + '
'
+ subject += frappe.bold(_(entry.get('label')) + ':') + cstr(formatted_value) + '
'
return subject
diff --git a/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py b/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py
index 33119d8185..9169ea642b 100644
--- a/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py
+++ b/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py
@@ -38,13 +38,12 @@ class TestPatientHistorySettings(unittest.TestCase):
# tests for medical record creation of standard doctypes in test_patient_medical_record.py
patient = create_patient()
doc = create_doc(patient)
-
# check for medical record
medical_rec = frappe.db.exists("Patient Medical Record", {"status": "Open", "reference_name": doc.name})
self.assertTrue(medical_rec)
medical_rec = frappe.get_doc("Patient Medical Record", medical_rec)
- expected_subject = "Date: {0}Rating: 3Feedback: Test Patient History Settings".format(
+ expected_subject = "Date:{0}Rating:3Feedback:Test Patient History Settings".format(
frappe.utils.format_date(getdate()))
self.assertEqual(strip_html(medical_rec.subject), expected_subject)
self.assertEqual(medical_rec.patient, patient)
diff --git a/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.js b/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.js
deleted file mode 100644
index 66dda09e25..0000000000
--- a/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Patient Medical Record", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Patient Medical Record
- () => frappe.tests.make('Patient Medical Record', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.py b/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.py
index f8ccc8a002..5b7d8d62c8 100644
--- a/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.py
+++ b/erpnext/healthcare/doctype/patient_medical_record/test_patient_medical_record.py
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
import unittest
import frappe
from frappe.utils import nowdate
-from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_encounter, create_healthcare_docs, create_appointment
+from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_encounter, create_healthcare_docs, create_appointment, create_medical_department
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
class TestPatientMedicalRecord(unittest.TestCase):
@@ -15,7 +15,8 @@ class TestPatientMedicalRecord(unittest.TestCase):
make_pos_profile()
def test_medical_record(self):
- patient, medical_department, practitioner = create_healthcare_docs()
+ patient, practitioner = create_healthcare_docs()
+ medical_department = create_medical_department()
appointment = create_appointment(patient, practitioner, nowdate(), invoice=1)
encounter = create_encounter(appointment)
diff --git a/erpnext/healthcare/doctype/practitioner_schedule/test_practitioner_schedule.js b/erpnext/healthcare/doctype/practitioner_schedule/test_practitioner_schedule.js
deleted file mode 100644
index 32dac2c652..0000000000
--- a/erpnext/healthcare/doctype/practitioner_schedule/test_practitioner_schedule.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Practitioner Schedule", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Practitioner Schedule
- () => frappe.tests.make('Practitioner Schedule', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/prescription_dosage/test_prescription_dosage.js b/erpnext/healthcare/doctype/prescription_dosage/test_prescription_dosage.js
deleted file mode 100644
index 009614ff5d..0000000000
--- a/erpnext/healthcare/doctype/prescription_dosage/test_prescription_dosage.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Prescription Dosage", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Prescription Dosage
- () => frappe.tests.make('Prescription Dosage', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/prescription_duration/test_prescription_duration.js b/erpnext/healthcare/doctype/prescription_duration/test_prescription_duration.js
deleted file mode 100644
index 4971e79198..0000000000
--- a/erpnext/healthcare/doctype/prescription_duration/test_prescription_duration.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Prescription Duration", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Prescription Duration
- () => frappe.tests.make('Prescription Duration', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/sample_collection/test_sample_collection.js b/erpnext/healthcare/doctype/sample_collection/test_sample_collection.js
deleted file mode 100644
index 2b4aed756b..0000000000
--- a/erpnext/healthcare/doctype/sample_collection/test_sample_collection.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Sample Collection", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Sample Collection
- () => frappe.tests.make('Sample Collection', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/sensitivity/test_sensitivity.js b/erpnext/healthcare/doctype/sensitivity/test_sensitivity.js
deleted file mode 100644
index c2cf406f96..0000000000
--- a/erpnext/healthcare/doctype/sensitivity/test_sensitivity.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Sensitivity", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Sensitivity
- () => frappe.tests.make('Sensitivity', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py b/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
index 113fa513f9..983fba9f5f 100644
--- a/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
+++ b/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
@@ -8,11 +8,13 @@ import unittest
from frappe.utils import getdate, flt, nowdate
from erpnext.healthcare.doctype.therapy_type.test_therapy_type import create_therapy_type
from erpnext.healthcare.doctype.therapy_plan.therapy_plan import make_therapy_session, make_sales_invoice
-from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_healthcare_docs, create_patient, create_appointment
+from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import \
+ create_healthcare_docs, create_patient, create_appointment, create_medical_department
class TestTherapyPlan(unittest.TestCase):
def test_creation_on_encounter_submission(self):
- patient, medical_department, practitioner = create_healthcare_docs()
+ patient, practitioner = create_healthcare_docs()
+ medical_department = create_medical_department()
encounter = create_encounter(patient, medical_department, practitioner)
self.assertTrue(frappe.db.exists('Therapy Plan', encounter.therapy_plan))
@@ -28,8 +30,9 @@ class TestTherapyPlan(unittest.TestCase):
frappe.get_doc(session).submit()
self.assertEqual(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'Completed')
- patient, medical_department, practitioner = create_healthcare_docs()
- appointment = create_appointment(patient, practitioner, nowdate())
+ patient, practitioner = create_healthcare_docs()
+ appointment = create_appointment(patient, practitioner, nowdate())
+
session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company', appointment.name)
session = frappe.get_doc(session)
session.submit()
diff --git a/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py b/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py
index a5dad293e3..80fc83fd6c 100644
--- a/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py
+++ b/erpnext/healthcare/doctype/therapy_type/test_therapy_type.py
@@ -34,7 +34,8 @@ def create_therapy_type():
})
therapy_type.save()
else:
- therapy_type = frappe.get_doc('Therapy Type', 'Basic Rehab')
+ therapy_type = frappe.get_doc('Therapy Type', therapy_type)
+
return therapy_type
def create_exercise_type():
@@ -47,4 +48,7 @@ def create_exercise_type():
'description': 'Squat and Rise'
})
exercise_type.save()
+ else:
+ exercise_type = frappe.get_doc('Exercise Type', exercise_type)
+
return exercise_type
diff --git a/erpnext/healthcare/doctype/treatment_plan_template/__init__.py b/erpnext/healthcare/doctype/treatment_plan_template/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/healthcare/doctype/treatment_plan_template/test_records.json b/erpnext/healthcare/doctype/treatment_plan_template/test_records.json
new file mode 100644
index 0000000000..d661b4304f
--- /dev/null
+++ b/erpnext/healthcare/doctype/treatment_plan_template/test_records.json
@@ -0,0 +1,7 @@
+[
+ {
+ "doctype": "Treatment Plan Template",
+ "template_name": "Chemo",
+ "patient_age_from": 21
+ }
+]
diff --git a/erpnext/healthcare/doctype/treatment_plan_template/test_treatment_plan_template.py b/erpnext/healthcare/doctype/treatment_plan_template/test_treatment_plan_template.py
new file mode 100644
index 0000000000..21ede7129f
--- /dev/null
+++ b/erpnext/healthcare/doctype/treatment_plan_template/test_treatment_plan_template.py
@@ -0,0 +1,8 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+
+# import frappe
+import unittest
+
+class TestTreatmentPlanTemplate(unittest.TestCase):
+ pass
diff --git a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.js b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.js
new file mode 100644
index 0000000000..986c3cb6e4
--- /dev/null
+++ b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.js
@@ -0,0 +1,14 @@
+// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Treatment Plan Template', {
+ refresh: function (frm) {
+ frm.set_query('type', 'items', function () {
+ return {
+ filters: {
+ 'name': ['in', ['Lab Test Template', 'Clinical Procedure Template', 'Therapy Type']],
+ }
+ };
+ });
+ },
+});
diff --git a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.json b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.json
new file mode 100644
index 0000000000..85a312fb17
--- /dev/null
+++ b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.json
@@ -0,0 +1,189 @@
+{
+ "actions": [],
+ "autoname": "field:template_name",
+ "creation": "2021-06-10 10:14:17.901273",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "section_break_1",
+ "template_name",
+ "description",
+ "practitioners",
+ "disabled",
+ "column_break_1",
+ "medical_department",
+ "goal",
+ "order_group",
+ "section_break_8",
+ "patient_age_from",
+ "complaints",
+ "gender",
+ "column_break_12",
+ "patient_age_to",
+ "diagnosis",
+ "plan_items_section",
+ "items",
+ "drugs"
+ ],
+ "fields": [
+ {
+ "fieldname": "section_break_1",
+ "fieldtype": "Section Break",
+ "label": "Plan Details"
+ },
+ {
+ "fieldname": "medical_department",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Medical Department",
+ "options": "Medical Department"
+ },
+ {
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "label": "Description"
+ },
+ {
+ "fieldname": "goal",
+ "fieldtype": "Small Text",
+ "label": "Goal"
+ },
+ {
+ "fieldname": "practitioners",
+ "fieldtype": "Table MultiSelect",
+ "label": "Practitioners",
+ "options": "Treatment Plan Template Practitioner"
+ },
+ {
+ "fieldname": "order_group",
+ "fieldtype": "Link",
+ "label": "Order Group",
+ "options": "Patient Encounter",
+ "read_only": 1
+ },
+ {
+ "fieldname": "section_break_8",
+ "fieldtype": "Section Break",
+ "label": "Plan Conditions"
+ },
+ {
+ "fieldname": "template_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Template Name",
+ "reqd": 1,
+ "unique": 1
+ },
+ {
+ "fieldname": "patient_age_from",
+ "fieldtype": "Int",
+ "label": "Patient Age From",
+ "non_negative": 1
+ },
+ {
+ "fieldname": "column_break_12",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "patient_age_to",
+ "fieldtype": "Int",
+ "label": "Patient Age To",
+ "non_negative": 1
+ },
+ {
+ "fieldname": "gender",
+ "fieldtype": "Link",
+ "label": "Gender",
+ "options": "Gender"
+ },
+ {
+ "fieldname": "complaints",
+ "fieldtype": "Table MultiSelect",
+ "label": "Complaints",
+ "options": "Patient Encounter Symptom"
+ },
+ {
+ "fieldname": "diagnosis",
+ "fieldtype": "Table MultiSelect",
+ "label": "Diagnosis",
+ "options": "Patient Encounter Diagnosis"
+ },
+ {
+ "fieldname": "plan_items_section",
+ "fieldtype": "Section Break",
+ "label": "Plan Items"
+ },
+ {
+ "fieldname": "items",
+ "fieldtype": "Table",
+ "label": "Items",
+ "options": "Treatment Plan Template Item"
+ },
+ {
+ "fieldname": "drugs",
+ "fieldtype": "Table",
+ "label": "Drugs",
+ "options": "Drug Prescription"
+ },
+ {
+ "default": "0",
+ "fieldname": "disabled",
+ "fieldtype": "Check",
+ "label": "Disabled"
+ },
+ {
+ "fieldname": "column_break_1",
+ "fieldtype": "Column Break"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2021-08-18 02:41:58.354296",
+ "modified_by": "Administrator",
+ "module": "Healthcare",
+ "name": "Treatment Plan Template",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "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": "Healthcare Administrator",
+ "share": 1,
+ "write": 1
+ }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "template_name",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.py b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.py
new file mode 100644
index 0000000000..a92e2668fe
--- /dev/null
+++ b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template.py
@@ -0,0 +1,19 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+import frappe
+from frappe import _
+from frappe.model.document import Document
+
+class TreatmentPlanTemplate(Document):
+ def validate(self):
+ self.validate_age()
+
+ def validate_age(self):
+ if self.patient_age_from and self.patient_age_from < 0:
+ frappe.throw(_('Patient Age From cannot be less than 0'))
+ if self.patient_age_to and self.patient_age_to < 0:
+ frappe.throw(_('Patient Age To cannot be less than 0'))
+ if self.patient_age_to and self.patient_age_from and \
+ self.patient_age_to < self.patient_age_from:
+ frappe.throw(_('Patient Age To cannot be less than Patient Age From'))
diff --git a/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template_list.js b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template_list.js
new file mode 100644
index 0000000000..7ab31dff79
--- /dev/null
+++ b/erpnext/healthcare/doctype/treatment_plan_template/treatment_plan_template_list.js
@@ -0,0 +1,10 @@
+frappe.listview_settings['Treatment Plan Template'] = {
+ get_indicator: function(doc) {
+ var colors = {
+ 1: 'gray',
+ 0: 'blue',
+ };
+ let label = doc.disabled == 1 ? 'Disabled' : 'Enabled';
+ return [__(label), colors[doc.disabled], 'disable,=,' + doc.disabled];
+ }
+};
diff --git a/erpnext/healthcare/doctype/treatment_plan_template_item/__init__.py b/erpnext/healthcare/doctype/treatment_plan_template_item/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/healthcare/doctype/treatment_plan_template_item/treatment_plan_template_item.json b/erpnext/healthcare/doctype/treatment_plan_template_item/treatment_plan_template_item.json
new file mode 100644
index 0000000000..20a9d6793a
--- /dev/null
+++ b/erpnext/healthcare/doctype/treatment_plan_template_item/treatment_plan_template_item.json
@@ -0,0 +1,55 @@
+{
+ "actions": [],
+ "creation": "2021-06-10 11:47:29.194795",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "type",
+ "template",
+ "qty",
+ "instructions"
+ ],
+ "fields": [
+ {
+ "fieldname": "type",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Type",
+ "options": "DocType",
+ "reqd": 1
+ },
+ {
+ "fieldname": "template",
+ "fieldtype": "Dynamic Link",
+ "in_list_view": 1,
+ "label": "Template",
+ "options": "type",
+ "reqd": 1
+ },
+ {
+ "default": "1",
+ "fieldname": "qty",
+ "fieldtype": "Int",
+ "label": "Qty"
+ },
+ {
+ "fieldname": "instructions",
+ "fieldtype": "Small Text",
+ "in_list_view": 1,
+ "label": "Instructions"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-08-17 11:19:03.515441",
+ "modified_by": "Administrator",
+ "module": "Healthcare",
+ "name": "Treatment Plan Template Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/treatment_plan_template_item/treatment_plan_template_item.py b/erpnext/healthcare/doctype/treatment_plan_template_item/treatment_plan_template_item.py
new file mode 100644
index 0000000000..5f58b06af6
--- /dev/null
+++ b/erpnext/healthcare/doctype/treatment_plan_template_item/treatment_plan_template_item.py
@@ -0,0 +1,8 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+class TreatmentPlanTemplateItem(Document):
+ pass
diff --git a/erpnext/healthcare/doctype/treatment_plan_template_practitioner/__init__.py b/erpnext/healthcare/doctype/treatment_plan_template_practitioner/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/erpnext/healthcare/doctype/treatment_plan_template_practitioner/treatment_plan_template_practitioner.json b/erpnext/healthcare/doctype/treatment_plan_template_practitioner/treatment_plan_template_practitioner.json
new file mode 100644
index 0000000000..04da387f7b
--- /dev/null
+++ b/erpnext/healthcare/doctype/treatment_plan_template_practitioner/treatment_plan_template_practitioner.json
@@ -0,0 +1,32 @@
+{
+ "actions": [],
+ "creation": "2021-06-10 10:37:56.669416",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "practitioner"
+ ],
+ "fields": [
+ {
+ "fieldname": "practitioner",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Practitioner",
+ "options": "Healthcare Practitioner",
+ "reqd": 1
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-06-11 16:05:06.733299",
+ "modified_by": "Administrator",
+ "module": "Healthcare",
+ "name": "Treatment Plan Template Practitioner",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/treatment_plan_template_practitioner/treatment_plan_template_practitioner.py b/erpnext/healthcare/doctype/treatment_plan_template_practitioner/treatment_plan_template_practitioner.py
new file mode 100644
index 0000000000..6d34568e15
--- /dev/null
+++ b/erpnext/healthcare/doctype/treatment_plan_template_practitioner/treatment_plan_template_practitioner.py
@@ -0,0 +1,8 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+class TreatmentPlanTemplatePractitioner(Document):
+ pass
diff --git a/erpnext/healthcare/doctype/vital_signs/test_vital_signs.js b/erpnext/healthcare/doctype/vital_signs/test_vital_signs.js
deleted file mode 100644
index f4ab4466be..0000000000
--- a/erpnext/healthcare/doctype/vital_signs/test_vital_signs.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/* eslint-disable */
-// rename this file from _test_[name] to test_[name] to activate
-// and remove above this line
-
-QUnit.test("test: Vital Signs", function (assert) {
- let done = assert.async();
-
- // number of asserts
- assert.expect(1);
-
- frappe.run_serially([
- // insert a new Vital Signs
- () => frappe.tests.make('Vital Signs', [
- // values to be set
- {key: 'value'}
- ]),
- () => {
- assert.equal(cur_frm.doc.key, 'value');
- },
- () => done()
- ]);
-
-});
diff --git a/erpnext/healthcare/module_onboarding/healthcare/healthcare.json b/erpnext/healthcare/module_onboarding/healthcare/healthcare.json
index 56c3c13559..0aa8f9a027 100644
--- a/erpnext/healthcare/module_onboarding/healthcare/healthcare.json
+++ b/erpnext/healthcare/module_onboarding/healthcare/healthcare.json
@@ -10,7 +10,7 @@
"documentation_url": "https://docs.erpnext.com/docs/user/manual/en/healthcare",
"idx": 0,
"is_complete": 0,
- "modified": "2020-07-08 14:06:19.512946",
+ "modified": "2021-01-30 19:22:20.273766",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Healthcare",
diff --git a/erpnext/healthcare/onboarding_step/create_healthcare_practitioner/create_healthcare_practitioner.json b/erpnext/healthcare/onboarding_step/create_healthcare_practitioner/create_healthcare_practitioner.json
index c45a347080..3f25a9d676 100644
--- a/erpnext/healthcare/onboarding_step/create_healthcare_practitioner/create_healthcare_practitioner.json
+++ b/erpnext/healthcare/onboarding_step/create_healthcare_practitioner/create_healthcare_practitioner.json
@@ -5,14 +5,14 @@
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
- "is_mandatory": 1,
"is_single": 0,
"is_skipped": 0,
- "modified": "2020-05-26 23:16:31.965521",
+ "modified": "2021-01-30 12:02:22.849260",
"modified_by": "Administrator",
"name": "Create Healthcare Practitioner",
"owner": "Administrator",
"reference_document": "Healthcare Practitioner",
+ "show_form_tour": 0,
"show_full_form": 1,
"title": "Create Healthcare Practitioner",
"validate_action": 1
diff --git a/erpnext/healthcare/onboarding_step/create_patient/create_patient.json b/erpnext/healthcare/onboarding_step/create_patient/create_patient.json
index 77bc5bd7ad..b46bb15b48 100644
--- a/erpnext/healthcare/onboarding_step/create_patient/create_patient.json
+++ b/erpnext/healthcare/onboarding_step/create_patient/create_patient.json
@@ -5,14 +5,14 @@
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
- "is_mandatory": 1,
"is_single": 0,
"is_skipped": 0,
- "modified": "2020-05-19 12:26:24.023418",
- "modified_by": "Administrator",
+ "modified": "2021-01-30 00:09:28.786428",
+ "modified_by": "ruchamahabal2@gmail.com",
"name": "Create Patient",
"owner": "Administrator",
"reference_document": "Patient",
+ "show_form_tour": 0,
"show_full_form": 1,
"title": "Create Patient",
"validate_action": 1
diff --git a/erpnext/healthcare/onboarding_step/create_practitioner_schedule/create_practitioner_schedule.json b/erpnext/healthcare/onboarding_step/create_practitioner_schedule/create_practitioner_schedule.json
index 65980ef668..7ce122d5c0 100644
--- a/erpnext/healthcare/onboarding_step/create_practitioner_schedule/create_practitioner_schedule.json
+++ b/erpnext/healthcare/onboarding_step/create_practitioner_schedule/create_practitioner_schedule.json
@@ -5,14 +5,14 @@
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
- "is_mandatory": 1,
"is_single": 0,
"is_skipped": 0,
- "modified": "2020-05-19 12:27:09.437825",
- "modified_by": "Administrator",
+ "modified": "2021-01-30 00:09:28.794602",
+ "modified_by": "ruchamahabal2@gmail.com",
"name": "Create Practitioner Schedule",
"owner": "Administrator",
"reference_document": "Practitioner Schedule",
+ "show_form_tour": 0,
"show_full_form": 1,
"title": "Create Practitioner Schedule",
"validate_action": 1
diff --git a/erpnext/healthcare/onboarding_step/explore_clinical_procedure_templates/explore_clinical_procedure_templates.json b/erpnext/healthcare/onboarding_step/explore_clinical_procedure_templates/explore_clinical_procedure_templates.json
index 697b761e52..dfe9f71a76 100644
--- a/erpnext/healthcare/onboarding_step/explore_clinical_procedure_templates/explore_clinical_procedure_templates.json
+++ b/erpnext/healthcare/onboarding_step/explore_clinical_procedure_templates/explore_clinical_procedure_templates.json
@@ -5,14 +5,14 @@
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
- "is_mandatory": 0,
"is_single": 0,
"is_skipped": 0,
- "modified": "2020-05-26 23:10:24.504030",
+ "modified": "2021-01-30 19:22:08.257160",
"modified_by": "Administrator",
"name": "Explore Clinical Procedure Templates",
"owner": "Administrator",
"reference_document": "Clinical Procedure Template",
+ "show_form_tour": 0,
"show_full_form": 0,
"title": "Explore Clinical Procedure Templates",
"validate_action": 1
diff --git a/erpnext/healthcare/onboarding_step/explore_healthcare_settings/explore_healthcare_settings.json b/erpnext/healthcare/onboarding_step/explore_healthcare_settings/explore_healthcare_settings.json
index b2d5aef431..2d952f3093 100644
--- a/erpnext/healthcare/onboarding_step/explore_healthcare_settings/explore_healthcare_settings.json
+++ b/erpnext/healthcare/onboarding_step/explore_healthcare_settings/explore_healthcare_settings.json
@@ -5,14 +5,14 @@
"doctype": "Onboarding Step",
"idx": 0,
"is_complete": 0,
- "is_mandatory": 1,
"is_single": 1,
"is_skipped": 0,
- "modified": "2020-05-26 23:10:24.507648",
+ "modified": "2021-01-30 19:22:07.275735",
"modified_by": "Administrator",
"name": "Explore Healthcare Settings",
"owner": "Administrator",
"reference_document": "Healthcare Settings",
+ "show_form_tour": 0,
"show_full_form": 0,
"title": "Explore Healthcare Settings",
"validate_action": 1
diff --git a/erpnext/healthcare/onboarding_step/introduction_to_healthcare_practitioner/introduction_to_healthcare_practitioner.json b/erpnext/healthcare/onboarding_step/introduction_to_healthcare_practitioner/introduction_to_healthcare_practitioner.json
index fa4c9036d7..baa8358c06 100644
--- a/erpnext/healthcare/onboarding_step/introduction_to_healthcare_practitioner/introduction_to_healthcare_practitioner.json
+++ b/erpnext/healthcare/onboarding_step/introduction_to_healthcare_practitioner/introduction_to_healthcare_practitioner.json
@@ -6,14 +6,14 @@
"field": "schedule",
"idx": 0,
"is_complete": 0,
- "is_mandatory": 1,
"is_single": 0,
"is_skipped": 0,
- "modified": "2020-05-26 22:07:07.482530",
- "modified_by": "Administrator",
+ "modified": "2021-01-30 00:09:28.807129",
+ "modified_by": "ruchamahabal2@gmail.com",
"name": "Introduction to Healthcare Practitioner",
"owner": "Administrator",
"reference_document": "Healthcare Practitioner",
+ "show_form_tour": 0,
"show_full_form": 0,
"title": "Introduction to Healthcare Practitioner",
"validate_action": 0
diff --git a/erpnext/healthcare/page/patient_history/patient_history.css b/erpnext/healthcare/page/patient_history/patient_history.css
index 1bb589164e..74b5e7eb91 100644
--- a/erpnext/healthcare/page/patient_history/patient_history.css
+++ b/erpnext/healthcare/page/patient_history/patient_history.css
@@ -9,6 +9,26 @@
cursor: pointer;
}
+.patient-image-container {
+ margin-top: 17px;
+ }
+
+.patient-image {
+ display: inline-block;
+ width: 100%;
+ height: 0;
+ padding: 50% 0px;
+ background-size: cover;
+ background-repeat: no-repeat;
+ background-position: center center;
+ border-radius: 4px;
+}
+
+.patient-name {
+ font-size: 20px;
+ margin-top: 25px;
+}
+
.medical_record-label {
max-width: 100px;
margin-bottom: -4px;
@@ -19,19 +39,19 @@
}
.date-indicator {
- background:none;
- font-size:12px;
- vertical-align:middle;
- font-weight:bold;
- color:#6c7680;
+ background:none;
+ font-size:12px;
+ vertical-align:middle;
+ font-weight:bold;
+ color:#6c7680;
}
.date-indicator::after {
- margin:0 -4px 0 12px;
- content:'';
- display:inline-block;
- height:8px;
- width:8px;
- border-radius:8px;
+ margin:0 -4px 0 12px;
+ content:'';
+ display:inline-block;
+ height:8px;
+ width:8px;
+ border-radius:8px;
background: #d1d8dd;
}
diff --git a/erpnext/healthcare/page/patient_history/patient_history.html b/erpnext/healthcare/page/patient_history/patient_history.html
index f1706557f4..d16b38637c 100644
--- a/erpnext/healthcare/page/patient_history/patient_history.html
+++ b/erpnext/healthcare/page/patient_history/patient_history.html
@@ -1,26 +1,18 @@
-
-
-
-
+
+
-
diff --git a/erpnext/healthcare/page/patient_history/patient_history.js b/erpnext/healthcare/page/patient_history/patient_history.js
index 54343aae44..bf947cac21 100644
--- a/erpnext/healthcare/page/patient_history/patient_history.js
+++ b/erpnext/healthcare/page/patient_history/patient_history.js
@@ -1,403 +1,455 @@
frappe.provide('frappe.patient_history');
frappe.pages['patient_history'].on_page_load = function(wrapper) {
- let me = this;
- let page = frappe.ui.make_app_page({
+ frappe.ui.make_app_page({
parent: wrapper,
- title: 'Patient History',
- single_column: true
+ title: __('Patient History')
});
- frappe.breadcrumbs.add('Healthcare');
- let pid = '';
- page.main.html(frappe.render_template('patient_history', {}));
- page.main.find('.header-separator').hide();
-
- let patient = frappe.ui.form.make_control({
- parent: page.main.find('.patient'),
- df: {
- fieldtype: 'Link',
- options: 'Patient',
- fieldname: 'patient',
- placeholder: __('Select Patient'),
- only_select: true,
- change: function() {
- let patient_id = patient.get_value();
- if (pid != patient_id && patient_id) {
- me.start = 0;
- me.page.main.find('.patient_documents_list').html('');
- setup_filters(patient_id, me);
- get_documents(patient_id, me);
- show_patient_info(patient_id, me);
- show_patient_vital_charts(patient_id, me, 'bp', 'mmHg', 'Blood Pressure');
- }
- pid = patient_id;
- }
- },
- });
- patient.refresh();
-
- if (frappe.route_options) {
- patient.set_value(frappe.route_options.patient);
- }
-
- this.page.main.on('click', '.btn-show-chart', function() {
- let btn_show_id = $(this).attr('data-show-chart-id'), pts = $(this).attr('data-pts');
- let title = $(this).attr('data-title');
- show_patient_vital_charts(patient.get_value(), me, btn_show_id, pts, title);
- });
-
- this.page.main.on('click', '.btn-more', function() {
- let doctype = $(this).attr('data-doctype'), docname = $(this).attr('data-docname');
- if (me.page.main.find('.'+docname).parent().find('.document-html').attr('data-fetched') == '1') {
- me.page.main.find('.'+docname).hide();
- me.page.main.find('.'+docname).parent().find('.document-html').show();
- } else {
- if (doctype && docname) {
- let exclude = ['patient', 'patient_name', 'patient_sex', 'encounter_date'];
- frappe.call({
- method: 'erpnext.healthcare.utils.render_doc_as_html',
- args:{
- doctype: doctype,
- docname: docname,
- exclude_fields: exclude
- },
- freeze: true,
- callback: function(r) {
- if (r.message) {
- me.page.main.find('.' + docname).hide();
-
- me.page.main.find('.' + docname).parent().find('.document-html').html(
- `${r.message.html}
-
- `);
-
- me.page.main.find('.' + docname).parent().find('.document-html').show();
- me.page.main.find('.' + docname).parent().find('.document-html').attr('data-fetched', '1');
- }
- }
- });
- }
- }
- });
-
- this.page.main.on('click', '.btn-less', function() {
- let docname = $(this).attr('data-docname');
- me.page.main.find('.' + docname).parent().find('.document-id').show();
- me.page.main.find('.' + docname).parent().find('.document-html').hide();
- });
- me.start = 0;
- me.page.main.on('click', '.btn-get-records', function() {
- get_documents(patient.get_value(), me);
+ let patient_history = new PatientHistory(wrapper);
+ $(wrapper).bind('show', ()=> {
+ patient_history.show();
});
};
-let setup_filters = function(patient, me) {
- $('.doctype-filter').empty();
- frappe.xcall(
- 'erpnext.healthcare.page.patient_history.patient_history.get_patient_history_doctypes'
- ).then(document_types => {
- let doctype_filter = frappe.ui.form.make_control({
- parent: $('.doctype-filter'),
+class PatientHistory {
+ constructor(wrapper) {
+ this.wrapper = $(wrapper);
+ this.page = wrapper.page;
+ this.sidebar = this.wrapper.find('.layout-side-section');
+ this.main_section = this.wrapper.find('.layout-main-section');
+ this.start = 0;
+ }
+
+ show() {
+ frappe.breadcrumbs.add('Healthcare');
+ this.sidebar.empty();
+
+ let me = this;
+ let patient = frappe.ui.form.make_control({
+ parent: me.sidebar,
df: {
- fieldtype: 'MultiSelectList',
- fieldname: 'document_type',
- placeholder: __('Select Document Type'),
- input_class: 'input-xs',
+ fieldtype: 'Link',
+ options: 'Patient',
+ fieldname: 'patient',
+ placeholder: __('Select Patient'),
+ only_select: true,
change: () => {
- me.start = 0;
- me.page.main.find('.patient_documents_list').html('');
- get_documents(patient, me, doctype_filter.get_value(), date_range_field.get_value());
- },
- get_data: () => {
- return document_types.map(document_type => {
- return {
- description: document_type,
- value: document_type
- };
- });
- },
+ me.patient_id = '';
+ if (me.patient_id != patient.get_value() && patient.get_value()) {
+ me.start = 0;
+ me.patient_id = patient.get_value();
+ me.make_patient_profile();
+ }
+ }
}
});
- doctype_filter.refresh();
+ patient.refresh();
- $('.date-filter').empty();
- let date_range_field = frappe.ui.form.make_control({
- df: {
- fieldtype: 'DateRange',
- fieldname: 'date_range',
- placeholder: __('Date Range'),
- input_class: 'input-xs',
- change: () => {
- let selected_date_range = date_range_field.get_value();
- if (selected_date_range && selected_date_range.length === 2) {
+ if (frappe.route_options && !this.patient_id) {
+ patient.set_value(frappe.route_options.patient);
+ this.patient_id = frappe.route_options.patient;
+ }
+
+ this.sidebar.find('[data-fieldname="patient"]').append('
');
+ }
+
+ make_patient_profile() {
+ this.page.set_title(__('Patient History'));
+ this.main_section.empty().append(frappe.render_template('patient_history'));
+ this.setup_filters();
+ this.setup_documents();
+ this.show_patient_info();
+ this.setup_buttons();
+ this.show_patient_vital_charts('bp', 'mmHg', 'Blood Pressure');
+ }
+
+ setup_filters() {
+ $('.doctype-filter').empty();
+ let me = this;
+
+ frappe.xcall(
+ 'erpnext.healthcare.page.patient_history.patient_history.get_patient_history_doctypes'
+ ).then(document_types => {
+ let doctype_filter = frappe.ui.form.make_control({
+ parent: $('.doctype-filter'),
+ df: {
+ fieldtype: 'MultiSelectList',
+ fieldname: 'document_type',
+ placeholder: __('Select Document Type'),
+ change: () => {
me.start = 0;
me.page.main.find('.patient_documents_list').html('');
- get_documents(patient, me, doctype_filter.get_value(), selected_date_range);
- }
+ this.setup_documents(doctype_filter.get_value(), date_range_field.get_value());
+ },
+ get_data: () => {
+ return document_types.map(document_type => {
+ return {
+ description: document_type,
+ value: document_type
+ };
+ });
+ },
}
- },
- parent: $('.date-filter')
+ });
+ doctype_filter.refresh();
+
+ $('.date-filter').empty();
+ let date_range_field = frappe.ui.form.make_control({
+ df: {
+ fieldtype: 'DateRange',
+ fieldname: 'date_range',
+ placeholder: __('Date Range'),
+ input_class: 'input-xs',
+ change: () => {
+ let selected_date_range = date_range_field.get_value();
+ if (selected_date_range && selected_date_range.length === 2) {
+ me.start = 0;
+ me.page.main.find('.patient_documents_list').html('');
+ this.setup_documents(doctype_filter.get_value(), date_range_field.get_value());
+ }
+ }
+ },
+ parent: $('.date-filter')
+ });
+ date_range_field.refresh();
});
- date_range_field.refresh();
- });
-};
+ }
-let get_documents = function(patient, me, document_types="", selected_date_range="") {
- let filters = {
- name: patient,
- start: me.start,
- page_length: 20
- };
- if (document_types)
- filters['document_types'] = document_types;
- if (selected_date_range)
- filters['date_range'] = selected_date_range;
+ setup_documents(document_types="", selected_date_range="") {
+ let filters = {
+ name: this.patient_id,
+ start: this.start,
+ page_length: 20
+ };
+ if (document_types)
+ filters['document_types'] = document_types;
+ if (selected_date_range)
+ filters['date_range'] = selected_date_range;
- frappe.call({
- 'method': 'erpnext.healthcare.page.patient_history.patient_history.get_feed',
- args: filters,
- callback: function(r) {
- let data = r.message;
- if (data.length) {
- add_to_records(me, data);
- } else {
- me.page.main.find('.patient_documents_list').append(`
-
-
${__('No more records..')}
-
`);
- me.page.main.find('.btn-get-records').hide();
+ let me = this;
+ frappe.call({
+ 'method': 'erpnext.healthcare.page.patient_history.patient_history.get_feed',
+ args: filters,
+ callback: function(r) {
+ let data = r.message;
+ if (data.length) {
+ me.add_to_records(data);
+ } else {
+ me.page.main.find('.patient_documents_list').append(`
+
+
${__('No more records..')}
+
`);
+ me.page.main.find('.btn-get-records').hide();
+ }
}
- }
- });
-};
+ });
+ }
-let add_to_records = function(me, data) {
- let details = "
";
- let i;
- for (i=0; i" + data[i].subject;
- }
- data[i] = add_date_separator(data[i]);
+ add_to_records(data) {
+ let details = "";
+ let i;
+ for (i=0; i" + data[i].subject;
+ }
+ data[i] = this.add_date_separator(data[i]);
- if (frappe.user_info(data[i].owner).image) {
- data[i].imgsrc = frappe.utils.get_file_link(frappe.user_info(data[i].owner).image);
- } else {
- data[i].imgsrc = false;
- }
+ if (frappe.user_info(data[i].owner).image) {
+ data[i].imgsrc = frappe.utils.get_file_link(frappe.user_info(data[i].owner).image);
+ } else {
+ data[i].imgsrc = false;
+ }
- let time_line_heading = data[i].practitioner ? `${data[i].practitioner} ` : ``;
- time_line_heading += data[i].reference_doctype + " - " +
- `
- ${data[i].reference_name}
- `;
+ let time_line_heading = data[i].practitioner ? `${data[i].practitioner} ` : ``;
+ time_line_heading += data[i].reference_doctype + " - " +
+ `
+ ${data[i].reference_name}
+ `;
- details += `
-