diff --git a/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py b/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py index 526bb95b70e..a061c66a54d 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 @@ from __future__ import unicode_literals 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 @@ class TestTherapyPlan(unittest.TestCase): 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 @@ 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 diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.js b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.js index dea0cfeb849..490d4588d15 100644 --- a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.js +++ b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.js @@ -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) { @@ -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]); @@ -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); diff --git a/erpnext/healthcare/doctype/therapy_plan/therapy_plan.json b/erpnext/healthcare/doctype/therapy_plan/therapy_plan.json index 9edfeb2faa1..ccb316e5c34 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 e0f015f3d7b..bc0ff1a5057 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 @@ class TherapyPlan(Document): 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 @@ def make_therapy_session(therapy_plan, patient, therapy_type): 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 df647829dbc..6526acda153 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 @@ from frappe import _ 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 9eb20e2ef3b..555587ea477 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 00000000000..e69de29bb2d 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 00000000000..33ee29db7d7 --- /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 00000000000..86de1928e23 --- /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 00000000000..48fc896257b --- /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 00000000000..748c12c6896 --- /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 00000000000..c748fbfcb7c --- /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 00000000000..e69de29bb2d 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 00000000000..5553a118f87 --- /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 00000000000..7b979fe9fc8 --- /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 e66e66751aa..65d4cc48611 100644 --- a/erpnext/healthcare/doctype/therapy_session/therapy_session.js +++ b/erpnext/healthcare/doctype/therapy_session/therapy_session.js @@ -92,7 +92,8 @@ frappe.ui.form.on('Therapy Session', { '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 @@ frappe.ui.form.on('Therapy Session', { '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 dc0cafcf9c7..1f877cc2964 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 96501837120..85d09701774 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 ea3d84e7c5d..6c825b8a58e 100644 --- a/erpnext/healthcare/doctype/therapy_type/therapy_type.py +++ b/erpnext/healthcare/doctype/therapy_type/therapy_type.py @@ -41,7 +41,7 @@ class TherapyType(Document): 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 dbd3b83f09b..96282f50a92 100644 --- a/erpnext/healthcare/utils.py +++ b/erpnext/healthcare/utils.py @@ -23,9 +23,9 @@ def get_healthcare_services_to_invoice(patient, company): 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 @@ def validate_customer_created(patient): msg += " {0}".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 @@ def get_inpatient_services_to_invoice(patient, company): 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 @@ def validate_invoiced_on_submit(item): 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):