Skip to content

Commit

Permalink
feat: Therapy Plan Template (#23558)
Browse files Browse the repository at this point in the history
* feat: Therapy Plan Template

* feat: Handle billing Therapy Plans created via Templates

* feat: add dashboard to Therapy Plan Template

* fix: codacy issues

* fix: sider

* fix: validate Therapy Session overlap

* feat: Create Sales Invoice from Therapy Plan

* fix: sider

* chore: added tests for Therapy Plan Template

* fix: test

* fix: test

Co-authored-by: rohitwaghchaure <rohitw1991@gmail.com>
Co-authored-by: Nabin Hait <nabinhait@gmail.com>
  • Loading branch information
3 people authored Oct 24, 2020
1 parent e977bc3 commit 434791e
Show file tree
Hide file tree
Showing 20 changed files with 594 additions and 29 deletions.
57 changes: 48 additions & 9 deletions erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

import frappe
import unittest
from frappe.utils import getdate
from frappe.utils import getdate, flt
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
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

class TestTherapyPlan(unittest.TestCase):
Expand All @@ -20,25 +20,45 @@ def test_status(self):
plan = create_therapy_plan()
self.assertEquals(plan.status, 'Not Started')

session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab')
session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company')
frappe.get_doc(session).submit()
self.assertEquals(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'In Progress')

session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab')
session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company')
frappe.get_doc(session).submit()
self.assertEquals(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'Completed')

def test_therapy_plan_from_template(self):
patient = create_patient()
template = create_therapy_plan_template()
# check linked item
self.assertTrue(frappe.db.exists('Therapy Plan Template', {'linked_item': 'Complete Rehab'}))

def create_therapy_plan():
plan = create_therapy_plan(template)
# invoice
si = make_sales_invoice(plan.name, patient, '_Test Company', template)
si.save()

therapy_plan_template_amt = frappe.db.get_value('Therapy Plan Template', template, 'total_amount')
self.assertEquals(si.items[0].amount, therapy_plan_template_amt)


def create_therapy_plan(template=None):
patient = create_patient()
therapy_type = create_therapy_type()
plan = frappe.new_doc('Therapy Plan')
plan.patient = patient
plan.start_date = getdate()
plan.append('therapy_plan_details', {
'therapy_type': therapy_type.name,
'no_of_sessions': 2
})

if template:
plan.therapy_plan_template = template
plan = plan.set_therapy_details_from_template()
else:
plan.append('therapy_plan_details', {
'therapy_type': therapy_type.name,
'no_of_sessions': 2
})

plan.save()
return plan

Expand All @@ -55,3 +75,22 @@ def create_encounter(patient, medical_department, practitioner):
encounter.save()
encounter.submit()
return encounter

def create_therapy_plan_template():
template_name = frappe.db.exists('Therapy Plan Template', 'Complete Rehab')
if not template_name:
therapy_type = create_therapy_type()
template = frappe.new_doc('Therapy Plan Template')
template.plan_name = template.item_code = template.item_name = 'Complete Rehab'
template.item_group = 'Services'
rate = frappe.db.get_value('Therapy Type', therapy_type.name, 'rate')
template.append('therapy_types', {
'therapy_type': therapy_type.name,
'no_of_sessions': 2,
'rate': rate,
'amount': 2 * flt(rate)
})
template.save()
template_name = template.name

return template_name
46 changes: 43 additions & 3 deletions erpnext/healthcare/doctype/therapy_plan/therapy_plan.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ frappe.ui.form.on('Therapy Plan', {
args: {
therapy_plan: frm.doc.name,
patient: frm.doc.patient,
therapy_type: data.therapy_type
therapy_type: data.therapy_type,
company: frm.doc.company
},
freeze: true,
callback: function(r) {
Expand All @@ -49,13 +50,53 @@ frappe.ui.form.on('Therapy Plan', {
});
}, __('Select Therapy Type'), __('Create'));
}, __('Create'));

if (frm.doc.therapy_plan_template && !frm.doc.invoiced) {
frm.add_custom_button(__('Sales Invoice'), function() {
frm.trigger('make_sales_invoice');
}, __('Create'));
}
}

