feat: Patient Appointment Analytics Script Report

This commit is contained in:
Rucha Mahabal 2020-03-02 23:14:30 +05:30
parent 9565e62e3a
commit 85aab34421
5 changed files with 293 additions and 2 deletions

View File

@ -228,7 +228,6 @@
"default": "0",
"fieldname": "invoiced",
"fieldtype": "Check",
"in_list_view": 1,
"label": "Invoiced",
"read_only": 1
},
@ -286,7 +285,7 @@
}
],
"links": [],
"modified": "2020-02-25 17:57:56.971064",
"modified": "2020-03-02 14:35:54.040428",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Patient Appointment",

View File

@ -0,0 +1,73 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* eslint-disable */
frappe.query_reports['Patient Appointment Analytics'] = {
"filters": [
{
fieldname: 'tree_type',
label: __('Tree Type'),
fieldtype: 'Select',
options: ['Healthcare Practitioner', 'Medical Department'],
default: 'Healthcare Practitioner',
reqd: 1
},
{
fieldname: 'status',
label: __('Appointment Status'),
fieldtype: 'Select',
options:[
{label: __('Scheduled'), value: 'Scheduled'},
{label: __('Open'), value: 'Open'},
{label: __('Closed'), value: 'Closed'},
{label: __('Expired'), value: 'Expired'},
{label: __('Cancelled'), value: 'Cancelled'}
]
},
{
fieldname: 'appointment_type',
label: __('Appointment Type'),
fieldtype: 'Link',
options: 'Appointment Type'
},
{
fieldname: 'practitioner',
label: __('Healthcare Practitioner'),
fieldtype: 'Link',
options: 'Healthcare Practitioner'
},
{
fieldname: 'department',
label: __('Medical Department'),
fieldtype: 'Link',
options: 'Medical Department'
},
{
fieldname: 'from_date',
label: __('From Date'),
fieldtype: 'Date',
default: frappe.defaults.get_user_default('year_start_date'),
reqd: 1
},
{
fieldname: 'to_date',
label: __('To Date'),
fieldtype: 'Date',
default: frappe.defaults.get_user_default('year_end_date'),
reqd: 1
},
{
fieldname: 'range',
label: __('Range'),
fieldtype: 'Select',
options:[
{label: __('Weekly'), value: 'Weekly'},
{label: __('Monthly'), value: 'Monthly'},
{label: __('Quarterly'), value: 'Quarterly'},
{label: __('Yearly'), value: 'Yearly'}
],
default: 'Monthly',
reqd: 1
}
]
};

View File

@ -0,0 +1,36 @@
{
"add_total_row": 1,
"creation": "2020-03-02 15:13:16.273493",
"disable_prepared_report": 0,
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"modified": "2020-03-02 15:13:16.273493",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Patient Appointment Analytics",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "Patient Appointment",
"report_name": "Patient Appointment Analytics",
"report_type": "Script Report",
"roles": [
{
"role": "Healthcare Administrator"
},
{
"role": "LabTest Approver"
},
{
"role": "Physician"
},
{
"role": "Nursing User"
},
{
"role": "Laboratory User"
}
]
}

View File

