feat: Therapy Plan Template (#23558)
* 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>
diff --git a/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py b/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
index 526bb95..a061c66 100644
--- a/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
+++ b/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
@@ -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):
@@ -20,25 +20,45 @@
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
@@ -55,3 +75,22 @@
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
diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.js b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.js
index dea0cfe..490d458 100644
--- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.js
+++ b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.js
@@ -37,7 +37,8 @@
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) {
@@ -49,13 +50,53 @@
});
}, __('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]);
@@ -71,7 +112,6 @@
});
if (bars[0].width == '0%') {
bars[0].width = '0.5%';
- added_min = 0.5;
}
message = title;
frm.dashboard.add_progress(__('Status'), bars, message);
diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.json b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.json
index 9edfeb2..ccb316e 100644
--- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.json
+++ b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.json
@@ -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",
@@ -46,6 +48,7 @@
"fieldtype": "Table",
"label": "Therapy Plan Details",
"options": "Therapy Plan Detail",
+ "read_only_depends_on": "therapy_plan_template",
"reqd": 1
},
{
@@ -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",
diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py
index e0f015f..bc0ff1a 100644
--- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py
+++ b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.py
@@ -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):
@@ -33,13 +33,26 @@
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
@@ -48,4 +61,39 @@
if frappe.flags.in_test:
therapy_session.start_date = today()
- return therapy_session.as_dict()
\ No newline at end of file
+ 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
diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan_dashboard.py b/erpnext/healthcare/doctype/therapy_plan/therapy_plan_dashboard.py
index df64782..6526acd 100644
--- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan_dashboard.py
+++ b/erpnext/healthcare/doctype/therapy_plan/therapy_plan_dashboard.py
@@ -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']
}
diff --git a/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.json b/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.json
index 9eb20e2..555587e 100644
--- a/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.json
+++ b/erpnext/healthcare/doctype/therapy_plan_detail/therapy_plan_detail.json
@@ -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",
diff --git a/erpnext/healthcare/doctype/therapy_plan_template/__init__.py b/erpnext/healthcare/doctype/therapy_plan_template/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/healthcare/doctype/therapy_plan_template/__init__.py
diff --git a/erpnext/healthcare/doctype/therapy_plan_template/test_therapy_plan_template.py b/erpnext/healthcare/doctype/therapy_plan_template/test_therapy_plan_template.py
new file mode 100644
index 0000000..33ee29d
--- /dev/null
+++ b/erpnext/healthcare/doctype/therapy_plan_template/test_therapy_plan_template.py
@@ -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
diff --git a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.js b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.js
new file mode 100644
index 0000000..86de192
--- /dev/null
+++ b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.js
@@ -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');
+ }
+});
diff --git a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.json b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.json
new file mode 100644
index 0000000..48fc896
--- /dev/null
+++ b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.json
@@ -0,0 +1,132 @@
+{
+ "actions": [],
+ "autoname": "field:plan_name",
+ "creation": "2020-09-22 17:51:38.861055",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "plan_name",
+ "linked_item_details_section",
+ "item_code",
+ "item_name",
+ "item_group",
+ "column_break_6",
+ "description",
+ "linked_item",
+ "therapy_types_section",
+ "therapy_types",
+ "section_break_11",
+ "total_sessions",
+ "column_break_13",
+ "total_amount"
+ ],
+ "fields": [
+ {
+ "fieldname": "plan_name",
+ "fieldtype": "Data",
+ "in_list_view": 1,
+ "label": "Plan Name",
+ "reqd": 1,
+ "unique": 1
+ },
+ {
+ "fieldname": "therapy_types_section",
+ "fieldtype": "Section Break",
+ "label": "Therapy Types"
+ },
+ {
+ "fieldname": "therapy_types",
+ "fieldtype": "Table",
+ "label": "Therapy Types",
+ "options": "Therapy Plan Template Detail",
+ "reqd": 1
+ },
+ {
+ "fieldname": "linked_item",
+ "fieldtype": "Link",
+ "label": "Linked Item",
+ "options": "Item",
+ "read_only": 1
+ },
+ {
+ "fieldname": "linked_item_details_section",
+ "fieldtype": "Section Break",
+ "label": "Linked Item Details"
+ },
+ {
+ "fieldname": "item_code",
+ "fieldtype": "Data",
+ "label": "Item Code",
+ "reqd": 1,
+ "set_only_once": 1
+ },
+ {
+ "fieldname": "item_name",
+ "fieldtype": "Data",
+ "label": "Item Name",
+ "reqd": 1
+ },
+ {
+ "fieldname": "item_group",
+ "fieldtype": "Link",
+ "label": "Item Group",
+ "options": "Item Group",
+ "reqd": 1
+ },
+ {
+ "fieldname": "column_break_6",
+ "fieldtype": "Column Break"
+ },
+ {
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "label": "Item Description"
+ },
+ {
+ "fieldname": "total_amount",
+ "fieldtype": "Currency",
+ "label": "Total Amount",
+ "read_only": 1
+ },
+ {
+ "fieldname": "section_break_11",
+ "fieldtype": "Section Break"
+ },
+ {
+ "fieldname": "total_sessions",
+ "fieldtype": "Int",
+ "label": "Total Sessions",
+ "read_only": 1
+ },
+ {
+ "fieldname": "column_break_13",
+ "fieldtype": "Column Break"
+ }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2020-10-08 00:56:58.062105",
+ "modified_by": "Administrator",
+ "module": "Healthcare",
+ "name": "Therapy 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
+ }
+ ],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.py b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.py
new file mode 100644
index 0000000..748c12c
--- /dev/null
+++ b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template.py
@@ -0,0 +1,73 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+from frappe.utils import cint, flt
+from erpnext.healthcare.doctype.therapy_type.therapy_type import make_item_price
+
+class TherapyPlanTemplate(Document):
+ def after_insert(self):
+ self.create_item_from_template()
+
+ def validate(self):
+ self.set_totals()
+
+ def on_update(self):
+ doc_before_save = self.get_doc_before_save()
+ if not doc_before_save: return
+ if doc_before_save.item_name != self.item_name or doc_before_save.item_group != self.item_group \
+ or doc_before_save.description != self.description:
+ self.update_item()
+
+ if doc_before_save.therapy_types != self.therapy_types:
+ self.update_item_price()
+
+ def set_totals(self):
+ total_sessions = 0
+ total_amount = 0
+
+ for entry in self.therapy_types:
+ total_sessions += cint(entry.no_of_sessions)
+ total_amount += flt(entry.amount)
+
+ self.total_sessions = total_sessions
+ self.total_amount = total_amount
+
+ def create_item_from_template(self):
+ uom = frappe.db.exists('UOM', 'Nos') or frappe.db.get_single_value('Stock Settings', 'stock_uom')
+
+ item = frappe.get_doc({
+ 'doctype': 'Item',
+ 'item_code': self.item_code,
+ 'item_name': self.item_name,
+ 'item_group': self.item_group,
+ 'description': self.description,
+ 'is_sales_item': 1,
+ 'is_service_item': 1,
+ 'is_purchase_item': 0,
+ 'is_stock_item': 0,
+ 'show_in_website': 0,
+ 'is_pro_applicable': 0,
+ 'stock_uom': uom
+ }).insert(ignore_permissions=True, ignore_mandatory=True)
+
+ make_item_price(item.name, self.total_amount)
+ self.db_set('linked_item', item.name)
+
+ def update_item(self):
+ item_doc = frappe.get_doc('Item', {'item_code': self.linked_item})
+ item_doc.item_name = self.item_name
+ item_doc.item_group = self.item_group
+ item_doc.description = self.description
+ item_doc.ignore_mandatory = True
+ item_doc.save(ignore_permissions=True)
+
+ def update_item_price(self):
+ item_price = frappe.get_doc('Item Price', {'item_code': self.linked_item})
+ item_price.item_name = self.item_name
+ item_price.price_list_rate = self.total_amount
+ item_price.ignore_mandatory = True
+ item_price.save(ignore_permissions=True)
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template_dashboard.py b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template_dashboard.py
new file mode 100644
index 0000000..c748fbf
--- /dev/null
+++ b/erpnext/healthcare/doctype/therapy_plan_template/therapy_plan_template_dashboard.py
@@ -0,0 +1,13 @@
+from __future__ import unicode_literals
+from frappe import _
+
+def get_data():
+ return {
+ 'fieldname': 'therapy_plan_template',
+ 'transactions': [
+ {
+ 'label': _('Therapy Plans'),
+ 'items': ['Therapy Plan']
+ }
+ ]
+ }
diff --git a/erpnext/healthcare/doctype/therapy_plan_template_detail/__init__.py b/erpnext/healthcare/doctype/therapy_plan_template_detail/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/healthcare/doctype/therapy_plan_template_detail/__init__.py
diff --git a/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.json b/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.json
new file mode 100644
index 0000000..5553a11
--- /dev/null
+++ b/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.json
@@ -0,0 +1,54 @@
+{
+ "actions": [],
+ "creation": "2020-10-07 23:04:44.373381",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+ "therapy_type",
+ "no_of_sessions",
+ "rate",
+ "amount"
+ ],
+ "fields": [
+ {
+ "fieldname": "therapy_type",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Therapy Type",
+ "options": "Therapy Type",
+ "reqd": 1
+ },
+ {
+ "fieldname": "no_of_sessions",
+ "fieldtype": "Int",
+ "in_list_view": 1,
+ "label": "No of Sessions"
+ },
+ {
+ "fieldname": "rate",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Rate"
+ },
+ {
+ "fieldname": "amount",
+ "fieldtype": "Currency",
+ "in_list_view": 1,
+ "label": "Amount",
+ "read_only": 1
+ }
+ ],
+ "istable": 1,
+ "links": [],
+ "modified": "2020-10-07 23:46:54.296322",
+ "modified_by": "Administrator",
+ "module": "Healthcare",
+ "name": "Therapy Plan Template Detail",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.py b/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.py
new file mode 100644
index 0000000..7b979fe
--- /dev/null
+++ b/erpnext/healthcare/doctype/therapy_plan_template_detail/therapy_plan_template_detail.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class TherapyPlanTemplateDetail(Document):
+ pass
diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session.js b/erpnext/healthcare/doctype/therapy_session/therapy_session.js
index e66e667..65d4cc4 100644
--- a/erpnext/healthcare/doctype/therapy_session/therapy_session.js
+++ b/erpnext/healthcare/doctype/therapy_session/therapy_session.js
@@ -92,7 +92,8 @@
'start_date': data.message.appointment_date,
'start_time': data.message.appointment_time,
'service_unit': data.message.service_unit,
- 'company': data.message.company
+ 'company': data.message.company,
+ 'duration': data.message.duration
};
frm.set_value(values);
}
@@ -107,6 +108,7 @@
'start_date': '',
'start_time': '',
'service_unit': '',
+ 'duration': ''
};
frm.set_value(values);
}
diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session.json b/erpnext/healthcare/doctype/therapy_session/therapy_session.json
index dc0cafc..1f877cc 100644
--- a/erpnext/healthcare/doctype/therapy_session/therapy_session.json
+++ b/erpnext/healthcare/doctype/therapy_session/therapy_session.json
@@ -47,7 +47,8 @@
"fieldname": "appointment",
"fieldtype": "Link",
"label": "Appointment",
- "options": "Patient Appointment"
+ "options": "Patient Appointment",
+ "set_only_once": 1
},
{
"fieldname": "patient",
@@ -90,7 +91,8 @@
"fetch_from": "therapy_template.default_duration",
"fieldname": "duration",
"fieldtype": "Int",
- "label": "Duration"
+ "label": "Duration",
+ "reqd": 1
},
{
"fieldname": "location",
@@ -220,7 +222,7 @@
],
"is_submittable": 1,
"links": [],
- "modified": "2020-06-30 10:56:10.354268",
+ "modified": "2020-10-22 23:10:21.178644",
"modified_by": "Administrator",
"module": "Healthcare",
"name": "Therapy Session",
diff --git a/erpnext/healthcare/doctype/therapy_session/therapy_session.py b/erpnext/healthcare/doctype/therapy_session/therapy_session.py
index 9650183..85d0970 100644
--- a/erpnext/healthcare/doctype/therapy_session/therapy_session.py
+++ b/erpnext/healthcare/doctype/therapy_session/therapy_session.py
@@ -4,16 +4,41 @@
from __future__ import unicode_literals
import frappe
+import datetime
from frappe.model.document import Document
+from frappe.utils import get_time, flt
from frappe.model.mapper import get_mapped_doc
from frappe import _
-from frappe.utils import cstr, getdate
+from frappe.utils import cstr, getdate, get_link_to_form
from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_receivable_account, get_income_account
class TherapySession(Document):
def validate(self):
+ self.validate_duplicate()
self.set_total_counts()
+ def validate_duplicate(self):
+ end_time = datetime.datetime.combine(getdate(self.start_date), get_time(self.start_time)) \
+ + datetime.timedelta(minutes=flt(self.duration))
+
+ overlaps = frappe.db.sql("""
+ select
+ name
+ from
+ `tabTherapy Session`
+ where
+ start_date=%s and name!=%s and docstatus!=2
+ and (practitioner=%s or patient=%s) and
+ ((start_time<%s and start_time + INTERVAL duration MINUTE>%s) or
+ (start_time>%s and start_time<%s) or
+ (start_time=%s))
+ """, (self.start_date, self.name, self.practitioner, self.patient,
+ self.start_time, end_time.time(), self.start_time, end_time.time(), self.start_time))
+
+ if overlaps:
+ overlapping_details = _('Therapy Session overlaps with {0}').format(get_link_to_form('Therapy Session', overlaps[0][0]))
+ frappe.throw(overlapping_details, title=_('Therapy Sessions Overlapping'))
+
def on_submit(self):
self.update_sessions_count_in_therapy_plan()
insert_session_medical_record(self)
diff --git a/erpnext/healthcare/doctype/therapy_type/therapy_type.py b/erpnext/healthcare/doctype/therapy_type/therapy_type.py
index ea3d84e..6c825b8 100644
--- a/erpnext/healthcare/doctype/therapy_type/therapy_type.py
+++ b/erpnext/healthcare/doctype/therapy_type/therapy_type.py
@@ -41,7 +41,7 @@
if self.rate:
item_price = frappe.get_doc('Item Price', {'item_code': self.item})
item_price.item_name = self.item_name
- item_price.price_list_name = self.rate
+ item_price.price_list_rate = self.rate
item_price.ignore_mandatory = True
item_price.save()
diff --git a/erpnext/healthcare/utils.py b/erpnext/healthcare/utils.py
index dbd3b83..96282f5 100644
--- a/erpnext/healthcare/utils.py
+++ b/erpnext/healthcare/utils.py
@@ -23,9 +23,9 @@
items_to_invoice += get_lab_tests_to_invoice(patient, company)
items_to_invoice += get_clinical_procedures_to_invoice(patient, company)
items_to_invoice += get_inpatient_services_to_invoice(patient, company)
+ items_to_invoice += get_therapy_plans_to_invoice(patient, company)
items_to_invoice += get_therapy_sessions_to_invoice(patient, company)
-
return items_to_invoice
@@ -35,6 +35,7 @@
msg += " <b><a href='#Form/Patient/{0}'>{0}</a></b>".format(patient.name)
frappe.throw(msg, title=_('Customer Not Found'))
+
def get_appointments_to_invoice(patient, company):
appointments_to_invoice = []
patient_appointments = frappe.get_list(
@@ -246,12 +247,44 @@
return services_to_invoice
+def get_therapy_plans_to_invoice(patient, company):
+ therapy_plans_to_invoice = []
+ therapy_plans = frappe.get_list(
+ 'Therapy Plan',
+ fields=['therapy_plan_template', 'name'],
+ filters={
+ 'patient': patient.name,
+ 'invoiced': 0,
+ 'company': company,
+ 'therapy_plan_template': ('!=', '')
+ }
+ )
+ for plan in therapy_plans:
+ therapy_plans_to_invoice.append({
+ 'reference_type': 'Therapy Plan',
+ 'reference_name': plan.name,
+ 'service': frappe.db.get_value('Therapy Plan Template', plan.therapy_plan_template, 'linked_item')
+ })
+
+ return therapy_plans_to_invoice
+
+
def get_therapy_sessions_to_invoice(patient, company):
therapy_sessions_to_invoice = []
+ therapy_plans = frappe.db.get_all('Therapy Plan', {'therapy_plan_template': ('!=', '')})
+ therapy_plans_created_from_template = []
+ for entry in therapy_plans:
+ therapy_plans_created_from_template.append(entry.name)
+
therapy_sessions = frappe.get_list(
'Therapy Session',
fields='*',
- filters={'patient': patient.name, 'invoiced': 0, 'company': company}
+ filters={
+ 'patient': patient.name,
+ 'invoiced': 0,
+ 'company': company,
+ 'therapy_plan': ('not in', therapy_plans_created_from_template)
+ }
)
for therapy in therapy_sessions:
if not therapy.appointment:
@@ -368,8 +401,8 @@
else:
is_invoiced = frappe.db.get_value(item.reference_dt, item.reference_dn, 'invoiced')
if is_invoiced:
- frappe.throw(_('The item referenced by {0} - {1} is already invoiced'\
- ).format(item.reference_dt, item.reference_dn))
+ frappe.throw(_('The item referenced by {0} - {1} is already invoiced').format(
+ item.reference_dt, item.reference_dn))
def manage_prescriptions(invoiced, ref_dt, ref_dn, dt, created_check_field):