if (frm.doc.therapy_plan_template) {
frappe.meta.get_docfield('Therapy Plan Detail', 'therapy_type', frm.doc.name).read_only = 1;
frappe.meta.get_docfield('Therapy Plan Detail', 'no_of_sessions', frm.doc.name).read_only = 1;
}
},

make_sales_invoice: function(frm) {
frappe.call({
args: {
'reference_name': frm.doc.name,
'patient': frm.doc.patient,
'company': frm.doc.company,
'therapy_plan_template': frm.doc.therapy_plan_template
},
method: 'erpnext.healthcare.doctype.therapy_plan.therapy_plan.make_sales_invoice',
callback: function(r) {
var doclist = frappe.model.sync(r.message);
frappe.set_route('Form', doclist[0].doctype, doclist[0].name);
}
});
},

therapy_plan_template: function(frm) {
if (frm.doc.therapy_plan_template) {
frappe.call({
method: 'set_therapy_details_from_template',
doc: frm.doc,
freeze: true,
freeze_message: __('Fetching Template Details'),
callback: function() {
refresh_field('therapy_plan_details');
}
});
}
},

show_progress_for_therapies: function(frm) {
let bars = [];
let message = '';
let added_min = false;

// completed sessions
let title = __('{0} sessions completed', [frm.doc.total_sessions_completed]);
Expand All @@ -71,7 +112,6 @@ frappe.ui.form.on('Therapy Plan', {
});
if (bars[0].width == '0%') {
bars[0].width = '0.5%';
added_min = 0.5;
}
message = title;
frm.dashboard.add_progress(__('Status'), bars, message);
Expand Down
23 changes: 21 additions & 2 deletions erpnext/healthcare/doctype/therapy_plan/therapy_plan.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
"naming_series",
"patient",
"patient_name",
"invoiced",
"column_break_4",
"company",
"status",
"start_date",
"section_break_3",
"therapy_plan_template",
"therapy_plan_details",
"title",
"section_break_9",
Expand Down Expand Up @@ -46,6 +48,7 @@
"fieldtype": "Table",
"label": "Therapy Plan Details",
"options": "Therapy Plan Detail",
"read_only_depends_on": "therapy_plan_template",
"reqd": 1
},
{
Expand Down Expand Up @@ -105,11 +108,27 @@
"fieldtype": "Link",
"in_standard_filter": 1,
"label": "Company",
"options": "Company"
"options": "Company",
"reqd": 1
},
{
"fieldname": "therapy_plan_template",
"fieldtype": "Link",
"label": "Therapy Plan Template",
"options": "Therapy Plan Template"
},
{
"default": "0",
"fieldname": "invoiced",
"fieldtype": "Check",
"label": "Invoiced",
"no_copy": 1,
"print_hide": 1,
"read_only": 1
}
],
"links": [],
"modified": "2020-05-25 14:38:53.649315",
"modified": "2020-10-23 01:27:42.128855",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Therapy Plan",
Expand Down
54 changes: 51 additions & 3 deletions erpnext/healthcare/doctype/therapy_plan/therapy_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from __future__ import unicode_literals
import frappe
from frappe.model.document import Document
from frappe.utils import today
from frappe.utils import flt, today

class TherapyPlan(Document):
def validate(self):
Expand Down Expand Up @@ -33,13 +33,26 @@ def set_totals(self):
self.db_set('total_sessions', total_sessions)
self.db_set('total_sessions_completed', total_sessions_completed)

def set_therapy_details_from_template(self):
# Add therapy types in the child table
self.set('therapy_plan_details', [])
therapy_plan_template = frappe.get_doc('Therapy Plan Template', self.therapy_plan_template)

for data in therapy_plan_template.therapy_types:
self.append('therapy_plan_details', {
'therapy_type': data.therapy_type,
'no_of_sessions': data.no_of_sessions
})
return self


@frappe.whitelist()
def make_therapy_session(therapy_plan, patient, therapy_type):
def make_therapy_session(therapy_plan, patient, therapy_type, company):
therapy_type = frappe.get_doc('Therapy Type', therapy_type)