@ -0,0 +1,183 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe.utils import getdate, flt, add_to_date, add_days
from frappe import _ , scrub
from six import iteritems
from erpnext.accounts.utils import get_fiscal_year
def execute(filters=None):
return Analytics(filters).run()
class Analytics(object):
def __init__(self, filters=None):
self.filters = frappe._dict(filters or {})
self.months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
self.get_period_date_ranges()
def run(self):
self.get_columns()
self.get_data()
self.get_chart_data()
self.chart = ''
return self.columns, self.data, None, self.chart
def get_period_date_ranges(self):
from dateutil.relativedelta import relativedelta, MO
from_date, to_date = getdate(self.filters.from_date), getdate(self.filters.to_date)
increment = {
'Monthly': 1,
'Quarterly': 3,
'Half-Yearly': 6,
'Yearly': 12
}.get(self.filters.range, 1)
if self.filters.range in ['Monthly', 'Quarterly']:
from_date = from_date.replace(day=1)
elif self.filters.range == 'Yearly':
from_date = get_fiscal_year(from_date)[1]
else:
from_date = from_date + relativedelta(from_date, weekday=MO(-1))
self.periodic_daterange = []
for dummy in range(1, 53):
if self.filters.range == 'Weekly':
period_end_date = add_days(from_date, 6)
else:
period_end_date = add_to_date(from_date, months=increment, days=-1)
if period_end_date > to_date:
period_end_date = to_date
self.periodic_daterange.append(period_end_date)
from_date = add_days(period_end_date, 1)
if period_end_date == to_date:
break
def get_columns(self):
self.columns = []
if self.filters.tree_type == 'Healthcare Practitioner':
self.columns.append({
'label': _('Healthcare Practitioner'),
'options': 'Healthcare Practitioner',
'fieldname': 'practitioner',
'fieldtype': 'Link',
'width': 200
})
elif self.filters.tree_type == 'Medical Department':
self.columns.append({
'label': _('Medical Department'),
'fieldname': 'department',
'fieldtype': 'Link',
'options': 'Medical Department',
'width': 150
})
for end_date in self.periodic_daterange:
period = self.get_period(end_date)
self.columns.append({
'label': _(period),
'fieldname': scrub(period),
'fieldtype': 'Float',
'width': 120
})
self.columns.append({
'label': _('Total'),
'fieldname': 'total',
'fieldtype': 'Float',
'width': 120
})
def get_data(self):
if self.filters.tree_type == 'Healthcare Practitioner':
self.get_appointments_based_on_healthcare_practitioner()
self.get_rows()
elif self.filters.tree_type == 'Medical Department':
self.get_appointments_based_on_medical_department()
self.get_rows()
def get_chart_data(self):
pass
def get_period(self, appointment_date):
if self.filters.range == 'Weekly':
period = 'Week ' + str(appointment_date.isocalendar()[1]) + ' ' + str(appointment_date.year)
elif self.filters.range == 'Monthly':
period = str(self.months[appointment_date.month - 1]) + ' ' + str(appointment_date.year)
elif self.filters.range == 'Quarterly':
period = 'Quarter ' + str(((appointment_date.month - 1) // 3) + 1) + ' ' + str(appointment_date.year)
else:
year = get_fiscal_year(appointment_date, company=self.filters.company)
period = str(year[0])
return period
def get_appointments_based_on_healthcare_practitioner(self):
filters = self.get_common_filters()
self.entries = frappe.db.get_all('Patient Appointment',
fields=['appointment_date', 'name', 'patient', 'practitioner'],
filters=filters
)
def get_appointments_based_on_medical_department(self):
filters = self.get_common_filters()
if not filters.get('department'):
filters['department'] = ('!=', '')
self.entries = frappe.db.get_all('Patient Appointment',
fields=['appointment_date', 'name', 'patient', 'practitioner', 'department'],
filters=filters
)
def get_common_filters(self):
filters = {}
filters['appointment_date'] = ('between', [self.filters.from_date, self.filters.to_date])
for entry in ['appointment_type', 'practitioner', 'department', 'status']:
if self.filters.get(entry):
filters[entry] = self.filters.get(entry)
return filters
def get_rows(self):
self.data = []
self.get_periodic_data()
for entity, period_data in iteritems(self.appointment_periodic_data):
if self.filters.tree_type == 'Healthcare Practitioner':
row = {'practitioner': entity}
elif self.filters.tree_type == 'Medical Department':
row = {'department': entity}
total = 0
for end_date in self.periodic_daterange:
period = self.get_period(end_date)
amount = flt(period_data.get(period, 0.0))
row[scrub(period)] = amount
total += amount
row['total'] = total
self.data.append(row)
def get_periodic_data(self):
self.appointment_periodic_data = frappe._dict()
for d in self.entries:
period = self.get_period(d.get('appointment_date'))
if self.filters.tree_type == 'Healthcare Practitioner':
self.appointment_periodic_data.setdefault(d.practitioner, frappe._dict()).setdefault(period, 0.0)
self.appointment_periodic_data[d.practitioner][period] += 1
elif self.filters.tree_type == 'Medical Department':
self.appointment_periodic_data.setdefault(d.department, frappe._dict()).setdefault(period, 0.0)
self.appointment_periodic_data[d.department][period] += 1