therapy_session = frappe.new_doc('Therapy Session')
therapy_session.therapy_plan = therapy_plan
therapy_session.company = company
therapy_session.patient = patient
therapy_session.therapy_type = therapy_type.name
therapy_session.duration = therapy_type.default_duration
Expand All @@ -48,4 +61,39 @@ def make_therapy_session(therapy_plan, patient, therapy_type):

if frappe.flags.in_test:
therapy_session.start_date = today()
return therapy_session.as_dict()
return therapy_session.as_dict()


@frappe.whitelist()
def make_sales_invoice(reference_name, patient, company, therapy_plan_template):
from erpnext.stock.get_item_details import get_item_details
si = frappe.new_doc('Sales Invoice')
si.company = company
si.patient = patient
si.customer = frappe.db.get_value('Patient', patient, 'customer')

item = frappe.db.get_value('Therapy Plan Template', therapy_plan_template, 'linked_item')
price_list, price_list_currency = frappe.db.get_values('Price List', {'selling': 1}, ['name', 'currency'])[0]
args = {
'doctype': 'Sales Invoice',
'item_code': item,
'company': company,
'customer': si.customer,
'selling_price_list': price_list,
'price_list_currency': price_list_currency,
'plc_conversion_rate': 1.0,
'conversion_rate': 1.0
}

item_line = si.append('items', {})
item_details = get_item_details(args)
item_line.item_code = item
item_line.qty = 1
item_line.rate = item_details.price_list_rate
item_line.amount = flt(item_line.rate) * flt(item_line.qty)
item_line.reference_dt = 'Therapy Plan'
item_line.reference_dn = reference_name
item_line.description = item_details.description

si.set_missing_values(for_validate = True)
return si
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,18 @@
def get_data():
return {
'fieldname': 'therapy_plan',
'non_standard_fieldnames': {
'Sales Invoice': 'reference_dn'
},
'transactions': [
{
'label': _('Therapy Sessions'),
'items': ['Therapy Session']
},
{
'label': _('Billing'),
'items': ['Sales Invoice']
}
]
],
'disable_create_buttons': ['Sales Invoice']
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
],
"istable": 1,
"links": [],
"modified": "2020-03-30 22:02:01.740109",
"modified": "2020-10-08 01:17:34.778028",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Therapy Plan Detail",
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
from __future__ import unicode_literals

# import frappe
import unittest

class TestTherapyPlanTemplate(unittest.TestCase):
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt

frappe.ui.form.on('Therapy Plan Template', {
refresh: function(frm) {
frm.set_query('therapy_type', 'therapy_types', () => {
return {
filters: {
'is_billable': 1
}
};
});
},

set_totals: function(frm) {
let total_sessions = 0;
let total_amount = 0.0;
frm.doc.therapy_types.forEach((d) => {
if (d.no_of_sessions) total_sessions += cint(d.no_of_sessions);
if (d.amount) total_amount += flt(d.amount);
});
frm.set_value('total_sessions', total_sessions);
frm.set_value('total_amount', total_amount);
frm.refresh_fields();
}
});

frappe.ui.form.on('Therapy Plan Template Detail', {
therapy_type: function(frm, cdt, cdn) {
let row = locals[cdt][cdn];
frappe.call('frappe.client.get', {
doctype: 'Therapy Type',
name: row.therapy_type
}).then((res) => {
row.rate = res.message.rate;
if (!row.no_of_sessions)
row.no_of_sessions = 1;
row.amount = flt(row.rate) * cint(row.no_of_sessions);
frm.refresh_field('therapy_types');
frm.trigger('set_totals');
});
},

no_of_sessions: function(frm, cdt, cdn) {
let row = locals[cdt][cdn];
row.amount = flt(row.rate) * cint(row.no_of_sessions);
frm.refresh_field('therapy_types');
frm.trigger('set_totals');
},

rate: function(frm, cdt, cdn) {
let row = locals[cdt][cdn];
row.amount = flt(row.rate) * cint(row.no_of_sessions);
frm.refresh_field('therapy_types');
frm.trigger('set_totals');
}
});
Loading

0 comments on commit 434791e

Please sign in to comment.