diff --git a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py index b6f5396ccb..fa4d40e297 100644 --- a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py +++ b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py @@ -164,7 +164,7 @@ def build_forest(data): error_messages = [] for i in data: - account_name, _, account_number, is_group, account_type, root_type = i + account_name, dummy, account_number, is_group, account_type, root_type = i if not account_name: error_messages.append("Row {0}: Please enter Account Name".format(line_no)) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index db6ac55a11..6f78db2ccc 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -794,7 +794,7 @@ frappe.ui.form.on('Sales Invoice', { }, refresh: function(frm) { - if (frappe.boot.active_domains.includes("Healthcare")){ + if (frappe.boot.active_domains.includes("Healthcare")) { frm.set_df_property("patient", "hidden", 0); frm.set_df_property("patient_name", "hidden", 0); frm.set_df_property("ref_practitioner", "hidden", 0); @@ -807,7 +807,7 @@ frappe.ui.form.on('Sales Invoice', { },"Get items from"); } } - else{ + else { frm.set_df_property("patient", "hidden", 1); frm.set_df_property("patient_name", "hidden", 1); frm.set_df_property("ref_practitioner", "hidden", 1); diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index 4cfeb251d6..47dfa09c61 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -162,8 +162,9 @@ def get_default_price_list(party): def set_price_list(party_details, party, party_type, given_price_list, pos=None): # price list price_list = get_permitted_documents('Price List') - - if price_list: + + # if there is only one permitted document based on user permissions, set it + if price_list and len(price_list) == 1: price_list = price_list[0] elif pos and party_type == 'Customer': customer_price_list = frappe.get_value('Customer', party.name, 'default_price_list') @@ -635,4 +636,4 @@ def get_default_contact(doctype, name): except: return None else: - return None \ No newline at end of file + return None diff --git a/erpnext/config/healthcare.py b/erpnext/config/healthcare.py index 756d22e416..2b461273ad 100644 --- a/erpnext/config/healthcare.py +++ b/erpnext/config/healthcare.py @@ -2,131 +2,68 @@ from __future__ import unicode_literals from frappe import _ def get_data(): - return [ - { - "label": _("Consultation"), - "icon": "icon-star", - "items": [ - { - "type": "doctype", - "name": "Patient Appointment", - "label": _("Patient Appointment"), - }, - { - "type": "doctype", - "name": "Patient Encounter", - "label": _("Patient Encounter"), - }, - { - "type": "doctype", - "name": "Vital Signs", - "label": _("Vital Signs"), - "description": _("Record Patient Vitals"), - }, - { - "type": "page", - "name": "patient_history", - "label": _("Patient History"), - }, - { - "type": "page", - "name": "appointment-analytic", - "label": _("Appointment Analytics"), - }, - { - "type": "doctype", - "name": "Clinical Procedure", - "label": _("Clinical Procedure"), - }, - { - "type": "doctype", - "name": "Inpatient Record", - "label": _("Inpatient Record"), - } - ] - }, - { - "label": _("Laboratory"), - "icon": "icon-list", - "items": [ - { - "type": "doctype", - "name": "Lab Test", - "label": _("Lab Test"), - }, - { - "type": "doctype", - "name": "Sample Collection", - "label": _("Sample Collection"), - }, - { - "type": "report", - "name": "Lab Test Report", - "is_query_report": True, - "label": _("Lab Test Report"), - } - ] - }, { "label": _("Masters"), - "icon": "icon-list", "items": [ { "type": "doctype", "name": "Patient", "label": _("Patient"), - "onboard": 1, + "onboard": 1 }, { "type": "doctype", "name": "Healthcare Practitioner", "label": _("Healthcare Practitioner"), - "onboard": 1, + "onboard": 1 }, { "type": "doctype", "name": "Practitioner Schedule", "label": _("Practitioner Schedule"), - }, - { - "type": "doctype", - "name": "Medical Code Standard", - "label": _("Medical Code Standard"), - }, - { - "type": "doctype", - "name": "Medical Code", - "label": _("Medical Code"), - "onboard": 1, - }, - { - "type": "doctype", - "name": "Healthcare Service Unit", - "label": _("Healthcare Service Unit") - } - ] - }, - { - "label": _("Settings"), - "icon": "icon-cog", - "items": [ - { - "type": "doctype", - "name": "Healthcare Settings", - "label": _("Healthcare Settings"), - "onboard": 1, + "onboard": 1 }, { "type": "doctype", "name": "Medical Department", "label": _("Medical Department"), }, + { + "type": "doctype", + "name": "Healthcare Service Unit Type", + "label": _("Healthcare Service Unit Type") + }, + { + "type": "doctype", + "name": "Healthcare Service Unit", + "label": _("Healthcare Service Unit") + }, + { + "type": "doctype", + "name": "Medical Code Standard", + "label": _("Medical Code Standard") + }, + { + "type": "doctype", + "name": "Medical Code", + "label": _("Medical Code") + } + ] + }, + { + "label": _("Consultation Setup"), + "items": [ { "type": "doctype", "name": "Appointment Type", "label": _("Appointment Type"), }, + { + "type": "doctype", + "name": "Clinical Procedure Template", + "label": _("Clinical Procedure Template") + }, { "type": "doctype", "name": "Prescription Dosage", @@ -137,6 +74,36 @@ def get_data(): "name": "Prescription Duration", "label": _("Prescription Duration") }, + { + "type": "doctype", + "name": "Antibiotic", + "label": _("Antibiotic") + } + ] + }, + { + "label": _("Consultation"), + "items": [ + { + "type": "doctype", + "name": "Patient Appointment", + "label": _("Patient Appointment") + }, + { + "type": "doctype", + "name": "Clinical Procedure", + "label": _("Clinical Procedure") + }, + { + "type": "doctype", + "name": "Patient Encounter", + "label": _("Patient Encounter") + }, + { + "type": "doctype", + "name": "Vital Signs", + "label": _("Vital Signs") + }, { "type": "doctype", "name": "Complaint", @@ -147,40 +114,104 @@ def get_data(): "name": "Diagnosis", "label": _("Diagnosis") }, + { + "type": "doctype", + "name": "Fee Validity", + "label": _("Fee Validity") + } + ] + }, + { + "label": _("Settings"), + "items": [ + { + "type": "doctype", + "name": "Healthcare Settings", + "label": _("Healthcare Settings"), + "onboard": 1 + } + ] + }, + { + "label": _("Laboratory Setup"), + "items": [ + { + "type": "doctype", + "name": "Lab Test Template", + "label": _("Lab Test Template") + }, { "type": "doctype", "name": "Lab Test Sample", - "label": _("Lab Test Sample"), + "label": _("Lab Test Sample") }, { "type": "doctype", "name": "Lab Test UOM", "label": _("Lab Test UOM") }, - { - "type": "doctype", - "name": "Antibiotic", - "label": _("Antibiotic") - }, { "type": "doctype", "name": "Sensitivity", "label": _("Sensitivity") + } + ] + }, + { + "label": _("Laboratory"), + "items": [ + { + "type": "doctype", + "name": "Lab Test", + "label": _("Lab Test") }, { "type": "doctype", - "name": "Lab Test Template", - "label": _("Lab Test Template") + "name": "Sample Collection", + "label": _("Sample Collection") }, { "type": "doctype", - "name": "Clinical Procedure Template", - "label": _("Clinical Procedure Template"), + "name": "Dosage Form", + "label": _("Dosage Form") + } + ] + }, + { + "label": _("Records and History"), + "items": [ + { + "type": "page", + "name": "patient_history", + "label": _("Patient History"), }, { "type": "doctype", - "name": "Healthcare Service Unit Type", - "label": _("Healthcare Service Unit Type") + "name": "Patient Medical Record", + "label": _("Patient Medical Record") + }, + { + "type": "doctype", + "name": "Inpatient Record", + "label": _("Inpatient Record") + } + ] + }, + { + "label": _("Reports"), + "items": [ + { + "type": "report", + "is_query_report": True, + "name": "Patient Appointment Analytics", + "doctype": "Patient Appointment" + }, + { + "type": "report", + "is_query_report": True, + "name": "Lab Test Report", + "doctype": "Lab Test", + "label": _("Lab Test Report") } ] } diff --git a/erpnext/healthcare/desk_page/healthcare/healthcare.json b/erpnext/healthcare/desk_page/healthcare/healthcare.json index 849f4c3919..54798ba08f 100644 --- a/erpnext/healthcare/desk_page/healthcare/healthcare.json +++ b/erpnext/healthcare/desk_page/healthcare/healthcare.json @@ -1,28 +1,49 @@ { "cards": [ { - "hidden": 0, - "label": "Settings", - "links": "[\n {\n \"label\": \"Healthcare Settings\",\n \"name\": \"Healthcare Settings\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Medical Department\",\n \"name\": \"Medical Department\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Appointment Type\",\n \"name\": \"Appointment Type\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Prescription Dosage\",\n \"name\": \"Prescription Dosage\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Prescription Duration\",\n \"name\": \"Prescription Duration\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Complaint\",\n \"name\": \"Complaint\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Diagnosis\",\n \"name\": \"Diagnosis\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Lab Test Sample\",\n \"name\": \"Lab Test Sample\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Lab Test UOM\",\n \"name\": \"Lab Test UOM\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Antibiotic\",\n \"name\": \"Antibiotic\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Sensitivity\",\n \"name\": \"Sensitivity\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Lab Test Template\",\n \"name\": \"Lab Test Template\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Clinical Procedure Template\",\n \"name\": \"Clinical Procedure Template\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Healthcare Service Unit Type\",\n \"name\": \"Healthcare Service Unit Type\",\n \"type\": \"doctype\"\n }\n]" + "icon": "", + "links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient\",\n\t\t\"label\": \"Patient\",\n\t\t\"onboard\": 1\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Healthcare Practitioner\",\n\t\t\"label\":\"Healthcare Practitioner\",\n\t\t\"onboard\": 1\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Practitioner Schedule\",\n\t\t\"label\": \"Practitioner Schedule\",\n\t\t\"onboard\": 1\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Medical Department\",\n\t\t\"label\": \"Medical Department\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Healthcare Service Unit Type\",\n\t\t\"label\": \"Healthcare Service Unit Type\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Healthcare Service Unit\",\n\t\t\"label\": \"Healthcare Service Unit\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Medical Code Standard\",\n\t\t\"label\": \"Medical Code Standard\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Medical Code\",\n\t\t\"label\": \"Medical Code\"\n\t}\n]", + "title": "Masters" }, { - "hidden": 0, - "label": "Laboratory", - "links": "[\n {\n \"label\": \"Lab Test\",\n \"name\": \"Lab Test\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Sample Collection\",\n \"name\": \"Sample Collection\",\n \"type\": \"doctype\"\n },\n {\n \"is_query_report\": true,\n \"label\": \"Lab Test Report\",\n \"name\": \"Lab Test Report\",\n \"type\": \"report\"\n }\n]" + "icon": "", + "links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Appointment Type\",\n\t\t\"label\": \"Appointment Type\"\n },\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Clinical Procedure Template\",\n\t\t\"label\": \"Clinical Procedure Template\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Prescription Dosage\",\n\t\t\"label\": \"Prescription Dosage\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Prescription Duration\",\n\t\t\"label\": \"Prescription Duration\"\n\t},\n\t{\n\t \"type\": \"doctype\",\n\t\t\"name\": \"Antibiotic\",\n\t\t\"label\": \"Antibiotic\"\n\t}\n]", + "title": "Consultation Setup" }, { - "hidden": 0, - "label": "Masters", - "links": "[\n {\n \"label\": \"Patient\",\n \"name\": \"Patient\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Healthcare Practitioner\",\n \"name\": \"Healthcare Practitioner\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Practitioner Schedule\",\n \"name\": \"Practitioner Schedule\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Medical Code Standard\",\n \"name\": \"Medical Code Standard\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Medical Code\",\n \"name\": \"Medical Code\",\n \"onboard\": 1,\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Healthcare Service Unit\",\n \"name\": \"Healthcare Service Unit\",\n \"type\": \"doctype\"\n }\n]" + "icon": "icon-star", + "links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Appointment\",\n\t\t\"label\": \"Patient Appointment\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Clinical Procedure\",\n\t\t\"label\": \"Clinical Procedure\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Encounter\",\n\t\t\"label\": \"Patient Encounter\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Vital Signs\",\n\t\t\"label\": \"Vital Signs\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Complaint\",\n\t\t\"label\": \"Complaint\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Diagnosis\",\n\t\t\"label\": \"Diagnosis\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Fee Validity\",\n\t\t\"label\": \"Fee Validity\"\n\t}\n]", + "title": "Consultation" }, { - "hidden": 0, - "label": "Consultation", - "links": "[\n {\n \"label\": \"Patient Appointment\",\n \"name\": \"Patient Appointment\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Patient Encounter\",\n \"name\": \"Patient Encounter\",\n \"type\": \"doctype\"\n },\n {\n \"description\": \"Record Patient Vitals\",\n \"label\": \"Vital Signs\",\n \"name\": \"Vital Signs\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Patient History\",\n \"name\": \"patient_history\",\n \"type\": \"page\"\n },\n {\n \"label\": \"Appointment Analytics\",\n \"name\": \"appointment-analytic\",\n \"type\": \"page\"\n },\n {\n \"label\": \"Clinical Procedure\",\n \"name\": \"Clinical Procedure\",\n \"type\": \"doctype\"\n },\n {\n \"label\": \"Inpatient Record\",\n \"name\": \"Inpatient Record\",\n \"type\": \"doctype\"\n }\n]" + "links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Healthcare Settings\",\n\t\t\"label\": \"Healthcare Settings\",\n\t\t\"onboard\": 1\n\t}\n]", + "title": "Settings" + }, + { + "links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Lab Test Template\",\n\t\t\"label\": \"Lab Test Template\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Lab Test Sample\",\n\t\t\"label\": \"Lab Test Sample\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Lab Test UOM\",\n\t\t\"label\": \"Lab Test UOM\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Sensitivity\",\n\t\t\"label\": \"Sensitivity\"\n\t}\n]", + "title": "Laboratory Setup" + }, + { + "links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Lab Test\",\n\t\t\"label\": \"Lab Test\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Sample Collection\",\n\t\t\"label\": \"Sample Collection\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Dosage Form\",\n\t\t\"label\": \"Dosage Form\"\n\t}\n]", + "title": "Laboratory" + }, + { + "links": "[\n\t{\n\t\t\"type\": \"page\",\n\t\t\"name\": \"patient_history\",\n\t\t\"label\": \"Patient History\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Medical Record\",\n\t\t\"label\": \"Patient Medical Record\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Inpatient Record\",\n\t\t\"label\": \"Inpatient Record\"\n\t}\n]", + "title": "Records and History" + }, + { + "links": "[\n\t{\n\t\t\"type\": \"report\",\n\t\t\"is_query_report\": true,\n\t\t\"name\": \"Patient Appointment Analytics\",\n\t\t\"doctype\": \"Patient Appointment\"\n\t},\n\t{\n\t\t\"type\": \"report\",\n\t\t\"is_query_report\": true,\n\t\t\"name\": \"Lab Test Report\",\n\t\t\"doctype\": \"Lab Test\",\n\t\t\"label\": \"Lab Test Report\"\n\t}\n]", + "title": "Reports" } ], "category": "Domains", - "charts": [], + "charts": [ + { + "chart_name": "Patient Appointments", + "label": "Patient Appointments" + } + ], + "charts_label": "", "creation": "2020-03-02 17:23:17.919682", "developer_mode_only": 0, "disable_user_customization": 0, @@ -32,7 +53,7 @@ "idx": 0, "is_standard": 1, "label": "Healthcare", - "modified": "2020-04-01 11:28:50.996366", + "modified": "2020-03-26 16:10:44.629795", "modified_by": "Administrator", "module": "Healthcare", "name": "Healthcare", @@ -40,5 +61,37 @@ "pin_to_bottom": 0, "pin_to_top": 0, "restrict_to_domain": "Healthcare", - "shortcuts": [] + "shortcuts": [ + { + "format": "{} Open", + "is_query_report": 0, + "link_to": "Patient Appointment", + "stats_filter": "{\n \"status\": \"Open\"\n}", + "type": "DocType" + }, + { + "format": "{} Active", + "is_query_report": 0, + "link_to": "Patient", + "stats_filter": "{\n \"status\": \"Active\"\n}", + "type": "DocType" + }, + { + "format": "{} Vacant", + "is_query_report": 0, + "link_to": "Healthcare Service Unit", + "stats_filter": "{\n \"occupancy_status\": \"Vacant\",\n \"is_group\": 0\n}", + "type": "DocType" + }, + { + "is_query_report": 0, + "link_to": "Healthcare Practitioner", + "type": "DocType" + }, + { + "is_query_report": 0, + "link_to": "patient_history", + "type": "Page" + } + ] } \ No newline at end of file diff --git a/erpnext/healthcare/doctype/appointment_type/appointment_type.json b/erpnext/healthcare/doctype/appointment_type/appointment_type.json index ceabce2de1..58753bb4f0 100644 --- a/erpnext/healthcare/doctype/appointment_type/appointment_type.json +++ b/erpnext/healthcare/doctype/appointment_type/appointment_type.json @@ -1,213 +1,94 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:appointment_type", - "beta": 1, - "creation": "2016-07-22 11:52:34.953019", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 0, + "actions": [], + "allow_import": 1, + "allow_rename": 1, + "autoname": "field:appointment_type", + "beta": 1, + "creation": "2016-07-22 11:52:34.953019", + "doctype": "DocType", + "document_type": "Setup", + "engine": "InnoDB", + "field_order": [ + "appointment_type", + "ip", + "default_duration", + "color" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 1, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "appointment_type", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Type", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 1, + "allow_in_quick_entry": 1, + "fieldname": "appointment_type", + "fieldtype": "Data", + "ignore_xss_filter": 1, + "in_list_view": 1, + "label": "Type", + "reqd": 1, + "translatable": 1, "unique": 1 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "fieldname": "ip", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Is Inpatient", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "bold": 1, + "default": "0", + "fieldname": "ip", + "fieldtype": "Check", + "label": "Is Inpatient", + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 1, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "description": "In Minutes", - "fieldname": "default_duration", - "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 1, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Default Duration", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "allow_in_quick_entry": 1, + "bold": 1, + "fieldname": "default_duration", + "fieldtype": "Int", + "in_filter": 1, + "in_list_view": 1, + "label": "Default Duration (In Minutes)" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 1, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "color", - "fieldtype": "Color", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Color", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "allow_in_quick_entry": 1, + "fieldname": "color", + "fieldtype": "Color", + "in_list_view": 1, + "label": "Color", + "no_copy": 1, + "report_hide": 1 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-08-08 12:57:54.544216", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Appointment Type", - "name_case": "", - "owner": "Administrator", + ], + "links": [], + "modified": "2020-02-03 21:06:05.833050", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Appointment Type", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Healthcare Administrator", + "share": 1, "write": 1 - }, + }, { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Physician", + "share": 1, "write": 1 } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "search_fields": "appointment_type", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + ], + "quick_entry": 1, + "restrict_to_domain": "Healthcare", + "search_fields": "appointment_type", + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/healthcare/doctype/appointment_type/appointment_type_dashboard.py b/erpnext/healthcare/doctype/appointment_type/appointment_type_dashboard.py new file mode 100644 index 0000000000..845e4466c1 --- /dev/null +++ b/erpnext/healthcare/doctype/appointment_type/appointment_type_dashboard.py @@ -0,0 +1,13 @@ +from __future__ import unicode_literals +from frappe import _ + +def get_data(): + return { + 'fieldname': 'appointment_type', + 'transactions': [ + { + 'label': _('Patient Appointments'), + 'items': ['Patient Appointment'] + }, + ] + } diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js index fa9188449e..5f36bdd95c 100644 --- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js +++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js @@ -4,244 +4,285 @@ frappe.ui.form.on('Clinical Procedure', { setup: function(frm) { frm.set_query('batch_no', 'items', function(doc, cdt, cdn) { - var item = locals[cdt][cdn]; - if(!item.item_code) { - frappe.throw(__("Please enter Item Code to get Batch Number")); + let item = locals[cdt][cdn]; + if (!item.item_code) { + frappe.throw(__('Please enter Item Code to get Batch Number')); } else { + let filters = {'item_code': item.item_code}; + if (frm.doc.status == 'In Progress') { - var filters = { - 'item_code': item.item_code, - 'posting_date': frm.doc.start_date || frappe.datetime.nowdate() - }; - if(frm.doc.warehouse) filters["warehouse"] = frm.doc.warehouse; - } else { - filters = { - 'item_code': item.item_code - }; + filters['posting_date'] = frm.doc.start_date || frappe.datetime.nowdate(); + if (frm.doc.warehouse) filters['warehouse'] = frm.doc.warehouse; } + return { - query : "erpnext.controllers.queries.get_batch_no", + query : 'erpnext.controllers.queries.get_batch_no', filters: filters }; } }); }, + refresh: function(frm) { - frm.set_query("patient", function () { + frm.set_query('patient', function () { return { - filters: {"disabled": 0} + filters: {'status': ['!=', 'Disabled']} }; }); - frm.set_query("appointment", function () { + + frm.set_query('appointment', function () { return { filters: { - "procedure_template": ["not in", null], - "status": ['in', 'Open, Scheduled'] + 'procedure_template': ['not in', null], + 'status': ['in', 'Open, Scheduled'] } }; }); - frm.set_query("service_unit", function(){ + + frm.set_query('service_unit', function() { return { filters: { - "is_group": false, - "allow_appointments": true + 'is_group': false, + 'allow_appointments': true } }; }); - frm.set_query("practitioner", function() { + + frm.set_query('practitioner', function() { return { filters: { 'department': frm.doc.medical_department } }; }); - if(frm.doc.consume_stock){ + + if (frm.doc.consume_stock) { frm.set_indicator_formatter('item_code', - function(doc) { return (doc.qty<=doc.actual_qty) ? "green" : "orange" ; }); + function(doc) { return (doc.qty<=doc.actual_qty) ? 'green' : 'orange' ; }); } - if (!frm.doc.__islocal && frm.doc.status == 'In Progress'){ + if (frm.doc.docstatus == 1) { + if (frm.doc.status == 'In Progress') { + let btn_label = ''; + let msg = ''; + if (frm.doc.consume_stock) { + btn_label = __('Complete and Consume'); + msg = __('Complete {0} and Consume Stock?', [frm.doc.name]); + } else { + btn_label = 'Complete'; + msg = __('Complete {0}?', [frm.doc.name]); + } - if(frm.doc.consume_stock){ - var btn_label = 'Complete and Consume'; - var msg = 'Complete '+frm.doc.name+' and Consume Stock?'; - }else{ - btn_label = 'Complete'; - msg = 'Complete '+frm.doc.name+'?'; - } + frm.add_custom_button(__(btn_label), function () { + frappe.confirm( + msg, + function() { + frappe.call({ + method: 'complete_procedure', + doc: frm.doc, + callback: function(r) { + if (r.message) { + frappe.show_alert({ + message: __('Stock Entry {0} created', + ['' + r.message + '']), + indicator: 'green' + }); + frm.reload_doc(); + } + } + }); + } + ); + }).addClass("btn-primary"); - frm.add_custom_button(__(btn_label), function () { - frappe.confirm( - __(msg), - function(){ - frappe.call({ - doc: frm.doc, - method: "complete", - callback: function(r) { - if(!r.exc){ + } else if (frm.doc.status == 'Pending') { + frm.add_custom_button(__('Start'), function() { + frappe.call({ + doc: frm.doc, + method: 'start_procedure', + callback: function(r) { + if (!r.exc) { + if (r.message == 'insufficient stock') { + let msg = __('Stock quantity to start the Procedure is not available in the Warehouse {0}. Do you want to record a Stock Entry?', + [frm.doc.warehouse.bold()]); + frappe.confirm( + msg, + function() { + frappe.call({ + doc: frm.doc, + method: 'make_material_receipt', + callback: function(r) { + if (!r.exc) { + cur_frm.reload_doc(); + let doclist = frappe.model.sync(r.message); + frappe.set_route('Form', doclist[0].doctype, doclist[0].name); + } + } + }); + } + ); + } else { cur_frm.reload_doc(); } } - }); - } - ); - }); - }else if (frm.doc.status == 'Draft') { - frm.add_custom_button(__("Start"), function () { - frappe.call({ - doc: frm.doc, - method: "start", - callback: function(r) { - if(!r.exc){ - if(frm.doc.status == 'Draft'){ - frappe.confirm( - __("Stock quantity to start procedure is not available in the warehouse. Do you want to record a Stock Transfer"), - function(){ - frappe.call({ - doc: frm.doc, - method: "make_material_transfer", - callback: function(r) { - if(!r.exc){ - cur_frm.reload_doc(); - var doclist = frappe.model.sync(r.message); - frappe.set_route("Form", doclist[0].doctype, doclist[0].name); - } - } - }); - } - ); - }else{ - cur_frm.reload_doc(); - } } - } - }); - }); - } - if (frm.doc.__islocal){ - frm.set_df_property("consumables", "hidden", 1); - }else{ - frm.set_df_property("consumables", "hidden", 0); + }); + }).addClass("btn-primary"); + } } }, - onload: function(frm){ - if(frm.doc.status == 'Completed'){ - frm.set_df_property("items", "read_only", 1); - } - if(frm.is_new()) { - frm.add_fetch("procedure_template", "medical_department", "medical_department"); - frm.set_value("start_time", null); + + onload: function(frm) { + if (frm.is_new()) { + frm.add_fetch('procedure_template', 'medical_department', 'medical_department'); + frm.set_value('start_time', null); } }, + patient: function(frm) { - if(frm.doc.patient){ + if (frm.doc.patient) { frappe.call({ - "method": "erpnext.healthcare.doctype.patient.patient.get_patient_detail", + 'method': 'erpnext.healthcare.doctype.patient.patient.get_patient_detail', args: { patient: frm.doc.patient }, callback: function (data) { - let age = ""; - if(data.message.dob){ + let age = ''; + if (data.message.dob) { age = calculate_age(data.message.dob); - }else if (data.message.age){ + } else if (data.message.age) { age = data.message.age; - if(data.message.age_as_on){ - age = age+" as on "+data.message.age_as_on; + if (data.message.age_as_on) { + age = __('{0} as on {1}', [age, data.message.age_as_on]); } } - frm.set_value("patient_age", age); - frm.set_value("patient_sex", data.message.sex); + frm.set_value('patient_age', age); + frm.set_value('patient_sex', data.message.sex); } }); - }else{ - frm.set_value("patient_age", ""); - frm.set_value("patient_sex", ""); + } else { + frm.set_value('patient_age', ''); + frm.set_value('patient_sex', ''); } }, + appointment: function(frm) { - if(frm.doc.appointment){ + if (frm.doc.appointment) { frappe.call({ - "method": "frappe.client.get", + 'method': 'frappe.client.get', args: { - doctype: "Patient Appointment", + doctype: 'Patient Appointment', name: frm.doc.appointment }, - callback: function (data) { - frm.set_value("patient", data.message.patient); - frm.set_value("procedure_template", data.message.procedure_template); - frm.set_value("medical_department", data.message.department); - frm.set_value("start_date", data.message.appointment_date); - frm.set_value("start_time", data.message.appointment_time); - frm.set_value("notes", data.message.notes); - frm.set_value("service_unit", data.message.service_unit); + callback: function(data) { + frm.set_value('patient', data.message.patient); + frm.set_value('procedure_template', data.message.procedure_template); + frm.set_value('medical_department', data.message.department); + frm.set_value('start_date', data.message.appointment_date); + frm.set_value('start_time', data.message.appointment_time); + frm.set_value('notes', data.message.notes); + frm.set_value('service_unit', data.message.service_unit); } }); } }, + procedure_template: function(frm) { - if(frm.doc.procedure_template){ + if (frm.doc.procedure_template) { frappe.call({ - "method": "frappe.client.get", + 'method': 'frappe.client.get', args: { - doctype: "Clinical Procedure Template", + doctype: 'Clinical Procedure Template', name: frm.doc.procedure_template }, callback: function (data) { - frm.set_value("medical_department", data.message.medical_department); - frm.set_value("consume_stock", data.message.consume_stock); - if(!frm.doc.warehouse){ - frappe.call({ - method: "frappe.client.get_value", - args: { - doctype: "Stock Settings", - fieldname: "default_warehouse" - }, - callback: function (data) { - frm.set_value("warehouse", data.message.default_warehouse); - } - }); - } + frm.set_value('medical_department', data.message.medical_department); + frm.set_value('consume_stock', data.message.consume_stock); + frm.events.set_warehouse(frm); + frm.events.set_procedure_consumables(frm); } }); - }else{ - frm.set_value("consume_stock", 0); } }, + service_unit: function(frm) { - if(frm.doc.service_unit){ + if (frm.doc.service_unit) { frappe.call({ - method: "frappe.client.get_value", + method: 'frappe.client.get_value', args:{ - fieldname: "warehouse", - doctype: "Healthcare Service Unit", + fieldname: 'warehouse', + doctype: 'Healthcare Service Unit', filters:{name: frm.doc.service_unit}, }, callback: function(data) { - if(data.message){ - frm.set_value("warehouse", data.message.warehouse); + if (data.message) { + frm.set_value('warehouse', data.message.warehouse); } } }); } }, + practitioner: function(frm) { - if(frm.doc.practitioner){ + if (frm.doc.practitioner) { frappe.call({ - "method": "frappe.client.get", + 'method': 'frappe.client.get', args: { - doctype: "Healthcare Practitioner", + doctype: 'Healthcare Practitioner', name: frm.doc.practitioner }, callback: function (data) { - frappe.model.set_value(frm.doctype,frm.docname, "medical_department",data.message.department); + frappe.model.set_value(frm.doctype,frm.docname, 'medical_department',data.message.department); } }); } + }, + + set_warehouse: function(frm) { + if (!frm.doc.warehouse) { + frappe.call({ + method: 'frappe.client.get_value', + args: { + doctype: 'Stock Settings', + fieldname: 'default_warehouse' + }, + callback: function (data) { + frm.set_value('warehouse', data.message.default_warehouse); + } + }); + } + }, + + set_procedure_consumables: function(frm) { + frappe.call({ + method: 'erpnext.healthcare.doctype.clinical_procedure.clinical_procedure.get_procedure_consumables', + args: { + procedure_template: frm.doc.procedure_template + }, + callback: function(data) { + if (data.message) { + frm.doc.items = []; + $.each(data.message, function(i, v) { + let item = frm.add_child('items'); + item.item_code = v.item_code; + item.item_name = v.item_name; + item.uom = v.uom; + item.stock_uom = v.stock_uom; + item.qty = flt(v.qty); + item.transfer_qty = v.transfer_qty; + item.conversion_factor = v.conversion_factor; + item.invoice_separately_as_consumables = v.invoice_separately_as_consumables; + item.batch_no = v.batch_no; + }); + refresh_field('items'); + } + } + }); } + }); -cur_frm.set_query("procedure_template", function(doc) { +cur_frm.set_query('procedure_template', function(doc) { return { filters: { 'medical_department': doc.medical_department @@ -249,57 +290,51 @@ cur_frm.set_query("procedure_template", function(doc) { }; }); -cur_frm.set_query("appointment", function() { - return { - filters: { - status:['in',["Open"]] - } - }; -}); - frappe.ui.form.on('Clinical Procedure Item', { - qty: function(frm, cdt, cdn){ - var d = locals[cdt][cdn]; - frappe.model.set_value(cdt, cdn, "transfer_qty", d.qty*d.conversion_factor); + qty: function(frm, cdt, cdn) { + let d = locals[cdt][cdn]; + frappe.model.set_value(cdt, cdn, 'transfer_qty', d.qty*d.conversion_factor); }, - uom: function(doc, cdt, cdn){ - var d = locals[cdt][cdn]; - if(d.uom && d.item_code){ + + uom: function(doc, cdt, cdn) { + let d = locals[cdt][cdn]; + if (d.uom && d.item_code) { return frappe.call({ - method: "erpnext.stock.doctype.stock_entry.stock_entry.get_uom_details", + method: 'erpnext.stock.doctype.stock_entry.stock_entry.get_uom_details', args: { item_code: d.item_code, uom: d.uom, qty: d.qty }, callback: function(r) { - if(r.message) { + if (r.message) { frappe.model.set_value(cdt, cdn, r.message); } } }); } }, + item_code: function(frm, cdt, cdn) { - var d = locals[cdt][cdn]; + let d = locals[cdt][cdn]; let args = null; - if(d.item_code) { + if (d.item_code) { args = { - 'doctype' : "Clinical Procedure", + 'doctype' : 'Clinical Procedure', 'item_code' : d.item_code, 'company' : frm.doc.company, 'warehouse': frm.doc.warehouse }; return frappe.call({ - method: "erpnext.stock.get_item_details.get_item_details", + method: 'erpnext.healthcare.doctype.clinical_procedure_template.clinical_procedure_template.get_item_details', args: {args: args}, callback: function(r) { - if(r.message) { - frappe.model.set_value(cdt, cdn, "item_name", r.message.item_name); - frappe.model.set_value(cdt, cdn, "stock_uom", r.message.stock_uom); - frappe.model.set_value(cdt, cdn, "conversion_factor", r.message.conversion_factor); - frappe.model.set_value(cdt, cdn, "actual_qty", r.message.actual_qty); - refresh_field("items"); + if (r.message) { + let d = locals[cdt][cdn]; + $.each(r.message, function(k, v) { + d[k] = v; + }); + refresh_field('items'); } } }); @@ -307,16 +342,16 @@ frappe.ui.form.on('Clinical Procedure Item', { } }); -var calculate_age = function(birth) { - var ageMS = Date.parse(Date()) - Date.parse(birth); - var age = new Date(); +let calculate_age = function(birth) { + let ageMS = Date.parse(Date()) - Date.parse(birth); + let age = new Date(); age.setTime(ageMS); - var years = age.getFullYear() - 1970; - return years + " Year(s) " + age.getMonth() + " Month(s) " + age.getDate() + " Day(s)"; + let years = age.getFullYear() - 1970; + return years + ' Year(s) ' + age.getMonth() + ' Month(s) ' + age.getDate() + ' Day(s)'; }; // List Stock items -cur_frm.set_query("item_code", "items", function() { +cur_frm.set_query('item_code', 'items', function() { return { filters: { is_stock_item:1 diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json index 3097ba3b9a..3c936bbf27 100644 --- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json +++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json @@ -1,955 +1,267 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "autoname": "naming_series:", - "beta": 1, - "creation": "2017-04-07 12:52:43.542429", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "autoname": "naming_series:", + "beta": 1, + "creation": "2017-04-07 12:52:43.542429", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "inpatient_record", + "naming_series", + "procedure_template", + "appointment", + "patient", + "patient_sex", + "patient_age", + "prescription", + "medical_department", + "practitioner", + "column_break_7", + "status", + "service_unit", + "warehouse", + "start_date", + "start_time", + "sample", + "invoiced", + "notes", + "company", + "consumables_section", + "consume_stock", + "items", + "section_break_24", + "invoice_separately_as_consumables", + "consumption_invoiced", + "consumable_total_amount", + "column_break_27", + "consumption_details", + "amended_from" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "patient.inpatient_record", - "fieldname": "inpatient_record", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Inpatient Record", - "length": 0, - "no_copy": 0, - "options": "Inpatient Record", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "patient.inpatient_record", + "fieldname": "inpatient_record", + "fieldtype": "Link", + "label": "Inpatient Record", + "options": "Inpatient Record", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fieldname": "naming_series", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Series", - "length": 0, - "no_copy": 0, - "options": "HLC-CPR-.YYYY.-", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "naming_series", + "fieldtype": "Select", + "label": "Series", + "options": "HLC-CPR-.YYYY.-" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "appointment", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Appointment", - "length": 0, - "no_copy": 0, - "options": "Patient Appointment", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 - }, + "fieldname": "appointment", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Appointment", + "options": "Patient Appointment" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "inpatient_record.patient", - "fieldname": "patient", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Patient", - "length": 0, - "no_copy": 0, - "options": "Patient", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "inpatient_record.patient", + "fieldname": "patient", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Patient", + "options": "Patient", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "patient_age", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Age", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 - }, + "fieldname": "patient_age", + "fieldtype": "Data", + "label": "Age", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "patient_sex", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Gender", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 - }, + "fieldname": "patient_sex", + "fieldtype": "Link", + "label": "Gender", + "options": "Gender", + "read_only": 1, + "set_only_once": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "prescription", - "fieldtype": "Link", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Procedure Prescription", - "length": 0, - "no_copy": 0, - "options": "Procedure Prescription", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "prescription", + "fieldtype": "Link", + "hidden": 1, + "label": "Procedure Prescription", + "options": "Procedure Prescription" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "medical_department", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Medical Department", - "length": 0, - "no_copy": 0, - "options": "Medical Department", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 - }, + "fieldname": "medical_department", + "fieldtype": "Link", + "label": "Medical Department", + "options": "Medical Department" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "practitioner", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Healthcare Practitioner", - "length": 0, - "no_copy": 0, - "options": "Healthcare Practitioner", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 - }, + "fieldname": "practitioner", + "fieldtype": "Link", + "label": "Healthcare Practitioner", + "options": "Healthcare Practitioner" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_7", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_7", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "procedure_template", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Procedure Template", - "length": 0, - "no_copy": 0, - "options": "Clinical Procedure Template", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 - }, + "fieldname": "procedure_template", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Procedure Template", + "options": "Clinical Procedure Template", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "service_unit", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Service Unit", - "length": 0, - "no_copy": 0, - "options": "Healthcare Service Unit", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 - }, + "fieldname": "service_unit", + "fieldtype": "Link", + "label": "Service Unit", + "options": "Healthcare Service Unit", + "set_only_once": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "warehouse", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Warehouse", - "length": 0, - "no_copy": 0, - "options": "Warehouse", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 - }, + "fieldname": "warehouse", + "fieldtype": "Link", + "label": "Warehouse", + "mandatory_depends_on": "eval: doc.consume_stock == 1", + "options": "Warehouse" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Today", - "fieldname": "start_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Start Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 - }, + "default": "Today", + "fieldname": "start_date", + "fieldtype": "Date", + "label": "Start Date" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "start_time", - "fieldtype": "Time", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Time", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "start_time", + "fieldtype": "Time", + "label": "Start Time" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sample", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Sample", - "length": 0, - "no_copy": 0, - "options": "Sample Collection", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sample", + "fieldtype": "Link", + "label": "Sample", + "options": "Sample Collection" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fieldname": "invoiced", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Invoiced", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "invoiced", + "fieldtype": "Check", + "label": "Invoiced", + "no_copy": 1, + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "notes", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Notes", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 - }, + "fieldname": "notes", + "fieldtype": "Small Text", + "label": "Notes", + "set_only_once": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "company", - "fieldtype": "Link", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Company", - "length": 0, - "no_copy": 0, - "options": "Company", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "company", + "fieldtype": "Link", + "label": "Company", + "options": "Company" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fieldname": "consume_stock", - "fieldtype": "Check", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Consume Stock", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "consume_stock", + "fieldtype": "Check", + "label": "Consume Stock" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.consume_stock == 1", - "fieldname": "consumables", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Consumables", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "items", + "fieldtype": "Table", + "label": "Consumables", + "options": "Clinical Procedure Item" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "items", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Consumables", - "length": 0, - "no_copy": 0, - "options": "Clinical Procedure Item", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "invoice_separately_as_consumables", + "fieldtype": "Check", + "hidden": 1, + "label": "Invoice Consumables Separately", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fieldname": "invoice_separately_as_consumables", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Consumables Invoice Separately", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "depends_on": "invoice_separately_as_consumables", + "fieldname": "consumable_total_amount", + "fieldtype": "Currency", + "label": "Consumable Total Amount", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "invoice_separately_as_consumables", - "fieldname": "consumable_total_amount", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Consumable Total Amount", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "depends_on": "invoice_separately_as_consumables", + "fieldname": "consumption_details", + "fieldtype": "Small Text", + "label": "Consumption Details" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "invoice_separately_as_consumables", - "fieldname": "consumption_details", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Consumption Details", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "depends_on": "invoice_separately_as_consumables", + "fieldname": "consumption_invoiced", + "fieldtype": "Check", + "hidden": 1, + "label": "Consumption Invoiced", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "depends_on": "invoice_separately_as_consumables", - "fieldname": "consumption_invoiced", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Consumption Invoiced", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "status", + "fieldtype": "Select", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Status", + "options": "Draft\nSubmitted\nCancelled\nIn Progress\nCompleted\nPending", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fieldname": "status", - "fieldtype": "Select", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Status", - "length": 0, - "no_copy": 0, - "options": "Draft\nIn Progress\nCompleted\nPending\nCancelled", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldname": "amended_from", + "fieldtype": "Link", + "label": "Amended From", + "no_copy": 1, + "options": "Clinical Procedure", + "print_hide": 1, + "read_only": 1 + }, + { + "fieldname": "consumables_section", + "fieldtype": "Section Break", + "label": "Consumables" + }, + { + "fieldname": "column_break_27", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_24", + "fieldtype": "Section Break" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-08-21 14:44:49.438611", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Clinical Procedure", - "name_case": "", - "owner": "Administrator", + ], + "is_submittable": 1, + "links": [], + "modified": "2020-03-02 11:44:27.970651", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Clinical Procedure", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Nursing User", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Nursing User", + "share": 1, "write": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 -} + ], + "restrict_to_domain": "Healthcare", + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 +} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py index 7c6f4d5999..db3afc8807 100644 --- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py +++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py @@ -6,88 +6,101 @@ from __future__ import unicode_literals import frappe from frappe import _ from frappe.model.document import Document -from frappe.utils import cint, flt, nowdate, nowtime, cstr +from frappe.utils import flt, nowdate, nowtime, cstr from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_account from erpnext.healthcare.doctype.lab_test.lab_test import create_sample_doc from erpnext.stock.stock_ledger import get_previous_sle from erpnext.stock.get_item_details import get_item_details +from frappe.model.mapper import get_mapped_doc class ClinicalProcedure(Document): def validate(self): - if self.consume_stock and not self.status == 'Draft': - if not self.warehouse: - frappe.throw(_("Set warehouse for Procedure {0} ").format(self.name)) + self.set_status() + if self.consume_stock: self.set_actual_qty() if self.items: self.invoice_separately_as_consumables = False for item in self.items: - if item.invoice_separately_as_consumables == 1: + if item.invoice_separately_as_consumables: self.invoice_separately_as_consumables = True def before_insert(self): if self.consume_stock: - set_stock_items(self, self.procedure_template, "Clinical Procedure Template") - self.set_actual_qty(); + self.set_actual_qty() def after_insert(self): if self.prescription: - frappe.db.set_value("Procedure Prescription", self.prescription, "procedure_created", 1) + frappe.db.set_value('Procedure Prescription', self.prescription, 'procedure_created', 1) if self.appointment: - frappe.db.set_value("Patient Appointment", self.appointment, "status", "Closed") - template = frappe.get_doc("Clinical Procedure Template", self.procedure_template) + frappe.db.set_value('Patient Appointment', self.appointment, 'status', 'Closed') + template = frappe.get_doc('Clinical Procedure Template', self.procedure_template) if template.sample: - patient = frappe.get_doc("Patient", self.patient) + patient = frappe.get_doc('Patient', self.patient) sample_collection = create_sample_doc(template, patient, None) - frappe.db.set_value("Clinical Procedure", self.name, "sample", sample_collection.name) + frappe.db.set_value('Clinical Procedure', self.name, 'sample', sample_collection.name) self.reload() - def complete(self): + def set_status(self): + if self.docstatus == 0: + self.status = 'Draft' + elif self.docstatus == 1: + if self.status not in ['In Progress', 'Completed']: + self.status = 'Pending' + elif self.docstatus == 2: + self.status = 'Cancelled' + + def complete_procedure(self): if self.consume_stock and self.items: - create_stock_entry(self) - frappe.db.set_value("Clinical Procedure", self.name, "status", 'Completed') + stock_entry = make_stock_entry(self) if self.items: consumable_total_amount = 0 consumption_details = False - for item in self.items: - if item.invoice_separately_as_consumables: - price_list, price_list_currency = frappe.db.get_values("Price List", {"selling": 1}, ['name', 'currency'])[0] - args = { - 'doctype': "Sales Invoice", - 'item_code': item.item_code, - 'company': self.company, - 'warehouse': self.warehouse, - 'customer': frappe.db.get_value("Patient", self.patient, "customer"), - 'selling_price_list': price_list, - 'price_list_currency': price_list_currency, - 'plc_conversion_rate': 1.0, - 'conversion_rate': 1.0 - } - item_details = get_item_details(args) - item_price = item_details.price_list_rate * item.transfer_qty - item_consumption_details = item_details.item_name+"\t"+str(item.qty)+" "+item.uom+"\t"+str(item_price) - consumable_total_amount += item_price - if not consumption_details: - consumption_details = "Clinical Procedure ("+self.name+"):\n\t"+item_consumption_details - else: - consumption_details += "\n\t"+item_consumption_details - if consumable_total_amount > 0: - frappe.db.set_value("Clinical Procedure", self.name, "consumable_total_amount", consumable_total_amount) - frappe.db.set_value("Clinical Procedure", self.name, "consumption_details", consumption_details) + customer = frappe.db.get_value('Patient', self.patient, 'customer') + if customer: + for item in self.items: + if item.invoice_separately_as_consumables: + price_list, price_list_currency = frappe.db.get_values('Price List', {'selling': 1}, ['name', 'currency'])[0] + args = { + 'doctype': 'Sales Invoice', + 'item_code': item.item_code, + 'company': self.company, + 'warehouse': self.warehouse, + 'customer': customer, + 'selling_price_list': price_list, + 'price_list_currency': price_list_currency, + 'plc_conversion_rate': 1.0, + 'conversion_rate': 1.0 + } + item_details = get_item_details(args) + item_price = item_details.price_list_rate * item.qty + item_consumption_details = item_details.item_name + ' ' + str(item.qty) + ' ' + item.uom + ' ' + str(item_price) + consumable_total_amount += item_price + if not consumption_details: + consumption_details = _('Clinical Procedure ({0}):').format(self.name) + consumption_details += '\n\t' + item_consumption_details + if consumable_total_amount > 0: + frappe.db.set_value('Clinical Procedure', self.name, 'consumable_total_amount', consumable_total_amount) + frappe.db.set_value('Clinical Procedure', self.name, 'consumption_details', consumption_details) + else: + frappe.throw(_('Please set Customer in Patient {0}').format(frappe.bold(self.patient)), title=_('Customer Not Found')) - def start(self): + frappe.db.set_value('Clinical Procedure', self.name, 'status', 'Completed') + if self.consume_stock and self.items: + return stock_entry + + def start_procedure(self): allow_start = self.set_actual_qty() if allow_start: - self.status = 'In Progress' + self.db_set('status', 'In Progress') insert_clinical_procedure_to_medical_record(self) - else: - self.status = 'Draft' - self.save() + return 'success' + return 'insufficient stock' def set_actual_qty(self): - allow_negative_stock = cint(frappe.db.get_value("Stock Settings", None, "allow_negative_stock")) + allow_negative_stock = frappe.db.get_single_value('Stock Settings', 'allow_negative_stock') allow_start = True for d in self.get('items'): @@ -95,15 +108,16 @@ class ClinicalProcedure(Document): # validate qty if not allow_negative_stock and d.actual_qty < d.qty: allow_start = False + break return allow_start - def make_material_transfer(self): - stock_entry = frappe.new_doc("Stock Entry") + def make_material_receipt(self, submit=False): + stock_entry = frappe.new_doc('Stock Entry') - stock_entry.purpose = "Material Transfer" + stock_entry.stock_entry_type = 'Material Receipt' stock_entry.to_warehouse = self.warehouse - expense_account = get_account(None, "expense_account", "Healthcare Settings", self.company) + expense_account = get_account(None, 'expense_account', 'Healthcare Settings', self.company) for item in self.items: if item.qty > item.actual_qty: se_child = stock_entry.append('items') @@ -111,7 +125,7 @@ class ClinicalProcedure(Document): se_child.item_name = item.item_name se_child.uom = item.uom se_child.stock_uom = item.stock_uom - se_child.qty = flt(item.qty-item.actual_qty) + se_child.qty = flt(item.qty - item.actual_qty) se_child.t_warehouse = self.warehouse # in stock uom se_child.transfer_qty = flt(item.transfer_qty) @@ -119,104 +133,130 @@ class ClinicalProcedure(Document): cost_center = frappe.get_cached_value('Company', self.company, 'cost_center') se_child.cost_center = cost_center se_child.expense_account = expense_account + if submit: + stock_entry.submit() + return stock_entry return stock_entry.as_dict() -@frappe.whitelist() + def get_stock_qty(item_code, warehouse): return get_previous_sle({ - "item_code": item_code, - "warehouse": warehouse, - "posting_date": nowdate(), - "posting_time": nowtime() - }).get("qty_after_transaction") or 0 + 'item_code': item_code, + 'warehouse': warehouse, + 'posting_date': nowdate(), + 'posting_time': nowtime() + }).get('qty_after_transaction') or 0 + + +@frappe.whitelist() +def get_procedure_consumables(procedure_template): + return get_items('Clinical Procedure Item', procedure_template, 'Clinical Procedure Template') + @frappe.whitelist() def set_stock_items(doc, stock_detail_parent, parenttype): - item_dict = get_item_dict("Clinical Procedure Item", stock_detail_parent, parenttype) + items = get_items('Clinical Procedure Item', stock_detail_parent, parenttype) - for d in item_dict: + for item in items: se_child = doc.append('items') - se_child.item_code = d["item_code"] - se_child.item_name = d["item_name"] - se_child.uom = d["uom"] - se_child.stock_uom = d["stock_uom"] - se_child.qty = flt(d["qty"]) + se_child.item_code = item.item_code + se_child.item_name = item.item_name + se_child.uom = item.uom + se_child.stock_uom = item.stock_uom + se_child.qty = flt(item.qty) # in stock uom - se_child.transfer_qty = flt(d["transfer_qty"]) - se_child.conversion_factor = flt(d["conversion_factor"]) - if d["batch_no"]: - se_child.batch_no = d["batch_no"] - if parenttype == "Clinical Procedure Template": - se_child.invoice_separately_as_consumables = d["invoice_separately_as_consumables"] + se_child.transfer_qty = flt(item.transfer_qty) + se_child.conversion_factor = flt(item.conversion_factor) + if item.batch_no: + se_child.batch_no = item.batch_no + if parenttype == 'Clinical Procedure Template': + se_child.invoice_separately_as_consumables = item.invoice_separately_as_consumables + return doc -def get_item_dict(table, parent, parenttype): - query = """select * from `tab{table}` where parent = '{parent}' and parenttype = '{parenttype}' """ - return frappe.db.sql(query.format(table=table, parent=parent, parenttype=parenttype), as_dict=True) +def get_items(table, parent, parenttype): + items = frappe.db.get_all(table, filters={ + 'parent': parent, + 'parenttype': parenttype + }, fields=['*']) -def create_stock_entry(doc): - stock_entry = frappe.new_doc("Stock Entry") - stock_entry = set_stock_items(stock_entry, doc.name, "Clinical Procedure") - stock_entry.purpose = "Material Issue" + return items + + +@frappe.whitelist() +def make_stock_entry(doc): + stock_entry = frappe.new_doc('Stock Entry') + stock_entry = set_stock_items(stock_entry, doc.name, 'Clinical Procedure') + stock_entry.stock_entry_type = 'Material Issue' stock_entry.from_warehouse = doc.warehouse stock_entry.company = doc.company - expense_account = get_account(None, "expense_account", "Healthcare Settings", doc.company) + expense_account = get_account(None, 'expense_account', 'Healthcare Settings', doc.company) for item_line in stock_entry.items: cost_center = frappe.get_cached_value('Company', doc.company, 'cost_center') - #item_line.s_warehouse = warehouse #deaful source warehouse set, stock entry to copy to lines item_line.cost_center = cost_center - #if not expense_account: - # expense_account = frappe.db.get_value("Item", item_line.item_code, "expense_account") item_line.expense_account = expense_account - stock_entry.insert(ignore_permissions = True) + stock_entry.save(ignore_permissions=True) stock_entry.submit() + return stock_entry.name + @frappe.whitelist() -def create_procedure(appointment): - appointment = frappe.get_doc("Patient Appointment",appointment) - procedure = frappe.new_doc("Clinical Procedure") - procedure.appointment = appointment.name - procedure.patient = appointment.patient - procedure.patient_age = appointment.patient_age - procedure.patient_sex = appointment.patient_sex - procedure.procedure_template = appointment.procedure_template - procedure.prescription = appointment.procedure_prescription - procedure.practitioner = appointment.practitioner - procedure.invoiced = appointment.invoiced - procedure.medical_department = appointment.department - procedure.start_date = appointment.appointment_date - procedure.start_time = appointment.appointment_time - procedure.notes = appointment.notes - procedure.service_unit = appointment.service_unit - procedure.company = appointment.company - consume_stock = frappe.db.get_value("Clinical Procedure Template", appointment.procedure_template, "consume_stock") - if consume_stock == 1: - procedure.consume_stock = True - warehouse = False - if appointment.service_unit: - warehouse = frappe.db.get_value("Healthcare Service Unit", appointment.service_unit, "warehouse") - if not warehouse: - warehouse = frappe.db.get_value("Stock Settings", None, "default_warehouse") - if warehouse: - procedure.warehouse = warehouse - return procedure.as_dict() +def make_procedure(source_name, target_doc=None): + def set_missing_values(source, target): + consume_stock = frappe.db.get_value('Clinical Procedure Template', source.procedure_template, 'consume_stock') + if consume_stock: + target.consume_stock = 1 + warehouse = None + if source.service_unit: + warehouse = frappe.db.get_value('Healthcare Service Unit', source.service_unit, 'warehouse') + if not warehouse: + warehouse = frappe.db.get_value('Stock Settings', None, 'default_warehouse') + if warehouse: + target.warehouse = warehouse + + set_stock_items(target, source.procedure_template, 'Clinical Procedure Template') + + doc = get_mapped_doc('Patient Appointment', source_name, { + 'Patient Appointment': { + 'doctype': 'Clinical Procedure', + 'field_map': [ + ['appointment', 'name'], + ['patient', 'patient'], + ['patient_age', 'patient_age'], + ['patient_sex', 'patient_sex'], + ['procedure_template', 'procedure_template'], + ['prescription', 'procedure_prescription'], + ['practitioner', 'practitioner'], + ['medical_department', 'department'], + ['start_date', 'appointment_date'], + ['start_time', 'appointment_time'], + ['notes', 'notes'], + ['service_unit', 'service_unit'], + ['company', 'company'], + ['invoiced', 'invoiced'] + ] + } + }, target_doc, set_missing_values) + + return doc + def insert_clinical_procedure_to_medical_record(doc): subject = cstr(doc.procedure_template) if doc.practitioner: - subject += " "+doc.practitioner + subject += ' ' + doc.practitioner if subject and doc.notes: - subject += "
"+doc.notes + subject += '
' + doc.notes - medical_record = frappe.new_doc("Patient Medical Record") + medical_record = frappe.new_doc('Patient Medical Record') medical_record.patient = doc.patient medical_record.subject = subject - medical_record.status = "Open" + medical_record.status = 'Open' medical_record.communication_date = doc.start_date - medical_record.reference_doctype = "Clinical Procedure" + medical_record.reference_doctype = 'Clinical Procedure' medical_record.reference_name = doc.name medical_record.reference_owner = doc.owner medical_record.save(ignore_permissions=True) diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure_list.js b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure_list.js new file mode 100644 index 0000000000..c8601f9677 --- /dev/null +++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure_list.js @@ -0,0 +1,11 @@ +frappe.listview_settings['Clinical Procedure'] = { + get_indicator: function(doc) { + var colors = { + 'Completed': 'green', + 'In Progress': 'orange', + 'Pending': 'orange', + 'Cancelled': 'grey' + }; + return [__(doc.status), colors[doc.status], 'status,=,' + doc.status]; + } +}; diff --git a/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py b/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py index 09059e1bb4..207351ff20 100644 --- a/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py +++ b/erpnext/healthcare/doctype/clinical_procedure/test_clinical_procedure.py @@ -4,6 +4,60 @@ from __future__ import unicode_literals import unittest +import frappe +from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_healthcare_docs, create_clinical_procedure_template class TestClinicalProcedure(unittest.TestCase): - pass + def test_procedure_template_item(self): + patient, medical_department, practitioner = create_healthcare_docs() + procedure_template = create_clinical_procedure_template() + self.assertTrue(frappe.db.exists('Item', procedure_template.item)) + + procedure_template.disabled = 1 + procedure_template.save() + self.assertEquals(frappe.db.get_value('Item', procedure_template.item, 'disabled'), 1) + + def test_consumables(self): + patient, medical_department, practitioner = create_healthcare_docs() + procedure_template = create_clinical_procedure_template() + procedure_template.allow_stock_consumption = 1 + consumable = create_consumable() + procedure_template.append('items', { + 'item_code': consumable.item_code, + 'qty': 1, + 'uom': consumable.stock_uom, + 'stock_uom': consumable.stock_uom + }) + procedure_template.save() + procedure = create_procedure(procedure_template, patient, practitioner) + result = procedure.start_procedure() + if result == 'insufficient stock': + procedure.make_material_receipt(submit=True) + result = procedure.start_procedure() + self.assertEqual(procedure.status, 'In Progress') + result = procedure.complete_procedure() + # check consumption + self.assertTrue(frappe.db.exists('Stock Entry', result)) + + +def create_consumable(): + if frappe.db.exists('Item', 'Syringe'): + return frappe.get_doc('Item', 'Syringe') + consumable = frappe.new_doc('Item') + consumable.item_code = 'Syringe' + consumable.item_group = '_Test Item Group' + consumable.stock_uom = 'Nos' + consumable.valuation_rate = 5.00 + consumable.save() + return consumable + +def create_procedure(procedure_template, patient, practitioner): + procedure = frappe.new_doc('Clinical Procedure') + procedure.procedure_template = procedure_template.name + procedure.patient = patient + procedure.practitioner = practitioner + procedure.consume_stock = procedure_template.allow_stock_consumption + procedure.items = procedure_template.items + procedure.warehouse = frappe.db.get_single_value('Stock Settings', 'default_warehouse') + procedure.submit() + return procedure \ No newline at end of file diff --git a/erpnext/healthcare/doctype/clinical_procedure_item/clinical_procedure_item.json b/erpnext/healthcare/doctype/clinical_procedure_item/clinical_procedure_item.json index 75151b1d3f..a7dde0bcd0 100644 --- a/erpnext/healthcare/doctype/clinical_procedure_item/clinical_procedure_item.json +++ b/erpnext/healthcare/doctype/clinical_procedure_item/clinical_procedure_item.json @@ -1,431 +1,123 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 1, - "creation": "2017-10-05 16:15:10.876952", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "beta": 1, + "creation": "2017-10-05 16:15:10.876952", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "item_code", + "item_name", + "qty", + "barcode", + "uom", + "invoice_separately_as_consumables", + "column_break_5", + "batch_no", + "conversion_factor", + "stock_uom", + "transfer_qty", + "actual_qty" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 3, - "fieldname": "item_code", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Item", - "length": 0, - "no_copy": 0, - "options": "Item", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "bold": 1, + "columns": 3, + "fieldname": "item_code", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "in_global_search": 1, + "in_list_view": 1, + "label": "Item", + "options": "Item", + "reqd": 1, + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "barcode", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Barcode", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "barcode", + "fieldtype": "Data", + "label": "Barcode" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "item_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Item Name", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "item_name", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Item Name", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "qty", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Quantity", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "qty", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Quantity", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "uom", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "UOM", - "length": 0, - "no_copy": 0, - "options": "UOM", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "uom", + "fieldtype": "Link", + "in_list_view": 1, + "label": "UOM", + "options": "UOM", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "invoice_separately_as_consumables", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Invoice Separately as Consumables", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "invoice_separately_as_consumables", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Invoice Separately as Consumables" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_5", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_5", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "batch_no", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Batch", - "length": 0, - "no_copy": 0, - "options": "Batch", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "batch_no", + "fieldtype": "Link", + "label": "Batch", + "options": "Batch" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "conversion_factor", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Conversion Factor", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "conversion_factor", + "fieldtype": "Float", + "label": "Conversion Factor", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "stock_uom", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Stock UOM", - "length": 0, - "no_copy": 0, - "options": "UOM", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "stock_uom", + "fieldtype": "Link", + "label": "Stock UOM", + "options": "UOM", + "read_only": 1, + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "transfer_qty", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Transfer Qty", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "transfer_qty", + "fieldtype": "Float", + "label": "Transfer Qty", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "actual_qty", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Actual Qty (at source/target)", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldname": "actual_qty", + "fieldtype": "Float", + "label": "Actual Qty (at source/target)", + "no_copy": 1, + "print_hide": 1, + "read_only": 1, + "search_index": 1 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2018-11-04 03:33:16.833884", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Clinical Procedure Item", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 + ], + "istable": 1, + "links": [], + "modified": "2020-03-01 15:34:54.226722", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Clinical Procedure Item", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "restrict_to_domain": "Healthcare", + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.js b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.js index 583728dd18..57f4cdf3b2 100644 --- a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.js +++ b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.js @@ -3,170 +3,141 @@ frappe.ui.form.on('Clinical Procedure Template', { template: function(frm) { - if(!frm.doc.item_code) - frm.set_value("item_code", frm.doc.template); - if(!frm.doc.description) - frm.set_value("description", frm.doc.template); + if (!frm.doc.item_code) + frm.set_value('item_code', frm.doc.template); + if (!frm.doc.description) + frm.set_value('description', frm.doc.template); mark_change_in_item(frm); }, + rate: function(frm) { mark_change_in_item(frm); }, + is_billable: function (frm) { mark_change_in_item(frm); }, + item_group: function(frm) { mark_change_in_item(frm); }, + description: function(frm) { mark_change_in_item(frm); }, + medical_department: function(frm) { mark_change_in_item(frm); }, + refresh: function(frm) { - frm.fields_dict["items"].grid.set_column_disp("barcode", false); - frm.fields_dict["items"].grid.set_column_disp("batch_no", false); - cur_frm.set_df_property("item_code", "read_only", frm.doc.__islocal ? 0 : 1); - if(!frm.doc.__islocal) { + frm.fields_dict['items'].grid.set_column_disp('barcode', false); + frm.fields_dict['items'].grid.set_column_disp('batch_no', false); + + if (!frm.doc.__islocal) { cur_frm.add_custom_button(__('Change Item Code'), function() { change_template_code(frm.doc); - } ); - if(frm.doc.disabled == 1){ - cur_frm.add_custom_button(__('Enable Template'), function() { - enable_template(frm.doc); - } ); - } - else{ - cur_frm.add_custom_button(__('Disable Template'), function() { - disable_template(frm.doc); - } ); - } + }); } } }); -var mark_change_in_item = function(frm) { - if(!frm.doc.__islocal){ +let mark_change_in_item = function(frm) { + if (!frm.doc.__islocal) { frm.doc.change_in_item = 1; } }; -var disable_template = function(doc){ - frappe.call({ - method: "erpnext.healthcare.doctype.clinical_procedure_template.clinical_procedure_template.disable_enable_template", - args: {status: 1, name: doc.name, item_code: doc.item_code, is_billable: doc.is_billable}, - callback: function(){ - cur_frm.reload_doc(); - } - }); -}; - -var enable_template = function(doc){ - frappe.call({ - method: "erpnext.healthcare.doctype.clinical_procedure_template.clinical_procedure_template.disable_enable_template", - args: {status: 0, name: doc.name, item_code: doc.item_code, is_billable: doc.is_billable}, - callback: function(){ - cur_frm.reload_doc(); - } - }); -}; - - -var change_template_code = function(doc){ - var d = new frappe.ui.Dialog({ - title:__("Change Template Code"), +let change_template_code = function(doc) { + let d = new frappe.ui.Dialog({ + title:__('Change Item Code'), fields:[ { - "fieldtype": "Data", - "label": "Template Code", - "fieldname": "Item Code", - reqd:1 - }, - { - "fieldtype": "Button", - "label": __("Change Code"), - click: function() { - var values = d.get_values(); - if(!values) - return; - change_item_code_from_template(values["Item Code"], doc); - d.hide(); - } + 'fieldtype': 'Data', + 'label': 'Item Code', + 'fieldname': 'item_code', + reqd: 1 } - ] + ], + primary_action: function() { + let values = d.get_values(); + + if (values) { + frappe.call({ + 'method': 'erpnext.healthcare.doctype.clinical_procedure_template.clinical_procedure_template.change_item_code_from_template', + 'args': {item_code: values.item_code, doc: doc}, + callback: function () { + cur_frm.reload_doc(); + frappe.show_alert({ + message: 'Item Code renamed successfully', + indicator: 'green' + }); + } + }); + } + d.hide(); + }, + primary_action_label: __('Change Item Code') }); d.show(); - d.set_values({ - 'Item Code': doc.item_code - }); -}; -var change_item_code_from_template = function(item_code, doc){ - frappe.call({ - "method": "erpnext.healthcare.doctype.clinical_procedure_template.clinical_procedure_template.change_item_code_from_template", - "args": {item_code: item_code, doc: doc}, - callback: function () { - cur_frm.reload_doc(); - frappe.show_alert({ - message: "Item Code renamed successfully", - indicator: "green" - }); - } + d.set_values({ + 'item_code': doc.item_code }); }; frappe.ui.form.on('Clinical Procedure Item', { - qty: function(frm, cdt, cdn){ - var d = locals[cdt][cdn]; - frappe.model.set_value(cdt, cdn, "transfer_qty", d.qty*d.conversion_factor); + qty: function(frm, cdt, cdn) { + let d = locals[cdt][cdn]; + frappe.model.set_value(cdt, cdn, 'transfer_qty', d.qty * d.conversion_factor); }, + uom: function(doc, cdt, cdn){ - var d = locals[cdt][cdn]; - if(d.uom && d.item_code){ + let d = locals[cdt][cdn]; + if (d.uom && d.item_code) { return frappe.call({ - method: "erpnext.stock.doctype.stock_entry.stock_entry.get_uom_details", + method: 'erpnext.stock.doctype.stock_entry.stock_entry.get_uom_details', args: { item_code: d.item_code, uom: d.uom, qty: d.qty }, callback: function(r) { - if(r.message) { + if (r.message) { frappe.model.set_value(cdt, cdn, r.message); } } }); } }, + item_code: function(frm, cdt, cdn) { - var d = locals[cdt][cdn]; - if(d.item_code) { + let d = locals[cdt][cdn]; + if (d.item_code) { let args = { 'item_code' : d.item_code, 'transfer_qty' : d.transfer_qty, - 'company' : frm.doc.company, - 'quantity' : d.qty + 'quantity' : d.qty }; return frappe.call({ - doc: frm.doc, - method: "get_item_details", - args: args, + method: 'erpnext.healthcare.doctype.clinical_procedure_template.clinical_procedure_template.get_item_details', + args: {args: args}, callback: function(r) { - if(r.message) { - var d = locals[cdt][cdn]; - $.each(r.message, function(k, v){ + if (r.message) { + let d = locals[cdt][cdn]; + $.each(r.message, function(k, v) { d[k] = v; }); - refresh_field("items"); + refresh_field('items'); } } }); } } }); + // List Stock items -cur_frm.set_query("item_code", "items", function() { +cur_frm.set_query('item_code', 'items', function() { return { filters: { is_stock_item:1 diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.json b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.json index 26564a34ce..9cfd682f1d 100644 --- a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.json +++ b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.json @@ -1,807 +1,236 @@ { - "allow_copy": 0, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:template", - "beta": 1, - "creation": "2017-10-05 14:59:55.438359", - "custom": 0, - "description": "Procedure Template", - "docstatus": 0, - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "allow_import": 1, + "allow_rename": 1, + "autoname": "field:template", + "beta": 1, + "creation": "2017-10-05 14:59:55.438359", + "description": "Procedure Template", + "doctype": "DocType", + "document_type": "Setup", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "template", + "item", + "item_code", + "item_group", + "description", + "column_break_5", + "disabled", + "is_billable", + "rate", + "medical_department", + "consumables", + "consume_stock", + "items", + "sample_collection", + "sample", + "sample_uom", + "sample_qty", + "column_break_21", + "sample_details", + "change_in_item" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "template", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 1, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Template Name", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "fieldname": "template", + "fieldtype": "Data", + "in_global_search": 1, + "in_list_view": 1, + "label": "Template Name", + "reqd": 1, "unique": 1 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "item_code", + "fieldname": "item_code", + "fieldtype": "Data", + "label": "Item Code", + "options": "Item", + "read_only_depends_on": "eval: !doc.__islocal ", + "reqd": 1 + }, + { + "fieldname": "item_group", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Item Code", - "length": 0, - "no_copy": 1, - "options": "Item", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "ignore_user_permissions": 1, + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Item Group", + "options": "Item Group", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "item_group", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Item Group", - "length": 0, - "no_copy": 0, - "options": "Item Group", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "medical_department", + "fieldtype": "Link", + "label": "Medical Department", + "options": "Medical Department" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "medical_department", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Medical Department", - "length": 0, - "no_copy": 0, - "options": "Medical Department", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_5", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_5", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "is_billable", + "fieldtype": "Check", + "label": "Is Billable" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "is_billable", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Is Billable", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "depends_on": "is_billable", + "fieldname": "rate", + "fieldtype": "Float", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Rate", + "mandatory_depends_on": "is_billable" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "is_billable", - "fieldname": "rate", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Rate", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "description", + "fieldtype": "Small Text", + "ignore_xss_filter": 1, + "label": "Description", + "no_copy": 1, + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "description", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Description", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "consume_stock", + "fieldtype": "Check", + "label": "Allow Stock Consumption", + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "fieldname": "section_break_9", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "consumables", + "fieldtype": "Section Break", + "label": "Consumables" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "consume_stock", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Allow Stock Consumption", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "depends_on": "eval:doc.consume_stock == 1", + "fieldname": "items", + "fieldtype": "Table", + "ignore_user_permissions": 1, + "label": "Items", + "options": "Clinical Procedure Item" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.consume_stock == 1", - "fieldname": "consumables", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Consumables", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "collapsible": 1, + "fieldname": "sample_collection", + "fieldtype": "Section Break", + "label": "Sample Collection" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "items", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Items", - "length": 0, - "no_copy": 0, - "options": "Clinical Procedure Item", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sample", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "label": "Sample", + "options": "Lab Test Sample" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "columns": 0, - "depends_on": "", - "fieldname": "sample_collection", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Sample Collection", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "sample.sample_uom", + "fieldname": "sample_uom", + "fieldtype": "Data", + "label": "Sample UOM", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sample", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Sample", - "length": 0, - "no_copy": 0, - "options": "Lab Test Sample", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sample_qty", + "fieldtype": "Float", + "label": "Quantity" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "sample.sample_uom", - "fieldname": "sample_uom", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "UOM", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_21", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sample_qty", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Quantity", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sample_details", + "fieldtype": "Small Text", + "ignore_xss_filter": 1, + "label": "Collection Details" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_21", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "change_in_item", + "fieldtype": "Check", + "hidden": 1, + "label": "Change In Item", + "no_copy": 1, + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sample_details", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Collection Details", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "disabled", + "fieldtype": "Check", + "label": "Disabled" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "change_in_item", - "fieldtype": "Check", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Change In Item", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "disabled", - "fieldtype": "Check", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Disabled", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "item", - "fieldtype": "Link", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Item", - "length": 0, - "no_copy": 1, - "options": "Item", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldname": "item", + "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Item", + "no_copy": 1, + "options": "Item", + "read_only": 1 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2019-02-12 11:37:18.713344", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Clinical Procedure Template", - "name_case": "", - "owner": "Administrator", + ], + "links": [], + "modified": "2020-02-28 14:16:13.184981", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Clinical Procedure Template", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, "write": 1 - }, + }, { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Healthcare Administrator", + "share": 1, "write": 1 - }, + }, { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Nursing User", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 0 - }, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Nursing User", + "share": 1 + }, { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Physician", + "share": 1, "write": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "search_fields": "template", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "template", - "track_changes": 1, - "track_seen": 1, - "track_views": 0 + ], + "restrict_to_domain": "Healthcare", + "search_fields": "template", + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "template", + "track_changes": 1, + "track_seen": 1 } \ No newline at end of file diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py index 5a71ca5f15..3f295afc3e 100644 --- a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py +++ b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template.py @@ -7,126 +7,114 @@ import frappe, json from frappe import _ from frappe.model.document import Document from frappe.model.rename_doc import rename_doc -from frappe.utils import nowdate class ClinicalProcedureTemplate(Document): - def on_update(self): - #Item and Price List update --> if (change_in_item) - if(self.change_in_item and self.is_billable == 1 and self.item): - updating_item(self) - if(self.rate != 0.0): - updating_rate(self) - elif(self.is_billable == 0 and self.item): - frappe.db.set_value("Item",self.item,"disabled",1) - - frappe.db.set_value(self.doctype,self.name,"change_in_item",0) - self.reload() + def validate(self): + self.enable_disable_item() def after_insert(self): create_item_from_template(self) - #Call before delete the template - def on_trash(self): - if(self.item): - try: - frappe.delete_doc("Item",self.item) - except Exception: - frappe.throw(_("""Not permitted. Please disable the Procedure Template""")) + def on_update(self): + if self.change_in_item: + self.update_item_and_item_price() - def get_item_details(self, args=None): - item = frappe.db.sql("""select stock_uom, item_name - from `tabItem` - where name = %s - and disabled=0 - and (end_of_life is null or end_of_life='0000-00-00' or end_of_life > %s)""", - (args.get('item_code'), nowdate()), as_dict = 1) - if not item: - frappe.throw(_("Item {0} is not active or end of life has been reached").format(args.get('item_code'))) + def enable_disable_item(self): + if self.is_billable: + if self.disabled: + frappe.db.set_value('Item', self.item, 'disabled', 1) + else: + frappe.db.set_value('Item', self.item, 'disabled', 0) - item = item[0] + def update_item_and_item_price(self): + if self.is_billable and self.item: + item_doc = frappe.get_doc('Item', {'item_code': self.item}) + item_doc.item_name = self.template + item_doc.item_group = self.item_group + item_doc.description = self.description + item_doc.disabled = 0 + item_doc.save(ignore_permissions=True) - ret = { - 'uom' : item.stock_uom, - 'stock_uom' : item.stock_uom, - 'item_name' : item.item_name, - 'quantity' : 0, - 'transfer_qty' : 0, - 'conversion_factor' : 1 - } - return ret + if self.rate: + item_price = frappe.get_doc('Item Price', {'item_code': self.item}) + item_price.item_name = self.template + item_price.price_list_rate = self.rate + item_price.save() -def updating_item(self): - frappe.db.sql("""update `tabItem` set item_name=%s, item_group=%s, disabled=0, - description=%s, modified=NOW() where item_code=%s""", - (self.template, self.item_group , self.description, self.item)) -def updating_rate(self): - frappe.db.sql("""update `tabItem Price` set item_name=%s, price_list_rate=%s, modified=NOW() where - item_code=%s""",(self.template, self.rate, self.item)) + elif not self.is_billable and self.item: + frappe.db.set_value('Item', self.item, 'disabled', 1) + + self.db_set('change_in_item', 0) + + +@frappe.whitelist() +def get_item_details(args=None): + if not isinstance(args, dict): + args = json.loads(args) + + item = frappe.db.get_all('Item', + filters={ + 'disabled': 0, + 'name': args.get('item_code') + }, + fields=['stock_uom', 'item_name'] + ) + + if not item: + frappe.throw(_('Item {0} is not active').format(args.get('item_code'))) + + item = item[0] + ret = { + 'uom': item.stock_uom, + 'stock_uom': item.stock_uom, + 'item_name': item.item_name, + 'qty': 1, + 'transfer_qty': 0, + 'conversion_factor': 1 + } + return ret def create_item_from_template(doc): - disabled = 1 - - if(doc.is_billable == 1): + disabled = doc.disabled + if doc.is_billable and not doc.disabled: disabled = 0 - #insert item - item = frappe.get_doc({ - "doctype": "Item", - "item_code": doc.template, - "item_name":doc.template, - "item_group": doc.item_group, - "description":doc.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, - "disabled": disabled, - "stock_uom": "Unit" - }).insert(ignore_permissions=True) + item = frappe.get_doc({ + 'doctype': 'Item', + 'item_code': doc.template, + 'item_name':doc.template, + 'item_group': doc.item_group, + 'description':doc.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, + 'disabled': disabled, + 'stock_uom': 'Unit' + }).insert(ignore_permissions=True, ignore_mandatory=True) - #insert item price - #get item price list to insert item price - if(doc.rate != 0.0): - price_list_name = frappe.db.get_value("Price List", {"selling": 1}) - if(doc.rate): - make_item_price(item.name, price_list_name, doc.rate) - else: - make_item_price(item.name, price_list_name, 0.0) - #Set item to the template - frappe.db.set_value("Clinical Procedure Template", doc.name, "item", item.name) + make_item_price(item.name, doc.rate) + doc.db_set('item', item.name) - doc.reload() #refresh the doc after insert. - -def make_item_price(item, price_list_name, item_price): +def make_item_price(item, item_price): + price_list_name = frappe.db.get_value('Price List', {'selling': 1}) frappe.get_doc({ - "doctype": "Item Price", - "price_list": price_list_name, - "item_code": item, - "price_list_rate": item_price - }).insert(ignore_permissions=True) + 'doctype': 'Item Price', + 'price_list': price_list_name, + 'item_code': item, + 'price_list_rate': item_price + }).insert(ignore_permissions=True, ignore_mandatory=True) @frappe.whitelist() def change_item_code_from_template(item_code, doc): - args = json.loads(doc) - doc = frappe._dict(args) + doc = frappe._dict(json.loads(doc)) - if(frappe.db.exists({ - "doctype": "Item", - "item_code": item_code})): - frappe.throw(_("Code {0} already exist").format(item_code)) + if frappe.db.exists('Item', {'item_code': item_code}): + frappe.throw(_('Item with Item Code {0} already exists').format(item_code)) else: - rename_doc("Item", doc.item_code, item_code, ignore_permissions=True) - frappe.db.set_value("Clinical Procedure Template", doc.name, "item_code", item_code) + rename_doc('Item', doc.item_code, item_code, ignore_permissions=True) + frappe.db.set_value('Clinical Procedure Template', doc.name, 'item_code', item_code) return -@frappe.whitelist() -def disable_enable_template(status, name, item_code): - frappe.db.set_value("Clinical Procedure Template", name, "disabled", status) - if (frappe.db.exists({ #set Item's disabled field to status - "doctype": "Item", - "item_code": item_code})): - frappe.db.set_value("Item", item_code, "disabled", status) - - return diff --git a/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template_dashboard.py b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template_dashboard.py new file mode 100644 index 0000000000..9aab5216e1 --- /dev/null +++ b/erpnext/healthcare/doctype/clinical_procedure_template/clinical_procedure_template_dashboard.py @@ -0,0 +1,13 @@ +from __future__ import unicode_literals +from frappe import _ + +def get_data(): + return { + 'fieldname': 'procedure_template', + 'transactions': [ + { + 'label': _('Consultations'), + 'items': ['Clinical Procedure'] + } + ] + } diff --git a/erpnext/healthcare/doctype/codification_table/codification_table.json b/erpnext/healthcare/doctype/codification_table/codification_table.json index e65ae77fbf..9a917b4fff 100644 --- a/erpnext/healthcare/doctype/codification_table/codification_table.json +++ b/erpnext/healthcare/doctype/codification_table/codification_table.json @@ -1,140 +1,56 @@ { - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 1, - "creation": "2017-06-22 13:09:23.159579", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "allow_copy": 1, + "beta": 1, + "creation": "2017-06-22 13:09:23.159579", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "medical_code", + "code", + "description" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "medical_code", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Medical Code", - "length": 0, - "no_copy": 0, - "options": "Medical Code", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "medical_code", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "in_list_view": 1, + "label": "Medical Code", + "options": "Medical Code", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fetch_from": "medical_code.code", - "fieldname": "code", - "fieldtype": "Read Only", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Code", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "code", + "fieldtype": "Data", + "ignore_xss_filter": 1, + "in_list_view": 1, + "label": "Code", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fetch_from": "medical_code.description", - "fieldname": "description", - "fieldtype": "Read Only", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Description", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldname": "description", + "fieldtype": "Small Text", + "ignore_xss_filter": 1, + "in_list_view": 1, + "label": "Description", + "read_only": 1 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2018-05-16 22:43:27.047479", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Codification Table", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0 + ], + "istable": 1, + "links": [], + "modified": "2020-02-26 13:17:49.016293", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Codification Table", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "restrict_to_domain": "Healthcare", + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/healthcare/doctype/drug_prescription/drug_prescription.json b/erpnext/healthcare/doctype/drug_prescription/drug_prescription.json index 5647d3c88e..5e4d59cacf 100644 --- a/erpnext/healthcare/doctype/drug_prescription/drug_prescription.json +++ b/erpnext/healthcare/doctype/drug_prescription/drug_prescription.json @@ -1,381 +1,116 @@ { - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 1, - "creation": "2016-09-16 16:41:45.533374", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "allow_copy": 1, + "beta": 1, + "creation": "2016-09-16 16:41:45.533374", + "doctype": "DocType", + "document_type": "Document", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "drug_code", + "drug_name", + "dosage", + "period", + "dosage_form", + "column_break_7", + "comment", + "usage_interval", + "interval", + "interval_uom", + "update_schedule" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "drug_code", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Drug Code", - "length": 0, - "no_copy": 0, - "options": "Item", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "drug_code", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "in_list_view": 1, + "label": "Drug", + "options": "Item", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "drug_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Description/Strength", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fetch_from": "drug_code.item_name", + "fieldname": "drug_name", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Drug Name / Description" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "dosage", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Dosage", - "length": 0, - "no_copy": 0, - "options": "Prescription Dosage", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "dosage", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "in_list_view": 1, + "label": "Dosage", + "options": "Prescription Dosage" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "period", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Period", - "length": 0, - "no_copy": 0, - "options": "Prescription Duration", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "period", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "in_list_view": 1, + "label": "Period", + "options": "Prescription Duration" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "dosage_form", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Dosage Form", - "length": 0, - "no_copy": 0, - "options": "Dosage Form", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "dosage_form", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "label": "Dosage Form", + "options": "Dosage Form" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_7", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "column_break_7", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "comment", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Comment", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "comment", + "fieldtype": "Small Text", + "ignore_xss_filter": 1, + "in_list_view": 1, + "label": "Comment" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fieldname": "use_interval", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Dosage by time interval", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "depends_on": "use_interval", + "fieldname": "interval", + "fieldtype": "Int", + "in_list_view": 1, + "label": "Interval" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "use_interval", - "fieldname": "interval", - "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Interval", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "default": "1", + "fieldname": "update_schedule", + "fieldtype": "Check", + "hidden": 1, + "label": "Update Schedule", + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "use_interval", - "fieldname": "in_every", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Interval UOM", - "length": 0, - "no_copy": 0, - "options": "\nHour\nDay", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "depends_on": "use_interval", + "fieldname": "interval_uom", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Interval UOM", + "options": "\nHour\nDay" + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "1", - "fieldname": "update_schedule", - "fieldtype": "Check", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Update Schedule", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 + "default": "0", + "fieldname": "usage_interval", + "fieldtype": "Check", + "label": "Dosage by Time Interval" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2017-10-04 17:09:54.998517", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Drug Prescription", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 0, - "track_seen": 0 + ], + "istable": 1, + "links": [], + "modified": "2020-02-26 17:02:42.741338", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Drug Prescription", + "owner": "Administrator", + "permissions": [], + "restrict_to_domain": "Healthcare", + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/healthcare/doctype/drug_prescription/drug_prescription.py b/erpnext/healthcare/doctype/drug_prescription/drug_prescription.py index 0d99198fde..68a2dc5d3c 100755 --- a/erpnext/healthcare/doctype/drug_prescription/drug_prescription.py +++ b/erpnext/healthcare/doctype/drug_prescription/drug_prescription.py @@ -12,21 +12,21 @@ class DrugPrescription(Document): dosage = None period = None - if(self.dosage): - dosage = frappe.get_doc("Prescription Dosage",self.dosage) + if self.dosage: + dosage = frappe.get_doc('Prescription Dosage', self.dosage) for item in dosage.dosage_strength: quantity += item.strength - if(self.period and self.interval): - period = frappe.get_doc("Prescription Duration",self.period) - if(self.interval < period.get_days()): - quantity = quantity*(period.get_days()/self.interval) + if self.period and self.interval: + period = frappe.get_doc('Prescription Duration', self.period) + if self.interval < period.get_days(): + quantity = quantity * (period.get_days()/self.interval) - elif(self.interval and self.in_every and self.period): - period = frappe.get_doc("Prescription Duration",self.period) - interval_in = self.in_every - if(interval_in == 'Day' and (self.interval < period.get_days())): + elif self.interval and self.interval_uom and self.period: + period = frappe.get_doc('Prescription Duration', self.period) + interval_in = self.interval_uom + if interval_in == 'Day' and self.interval < period.get_days(): quantity = period.get_days()/self.interval - elif(interval_in == 'Hour' and (self.interval < period.get_hours())): + elif interval_in == 'Hour' and self.interval < period.get_hours(): quantity = period.get_hours()/self.interval if quantity > 0: return quantity diff --git a/erpnext/healthcare/doctype/fee_validity/fee_validity.json b/erpnext/healthcare/doctype/fee_validity/fee_validity.json index 802f04a359..b001bf024c 100644 --- a/erpnext/healthcare/doctype/fee_validity/fee_validity.json +++ b/erpnext/healthcare/doctype/fee_validity/fee_validity.json @@ -1,259 +1,134 @@ { - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 0, - "beta": 1, - "creation": "2017-01-05 10:56:29.564806", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "allow_copy": 1, + "allow_import": 1, + "beta": 1, + "creation": "2017-01-05 10:56:29.564806", + "doctype": "DocType", + "document_type": "Setup", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "practitioner", + "patient", + "column_break_3", + "status", + "section_break_5", + "section_break_3", + "max_visits", + "visited", + "ref_appointments", + "column_break_6", + "start_date", + "valid_till" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "practitioner", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Healthcare Practitioner", - "length": 0, - "no_copy": 0, - "options": "Healthcare Practitioner", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "practitioner", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Healthcare Practitioner", + "options": "Healthcare Practitioner", + "read_only": 1, + "reqd": 1, + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "patient", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Patient", - "length": 0, - "no_copy": 0, - "options": "Patient", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "patient", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Patient", + "options": "Patient", + "read_only": 1, + "reqd": 1, + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "max_visit", - "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Max number of visit", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "visited", + "fieldtype": "Int", + "label": "Visited yet", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "visited", - "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Visited yet", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "valid_till", + "fieldtype": "Date", + "label": "Valid till", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "valid_till", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Valid till", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "section_break_3", + "fieldtype": "Section Break", + "label": "Validity", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "ref_invoice", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Reference Inv", - "length": 0, - "no_copy": 0, - "options": "Sales Invoice", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldname": "column_break_6", + "fieldtype": "Column Break" + }, + { + "fieldname": "max_visits", + "fieldtype": "Int", + "label": "Max number of visit", + "read_only": 1 + }, + { + "fieldname": "column_break_3", + "fieldtype": "Column Break" + }, + { + "fieldname": "status", + "fieldtype": "Select", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Status", + "options": "Completed\nPending", + "read_only": 1 + }, + { + "fetch_from": "ref_appointment.appointment_date", + "fieldname": "start_date", + "fieldtype": "Date", + "label": "Start Date", + "read_only": 1 + }, + { + "fieldname": "ref_appointments", + "fieldtype": "Table MultiSelect", + "label": "Reference Appointments", + "options": "Fee Validity Reference", + "read_only": 1 + }, + { + "collapsible": 1, + "fieldname": "section_break_5", + "fieldtype": "Section Break" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-07-16 12:43:45.635230", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Fee Validity", - "name_case": "", - "owner": "Administrator", + ], + "in_create": 1, + "links": [], + "modified": "2020-03-17 20:25:06.487418", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Fee Validity", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Healthcare Administrator", + "share": 1, "write": 1 } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "search_fields": "practitioner, patient", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "practitioner", - "track_changes": 0, - "track_seen": 0 + ], + "quick_entry": 1, + "restrict_to_domain": "Healthcare", + "search_fields": "practitioner, patient", + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "practitioner" } \ No newline at end of file diff --git a/erpnext/healthcare/doctype/fee_validity/fee_validity.py b/erpnext/healthcare/doctype/fee_validity/fee_validity.py index 90285459ce..058bc97192 100644 --- a/erpnext/healthcare/doctype/fee_validity/fee_validity.py +++ b/erpnext/healthcare/doctype/fee_validity/fee_validity.py @@ -9,28 +9,55 @@ from frappe.utils import getdate import datetime class FeeValidity(Document): - pass + def validate(self): + self.update_status() + self.set_start_date() -def update_fee_validity(fee_validity, date, ref_invoice=None): - max_visit = frappe.db.get_value("Healthcare Settings", None, "max_visit") - valid_days = frappe.db.get_value("Healthcare Settings", None, "valid_days") - if not valid_days: - valid_days = 1 - if not max_visit: - max_visit = 1 - date = getdate(date) - valid_till = date + datetime.timedelta(days=int(valid_days)) - fee_validity.max_visit = max_visit + def update_status(self): + if self.visited >= self.max_visits: + self.status = 'Completed' + else: + self.status = 'Pending' + + def set_start_date(self): + self.start_date = getdate() + for appointment in self.ref_appointments: + appointment_date = frappe.db.get_value('Patient Appointment', appointment.appointment, 'appointment_date') + if getdate(appointment_date) < self.start_date: + self.start_date = getdate(appointment_date) + + +def create_fee_validity(appointment): + if not check_is_new_patient(appointment): + return + + fee_validity = frappe.new_doc('Fee Validity') + fee_validity.practitioner = appointment.practitioner + fee_validity.patient = appointment.patient + fee_validity.max_visits = frappe.db.get_single_value('Healthcare Settings', 'max_visits') or 1 + valid_days = frappe.db.get_single_value('Healthcare Settings', 'valid_days') or 1 fee_validity.visited = 1 - fee_validity.valid_till = valid_till - fee_validity.ref_invoice = ref_invoice + fee_validity.valid_till = getdate(appointment.appointment_date) + datetime.timedelta(days=int(valid_days)) + fee_validity.append('ref_appointments', { + 'appointment': appointment.name + }) fee_validity.save(ignore_permissions=True) return fee_validity +def check_is_new_patient(appointment): + validity_exists = frappe.db.exists('Fee Validity', { + 'practitioner': appointment.practitioner, + 'patient': appointment.patient + }) + if validity_exists: + return False -def create_fee_validity(practitioner, patient, date, ref_invoice=None): - fee_validity = frappe.new_doc("Fee Validity") - fee_validity.practitioner = practitioner - fee_validity.patient = patient - fee_validity = update_fee_validity(fee_validity, date, ref_invoice) - return fee_validity + appointment_exists = frappe.db.get_all('Patient Appointment', { + 'name': ('!=', appointment.name), + 'status': ('!=', 'Cancelled'), + 'patient': appointment.patient, + 'practitioner': appointment.practitioner + }) + if len(appointment_exists) and appointment_exists[0]: + return False + return True \ No newline at end of file diff --git a/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py b/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py index 26b1450463..cdf692e68b 100644 --- a/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py +++ b/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py @@ -5,100 +5,44 @@ from __future__ import unicode_literals import frappe import unittest -from frappe.utils.make_random import get_random -from frappe.utils import nowdate, add_days, getdate +from frappe.utils import nowdate, add_days +from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_healthcare_docs, create_appointment, create_healthcare_service_items test_dependencies = ["Company"] class TestFeeValidity(unittest.TestCase): - def test_fee_validity(self): + def setUp(self): frappe.db.sql("""delete from `tabPatient Appointment`""") frappe.db.sql("""delete from `tabFee Validity`""") - patient = get_random("Patient") - practitioner = get_random("Healthcare Practitioner") - department = get_random("Medical Department") + frappe.db.sql("""delete from `tabPatient`""") - if not patient: - patient = frappe.new_doc("Patient") - patient.patient_name = "_Test Patient" - patient.sex = "Male" - patient.save(ignore_permissions=True) - patient = patient.name + def test_fee_validity(self): + item = create_healthcare_service_items() + healthcare_settings = frappe.get_single("Healthcare Settings") + healthcare_settings.enable_free_follow_ups = 1 + healthcare_settings.max_visits = 2 + healthcare_settings.valid_days = 7 + healthcare_settings.automate_appointment_invoicing = 1 + healthcare_settings.op_consulting_charge_item = item + healthcare_settings.save(ignore_permissions=True) + patient, medical_department, practitioner = create_healthcare_docs() - if not department: - medical_department = frappe.new_doc("Medical Department") - medical_department.department = "_Test Medical Department" - medical_department.save(ignore_permissions=True) - department = medical_department.name - - if not practitioner: - practitioner = frappe.new_doc("Healthcare Practitioner") - practitioner.first_name = "_Test Healthcare Practitioner" - practitioner.department = department - practitioner.save(ignore_permissions=True) - practitioner = practitioner.name - - - - frappe.db.set_value("Healthcare Settings", None, "max_visit", 2) - frappe.db.set_value("Healthcare Settings", None, "valid_days", 7) - - appointment = create_appointment(patient, practitioner, nowdate(), department) + # appointment should not be invoiced. Check Fee Validity created for new patient + appointment = create_appointment(patient, practitioner, nowdate()) invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced") self.assertEqual(invoiced, 0) - invoice_appointment(appointment) - - appointment = create_appointment(patient, practitioner, add_days(nowdate(), 4), department) - invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced") - self.assertTrue(invoiced) - - appointment = create_appointment(patient, practitioner, add_days(nowdate(), 5), department) + # appointment should not be invoiced as it is within fee validity + appointment = create_appointment(patient, practitioner, add_days(nowdate(), 4)) invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced") self.assertEqual(invoiced, 0) - appointment = create_appointment(patient, practitioner, add_days(nowdate(), 10), department) + # appointment should be invoiced as it is within fee validity but the max_visits are exceeded + appointment = create_appointment(patient, practitioner, add_days(nowdate(), 5), invoice=1) invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced") - self.assertEqual(invoiced, 0) + self.assertEqual(invoiced, 1) -def create_appointment(patient, practitioner, appointment_date, department): - appointment = frappe.new_doc("Patient Appointment") - appointment.patient = patient - appointment.practitioner = practitioner - appointment.department = department - appointment.appointment_date = appointment_date - appointment.company = "_Test Company" - appointment.duration = 15 - appointment.save(ignore_permissions=True) - return appointment - -def invoice_appointment(appointment_doc): - if not appointment_doc.name: - return False - sales_invoice = frappe.new_doc("Sales Invoice") - sales_invoice.customer = frappe.get_value("Patient", appointment_doc.patient, "customer") - sales_invoice.due_date = getdate() - sales_invoice.is_pos = 0 - sales_invoice.company = appointment_doc.company - sales_invoice.debit_to = "_Test Receivable - _TC" - - create_invoice_items(appointment_doc, sales_invoice) - - sales_invoice.save(ignore_permissions=True) - sales_invoice.submit() - -def create_invoice_items(appointment, invoice): - item_line = invoice.append("items") - item_line.item_name = "Consulting Charges" - item_line.description = "Consulting Charges: " + appointment.practitioner - item_line.uom = "Nos" - item_line.conversion_factor = 1 - item_line.income_account = "_Test Account Cost for Goods Sold - _TC" - item_line.cost_center = "_Test Cost Center - _TC" - item_line.rate = 250 - item_line.amount = 250 - item_line.qty = 1 - item_line.reference_dt = "Patient Appointment" - item_line.reference_dn = appointment.name - - return invoice + # appointment should be invoiced as it is not within fee validity and the max_visits are exceeded + appointment = create_appointment(patient, practitioner, add_days(nowdate(), 10), invoice=1) + invoiced = frappe.db.get_value("Patient Appointment", appointment.name, "invoiced") + self.assertEqual(invoiced, 1) \ No newline at end of file diff --git a/erpnext/healthcare/page/appointment_analytic/__init__.py b/erpnext/healthcare/doctype/fee_validity_reference/__init__.py similarity index 100% rename from erpnext/healthcare/page/appointment_analytic/__init__.py rename to erpnext/healthcare/doctype/fee_validity_reference/__init__.py diff --git a/erpnext/healthcare/doctype/fee_validity_reference/fee_validity_reference.json b/erpnext/healthcare/doctype/fee_validity_reference/fee_validity_reference.json new file mode 100644 index 0000000000..40f128e973 --- /dev/null +++ b/erpnext/healthcare/doctype/fee_validity_reference/fee_validity_reference.json @@ -0,0 +1,32 @@ +{ + "actions": [], + "creation": "2020-03-13 16:08:42.859996", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "appointment" + ], + "fields": [ + { + "fieldname": "appointment", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Patient Appointment", + "options": "Patient Appointment", + "reqd": 1 + } + ], + "istable": 1, + "links": [], + "modified": "2020-03-15 00:27:02.076470", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Fee Validity Reference", + "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/fee_validity_reference/fee_validity_reference.py b/erpnext/healthcare/doctype/fee_validity_reference/fee_validity_reference.py new file mode 100644 index 0000000000..c819280832 --- /dev/null +++ b/erpnext/healthcare/doctype/fee_validity_reference/fee_validity_reference.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 FeeValidityReference(Document): + pass diff --git a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.js b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.js index efca484d6a..4ab3b6e9c1 100644 --- a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.js +++ b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.js @@ -4,7 +4,7 @@ frappe.ui.form.on('Healthcare Practitioner', { setup: function(frm) { frm.set_query('account', 'accounts', function(doc, cdt, cdn) { - var d = locals[cdt][cdn]; + let d = locals[cdt][cdn]; return { filters: { 'root_type': 'Income', @@ -16,23 +16,28 @@ frappe.ui.form.on('Healthcare Practitioner', { }, refresh: function(frm) { frappe.dynamic_link = {doc: frm.doc, fieldname: 'name', doctype: 'Healthcare Practitioner'}; - if(!frm.is_new()) { + + if (!frm.is_new()) { frappe.contacts.render_address_and_contact(frm); + } else { + frappe.contacts.clear_address_and_contact(frm); } - frm.set_query("service_unit", "practitioner_schedules", function(){ + + frm.set_query('service_unit', 'practitioner_schedules', function(){ return { filters: { - "is_group": false, - "allow_appointments": true + 'is_group': false, + 'allow_appointments': true } }; }); + set_query_service_item(frm, 'inpatient_visit_charge_item'); set_query_service_item(frm, 'op_consulting_charge_item'); } }); -var set_query_service_item = function(frm, service_item_field) { +let set_query_service_item = function(frm, service_item_field) { frm.set_query(service_item_field, function() { return { filters: { @@ -43,62 +48,62 @@ var set_query_service_item = function(frm, service_item_field) { }); }; -frappe.ui.form.on("Healthcare Practitioner", "user_id",function(frm) { - if(frm.doc.user_id){ +frappe.ui.form.on('Healthcare Practitioner', 'user_id',function(frm) { + if (frm.doc.user_id) { frappe.call({ - "method": "frappe.client.get", + 'method': 'frappe.client.get', args: { - doctype: "User", + doctype: 'User', name: frm.doc.user_id }, callback: function (data) { frappe.model.get_value('Employee', {'user_id': frm.doc.user_id}, 'name', function(data) { - if(data){ - if(!frm.doc.employee || frm.doc.employee != data.name) - frappe.model.set_value(frm.doctype,frm.docname, "employee", data.name); - }else{ - frappe.model.set_value(frm.doctype,frm.docname, "employee", ""); + if (data) { + if (!frm.doc.employee || frm.doc.employee != data.name) + frappe.model.set_value(frm.doctype, frm.docname, 'employee', data.name); + } else { + frappe.model.set_value(frm.doctype, frm.docname, 'employee', ''); } } ); - if(!frm.doc.first_name || frm.doc.first_name != data.message.first_name) - frappe.model.set_value(frm.doctype,frm.docname, "first_name", data.message.first_name); - if(!frm.doc.middle_name || frm.doc.middle_name != data.message.middle_name) - frappe.model.set_value(frm.doctype,frm.docname, "middle_name", data.message.middle_name); - if(!frm.doc.last_name || frm.doc.last_name != data.message.last_name) - frappe.model.set_value(frm.doctype,frm.docname, "last_name", data.message.last_name); - if(!frm.doc.mobile_phone || frm.doc.mobile_phone != data.message.mobile_no) - frappe.model.set_value(frm.doctype,frm.docname, "mobile_phone", data.message.mobile_no); + if (!frm.doc.first_name || frm.doc.first_name != data.message.first_name) + frappe.model.set_value(frm.doctype,frm.docname, 'first_name', data.message.first_name); + if (!frm.doc.middle_name || frm.doc.middle_name != data.message.middle_name) + frappe.model.set_value(frm.doctype,frm.docname, 'middle_name', data.message.middle_name); + if (!frm.doc.last_name || frm.doc.last_name != data.message.last_name) + frappe.model.set_value(frm.doctype,frm.docname, 'last_name', data.message.last_name); + if (!frm.doc.mobile_phone || frm.doc.mobile_phone != data.message.mobile_no) + frappe.model.set_value(frm.doctype,frm.docname, 'mobile_phone', data.message.mobile_no); } }); } }); -frappe.ui.form.on("Healthcare Practitioner", "employee", function(frm) { - if(frm.doc.employee){ +frappe.ui.form.on('Healthcare Practitioner', 'employee', function(frm) { + if (frm.doc.employee){ frappe.call({ - "method": "frappe.client.get", + 'method': 'frappe.client.get', args: { - doctype: "Employee", + doctype: 'Employee', name: frm.doc.employee }, callback: function (data) { - if(!frm.doc.user_id || frm.doc.user_id != data.message.user_id) - frm.set_value("user_id", data.message.user_id); - if(!frm.doc.designation || frm.doc.designation != data.message.designation) - frappe.model.set_value(frm.doctype,frm.docname, "designation", data.message.designation); - if(!frm.doc.first_name || !frm.doc.user_id){ - frappe.model.set_value(frm.doctype,frm.docname, "first_name", data.message.employee_name); - frappe.model.set_value(frm.doctype,frm.docname, "middle_name", ""); - frappe.model.set_value(frm.doctype,frm.docname, "last_name", ""); + if (!frm.doc.user_id || frm.doc.user_id != data.message.user_id) + frm.set_value('user_id', data.message.user_id); + if (!frm.doc.designation || frm.doc.designation != data.message.designation) + frappe.model.set_value(frm.doctype,frm.docname, 'designation', data.message.designation); + if (!frm.doc.first_name || !frm.doc.user_id){ + frappe.model.set_value(frm.doctype,frm.docname, 'first_name', data.message.first_name); + frappe.model.set_value(frm.doctype,frm.docname, 'middle_name', ''); + frappe.model.set_value(frm.doctype,frm.docname, 'last_name', data.message.last_name); } - if(!frm.doc.mobile_phone || !frm.doc.user_id) - frappe.model.set_value(frm.doctype,frm.docname, "mobile_phone", data.message.cell_number); - if(!frm.doc.address || frm.doc.address != data.message.current_address) - frappe.model.set_value(frm.doctype,frm.docname, "address", data.message.current_address); + if (!frm.doc.mobile_phone || !frm.doc.user_id) + frappe.model.set_value(frm.doctype,frm.docname, 'mobile_phone', data.message.cell_number); + if (!frm.doc.address || frm.doc.address != data.message.current_address) + frappe.model.set_value(frm.doctype,frm.docname, 'address', data.message.current_address); } }); } diff --git a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.json b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.json index 4a848a081d..fd5b6e12f6 100644 --- a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.json +++ b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.json @@ -1,1041 +1,327 @@ { + "actions": [], "allow_copy": 1, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, "allow_import": 1, "allow_rename": 1, - "autoname": "", + "autoname": "naming_series:", "beta": 1, "creation": "2016-02-23 11:20:53.565119", - "custom": 0, - "docstatus": 0, "doctype": "DocType", "document_type": "Setup", - "editable_grid": 0, + "engine": "InnoDB", + "field_order": [ + "basic_details_section", + "naming_series", + "first_name", + "middle_name", + "last_name", + "practitioner_name", + "gender", + "image", + "column_break_7", + "status", + "mobile_phone", + "residence_phone", + "office_phone", + "employee_and_user_details_section", + "employee", + "department", + "designation", + "column_break_17", + "user_id", + "hospital", + "appointments", + "practitioner_schedules", + "charges", + "op_consulting_charge_item", + "op_consulting_charge", + "column_break_18", + "inpatient_visit_charge_item", + "inpatient_visit_charge", + "account_details", + "default_currency", + "accounts", + "address_and_contacts_section", + "address_html", + "column_break_19", + "contact_html" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "first_name", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, "label": "First Name", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "reqd": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "middle_name", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Middle Name (Optional)", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Middle Name (Optional)" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "last_name", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Last Name", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Last Name" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "image", "fieldtype": "Attach Image", "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Image", - "length": 0, "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "print_hide": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "employee", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Employee", - "length": 0, - "no_copy": 0, - "options": "Employee", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "Employee" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "user_id", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "User", - "length": 0, - "no_copy": 0, "options": "User", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "fetch_from": "employee", "fieldname": "designation", "fieldtype": "Link", - "hidden": 0, "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, "in_standard_filter": 1, "label": "Designation", - "length": 0, - "no_copy": 0, "options": "Designation", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "department", "fieldtype": "Link", - "hidden": 0, "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, "in_standard_filter": 1, - "label": "Department", - "length": 0, - "no_copy": 0, - "options": "Medical Department", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Medical Department", + "options": "Medical Department" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "column_break_7", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "hospital", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Hospital", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Hospital" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "mobile_phone", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, - "label": "Mobile", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Mobile" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "residence_phone", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Phone (R)", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Phone (R)" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "office_phone", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, - "label": "Phone (Office)", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Phone (Office)" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "1", - "fieldname": "active", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Active", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "collapsible": 1, "fieldname": "appointments", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Appointments", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Appointments" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "practitioner_schedules", "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Practitioner Schedules", - "length": 0, - "no_copy": 0, - "options": "Practitioner Service Unit Schedule", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "Practitioner Service Unit Schedule" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "collapsible": 1, "fieldname": "charges", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Charges", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Charges" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "op_consulting_charge_item", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Out Patient Consulting Charge Item", - "length": 0, - "no_copy": 0, - "options": "Item", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "Item" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "op_consulting_charge", "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "OP Consulting Charge", - "length": 0, - "no_copy": 0, - "options": "Currency", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Out Patient Consulting Charge", + "options": "Currency" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "column_break_18", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "inpatient_visit_charge_item", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Inpatient Visit Charge Item", - "length": 0, - "no_copy": 0, - "options": "Item", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "Item" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "inpatient_visit_charge", "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Inpatient Visit Charge", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Inpatient Visit Charge" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "contacts_and_address", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Contacts and Address", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "depends_on": "eval: !doc.__islocal", "fieldname": "address_html", "fieldtype": "HTML", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Address HTML", - "length": 0, "no_copy": 1, - "permlevel": 0, - "precision": "", "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "report_hide": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "column_break_19", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "depends_on": "eval: !doc.__islocal", "fieldname": "contact_html", "fieldtype": "HTML", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Contact HTML", - "length": 0, "no_copy": 1, - "permlevel": 0, - "precision": "", "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "report_hide": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "collapsible": 1, "fieldname": "account_details", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Account Details", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Account Details" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "accounts", "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Income Account", - "length": 0, - "no_copy": 0, - "options": "Party Account", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "Party Account" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "default_currency", "fieldtype": "Link", "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Default Currency", - "length": 0, "no_copy": 1, "options": "Currency", - "permlevel": 0, - "precision": "", "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, + "report_hide": 1 + }, + { + "bold": 1, + "fieldname": "practitioner_name", + "fieldtype": "Data", + "in_global_search": 1, + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Full Name", + "read_only": 1, + "search_index": 1 + }, + { + "fieldname": "naming_series", + "fieldtype": "Select", + "label": "Series", + "options": "HLC-PRAC-.YYYY.-", "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "set_only_once": 1 + }, + { + "fieldname": "gender", + "fieldtype": "Link", + "label": "Gender", + "options": "Gender" + }, + { + "fieldname": "employee_and_user_details_section", + "fieldtype": "Section Break", + "label": "Employee and User Details" + }, + { + "fieldname": "column_break_17", + "fieldtype": "Column Break" + }, + { + "default": "Active", + "fieldname": "status", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Status", + "options": "\nActive\nDisabled", + "reqd": 1 + }, + { + "fieldname": "basic_details_section", + "fieldtype": "Section Break", + "label": "Basic Details" + }, + { + "collapsible": 1, + "depends_on": "eval: !doc.__islocal", + "fieldname": "address_and_contacts_section", + "fieldtype": "Section Break", + "label": "Address and Contacts" } ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, "image_field": "image", - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-11-23 08:54:51.442105", + "links": [], + "modified": "2020-04-06 13:44:24.759623", "modified_by": "Administrator", "module": "Healthcare", "name": "Healthcare Practitioner", - "name_case": "", "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, "create": 1, - "delete": 0, "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "Laboratory User", - "set_user_permissions": 0, "share": 1, - "submit": 0, "write": 1 }, { - "amend": 0, - "cancel": 0, "create": 1, "delete": 1, "email": 1, "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "Physician", - "set_user_permissions": 0, "share": 1, - "submit": 0, "write": 1 }, { - "amend": 0, - "cancel": 0, "create": 1, "delete": 1, "email": 1, "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "Nursing User", - "set_user_permissions": 0, "share": 1, - "submit": 0, "write": 1 } ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, "restrict_to_domain": "Healthcare", - "search_fields": "first_name,mobile_phone,office_phone", + "search_fields": "practitioner_name, mobile_phone, office_phone", "show_name_in_global_search": 1, "sort_field": "modified", "sort_order": "DESC", - "title_field": "first_name", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 + "title_field": "practitioner_name", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py index ad32e94631..0c13b6af9d 100644 --- a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py +++ b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner.py @@ -5,10 +5,10 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document -from frappe import throw, _ -from frappe.utils import cstr +from frappe import _ from erpnext.accounts.party import validate_party_accounts from frappe.contacts.address_and_contact import load_address_and_contact, delete_contact_and_address +from frappe.model.naming import append_number_if_name_exists from frappe.desk.reportview import build_match_conditions, get_filters_cond class HealthcarePractitioner(Document): @@ -16,63 +16,66 @@ class HealthcarePractitioner(Document): load_address_and_contact(self) def autoname(self): - # practitioner first_name and last_name - self.name = " ".join(filter(None, - [cstr(self.get(f)).strip() for f in ["first_name","middle_name","last_name"]])) + # concat first and last name + self.name = self.practitioner_name + + if frappe.db.exists('Healthcare Practitioner', self.name): + self.name = append_number_if_name_exists('Contact', self.name) def validate(self): + self.set_full_name() validate_party_accounts(self) if self.inpatient_visit_charge_item: - validate_service_item(self.inpatient_visit_charge_item, "Configure a service Item for Inpatient Visit Charge Item") + validate_service_item(self.inpatient_visit_charge_item, 'Configure a service Item for Inpatient Consulting Charge Item') if self.op_consulting_charge_item: - validate_service_item(self.op_consulting_charge_item, "Configure a service Item for Out Patient Consulting Charge Item") + validate_service_item(self.op_consulting_charge_item, 'Configure a service Item for Out Patient Consulting Charge Item') if self.user_id: - self.validate_for_enabled_user_id() - self.validate_duplicate_user_id() - existing_user_id = frappe.db.get_value("Healthcare Practitioner", self.name, "user_id") - if self.user_id != existing_user_id: - frappe.permissions.remove_user_permission( - "Healthcare Practitioner", self.name, existing_user_id) - + self.validate_user_id() else: - existing_user_id = frappe.db.get_value("Healthcare Practitioner", self.name, "user_id") + existing_user_id = frappe.db.get_value('Healthcare Practitioner', self.name, 'user_id') if existing_user_id: frappe.permissions.remove_user_permission( - "Healthcare Practitioner", self.name, existing_user_id) + 'Healthcare Practitioner', self.name, existing_user_id) def on_update(self): if self.user_id: - frappe.permissions.add_user_permission("Healthcare Practitioner", self.name, self.user_id) + frappe.permissions.add_user_permission('Healthcare Practitioner', self.name, self.user_id) + def set_full_name(self): + if self.last_name: + self.practitioner_name = ' '.join(filter(None, [self.first_name, self.last_name])) + else: + self.practitioner_name = self.first_name - def validate_for_enabled_user_id(self): - enabled = frappe.db.get_value("User", self.user_id, "enabled") - if enabled is None: - frappe.throw(_("User {0} does not exist").format(self.user_id)) - if enabled == 0: - frappe.throw(_("User {0} is disabled").format(self.user_id)) + def validate_user_id(self): + if not frappe.db.exists('User', self.user_id): + frappe.throw(_('User {0} does not exist').format(self.user_id)) + elif not frappe.db.exists('User', self.user_id, 'enabled'): + frappe.throw(_('User {0} is disabled').format(self.user_id)) - def validate_duplicate_user_id(self): - practitioner = frappe.db.sql_list("""select name from `tabHealthcare Practitioner` where - user_id=%s and name!=%s""", (self.user_id, self.name)) + # check duplicate + practitioner = frappe.db.exists('Healthcare Practitioner', { + 'user_id': self.user_id, + 'name': ('!=', self.name) + }) if practitioner: - throw(_("User {0} is already assigned to Healthcare Practitioner {1}").format( - self.user_id, practitioner[0]), frappe.DuplicateEntryError) + frappe.throw(_('User {0} is already assigned to Healthcare Practitioner {1}').format( + self.user_id, practitioner)) def on_trash(self): delete_contact_and_address('Healthcare Practitioner', self.name) def validate_service_item(item, msg): - if frappe.db.get_value("Item", item, "is_stock_item") == 1: + if frappe.db.get_value('Item', item, 'is_stock_item'): frappe.throw(_(msg)) def get_practitioner_list(doctype, txt, searchfield, start, page_len, filters=None): - fields = ["name", "first_name", "mobile_phone"] + fields = ['name', 'practitioner_name', 'mobile_phone'] filters = { - 'name': ("like", "%%%s%%" % txt) + 'name': ('like', '%%%s%%' % txt) } - return frappe.get_all("Healthcare Practitioner", fields = fields, - filters = filters, start=start, page_length=page_len, order_by="name, first_name", as_list=1) + return frappe.get_all('Healthcare Practitioner', fields = fields, + filters = filters, start=start, page_length=page_len, order_by='name, practitioner_name', as_list=1) diff --git a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner_dashboard.py b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner_dashboard.py index 70c0b3c098..bcee44430a 100644 --- a/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner_dashboard.py +++ b/erpnext/healthcare/doctype/healthcare_practitioner/healthcare_practitioner_dashboard.py @@ -9,7 +9,11 @@ def get_data(): 'transactions': [ { 'label': _('Appointments and Patient Encounters'), - 'items': ['Patient Appointment', 'Patient Encounter'] + 'items': ['Patient Appointment', 'Patient Encounter', 'Fee Validity'] + }, + { + 'label': _('Consultation'), + 'items': ['Clinical Procedure', 'Lab Test'] } ] } diff --git a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.js b/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.js index 8480a526b4..2cdd550656 100644 --- a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.js +++ b/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.js @@ -3,7 +3,7 @@ frappe.ui.form.on('Healthcare Service Unit', { onload: function(frm) { - frm.list_route = "Tree/Healthcare Service Unit"; + frm.list_route = 'Tree/Healthcare Service Unit'; // get query select healthcare service unit frm.fields_dict['parent_healthcare_service_unit'].get_query = function(doc) { @@ -16,32 +16,32 @@ frappe.ui.form.on('Healthcare Service Unit', { }; }, refresh: function(frm) { - frm.trigger("set_root_readonly"); - frm.set_df_property("service_unit_type", "reqd", 1); - frm.add_custom_button(__("Healthcare Service Unit Tree"), function() { - frappe.set_route("Tree", "Healthcare Service Unit"); + frm.trigger('set_root_readonly'); + frm.set_df_property('service_unit_type', 'reqd', 1); + frm.add_custom_button(__('Healthcare Service Unit Tree'), function() { + frappe.set_route('Tree', 'Healthcare Service Unit'); }); }, set_root_readonly: function(frm) { // read-only for root healthcare service unit - frm.set_intro(""); - if(!frm.doc.parent_healthcare_service_unit) { + frm.set_intro(''); + if (!frm.doc.parent_healthcare_service_unit) { frm.set_read_only(); - frm.set_intro(__("This is a root healthcare service unit and cannot be edited."), true); + frm.set_intro(__('This is a root healthcare service unit and cannot be edited.'), true); } }, allow_appointments: function(frm) { - if(!frm.doc.allow_appointments){ - frm.set_value("overlap_appointments", false); + if (!frm.doc.allow_appointments) { + frm.set_value('overlap_appointments', false); } }, is_group: function(frm) { - if(frm.doc.is_group == 1){ - frm.set_value("allow_appointments", false); - frm.set_df_property("service_unit_type", "reqd", 0); + if (frm.doc.is_group == 1) { + frm.set_value('allow_appointments', false); + frm.set_df_property('service_unit_type', 'reqd', 0); } - else{ - frm.set_df_property("service_unit_type", "reqd", 1); + else { + frm.set_df_property('service_unit_type', 'reqd', 1); } } }); diff --git a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.json b/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.json index 8601f69c07..ea4ae846f7 100644 --- a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.json +++ b/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.json @@ -9,6 +9,7 @@ "doctype": "DocType", "document_type": "Setup", "editable_grid": 1, + "engine": "InnoDB", "field_order": [ "healthcare_service_unit_name", "parent_healthcare_service_unit", @@ -18,6 +19,7 @@ "overlap_appointments", "inpatient_occupancy", "occupancy_status", + "column_break_9", "warehouse", "company", "lft", @@ -99,9 +101,13 @@ "fieldtype": "Select", "label": "Occupancy Status", "no_copy": 1, - "options": "Vacant\nOccupied", + "options": "\nVacant\nOccupied", "read_only": 1 }, + { + "fieldname": "column_break_9", + "fieldtype": "Column Break" + }, { "bold": 1, "depends_on": "eval:doc.is_group != 1", @@ -153,13 +159,11 @@ "report_hide": 1 } ], - "is_tree": 1, "links": [], - "modified": "2020-03-18 18:02:23.713439", + "modified": "2020-03-26 16:13:08.675952", "modified_by": "Administrator", "module": "Healthcare", "name": "Healthcare Service Unit", - "nsm_parent_field": "parent_healthcare_service_unit", "owner": "Administrator", "permissions": [ { diff --git a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.py b/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.py index b40869348d..13cc43d2be 100644 --- a/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.py +++ b/erpnext/healthcare/doctype/healthcare_service_unit/healthcare_service_unit.py @@ -23,9 +23,9 @@ class HealthcareServiceUnit(NestedSet): self.validate_one_root() def validate(self): - if self.is_group == 1: + if self.is_group: self.allow_appointments = 0 self.overlap_appointments = 0 self.inpatient_occupancy = 0 - elif self.allow_appointments != 1: + elif not self.allow_appointments: self.overlap_appointments = 0 diff --git a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.js b/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.js index 288ebc40b4..eb33ab68c0 100644 --- a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.js +++ b/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.js @@ -2,118 +2,85 @@ // For license information, please see license.txt frappe.ui.form.on('Healthcare Service Unit Type', { + refresh: function(frm) { + frm.set_df_property('item_code', 'read_only', frm.doc.__islocal ? 0 : 1); + if (!frm.doc.__islocal && frm.doc.is_billable) { + frm.add_custom_button(__('Change Item Code'), function() { + change_item_code(cur_frm, frm.doc); + }); + } + }, + service_unit_type: function(frm) { set_item_details(frm); - if(!frm.doc.__islocal){ + + if (!frm.doc.__islocal) { frm.doc.change_in_item = 1; } }, + is_billable: function(frm) { set_item_details(frm); }, - refresh: function(frm) { - frm.set_df_property("item_code", "read_only", frm.doc.__islocal ? 0 : 1); - if(!frm.doc.__islocal) { - frm.add_custom_button(__('Change Item Code'), function() { - change_item_code(cur_frm,frm.doc); - } ); - if(frm.doc.disabled == 1){ - frm.add_custom_button(__('Enable'), function() { - enable(cur_frm); - } ); - } - else{ - frm.add_custom_button(__('Disable'), function() { - disable(cur_frm); - } ); - } - } - }, + rate: function(frm) { - if(!frm.doc.__islocal){ + if (!frm.doc.__islocal) { frm.doc.change_in_item = 1; } }, item_group: function(frm) { - if(!frm.doc.__islocal){ + if (!frm.doc.__islocal) { frm.doc.change_in_item = 1; } }, description: function(frm) { - if(!frm.doc.__islocal){ + if (!frm.doc.__islocal) { frm.doc.change_in_item = 1; } } }); -var disable = function(frm){ - var doc = frm.doc; - frappe.call({ - method: "erpnext.healthcare.doctype.healthcare_service_unit_type.healthcare_service_unit_type.disable_enable", - args: {status: 1, doc_name: doc.name, item: doc.item, is_billable: doc.is_billable}, - callback: function(){ - cur_frm.reload_doc(); - } - }); +let set_item_details = function(frm) { + if (frm.doc.service_unit_type && frm.doc.is_billable) { + if (!frm.doc.item_code) + frm.set_value('item_code', frm.doc.service_unit_type); + if (!frm.doc.description) + frm.set_value('description', frm.doc.service_unit_type); + if (!frm.doc.item_group) + frm.set_value('item_group', 'Services'); + } }; -var enable = function(frm){ - var doc = frm.doc; - frappe.call({ - method: "erpnext.healthcare.doctype.healthcare_service_unit_type.healthcare_service_unit_type.disable_enable", - args: {status: 0, doc_name: doc.name, item: doc.item, is_billable: doc.is_billable}, - callback: function(){ - cur_frm.reload_doc(); - } - }); -}; - -var change_item_code = function(frm, doc){ - var d = new frappe.ui.Dialog({ - title:__("Change Item Code"), - fields:[ +let change_item_code = function(frm, doc) { + let d = new frappe.ui.Dialog({ + title: __('Change Item Code'), + fields: [ { - "fieldtype": "Data", - "label": "Item Code", - "fieldname": "Item Code", - reqd:1 - }, - { - "fieldtype": "Button", - "label": __("Change Code"), - click: function() { - var values = d.get_values(); - if(!values) - return; - change_item_code_from_unit_type(values["Item Code"], doc); - d.hide(); - } + 'fieldtype': 'Data', + 'label': 'Item Code', + 'fieldname': 'item_code', + 'default': doc.item_code, + reqd: 1, } - ] + ], + primary_action: function() { + let values = d.get_values(); + if (values) { + frappe.call({ + "method": "erpnext.healthcare.doctype.healthcare_service_unit_type.healthcare_service_unit_type.change_item_code", + "args": {item: doc.item, item_code: values['item_code'], doc_name: doc.name}, + callback: function () { + frm.reload_doc(); + } + }); + } + d.hide(); + }, + primary_action_label: __("Change Template Code") }); + d.show(); d.set_values({ 'Item Code': frm.doc.item_code }); - - var change_item_code_from_unit_type = function(item_code, doc){ - frappe.call({ - "method": "erpnext.healthcare.doctype.healthcare_service_unit_type.healthcare_service_unit_type.change_item_code", - "args": {item: doc.item, item_code: item_code, doc_name: doc.name}, - callback: function () { - frm.reload_doc(); - } - }); - }; -}; - -var set_item_details = function(frm) { - if(frm.doc.service_unit_type && frm.doc.is_billable == 1){ - if(!frm.doc.item_code) - frm.set_value("item_code", frm.doc.service_unit_type); - if(!frm.doc.description) - frm.set_value("description", frm.doc.service_unit_type); - if(!frm.doc.item_group) - frm.set_value("item_group", 'Services'); - } }; diff --git a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.json b/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.json index 40681e9f77..5fa47d91bc 100644 --- a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.json +++ b/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.json @@ -1,588 +1,164 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:service_unit_type", - "beta": 0, - "creation": "2018-07-11 16:47:51.414675", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "allow_import": 1, + "allow_rename": 1, + "autoname": "field:service_unit_type", + "creation": "2018-07-11 16:47:51.414675", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "disabled", + "service_unit_type", + "allow_appointments", + "overlap_appointments", + "inpatient_occupancy", + "is_billable", + "item_details", + "item", + "item_code", + "item_group", + "uom", + "no_of_hours", + "column_break_11", + "rate", + "description", + "change_in_item" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "service_unit_type", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Service Unit Type", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, + "fieldname": "service_unit_type", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Service Unit Type", + "reqd": 1, "unique": 1 - }, + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "default": "0", - "depends_on": "eval:doc.inpatient_occupancy != 1", - "fieldname": "allow_appointments", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Allow Appointments", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "bold": 1, + "default": "0", + "depends_on": "eval:doc.inpatient_occupancy != 1", + "fieldname": "allow_appointments", + "fieldtype": "Check", + "label": "Allow Appointments", + "no_copy": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "default": "0", - "depends_on": "eval:doc.allow_appointments == 1 && doc.inpatient_occupany != 1", - "fieldname": "overlap_appointments", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Allow Overlap", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "bold": 1, + "default": "0", + "depends_on": "eval:doc.allow_appointments == 1 && doc.inpatient_occupany != 1", + "fieldname": "overlap_appointments", + "fieldtype": "Check", + "label": "Allow Overlap", + "no_copy": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "default": "0", - "depends_on": "eval:doc.allow_appointments != 1", - "fieldname": "inpatient_occupancy", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Inpatient Occupancy", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "bold": 1, + "default": "0", + "depends_on": "eval:doc.allow_appointments != 1", + "fieldname": "inpatient_occupancy", + "fieldtype": "Check", + "label": "Inpatient Occupancy", + "no_copy": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.inpatient_occupancy == 1 && doc.allow_appointments != 1", - "fieldname": "is_billable", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Is Billable", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "bold": 1, + "default": "0", + "depends_on": "eval:doc.inpatient_occupancy == 1 && doc.allow_appointments != 1", + "fieldname": "is_billable", + "fieldtype": "Check", + "label": "Is Billable" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "is_billable", - "fieldname": "item_details", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Item Details", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "depends_on": "is_billable", + "fieldname": "item_details", + "fieldtype": "Section Break", + "label": "Item Details" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "item", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Item", - "length": 0, - "no_copy": 0, - "options": "Item", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "item", + "fieldtype": "Link", + "label": "Item", + "options": "Item", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "item_code", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Item Code", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "item_code", + "fieldtype": "Data", + "label": "Item Code", + "mandatory_depends_on": "eval: doc.is_billable == 1" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "item_group", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Item Group", - "length": 0, - "no_copy": 0, - "options": "Item Group", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "item_group", + "fieldtype": "Link", + "label": "Item Group", + "mandatory_depends_on": "eval: doc.is_billable == 1", + "options": "Item Group" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "uom", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "UOM", - "length": 0, - "no_copy": 0, - "options": "UOM", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "uom", + "fieldtype": "Link", + "label": "UOM", + "mandatory_depends_on": "eval: doc.is_billable == 1", + "options": "UOM" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "no_of_hours", - "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "UOM Conversion in Hours", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "no_of_hours", + "fieldtype": "Int", + "label": "UOM Conversion in Hours", + "mandatory_depends_on": "eval: doc.is_billable == 1" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_11", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_11", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "rate", - "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Rate / UOM", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "rate", + "fieldtype": "Currency", + "label": "Rate / UOM" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fieldname": "disabled", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Disabled", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "disabled", + "fieldtype": "Check", + "label": "Disabled", + "no_copy": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "description", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Description", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "description", + "fieldtype": "Small Text", + "label": "Description" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "change_in_item", - "fieldtype": "Check", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Change in Item", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "default": "0", + "fieldname": "change_in_item", + "fieldtype": "Check", + "hidden": 1, + "label": "Change in Item" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-08-08 13:00:23.751635", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Healthcare Service Unit Type", - "name_case": "", - "owner": "Administrator", + ], + "links": [], + "modified": "2020-01-30 16:06:00.624496", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Healthcare Service Unit Type", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Healthcare Administrator", + "share": 1, "write": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "service_unit_type", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + ], + "restrict_to_domain": "Healthcare", + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "service_unit_type" } \ No newline at end of file diff --git a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.py b/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.py index 43f01c86b9..286ecc0ff8 100644 --- a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.py +++ b/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type.py @@ -10,109 +10,107 @@ from frappe.model.rename_doc import rename_doc class HealthcareServiceUnitType(Document): def validate(self): - if self.is_billable == 1: - if not self.uom or not self.item_group or not self.description or not self.no_of_hours > 0: - frappe.throw(_("Configure Item Fields like UOM, Item Group, Description and No of Hours.")) + if self.is_billable: + if self.disabled: + frappe.db.set_value('Item', self.item, 'disabled', 1) + else: + frappe.db.set_value('Item', self.item, 'disabled', 0) def after_insert(self): if self.inpatient_occupancy and self.is_billable: create_item(self) def on_trash(self): - if(self.item): + if self.item: try: - frappe.delete_doc("Item",self.item) + frappe.delete_doc('Item', self.item) except Exception: - frappe.throw(_("""Not permitted. Please disable the Service Unit Type""")) + frappe.throw(_('Not permitted. Please disable the Service Unit Type')) def on_update(self): - if(self.change_in_item and self.is_billable == 1 and self.item): - updating_item(self) - item_price = item_price_exist(self) - if not item_price: - if(self.rate != 0.0): - price_list_name = frappe.db.get_value("Price List", {"selling": 1}) - if(self.rate): - make_item_price(self.item_code, price_list_name, self.rate) - else: - make_item_price(self.item_code, price_list_name, 0.0) - else: - frappe.db.set_value("Item Price", item_price, "price_list_rate", self.rate) + if self.change_in_item and self.is_billable and self.item: + update_item(self) - frappe.db.set_value(self.doctype,self.name,"change_in_item",0) - elif(self.is_billable == 0 and self.item): - frappe.db.set_value("Item",self.item,"disabled",1) + item_price = item_price_exists(self) + + if not item_price: + price_list_name = frappe.db.get_value('Price List', {'selling': 1}) + if self.rate: + make_item_price(self.item_code, price_list_name, self.rate) + else: + make_item_price(self.item_code, price_list_name, 0.0) + else: + frappe.db.set_value('Item Price', item_price, 'price_list_rate', self.rate) + + frappe.db.set_value(self.doctype, self.name, 'change_in_item',0) + elif not self.is_billable and self.item: + frappe.db.set_value('Item', self.item, 'disabled', 1) self.reload() -def item_price_exist(doc): - item_price = frappe.db.exists({ - "doctype": "Item Price", - "item_code": doc.item_code}) - if(item_price): - return item_price[0][0] - else: - return False -def updating_item(doc): - frappe.db.sql("""update `tabItem` set item_name=%s, item_group=%s, disabled=0, standard_rate=%s, - description=%s, modified=NOW() where item_code=%s""", - (doc.service_unit_type, doc.item_group , doc.rate, doc.description, doc.item)) +def item_price_exists(doc): + item_price = frappe.db.exists({'doctype': 'Item Price', 'item_code': doc.item_code}) + if len(item_price): + return item_price[0][0] + return False def create_item(doc): - #insert item + # insert item item = frappe.get_doc({ - "doctype": "Item", - "item_code": doc.item_code, - "item_name":doc.service_unit_type, - "item_group": doc.item_group, - "description":doc.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, - "disabled": 0, - "stock_uom": doc.uom - }).insert(ignore_permissions=True) + 'doctype': 'Item', + 'item_code': doc.item_code, + 'item_name': doc.service_unit_type, + 'item_group': doc.item_group, + 'description': doc.description or doc.item_code, + 'is_sales_item': 1, + 'is_service_item': 1, + 'is_purchase_item': 0, + 'is_stock_item': 0, + 'show_in_website': 0, + 'is_pro_applicable': 0, + 'disabled': 0, + 'stock_uom': doc.uom + }).insert(ignore_permissions=True, ignore_mandatory=True) - #insert item price - #get item price list to insert item price - if(doc.rate != 0.0): - price_list_name = frappe.db.get_value("Price List", {"selling": 1}) - if(doc.rate): - make_item_price(item.name, price_list_name, doc.rate) - item.standard_rate = doc.rate - else: - make_item_price(item.name, price_list_name, 0.0) - item.standard_rate = 0.0 - item.save(ignore_permissions = True) - #Set item to the Doc - frappe.db.set_value("Healthcare Service Unit Type", doc.name, "item", item.name) + # insert item price + # get item price list to insert item price + price_list_name = frappe.db.get_value('Price List', {'selling': 1}) + if doc.rate: + make_item_price(item.name, price_list_name, doc.rate) + item.standard_rate = doc.rate + else: + make_item_price(item.name, price_list_name, 0.0) + item.standard_rate = 0.0 - doc.reload() #refresh the doc after insert. + item.save(ignore_permissions=True) + + # Set item in the doc + doc.db_set('item', item.name) def make_item_price(item, price_list_name, item_price): frappe.get_doc({ - "doctype": "Item Price", - "price_list": price_list_name, - "item_code": item, - "price_list_rate": item_price - }).insert(ignore_permissions=True) + 'doctype': 'Item Price', + 'price_list': price_list_name, + 'item_code': item, + 'price_list_rate': item_price + }).insert(ignore_permissions=True, ignore_mandatory=True) + +def update_item(doc): + item = frappe.get_doc("Item", doc.item) + if item: + item.update({ + "item_name": doc.service_unit_type, + "item_group": doc.item_group, + "disabled": 0, + "standard_rate": doc.rate, + "description": doc.description + }) + item.db_update() @frappe.whitelist() def change_item_code(item, item_code, doc_name): - item_exist = frappe.db.exists({ - "doctype": "Item", - "item_code": item_code}) - if(item_exist): - frappe.throw(_("Code {0} already exist").format(item_code)) + if frappe.db.exists({'doctype': 'Item', 'item_code': item_code}): + frappe.throw(_('Item with Item Code {0} already exists').format(item_code)) else: - rename_doc("Item", item, item_code, ignore_permissions=True) - frappe.db.set_value("Healthcare Service Unit Type", doc_name, "item_code", item_code) - -@frappe.whitelist() -def disable_enable(status, doc_name, item=None, is_billable=None): - frappe.db.set_value("Healthcare Service Unit Type", doc_name, "disabled", status) - if(is_billable == 1): - frappe.db.set_value("Item", item, "disabled", status) + rename_doc('Item', item, item_code, ignore_permissions=True) + frappe.db.set_value('Healthcare Service Unit Type', doc_name, 'item_code', item_code) diff --git a/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type_dashboard.py b/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type_dashboard.py new file mode 100644 index 0000000000..0ac548b3ff --- /dev/null +++ b/erpnext/healthcare/doctype/healthcare_service_unit_type/healthcare_service_unit_type_dashboard.py @@ -0,0 +1,13 @@ +from __future__ import unicode_literals +from frappe import _ + +def get_data(): + return { + 'fieldname': 'service_unit_type', + 'transactions': [ + { + 'label': _('Healthcare Service Units'), + 'items': ['Healthcare Service Unit'] + }, + ] + } diff --git a/erpnext/healthcare/doctype/healthcare_service_unit_type/test_healthcare_service_unit_type.py b/erpnext/healthcare/doctype/healthcare_service_unit_type/test_healthcare_service_unit_type.py index 3c5b64fd93..01cf4b0a49 100644 --- a/erpnext/healthcare/doctype/healthcare_service_unit_type/test_healthcare_service_unit_type.py +++ b/erpnext/healthcare/doctype/healthcare_service_unit_type/test_healthcare_service_unit_type.py @@ -3,6 +3,31 @@ # See license.txt from __future__ import unicode_literals import unittest +import frappe class TestHealthcareServiceUnitType(unittest.TestCase): - pass + def test_item_creation(self): + unit_type = get_unit_type() + self.assertTrue(frappe.db.exists('Item', unit_type.item)) + + # check item disabled + unit_type.disabled = 1 + unit_type.save() + self.assertEqual(frappe.db.get_value('Item', unit_type.item, 'disabled'), 1) + + +def get_unit_type(): + if frappe.db.exists('Healthcare Service Unit Type', 'Inpatient Rooms'): + return frappe.get_doc('Healthcare Service Unit Type', 'Inpatient Rooms') + + unit_type = frappe.new_doc('Healthcare Service Unit Type') + unit_type.service_unit_type = 'Inpatient Rooms' + unit_type.inpatient_occupancy = 1 + unit_type.is_billable = 1 + unit_type.item_code = 'Inpatient Rooms' + unit_type.item_group = 'Services' + unit_type.uom = 'Hour' + unit_type.no_of_hours = 1 + unit_type.rate = 4000 + unit_type.save() + return unit_type \ No newline at end of file diff --git a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json b/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json index 95d9e44cdd..de08620179 100644 --- a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json +++ b/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json @@ -7,40 +7,40 @@ "engine": "InnoDB", "field_order": [ "sb_op_settings", - "patient_master_name", - "manage_customer", + "patient_name_by", + "link_customer_to_patient", "default_medical_code_standard", "column_break_9", "collect_registration_fee", "registration_fee", - "manage_appointment_invoice_automatically", - "max_visit", + "automate_appointment_invoicing", + "enable_free_follow_ups", + "max_visits", "valid_days", "healthcare_service_items", "inpatient_visit_charge_item", "op_consulting_charge_item", "column_break_13", "clinical_procedure_consumable_item", - "out_patient_sms_alerts", - "reg_sms", - "reg_msg", - "app_con", - "app_con_msg", - "no_con", - "column_break_16", - "app_rem", - "app_rem_msg", - "rem_before", "sb_in_ac", "income_account", - "sb_r_ac", "receivable_account", + "out_patient_sms_alerts", + "send_registration_msg", + "registration_msg", + "send_appointment_confirmation", + "appointment_confirmation_msg", + "avoid_confirmation", + "column_break_16", + "send_appointment_reminder", + "appointment_reminder_msg", + "remind_before", "sb_lab_settings", - "create_test_on_si_submit", - "require_sample_collection", - "require_test_result_approval", + "create_lab_test_on_si_submit", + "create_sample_collection_for_lab_test", "column_break_34", "employee_name_and_designation_in_print", + "lab_test_approval_required", "custom_signature_in_print", "laboratory_sms_alerts", "sms_printed", @@ -53,19 +53,6 @@ "fieldtype": "Section Break", "label": "Out Patient Settings" }, - { - "fieldname": "patient_master_name", - "fieldtype": "Select", - "label": "Patient Name By", - "options": "Patient Name\nNaming Series" - }, - { - "default": "1", - "description": "If checked, a customer will be created, mapped to Patient.\nPatient Invoices will be created against this Customer. You can also select existing Customer while creating Patient.", - "fieldname": "manage_customer", - "fieldtype": "Check", - "label": "Manage Customer" - }, { "fieldname": "default_medical_code_standard", "fieldtype": "Link", @@ -78,6 +65,7 @@ }, { "default": "0", + "description": "Checking this will create new Patients with a Disabled status by default and will only be enabled after invoicing the Registration Fee.", "fieldname": "collect_registration_fee", "fieldtype": "Check", "label": "Collect Fee for Patient Registration" @@ -91,27 +79,19 @@ "options": "Currency" }, { - "default": "0", - "description": "Manage Appointment Invoice submit and cancel automatically for Patient Encounter", - "fieldname": "manage_appointment_invoice_automatically", - "fieldtype": "Check", - "label": "Invoice Appointments Automatically" - }, - { - "fieldname": "max_visit", - "fieldtype": "Int", - "label": "Patient Encounters in valid days" - }, - { + "depends_on": "eval:doc.enable_free_follow_ups == 1", + "description": "Time period (Valid number of days) for free consultations", "fieldname": "valid_days", "fieldtype": "Int", - "label": "Valid number of days" + "label": "Valid Number of Days", + "mandatory_depends_on": "eval:doc.enable_free_follow_ups == 1" }, { "collapsible": 1, + "description": "You can configure default Items for billing consultation charges, procedure consumption items and inpatient visits", "fieldname": "healthcare_service_items", "fieldtype": "Section Break", - "label": "Healthcare Service Items" + "label": "Default Healthcare Service Items" }, { "fieldname": "inpatient_visit_charge_item", @@ -141,87 +121,25 @@ "fieldtype": "Section Break", "label": "Out Patient SMS Alerts" }, - { - "default": "0", - "fieldname": "reg_sms", - "fieldtype": "Check", - "label": "Patient Registration" - }, - { - "default": "Hello {{doc.patient}}, Thank you for registering with {{doc.company}}. Your ID is {{doc.id}} . Please note this ID for future reference. \nThank You, Get well soon!", - "depends_on": "reg_sms", - "fieldname": "reg_msg", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "label": "Registration Message" - }, - { - "default": "0", - "fieldname": "app_con", - "fieldtype": "Check", - "label": "Appointment Confirmation" - }, - { - "default": "Hello {{doc.patient}}, You have scheduled an appointment with {{doc.practitioner}} by {{doc.start_dt}} at {{doc.company}}.\nThank you, Good day!", - "depends_on": "app_con", - "fieldname": "app_con_msg", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "label": "Confirmation Message" - }, - { - "default": "0", - "depends_on": "app_con", - "description": "Do not confirm if appointment is created for the same day", - "fieldname": "no_con", - "fieldtype": "Check", - "label": "Avoid Confirmation" - }, { "fieldname": "column_break_16", "fieldtype": "Column Break" }, - { - "default": "0", - "fieldname": "app_rem", - "fieldtype": "Check", - "label": "Appointment Reminder" - }, - { - "default": "Hello {{doc.patient}}, You have an appointment with {{doc.practitioner}} by {{doc.appointment_time}} at {{doc.company}}.\nThank you, Good day!\n", - "depends_on": "app_rem", - "fieldname": "app_rem_msg", - "fieldtype": "Small Text", - "ignore_xss_filter": 1, - "label": "Reminder Message" - }, - { - "depends_on": "app_rem", - "fieldname": "rem_before", - "fieldtype": "Time", - "label": "Remind Before" - }, { "collapsible": 1, - "description": "Default income accounts to be used if not set in Healthcare Practitioner to book Appointment charges.", "fieldname": "sb_in_ac", "fieldtype": "Section Break", - "label": "Income Account" + "label": "Default Accounts" }, { + "description": "Default income accounts to be used if not set in Healthcare Practitioner to book Appointment charges.", "fieldname": "income_account", "fieldtype": "Table", "label": "Income Account", "options": "Party Account" }, { - "collapsible": 1, - "description": "Default receivable accounts to be used if not set in Patient to book Appointment charges.", - "fieldname": "sb_r_ac", - "fieldtype": "Section Break", - "label": "Receivable Account" - }, - { + "description": "Default receivable accounts to be used to book Appointment charges.", "fieldname": "receivable_account", "fieldtype": "Table", "label": "Receivable Account", @@ -233,31 +151,13 @@ "fieldtype": "Section Break", "label": "Laboratory Settings" }, - { - "default": "0", - "fieldname": "create_test_on_si_submit", - "fieldtype": "Check", - "label": "Create Lab Test(s) on Sales Invoice Submit" - }, - { - "default": "0", - "description": "Create documents for sample collection", - "fieldname": "require_sample_collection", - "fieldtype": "Check", - "label": "Manage Sample Collection" - }, - { - "default": "0", - "fieldname": "require_test_result_approval", - "fieldtype": "Check", - "label": "Require Lab Test Approval" - }, { "fieldname": "column_break_34", "fieldtype": "Column Break" }, { "default": "1", + "description": "Check this if you want the Name and Designation of the Employee associated with the User who submits the document to be printed in the Lab Test Report.", "fieldname": "employee_name_and_designation_in_print", "fieldtype": "Check", "label": "Employee name and designation in print" @@ -279,7 +179,7 @@ "fieldname": "sms_printed", "fieldtype": "Small Text", "ignore_xss_filter": 1, - "label": "Result Printed" + "label": "Result Printed Message" }, { "fieldname": "column_break_28", @@ -290,12 +190,123 @@ "fieldname": "sms_emailed", "fieldtype": "Small Text", "ignore_xss_filter": 1, - "label": "Result Emailed" + "label": "Result Emailed Message" + }, + { + "default": "0", + "description": "Checking this will restrict printing and emailing of Lab Test documents unless they have the status as Approved.", + "fieldname": "lab_test_approval_required", + "fieldtype": "Check", + "label": "Do not print or email Lab Tests without Approval" + }, + { + "default": "1", + "description": "If checked, a customer will be created, mapped to Patient.\nPatient Invoices will be created against this Customer. You can also select existing Customer while creating Patient.", + "fieldname": "link_customer_to_patient", + "fieldtype": "Check", + "label": "Link Customer to Patient" + }, + { + "default": "0", + "description": "Checking this will create Lab Test(s) specified in the Sales Invoice on submission.", + "fieldname": "create_lab_test_on_si_submit", + "fieldtype": "Check", + "label": "Create Lab Test(s) on Sales Invoice Submission" + }, + { + "default": "0", + "description": "Checking this will create a Sample Collection document every time you create a Lab Test", + "fieldname": "create_sample_collection_for_lab_test", + "fieldtype": "Check", + "label": "Create Sample Collection document for Lab Test" + }, + { + "fieldname": "patient_name_by", + "fieldtype": "Select", + "label": "Patient Name By", + "options": "Patient Name\nNaming Series" + }, + { + "default": "0", + "description": "Manage Appointment Invoice submit and cancel automatically for Patient Encounter", + "fieldname": "automate_appointment_invoicing", + "fieldtype": "Check", + "label": "Automate Appointment Invoicing" + }, + { + "default": "0", + "fieldname": "send_registration_msg", + "fieldtype": "Check", + "label": "Patient Registration" + }, + { + "default": "Hello {{doc.patient}}, Thank you for registering with {{doc.company}}. Your ID is {{doc.id}} . Please note this ID for future reference. \nThank You, Get well soon!", + "depends_on": "send_registration_msg", + "fieldname": "registration_msg", + "fieldtype": "Small Text", + "ignore_xss_filter": 1, + "label": "Registration Message" + }, + { + "default": "0", + "fieldname": "send_appointment_confirmation", + "fieldtype": "Check", + "label": "Appointment Confirmation" + }, + { + "default": "Hello {{doc.patient}}, You have scheduled an appointment with {{doc.practitioner}} by {{doc.start_dt}} at {{doc.company}}.\nThank you, Good day!", + "depends_on": "send_appointment_confirmation", + "fieldname": "appointment_confirmation_msg", + "fieldtype": "Small Text", + "ignore_xss_filter": 1, + "label": "Confirmation Message" + }, + { + "default": "0", + "depends_on": "send_appointment_confirmation", + "description": "Do not confirm if appointment is created for the same day", + "fieldname": "avoid_confirmation", + "fieldtype": "Check", + "label": "Avoid Confirmation" + }, + { + "default": "0", + "fieldname": "send_appointment_reminder", + "fieldtype": "Check", + "label": "Appointment Reminder" + }, + { + "default": "Hello {{doc.patient}}, You have an appointment with {{doc.practitioner}} by {{doc.appointment_time}} at {{doc.company}}.\nThank you, Good day!\n", + "depends_on": "send_appointment_reminder", + "fieldname": "appointment_reminder_msg", + "fieldtype": "Small Text", + "ignore_xss_filter": 1, + "label": "Reminder Message" + }, + { + "depends_on": "send_appointment_reminder", + "fieldname": "remind_before", + "fieldtype": "Time", + "label": "Remind Before" + }, + { + "depends_on": "eval:doc.enable_free_follow_ups == 1", + "description": "The number of free follow ups (Patient Encounters in valid days) allowed", + "fieldname": "max_visits", + "fieldtype": "Int", + "label": "Number of Patient Encounters in Valid Days", + "mandatory_depends_on": "eval:doc.enable_free_follow_ups == 1" + }, + { + "default": "0", + "fieldname": "enable_free_follow_ups", + "fieldtype": "Check", + "label": "Enable Free Follow-ups" } ], "issingle": 1, "links": [], - "modified": "2020-01-23 13:31:43.699711", + "modified": "2020-03-26 11:25:21.842092", "modified_by": "Administrator", "module": "Healthcare", "name": "Healthcare Settings", diff --git a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.py b/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.py index 8555e80f84..a16fceb74d 100644 --- a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.py +++ b/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.py @@ -11,69 +11,80 @@ import json class HealthcareSettings(Document): def validate(self): - for key in ["collect_registration_fee","manage_customer","patient_master_name", - "require_test_result_approval","require_sample_collection", "default_medical_code_standard"]: + for key in ['collect_registration_fee', 'link_customer_to_patient', 'patient_name_by', + 'lab_test_approval_required', 'create_sample_collection_for_lab_test', 'default_medical_code_standard']: frappe.db.set_default(key, self.get(key, "")) - if(self.collect_registration_fee): - if self.registration_fee <= 0 : - frappe.throw(_("Registration fee can not be Zero")) + + if self.collect_registration_fee: + if self.registration_fee <= 0: + frappe.throw(_('Registration Fee cannot be negative or zero')) + if self.inpatient_visit_charge_item: - validate_service_item(self.inpatient_visit_charge_item, "Configure a service Item for Inpatient Visit Charge Item") + validate_service_item(self.inpatient_visit_charge_item) if self.op_consulting_charge_item: - validate_service_item(self.op_consulting_charge_item, "Configure a service Item for Out Patient Consulting Charge Item") + validate_service_item(self.op_consulting_charge_item) if self.clinical_procedure_consumable_item: - validate_service_item(self.clinical_procedure_consumable_item, "Configure a service Item for Clinical Procedure Consumable Item") + validate_service_item(self.clinical_procedure_consumable_item) + + +def validate_service_item(item): + if frappe.db.get_value('Item', item, 'is_stock_item'): + frappe.throw(_('Configure a service Item for {0}').format(item)) @frappe.whitelist() def get_sms_text(doc): - sms_text = {} - doc = frappe.get_doc("Lab Test",doc) - #doc = json.loads(doc) - context = {"doc": doc, "alert": doc, "comments": None} - emailed = frappe.db.get_value("Healthcare Settings", None, "sms_emailed") - sms_text['emailed'] = frappe.render_template(emailed, context) - printed = frappe.db.get_value("Healthcare Settings", None, "sms_printed") - sms_text['printed'] = frappe.render_template(printed, context) - return sms_text + sms_text = {} + doc = frappe.get_doc('Lab Test', doc) + context = {'doc': doc, 'alert': doc, 'comments': None} + + emailed = frappe.db.get_value('Healthcare Settings', None, 'sms_emailed') + sms_text['emailed'] = frappe.render_template(emailed, context) + + printed = frappe.db.get_value('Healthcare Settings', None, 'sms_printed') + sms_text['printed'] = frappe.render_template(printed, context) + + return sms_text def send_registration_sms(doc): - if (frappe.db.get_value("Healthcare Settings", None, "reg_sms")=='1'): - if doc.mobile: - context = {"doc": doc, "alert": doc, "comments": None} - if doc.get("_comments"): - context["comments"] = json.loads(doc.get("_comments")) - messages = frappe.db.get_value("Healthcare Settings", None, "reg_msg") - messages = frappe.render_template(messages, context) - number = [doc.mobile] - send_sms(number,messages) - else: - frappe.msgprint(doc.name + " Has no mobile number to send registration SMS", alert=True) - + if frappe.db.get_single_value('Healthcare Settings', 'send_registration_msg'): + if doc.mobile: + context = {'doc': doc, 'alert': doc, 'comments': None} + if doc.get('_comments'): + context['comments'] = json.loads(doc.get('_comments')) + messages = frappe.db.get_single_value('Healthcare Settings', 'registration_msg') + messages = frappe.render_template(messages, context) + number = [doc.mobile] + send_sms(number,messages) + else: + frappe.msgprint(doc.name + ' has no mobile number to send registration SMS', alert=True) def get_receivable_account(company): - receivable_account = get_account(None, "receivable_account", "Healthcare Settings", company) - if receivable_account: - return receivable_account - return frappe.get_cached_value('Company', company, "default_receivable_account") + receivable_account = get_account(None, 'receivable_account', 'Healthcare Settings', company) + if receivable_account: + return receivable_account + + return frappe.get_cached_value('Company', company, 'default_receivable_account') def get_income_account(practitioner, company): - if(practitioner): - income_account = get_account("Healthcare Practitioner", None, practitioner, company) - if income_account: - return income_account - income_account = get_account(None, "income_account", "Healthcare Settings", company) - if income_account: - return income_account - return frappe.get_cached_value('Company', company, "default_income_account") + # check income account in Healthcare Practitioner + if practitioner: + income_account = get_account('Healthcare Practitioner', None, practitioner, company) + if income_account: + return income_account + + # else check income account in Healthcare Settings + income_account = get_account(None, 'income_account', 'Healthcare Settings', company) + if income_account: + return income_account + + # else return default income account of company + return frappe.get_cached_value('Company', company, 'default_income_account') def get_account(parent_type, parent_field, parent, company): - if(parent_type): - return frappe.db.get_value("Party Account", - {"parenttype": parent_type, "parent": parent, "company": company}, "account") - if(parent_field): - return frappe.db.get_value("Party Account", - {"parentfield": parent_field, "parent": parent, "company": company}, "account") + if parent_type: + return frappe.db.get_value('Party Account', + {'parenttype': parent_type, 'parent': parent, 'company': company}, 'account') -def validate_service_item(item, msg): - if frappe.db.get_value("Item", item, "is_stock_item") == 1: - frappe.throw(_(msg)) + if parent_field: + return frappe.db.get_value('Party Account', + {'parentfield': parent_field, 'parent': parent, 'company': company}, 'account') diff --git a/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py b/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py index f10725ed9b..e15324c55b 100644 --- a/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py +++ b/erpnext/healthcare/doctype/inpatient_record/test_inpatient_record.py @@ -8,11 +8,12 @@ import unittest from frappe.utils import now_datetime, today from frappe.utils.make_random import get_random from erpnext.healthcare.doctype.inpatient_record.inpatient_record import admit_patient, discharge_patient, schedule_discharge +from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_patient class TestInpatientRecord(unittest.TestCase): def test_admit_and_discharge(self): frappe.db.sql("""delete from `tabInpatient Record`""") - patient = get_patient() + patient = create_patient() # Schedule Admission ip_record = create_inpatient(patient) ip_record.save(ignore_permissions = True) @@ -41,7 +42,7 @@ class TestInpatientRecord(unittest.TestCase): def test_validate_overlap_admission(self): frappe.db.sql("""delete from `tabInpatient Record`""") - patient = get_patient() + patient = create_patient() ip_record = create_inpatient(patient) ip_record.save(ignore_permissions = True) @@ -75,17 +76,6 @@ def create_inpatient(patient): inpatient_record.scheduled_date = today() return inpatient_record -def get_patient(): - patient = get_random("Patient") - if not patient: - patient = frappe.new_doc("Patient") - patient.patient_name = "Test Patient" - patient.sex = "Male" - patient.save(ignore_permissions=True) - return patient.name - return patient - - def get_healthcare_service_unit(): service_unit = get_random("Healthcare Service Unit", filters={"inpatient_occupancy": 1}) if not service_unit: diff --git a/erpnext/healthcare/doctype/lab_prescription/lab_prescription.json b/erpnext/healthcare/doctype/lab_prescription/lab_prescription.json index d6691d4295..0720bb4eec 100644 --- a/erpnext/healthcare/doctype/lab_prescription/lab_prescription.json +++ b/erpnext/healthcare/doctype/lab_prescription/lab_prescription.json @@ -1,238 +1,78 @@ { - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 1, - "creation": "2016-09-16 16:53:06.882970", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 1, + "actions": [], + "allow_copy": 1, + "beta": 1, + "creation": "2016-09-16 16:53:06.882970", + "doctype": "DocType", + "document_type": "Document", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "lab_test_code", + "lab_test_name", + "invoiced", + "column_break_4", + "lab_test_comment", + "lab_test_created" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "lab_test_code", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Test Code", - "length": 0, - "no_copy": 0, - "options": "Lab Test Template", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "lab_test_code", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "in_list_view": 1, + "label": "Lab Test", + "options": "Lab Test Template", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "lab_test_code.lab_test_name", - "fieldname": "lab_test_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Test", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "lab_test_code.lab_test_name", + "fieldname": "lab_test_name", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Lab Test Name" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fieldname": "invoiced", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Invoiced", - "length": 0, - "no_copy": 1, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "invoiced", + "fieldtype": "Check", + "label": "Invoiced", + "no_copy": 1, + "read_only": 1, + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_4", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_4", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "lab_test_comment", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Comments", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "lab_test_comment", + "fieldtype": "Small Text", + "ignore_xss_filter": 1, + "in_list_view": 1, + "label": "Comments" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "lab_test_created", - "fieldtype": "Check", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Test Created", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "default": "0", + "fieldname": "lab_test_created", + "fieldtype": "Check", + "hidden": 1, + "label": "Test Created", + "no_copy": 1, + "print_hide": 1, + "report_hide": 1, + "search_index": 1 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2018-09-04 09:02:18.592637", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Lab Prescription", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + ], + "istable": 1, + "links": [], + "modified": "2020-02-26 17:03:00.255560", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Lab Prescription", + "owner": "Administrator", + "permissions": [], + "restrict_to_domain": "Healthcare", + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/healthcare/doctype/lab_test/lab_test.js b/erpnext/healthcare/doctype/lab_test/lab_test.js index b60e70fd76..5b3f4c705a 100644 --- a/erpnext/healthcare/doctype/lab_test/lab_test.js +++ b/erpnext/healthcare/doctype/lab_test/lab_test.js @@ -29,7 +29,7 @@ frappe.ui.form.on('Lab Test', { get_lab_test_prescribed(frm); }); } - if(frm.doc.docstatus==1 && frm.doc.status!='Approved' && frm.doc.status!='Rejected' && frappe.defaults.get_default("require_test_result_approval") && frappe.user.has_role("LabTest Approver")){ + if(frm.doc.docstatus==1 && frm.doc.status!='Approved' && frm.doc.status!='Rejected' && frappe.defaults.get_default("lab_test_approval_required") && frappe.user.has_role("LabTest Approver")){ frm.add_custom_button(__('Approve'), function() { status_update(1,frm); }); diff --git a/erpnext/healthcare/doctype/lab_test/lab_test.json b/erpnext/healthcare/doctype/lab_test/lab_test.json index 00e613a179..ccbc24b3fb 100644 --- a/erpnext/healthcare/doctype/lab_test/lab_test.json +++ b/erpnext/healthcare/doctype/lab_test/lab_test.json @@ -1,1597 +1,478 @@ { - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 0, - "autoname": "naming_series:", - "beta": 1, - "creation": "2016-03-29 17:34:47.509094", - "custom": 0, - "default_print_format": "", - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 0, + "actions": [], + "allow_copy": 1, + "allow_import": 1, + "autoname": "naming_series:", + "beta": 1, + "creation": "2016-03-29 17:34:47.509094", + "doctype": "DocType", + "document_type": "Document", + "engine": "InnoDB", + "field_order": [ + "inpatient_record", + "naming_series", + "invoiced", + "patient", + "patient_name", + "patient_age", + "patient_sex", + "practitioner", + "email", + "mobile", + "company", + "c_b", + "department", + "status", + "submitted_date", + "approved_date", + "sample", + "result_date", + "employee", + "employee_name", + "employee_designation", + "user", + "report_preference", + "sb_first", + "lab_test_name", + "column_break_26", + "template", + "lab_test_group", + "sb_normal", + "normal_test_items", + "sb_special", + "special_test_items", + "sb_sensitivity", + "sensitivity_test_items", + "sb_comments", + "lab_test_comment", + "sb_customresult", + "custom_result", + "email_sent", + "sms_sent", + "printed", + "normal_toggle", + "special_toggle", + "sensitivity_toggle", + "amended_from", + "prescription" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "patient.inpatient_record", - "fieldname": "inpatient_record", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Inpatient Record", - "length": 0, - "no_copy": 0, - "options": "Inpatient Record", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "patient.inpatient_record", + "fieldname": "inpatient_record", + "fieldtype": "Link", + "label": "Inpatient Record", + "options": "Inpatient Record", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "naming_series", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Series", - "length": 0, - "no_copy": 0, - "options": "LP-", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "naming_series", + "fieldtype": "Select", + "label": "Series", + "options": "LP-", + "print_hide": 1, + "report_hide": 1, + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fieldname": "invoiced", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Invoiced", - "length": 0, - "no_copy": 1, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "invoiced", + "fieldtype": "Check", + "label": "Invoiced", + "no_copy": 1, + "read_only": 1, + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "inpatient_record.patient", - "fieldname": "patient", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Patient", - "length": 0, - "no_copy": 0, - "options": "Patient", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 1, - "set_only_once": 1, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "inpatient_record.patient", + "fieldname": "patient", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Patient", + "options": "Patient", + "reqd": 1, + "search_index": 1, + "set_only_once": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "patient.patient_name", - "fieldname": "patient_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Patient Name", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "patient.patient_name", + "fieldname": "patient_name", + "fieldtype": "Data", + "label": "Patient Name", + "print_hide": 1, + "read_only": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "patient_age", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Age", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "patient_age", + "fieldtype": "Data", + "label": "Age", + "print_hide": 1, + "read_only": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "patient_sex", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Gender", - "length": 0, - "no_copy": 0, - "options": "\nMale\nFemale\nOther", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 1, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 - }, + "fieldname": "patient_sex", + "fieldtype": "Link", + "label": "Gender", + "options": "Gender", + "print_hide": 1, + "report_hide": 1, + "reqd": 1, + "set_only_once": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "practitioner", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Healthcare Practitioner", - "length": 0, - "no_copy": 0, - "options": "Healthcare Practitioner", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "practitioner", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "label": "Healthcare Practitioner", + "options": "Healthcare Practitioner", + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "email", - "fieldtype": "Data", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Email", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "email", + "fieldtype": "Data", + "hidden": 1, + "label": "Email", + "print_hide": 1, + "read_only": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "mobile", - "fieldtype": "Data", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Mobile", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "mobile", + "fieldtype": "Data", + "hidden": 1, + "label": "Mobile", + "print_hide": 1, + "read_only": 1, + "report_hide": 1, + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "company", - "fieldtype": "Link", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Company", - "length": 0, - "no_copy": 0, - "options": "Company", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "company", + "fieldtype": "Link", + "hidden": 1, + "label": "Company", + "options": "Company", + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "c_b", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "c_b", + "fieldtype": "Column Break", + "print_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "department", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Department", - "length": 0, - "no_copy": 0, - "options": "Medical Department", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "department", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "label": "Department", + "options": "Medical Department", + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "status", - "fieldtype": "Select", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Status", - "length": 0, - "no_copy": 0, - "options": "Draft\nCompleted\nApproved\nRejected\nCancelled", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "status", + "fieldtype": "Select", + "hidden": 1, + "label": "Status", + "options": "Draft\nCompleted\nApproved\nRejected\nCancelled", + "print_hide": 1, + "report_hide": 1, + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "submitted_date", - "fieldtype": "Datetime", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Submitted Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "submitted_date", + "fieldtype": "Datetime", + "hidden": 1, + "label": "Submitted Date", + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "approved_date", - "fieldtype": "Datetime", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Approved Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "approved_date", + "fieldtype": "Datetime", + "hidden": 1, + "label": "Approved Date", + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sample", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 1, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Sample ID", - "length": 0, - "no_copy": 0, - "options": "Sample Collection", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sample", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "in_filter": 1, + "label": "Sample ID", + "options": "Sample Collection", + "print_hide": 1, + "read_only": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fieldname": "result_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Result Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "result_date", + "fieldtype": "Date", + "label": "Result Date", + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "fieldname": "employee", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Lab Technician", - "length": 0, - "no_copy": 1, - "options": "Employee", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "employee", + "fieldtype": "Link", + "label": "Lab Technician", + "no_copy": 1, + "options": "Employee", + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "employee.employee_name", - "fieldname": "employee_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Technician Name", - "length": 0, - "no_copy": 1, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "employee.employee_name", + "fieldname": "employee_name", + "fieldtype": "Data", + "label": "Technician Name", + "no_copy": 1, + "print_hide": 1, + "read_only": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "employee.designation", - "fieldname": "employee_designation", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Designation", - "length": 0, - "no_copy": 1, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "employee.designation", + "fieldname": "employee_designation", + "fieldtype": "Data", + "label": "Designation", + "no_copy": 1, + "print_hide": 1, + "read_only": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "user", - "fieldtype": "Link", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "User", - "length": 0, - "no_copy": 1, - "options": "User", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "user", + "fieldtype": "Link", + "hidden": 1, + "label": "User", + "no_copy": 1, + "options": "User", + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "report_preference", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Report Preference", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "report_preference", + "fieldtype": "Data", + "label": "Report Preference", + "print_hide": 1, + "read_only": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sb_first", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sb_first", + "fieldtype": "Section Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "lab_test_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Test Name", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "lab_test_name", + "fieldtype": "Data", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Test Name", + "no_copy": 1, + "print_hide": 1, + "read_only": 1, + "report_hide": 1, + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_26", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_26", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "template", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Test Template", - "length": 0, - "no_copy": 0, - "options": "Lab Test Template", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 1, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 - }, + "fieldname": "template", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "label": "Test Template", + "options": "Lab Test Template", + "print_hide": 1, + "report_hide": 1, + "reqd": 1, + "set_only_once": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "lab_test_group", - "fieldtype": "Link", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Test Group", - "length": 0, - "no_copy": 0, - "options": "Item Group", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "lab_test_group", + "fieldtype": "Link", + "hidden": 1, + "label": "Test Group", + "options": "Item Group", + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sb_normal", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sb_normal", + "fieldtype": "Section Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "normal_test_items", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "options": "Normal Test Items", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "normal_test_items", + "fieldtype": "Table", + "options": "Normal Test Items" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sb_special", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sb_special", + "fieldtype": "Section Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "special_test_items", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "options": "Special Test Items", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "special_test_items", + "fieldtype": "Table", + "options": "Special Test Items", + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sb_sensitivity", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sb_sensitivity", + "fieldtype": "Section Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sensitivity_test_items", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "options": "Sensitivity Test Items", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sensitivity_test_items", + "fieldtype": "Table", + "options": "Sensitivity Test Items", + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sb_comments", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sb_comments", + "fieldtype": "Section Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "lab_test_comment", - "fieldtype": "Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Comments", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "lab_test_comment", + "fieldtype": "Text", + "ignore_xss_filter": 1, + "label": "Comments" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "columns": 0, - "fieldname": "sb_customresult", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Custom Result", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "collapsible": 1, + "fieldname": "sb_customresult", + "fieldtype": "Section Break", + "label": "Custom Result" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "custom_result", - "fieldtype": "Text Editor", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Custom Result", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "custom_result", + "fieldtype": "Text Editor", + "ignore_xss_filter": 1, + "label": "Custom Result" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fieldname": "email_sent", - "fieldtype": "Check", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "email_sent", + "fieldtype": "Check", + "hidden": 1, + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fieldname": "sms_sent", - "fieldtype": "Check", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "sms_sent", + "fieldtype": "Check", + "hidden": 1, + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fieldname": "printed", - "fieldtype": "Check", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "printed", + "fieldtype": "Check", + "hidden": 1, + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fieldname": "normal_toggle", - "fieldtype": "Check", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "normal_toggle", + "fieldtype": "Check", + "hidden": 1, + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fieldname": "special_toggle", - "fieldtype": "Check", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "special_toggle", + "fieldtype": "Check", + "hidden": 1, + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fieldname": "sensitivity_toggle", - "fieldtype": "Check", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "sensitivity_toggle", + "fieldtype": "Check", + "hidden": 1, + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "amended_from", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Amended From", - "length": 0, - "no_copy": 1, - "options": "Lab Test", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "amended_from", + "fieldtype": "Link", + "label": "Amended From", + "no_copy": 1, + "options": "Lab Test", + "print_hide": 1, + "read_only": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "prescription", - "fieldtype": "Link", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Prescription", - "length": 0, - "no_copy": 1, - "options": "Lab Prescription", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldname": "prescription", + "fieldtype": "Link", + "hidden": 1, + "label": "Prescription", + "no_copy": 1, + "options": "Lab Prescription", + "print_hide": 1, + "read_only": 1, + "report_hide": 1 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "icon": "", - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 1, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-09-04 10:19:33.422304", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Lab Test", - "name_case": "", - "owner": "Administrator", + ], + "is_submittable": 1, + "links": [], + "modified": "2020-03-23 19:37:06.617764", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Lab Test", + "owner": "Administrator", "permissions": [ { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 0, - "email": 1, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Laboratory User", - "set_user_permissions": 0, - "share": 1, - "submit": 1, + "amend": 1, + "cancel": 1, + "create": 1, + "email": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Laboratory User", + "share": 1, + "submit": 1, "write": 1 - }, + }, { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "LabTest Approver", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "LabTest Approver", + "share": 1, "write": 1 - }, + }, { - "amend": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Physician", + "share": 1, "write": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "search_fields": "patient,practitioner,lab_test_name,sample", - "show_name_in_global_search": 1, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "patient", - "track_changes": 1, - "track_seen": 1, - "track_views": 0 + ], + "restrict_to_domain": "Healthcare", + "search_fields": "patient,practitioner,lab_test_name,sample", + "show_name_in_global_search": 1, + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "patient", + "track_changes": 1, + "track_seen": 1 } \ No newline at end of file diff --git a/erpnext/healthcare/doctype/lab_test/lab_test.py b/erpnext/healthcare/doctype/lab_test/lab_test.py index 8609489615..4e4015d2f0 100644 --- a/erpnext/healthcare/doctype/lab_test/lab_test.py +++ b/erpnext/healthcare/doctype/lab_test/lab_test.py @@ -191,20 +191,24 @@ def create_specials(template, lab_test): special.template = template.name def create_sample_doc(template, patient, invoice): - if(template.sample): - sample_exist = frappe.db.exists({ + if template.sample: + sample_exists = frappe.db.exists({ "doctype": "Sample Collection", "patient": patient.name, "docstatus": 0, - "sample": template.sample}) - if sample_exist : - #Update Sample Collection by adding quantity - sample_collection = frappe.get_doc("Sample Collection",sample_exist[0][0]) - quantity = int(sample_collection.sample_quantity)+int(template.sample_quantity) - if(template.sample_collection_details): - sample_collection_details = sample_collection.sample_collection_details+"\n==============\n"+"Test :"+template.lab_test_name+"\n"+"Collection Detials:\n\t"+template.sample_collection_details - frappe.db.set_value("Sample Collection", sample_collection.name, "sample_collection_details",sample_collection_details) - frappe.db.set_value("Sample Collection", sample_collection.name, "sample_quantity",quantity) + "sample": template.sample + }) + if sample_exists: + # update Sample Collection by adding quantity + sample_collection = frappe.get_doc("Sample Collection", sample_exists[0][0]) + quantity = int(sample_collection.sample_qty) + int(template.sample_qty) + if template.sample_details: + sample_details = sample_collection.sample_details + "\n==============\n" + _("Test: ") + sample_details += (template.get("lab_test_name") or template.get("template")) + "\n" + sample_details += _("Collection Details: ") + "\n\t" + template.sample_details + + frappe.db.set_value("Sample Collection", sample_collection.name, "sample_details", sample_details) + frappe.db.set_value("Sample Collection", sample_collection.name, "sample_qty", quantity) else: #create Sample Collection for template, copy vals from Invoice @@ -216,15 +220,15 @@ def create_sample_doc(template, patient, invoice): sample_collection.patient_sex = patient.sex sample_collection.sample = template.sample sample_collection.sample_uom = template.sample_uom - sample_collection.sample_quantity = template.sample_quantity - if(template.sample_collection_details): - sample_collection.sample_collection_details = "Test :"+template.lab_test_name+"\n"+"Collection Detials:\n\t"+template.sample_collection_details + sample_collection.sample_qty = template.sample_qty + if(template.sample_details): + sample_collection.sample_details = "Test :" + (template.get("lab_test_name") or template.get("template")) +"\n"+"Collection Detials:\n\t"+template.sample_details sample_collection.save(ignore_permissions=True) return sample_collection def create_sample_collection(lab_test, template, patient, invoice): - if(frappe.db.get_value("Healthcare Settings", None, "require_sample_collection") == "1"): + if(frappe.db.get_value("Healthcare Settings", None, "create_sample_collection_for_lab_test") == "1"): sample_collection = create_sample_doc(template, patient, invoice) if(sample_collection): lab_test.sample = sample_collection.name @@ -290,10 +294,14 @@ def insert_lab_test_to_medical_record(doc): comment = "" if item.lab_test_comment: comment = str(item.lab_test_comment) - event = "" + table_row = item.lab_test_name + if item.lab_test_event: - event = item.lab_test_event - table_row = item.lab_test_name +" "+ event +" "+ item.result_value + table_row += " " + item.lab_test_event + + if item.result_value: + table_row += " " + item.result_value + if item.normal_range: table_row += " normal_range("+item.normal_range+")" table_row += " "+comment diff --git a/erpnext/healthcare/doctype/lab_test_sample/lab_test_sample.json b/erpnext/healthcare/doctype/lab_test_sample/lab_test_sample.json index 46c04c696e..2830038eaf 100644 --- a/erpnext/healthcare/doctype/lab_test_sample/lab_test_sample.json +++ b/erpnext/healthcare/doctype/lab_test_sample/lab_test_sample.json @@ -1,145 +1,68 @@ { - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:sample", - "beta": 1, - "creation": "2016-04-04 17:35:44.823951", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 0, + "actions": [], + "allow_copy": 1, + "allow_import": 1, + "allow_rename": 1, + "autoname": "field:sample", + "beta": 1, + "creation": "2016-04-04 17:35:44.823951", + "doctype": "DocType", + "document_type": "Setup", + "engine": "InnoDB", + "field_order": [ + "sample", + "sample_uom" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sample", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Sample", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "sample", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Sample", + "reqd": 1, + "unique": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "fieldname": "sample_uom", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "UOM", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 + "bold": 1, + "fieldname": "sample_uom", + "fieldtype": "Link", + "in_list_view": 1, + "label": "UOM", + "options": "Lab Test UOM" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2017-08-31 13:46:22.508908", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Lab Test Sample", - "name_case": "", - "owner": "Administrator", + ], + "links": [], + "modified": "2020-01-29 23:02:02.249839", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Lab Test Sample", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 1, - "delete": 0, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Healthcare Administrator", + "share": 1, "write": 1 - }, + }, { - "amend": 0, - "apply_user_permissions": 0, - "cancel": 0, - "create": 0, - "delete": 0, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Laboratory User", - "set_user_permissions": 0, - "share": 1, - "submit": 0, - "write": 0 + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Laboratory User", + "share": 1 } - ], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "sample", - "track_changes": 1, - "track_seen": 0 + ], + "quick_entry": 1, + "restrict_to_domain": "Healthcare", + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "sample", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/healthcare/doctype/lab_test_template/lab_test_template.json b/erpnext/healthcare/doctype/lab_test_template/lab_test_template.json index fcfecba576..a606bc4b1d 100644 --- a/erpnext/healthcare/doctype/lab_test_template/lab_test_template.json +++ b/erpnext/healthcare/doctype/lab_test_template/lab_test_template.json @@ -35,8 +35,8 @@ "sb_sample_collection", "sample", "sample_uom", - "sample_quantity", - "sample_collection_details", + "sample_qty", + "sample_details", "change_in_item" ], "fields": [ @@ -105,7 +105,7 @@ "description": "If unchecked, the item wont be appear in Sales Invoice, but can be used in group test creation. ", "fieldname": "is_billable", "fieldtype": "Check", - "label": "Is billable", + "label": "Is Billable", "search_index": 1 }, { @@ -114,7 +114,8 @@ "fieldname": "lab_test_rate", "fieldtype": "Currency", "in_list_view": 1, - "label": "Standard Selling Rate" + "label": "Rate", + "mandatory_depends_on": "eval:doc.is_billable == 1" }, { "depends_on": "eval:doc.lab_test_template_type == 'Single'", @@ -209,18 +210,6 @@ "label": "UOM", "read_only": 1 }, - { - "default": "0", - "fieldname": "sample_quantity", - "fieldtype": "Float", - "label": "Quantity" - }, - { - "fieldname": "sample_collection_details", - "fieldtype": "Text", - "ignore_xss_filter": 1, - "label": "Collection Details" - }, { "default": "0", "fieldname": "change_in_item", @@ -236,11 +225,23 @@ "fieldname": "disabled", "fieldtype": "Check", "label": "Disabled" + }, + { + "default": "0", + "fieldname": "sample_qty", + "fieldtype": "Float", + "label": "Quantity" + }, + { + "fieldname": "sample_details", + "fieldtype": "Text", + "ignore_xss_filter": 1, + "label": "Collection Details" } ], "links": [], - "modified": "2020-01-21 21:02:16.108347", - "modified_by": "ruchamahabal2@gmail.com", + "modified": "2020-03-25 16:53:01.740103", + "modified_by": "Administrator", "module": "Healthcare", "name": "Lab Test Template", "owner": "Administrator", diff --git a/erpnext/healthcare/doctype/lab_test_template/lab_test_template.py b/erpnext/healthcare/doctype/lab_test_template/lab_test_template.py index fd7ae801d9..6bbb4f1c3a 100644 --- a/erpnext/healthcare/doctype/lab_test_template/lab_test_template.py +++ b/erpnext/healthcare/doctype/lab_test_template/lab_test_template.py @@ -99,13 +99,10 @@ def create_item_from_template(doc): # get item price list to insert item price if doc.lab_test_rate != 0.0: price_list_name = frappe.db.get_value("Price List", {"selling": 1}) - if(doc.lab_test_rate): + if doc.lab_test_rate: make_item_price(item.name, price_list_name, doc.lab_test_rate) - item.standard_rate = doc.lab_test_rate else: make_item_price(item.name, price_list_name, 0.0) - item.standard_rate = 0.0 - item.save(ignore_permissions = True) # Set item in the template frappe.db.set_value("Lab Test Template", doc.name, "item", item.name) diff --git a/erpnext/healthcare/doctype/patient/patient.js b/erpnext/healthcare/doctype/patient/patient.js index 1a34fe8076..d5df9567ec 100644 --- a/erpnext/healthcare/doctype/patient/patient.js +++ b/erpnext/healthcare/doctype/patient/patient.js @@ -3,128 +3,77 @@ frappe.ui.form.on('Patient', { refresh: function (frm) { - frm.set_query("patient", "patient_relation", function () { + frm.set_query('patient', 'patient_relation', function () { return { filters: [ - ["Patient", "name", "!=", frm.doc.name] + ['Patient', 'name', '!=', frm.doc.name] ] }; }); - if (frappe.defaults.get_default("patient_master_name") != "Naming Series") { - frm.toggle_display("naming_series", false); + + if (frappe.defaults.get_default('patient_name_by') != 'Naming Series') { + frm.toggle_display('naming_series', false); } else { erpnext.toggle_naming_series(); } - if (frappe.defaults.get_default("collect_registration_fee") && frm.doc.disabled == 1) { + + if (frappe.defaults.get_default('collect_registration_fee') && frm.doc.status == 'Disabled') { frm.add_custom_button(__('Invoice Patient Registration'), function () { - btn_invoice_registration(frm); + invoice_registration(frm); }); } - if (frm.doc.patient_name && frappe.user.has_role("Physician")) { - frm.add_custom_button(__('Patient History'), function () { - frappe.route_options = { "patient": frm.doc.name }; - frappe.set_route("patient_history"); - },"View"); + + if (frm.doc.patient_name && frappe.user.has_role('Physician')) { + frm.add_custom_button(__('Patient History'), function() { + frappe.route_options = {'patient': frm.doc.name}; + frappe.set_route('patient_history'); + },'View'); } - if (!frm.doc.__islocal && (frappe.user.has_role("Nursing User") || frappe.user.has_role("Physician"))) { + + if (!frm.doc.__islocal && (frappe.user.has_role('Nursing User') || frappe.user.has_role('Physician'))) { frm.add_custom_button(__('Vital Signs'), function () { - btn_create_vital_signs(frm); - }, "Create"); + create_vital_signs(frm); + }, 'Create'); frm.add_custom_button(__('Medical Record'), function () { create_medical_record(frm); - }, "Create"); + }, 'Create'); frm.add_custom_button(__('Patient Encounter'), function () { - btn_create_encounter(frm); - }, "Create"); + create_encounter(frm); + }, 'Create'); } }, onload: function (frm) { if(!frm.doc.dob){ - $(frm.fields_dict['age_html'].wrapper).html(""); + $(frm.fields_dict['age_html'].wrapper).html(''); } if(frm.doc.dob){ - $(frm.fields_dict['age_html'].wrapper).html("AGE : " + get_age(frm.doc.dob)); + $(frm.fields_dict['age_html'].wrapper).html('AGE : ' + get_age(frm.doc.dob)); } } }); -frappe.ui.form.on("Patient", "dob", function(frm) { - if(frm.doc.dob) { - var today = new Date(); - var birthDate = new Date(frm.doc.dob); - if(today < birthDate){ - frappe.msgprint(__("Please select a valid Date")); - frappe.model.set_value(frm.doctype,frm.docname, "dob", ""); +frappe.ui.form.on('Patient', 'dob', function(frm) { + if (frm.doc.dob) { + let today = new Date(); + let birthDate = new Date(frm.doc.dob); + if (today < birthDate){ + frappe.msgprint(__('Please select a valid Date')); + frappe.model.set_value(frm.doctype,frm.docname, 'dob', ''); } - else{ - var age_str = get_age(frm.doc.dob); - $(frm.fields_dict['age_html'].wrapper).html("AGE : " + age_str); + else { + let age_str = get_age(frm.doc.dob); + $(frm.fields_dict['age_html'].wrapper).html('AGE : ' + age_str); } } else { - $(frm.fields_dict['age_html'].wrapper).html(""); + $(frm.fields_dict['age_html'].wrapper).html(''); } }); -var create_medical_record = function (frm) { - frappe.route_options = { - "patient": frm.doc.name, - "status": "Open", - "reference_doctype": "Patient Medical Record", - "reference_owner": frm.doc.owner - }; - frappe.new_doc("Patient Medical Record"); -}; - -var get_age = function (birth) { - var ageMS = Date.parse(Date()) - Date.parse(birth); - var age = new Date(); - age.setTime(ageMS); - var years = age.getFullYear() - 1970; - return years + " Year(s) " + age.getMonth() + " Month(s) " + age.getDate() + " Day(s)"; -}; - -var btn_create_vital_signs = function (frm) { - if (!frm.doc.name) { - frappe.throw(__("Please save the patient first")); - } - frappe.route_options = { - "patient": frm.doc.name, - }; - frappe.new_doc("Vital Signs"); -}; - -var btn_create_encounter = function (frm) { - if (!frm.doc.name) { - frappe.throw(__("Please save the patient first")); - } - frappe.route_options = { - "patient": frm.doc.name, - }; - frappe.new_doc("Patient Encounter"); -}; - -var btn_invoice_registration = function (frm) { - frappe.call({ - doc: frm.doc, - method: "invoice_patient_registration", - callback: function(data){ - if(!data.exc){ - if(data.message.invoice){ - /* frappe.show_alert(__('Sales Invoice {0} created', - ['' + data.message.invoice+ ''])); */ - frappe.set_route("Form", "Sales Invoice", data.message.invoice); - } - cur_frm.reload_doc(); - } - } - }); -}; - frappe.ui.form.on('Patient Relation', { patient_relation_add: function(frm){ frm.fields_dict['patient_relation'].grid.get_field('patient').get_query = function(doc){ - var patient_list = []; + let patient_list = []; if(!doc.__islocal) patient_list.push(doc.name); $.each(doc.patient_relation, function(idx, val){ if (val.patient) patient_list.push(val.patient); @@ -133,3 +82,56 @@ frappe.ui.form.on('Patient Relation', { }; } }); + +let create_medical_record = function (frm) { + frappe.route_options = { + 'patient': frm.doc.name, + 'status': 'Open', + 'reference_doctype': 'Patient Medical Record', + 'reference_owner': frm.doc.owner + }; + frappe.new_doc('Patient Medical Record'); +}; + +let get_age = function (birth) { + let ageMS = Date.parse(Date()) - Date.parse(birth); + let age = new Date(); + age.setTime(ageMS); + let years = age.getFullYear() - 1970; + return years + ' Year(s) ' + age.getMonth() + ' Month(s) ' + age.getDate() + ' Day(s)'; +}; + +let create_vital_signs = function (frm) { + if (!frm.doc.name) { + frappe.throw(__('Please save the patient first')); + } + frappe.route_options = { + 'patient': frm.doc.name, + }; + frappe.new_doc('Vital Signs'); +}; + +let create_encounter = function (frm) { + if (!frm.doc.name) { + frappe.throw(__('Please save the patient first')); + } + frappe.route_options = { + 'patient': frm.doc.name, + }; + frappe.new_doc('Patient Encounter'); +}; + +let invoice_registration = function (frm) { + frappe.call({ + doc: frm.doc, + method: 'invoice_patient_registration', + callback: function(data) { + if (!data.exc) { + if (data.message.invoice) { + frappe.set_route('Form', 'Sales Invoice', data.message.invoice); + } + cur_frm.reload_doc(); + } + } + }); +}; diff --git a/erpnext/healthcare/doctype/patient/patient.json b/erpnext/healthcare/doctype/patient/patient.json index 0136f72f5b..4258e4011d 100644 --- a/erpnext/healthcare/doctype/patient/patient.json +++ b/erpnext/healthcare/doctype/patient/patient.json @@ -1,4 +1,5 @@ { + "actions": [], "allow_copy": 1, "allow_import": 1, "allow_rename": 1, @@ -11,23 +12,29 @@ "engine": "InnoDB", "field_order": [ "basic_info", - "inpatient_status", - "inpatient_record", "naming_series", + "first_name", + "middle_name", + "last_name", "patient_name", "sex", "blood_group", "dob", "age_html", - "status", "image", "column_break_14", + "status", + "inpatient_status", + "inpatient_record", "customer", - "report_preference", "mobile", "email", "phone", - "disabled", + "report_preference", + "personal_and_social_history", + "occupation", + "column_break_25", + "marital_status", "sb_relation", "patient_relation", "allergy_medical_and_surgical_history", @@ -36,10 +43,6 @@ "column_break_20", "medical_history", "surgical_history", - "personal_and_social_history", - "occupation", - "column_break_25", - "marital_status", "risk_factors", "tobacco_past_use", "tobacco_current_use", @@ -78,28 +81,28 @@ { "fieldname": "naming_series", "fieldtype": "Select", - "label": "Patient ID", + "label": "Series", "options": "HLC-PAT-.YYYY.-", "print_hide": 1, - "report_hide": 1 + "report_hide": 1, + "set_only_once": 1 }, { "bold": 1, "fieldname": "patient_name", "fieldtype": "Data", - "in_filter": 1, + "in_global_search": 1, + "in_list_view": 1, "in_standard_filter": 1, "label": "Full Name", - "no_copy": 1, - "oldfieldtype": "Data", - "reqd": 1, + "read_only": 1, "search_index": 1 }, { "fieldname": "sex", - "fieldtype": "Select", + "fieldtype": "Link", "label": "Gender", - "options": "\nMale\nFemale\nOther", + "options": "Gender", "reqd": 1 }, { @@ -125,15 +128,15 @@ "report_hide": 1 }, { - "default": "Active", "fieldname": "status", "fieldtype": "Select", - "hidden": 1, + "in_filter": 1, + "in_list_view": 1, "label": "Status", "no_copy": 1, - "options": "Active\nDormant\nOpen", + "options": "Active\nDisabled", "print_hide": 1, - "report_hide": 1 + "read_only": 1 }, { "fieldname": "image", @@ -149,12 +152,12 @@ "fieldtype": "Column Break" }, { + "description": "If \"Link Customer to Patient\" is checked in Healthcare Settings and an existing Customer is not selected then, a Customer will be created for this Patient for recording transactions in Accounts module.", "fieldname": "customer", "fieldtype": "Link", "ignore_user_permissions": 1, "label": "Customer", - "options": "Customer", - "set_only_once": 1 + "options": "Customer" }, { "fieldname": "report_preference", @@ -183,19 +186,8 @@ "fieldname": "phone", "fieldtype": "Data", "in_filter": 1, - "in_list_view": 1, "label": "Phone" }, - { - "default": "0", - "fieldname": "disabled", - "fieldtype": "Check", - "hidden": 1, - "label": "Disabled", - "no_copy": 1, - "print_hide": 1, - "report_hide": 1 - }, { "collapsible": 1, "fieldname": "sb_relation", @@ -276,25 +268,25 @@ "fieldname": "tobacco_past_use", "fieldtype": "Data", "ignore_xss_filter": 1, - "label": "Tobacco Past Use" + "label": "Tobacco Consumption Habbits (Past)" }, { "fieldname": "tobacco_current_use", "fieldtype": "Data", "ignore_xss_filter": 1, - "label": "Tobacco Current Use" + "label": "Tobacco Consumption Habbits (Present)" }, { "fieldname": "alcohol_past_use", "fieldtype": "Data", "ignore_xss_filter": 1, - "label": "Alcohol Past Use" + "label": "Alcohol Consumption Habbits (Past)" }, { "fieldname": "alcohol_current_use", "fieldtype": "Data", "ignore_user_permissions": 1, - "label": "Alcohol Current Use" + "label": "Alcohol Consumption Habbits (Present)" }, { "fieldname": "column_break_32", @@ -342,12 +334,30 @@ "label": "Default Currency", "options": "Currency", "print_hide": 1 + }, + { + "fieldname": "last_name", + "fieldtype": "Data", + "label": "Last Name" + }, + { + "fieldname": "first_name", + "fieldtype": "Data", + "label": "First Name", + "oldfieldtype": "Data", + "reqd": 1 + }, + { + "fieldname": "middle_name", + "fieldtype": "Data", + "label": "Middle Name (optional)" } ], "icon": "fa fa-user", "image_field": "image", + "links": [], "max_attachments": 50, - "modified": "2019-09-25 23:30:49.905893", + "modified": "2020-04-06 12:55:30.807744", "modified_by": "Administrator", "module": "Healthcare", "name": "Patient", diff --git a/erpnext/healthcare/doctype/patient/patient.py b/erpnext/healthcare/doctype/patient/patient.py index e3eea96f85..e304a0bbc3 100644 --- a/erpnext/healthcare/doctype/patient/patient.py +++ b/erpnext/healthcare/doctype/patient/patient.py @@ -6,46 +6,57 @@ from __future__ import unicode_literals import frappe from frappe import _ from frappe.model.document import Document -from frappe.utils import cint, cstr, getdate, flt +from frappe.utils import cint, cstr, getdate import dateutil from frappe.model.naming import set_name_by_naming_series -from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_receivable_account,get_income_account,send_registration_sms +from frappe.utils.nestedset import get_root_of +from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_receivable_account, get_income_account, send_registration_sms class Patient(Document): - def after_insert(self): - if(frappe.db.get_value("Healthcare Settings", None, "manage_customer") == '1' and not self.customer): - create_customer(self) - if(frappe.db.get_value("Healthcare Settings", None, "collect_registration_fee") == '1'): - frappe.db.set_value("Patient", self.name, "disabled", 1) - else: - send_registration_sms(self) - self.reload() - - def on_update(self): + def validate(self): + self.set_full_name() self.add_as_website_user() + def after_insert(self): + self.add_as_website_user() + self.reload() + if frappe.db.get_single_value('Healthcare Settings', 'link_customer_to_patient') and not self.customer: + create_customer(self) + if frappe.db.get_single_value('Healthcare Settings', 'collect_registration_fee'): + frappe.db.set_value('Patient', self.name, 'status', 'Disabled') + else: + send_registration_sms(self) + + def set_full_name(self): + if self.last_name: + self.patient_name = ' '.join(filter(None, [self.first_name, self.last_name])) + else: + self.patient_name = self.first_name + def add_as_website_user(self): - if(self.email): - if not frappe.db.exists ("User", self.email): + if self.email: + if not frappe.db.exists ('User', self.email): user = frappe.get_doc({ - "doctype": "User", - "first_name": self.patient_name, - "email": self.email, - "user_type": "Website User" + 'doctype': 'User', + 'first_name': self.first_name, + 'last_name': self.last_name, + 'email': self.email, + 'user_type': 'Website User' }) user.flags.ignore_permissions = True - user.add_roles("Patient") + user.add_roles('Patient') def autoname(self): - patient_master_name = frappe.defaults.get_global_default('patient_master_name') - if patient_master_name == 'Patient Name': + patient_name_by = frappe.db.get_single_value('Healthcare Settings', 'patient_name_by') + if patient_name_by == 'Patient Name': self.name = self.get_patient_name() else: set_name_by_naming_series(self) def get_patient_name(self): + self.set_full_name() name = self.patient_name - if frappe.db.get_value("Patient", name): + if frappe.db.get_value('Patient', name): count = frappe.db.sql("""select ifnull(MAX(CAST(SUBSTRING_INDEX(name, ' ', -1) AS UNSIGNED)), 0) from tabPatient where name like %s""", "%{0} - %".format(name), as_list=1)[0][0] count = cint(count) + 1 @@ -54,56 +65,62 @@ class Patient(Document): return name def get_age(self): - age_str = "" + age_str = '' if self.dob: - born = getdate(self.dob) - age = dateutil.relativedelta.relativedelta(getdate(), born) - age_str = str(age.years) + " year(s) " + str(age.months) + " month(s) " + str(age.days) + " day(s)" + dob = getdate(self.dob) + age = dateutil.relativedelta.relativedelta(getdate(), dob) + age_str = str(age.years) + ' year(s) ' + str(age.months) + ' month(s) ' + str(age.days) + ' day(s)' return age_str def invoice_patient_registration(self): - frappe.db.set_value("Patient", self.name, "disabled", 0) - send_registration_sms(self) - if(flt(frappe.get_value("Healthcare Settings", None, "registration_fee"))>0): + if frappe.db.get_single_value('Healthcare Settings', 'registration_fee'): company = frappe.defaults.get_user_default('company') if not company: - company = frappe.db.get_value("Global Defaults", None, "default_company") + company = frappe.db.get_single_value('Global Defaults', 'default_company') + sales_invoice = make_invoice(self.name, company) sales_invoice.save(ignore_permissions=True) + frappe.db.set_value('Patient', self.name, 'status', 'Active') + send_registration_sms(self) + return {'invoice': sales_invoice.name} def create_customer(doc): - customer_group = frappe.get_value("Selling Settings", None, "customer_group") - territory = frappe.get_value("Selling Settings", None, "territory") + customer_group = frappe.db.get_single_value('Selling Settings', 'customer_group') + territory = frappe.db.get_single_value('Selling Settings', 'territory') if not (customer_group and territory): - customer_group = "Commercial" - territory = "Rest Of The World" - frappe.msgprint(_("Please set default customer group and territory in Selling Settings"), alert=True) - customer = frappe.get_doc({"doctype": "Customer", - "customer_name": doc.patient_name, - "customer_group": customer_group, - "territory" : territory, - "customer_type": "Individual" - }).insert(ignore_permissions=True) - frappe.db.set_value("Patient", doc.name, "customer", customer.name) - frappe.msgprint(_("Customer {0} is created.").format(customer.name), alert=True) + customer_group = get_root_of('Customer Group') + territory = get_root_of('Territory') + frappe.msgprint(_('Please set default customer group and territory in Selling Settings'), alert=True) + + customer = frappe.get_doc({ + 'doctype': 'Customer', + 'customer_name': doc.patient_name, + 'customer_group': customer_group, + 'territory' : territory, + 'customer_type': 'Individual' + }).insert(ignore_permissions=True, ignore_mandatory=True) + + frappe.db.set_value('Patient', doc.name, 'customer', customer.name) + frappe.msgprint(_('Customer {0} is created.').format(customer.name), alert=True) def make_invoice(patient, company): - sales_invoice = frappe.new_doc("Sales Invoice") - sales_invoice.customer = frappe.get_value("Patient", patient, "customer") + uom = frappe.db.exists('UOM', 'Nos') or frappe.db.get_single_value('Stock Settings', 'stock_uom') + sales_invoice = frappe.new_doc('Sales Invoice') + sales_invoice.customer = frappe.db.get_value('Patient', patient, 'customer') sales_invoice.due_date = getdate() sales_invoice.company = company - sales_invoice.is_pos = '0' + sales_invoice.is_pos = 0 sales_invoice.debit_to = get_receivable_account(company) - item_line = sales_invoice.append("items") - item_line.item_name = "Registeration Fee" - item_line.description = "Registeration Fee" + item_line = sales_invoice.append('items') + item_line.item_name = 'Registeration Fee' + item_line.description = 'Registeration Fee' item_line.qty = 1 - item_line.uom = "Nos" + item_line.uom = uom item_line.conversion_factor = 1 item_line.income_account = get_income_account(None, company) - item_line.rate = frappe.get_value("Healthcare Settings", None, "registration_fee") + item_line.rate = frappe.db.get_single_value('Healthcare Settings', 'registration_fee') item_line.amount = item_line.rate sales_invoice.set_missing_values() return sales_invoice @@ -112,7 +129,7 @@ def make_invoice(patient, company): def get_patient_detail(patient): patient_dict = frappe.db.sql("""select * from tabPatient where name=%s""", (patient), as_dict=1) if not patient_dict: - frappe.throw(_("Patient not found")) + frappe.throw(_('Patient not found')) vital_sign = frappe.db.sql("""select * from `tabVital Signs` where patient=%s order by signs_date desc limit 1""", (patient), as_dict=1) diff --git a/erpnext/healthcare/doctype/patient/test_patient.py b/erpnext/healthcare/doctype/patient/test_patient.py index aebaa6b989..9274b6f5e8 100644 --- a/erpnext/healthcare/doctype/patient/test_patient.py +++ b/erpnext/healthcare/doctype/patient/test_patient.py @@ -4,8 +4,31 @@ from __future__ import unicode_literals import unittest - -# test_records = frappe.get_test_records('Patient') +import frappe +from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_patient class TestPatient(unittest.TestCase): - pass + def test_customer_created(self): + frappe.db.sql("""delete from `tabPatient`""") + frappe.db.set_value('Healthcare Settings', None, 'link_customer_to_patient', 1) + patient = create_patient() + self.assertTrue(frappe.db.get_value('Patient', patient, 'customer')) + + def test_patient_registration(self): + frappe.db.sql("""delete from `tabPatient`""") + settings = frappe.get_single('Healthcare Settings') + settings.collect_registration_fee = 1 + settings.registration_fee = 500 + settings.save() + + patient = create_patient() + patient = frappe.get_doc('Patient', patient) + self.assertEqual(patient.status, 'Disabled') + + # check sales invoice and patient status + result = patient.invoice_patient_registration() + self.assertTrue(frappe.db.exists('Sales Invoice', result.get('invoice'))) + self.assertTrue(patient.status, 'Active') + + settings.collect_registration_fee = 0 + settings.save() diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js index 858145eef3..efa6b249b3 100644 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js +++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js @@ -1,6 +1,6 @@ // Copyright (c) 2016, ESS LLP and contributors // For license information, please see license.txt -frappe.provide("erpnext.queries"); +frappe.provide('erpnext.queries'); frappe.ui.form.on('Patient Appointment', { setup: function(frm) { frm.custom_make_buttons = { @@ -8,151 +8,188 @@ frappe.ui.form.on('Patient Appointment', { 'Patient Encounter': 'Patient Encounter' }; }, + + onload: function(frm) { + if (frm.is_new()) { + frm.set_value('appointment_time', null); + frm.disable_save(); + } + }, + refresh: function(frm) { - frm.set_query("patient", function () { + frm.set_query('patient', function () { return { - filters: {"disabled": 0} + filters: {'status': 'Active'} }; }); - frm.set_query("practitioner", function() { + frm.set_query('practitioner', function() { return { filters: { 'department': frm.doc.department } }; }); - frm.set_query("service_unit", function(){ + frm.set_query('service_unit', function(){ return { filters: { - "is_group": false, - "allow_appointments": true + 'is_group': 0, + 'allow_appointments': 1 } }; }); - if(frm.doc.patient){ + + if (frm.is_new()) { + frm.page.set_primary_action(__('Check Availability'), function() { + if (!frm.doc.patient) { + frappe.msgprint({ + title: __('Not Allowed'), + message: __('Please select Patient first'), + indicator: 'red' + }); + } else { + frappe.call({ + method: 'erpnext.healthcare.doctype.patient_appointment.patient_appointment.check_payment_fields_reqd', + args: {'patient': frm.doc.patient}, + callback: function(data) { + if (data.message == true) { + if (frm.doc.mode_of_payment && frm.doc.paid_amount) { + check_and_set_availability(frm); + } + if (!frm.doc.mode_of_payment) { + frappe.msgprint({ + title: __('Not Allowed'), + message: __('Please select a Mode of Payment first'), + indicator: 'red' + }); + } + if (!frm.doc.paid_amount) { + frappe.msgprint({ + title: __('Not Allowed'), + message: __('Please set the Paid Amount first'), + indicator: 'red' + }); + } + } else { + check_and_set_availability(frm); + } + } + }); + } + }); + } else { + frm.page.set_primary_action(__('Save'), () => frm.save()); + } + + if (frm.doc.patient) { frm.add_custom_button(__('Patient History'), function() { - frappe.route_options = {"patient": frm.doc.patient}; - frappe.set_route("patient_history"); - },__("View")); + frappe.route_options = {'patient': frm.doc.patient}; + frappe.set_route('patient_history'); + }, __('View')); } - if(frm.doc.status == "Open"){ + + if (frm.doc.status == 'Open' || (frm.doc.status == 'Scheduled' && !frm.doc.__islocal)) { frm.add_custom_button(__('Cancel'), function() { - btn_update_status(frm, "Cancelled"); + update_status(frm, 'Cancelled'); }); frm.add_custom_button(__('Reschedule'), function() { check_and_set_availability(frm); }); - if(frm.doc.procedure_template){ - frm.add_custom_button(__("Procedure"),function(){ - btn_create_procedure(frm); - },"Create"); - } - else{ - frm.add_custom_button(__("Patient Encounter"),function(){ - btn_create_encounter(frm); - },"Create"); + + if (frm.doc.procedure_template) { + frm.add_custom_button(__('Clinical Procedure'), function(){ + frappe.model.open_mapped_doc({ + method: 'erpnext.healthcare.doctype.clinical_procedure.clinical_procedure.make_procedure', + frm: frm, + }); + }, __('Create')); + } else { + frm.add_custom_button(__('Patient Encounter'), function() { + frappe.model.open_mapped_doc({ + method: 'erpnext.healthcare.doctype.patient_appointment.patient_appointment.make_encounter', + frm: frm, + }); + }, __('Create')); } frm.add_custom_button(__('Vital Signs'), function() { - btn_create_vital_signs(frm); - },"Create"); + create_vital_signs(frm); + }, __('Create')); } - if(frm.doc.status == "Scheduled" && !frm.doc.__islocal){ - frm.add_custom_button(__('Cancel'), function() { - btn_update_status(frm, "Cancelled"); - }); - frm.add_custom_button(__('Reschedule'), function() { - check_and_set_availability(frm); - }); - if(frm.doc.procedure_template){ - frm.add_custom_button(__("Procedure"),function(){ - btn_create_procedure(frm); - },"Create"); - } - else{ - frm.add_custom_button(__("Patient Encounter"),function(){ - btn_create_encounter(frm); - },"Create"); - } + }, - frm.add_custom_button(__('Vital Signs'), function() { - btn_create_vital_signs(frm); - },"Create"); + patient: function(frm) { + if (frm.doc.patient) { + frm.trigger('toggle_payment_fields'); } - if(frm.doc.status == "Pending"){ - frm.add_custom_button(__('Set Open'), function() { - btn_update_status(frm, "Open"); - }); - frm.add_custom_button(__('Cancel'), function() { - btn_update_status(frm, "Cancelled"); - }); - } - frm.set_df_property("get_procedure_from_encounter", "read_only", frm.doc.__islocal ? 0 : 1); - frappe.db.get_value('Healthcare Settings', {name: 'Healthcare Settings'}, 'manage_appointment_invoice_automatically', (r) => { - if(r.manage_appointment_invoice_automatically == 1){ - frm.set_df_property("mode_of_payment", "hidden", 0); - frm.set_df_property("paid_amount", "hidden", 0); - frm.set_df_property("mode_of_payment", "reqd", 1); - frm.set_df_property("paid_amount", "reqd", 1); - } - else{ - frm.set_df_property("mode_of_payment", "hidden", 1); - frm.set_df_property("paid_amount", "hidden", 1); - frm.set_df_property("mode_of_payment", "reqd", 0); - frm.set_df_property("paid_amount", "reqd", 0); + }, + + get_procedure_from_encounter: function(frm) { + get_prescribed_procedure(frm); + }, + + toggle_payment_fields: function(frm) { + frappe.call({ + method: 'erpnext.healthcare.doctype.patient_appointment.patient_appointment.check_payment_fields_reqd', + args: {'patient': frm.doc.patient}, + callback: function(data) { + if (data.message.fee_validity) { + // if fee validity exists and automated appointment invoicing is enabled, + // show payment fields as non-mandatory + frm.toggle_display('mode_of_payment', 0); + frm.toggle_display('paid_amount', 0); + frm.toggle_reqd('mode_of_payment', 0); + frm.toggle_reqd('paid_amount', 0); + } else { + // if automated appointment invoicing is disabled, hide fields + frm.toggle_display('mode_of_payment', data.message ? 1 : 0); + frm.toggle_display('paid_amount', data.message ? 1 : 0); + frm.toggle_reqd('mode_of_payment', data.message ? 1 : 0); + frm.toggle_reqd('paid_amount', data.message ? 1 :0); + } } }); - }, - check_availability: function(frm) { - check_and_set_availability(frm); - }, - onload:function(frm){ - if(frm.is_new()) { - frm.set_value("appointment_time", null); - frm.disable_save(); - } - }, - get_procedure_from_encounter: function(frm) { - get_procedure_prescribed(frm); } }); -var check_and_set_availability = function(frm) { - var selected_slot = null; - var service_unit = null; - var duration = null; +let check_and_set_availability = function(frm) { + let selected_slot = null; + let service_unit = null; + let duration = null; show_availability(); function show_empty_state(practitioner, appointment_date) { frappe.msgprint({ title: __('Not Available'), - message: __("Healthcare Practitioner {0} not available on {1}", [practitioner.bold(), appointment_date.bold()]), + message: __('Healthcare Practitioner {0} not available on {1}', [practitioner.bold(), appointment_date.bold()]), indicator: 'red' }); } function show_availability() { let selected_practitioner = ''; - var d = new frappe.ui.Dialog({ - title: __("Available slots"), + let d = new frappe.ui.Dialog({ + title: __('Available slots'), fields: [ - { fieldtype: 'Link', options: 'Medical Department', reqd:1, fieldname: 'department', label: 'Medical Department'}, + { fieldtype: 'Link', options: 'Medical Department', reqd: 1, fieldname: 'department', label: 'Medical Department'}, { fieldtype: 'Column Break'}, - { fieldtype: 'Link', options: 'Healthcare Practitioner', reqd:1, fieldname: 'practitioner', label: 'Healthcare Practitioner'}, + { fieldtype: 'Link', options: 'Healthcare Practitioner', reqd: 1, fieldname: 'practitioner', label: 'Healthcare Practitioner'}, { fieldtype: 'Column Break'}, - { fieldtype: 'Date', reqd:1, fieldname: 'appointment_date', label: 'Date'}, + { fieldtype: 'Date', reqd: 1, fieldname: 'appointment_date', label: 'Date'}, { fieldtype: 'Section Break'}, { fieldtype: 'HTML', fieldname: 'available_slots'} + ], - primary_action_label: __("Book"), + primary_action_label: __('Book'), primary_action: function() { frm.set_value('appointment_time', selected_slot); - frm.set_value('service_unit', service_unit || ''); frm.set_value('duration', duration); frm.set_value('practitioner', d.get_value('practitioner')); frm.set_value('department', d.get_value('department')); frm.set_value('appointment_date', d.get_value('appointment_date')); + if (service_unit) { + frm.set_value('service_unit', service_unit); + } d.hide(); frm.enable_save(); frm.save(); @@ -167,16 +204,16 @@ var check_and_set_availability = function(frm) { 'appointment_date': frm.doc.appointment_date }); - d.fields_dict["department"].df.onchange = () => { + d.fields_dict['department'].df.onchange = () => { d.set_values({ 'practitioner': '' }); - var department = d.get_value('department'); - if(department){ + let department = d.get_value('department'); + if (department) { d.fields_dict.practitioner.get_query = function() { return { filters: { - "department": department + 'department': department } }; }; @@ -188,13 +225,13 @@ var check_and_set_availability = function(frm) { // Field Change Handler - var fd = d.fields_dict; + let fd = d.fields_dict; - d.fields_dict["appointment_date"].df.onchange = () => { + d.fields_dict['appointment_date'].df.onchange = () => { show_slots(d, fd); }; - d.fields_dict["practitioner"].df.onchange = () => { - if(d.get_value('practitioner') && d.get_value('practitioner') != selected_practitioner){ + d.fields_dict['practitioner'].df.onchange = () => { + if (d.get_value('practitioner') && d.get_value('practitioner') != selected_practitioner) { selected_practitioner = d.get_value('practitioner'); show_slots(d, fd); } @@ -203,8 +240,8 @@ var check_and_set_availability = function(frm) { } function show_slots(d, fd) { - if (d.get_value('appointment_date') && d.get_value('practitioner')){ - fd.available_slots.html(""); + if (d.get_value('appointment_date') && d.get_value('practitioner')) { + fd.available_slots.html(''); frappe.call({ method: 'erpnext.healthcare.doctype.patient_appointment.patient_appointment.get_availability_data', args: { @@ -212,13 +249,13 @@ var check_and_set_availability = function(frm) { date: d.get_value('appointment_date') }, callback: (r) => { - var data = r.message; - if(data.slot_details.length > 0) { - var $wrapper = d.fields_dict.available_slots.$wrapper; + let data = r.message; + if (data.slot_details.length > 0) { + let $wrapper = d.fields_dict.available_slots.$wrapper; // make buttons for each slot - var slot_details = data.slot_details; - var slot_html = ""; + let slot_details = data.slot_details; + let slot_html = ''; for (let i = 0; i < slot_details.length; i++) { slot_html = slot_html + ``; slot_html = slot_html + `
` + slot_details[i].avail_slot.map(slot => { @@ -232,14 +269,14 @@ var check_and_set_availability = function(frm) { let booked_moment = moment(booked.appointment_time, 'HH:mm:ss'); let end_time = booked_moment.clone().add(booked.duration, 'minutes'); // Deal with 0 duration appointments - if(booked_moment.isSame(slot_start_time) || booked_moment.isBetween(slot_start_time, slot_to_time)){ + if (booked_moment.isSame(slot_start_time) || booked_moment.isBetween(slot_start_time, slot_to_time)) { if(booked.duration == 0){ disabled = 'disabled="disabled"'; return false; } } // Check for overlaps considering appointment duration - if(slot_start_time.isBefore(end_time) && slot_to_time.isAfter(booked_moment)){ + if (slot_start_time.isBefore(end_time) && slot_to_time.isAfter(booked_moment)) { // There is an overlap disabled = 'disabled="disabled"'; return false; @@ -263,7 +300,7 @@ var check_and_set_availability = function(frm) { // blue button when clicked $wrapper.on('click', 'button', function() { - var $btn = $(this); + let $btn = $(this); $wrapper.find('button').removeClass('btn-primary'); $btn.addClass('btn-primary'); selected_slot = $btn.attr('data-name'); @@ -273,48 +310,57 @@ var check_and_set_availability = function(frm) { d.get_primary_btn().attr('disabled', null); }); - }else { - // fd.available_slots.html("Please select a valid date.".bold()) + } else { + // fd.available_slots.html('Please select a valid date.'.bold()) show_empty_state(d.get_value('practitioner'), d.get_value('appointment_date')); } }, freeze: true, - freeze_message: __("Fetching records......") + freeze_message: __('Fetching records......') }); - }else{ - fd.available_slots.html("Appointment date and Healthcare Practitioner are Mandatory".bold()); + } else { + fd.available_slots.html(__('Appointment date and Healthcare Practitioner are Mandatory').bold()); } } }; -var get_procedure_prescribed = function(frm){ - if(frm.doc.patient){ +let get_prescribed_procedure = function(frm) { + if (frm.doc.patient) { frappe.call({ - method:"erpnext.healthcare.doctype.patient_appointment.patient_appointment.get_procedure_prescribed", + method: 'erpnext.healthcare.doctype.patient_appointment.patient_appointment.get_procedure_prescribed', args: {patient: frm.doc.patient}, - callback: function(r){ - show_procedure_templates(frm, r.message); + callback: function(r) { + if (r.message && r.message.length) { + show_procedure_templates(frm, r.message); + } else { + frappe.msgprint({ + title: __('Not Found'), + message: __('No Prescribed Procedures found for the selected Patient') + }); + } } }); - } - else{ - frappe.msgprint(__("Please select Patient to get prescribed procedure")); + } else { + frappe.msgprint({ + title: __('Not Allowed'), + message: __('Please select a Patient first') + }); } }; -var show_procedure_templates = function(frm, result){ - var d = new frappe.ui.Dialog({ - title: __("Prescribed Procedures"), +let show_procedure_templates = function(frm, result){ + let d = new frappe.ui.Dialog({ + title: __('Prescribed Procedures'), fields: [ { - fieldtype: "HTML", fieldname: "procedure_template" + fieldtype: 'HTML', fieldname: 'procedure_template' } ] }); - var html_field = d.fields_dict.procedure_template.$wrapper; + let html_field = d.fields_dict.procedure_template.$wrapper; html_field.empty(); - $.each(result, function(x, y){ - var row = $(repl('
\ + $.each(result, function(x, y) { + let row = $(repl('
\
%(encounter)s
%(consulting_practitioner)s
%(encounter_date)s
\
%(procedure_template)s
%(practitioner)s
%(date)s
\
\ @@ -326,76 +372,47 @@ var show_procedure_templates = function(frm, result){ encounter:y[2], consulting_practitioner:y[3], encounter_date:y[4], practitioner:y[5]? y[5]:'', date: y[6]? y[6]:'', department: y[7]? y[7]:''})).appendTo(html_field); row.find("a").click(function() { - frm.doc.procedure_template = $(this).attr("data-procedure-template"); - frm.doc.procedure_prescription = $(this).attr("data-name"); - frm.doc.practitioner = $(this).attr("data-practitioner"); - frm.doc.appointment_date = $(this).attr("data-date"); - frm.doc.department = $(this).attr("data-department"); - refresh_field("procedure_template"); - refresh_field("procedure_prescription"); - refresh_field("appointment_date"); - refresh_field("practitioner"); - refresh_field("department"); + frm.doc.procedure_template = $(this).attr('data-procedure-template'); + frm.doc.procedure_prescription = $(this).attr('data-name'); + frm.doc.practitioner = $(this).attr('data-practitioner'); + frm.doc.appointment_date = $(this).attr('data-date'); + frm.doc.department = $(this).attr('data-department'); + refresh_field('procedure_template'); + refresh_field('procedure_prescription'); + refresh_field('appointment_date'); + refresh_field('practitioner'); + refresh_field('department'); d.hide(); return false; }); }); - if(!result){ - var msg = "There are no procedure prescribed for "+frm.doc.patient; + if (!result) { + let msg = __('There are no procedure prescribed for ') + frm.doc.patient; $(repl('
%(msg)s
', {msg: msg})).appendTo(html_field); } d.show(); }; -var btn_create_procedure = function(frm){ - var doc = frm.doc; - frappe.call({ - method:"erpnext.healthcare.doctype.clinical_procedure.clinical_procedure.create_procedure", - args: {appointment: doc.name}, - callback: function(data){ - if(!data.exc){ - var doclist = frappe.model.sync(data.message); - frappe.set_route("Form", doclist[0].doctype, doclist[0].name); - } - } - }); -}; - -var btn_create_encounter = function(frm){ - var doc = frm.doc; - frappe.call({ - method:"erpnext.healthcare.doctype.patient_appointment.patient_appointment.create_encounter", - args: {appointment: doc.name}, - callback: function(data){ - if(!data.exc){ - var doclist = frappe.model.sync(data.message); - frappe.set_route("Form", doclist[0].doctype, doclist[0].name); - } - } - }); -}; - -var btn_create_vital_signs = function (frm) { - if(!frm.doc.patient){ - frappe.throw(__("Please select patient")); +let create_vital_signs = function(frm) { + if (!frm.doc.patient) { + frappe.throw(__('Please select patient')); } frappe.route_options = { - "patient": frm.doc.patient, - "appointment": frm.doc.name, + 'patient': frm.doc.patient, + 'appointment': frm.doc.name, }; - frappe.new_doc("Vital Signs"); + frappe.new_doc('Vital Signs'); }; -var btn_update_status = function(frm, status){ - var doc = frm.doc; +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", + method: 'erpnext.healthcare.doctype.patient_appointment.patient_appointment.update_status', args: {appointment_id: doc.name, status:status}, - callback: function(data){ - if(!data.exc){ + callback: function(data) { + if (!data.exc) { frm.reload_doc(); } } @@ -404,60 +421,60 @@ var btn_update_status = function(frm, status){ ); }; -frappe.ui.form.on("Patient Appointment", "practitioner", function(frm) { - if(frm.doc.practitioner){ +frappe.ui.form.on('Patient Appointment', 'practitioner', function(frm) { + if (frm.doc.practitioner) { frappe.call({ - "method": "frappe.client.get", + method: 'frappe.client.get', args: { - doctype: "Healthcare Practitioner", + doctype: 'Healthcare Practitioner', name: frm.doc.practitioner }, callback: function (data) { - frappe.model.set_value(frm.doctype,frm.docname, "department",data.message.department); - frappe.model.set_value(frm.doctype,frm.docname, "paid_amount",data.message.op_consulting_charge); + frappe.model.set_value(frm.doctype, frm.docname, 'department', data.message.department); + frappe.model.set_value(frm.doctype, frm.docname, 'paid_amount', data.message.op_consulting_charge); } }); } }); -frappe.ui.form.on("Patient Appointment", "patient", function(frm) { - if(frm.doc.patient){ +frappe.ui.form.on('Patient Appointment', 'patient', function(frm) { + if (frm.doc.patient) { frappe.call({ - "method": "frappe.client.get", + method: 'frappe.client.get', args: { - doctype: "Patient", + doctype: 'Patient', name: frm.doc.patient }, callback: function (data) { - var age = null; - if(data.message.dob){ + let age = null; + if (data.message.dob) { age = calculate_age(data.message.dob); } - frappe.model.set_value(frm.doctype,frm.docname, "patient_age", age); + frappe.model.set_value(frm.doctype,frm.docname, 'patient_age', age); } }); } }); -frappe.ui.form.on("Patient Appointment", "appointment_type", function(frm) { - if(frm.doc.appointment_type) { +frappe.ui.form.on('Patient Appointment', 'appointment_type', function(frm) { + if (frm.doc.appointment_type) { frappe.call({ - "method": "frappe.client.get", + method: 'frappe.client.get', args: { - doctype: "Appointment Type", + doctype: 'Appointment Type', name: frm.doc.appointment_type }, - callback: function (data) { - frappe.model.set_value(frm.doctype,frm.docname, "duration",data.message.default_duration); + callback: function(data) { + frappe.model.set_value(frm.doctype,frm.docname, 'duration',data.message.default_duration); } }); } }); -var calculate_age = function(birth) { - var ageMS = Date.parse(Date()) - Date.parse(birth); - var age = new Date(); +let calculate_age = function(birth) { + let ageMS = Date.parse(Date()) - Date.parse(birth); + let age = new Date(); age.setTime(ageMS); - var years = age.getFullYear() - 1970; - return years + " Year(s) " + age.getMonth() + " Month(s) " + age.getDate() + " Day(s)"; + let years = age.getFullYear() - 1970; + return years + ' Year(s) ' + age.getMonth() + ' Month(s) ' + age.getDate() + ' Day(s)'; }; diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json index ee9f013084..7f9a671d47 100644 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json +++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json @@ -1,1177 +1,333 @@ { + "actions": [], "allow_copy": 1, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, "allow_import": 1, - "allow_rename": 0, - "autoname": "OP-.######", + "autoname": "naming_series:", "beta": 1, "creation": "2017-05-04 11:52:40.941507", - "custom": 0, - "docstatus": 0, "doctype": "DocType", "document_type": "Document", - "editable_grid": 0, "engine": "InnoDB", + "field_order": [ + "naming_series", + "patient", + "patient_name", + "patient_sex", + "patient_age", + "inpatient_record", + "column_break_1", + "status", + "procedure_template", + "get_procedure_from_encounter", + "procedure_prescription", + "service_unit", + "section_break_12", + "practitioner", + "department", + "appointment_type", + "column_break_17", + "appointment_date", + "appointment_time", + "appointment_datetime", + "duration", + "section_break_16", + "mode_of_payment", + "paid_amount", + "company", + "column_break_2", + "invoiced", + "ref_sales_invoice", + "section_break_3", + "notes", + "referring_practitioner", + "reminded" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fetch_from": "patient.inpatient_record", "fieldname": "inpatient_record", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Inpatient Record", - "length": 0, - "no_copy": 0, "options": "Inpatient Record", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fetch_from": "inpatient_record.patient", "fieldname": "patient", "fieldtype": "Link", - "hidden": 0, "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, "in_standard_filter": 1, "label": "Patient", - "length": 0, - "no_copy": 0, "options": "Patient", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, "reqd": 1, "search_index": 1, - "set_only_once": 1, - "translatable": 0, - "unique": 0 + "set_only_once": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "appointment_type", "fieldtype": "Link", - "hidden": 0, "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Appointment Type", - "length": 0, - "no_copy": 0, "options": "Appointment Type", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 + "set_only_once": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "In Minutes", "fieldname": "duration", "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, "in_filter": 1, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Duration", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Duration (In Minutes)" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "column_break_1", "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Scheduled", "depends_on": "eval:!doc.__islocal", "fieldname": "status", "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, "in_filter": 1, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, + "in_list_view": 1, "label": "Status", - "length": 0, - "no_copy": 0, - "options": "\nScheduled\nOpen\nClosed\nPending\nCancelled", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, + "options": "\nScheduled\nOpen\nClosed\nCancelled", "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "procedure_template", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Procedure", - "length": 0, - "no_copy": 0, + "label": "Clinical Procedure Template", "options": "Clinical Procedure Template", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 + "set_only_once": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, + "depends_on": "eval:doc.__islocal && doc.patient", "fieldname": "get_procedure_from_encounter", "fieldtype": "Button", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Get prescribed procedures", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Get Prescribed Clinical Procedures" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "procedure_prescription", "fieldtype": "Link", "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Procedure Prescription", - "length": 0, "no_copy": 1, "options": "Procedure Prescription", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "print_hide": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "service_unit", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Service Unit", - "length": 0, - "no_copy": 0, "options": "Healthcare Service Unit", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 + "set_only_once": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "eval:doc.__islocal", - "fieldname": "check_availability", - "fieldtype": "Button", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Check availability", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "section_break_12", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Section Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "practitioner", "fieldtype": "Link", - "hidden": 0, "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, "in_standard_filter": 1, "label": "Healthcare Practitioner", - "length": 0, - "no_copy": 0, "options": "Healthcare Practitioner", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, "reqd": 1, "search_index": 1, - "set_only_once": 1, - "translatable": 0, - "unique": 0 + "set_only_once": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "department", "fieldtype": "Link", - "hidden": 0, "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, "in_standard_filter": 1, "label": "Department", - "length": 0, - "no_copy": 0, "options": "Medical Department", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, "search_index": 1, - "set_only_once": 1, - "translatable": 0, - "unique": 0 + "set_only_once": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "column_break_17", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "appointment_date", "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, "in_standard_filter": 1, "label": "Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "appointment_time", "fieldtype": "Time", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "Time", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "section_break_16", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Section Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", "fetch_from": "patient.patient_name", "fieldname": "patient_name", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Patient Name", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fetch_from": "patient.sex", "fieldname": "patient_sex", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, + "fieldtype": "Link", "label": "Gender", - "length": 0, "no_copy": 1, - "options": "", - "permlevel": 0, - "precision": "", + "options": "Gender", "print_hide": 1, - "print_hide_if_no_value": 0, "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "report_hide": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_21", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "patient_age", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Patient Age", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "fieldname": "section_break_1", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "appointment_datetime", "fieldtype": "Datetime", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Date TIme", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", + "label": "Appointment Datetime", "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, + "read_only": 1, "report_hide": 1, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "search_index": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "mode_of_payment", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Mode of Payment", - "length": 0, - "no_copy": 0, - "options": "Mode of Payment", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "Mode of Payment" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "paid_amount", "fieldtype": "Currency", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Paid Amount", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Paid Amount" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "column_break_2", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "0", "fieldname": "invoiced", "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Invoiced", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "company", "fieldtype": "Link", "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Company", - "length": 0, "no_copy": 1, "options": "Company", - "permlevel": 0, - "precision": "", "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "report_hide": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, "collapsible": 1, - "columns": 0, "fieldname": "section_break_3", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "More Info", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "More Info" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "notes", "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Notes", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Notes" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "referring_practitioner", "fieldtype": "Link", - "hidden": 0, "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Referring Practitioner", - "length": 0, - "no_copy": 0, - "options": "Healthcare Practitioner", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 1, - "translatable": 0, - "unique": 0 + "options": "Healthcare Practitioner" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "0", "fieldname": "reminded", "fieldtype": "Check", "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Reminded", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "report_hide": 1 + }, + { + "fieldname": "ref_sales_invoice", + "fieldtype": "Link", + "label": "Reference Sales Invoice", + "options": "Sales Invoice", + "read_only": 1 + }, + { + "fieldname": "naming_series", + "fieldtype": "Select", + "label": "Series", + "options": "HLC-APP-.YYYY.-", + "set_only_once": 1 } ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-11-14 13:24:01.529536", + "links": [], + "modified": "2020-03-27 11:27:33.773195", "modified_by": "Administrator", "module": "Healthcare", "name": "Patient Appointment", - "name_case": "", "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, "create": 1, "delete": 1, "email": 1, "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "Healthcare Administrator", - "set_user_permissions": 0, "share": 1, - "submit": 0, "write": 1 }, { - "amend": 0, - "cancel": 0, "create": 1, "delete": 1, "email": 1, "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "Physician", - "set_user_permissions": 0, "share": 1, - "submit": 0, "write": 1 }, { - "amend": 0, - "cancel": 0, "create": 1, "delete": 1, "email": 1, "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "Nursing User", - "set_user_permissions": 0, "share": 1, - "submit": 0, "write": 1 } ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, "restrict_to_domain": "Healthcare", "search_fields": "patient, practitioner, department, appointment_date, appointment_time", "show_name_in_global_search": 1, @@ -1179,6 +335,5 @@ "sort_order": "DESC", "title_field": "patient", "track_changes": 1, - "track_seen": 1, - "track_views": 0 -} + "track_seen": 1 +} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py index 5f48c9ffe4..a2d9d0240f 100755 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py +++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py @@ -6,26 +6,42 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document import json -from frappe.utils import getdate, add_days, get_time +from frappe.utils import getdate, get_time +from frappe.model.mapper import get_mapped_doc from frappe import _ import datetime from frappe.core.doctype.sms_settings.sms_settings import send_sms 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 validity_exists, service_item_and_practitioner_charge +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 PatientAppointment(Document): - def on_update(self): - today = datetime.date.today() + def validate(self): + self.validate_overlaps() + self.set_appointment_datetime() + self.validate_customer_created() + self.set_status() + + def after_insert(self): + self.update_prescription_details() + invoice_appointment(self) + self.update_fee_validity() + send_confirmation_msg(self) + + def set_status(self): + today = getdate() appointment_date = getdate(self.appointment_date) - # If appointment created for today set as open - if today == appointment_date: - frappe.db.set_value("Patient Appointment", self.name, "status", "Open") - self.reload() + # If appointment is created for today set status as Open else Scheduled + if appointment_date == today: + self.status = 'Open' + elif appointment_date > today: + self.status = 'Scheduled' + + def validate_overlaps(self): + end_time = datetime.datetime.combine(getdate(self.appointment_date), get_time(self.appointment_time)) \ + + datetime.timedelta(minutes=float(self.duration)) - def validate(self): - end_time = datetime.datetime.combine(getdate(self.appointment_date), get_time(self.appointment_time)) + datetime.timedelta(minutes=float(self.duration)) overlaps = frappe.db.sql(""" select name, practitioner, patient, appointment_time, duration @@ -41,135 +57,153 @@ class PatientAppointment(Document): self.appointment_time, end_time.time(), self.appointment_time, end_time.time(), self.appointment_time)) if overlaps: - frappe.throw(_("""Appointment overlaps with {0}.
{1} has appointment scheduled - with {2} at {3} having {4} minute(s) duration.""").format(overlaps[0][0], overlaps[0][1], overlaps[0][2], overlaps[0][3], overlaps[0][4])) + 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 after_insert(self): + def set_appointment_datetime(self): + self.appointment_datetime = "%s %s" % (self.appointment_date, self.appointment_time or "00:00:00") + + def validate_customer_created(self): + if frappe.db.get_single_value('Healthcare Settings', 'automate_appointment_invoicing'): + if not frappe.db.get_value('Patient', self.patient, 'customer'): + msg = _("Please set a Customer linked to the Patient") + msg += " {0}".format(self.patient) + frappe.throw(msg, title=_('Customer Not Found')) + + def update_prescription_details(self): if self.procedure_prescription: - frappe.db.set_value("Procedure Prescription", self.procedure_prescription, "appointment_booked", True) + frappe.db.set_value('Procedure Prescription', self.procedure_prescription, 'appointment_booked', 1) if self.procedure_template: - comments = frappe.db.get_value("Procedure Prescription", self.procedure_prescription, "comments") + comments = frappe.db.get_value('Procedure Prescription', self.procedure_prescription, 'comments') if comments: - frappe.db.set_value("Patient Appointment", self.name, "notes", comments) - # Check fee validity exists - appointment = self - validity_exist = validity_exists(appointment.practitioner, appointment.patient) - if validity_exist: - fee_validity = frappe.get_doc("Fee Validity", validity_exist[0][0]) + frappe.db.set_value('Patient Appointment', self.name, 'notes', comments) - # Check if the validity is valid - appointment_date = getdate(appointment.appointment_date) - if (fee_validity.valid_till >= appointment_date) and (fee_validity.visited < fee_validity.max_visit): - visited = fee_validity.visited + 1 - frappe.db.set_value("Fee Validity", fee_validity.name, "visited", visited) - if fee_validity.ref_invoice: - frappe.db.set_value("Patient Appointment", appointment.name, "invoiced", True) - frappe.msgprint(_("{0} has fee validity till {1}").format(appointment.patient, fee_validity.valid_till)) - confirm_sms(self) + def update_fee_validity(self): + fee_validity = manage_fee_validity(self) + if fee_validity: + frappe.msgprint(_('{0} has fee validity till {1}').format(self.patient, fee_validity.valid_till)) - if frappe.db.get_value("Healthcare Settings", None, "manage_appointment_invoice_automatically") == '1' and \ - frappe.db.get_value("Patient Appointment", self.name, "invoiced") != 1: - invoice_appointment(self) @frappe.whitelist() -def invoice_appointment(appointment_doc): - if not appointment_doc.name: - return False - sales_invoice = frappe.new_doc("Sales Invoice") - sales_invoice.customer = frappe.get_value("Patient", appointment_doc.patient, "customer") - sales_invoice.appointment = appointment_doc.name - sales_invoice.due_date = getdate() - sales_invoice.is_pos = True - sales_invoice.company = appointment_doc.company - sales_invoice.debit_to = get_receivable_account(appointment_doc.company) - - item_line = sales_invoice.append("items") - service_item, practitioner_charge = service_item_and_practitioner_charge(appointment_doc) - item_line.item_code = service_item - item_line.description = "Consulting Charges: " + appointment_doc.practitioner - item_line.income_account = get_income_account(appointment_doc.practitioner, appointment_doc.company) - item_line.rate = practitioner_charge - item_line.amount = practitioner_charge - item_line.qty = 1 - item_line.reference_dt = "Patient Appointment" - item_line.reference_dn = appointment_doc.name - - payments_line = sales_invoice.append("payments") - payments_line.mode_of_payment = appointment_doc.mode_of_payment - payments_line.amount = appointment_doc.paid_amount - - sales_invoice.set_missing_values(for_validate = True) - - sales_invoice.save(ignore_permissions=True) - sales_invoice.submit() - frappe.msgprint(_("Sales Invoice {0} created as paid").format(sales_invoice.name), alert=True) - -def appointment_cancel(appointment_id): - appointment = frappe.get_doc("Patient Appointment", appointment_id) - # If invoiced --> fee_validity update with -1 visit - if appointment.invoiced: - sales_invoice = exists_sales_invoice(appointment) - if sales_invoice and cancel_sales_invoice(sales_invoice): - frappe.msgprint( - _("Appointment {0} and Sales Invoice {1} cancelled").format(appointment.name, sales_invoice.name) - ) - else: - validity = validity_exists(appointment.practitioner, appointment.patient) - if validity: - fee_validity = frappe.get_doc("Fee Validity", validity[0][0]) - if appointment_valid_in_fee_validity(appointment, fee_validity.valid_till, True, fee_validity.ref_invoice): - visited = fee_validity.visited - 1 - frappe.db.set_value("Fee Validity", fee_validity.name, "visited", visited) - frappe.msgprint( - _("Appointment cancelled, Please review and cancel the invoice {0}").format(fee_validity.ref_invoice) - ) - else: - frappe.msgprint(_("Appointment cancelled")) - else: - frappe.msgprint(_("Appointment cancelled")) - else: - frappe.msgprint(_("Appointment cancelled")) - -def appointment_valid_in_fee_validity(appointment, valid_end_date, invoiced, ref_invoice): - valid_days = frappe.db.get_value("Healthcare Settings", None, "valid_days") - max_visit = frappe.db.get_value("Healthcare Settings", None, "max_visit") - valid_start_date = add_days(getdate(valid_end_date), -int(valid_days)) - - # Appointments which has same fee validity range with the appointment - appointments = frappe.get_list("Patient Appointment",{'patient': appointment.patient, 'invoiced': invoiced, - 'appointment_date':("<=", getdate(valid_end_date)), 'appointment_date':(">=", getdate(valid_start_date)), - 'practitioner': appointment.practitioner}, order_by="appointment_date desc", limit=int(max_visit)) - - if appointments and len(appointments) > 0: - appointment_obj = appointments[len(appointments)-1] - sales_invoice = exists_sales_invoice(appointment_obj) - if sales_invoice.name == ref_invoice: - return True +def check_payment_fields_reqd(patient): + automate_invoicing = frappe.db.get_single_value('Healthcare Settings', 'automate_appointment_invoicing') + free_follow_ups = frappe.db.get_single_value('Healthcare Settings', 'enable_free_follow_ups') + if automate_invoicing: + if free_follow_ups: + fee_validity = frappe.db.exists('Fee Validity', {'patient': patient, 'status': 'Pending'}) + if fee_validity: + return {'fee_validity': fee_validity} + if check_is_new_patient(patient): + return False + return True return False +def invoice_appointment(appointment_doc): + automate_invoicing = frappe.db.get_single_value('Healthcare Settings', 'automate_appointment_invoicing') + appointment_invoiced = frappe.db.get_value('Patient Appointment', appointment_doc.name, 'invoiced') + enable_free_follow_ups = frappe.db.get_single_value('Healthcare Settings', 'enable_free_follow_ups') + if enable_free_follow_ups: + fee_validity = check_fee_validity(appointment_doc) + if fee_validity and fee_validity.status == 'Completed': + fee_validity = None + elif not fee_validity: + if frappe.db.exists('Fee Validity Reference', {'appointment': appointment_doc.name}): + return + if check_is_new_patient(appointment_doc.patient, appointment_doc.name): + return + else: + fee_validity = None + + if automate_invoicing and not appointment_invoiced and not fee_validity: + sales_invoice = frappe.new_doc('Sales Invoice') + sales_invoice.customer = frappe.get_value('Patient', appointment_doc.patient, 'customer') + sales_invoice.appointment = appointment_doc.name + sales_invoice.due_date = getdate() + sales_invoice.is_pos = 1 + sales_invoice.company = appointment_doc.company + sales_invoice.debit_to = get_receivable_account(appointment_doc.company) + + item = sales_invoice.append('items', {}) + item = get_appointment_item(appointment_doc, item) + + payment = sales_invoice.append('payments', {}) + payment.mode_of_payment = appointment_doc.mode_of_payment + payment.amount = appointment_doc.paid_amount + + sales_invoice.set_missing_values(for_validate=True) + sales_invoice.flags.ignore_mandatory = True + sales_invoice.save(ignore_permissions=True) + sales_invoice.submit() + frappe.msgprint(_('Sales Invoice {0} created as paid'.format(sales_invoice.name)), alert=True) + frappe.db.set_value('Patient Appointment', appointment_doc.name, 'invoiced', 1) + frappe.db.set_value('Patient Appointment', appointment_doc.name, 'ref_sales_invoice', sales_invoice.name) + + +def check_is_new_patient(patient, name=None): + filters = {'patient': patient, 'status': ('!=','Cancelled')} + if name: + filters['name'] = ('!=', name) + + has_previous_appointment = frappe.db.exists('Patient Appointment', filters) + if has_previous_appointment: + return False + return True + + +def get_appointment_item(appointment_doc, item): + service_item, practitioner_charge = get_service_item_and_practitioner_charge(appointment_doc) + item.item_code = service_item + item.description = _('Consulting Charges: {0}').format(appointment_doc.practitioner) + item.income_account = get_income_account(appointment_doc.practitioner, appointment_doc.company) + item.cost_center = frappe.get_cached_value('Company', appointment_doc.company, 'cost_center') + item.rate = practitioner_charge + item.amount = practitioner_charge + item.qty = 1 + item.reference_dt = 'Patient Appointment' + item.reference_dn = appointment_doc.name + return item + + +def cancel_appointment(appointment_id): + appointment = frappe.get_doc('Patient Appointment', appointment_id) + if appointment.invoiced: + sales_invoice = check_sales_invoice_exists(appointment) + if sales_invoice and cancel_sales_invoice(sales_invoice): + msg = _('Appointment {0} and Sales Invoice {1} cancelled').format(appointment.name, sales_invoice.name) + else: + msg = _('Appointment Cancelled. Please review and cancel the invoice {0}').format(sales_invoice.name) + else: + fee_validity = manage_fee_validity(appointment) + msg = _('Appointment Cancelled.') + if fee_validity: + msg += _('Fee Validity {0} updated.').format(fee_validity.name) + + frappe.msgprint(msg) + + def cancel_sales_invoice(sales_invoice): - if frappe.db.get_value("Healthcare Settings", None, "manage_appointment_invoice_automatically") == '1': + if frappe.db.get_single_value('Healthcare Settings', 'automate_appointment_invoicing'): if len(sales_invoice.items) == 1: sales_invoice.cancel() return True return False -def exists_sales_invoice_item(appointment): - return frappe.db.exists( - "Sales Invoice Item", - { - "reference_dt": "Patient Appointment", - "reference_dn": appointment.name - } - ) -def exists_sales_invoice(appointment): - sales_item_exist = exists_sales_invoice_item(appointment) - if sales_item_exist: - sales_invoice = frappe.get_doc("Sales Invoice", frappe.db.get_value("Sales Invoice Item", sales_item_exist, "parent")) +def check_sales_invoice_exists(appointment): + sales_invoice = frappe.db.get_value('Sales Invoice Item', { + 'reference_dt': 'Patient Appointment', + 'reference_dn': appointment.name + }, 'parent') + + if sales_invoice: + sales_invoice = frappe.get_doc('Sales Invoice', sales_invoice) return sales_invoice return False + @frappe.whitelist() def get_availability_data(date, practitioner): """ @@ -180,169 +214,163 @@ def get_availability_data(date, practitioner): """ date = getdate(date) - weekday = date.strftime("%A") + weekday = date.strftime('%A') - available_slots = [] - slot_details = [] - practitioner_schedule = None + practitioner_doc = frappe.get_doc('Healthcare Practitioner', practitioner) + check_employee_wise_availability(date, practitioner_doc) + + if practitioner_doc.practitioner_schedules: + slot_details = get_available_slots(practitioner_doc, date) + else: + frappe.throw(_('{0} does not have a Healthcare Practitioner Schedule. Add it in Healthcare Practitioner master').format( + practitioner), title=_('Practitioner Schedule Not Found')) + + + if not slot_details: + # TODO: return available slots in nearby dates + frappe.throw(_('Healthcare Practitioner not available on {0}').format(weekday), title=_('Not Available')) + + return {'slot_details': slot_details} + + +def check_employee_wise_availability(date, practitioner_doc): employee = None - - practitioner_obj = frappe.get_doc("Healthcare Practitioner", practitioner) - - # Get practitioner employee relation - if practitioner_obj.employee: - employee = practitioner_obj.employee - elif practitioner_obj.user_id: - if frappe.db.exists({ - "doctype": "Employee", - "user_id": practitioner_obj.user_id - }): - employee = frappe.get_doc("Employee", {"user_id": practitioner_obj.user_id}).name + if practitioner_doc.employee: + employee = practitioner_doc.employee + elif practitioner_doc.user_id: + employee = frappe.db.get_value('Employee', {'user_id': practitioner_doc.user_id}, 'name') if employee: - # Check if it is Holiday + # check holiday if is_holiday(employee, date): - frappe.throw(_("{0} is a company holiday").format(date)) + frappe.throw(_('{0} is a holiday'.format(date)), title=_('Not Available')) - # Check if He/She on Leave + # check leave status leave_record = frappe.db.sql("""select half_day from `tabLeave Application` where employee = %s and %s between from_date and to_date and docstatus = 1""", (employee, date), as_dict=True) if leave_record: if leave_record[0].half_day: - frappe.throw(_("{0} on Half day Leave on {1}").format(practitioner, date)) + frappe.throw(_('{0} is on a Half day Leave on {1}').format(practitioner_doc.name, date), title=_('Not Available')) else: - frappe.throw(_("{0} on Leave on {1}").format(practitioner, date)) + frappe.throw(_('{0} is on Leave on {1}').format(practitioner_doc.name, date), title=_('Not Available')) - # get practitioners schedule - if practitioner_obj.practitioner_schedules: - for schedule in practitioner_obj.practitioner_schedules: - if schedule.schedule: - practitioner_schedule = frappe.get_doc("Practitioner Schedule", schedule.schedule) - else: - frappe.throw(_("{0} does not have a Healthcare Practitioner Schedule. Add it in Healthcare Practitioner master").format(practitioner)) - if practitioner_schedule: - available_slots = [] - for t in practitioner_schedule.time_slots: - if weekday == t.day: - available_slots.append(t) +def get_available_slots(practitioner_doc, date): + available_slots = [] + slot_details = [] + weekday = date.strftime('%A') + practitioner = practitioner_doc.name - if available_slots: - appointments = [] + 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')) - if schedule.service_unit: - slot_name = schedule.schedule+" - "+schedule.service_unit - allow_overlap = frappe.get_value('Healthcare Service Unit', schedule.service_unit, 'overlap_appointments') - if allow_overlap: - # fetch all appointments to practitioner by service unit - appointments = frappe.get_all( - "Patient Appointment", - filters={"practitioner": practitioner, "service_unit": schedule.service_unit, "appointment_date": date, "status": ["not in",["Cancelled"]]}, - fields=["name", "appointment_time", "duration", "status"]) - else: - # fetch all appointments to service unit - appointments = frappe.get_all( - "Patient Appointment", - filters={"service_unit": schedule.service_unit, "appointment_date": date, "status": ["not in",["Cancelled"]]}, - fields=["name", "appointment_time", "duration", "status"]) - else: - slot_name = schedule.schedule - # fetch all appointments to practitioner without service unit - appointments = frappe.get_all( - "Patient Appointment", - filters={"practitioner": practitioner, "service_unit": '', "appointment_date": date, "status": ["not in",["Cancelled"]]}, - fields=["name", "appointment_time", "duration", "status"]) + if practitioner_schedule: + available_slots = [] + for time_slot in practitioner_schedule.time_slots: + if weekday == time_slot.day: + available_slots.append(time_slot) - slot_details.append({"slot_name":slot_name, "service_unit":schedule.service_unit, - "avail_slot":available_slots, 'appointments': appointments}) + if available_slots: + appointments = [] + # fetch all appointments to practitioner by service unit + filters = { + 'practitioner': practitioner, + 'service_unit': schedule_entry.service_unit, + 'appointment_date': date, + 'status': ['not in',['Cancelled']] + } - else: - frappe.throw(_("{0} does not have a Healthcare Practitioner Schedule. Add it in Healthcare Practitioner master").format(practitioner)) + 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') + if not allow_overlap: + # fetch all appointments to service unit + filters.pop('practitioner') + else: + slot_name = schedule_entry.schedule + # fetch all appointments to practitioner without service unit + filters['practitioner'] = practitioner + filters.pop('service_unit') - if not available_slots and not slot_details: - # TODO: return available slots in nearby dates - frappe.throw(_("Healthcare Practitioner not available on {0}").format(weekday)) + appointments = frappe.get_all( + 'Patient Appointment', + filters=filters, + fields=['name', 'appointment_time', 'duration', 'status']) - return { - "slot_details": slot_details - } + slot_details.append({'slot_name':slot_name, 'service_unit':schedule_entry.service_unit, + 'avail_slot':available_slots, 'appointments': appointments}) + + return slot_details @frappe.whitelist() def update_status(appointment_id, status): - frappe.db.set_value("Patient Appointment", appointment_id, "status", status) + frappe.db.set_value('Patient Appointment', appointment_id, 'status', status) appointment_booked = True - if status == "Cancelled": + if status == 'Cancelled': appointment_booked = False - appointment_cancel(appointment_id) + cancel_appointment(appointment_id) - procedure_prescription = frappe.db.get_value("Patient Appointment", appointment_id, "procedure_prescription") + procedure_prescription = frappe.db.get_value('Patient Appointment', appointment_id, 'procedure_prescription') if procedure_prescription: - frappe.db.set_value("Procedure Prescription", procedure_prescription, "appointment_booked", appointment_booked) + frappe.db.set_value('Procedure Prescription', procedure_prescription, 'appointment_booked', appointment_booked) -@frappe.whitelist() -def set_open_appointments(): - today = getdate() - frappe.db.sql( - "update `tabPatient Appointment` set status='Open' where status = 'Scheduled'" - " and appointment_date = %s", today) - - -@frappe.whitelist() -def set_pending_appointments(): - today = getdate() - frappe.db.sql( - "update `tabPatient Appointment` set status='Pending' where status in " - "('Scheduled','Open') and appointment_date < %s", today) - - -def confirm_sms(doc): - if frappe.db.get_value("Healthcare Settings", None, "app_con") == '1': - message = frappe.db.get_value("Healthcare Settings", None, "app_con_msg") +def send_confirmation_msg(doc): + if frappe.db.get_single_value('Healthcare Settings', 'send_appointment_confirmation'): + message = frappe.db.get_single_value('Healthcare Settings', 'appointment_confirmation_msg') send_message(doc, message) + @frappe.whitelist() -def create_encounter(appointment): - appointment = frappe.get_doc("Patient Appointment", appointment) - encounter = frappe.new_doc("Patient Encounter") - encounter.appointment = appointment.name - encounter.patient = appointment.patient - encounter.practitioner = appointment.practitioner - encounter.visit_department = appointment.department - encounter.patient_sex = appointment.patient_sex - encounter.encounter_date = appointment.appointment_date - if appointment.invoiced: - encounter.invoiced = True - return encounter.as_dict() +def make_encounter(source_name, target_doc=None): + doc = get_mapped_doc('Patient Appointment', source_name, { + 'Patient Appointment': { + 'doctype': 'Patient Encounter', + 'field_map': [ + ['appointment', 'name'], + ['patient', 'patient'], + ['practitioner', 'practitioner'], + ['medical_department', 'department'], + ['patient_sex', 'patient_sex'], + ['encounter_date', 'appointment_date'], + ['invoiced', 'invoiced'] + ] + } + }, target_doc) + return doc -def remind_appointment(): - if frappe.db.get_value("Healthcare Settings", None, "app_rem") == '1': - rem_before = datetime.datetime.strptime(frappe.get_value("Healthcare Settings", None, "rem_before"), "%H:%M:%S") - rem_dt = datetime.datetime.now() + datetime.timedelta( - hours=rem_before.hour, minutes=rem_before.minute, seconds=rem_before.second) +def send_appointment_reminder(): + if frappe.db.get_single_value('Healthcare Settings', 'send_appointment_reminder'): + remind_before = datetime.datetime.strptime(frappe.db.get_single_value('Healthcare Settings', 'remind_before'), '%H:%M:%S') + reminder_dt = datetime.datetime.now() + datetime.timedelta( + hours=remind_before.hour, minutes=remind_before.minute, seconds=remind_before.second) - appointment_list = frappe.db.sql( - "select name from `tabPatient Appointment` where start_dt between %s and %s and reminded = 0 ", - (datetime.datetime.now(), rem_dt) - ) + appointment_list = frappe.db.get_all('Patient Appointment', { + 'appointment_datetime': ['between', (datetime.datetime.now(), reminder_dt)], + 'reminded': 0, + 'status': ['!=', 'Cancelled'] + }) - for i in range(0, len(appointment_list)): - doc = frappe.get_doc("Patient Appointment", appointment_list[i][0]) - message = frappe.db.get_value("Healthcare Settings", None, "app_rem_msg") + for appointment in appointment_list: + doc = frappe.get_doc('Patient Appointment', appointment.name) + message = frappe.db.get_single_value('Healthcare Settings', 'appointment_reminder_msg') send_message(doc, message) - frappe.db.set_value("Patient Appointment", doc.name, "reminded",1) - + frappe.db.set_value('Patient Appointment', doc.name, 'reminded', 1) def send_message(doc, message): - patient = frappe.get_doc("Patient", doc.patient) + patient = frappe.get_doc('Patient', doc.patient) if patient.mobile: - context = {"doc": doc, "alert": doc, "comments": None} - if doc.get("_comments"): - context["comments"] = json.loads(doc.get("_comments")) + context = {'doc': doc, 'alert': doc, 'comments': None} + if doc.get('_comments'): + context['comments'] = json.loads(doc.get('_comments')) # jinja to string convertion happens here message = frappe.render_template(message, context) @@ -359,7 +387,7 @@ def get_events(start, end, filters=None): :param filters: Filters (JSON). """ from frappe.desk.calendar import get_event_conditions - conditions = get_event_conditions("Patient Appointment", filters) + conditions = get_event_conditions('Patient Appointment', filters) data = frappe.db.sql(""" select @@ -381,10 +409,21 @@ def get_events(start, end, filters=None): return data + @frappe.whitelist() def get_procedure_prescribed(patient): return frappe.db.sql("""select pp.name, pp.procedure, pp.parent, ct.practitioner, ct.encounter_date, pp.practitioner, pp.date, pp.department from `tabPatient Encounter` ct, `tabProcedure Prescription` pp where ct.patient=%(patient)s and pp.parent=ct.name and pp.appointment_booked=0 - order by ct.creation desc""", {"patient": patient}) + order by ct.creation desc""", {'patient': patient}) + + +def update_appointment_status(): + # update the status of appointments daily + appointments = frappe.get_all('Patient Appointment', { + 'status': ('not in', ['Closed', 'Cancelled']) + }, as_dict=1) + + for appointment in appointments: + frappe.get_doc('Patient Appointment', appointment.name).set_status() diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment_list.js b/erpnext/healthcare/doctype/patient_appointment/patient_appointment_list.js index 701cb69806..721887b459 100644 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment_list.js +++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment_list.js @@ -3,4 +3,14 @@ */ frappe.listview_settings['Patient Appointment'] = { filters: [["status", "=", "Open"]], + get_indicator: function(doc) { + var colors = { + "Open": "orange", + "Scheduled": "yellow", + "Closed": "green", + "Cancelled": "red", + "Expired": "grey" + }; + return [__(doc.status), colors[doc.status], "status,=," + doc.status]; + } }; diff --git a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py index 3536a5f951..7075af5d00 100644 --- a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py +++ b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py @@ -3,8 +3,144 @@ # See license.txt from __future__ import unicode_literals import unittest - -# test_records = frappe.get_test_records('Patient Appointment') +import frappe +from erpnext.healthcare.doctype.patient_appointment.patient_appointment import update_status +from frappe.utils import nowdate, add_days +from frappe.utils.make_random import get_random class TestPatientAppointment(unittest.TestCase): - pass + def setUp(self): + frappe.db.sql("""delete from `tabPatient Appointment`""") + frappe.db.sql("""delete from `tabFee Validity""") + + def test_status(self): + patient, medical_department, practitioner = create_healthcare_docs() + frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 0) + appointment = create_appointment(patient, practitioner, nowdate()) + self.assertEquals(appointment.status, 'Open') + appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2)) + self.assertEquals(appointment.status, 'Scheduled') + create_encounter(appointment) + self.assertEquals(frappe.db.get_value('Patient Appointment', appointment.name, 'status'), 'Closed') + + def test_invoicing(self): + patient, medical_department, 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()) + self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'invoiced'), 0) + + frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1) + appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2), invoice=1) + self.assertEqual(frappe.db.get_value('Patient Appointment', appointment.name, 'invoiced'), 1) + self.assertTrue(frappe.db.get_value('Patient Appointment', appointment.name, 'ref_sales_invoice')) + + def test_appointment_cancel(self): + patient, medical_department, 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 created + self.assertTrue(fee_validity) + + visited = frappe.db.get_value('Fee Validity', fee_validity, 'visited') + update_status(appointment.name, 'Cancelled') + # check fee validity updated + self.assertEqual(frappe.db.get_value('Fee Validity', fee_validity, 'visited'), visited - 1) + + 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) + update_status(appointment.name, 'Cancelled') + # check invoice cancelled + sales_invoice = frappe.db.get_value('Patient Appointment', appointment.name, 'ref_sales_invoice') + self.assertEqual(frappe.db.get_value('Sales Invoice', sales_invoice, 'status'), 'Cancelled') + + +def create_healthcare_docs(): + patient = create_patient() + practitioner = frappe.db.exists('Healthcare Practitioner', '_Test Healthcare Practitioner') + medical_department = frappe.db.exists('Medical Department', '_Test Medical Department') + + 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 + + if not practitioner: + practitioner = frappe.new_doc('Healthcare Practitioner') + practitioner.first_name = '_Test Healthcare Practitioner' + 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 + + return patient, medical_department, practitioner + +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=None): + encounter = frappe.new_doc('Patient Encounter') + if appointment: + encounter.appointment = appointment.name + encounter.patient = appointment.patient + encounter.practitioner = appointment.practitioner + encounter.encounter_date = appointment.appointment_date + encounter.encounter_time = appointment.appointment_time + encounter.save() + encounter.submit() + return encounter + +def create_appointment(patient, practitioner, appointment_date, invoice=0, procedure_template=0): + item = create_healthcare_service_items() + frappe.db.set_value('Healthcare Settings', None, 'inpatient_visit_charge_item', item) + frappe.db.set_value('Healthcare Settings', None, 'op_consulting_charge_item', item) + appointment = frappe.new_doc('Patient Appointment') + appointment.patient = patient + appointment.practitioner = practitioner + appointment.department = '_Test Medical Department' + appointment.appointment_date = appointment_date + appointment.company = '_Test Company' + appointment.duration = 15 + if invoice: + appointment.mode_of_payment = 'Cash' + appointment.paid_amount = 500 + if procedure_template: + appointment.procedure_template = create_clinical_procedure_template().get('name') + 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' + item.item_group = 'Services' + item.is_stock_item = 0 + 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' + template.item_group = 'Services' + template.is_billable = 1 + template.description = 'Knee Surgery and Rehab' + template.rate = 50000 + template.save() + return template \ No newline at end of file diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js index 088bc8161b..83c5d2be9c 100644 --- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js +++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js @@ -19,297 +19,237 @@ frappe.ui.form.on('Patient Encounter', { refresh: function(frm) { refresh_field('drug_prescription'); refresh_field('lab_test_prescription'); - if (!frm.doc.__islocal){ - frappe.call({ - method: 'frappe.client.get_value', - args: { - doctype: 'Patient', - fieldname: 'inpatient_status', - filters: {name: frm.doc.patient} - }, - callback: function(data) { - if(data.message && data.message.inpatient_status == "Admission Scheduled" || data.message.inpatient_status == "Admitted"){ - frm.add_custom_button(__('Schedule Discharge'), function() { - schedule_discharge(frm); - }); - } - else if(data.message.inpatient_status != "Discharge Scheduled"){ - frm.add_custom_button(__('Schedule Admission'), function() { - schedule_inpatient(frm); - }); - } - } - }); - } - frm.add_custom_button(__('Patient History'), function() { - if (frm.doc.patient) { - frappe.route_options = {"patient": frm.doc.patient}; - frappe.set_route("patient_history"); - } else { - frappe.msgprint(__("Please select Patient")); + + if (!frm.doc.__islocal) { + + if (frm.doc.inpatient_status == 'Admission Scheduled' || frm.doc.inpatient_status == 'Admitted') { + frm.add_custom_button(__('Schedule Discharge'), function() { + schedule_discharge(frm); + }); + } else if (frm.doc.inpatient_status != 'Discharge Scheduled') { + frm.add_custom_button(__('Schedule Admission'), function() { + schedule_inpatient(frm); + }); } - },"View"); - frm.add_custom_button(__('Vital Signs'), function() { - btn_create_vital_signs(frm); - },"Create"); - frm.add_custom_button(__('Medical Record'), function() { - create_medical_record(frm); - },"Create"); - frm.add_custom_button(__("Procedure"),function(){ - btn_create_procedure(frm); - },"Create"); + frm.add_custom_button(__('Patient History'), function() { + if (frm.doc.patient) { + frappe.route_options = {'patient': frm.doc.patient}; + frappe.set_route('patient_history'); + } else { + frappe.msgprint(__('Please select Patient')); + } + },'View'); - frm.set_query("patient", function () { + frm.add_custom_button(__('Vital Signs'), function() { + create_vital_signs(frm); + },'Create'); + + frm.add_custom_button(__('Medical Record'), function() { + create_medical_record(frm); + },'Create'); + + frm.add_custom_button(__('Clinical Procedure'), function() { + create_procedure(frm); + },'Create'); + + } + + frm.set_query('patient', function() { return { - filters: {"disabled": 0} + filters: {'status': 'Active'} }; }); - frm.set_query("drug_code", "drug_prescription", function() { + + frm.set_query('drug_code', 'drug_prescription', function() { return { filters: { - is_stock_item:'1' + is_stock_item: 1 } }; }); - frm.set_query("lab_test_code", "lab_test_prescription", function() { + + frm.set_query('lab_test_code', 'lab_test_prescription', function() { return { filters: { - is_billable:'1' + is_billable: 1 } }; }); - frm.set_query("medical_code", "codification_table", function() { - return { - filters: { - medical_code_standard: frappe.defaults.get_default("default_medical_code_standard") - } - }; - }); - frm.set_query("appointment", function() { + + frm.set_query('appointment', function() { return { filters: { // Scheduled filter for demo ... - status:['in',["Open","Scheduled"]] + status:['in',['Open','Scheduled']] } }; }); - frm.set_df_property("appointment", "read_only", frm.doc.__islocal ? 0:1); - frm.set_df_property("patient", "read_only", frm.doc.__islocal ? 0:1); - frm.set_df_property("patient_age", "read_only", frm.doc.__islocal ? 0:1); - frm.set_df_property("patient_sex", "read_only", frm.doc.__islocal ? 0:1); - frm.set_df_property("type", "read_only", frm.doc.__islocal ? 0:1); - frm.set_df_property("practitioner", "read_only", frm.doc.__islocal ? 0:1); - frm.set_df_property("visit_department", "read_only", frm.doc.__islocal ? 0:1); - frm.set_df_property("encounter_date", "read_only", frm.doc.__islocal ? 0:1); - frm.set_df_property("encounter_time", "read_only", frm.doc.__islocal ? 0:1); - } -}); -var schedule_inpatient = function(frm) { - frappe.call({ - method: "erpnext.healthcare.doctype.inpatient_record.inpatient_record.schedule_inpatient", - args: {patient: frm.doc.patient, encounter_id: frm.doc.name, practitioner: frm.doc.practitioner}, - callback: function(data) { - if(!data.exc){ - frm.reload_doc(); - } - }, - freeze: true, - freeze_message: "Process Inpatient Scheduling" - }); -}; + frm.set_df_property('patient', 'read_only', frm.doc.appointment ? 1 : 0); + }, -var schedule_discharge = function(frm) { - frappe.call({ - method: "erpnext.healthcare.doctype.inpatient_record.inpatient_record.schedule_discharge", - args: {patient: frm.doc.patient, encounter_id: frm.doc.name, practitioner: frm.doc.practitioner}, - callback: function(data) { - if(!data.exc){ - frm.reload_doc(); - } - }, - freeze: true, - freeze_message: "Process Discharge" - }); -}; + appointment: function(frm) { + frm.events.set_appointment_fields(frm); + }, -var create_medical_record = function (frm) { - if(!frm.doc.patient){ - frappe.throw(__("Please select patient")); - } - frappe.route_options = { - "patient": frm.doc.patient, - "status": "Open", - "reference_doctype": "Patient Medical Record", - "reference_owner": frm.doc.owner - }; - frappe.new_doc("Patient Medical Record"); -}; + patient: function(frm) { + frm.events.set_patient_info(frm); + }, -var btn_create_vital_signs = function (frm) { - if(!frm.doc.patient){ - frappe.throw(__("Please select patient")); - } - frappe.route_options = { - "patient": frm.doc.patient, - "appointment": frm.doc.appointment - }; - frappe.new_doc("Vital Signs"); -}; - -var btn_create_procedure = function (frm) { - if(!frm.doc.patient){ - frappe.throw(__("Please select patient")); - } - frappe.route_options = { - "patient": frm.doc.patient, - "medical_department": frm.doc.visit_department - }; - frappe.new_doc("Clinical Procedure"); -}; - -frappe.ui.form.on("Patient Encounter", "appointment", function(frm){ - if(frm.doc.appointment){ - frappe.call({ - "method": "frappe.client.get", - args: { - doctype: "Patient Appointment", - name: frm.doc.appointment - }, - callback: function (data) { - frappe.model.set_value(frm.doctype,frm.docname, "patient", data.message.patient); - frappe.model.set_value(frm.doctype,frm.docname, "type", data.message.appointment_type); - frappe.model.set_value(frm.doctype,frm.docname, "practitioner", data.message.practitioner); - frappe.model.set_value(frm.doctype,frm.docname, "invoiced", data.message.invoiced); - } - }); - } - else{ - frappe.model.set_value(frm.doctype,frm.docname, "patient", ""); - frappe.model.set_value(frm.doctype,frm.docname, "type", ""); - frappe.model.set_value(frm.doctype,frm.docname, "practitioner", ""); - frappe.model.set_value(frm.doctype,frm.docname, "invoiced", 0); - } -}); - -frappe.ui.form.on("Patient Encounter", "practitioner", function(frm) { - if(frm.doc.practitioner){ - frappe.call({ - "method": "frappe.client.get", - args: { - doctype: "Healthcare Practitioner", - name: frm.doc.practitioner - }, - callback: function (data) { - frappe.model.set_value(frm.doctype,frm.docname, "visit_department",data.message.department); - } - }); - } -}); - -frappe.ui.form.on("Patient Encounter", "symptoms_select", function(frm) { - if(frm.doc.symptoms_select){ - var symptoms = null; - if(frm.doc.symptoms) - symptoms = frm.doc.symptoms + "\n" +frm.doc.symptoms_select; - else - symptoms = frm.doc.symptoms_select; - frappe.model.set_value(frm.doctype,frm.docname, "symptoms", symptoms); - frappe.model.set_value(frm.doctype,frm.docname, "symptoms_select", null); - } -}); -frappe.ui.form.on("Patient Encounter", "diagnosis_select", function(frm) { - if(frm.doc.diagnosis_select){ - var diagnosis = null; - if(frm.doc.diagnosis) - diagnosis = frm.doc.diagnosis + "\n" +frm.doc.diagnosis_select; - else - diagnosis = frm.doc.diagnosis_select; - frappe.model.set_value(frm.doctype,frm.docname, "diagnosis", diagnosis); - frappe.model.set_value(frm.doctype,frm.docname, "diagnosis_select", null); - } -}); - -frappe.ui.form.on("Patient Encounter", "patient", function(frm) { - if(frm.doc.patient){ - frappe.call({ - "method": "erpnext.healthcare.doctype.patient.patient.get_patient_detail", - args: { - patient: frm.doc.patient - }, - callback: function (data) { - var age = ""; - if(data.message.dob){ - age = calculate_age(data.message.dob); - } - frappe.model.set_value(frm.doctype,frm.docname, "patient_age", age); - frappe.model.set_value(frm.doctype,frm.docname, "patient_sex", data.message.sex); - } - }); - } -}); - -frappe.ui.form.on("Drug Prescription", { - drug_code: function(frm, cdt, cdn) { - var child = locals[cdt][cdn]; - if(child.drug_code){ + set_appointment_fields: function(frm) { + if (frm.doc.appointment) { frappe.call({ - "method": "frappe.client.get", + method: 'frappe.client.get', args: { - doctype: "Item", - name: child.drug_code, + doctype: 'Patient Appointment', + name: frm.doc.appointment }, - callback: function (data) { - frappe.model.set_value(cdt, cdn, 'drug_name',data.message.item_name); + callback: function(data) { + let values = { + 'patient':data.message.patient, + 'type': data.message.appointment_type, + 'practitioner': data.message.practitioner, + 'invoiced': data.message.invoiced + }; + frm.set_value(values); } }); } + else { + let values = { + 'patient': '', + 'patient_name': '', + 'type': '', + 'practitioner': '', + 'invoiced': 0, + 'patient_sex': '', + 'patient_age': '', + 'inpatient_record': '', + 'inpatient_status': '' + }; + frm.set_value(values); + } }, + + set_patient_info: function(frm) { + if (frm.doc.patient) { + frappe.call({ + method: 'erpnext.healthcare.doctype.patient.patient.get_patient_detail', + args: { + patient: frm.doc.patient + }, + callback: function(data) { + let age = ''; + if (data.message.dob) { + age = calculate_age(data.message.dob); + } + frappe.model.set_value(frm.doctype, frm.docname, 'patient_age', age); + frappe.model.set_value(frm.doctype, frm.docname, 'patient_sex', data.message.sex); + if (data.message.inpatient_record) { + frappe.model.set_value(frm.doctype, frm.docname, 'inpatient_record', data.message.inpatient_record); + frappe.model.set_value(frm.doctype, frm.docname, 'inpatient_status', data.message.inpatient_status); + } + } + }); + } else { + frappe.model.set_value(frm.doctype, frm.docname, 'patient_sex', ''); + frappe.model.set_value(frm.doctype, frm.docname, 'patient_age', ''); + frappe.model.set_value(frm.doctype, frm.docname, 'inpatient_record', ''); + frappe.model.set_value(frm.doctype, frm.docname, 'inpatient_status', ''); + } + } +}); + +let schedule_inpatient = function(frm) { + frappe.call({ + method: 'erpnext.healthcare.doctype.inpatient_record.inpatient_record.schedule_inpatient', + args: {patient: frm.doc.patient, encounter_id: frm.doc.name, practitioner: frm.doc.practitioner}, + callback: function(data) { + if (!data.exc) { + frm.reload_doc(); + } + }, + freeze: true, + freeze_message: __('Process Inpatient Scheduling') + }); +}; + +let schedule_discharge = function(frm) { + frappe.call({ + method: 'erpnext.healthcare.doctype.inpatient_record.inpatient_record.schedule_discharge', + args: {patient: frm.doc.patient, encounter_id: frm.doc.name, practitioner: frm.doc.practitioner}, + callback: function(data) { + if (!data.exc) { + frm.reload_doc(); + } + }, + freeze: true, + freeze_message: 'Process Discharge' + }); +}; + +let create_medical_record = function (frm) { + if (!frm.doc.patient) { + frappe.throw(__('Please select patient')); + } + frappe.route_options = { + 'patient': frm.doc.patient, + 'status': 'Open', + 'reference_doctype': 'Patient Medical Record', + 'reference_owner': frm.doc.owner + }; + frappe.new_doc('Patient Medical Record'); +}; + +let create_vital_signs = function (frm) { + if (!frm.doc.patient) { + frappe.throw(__('Please select patient')); + } + frappe.route_options = { + 'patient': frm.doc.patient, + 'appointment': frm.doc.appointment, + 'encounter': frm.doc.name + }; + frappe.new_doc('Vital Signs'); +}; + +let create_procedure = function (frm) { + if (!frm.doc.patient) { + frappe.throw(__('Please select patient')); + } + frappe.route_options = { + 'patient': frm.doc.patient, + 'medical_department': frm.doc.medical_department + }; + frappe.new_doc('Clinical Procedure'); +}; + +frappe.ui.form.on('Drug Prescription', { dosage: function(frm, cdt, cdn){ frappe.model.set_value(cdt, cdn, 'update_schedule', 1); - var child = locals[cdt][cdn]; - if(child.dosage){ - frappe.model.set_value(cdt, cdn, 'in_every', 'Day'); + let child = locals[cdt][cdn]; + if (child.dosage) { + frappe.model.set_value(cdt, cdn, 'interval_uom', 'Day'); frappe.model.set_value(cdt, cdn, 'interval', 1); } }, - period: function(frm, cdt, cdn){ + period: function(frm, cdt, cdn) { frappe.model.set_value(cdt, cdn, 'update_schedule', 1); }, - in_every: function(frm, cdt, cdn){ + interval_uom: function(frm, cdt, cdn) { frappe.model.set_value(cdt, cdn, 'update_schedule', 1); - var child = locals[cdt][cdn]; - if(child.in_every == "Hour"){ + let child = locals[cdt][cdn]; + if (child.interval_uom == 'Hour') { frappe.model.set_value(cdt, cdn, 'dosage', null); } } }); -frappe.ui.form.on("Procedure Prescription", { - procedure: function(frm, cdt, cdn) { - var child = locals[cdt][cdn]; - if(child.procedure){ - frappe.call({ - "method": "frappe.client.get_value", - args: { - doctype: "Clinical Procedure Template", - fieldname: "medical_department", - filters: {name: child.procedure} - }, - callback: function (data) { - frappe.model.set_value(cdt, cdn, 'department',data.message.medical_department); - } - }); - } - } -}); - - -var calculate_age = function(birth) { - var ageMS = Date.parse(Date()) - Date.parse(birth); - var age = new Date(); +let calculate_age = function(birth) { + let ageMS = Date.parse(Date()) - Date.parse(birth); + let age = new Date(); age.setTime(ageMS); - var years = age.getFullYear() - 1970; - return years + " Year(s) " + age.getMonth() + " Month(s) " + age.getDate() + " Day(s)"; + let years = age.getFullYear() - 1970; + return years + ' Year(s) ' + age.getMonth() + ' Month(s) ' + age.getDate() + ' Day(s)'; }; diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json index 91c9d7bcf2..d00e7bc7dd 100644 --- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json +++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.json @@ -1,1183 +1,324 @@ { - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 0, - "autoname": "naming_series:", - "beta": 1, - "creation": "2016-04-21 10:53:44.637684", - "custom": 0, - "default_print_format": "", - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 1, + "actions": [], + "allow_copy": 1, + "allow_import": 1, + "autoname": "naming_series:", + "beta": 1, + "creation": "2016-04-21 10:53:44.637684", + "doctype": "DocType", + "document_type": "Document", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "naming_series", + "appointment", + "appointment_type", + "patient", + "patient_name", + "patient_sex", + "patient_age", + "company", + "column_break_6", + "practitioner", + "medical_department", + "encounter_date", + "encounter_time", + "invoiced", + "section_break_1", + "inpatient_record", + "column_break_17", + "inpatient_status", + "sb_symptoms", + "symptoms", + "symptoms_in_print", + "physical_examination", + "diagnosis", + "diagnosis_in_print", + "codification", + "codification_table", + "sb_drug_prescription", + "drug_prescription", + "sb_test_prescription", + "lab_test_prescription", + "sb_procedures", + "procedure_prescription", + "encounter_comment", + "amended_from" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "patient.inpatient_record", - "fieldname": "inpatient_record", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Inpatient Record", - "length": 0, - "no_copy": 0, - "options": "Inpatient Record", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "inpatient_record", + "fieldtype": "Link", + "label": "Inpatient Record", + "options": "Inpatient Record", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_1", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "collapsible": 1, + "fieldname": "section_break_1", + "fieldtype": "Section Break", + "label": "Inpatient Details" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fieldname": "naming_series", - "fieldtype": "Select", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Series", - "length": 0, - "no_copy": 0, - "options": "HLC-ENC-.YYYY.-", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "naming_series", + "fieldtype": "Select", + "label": "Series", + "no_copy": 1, + "options": "HLC-ENC-.YYYY.-", + "set_only_once": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "fieldname": "appointment", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Appointment", - "length": 0, - "no_copy": 0, - "options": "Patient Appointment", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "appointment", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "label": "Appointment", + "options": "Patient Appointment", + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "type", - "fieldtype": "Link", - "hidden": 1, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Type", - "length": 0, - "no_copy": 1, - "options": "Appointment Type", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "inpatient_record.patient", + "fieldname": "patient", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Patient", + "options": "Patient", + "reqd": 1, + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "inpatient_record.patient", - "fieldname": "patient", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Patient", - "length": 0, - "no_copy": 0, - "options": "Patient", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "patient.patient_name", + "fieldname": "patient_name", + "fieldtype": "Data", + "label": "Patient Name", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fetch_from": "patient.patient_name", - "fieldname": "patient_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Patient Name", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "patient_age", + "fieldtype": "Data", + "label": "Age", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "patient_age", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Age", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "patient_sex", + "fieldtype": "Link", + "label": "Gender", + "options": "Gender", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "patient_sex", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Gender", - "length": 0, - "no_copy": 0, - "options": "\nMale\nFemale\nOther", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "company", + "fieldtype": "Link", + "hidden": 1, + "label": "Company", + "options": "Company" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "company", - "fieldtype": "Link", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Company", - "length": 0, - "no_copy": 0, - "options": "Company", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_6", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_6", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "practitioner", + "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Healthcare Practitioner", + "options": "Healthcare Practitioner", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "practitioner", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Healthcare Practitioner", - "length": 0, - "no_copy": 0, - "options": "Healthcare Practitioner", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "Today", + "fieldname": "encounter_date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "Encounter Date", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "visit_department", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Department", - "length": 0, - "no_copy": 0, - "options": "Medical Department", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "encounter_time", + "fieldtype": "Time", + "label": "Encounter Time", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Today", - "fieldname": "encounter_date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Encounter Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "invoiced", + "fieldtype": "Check", + "label": "Invoiced", + "no_copy": 1, + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fieldname": "encounter_time", - "fieldtype": "Time", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Encounter Time", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sb_symptoms", + "fieldtype": "Section Break", + "label": "Encounter Impression" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fieldname": "invoiced", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Invoiced", - "length": 0, - "no_copy": 1, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "symptoms", + "fieldtype": "Table MultiSelect", + "ignore_xss_filter": 1, + "label": "Symptoms", + "no_copy": 1, + "options": "Patient Encounter Symptom" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "columns": 0, - "fieldname": "sb_symptoms", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Encounter Impression", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "depends_on": "eval: doc.symptoms != ''", + "fieldname": "symptoms_in_print", + "fieldtype": "Check", + "label": "In print", + "no_copy": 1, + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "symptoms_select", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Complaints", - "length": 0, - "no_copy": 1, - "options": "Complaint", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "physical_examination", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "symptoms", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "diagnosis", + "fieldtype": "Table MultiSelect", + "ignore_xss_filter": 1, + "label": "Diagnosis", + "no_copy": 1, + "options": "Patient Encounter Diagnosis" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fieldname": "symptoms_in_print", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "In print", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "1", + "depends_on": "eval: doc.diagnosis != ''", + "fieldname": "diagnosis_in_print", + "fieldtype": "Check", + "label": "In print", + "no_copy": 1, + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "physical_examination", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "collapsible": 1, + "fieldname": "codification", + "fieldtype": "Section Break", + "label": "Medical Coding" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "fieldname": "diagnosis_select", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Diagnosis", - "length": 0, - "no_copy": 1, - "options": "Diagnosis", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "codification_table", + "fieldtype": "Table", + "label": "Medical Coding", + "options": "Codification Table" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "depends_on": "", - "fieldname": "diagnosis", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sb_drug_prescription", + "fieldtype": "Section Break", + "label": "Medication" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "1", - "depends_on": "", - "fieldname": "diagnosis_in_print", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "In print", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "drug_prescription", + "fieldtype": "Table", + "label": "Drug Prescription", + "options": "Drug Prescription" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 1, - "columns": 0, - "fieldname": "codification", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Medical Coding", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sb_test_prescription", + "fieldtype": "Section Break", + "label": "Investigation" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "codification_table", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Medical Coding", - "length": 0, - "no_copy": 0, - "options": "Codification Table", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "lab_test_prescription", + "fieldtype": "Table", + "label": "Lab Prescription", + "options": "Lab Prescription" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sb_drug_prescription", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Medication", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sb_procedures", + "fieldtype": "Section Break", + "label": "Procedures" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "drug_prescription", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Medication", - "length": 0, - "no_copy": 0, - "options": "Drug Prescription", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "procedure_prescription", + "fieldtype": "Table", + "label": "Procedure Prescription", + "no_copy": 1, + "options": "Procedure Prescription" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sb_test_prescription", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Investigations", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "encounter_comment", + "fieldtype": "Small Text", + "ignore_xss_filter": 1, + "label": "Review Details", + "no_copy": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "lab_test_prescription", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Investigations", - "length": 0, - "no_copy": 0, - "options": "Lab Prescription", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "amended_from", + "fieldtype": "Link", + "label": "Amended From", + "no_copy": 1, + "options": "Patient Encounter", + "print_hide": 1, + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sb_procedures", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Procedures", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "appointment_type", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "label": "Appointment Type", + "no_copy": 1, + "options": "Appointment Type", + "print_hide": 1, + "read_only": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "procedure_prescription", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Procedures", - "length": 0, - "no_copy": 1, - "options": "Procedure Prescription", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "practitioner.department", + "fieldname": "medical_department", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Department", + "options": "Medical Department", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "encounter_comment", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Review Details", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "inpatient_status", + "fieldtype": "Data", + "label": "Inpatient Status", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "amended_from", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Amended From", - "length": 0, - "no_copy": 1, - "options": "Patient Encounter", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldname": "column_break_17", + "fieldtype": "Column Break" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 1, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-09-04 11:50:52.217175", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Patient Encounter", - "name_case": "", - "owner": "Administrator", + ], + "is_submittable": 1, + "links": [], + "modified": "2020-02-27 12:42:21.751964", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Patient Encounter", + "owner": "Administrator", "permissions": [ { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "set_user_permissions": 0, - "share": 1, - "submit": 1, + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Physician", + "share": 1, + "submit": 1, "write": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "search_fields": "patient, practitioner, visit_department, encounter_date, encounter_time", - "show_name_in_global_search": 1, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "patient", - "track_changes": 1, - "track_seen": 1, - "track_views": 0 + ], + "restrict_to_domain": "Healthcare", + "search_fields": "patient, practitioner, medical_department, encounter_date, encounter_time", + "show_name_in_global_search": 1, + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "patient", + "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 fe7ac8eb33..ade4748ece 100644 --- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py +++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py @@ -6,59 +6,63 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document from frappe.utils import cstr +from frappe import _ class PatientEncounter(Document): def on_update(self): - if(self.appointment): - frappe.db.set_value("Patient Appointment", self.appointment, "status", "Closed") - update_encounter_to_medical_record(self) + if self.appointment: + frappe.db.set_value('Patient Appointment', self.appointment, 'status', 'Closed') + update_encounter_medical_record(self) def after_insert(self): insert_encounter_to_medical_record(self) def on_cancel(self): - if(self.appointment): - frappe.db.set_value("Patient Appointment", self.appointment, "status", "Open") + if self.appointment: + frappe.db.set_value('Patient Appointment', self.appointment, 'status', 'Open') delete_medical_record(self) def insert_encounter_to_medical_record(doc): subject = set_subject_field(doc) - medical_record = frappe.new_doc("Patient Medical Record") + medical_record = frappe.new_doc('Patient Medical Record') medical_record.patient = doc.patient medical_record.subject = subject - medical_record.status = "Open" + medical_record.status = 'Open' medical_record.communication_date = doc.encounter_date - medical_record.reference_doctype = "Patient Encounter" + medical_record.reference_doctype = 'Patient Encounter' medical_record.reference_name = doc.name medical_record.reference_owner = doc.owner medical_record.save(ignore_permissions=True) -def update_encounter_to_medical_record(encounter): - medical_record_id = frappe.db.sql("select name from `tabPatient Medical Record` where reference_name=%s", (encounter.name)) +def update_encounter_medical_record(encounter): + medical_record_id = frappe.db.exists('Patient Medical Record', {'reference_name': encounter.name}) + if medical_record_id and medical_record_id[0][0]: subject = set_subject_field(encounter) - frappe.db.set_value("Patient Medical Record", medical_record_id[0][0], "subject", subject) + frappe.db.set_value('Patient Medical Record', medical_record_id[0][0], 'subject', subject) else: insert_encounter_to_medical_record(encounter) def delete_medical_record(encounter): - frappe.db.sql("""delete from `tabPatient Medical Record` where reference_name = %s""", (encounter.name)) + frappe.db.delete_doc_if_exists('Patient Medical Record', 'reference_name', encounter.name) def set_subject_field(encounter): - subject = encounter.practitioner+"
" - if(encounter.symptoms): - subject += "Symptoms: "+ cstr(encounter.symptoms)+".
" + subject = encounter.practitioner + '\n' + if encounter.symptoms: + subject += _('Symptoms: ') + cstr(encounter.symptoms) + '\n' else: - subject += "No Symptoms
" - if(encounter.diagnosis): - subject += "Diagnosis: "+ cstr(encounter.diagnosis)+".
" + subject += _('No Symptoms') + '\n' + + if encounter.diagnosis: + subject += _('Diagnosis: ') + cstr(encounter.diagnosis) + '\n' else: - subject += "No Diagnosis
" - if(encounter.drug_prescription): - subject +="\nDrug(s) Prescribed. " - if(encounter.lab_test_prescription): - subject += "\nTest(s) Prescribed." - if(encounter.procedure_prescription): - subject += "\nProcedure(s) Prescribed." + subject += _('No Diagnosis') + '\n' + + if encounter.drug_prescription: + subject += '\n' + _('Drug(s) Prescribed.') + if encounter.lab_test_prescription: + subject += '\n' + _('Test(s) Prescribed.') + if encounter.procedure_prescription: + subject += '\n' + _('Procedure(s) Prescribed.') return subject diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter_list.js b/erpnext/healthcare/doctype/patient_encounter/patient_encounter_list.js index 93c02f60c5..d8f63bd0fa 100644 --- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter_list.js +++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter_list.js @@ -2,5 +2,5 @@ (c) ESS 2015-16 */ frappe.listview_settings['Patient Encounter'] = { - filters:[["docstatus","!=","1"]] + filters:[["docstatus","!=","2"]] }; diff --git a/erpnext/healthcare/doctype/patient_encounter_diagnosis/__init__.py b/erpnext/healthcare/doctype/patient_encounter_diagnosis/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/healthcare/doctype/patient_encounter_diagnosis/patient_encounter_diagnosis.json b/erpnext/healthcare/doctype/patient_encounter_diagnosis/patient_encounter_diagnosis.json new file mode 100644 index 0000000000..00ca309d63 --- /dev/null +++ b/erpnext/healthcare/doctype/patient_encounter_diagnosis/patient_encounter_diagnosis.json @@ -0,0 +1,33 @@ +{ + "actions": [], + "beta": 1, + "creation": "2020-02-26 16:48:16.835105", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "diagnosis" + ], + "fields": [ + { + "fieldname": "diagnosis", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Diagnosis", + "options": "Diagnosis", + "reqd": 1 + } + ], + "istable": 1, + "links": [], + "modified": "2020-02-26 16:58:16.480583", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Patient Encounter Diagnosis", + "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/patient_encounter_diagnosis/patient_encounter_diagnosis.py b/erpnext/healthcare/doctype/patient_encounter_diagnosis/patient_encounter_diagnosis.py new file mode 100644 index 0000000000..34b0cf8a58 --- /dev/null +++ b/erpnext/healthcare/doctype/patient_encounter_diagnosis/patient_encounter_diagnosis.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 PatientEncounterDiagnosis(Document): + pass diff --git a/erpnext/healthcare/doctype/patient_encounter_symptom/__init__.py b/erpnext/healthcare/doctype/patient_encounter_symptom/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/healthcare/doctype/patient_encounter_symptom/patient_encounter_symptom.json b/erpnext/healthcare/doctype/patient_encounter_symptom/patient_encounter_symptom.json new file mode 100644 index 0000000000..bc92145867 --- /dev/null +++ b/erpnext/healthcare/doctype/patient_encounter_symptom/patient_encounter_symptom.json @@ -0,0 +1,33 @@ +{ + "actions": [], + "beta": 1, + "creation": "2020-02-26 16:47:00.525657", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "complaint" + ], + "fields": [ + { + "fieldname": "complaint", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Complaint", + "options": "Complaint", + "reqd": 1 + } + ], + "istable": 1, + "links": [], + "modified": "2020-02-26 16:57:37.997481", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Patient Encounter Symptom", + "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/patient_encounter_symptom/patient_encounter_symptom.py b/erpnext/healthcare/doctype/patient_encounter_symptom/patient_encounter_symptom.py new file mode 100644 index 0000000000..bdb7bb218e --- /dev/null +++ b/erpnext/healthcare/doctype/patient_encounter_symptom/patient_encounter_symptom.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 PatientEncounterSymptom(Document): + pass diff --git a/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.json b/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.json index c6a6b44ce7..3655e24cb9 100644 --- a/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.json +++ b/erpnext/healthcare/doctype/patient_medical_record/patient_medical_record.json @@ -1,457 +1,155 @@ { - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 0, - "autoname": "naming_series:", - "beta": 1, - "creation": "2016-06-09 11:30:44.972056", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "Setup", - "editable_grid": 0, + "actions": [], + "allow_copy": 1, + "allow_import": 1, + "autoname": "naming_series:", + "beta": 1, + "creation": "2016-06-09 11:30:44.972056", + "doctype": "DocType", + "document_type": "Setup", + "engine": "InnoDB", + "field_order": [ + "naming_series", + "patient", + "status", + "column_break_2", + "attach", + "section_break_4", + "subject", + "section_break_8", + "communication_date", + "reference_doctype", + "reference_name", + "column_break_9", + "reference_owner", + "user" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fieldname": "naming_series", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Series", - "length": 0, - "no_copy": 0, - "options": "HLC-PMR-.YYYY.-", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "naming_series", + "fieldtype": "Select", + "label": "Series", + "options": "HLC-PMR-.YYYY.-", + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "patient", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Patient", - "length": 0, - "no_copy": 0, - "options": "Patient", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "patient", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "in_list_view": 1, + "label": "Patient", + "options": "Patient", + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_2", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_2", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "attach", - "fieldtype": "Attach", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "attach", + "fieldtype": "Attach", + "label": "Attach Medical Record" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_4", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "section_break_4", + "fieldtype": "Section Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "subject", - "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Subject", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "subject", + "fieldtype": "Small Text", + "ignore_xss_filter": 1, + "label": "Subject" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "status", - "fieldtype": "Select", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Status", - "length": 0, - "no_copy": 0, - "options": "Open\nClose", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "status", + "fieldtype": "Select", + "label": "Status", + "options": "Open\nClose", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "Today", - "fieldname": "communication_date", - "fieldtype": "Date", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Datetime", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "Today", + "fieldname": "communication_date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "Datetime", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "reference_doctype", - "fieldtype": "Link", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Reference DocType", - "length": 0, - "no_copy": 0, - "options": "DocType", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "reference_doctype", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Reference DocType", + "options": "DocType", + "read_only": 1, + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "reference_name", - "fieldtype": "Dynamic Link", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Reference Name", - "length": 0, - "no_copy": 0, - "options": "reference_doctype", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "reference_name", + "fieldtype": "Dynamic Link", + "in_list_view": 1, + "label": "Reference Name", + "options": "reference_doctype", + "read_only": 1, + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "reference_name.owner", - "fieldname": "reference_owner", - "fieldtype": "Data", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Reference Owner", - "length": 0, - "no_copy": 1, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "reference_name.owner", + "fieldname": "reference_owner", + "fieldtype": "Data", + "label": "Reference Owner", + "no_copy": 1, + "print_hide": 1, + "read_only": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "__user", - "fieldname": "user", - "fieldtype": "Link", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "User", - "length": 0, - "no_copy": 0, - "options": "User", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "default": "__user", + "fieldname": "user", + "fieldtype": "Link", + "label": "User", + "options": "User", + "print_hide": 1, + "read_only": 1, + "report_hide": 1 + }, + { + "fieldname": "column_break_9", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_8", + "fieldtype": "Section Break" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 1, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-08-21 14:44:37.927284", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Patient Medical Record", - "name_case": "", - "owner": "Administrator", + ], + "in_create": 1, + "links": [], + "modified": "2020-03-23 19:26:59.308383", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Patient Medical Record", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Physician", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Physician", + "share": 1, "write": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "search_fields": "patient, subject, communication_date, reference_doctype, reference_name", - "show_name_in_global_search": 1, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "patient", - "track_changes": 1, - "track_seen": 1, - "track_views": 0 -} + ], + "restrict_to_domain": "Healthcare", + "search_fields": "patient, subject, communication_date, reference_doctype, reference_name", + "show_name_in_global_search": 1, + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "patient", + "track_changes": 1, + "track_seen": 1 +} \ No newline at end of file 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 460774a7ec..e5a5e4c010 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 @@ -3,8 +3,86 @@ # See license.txt from __future__ import unicode_literals import unittest - -# test_records = frappe.get_test_records('Patient Medical Record') +import frappe +from frappe.utils import nowdate +from erpnext.healthcare.doctype.patient_appointment.test_patient_appointment import create_encounter, create_healthcare_docs, create_appointment class TestPatientMedicalRecord(unittest.TestCase): - pass + def setUp(self): + frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0) + frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1) + + def test_medical_record(self): + patient, medical_department, practitioner = create_healthcare_docs() + appointment = create_appointment(patient, practitioner, nowdate(), invoice=1) + encounter = create_encounter(appointment) + # check for encounter + medical_rec = frappe.db.exists('Patient Medical Record', {'status': 'Open', 'reference_name': encounter.name}) + self.assertTrue(medical_rec) + + vital_signs = create_vital_signs(appointment) + # check for vital signs + medical_rec = frappe.db.exists('Patient Medical Record', {'status': 'Open', 'reference_name': vital_signs.name}) + self.assertTrue(medical_rec) + + appointment = create_appointment(patient, practitioner, nowdate(), invoice=1, procedure_template=1) + procedure = create_procedure(appointment) + procedure.start_procedure() + procedure.complete_procedure() + # check for clinical procedure + medical_rec = frappe.db.exists('Patient Medical Record', {'status': 'Open', 'reference_name': procedure.name}) + self.assertTrue(medical_rec) + + template = create_lab_test_template(medical_department) + lab_test = create_lab_test(template, patient) + # check for lab test + medical_rec = frappe.db.exists('Patient Medical Record', {'status': 'Open', 'reference_name': lab_test.name}) + self.assertTrue(medical_rec) + + +def create_procedure(appointment): + if appointment: + procedure = frappe.new_doc('Clinical Procedure') + procedure.procedure_template = appointment.procedure_template + procedure.appointment = appointment.name + procedure.patient = appointment.patient + procedure.practitioner = appointment.practitioner + procedure.medical_department = appointment.department + procedure.start_dt = appointment.appointment_date + procedure.start_time = appointment.appointment_time + procedure.save() + procedure.submit() + return procedure + +def create_vital_signs(appointment): + vital_signs = frappe.new_doc('Vital Signs') + vital_signs.patient = appointment.patient + vital_signs.signs_date = appointment.appointment_date + vital_signs.signs_time = appointment.appointment_time + vital_signs.temperature = 38.5 + vital_signs.save() + vital_signs.submit() + return vital_signs + +def create_lab_test_template(medical_department): + if frappe.db.exists('Lab Test Template', 'Blood Test'): + return 'Blood Test' + + template = frappe.new_doc('Lab Test Template') + template.lab_test_name = 'Blood Test' + template.lab_test_code = 'Blood Test' + template.lab_test_group = 'Services' + template.department = medical_department + template.is_billable = 1 + template.lab_test_rate = 2000 + template.save() + return template.name + +def create_lab_test(template, patient): + lab_test = frappe.new_doc('Lab Test') + lab_test.patient = patient + lab_test.patient_sex = frappe.db.get_value('Patient', patient, 'sex') + lab_test.template = template + lab_test.save() + lab_test.submit() + return lab_test \ No newline at end of file diff --git a/erpnext/healthcare/doctype/patient_relation/patient_relation.json b/erpnext/healthcare/doctype/patient_relation/patient_relation.json index 209a3746a6..376f7f76d6 100644 --- a/erpnext/healthcare/doctype/patient_relation/patient_relation.json +++ b/erpnext/healthcare/doctype/patient_relation/patient_relation.json @@ -1,134 +1,52 @@ { - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 1, - "creation": "2017-04-26 15:40:11.561855", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "allow_copy": 1, + "beta": 1, + "creation": "2017-04-26 15:40:11.561855", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "patient", + "relation", + "description" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "relation", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Relation", - "length": 0, - "no_copy": 0, - "options": "\nFather\nMother\nSpouse\nSiblings\nFamily", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "relation", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Relation", + "options": "\nFather\nMother\nSpouse\nSiblings\nFamily\nOther", + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "patient", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Patient", - "length": 0, - "no_copy": 0, - "options": "Patient", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, + "fieldname": "patient", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "in_list_view": 1, + "label": "Patient", + "options": "Patient", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "description", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Description", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "unique": 0 + "fieldname": "description", + "fieldtype": "Small Text", + "ignore_xss_filter": 1, + "label": "Description" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2017-10-04 16:12:45.485333", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Patient Relation", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 1, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0 + ], + "istable": 1, + "links": [], + "modified": "2020-01-29 12:45:40.081899", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Patient Relation", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "restrict_to_domain": "Healthcare", + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.js b/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.js index f247856b92..7cb7c4b65e 100644 --- a/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.js +++ b/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.js @@ -5,9 +5,9 @@ frappe.ui.form.on('Practitioner Schedule', { refresh: function(frm) { cur_frm.fields_dict["time_slots"].grid.wrapper.find('.grid-add-row').hide(); cur_frm.fields_dict["time_slots"].grid.add_custom_button(__('Add Time Slots'), () => { - var d = new frappe.ui.Dialog({ + let d = new frappe.ui.Dialog({ fields: [ - {fieldname: 'days', label: __('Select Days'), fieldtype:'MultiSelect', + {fieldname: 'days', label: __('Select Days'), fieldtype: 'MultiSelect', options:[ {value:'Sunday', label:__('Sunday')}, {value:'Monday', label:__('Monday')}, @@ -17,40 +17,41 @@ frappe.ui.form.on('Practitioner Schedule', { {value:'Friday', label:__('Friday')}, {value:'Saturday', label:__('Saturday')}, ], reqd: 1}, - {fieldname: 'from_time', label:__('From'), fieldtype:'Time', + {fieldname: 'from_time', label: __('From'), fieldtype: 'Time', 'default': '09:00:00', reqd: 1}, - {fieldname: 'to_time', label:__('To'), fieldtype:'Time', + {fieldname: 'to_time', label: __('To'), fieldtype: 'Time', 'default': '12:00:00', reqd: 1}, - {fieldname: 'duration', label:__('Appointment Duration (mins)'), + {fieldname: 'duration', label: __('Appointment Duration (mins)'), fieldtype:'Int', 'default': 15, reqd: 1}, ], primary_action_label: __('Add Timeslots'), primary_action: () => { - var values = d.get_values(); - if(values) { + let values = d.get_values(); + if (values) { let slot_added = false; values.days.split(',').forEach(function(day){ day = $.trim(day); - if(['Sunday', 'Monday', 'Tuesday', 'Wednesday', + if (['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'].includes(day)){ add_slots(day); } }); + function check_overlap_or_add_slot(week_day, cur_time, end_time, add_slots_to_child){ let overlap = false; - while(cur_time < end_time) { + while (cur_time < end_time) { let add_to_child = true; let to_time = cur_time.clone().add(values.duration, 'minutes'); - if(to_time <= end_time) { - if(frm.doc.time_slots){ + if (to_time <= end_time) { + if (frm.doc.time_slots){ frm.doc.time_slots.forEach(function(slot) { - if(slot.day == week_day){ + if (slot.day == week_day){ let slot_from_moment = moment(slot.from_time, 'HH:mm:ss'); let slot_to_moment = moment(slot.to_time, 'HH:mm:ss'); - if(cur_time.isSame(slot_from_moment) || cur_time.isBetween(slot_from_moment, slot_to_moment) || - to_time.isSame(slot_to_moment) || to_time.isBetween(slot_from_moment, slot_to_moment)){ + if (cur_time.isSame(slot_from_moment) || cur_time.isBetween(slot_from_moment, slot_to_moment) || + to_time.isSame(slot_to_moment) || to_time.isBetween(slot_from_moment, slot_to_moment)) { overlap = true; - if(add_slots_to_child){ + if (add_slots_to_child) { frappe.show_alert({ message:__('Time slot skiped, the slot {0} to {1} overlap exisiting slot {2} to {3}', [cur_time.format('HH:mm:ss'), to_time.format('HH:mm:ss'), slot.from_time, slot.to_time]), @@ -63,7 +64,7 @@ frappe.ui.form.on('Practitioner Schedule', { }); } // add a new timeslot - if(add_to_child && add_slots_to_child){ + if (add_to_child && add_slots_to_child) { frm.add_child('time_slots', { from_time: cur_time.format('HH:mm:ss'), to_time: to_time.format('HH:mm:ss'), @@ -76,10 +77,11 @@ frappe.ui.form.on('Practitioner Schedule', { } return overlap; } - function add_slots(week_day){ + + function add_slots(week_day) { let cur_time = moment(values.from_time, 'HH:mm:ss'); let end_time = moment(values.to_time, 'HH:mm:ss'); - if(check_overlap_or_add_slot(week_day, cur_time, end_time, false)){ + if (check_overlap_or_add_slot(week_day, cur_time, end_time, false)) { frappe.confirm(__('Schedules for {0} overlaps, do you want to proceed after skiping overlaped slots ?', [week_day]), function() { // if Yes @@ -88,21 +90,22 @@ frappe.ui.form.on('Practitioner Schedule', { function() { // if No frappe.show_alert({ - message:__('Slots for {0} are not added to the schedule', [week_day]), - indicator:'red' + message: __('Slots for {0} are not added to the schedule', [week_day]), + indicator: 'red' }); } ); - } - else{ + } else { check_overlap_or_add_slot(week_day, cur_time, end_time, true); } } + frm.refresh_field('time_slots'); - if(slot_added){ + + if (slot_added) { frappe.show_alert({ - message:__('Time slots added'), - indicator:'green' + message: __('Time slots added'), + indicator: 'green' }); } } diff --git a/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.json b/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.json index 08a1b86969..cff100cc70 100644 --- a/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.json +++ b/erpnext/healthcare/doctype/practitioner_schedule/practitioner_schedule.json @@ -1,160 +1,71 @@ { - "allow_copy": 0, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 1, - "autoname": "field:schedule_name", - "beta": 1, - "creation": "2017-05-03 17:28:03.926787", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "allow_import": 1, + "allow_rename": 1, + "autoname": "field:schedule_name", + "beta": 1, + "creation": "2017-05-03 17:28:03.926787", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "disabled", + "schedule_details_section", + "schedule_name", + "time_slots" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "schedule_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Schedule Name", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "schedule_name", + "fieldtype": "Data", + "ignore_xss_filter": 1, + "in_list_view": 1, + "label": "Schedule Name", + "reqd": 1, + "unique": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "time_slots", - "fieldtype": "Table", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Time Slots", - "length": 0, - "no_copy": 0, - "options": "Healthcare Schedule Time Slot", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "time_slots", + "fieldtype": "Table", + "label": "Time Slots", + "options": "Healthcare Schedule Time Slot" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "disabled", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Disabled", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "default": "0", + "fieldname": "disabled", + "fieldtype": "Check", + "label": "Disabled", + "print_hide": 1 + }, + { + "fieldname": "schedule_details_section", + "fieldtype": "Section Break", + "label": "Schedule Details" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-06-29 14:55:34.795995", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Practitioner Schedule", - "name_case": "", - "owner": "rmehta@gmail.com", + ], + "links": [], + "modified": "2020-01-31 12:21:45.975488", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Practitioner Schedule", + "owner": "rmehta@gmail.com", "permissions": [ { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Healthcare Administrator", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Healthcare Administrator", + "share": 1, "write": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "show_name_in_global_search": 1, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0 + ], + "restrict_to_domain": "Healthcare", + "show_name_in_global_search": 1, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.json b/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.json index 236c2b8402..e4c01d79c1 100644 --- a/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.json +++ b/erpnext/healthcare/doctype/procedure_prescription/procedure_prescription.json @@ -1,338 +1,99 @@ { - "allow_copy": 1, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 1, - "creation": "2017-11-17 15:52:48.324157", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "document_type": "", - "editable_grid": 1, - "engine": "InnoDB", + "actions": [], + "allow_copy": 1, + "beta": 1, + "creation": "2017-11-17 15:52:48.324157", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "procedure", + "procedure_name", + "department", + "practitioner", + "date", + "comments", + "appointment_booked", + "procedure_created", + "invoiced" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "procedure", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Procedure", - "length": 0, - "no_copy": 0, - "options": "Clinical Procedure Template", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "procedure", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Clinical Procedure", + "options": "Clinical Procedure Template", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "procedure.template", - "fieldname": "procedure_name", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Procedure Name", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "procedure.template", + "fieldname": "procedure_name", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Procedure Name" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "department", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Department", - "length": 0, - "no_copy": 0, - "options": "Medical Department", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "procedure.medical_department", + "fieldname": "department", + "fieldtype": "Link", + "label": "Department", + "options": "Medical Department" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "practitioner", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Referral", - "length": 0, - "no_copy": 0, - "options": "Healthcare Practitioner", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "practitioner", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Referring Practitioner", + "options": "Healthcare Practitioner" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "date", - "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "Date" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "comments", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Comments", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "comments", + "fieldtype": "Data", + "label": "Comments" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "appointment_booked", - "fieldtype": "Check", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Appointment Booked", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "appointment_booked", + "fieldtype": "Check", + "hidden": 1, + "label": "Appointment Booked", + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "procedure_created", - "fieldtype": "Check", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Procedure Created", - "length": 0, - "no_copy": 1, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "procedure_created", + "fieldtype": "Check", + "hidden": 1, + "label": "Procedure Created", + "no_copy": 1, + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fieldname": "invoiced", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Invoiced", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "default": "0", + "fieldname": "invoiced", + "fieldtype": "Check", + "label": "Invoiced", + "read_only": 1, + "search_index": 1 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 0, - "issingle": 0, - "istable": 1, - "max_attachments": 0, - "modified": "2018-11-04 03:33:35.939816", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Procedure Prescription", - "name_case": "", - "owner": "Administrator", - "permissions": [], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "show_name_in_global_search": 0, - "sort_field": "modified", - "sort_order": "DESC", - "track_changes": 1, - "track_seen": 0, - "track_views": 0 + ], + "istable": 1, + "links": [], + "modified": "2020-02-26 15:42:33.988081", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Procedure Prescription", + "owner": "Administrator", + "permissions": [], + "restrict_to_domain": "Healthcare", + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1 } \ No newline at end of file diff --git a/erpnext/healthcare/doctype/sample_collection/sample_collection.js b/erpnext/healthcare/doctype/sample_collection/sample_collection.js index 9934ce4845..2f5278b2d5 100644 --- a/erpnext/healthcare/doctype/sample_collection/sample_collection.js +++ b/erpnext/healthcare/doctype/sample_collection/sample_collection.js @@ -3,7 +3,7 @@ frappe.ui.form.on('Sample Collection', { refresh: function(frm) { - if(frappe.defaults.get_default("require_sample_collection")){ + if(frappe.defaults.get_default("create_sample_collection_for_lab_test")){ frm.add_custom_button(__("View Lab Tests"), function() { frappe.route_options = {"sample": frm.doc.name}; frappe.set_route("List", "Lab Test"); diff --git a/erpnext/healthcare/doctype/sample_collection/sample_collection.json b/erpnext/healthcare/doctype/sample_collection/sample_collection.json index 783fc3d044..39cead8862 100644 --- a/erpnext/healthcare/doctype/sample_collection/sample_collection.json +++ b/erpnext/healthcare/doctype/sample_collection/sample_collection.json @@ -1,687 +1,199 @@ { - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 1, - "allow_rename": 0, - "autoname": "naming_series:", - "beta": 1, - "creation": "2016-04-05 15:58:18.076977", - "custom": 0, - "default_print_format": "", - "docstatus": 0, - "doctype": "DocType", - "document_type": "Document", - "editable_grid": 0, + "actions": [], + "allow_copy": 1, + "allow_import": 1, + "autoname": "naming_series:", + "beta": 1, + "creation": "2016-04-05 15:58:18.076977", + "doctype": "DocType", + "document_type": "Document", + "engine": "InnoDB", + "field_order": [ + "inpatient_record", + "naming_series", + "invoiced", + "patient", + "column_break_4", + "patient_age", + "patient_sex", + "company", + "section_break_6", + "sample", + "sample_uom", + "sample_qty", + "column_break_10", + "collected_by", + "collected_time", + "num_print", + "amended_from", + "section_break_15", + "sample_details" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "patient.inpatient_record", - "fieldname": "inpatient_record", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Inpatient Record", - "length": 0, - "no_copy": 0, - "options": "Inpatient Record", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "patient.inpatient_record", + "fieldname": "inpatient_record", + "fieldtype": "Link", + "label": "Inpatient Record", + "options": "Inpatient Record", + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "default": "", - "fieldname": "naming_series", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Series", - "length": 0, - "no_copy": 1, - "options": "HLC-SC-.YYYY.-", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "bold": 1, + "fieldname": "naming_series", + "fieldtype": "Select", + "label": "Series", + "no_copy": 1, + "options": "HLC-SC-.YYYY.-", + "print_hide": 1, + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "invoiced", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Invoiced", - "length": 0, - "no_copy": 1, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "invoiced", + "fieldtype": "Check", + "label": "Invoiced", + "no_copy": 1, + "read_only": 1, + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "inpatient_record.patient", - "fieldname": "patient", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 1, - "label": "Patient", - "length": 0, - "no_copy": 0, - "options": "Patient", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "inpatient_record.patient", + "fieldname": "patient", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "in_standard_filter": 1, + "label": "Patient", + "options": "Patient", + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_4", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_4", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "patient_age", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Age", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "patient_age", + "fieldtype": "Data", + "label": "Age" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "patient.sex", - "fieldname": "patient_sex", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Gender", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "patient.sex", + "fieldname": "patient_sex", + "fieldtype": "Data", + "label": "Gender" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "company", - "fieldtype": "Link", - "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Company", - "length": 0, - "no_copy": 0, - "options": "Company", - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "company", + "fieldtype": "Link", + "hidden": 1, + "label": "Company", + "options": "Company", + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_6", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "section_break_6", + "fieldtype": "Section Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sample", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Sample", - "length": 0, - "no_copy": 0, - "options": "Lab Test Sample", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 1, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "sample", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Sample", + "options": "Lab Test Sample", + "reqd": 1, + "search_index": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fetch_from": "sample.sample_uom", - "fieldname": "sample_uom", - "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "UOM", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fetch_from": "sample.sample_uom", + "fieldname": "sample_uom", + "fieldtype": "Data", + "in_list_view": 1, + "label": "UOM" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "0", - "fieldname": "sample_quantity", - "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Quantity", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_10", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_10", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "collected_by", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "label": "Collected By", + "options": "User" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "collected_by", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Collected By", - "length": 0, - "no_copy": 0, - "options": "User", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "collected_time", + "fieldtype": "Datetime", + "label": "Collected Time" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "collected_time", - "fieldtype": "Datetime", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Collected Time", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "allow_on_submit": 1, + "default": "1", + "fieldname": "num_print", + "fieldtype": "Int", + "label": "No. of print", + "print_hide": 1, + "report_hide": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 1, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "1", - "fieldname": "num_print", - "fieldtype": "Int", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "No. of print", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "amended_from", + "fieldtype": "Link", + "label": "Amended From", + "no_copy": 1, + "options": "Sample Collection", + "print_hide": 1, + "read_only": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "amended_from", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Amended From", - "length": 0, - "no_copy": 1, - "options": "Sample Collection", - "permlevel": 0, - "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "section_break_15", + "fieldtype": "Section Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "section_break_15", - "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "fieldname": "sample_qty", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Quantity" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "sample_collection_details", - "fieldtype": "Long Text", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Collection Details", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldname": "sample_details", + "fieldtype": "Long Text", + "ignore_xss_filter": 1, + "label": "Collection Details" } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, - "is_submittable": 1, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-08-21 14:44:39.128989", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Sample Collection", - "name_case": "", - "owner": "Administrator", + ], + "is_submittable": 1, + "links": [], + "modified": "2020-03-25 16:55:52.376834", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Sample Collection", + "owner": "Administrator", "permissions": [ { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 0, - "email": 1, - "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 1, - "read": 1, - "report": 1, - "role": "Laboratory User", - "set_user_permissions": 0, - "share": 1, - "submit": 1, + "amend": 1, + "cancel": 1, + "create": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "Laboratory User", + "share": 1, + "submit": 1, "write": 1 } - ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, - "restrict_to_domain": "Healthcare", - "search_fields": "patient, sample", - "show_name_in_global_search": 1, - "sort_field": "modified", - "sort_order": "DESC", - "title_field": "patient", - "track_changes": 1, - "track_seen": 1, - "track_views": 0 -} + ], + "restrict_to_domain": "Healthcare", + "search_fields": "patient, sample", + "show_name_in_global_search": 1, + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "patient", + "track_changes": 1, + "track_seen": 1 +} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/vital_signs/vital_signs.js b/erpnext/healthcare/doctype/vital_signs/vital_signs.js index a5f9d61295..78509e0323 100644 --- a/erpnext/healthcare/doctype/vital_signs/vital_signs.js +++ b/erpnext/healthcare/doctype/vital_signs/vital_signs.js @@ -1,49 +1,52 @@ // Copyright (c) 2016, ESS LLP and contributors // For license information, please see license.txt -frappe.ui.form.on("Vital Signs", "height", function(frm) { - if(frm.doc.height && frm.doc.weight){ - calculate_bmi(frm); +frappe.ui.form.on('Vital Signs', { + height: function(frm) { + if (frm.doc.height && frm.doc.weight) { + calculate_bmi(frm); + } + }, + + weight: function(frm) { + if (frm.doc.height && frm.doc.weight) { + calculate_bmi(frm); + } + }, + + bp_systolic: function(frm) { + if (frm.doc.bp_systolic && frm.doc.bp_diastolic) { + set_bp(frm); + } + }, + + bp_diastolic: function(frm) { + if (frm.doc.bp_systolic && frm.doc.bp_diastolic) { + set_bp(frm); + } } }); -frappe.ui.form.on("Vital Signs", "weight", function(frm) { - if(frm.doc.height && frm.doc.weight){ - calculate_bmi(frm); - } -}); - -var calculate_bmi = function(frm){ +let calculate_bmi = function(frm){ // Reference https://en.wikipedia.org/wiki/Body_mass_index // bmi = weight (in Kg) / height * height (in Meter) - var bmi = (frm.doc.weight/(frm.doc.height*frm.doc.height)).toFixed(2); - var bmi_note = null; - if(bmi<18.5){ - bmi_note = "Underweight"; - }else if(bmi>=18.5 && bmi<25){ - bmi_note = "Normal"; - }else if(bmi>=25 && bmi<30){ - bmi_note = "Overweight"; - }else if(bmi>=30){ - bmi_note = "Obese"; + let bmi = (frm.doc.weight / (frm.doc.height * frm.doc.height)).toFixed(2); + let bmi_note = null; + + if (bmi<18.5) { + bmi_note = 'Underweight'; + } else if (bmi>=18.5 && bmi<25) { + bmi_note = 'Normal'; + } else if (bmi>=25 && bmi<30) { + bmi_note = 'Overweight'; + } else if (bmi>=30) { + bmi_note = 'Obese'; } - frappe.model.set_value(frm.doctype,frm.docname, "bmi", bmi); - frappe.model.set_value(frm.doctype,frm.docname, "nutrition_note", bmi_note); + frappe.model.set_value(frm.doctype,frm.docname, 'bmi', bmi); + frappe.model.set_value(frm.doctype,frm.docname, 'nutrition_note', bmi_note); }; -frappe.ui.form.on("Vital Signs", "bp_systolic", function(frm) { - if(frm.doc.bp_systolic && frm.doc.bp_diastolic){ - set_bp(frm); - } -}); - -frappe.ui.form.on("Vital Signs", "bp_diastolic", function(frm) { - if(frm.doc.bp_systolic && frm.doc.bp_diastolic){ - set_bp(frm); - } -}); - -var set_bp = function(frm){ - var bp = frm.doc.bp_systolic+"/"+frm.doc.bp_diastolic+" mmHg"; - frappe.model.set_value(frm.doctype,frm.docname, "bp", bp); +let set_bp = function(frm){ + let bp = frm.doc.bp_systolic+ '/' + frm.doc.bp_diastolic + ' mmHg'; + frappe.model.set_value(frm.doctype,frm.docname, 'bp', bp); }; diff --git a/erpnext/healthcare/doctype/vital_signs/vital_signs.json b/erpnext/healthcare/doctype/vital_signs/vital_signs.json index 1503f835a4..75726dbe07 100644 --- a/erpnext/healthcare/doctype/vital_signs/vital_signs.json +++ b/erpnext/healthcare/doctype/vital_signs/vital_signs.json @@ -1,991 +1,273 @@ { + "actions": [], "allow_copy": 1, - "allow_events_in_timeline": 0, - "allow_guest_to_view": 0, "allow_import": 1, - "allow_rename": 0, "beta": 1, "creation": "2017-02-02 11:00:24.853005", - "custom": 0, - "docstatus": 0, "doctype": "DocType", - "document_type": "", "editable_grid": 1, "engine": "InnoDB", + "field_order": [ + "inpatient_record", + "patient", + "patient_name", + "appointment", + "encounter", + "column_break_2", + "signs_date", + "signs_time", + "sb_vs", + "temperature", + "pulse", + "respiratory_rate", + "tongue", + "abdomen", + "column_break_8", + "reflexes", + "bp_systolic", + "bp_diastolic", + "bp", + "vital_signs_note", + "sb_nutrition_values", + "height", + "weight", + "bmi", + "column_break_14", + "nutrition_note", + "company", + "amended_from" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fetch_from": "patient.inpatient_record", "fieldname": "inpatient_record", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Inpatient Record", - "length": 0, - "no_copy": 0, "options": "Inpatient Record", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fetch_from": "inpatient_record.patient", "fieldname": "patient", "fieldtype": "Link", - "hidden": 0, "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, "in_standard_filter": 1, "label": "Patient", - "length": 0, - "no_copy": 0, "options": "Patient", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "reqd": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fetch_from": "patient.patient_name", "fieldname": "patient_name", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Patient Name", - "length": 0, - "no_copy": 0, - "options": "", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "appointment", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, "in_filter": 1, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Appointment", - "length": 0, - "no_copy": 1, "options": "Patient Appointment", - "permlevel": 0, - "precision": "", "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "encounter", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, "in_filter": 1, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Patient Encounter", - "length": 0, "no_copy": 1, "options": "Patient Encounter", - "permlevel": 0, - "precision": "", "print_hide": 1, - "print_hide_if_no_value": 0, "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 1, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "report_hide": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "column_break_2", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "Today", "fieldname": "signs_date", "fieldtype": "Date", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Date", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "reqd": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", "fieldname": "signs_time", "fieldtype": "Time", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Time", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "reqd": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "sb_vs", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Vital Signs", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Vital Signs" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "description": "Presence of a fever (temp > 38.5 \u00b0C/101.3 \u00b0F or sustained temp > 38 \u00b0C/100.4 \u00b0F)", "fieldname": "temperature", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, - "label": "Body Temperature", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Body Temperature" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "description": "Adults' pulse rate is anywhere between 50 and 80 beats per minute.", "fieldname": "pulse", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, - "label": "Heart Rate / Pulse", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Heart Rate / Pulse" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "description": "Normal reference range for an adult is 16\u201320 breaths/minute (RCP 2012)", "fieldname": "respiratory_rate", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, - "label": "Respiratory rate", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Respiratory rate" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "tongue", "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Tongue", - "length": 0, - "no_copy": 0, - "options": "\nCoated\nVery Coated\nNormal\nFurry\nCuts", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "\nCoated\nVery Coated\nNormal\nFurry\nCuts" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "abdomen", "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Abdomen", - "length": 0, - "no_copy": 0, - "options": "\nNormal\nBloated\nFull\nFluid\nConstipated", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "\nNormal\nBloated\nFull\nFluid\nConstipated" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "column_break_8", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "reflexes", "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Reflexes", - "length": 0, - "no_copy": 0, - "options": "\nNormal\nHyper\nVery Hyper\nOne Sided", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "\nNormal\nHyper\nVery Hyper\nOne Sided" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "bp_systolic", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, - "label": "Blood Pressure (systolic)", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Blood Pressure (systolic)" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "", "fieldname": "bp_diastolic", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, - "label": "Blood Pressure (diastolic)", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Blood Pressure (diastolic)" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "description": "Normal resting blood pressure in an adult is approximately 120 mmHg systolic, and 80 mmHg diastolic, abbreviated \"120/80 mmHg\"", "fieldname": "bp", "fieldtype": "Data", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Blood Pressure", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "vital_signs_note", "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Notes", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Notes" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "sb_nutrition_values", "fieldtype": "Section Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Nutrition Values", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Nutrition Values" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "height", "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, - "label": "Height (In Meter)", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Height (In Meter)" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "weight", "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, - "label": "Weight (In Kilogram)", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Weight (In Kilogram)" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "default": "0.00", "fieldname": "bmi", "fieldtype": "Float", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, "in_list_view": 1, - "in_standard_filter": 0, "label": "BMI", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "column_break_14", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "fieldtype": "Column Break" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "nutrition_note", "fieldtype": "Small Text", - "hidden": 0, - "ignore_user_permissions": 0, "ignore_xss_filter": 1, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Notes", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "label": "Notes" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "company", "fieldtype": "Link", "hidden": 1, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Company", - "length": 0, - "no_copy": 0, - "options": "Company", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "options": "Company" }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, "fieldname": "amended_from", "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, "label": "Amended From", - "length": 0, "no_copy": 1, "options": "Vital Signs", - "permlevel": 0, "print_hide": 1, - "print_hide_if_no_value": 0, - "read_only": 1, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "read_only": 1 } ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "idx": 0, - "image_view": 0, - "in_create": 0, "is_submittable": 1, - "issingle": 0, - "istable": 0, - "max_attachments": 0, - "modified": "2018-11-23 14:14:05.933292", + "links": [], + "modified": "2020-03-04 17:19:29.549889", "modified_by": "Administrator", "module": "Healthcare", "name": "Vital Signs", - "name_case": "", "owner": "Administrator", "permissions": [ { - "amend": 0, "cancel": 1, "create": 1, "delete": 1, "email": 1, "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "Physician", - "set_user_permissions": 0, "share": 1, "submit": 1, "write": 1 }, { - "amend": 0, "cancel": 1, "create": 1, "delete": 1, "email": 1, "export": 1, - "if_owner": 0, - "import": 0, - "permlevel": 0, "print": 1, "read": 1, "report": 1, "role": "Nursing User", - "set_user_permissions": 0, "share": 1, "submit": 1, "write": 1 } ], - "quick_entry": 0, - "read_only": 0, - "read_only_onload": 0, "restrict_to_domain": "Healthcare", "search_fields": "patient, signs_date", "show_name_in_global_search": 1, @@ -993,6 +275,5 @@ "sort_order": "DESC", "title_field": "patient", "track_changes": 1, - "track_seen": 1, - "track_views": 0 + "track_seen": 1 } \ No newline at end of file diff --git a/erpnext/healthcare/doctype/vital_signs/vital_signs.py b/erpnext/healthcare/doctype/vital_signs/vital_signs.py index bf4dace22b..959e8504c4 100644 --- a/erpnext/healthcare/doctype/vital_signs/vital_signs.py +++ b/erpnext/healthcare/doctype/vital_signs/vital_signs.py @@ -6,6 +6,7 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document from frappe.utils import cstr +from frappe import _ class VitalSigns(Document): def on_submit(self): @@ -16,34 +17,35 @@ class VitalSigns(Document): def insert_vital_signs_to_medical_record(doc): subject = set_subject_field(doc) - medical_record = frappe.new_doc("Patient Medical Record") + medical_record = frappe.new_doc('Patient Medical Record') medical_record.patient = doc.patient medical_record.subject = subject - medical_record.status = "Open" + medical_record.status = 'Open' medical_record.communication_date = doc.signs_date - medical_record.reference_doctype = "Vital Signs" + medical_record.reference_doctype = 'Vital Signs' medical_record.reference_name = doc.name medical_record.reference_owner = doc.owner + medical_record.flags.ignore_mandatory = True medical_record.save(ignore_permissions=True) def delete_vital_signs_from_medical_record(doc): - medical_record_id = frappe.db.sql("select name from `tabPatient Medical Record` where reference_name=%s",(doc.name)) - if medical_record_id and medical_record_id[0][0]: - frappe.delete_doc("Patient Medical Record", medical_record_id[0][0]) + medical_record = frappe.db.get_value('Patient Medical Record', {'reference_name': doc.name}) + if medical_record: + frappe.delete_doc('Patient Medical Record', medical_record) def set_subject_field(doc): - subject = "" + subject = '' if(doc.temperature): - subject += "Temperature: \n"+ cstr(doc.temperature)+". " + subject += _('Temperature: ') + '\n'+ cstr(doc.temperature) + '. ' if(doc.pulse): - subject += "Pulse: \n"+ cstr(doc.pulse)+". " + subject += _('Pulse: ') + '\n' + cstr(doc.pulse) + '. ' if(doc.respiratory_rate): - subject += "Respiratory Rate: \n"+ cstr(doc.respiratory_rate)+". " + subject += _('Respiratory Rate: ') + '\n' + cstr(doc.respiratory_rate) + '. ' if(doc.bp): - subject += "BP: \n"+ cstr(doc.bp)+". " + subject += _('BP: ') + '\n' + cstr(doc.bp) + '. ' if(doc.bmi): - subject += "BMI: \n"+ cstr(doc.bmi)+". " + subject += _('BMI: ') + '\n' + cstr(doc.bmi) + '. ' if(doc.nutrition_note): - subject += "Note: \n"+ cstr(doc.nutrition_note)+". " + subject += _('Note: ') + '\n' + cstr(doc.nutrition_note) + '. ' return subject diff --git a/erpnext/healthcare/page/appointment_analytic/appointment_analytic.js b/erpnext/healthcare/page/appointment_analytic/appointment_analytic.js deleted file mode 100644 index 9f2e552efc..0000000000 --- a/erpnext/healthcare/page/appointment_analytic/appointment_analytic.js +++ /dev/null @@ -1,205 +0,0 @@ -frappe.pages['appointment-analytic'].on_page_load = function(wrapper) { - frappe.ui.make_app_page({ - parent: wrapper, - title: 'Appointment Analytics', - single_column: true - }); - new erpnext.AppointmentAnalytics(wrapper); - frappe.breadcrumbs.add("Medical"); -}; - -erpnext.AppointmentAnalytics = frappe.views.TreeGridReport.extend({ - init: function(wrapper) { - this._super({ - title: __("Appointment Analytics"), - parent: $(wrapper).find('.layout-main'), - page: wrapper.page, - doctypes: ["Patient Appointment", "Healthcare Practitioner", "Medical Department", "Appointment Type", "Patient"], - tree_grid: { show: true } - }); - - this.tree_grids = { - "Medical Department": { - label: __("Department"), - show: true, - item_key: "practitioner", - parent_field: "department", - formatter: function(item) { - return item.name; - } - }, - "Healthcare Practitioner": { - label: __("Healthcare Practitioner"), - show: true, - item_key: "practitioner", - formatter: function(item) { - return item.name; - } - }, - }; - }, - setup_columns: function() { - this.tree_grid = this.tree_grids[this.tree_type]; - - var std_columns = [ - {id: "name", name: this.tree_grid.label, field: "name", width: 300}, - {id: "total", name: "Total", field: "total", plot: false, - formatter: this.currency_formatter} - ]; - - this.make_date_range_columns(); - this.columns = std_columns.concat(this.columns); - }, - filters: [ - {fieldtype:"Select", label: __("Tree Type"), fieldname: "tree_type", - options:["Healthcare Practitioner", "Medical Department"], filter: function(val, item, opts, me) { - return me.apply_zero_filter(val, item, opts, me);}}, - {fieldtype:"Select", label: __("Status"), fieldname: "status", - options:[ - {label: __("Select Status"), value: "Select Status..."}, - {label: __("Open"), value: "Open"}, - {label: __("Closed"), value: "Closed"}, - {label: __("Pending"), value: "Pending"}, - {label: __("Scheduled"), value: "Scheduled"}, - {label: __("Cancelled"), value: "Cancelled"}]}, - {fieldtype:"Select", label: __("Type"), link:"Appointment Type", fieldname: "type", - default_value: __("Select Type...")}, - {fieldtype:"Select", label: __("Healthcare Practitioner"), link:"Healthcare Practitioner", fieldname: "practitioner", - default_value: __("Select Healthcare Practitioner..."), filter: function(val, item, opts) { - return val == opts.default_value || item.name == val || item._show; - }, link_formatter: {filter_input: "practitioner"}}, - {fieldtype:"Select", label: __("Department"), link:"Medical Department", fieldname: "department", - default_value: __("Select Department..."), filter: function(val, item, opts) { - return val == opts.default_value || item.department == val || item._show; - }, link_formatter: {filter_input: "department"}}, - {fieldtype:"Date", label: __("From Date"), fieldname: "from_date"}, - {fieldtype:"Date", label: __("To Date"), fieldname: "to_date"}, - {fieldtype:"Select", label: __("Range"), fieldname: "range", - options:[{label: __("Daily"), value: "Daily"}, {label: __("Weekly"), value: "Weekly"}, - {label: __("Monthly"), value: "Monthly"}, {label: __("Quarterly"), value: "Quarterly"}, - {label: __("Yearly"), value: "Yearly"}]} - ], - setup_filters: function() { - this._super(); - this.trigger_refresh_on_change(["tree_type", "practitioner", "department", "status", "type"]); - - // this.show_zero_check() - }, - init_filter_values: function() { - this._super(); - this.filter_inputs.range.val('Quarterly'); - }, - prepare_data: function() { - var me = this; - if (!this.tl) { - this.tl = frappe.report_dump.data["Patient Appointment"]; - } - if(!this.data || me.item_type != me.tree_type) { - var items = null; - if(me.tree_type=='Healthcare Practitioner') { - items = frappe.report_dump.data["Healthcare Practitioner"]; - } if(me.tree_type=='Medical Department') { - items = this.prepare_tree("Healthcare Practitioner", "Medical Department"); - } - me.item_type = me.tree_type; - me.parent_map = {}; - me.item_by_name = {}; - me.data = []; - - $.each(items, function(i, v) { - var d = copy_dict(v); - - me.data.push(d); - me.item_by_name[d.name] = d; - if(d[me.tree_grid.parent_field]) { - me.parent_map[d.name] = d[me.tree_grid.parent_field]; - } - me.reset_item_values(d); - }); - - this.set_indent(); - - - } else { - // otherwise, only reset values - $.each(this.data, function(i, d) { - me.reset_item_values(d); - }); - } - this.prepare_balances(); - if(me.tree_grid.show) { - this.set_totals(false); - this.update_groups(); - } else { - this.set_totals(true); - } - - - }, - prepare_balances: function() { - var me = this; - var from_date = frappe.datetime.str_to_obj(this.from_date); - var status = this.status; - var type = this.type; - var to_date = frappe.datetime.str_to_obj(this.to_date); - $.each(this.tl, function(i, tl) { - if (me.is_default('company') ? true : tl.company === me.company) { - - var date = frappe.datetime.str_to_obj(tl.appointment_date); - if (date >= from_date && date <= to_date) { - var item = me.item_by_name[tl[me.tree_grid.item_key]] || - me.item_by_name['Not Set']; - - var d = tl.appointment_date.split(" ")[0]; - if(status == "Select Status..." && type=="Select Type...") - { - item[me.column_map[d].field] += 1; - - }else if (status !== "Select Status..." && type == "Select Type..."){ - if(status === tl.status){item[me.column_map[d].field] += 1;} - }else if (status == "Select Status..." && type !== "Select Type..."){ - if(type === tl.appointment_type){item[me.column_map[d].field] += 1;} - }else { - if(type === tl.appointment_type && status === tl.status){item[me.column_map[d].field] += 1;} - } - } - } - }); - }, - update_groups: function() { - var me = this; - - $.each(this.data, function(i, item) { - var parent = me.parent_map[item.name]; - while(parent) { - var parent_group = me.item_by_name[parent]; - - $.each(me.columns, function(c, col) { - if (col.formatter == me.currency_formatter) { - parent_group[col.field] = - flt(parent_group[col.field]) - + flt(item[col.field]); - } - }); - parent = me.parent_map[parent]; - } - }); - }, - set_totals: function(sort) { - var me = this; - $.each(this.data, function(i, d) { - d.total = 0.0; - $.each(me.columns, function(i, col) { - if(col.formatter==me.currency_formatter && !col.hidden && col.field!="total") - d.total += d[col.field]; - }); - }); - - if(sort)this.data = this.data.sort(function(a, b) { return b.total - a.total; }); - - if(!this.checked) { - this.data[0].checked = true; - } - } - -}); diff --git a/erpnext/healthcare/page/appointment_analytic/appointment_analytic.json b/erpnext/healthcare/page/appointment_analytic/appointment_analytic.json deleted file mode 100644 index ac5ca1a266..0000000000 --- a/erpnext/healthcare/page/appointment_analytic/appointment_analytic.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "content": null, - "creation": "2016-08-18 12:29:52.497819", - "docstatus": 0, - "doctype": "Page", - "idx": 0, - "modified": "2018-08-06 11:40:53.082863", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "appointment-analytic", - "owner": "Administrator", - "page_name": "Appointment Analytics", - "restrict_to_domain": "Healthcare", - "roles": [ - { - "role": "Physician" - } - ], - "script": null, - "standard": "Yes", - "style": null, - "system_page": 0, - "title": "Appointment Analytics" -} \ No newline at end of file diff --git a/erpnext/healthcare/print_format/encounter_print/encounter_print.json b/erpnext/healthcare/print_format/encounter_print/encounter_print.json index 20e44b7904..ec1e0f202a 100644 --- a/erpnext/healthcare/print_format/encounter_print/encounter_print.json +++ b/erpnext/healthcare/print_format/encounter_print/encounter_print.json @@ -1,22 +1,22 @@ { - "align_labels_right": 0, - "creation": "2017-04-10 14:05:53.355863", - "custom_format": 1, - "disabled": 0, - "doc_type": "Patient Encounter", - "docstatus": 0, - "doctype": "Print Format", - "font": "Default", - "html": "
\n {% if letter_head and not no_letterhead -%}\n
{{ letter_head }}
\n
\n {% else %}\n
\n

{{doc.name}}

\n
\n {%- endif %}\n
\n
\n {% if doc.appointment %}\n\t
\n\t\t\t
\n\t\t\t\n\t\t\t
\n\t\t\t
\n\t\t\t: {{doc.appointment}}\n\t\t\t
\n\t\t
\n\t\t{%- endif -%}\n\n
\n\t\t
\n\t\t\t \n\t\t
\n {% if doc.patient %}\n\t\t
\n\t\t\t : {{doc.patient}}\n\t\t
\n {% else %}\n
\n\t\t\t : Patient Name\n\t\t
\n {%- endif -%}\n\t\t
\n\t
\n\t\t\t
\n\t\t\t\t\n\t\t\t
\n\t\t\t
\n\t\t\t : {{doc.patient_age}}\n\t\t\t
\n\t\t
\n\n
\n
\n\t\t\t\t\n\t\t\t
\n\t\t\t
\n\t\t\t : {{doc.patient_sex}}\n\t\t\t
\n
\n\n
\n
\n\n
\n\t
\n\t\t \n\t
\n {% if doc.practitioner %}\n\t
\n\t\t\t: {{doc.practitioner}}\n\t
\n {%- endif -%}\n\t
\n\n {% if doc.encounter_date %}\n\t
\n\t\t
\n\t\t\n\t\t
\n\t\t
\n\t\t: {{doc.encounter_date}}\n\t\t
\n
\n\t {%- endif -%}\n {% if doc.encounter_time %}\n\t
\n\t\t
\n\t\t\n\t\t
\n\t\t
\n\t\t: {{doc.encounter_time}}\n\t\t
\n
\n\t {%- endif -%}\n {% if doc.visit_department %}\n\t
\n\t\t
\n\t\t\n\t\t
\n\t\t
\n\t\t: {{doc.visit_department}}\n\t\t
\n
\n {%- endif -%}\n
\n\n
\n\n
\n
\n
\n {% if doc.symptoms_in_print%}\n {% if doc.symptoms %}\n Complaints:\n {{doc.symptoms}}\n \t
\n {%- endif -%}\n {%- endif -%}\n\n {% if doc.diagnosis_in_print%}\n {% if doc.diagnosis %}\n \t Diagnosis:\n {{doc.diagnosis}}\n
\n {%- endif -%}\n {%- endif -%}\n\n
\n\n
\n {% if doc.drug_prescription %}\n
\n Rx,\n \n \n \n\n {%- for row in doc.drug_prescription -%}\n \n \n \t\n \t\n \n \n\t {%- endfor -%}\n \n
\n {%- if row.drug_name -%}{{ row.drug_name }}{%- endif -%}\n \n {%- if row.dosage -%}{{ row.dosage }}{%- endif -%}\n \n {%- if row.period -%}{{ row.period }}{%- endif -%}\n\t\t \n\t\t\t
\n {%- if row.comment -%}{{ row.comment }}{%- endif -%}\n
\n\t\t
\n\n\n {%- endif -%}\n
\n\n\n
\n {% if doc.lab_test_prescription %}\n Investigations,\n \n \n \n\n {%- for row in doc.lab_test_prescription -%}\n \n \n \n \n\n\t {%- endfor -%}\n \n
\n {%- if row.lab_test_name -%}{{ row.lab_test_name }}{%- endif -%}\n \n\t\t\t
\n {%- if row.lab_test_comment -%}{{ row.lab_test_comment }}{%- endif -%}\n
\n\t\t
\n\n\n {%- endif -%}\n
\n
\n {% if doc.encounter_comment %}\n
\n {{doc.encounter_comment}}\n {%- endif -%}\n
\n", - "idx": 0, - "line_breaks": 0, - "modified": "2018-09-04 11:52:54.473702", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Encounter Print", - "owner": "Administrator", - "print_format_builder": 0, - "print_format_type": "Server", - "show_section_headings": 0, + "align_labels_right": 0, + "creation": "2017-04-10 14:05:53.355863", + "custom_format": 1, + "disabled": 0, + "doc_type": "Patient Encounter", + "docstatus": 0, + "doctype": "Print Format", + "font": "Default", + "html": "
\n {% if letter_head and not no_letterhead -%}\n
{{ letter_head }}
\n
\n {% else %}\n
\n

{{doc.name}}

\n
\n {%- endif %}\n
\n
\n {% if doc.appointment %}\n\t
\n\t\t\t
\n\t\t\t\n\t\t\t
\n\t\t\t
\n\t\t\t: {{doc.appointment}}\n\t\t\t
\n\t\t
\n\t\t{%- endif -%}\n\n
\n\t\t
\n\t\t\t \n\t\t
\n {% if doc.patient %}\n\t\t
\n\t\t\t : {{doc.patient}}\n\t\t
\n {% else %}\n
\n\t\t\t : Patient Name\n\t\t
\n {%- endif -%}\n\t\t
\n\t
\n\t\t\t
\n\t\t\t\t\n\t\t\t
\n\t\t\t
\n\t\t\t : {{doc.patient_age}}\n\t\t\t
\n\t\t
\n\n
\n
\n\t\t\t\t\n\t\t\t
\n\t\t\t
\n\t\t\t : {{doc.patient_sex}}\n\t\t\t
\n
\n\n
\n
\n\n
\n\t
\n\t\t \n\t
\n {% if doc.practitioner %}\n\t
\n\t\t\t: {{doc.practitioner}}\n\t
\n {%- endif -%}\n\t
\n\n {% if doc.encounter_date %}\n\t
\n\t\t
\n\t\t\n\t\t
\n\t\t
\n\t\t: {{doc.encounter_date}}\n\t\t
\n
\n\t {%- endif -%}\n {% if doc.encounter_time %}\n\t
\n\t\t
\n\t\t\n\t\t
\n\t\t
\n\t\t: {{doc.encounter_time}}\n\t\t
\n
\n\t {%- endif -%}\n {% if doc.medical_department %}\n\t
\n\t\t
\n\t\t\n\t\t
\n\t\t
\n\t\t: {{doc.visit_department}}\n\t\t
\n
\n {%- endif -%}\n
\n\n
\n\n
\n
\n
\n {% if doc.symptoms_in_print%}\n {% if doc.symptoms %}\n Complaints:\n {{doc.symptoms}}\n \t
\n {%- endif -%}\n {%- endif -%}\n\n {% if doc.diagnosis_in_print%}\n {% if doc.diagnosis %}\n \t Diagnosis:\n {{doc.diagnosis}}\n
\n {%- endif -%}\n {%- endif -%}\n\n
\n\n
\n {% if doc.drug_prescription %}\n
\n Rx,\n \n \n \n\n {%- for row in doc.drug_prescription -%}\n \n \n \t\n \t\n \n \n\t {%- endfor -%}\n \n
\n {%- if row.drug_name -%}{{ row.drug_name }}{%- endif -%}\n \n {%- if row.dosage -%}{{ row.dosage }}{%- endif -%}\n \n {%- if row.period -%}{{ row.period }}{%- endif -%}\n\t\t \n\t\t\t
\n {%- if row.comment -%}{{ row.comment }}{%- endif -%}\n
\n\t\t
\n\n\n {%- endif -%}\n
\n\n\n
\n {% if doc.lab_test_prescription %}\n Investigations,\n \n \n \n\n {%- for row in doc.lab_test_prescription -%}\n \n \n \n \n\n\t {%- endfor -%}\n \n
\n {%- if row.lab_test_name -%}{{ row.lab_test_name }}{%- endif -%}\n \n\t\t\t
\n {%- if row.lab_test_comment -%}{{ row.lab_test_comment }}{%- endif -%}\n
\n\t\t
\n\n\n {%- endif -%}\n
\n
\n {% if doc.encounter_comment %}\n
\n {{doc.encounter_comment}}\n {%- endif -%}\n
\n", + "idx": 0, + "line_breaks": 0, + "modified": "2018-09-04 11:52:54.473702", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Encounter Print", + "owner": "Administrator", + "print_format_builder": 0, + "print_format_type": "Server", + "show_section_headings": 0, "standard": "Yes" } \ No newline at end of file diff --git a/erpnext/healthcare/print_format/lab_test_print/lab_test_print.json b/erpnext/healthcare/print_format/lab_test_print/lab_test_print.json index 6badc6f82d..e8e95d8439 100644 --- a/erpnext/healthcare/print_format/lab_test_print/lab_test_print.json +++ b/erpnext/healthcare/print_format/lab_test_print/lab_test_print.json @@ -1,22 +1,22 @@ { - "align_labels_right": 0, - "creation": "2017-04-24 15:38:45.332473", - "custom_format": 1, - "disabled": 0, - "doc_type": "Lab Test", - "docstatus": 0, - "doctype": "Print Format", - "font": "Default", - "html": "
\n {% if letter_head and not no_letterhead -%}\n
{{ letter_head }}
\n
\n {%- endif %}\n\n {% if (doc.docstatus != 1) %}\n Lab Tests have to be Submitted for Print .. !\n {% elif (frappe.db.get_value(\"Healthcare Settings\", \"None\", \"require_test_result_approval\") == '1' and doc.approval_status != \"Approved\") %}\n Lab Tests have to be Approved for Print .. !\n {%- else -%}\n
\n
\n\n
\n
\n \n
\n {% if doc.patient %}\n
\n : {{doc.patient}}\n
\n {% else %}\n
\n : Patient Name\n
\n {%- endif -%}\n
\n\n
\n
\n \n
\n
\n : {{doc.patient_age}}\n
\n
\n\n
\n
\n \n
\n
\n : {{doc.patient_sex}}\n
\n
\n\n
\n\n
\n\n
\n
\n \n
\n {% if doc.practitioner %}\n
\n : {{doc.practitioner}}\n
\n {%- endif -%}\n
\n\n {% if doc.sample_date %}\n
\n
\n \n
\n
\n : {{doc.sample_date}}\n
\n
\n {%- endif -%}\n\n {% if doc.result_date %}\n
\n
\n \n
\n
\n : {{doc.result_date}}\n
\n
\n {%- endif -%}\n\n
\n\n
\n\n
\n

Department of {{doc.department}}

\n
\n\n \n \n {%- if doc.normal_test_items -%}\n \n \n \n \n \n\n {%- if doc.normal_test_items|length > 1 %}\n \n {%- endif -%}\n\n {%- for row in doc.normal_test_items -%}\n \n \n\n \n\n \n \n\n {%- endfor -%}\n {%- endif -%}\n \n
Name of TestResultNormal Range
{{ doc.lab_test_name }}
\n {%- if doc.normal_test_items|length > 1 %}  {%- endif -%}\n {%- if row.lab_test_name -%}{{ row.lab_test_name }}\n {%- else -%}   {%- endif -%}\n {%- if row.lab_test_event -%}   {{ row.lab_test_event }}{%- endif -%}\n \n {%- if row.result_value -%}{{ row.result_value }}{%- endif -%} \n {%- if row.lab_test_uom -%}{{ row.lab_test_uom }}{%- endif -%}\n \n
\n {%- if row.normal_range -%}{{ row.normal_range }}{%- endif -%}\n
\n
\n\n \n \n {%- if doc.special_test_items -%}\n \n \n \n \n \n {%- for row in doc.special_test_items -%}\n \n \n \n \n\n {%- endfor -%}\n {%- endif -%}\n\n {%- if doc.sensitivity_test_items -%}\n \n \n \n \n {%- for row in doc.sensitivity_test_items -%}\n \n \n \n \n\n {%- endfor -%}\n {%- endif -%}\n\n \n
Name of TestResult
{{ doc.lab_test_name }}
  {{ row.lab_test_particulars }} \n {%- if row.result_value -%}{{ row.result_value }}{%- endif -%}\n
AntibioticSensitivity
{{ row.antibiotic }} {{ row.antibiotic_sensitivity }}
\n {%- endif -%}\n\n
\n {%- if (frappe.db.get_value(\"Healthcare Settings\", \"None\", \"employee_name_and_designation_in_print\") == '1') -%}\n
{{doc.employee_name}}
\n
{{doc.employee_designation}}
\n {%- else -%}\n
{{frappe.db.get_value(\"Healthcare Settings\", \"None\", \"custom_signature_in_print\") }}
\n {%- endif -%}\n
\n
\n", - "idx": 0, - "line_breaks": 0, - "modified": "2018-09-04 12:03:47.066918", - "modified_by": "Administrator", - "module": "Healthcare", - "name": "Lab Test Print", - "owner": "Administrator", - "print_format_builder": 0, - "print_format_type": "Server", - "show_section_headings": 0, + "align_labels_right": 0, + "creation": "2017-04-24 15:38:45.332473", + "custom_format": 1, + "disabled": 0, + "doc_type": "Lab Test", + "docstatus": 0, + "doctype": "Print Format", + "font": "Default", + "html": "
\n {% if letter_head and not no_letterhead -%}\n
{{ letter_head }}
\n
\n {%- endif %}\n\n {% if (doc.docstatus != 1) %}\n Lab Tests have to be Submitted for Print .. !\n {% elif (frappe.db.get_value(\"Healthcare Settings\", \"None\", \"lab_test_approval_required\") == '1' and doc.approval_status != \"Approved\") %}\n Lab Tests have to be Approved for Print .. !\n {%- else -%}\n
\n
\n\n
\n
\n \n
\n {% if doc.patient %}\n
\n : {{doc.patient}}\n
\n {% else %}\n
\n : Patient Name\n
\n {%- endif -%}\n
\n\n
\n
\n \n
\n
\n : {{doc.patient_age}}\n
\n
\n\n
\n
\n \n
\n
\n : {{doc.patient_sex}}\n
\n
\n\n
\n\n
\n\n
\n
\n \n
\n {% if doc.practitioner %}\n
\n : {{doc.practitioner}}\n
\n {%- endif -%}\n
\n\n {% if doc.sample_date %}\n
\n
\n \n
\n
\n : {{doc.sample_date}}\n
\n
\n {%- endif -%}\n\n {% if doc.result_date %}\n
\n
\n \n
\n
\n : {{doc.result_date}}\n
\n
\n {%- endif -%}\n\n
\n\n
\n\n
\n

Department of {{doc.department}}

\n
\n\n \n \n {%- if doc.normal_test_items -%}\n \n \n \n \n \n\n {%- if doc.normal_test_items|length > 1 %}\n \n {%- endif -%}\n\n {%- for row in doc.normal_test_items -%}\n \n \n\n \n\n \n \n\n {%- endfor -%}\n {%- endif -%}\n \n
Name of TestResultNormal Range
{{ doc.lab_test_name }}
\n {%- if doc.normal_test_items|length > 1 %}  {%- endif -%}\n {%- if row.lab_test_name -%}{{ row.lab_test_name }}\n {%- else -%}   {%- endif -%}\n {%- if row.lab_test_event -%}   {{ row.lab_test_event }}{%- endif -%}\n \n {%- if row.result_value -%}{{ row.result_value }}{%- endif -%} \n {%- if row.lab_test_uom -%}{{ row.lab_test_uom }}{%- endif -%}\n \n
\n {%- if row.normal_range -%}{{ row.normal_range }}{%- endif -%}\n
\n
\n\n \n \n {%- if doc.special_test_items -%}\n \n \n \n \n \n {%- for row in doc.special_test_items -%}\n \n \n \n \n\n {%- endfor -%}\n {%- endif -%}\n\n {%- if doc.sensitivity_test_items -%}\n \n \n \n \n {%- for row in doc.sensitivity_test_items -%}\n \n \n \n \n\n {%- endfor -%}\n {%- endif -%}\n\n \n
Name of TestResult
{{ doc.lab_test_name }}
  {{ row.lab_test_particulars }} \n {%- if row.result_value -%}{{ row.result_value }}{%- endif -%}\n
AntibioticSensitivity
{{ row.antibiotic }} {{ row.antibiotic_sensitivity }}
\n {%- endif -%}\n\n
\n {%- if (frappe.db.get_value(\"Healthcare Settings\", \"None\", \"employee_name_and_designation_in_print\") == '1') -%}\n
{{doc.employee_name}}
\n
{{doc.employee_designation}}
\n {%- else -%}\n
{{frappe.db.get_value(\"Healthcare Settings\", \"None\", \"custom_signature_in_print\") }}
\n {%- endif -%}\n
\n
\n", + "idx": 0, + "line_breaks": 0, + "modified": "2018-09-04 12:03:47.066918", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Lab Test Print", + "owner": "Administrator", + "print_format_builder": 0, + "print_format_type": "Server", + "show_section_headings": 0, "standard": "Yes" } \ No newline at end of file diff --git a/erpnext/healthcare/report/patient_appointment_analytics/__init__.py b/erpnext/healthcare/report/patient_appointment_analytics/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.js b/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.js new file mode 100644 index 0000000000..18d252ede1 --- /dev/null +++ b/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.js @@ -0,0 +1,128 @@ +// 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 + } + ], + after_datatable_render: function(datatable_obj) { + $(datatable_obj.wrapper).find(".dt-row-0").find('input[type=checkbox]').click(); + }, + get_datatable_options(options) { + return Object.assign(options, { + checkboxColumn: true, + events: { + onCheckRow: function(data) { + row_name = data[2].content; + length = data.length; + + row_values = data.slice(3,length-1).map(function (column) { + return column.content; + }) + + entry = { + 'name': row_name, + 'values': row_values + } + + let raw_data = frappe.query_report.chart.data; + let new_datasets = raw_data.datasets; + + let found = false; + for (let i=0; i < new_datasets.length;i++) { + if (new_datasets[i].name == row_name) { + found = true; + new_datasets.splice(i,1); + break; + } + } + + if (!found) { + new_datasets.push(entry); + } + + let new_data = { + labels: raw_data.labels, + datasets: new_datasets + } + + setTimeout(() => { + frappe.query_report.chart.update(new_data) + }, 500) + + + setTimeout(() => { + frappe.query_report.chart.draw(true); + }, 1000) + + frappe.query_report.raw_chart_data = new_data; + }, + } + }) + }, +}; diff --git a/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.json b/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.json new file mode 100644 index 0000000000..64750c012f --- /dev/null +++ b/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.json @@ -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" + } + ] +} \ No newline at end of file diff --git a/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.py b/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.py new file mode 100644 index 0000000000..9c35dbb3ea --- /dev/null +++ b/erpnext/healthcare/report/patient_appointment_analytics/patient_appointment_analytics.py @@ -0,0 +1,194 @@ +# 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): + """Patient Appointment Analytics Report.""" + 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() + + 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': 'Int', + 'width': 120 + }) + + self.columns.append({ + 'label': _('Total'), + 'fieldname': 'total', + 'fieldtype': 'Int', + '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_period(self, appointment_date): + if self.filters.range == 'Weekly': + period = 'Week ' + str(appointment_date.isocalendar()[1]) + elif self.filters.range == 'Monthly': + period = str(self.months[appointment_date.month - 1]) + elif self.filters.range == 'Quarterly': + period = 'Quarter ' + str(((appointment_date.month - 1) // 3) + 1) + else: + year = get_fiscal_year(appointment_date, company=self.filters.company) + period = str(year[0]) + + if getdate(self.filters.from_date).year != getdate(self.filters.to_date).year: + period += ' ' + str(appointment_date.year) + + 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 + + def get_chart_data(self): + length = len(self.columns) + labels = [d.get("label") for d in self.columns[1:length - 1]] + self.chart = { + "data": { + 'labels': labels, + 'datasets': [] + }, + "type": "line" + } \ No newline at end of file diff --git a/erpnext/healthcare/utils.py b/erpnext/healthcare/utils.py index 97bb98f677..246242ad84 100644 --- a/erpnext/healthcare/utils.py +++ b/erpnext/healthcare/utils.py @@ -4,417 +4,471 @@ from __future__ import unicode_literals import frappe -import datetime from frappe import _ import math -from frappe.utils import time_diff_in_hours, rounded, getdate, add_days +from frappe.utils import time_diff_in_hours, rounded from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_income_account -from erpnext.healthcare.doctype.fee_validity.fee_validity import create_fee_validity, update_fee_validity +from erpnext.healthcare.doctype.fee_validity.fee_validity import create_fee_validity from erpnext.healthcare.doctype.lab_test.lab_test import create_multiple @frappe.whitelist() def get_healthcare_services_to_invoice(patient): - patient = frappe.get_doc("Patient", patient) + patient = frappe.get_doc('Patient', patient) if patient: - if patient.customer: - item_to_invoice = [] - patient_appointments = frappe.get_list("Patient Appointment",{'patient': patient.name, 'invoiced': False}, - order_by="appointment_date") - if patient_appointments: - fee_validity_details = [] - valid_days = frappe.db.get_value("Healthcare Settings", None, "valid_days") - max_visit = frappe.db.get_value("Healthcare Settings", None, "max_visit") - for patient_appointment in patient_appointments: - patient_appointment_obj = frappe.get_doc("Patient Appointment", patient_appointment['name']) + validate_customer_created(patient) + items_to_invoice = [] + patient_appointments = frappe.get_list( + 'Patient Appointment', + fields='*', + filters={'patient': patient.name, 'invoiced': 0}, + order_by='appointment_date' + ) + if patient_appointments: + items_to_invoice = get_fee_validity(patient_appointments) - if patient_appointment_obj.procedure_template: - if frappe.db.get_value("Clinical Procedure Template", patient_appointment_obj.procedure_template, "is_billable") == 1: - item_to_invoice.append({'reference_type': 'Patient Appointment', 'reference_name': patient_appointment_obj.name, 'service': patient_appointment_obj.procedure_template}) - else: - practitioner_exist_in_list = False - skip_invoice = False - if fee_validity_details: - for validity in fee_validity_details: - if validity['practitioner'] == patient_appointment_obj.practitioner: - practitioner_exist_in_list = True - if validity['valid_till'] >= patient_appointment_obj.appointment_date: - validity['visits'] = validity['visits']+1 - if int(max_visit) > validity['visits']: - skip_invoice = True - if not skip_invoice: - validity['visits'] = 1 - validity['valid_till'] = patient_appointment_obj.appointment_date + datetime.timedelta(days=int(valid_days)) - if not practitioner_exist_in_list: - valid_till = patient_appointment_obj.appointment_date + datetime.timedelta(days=int(valid_days)) - visits = 0 - validity_exist = validity_exists(patient_appointment_obj.practitioner, patient_appointment_obj.patient) - if validity_exist: - fee_validity = frappe.get_doc("Fee Validity", validity_exist[0][0]) - valid_till = fee_validity.valid_till - visits = fee_validity.visited - fee_validity_details.append({'practitioner': patient_appointment_obj.practitioner, - 'valid_till': valid_till, 'visits': visits}) + encounters = get_encounters_to_invoice(patient) + lab_tests = get_lab_tests_to_invoice(patient) + clinical_procedures = get_clinical_procedures_to_invoice(patient) + inpatient_services = get_inpatient_services_to_invoice(patient) - if not skip_invoice: - practitioner_charge = 0 - income_account = None - service_item = None - if patient_appointment_obj.practitioner: - service_item, practitioner_charge = service_item_and_practitioner_charge(patient_appointment_obj) - income_account = get_income_account(patient_appointment_obj.practitioner, patient_appointment_obj.company) - item_to_invoice.append({'reference_type': 'Patient Appointment', 'reference_name': patient_appointment_obj.name, - 'service': service_item, 'rate': practitioner_charge, - 'income_account': income_account}) + items_to_invoice += encounters + lab_tests + clinical_procedures + inpatient_services + return items_to_invoice - encounters = frappe.get_list("Patient Encounter", {'patient': patient.name, 'invoiced': False, 'docstatus': 1}) - if encounters: - for encounter in encounters: - encounter_obj = frappe.get_doc("Patient Encounter", encounter['name']) - if not encounter_obj.appointment: - practitioner_charge = 0 - income_account = None - service_item = None - if encounter_obj.practitioner: - service_item, practitioner_charge = service_item_and_practitioner_charge(encounter_obj) - income_account = get_income_account(encounter_obj.practitioner, encounter_obj.company) +def validate_customer_created(patient): + if not frappe.db.get_value('Patient', patient.name, 'customer'): + msg = _("Please set a Customer linked to the Patient") + msg += " {0}".format(patient.name) + frappe.throw(msg, title=_('Customer Not Found')) - item_to_invoice.append({'reference_type': 'Patient Encounter', 'reference_name': encounter_obj.name, - 'service': service_item, 'rate': practitioner_charge, - 'income_account': income_account}) +def get_fee_validity(patient_appointments): + if not frappe.db.get_single_value('Healthcare Settings', 'enable_free_follow_ups'): + return - lab_tests = frappe.get_list("Lab Test", {'patient': patient.name, 'invoiced': False, 'docstatus': 1}) - if lab_tests: - for lab_test in lab_tests: - lab_test_obj = frappe.get_doc("Lab Test", lab_test['name']) - if frappe.db.get_value("Lab Test Template", lab_test_obj.template, "is_billable") == 1: - item_to_invoice.append({'reference_type': 'Lab Test', 'reference_name': lab_test_obj.name, - 'service': frappe.db.get_value("Lab Test Template", lab_test_obj.template, "item")}) - - lab_rxs = frappe.db.sql("""select lp.name from `tabPatient Encounter` et, `tabLab Prescription` lp - where et.patient=%s and lp.parent=et.name and lp.lab_test_created=0 and lp.invoiced=0""", (patient.name)) - if lab_rxs: - for lab_rx in lab_rxs: - rx_obj = frappe.get_doc("Lab Prescription", lab_rx[0]) - if rx_obj.lab_test_code and (frappe.db.get_value("Lab Test Template", rx_obj.lab_test_code, "is_billable") == 1): - item_to_invoice.append({'reference_type': 'Lab Prescription', 'reference_name': rx_obj.name, - 'service': frappe.db.get_value("Lab Test Template", rx_obj.lab_test_code, "item")}) - - procedures = frappe.get_list("Clinical Procedure", {'patient': patient.name, 'invoiced': False}) - if procedures: - for procedure in procedures: - procedure_obj = frappe.get_doc("Clinical Procedure", procedure['name']) - if not procedure_obj.appointment: - if procedure_obj.procedure_template and (frappe.db.get_value("Clinical Procedure Template", procedure_obj.procedure_template, "is_billable") == 1): - item_to_invoice.append({'reference_type': 'Clinical Procedure', 'reference_name': procedure_obj.name, - 'service': frappe.db.get_value("Clinical Procedure Template", procedure_obj.procedure_template, "item")}) - - procedure_rxs = frappe.db.sql("""select pp.name from `tabPatient Encounter` et, - `tabProcedure Prescription` pp where et.patient=%s and pp.parent=et.name and - pp.procedure_created=0 and pp.invoiced=0 and pp.appointment_booked=0""", (patient.name)) - if procedure_rxs: - for procedure_rx in procedure_rxs: - rx_obj = frappe.get_doc("Procedure Prescription", procedure_rx[0]) - if frappe.db.get_value("Clinical Procedure Template", rx_obj.procedure, "is_billable") == 1: - item_to_invoice.append({'reference_type': 'Procedure Prescription', 'reference_name': rx_obj.name, - 'service': frappe.db.get_value("Clinical Procedure Template", rx_obj.procedure, "item")}) - - procedures = frappe.get_list("Clinical Procedure", - {'patient': patient.name, 'invoice_separately_as_consumables': True, 'consumption_invoiced': False, - 'consume_stock': True, 'status': 'Completed'}) - if procedures: - service_item = get_healthcare_service_item('clinical_procedure_consumable_item') - if not service_item: - msg = _(("Please Configure {0} in ").format("Clinical Procedure Consumable Item") \ - + """Healthcare Settings""") - frappe.throw(msg) - for procedure in procedures: - procedure_obj = frappe.get_doc("Clinical Procedure", procedure['name']) - item_to_invoice.append({'reference_type': 'Clinical Procedure', 'reference_name': procedure_obj.name, - 'service': service_item, 'rate': procedure_obj.consumable_total_amount, 'description': procedure_obj.consumption_details}) - - inpatient_services = frappe.db.sql("""select io.name, io.parent from `tabInpatient Record` ip, - `tabInpatient Occupancy` io where ip.patient=%s and io.parent=ip.name and - io.left=1 and io.invoiced=0""", (patient.name)) - if inpatient_services: - for inpatient_service in inpatient_services: - inpatient_occupancy = frappe.get_doc("Inpatient Occupancy", inpatient_service[0]) - service_unit_type = frappe.get_doc("Healthcare Service Unit Type", frappe.db.get_value("Healthcare Service Unit", inpatient_occupancy.service_unit, "service_unit_type")) - if service_unit_type and service_unit_type.is_billable == 1: - hours_occupied = time_diff_in_hours(inpatient_occupancy.check_out, inpatient_occupancy.check_in) - qty = 0.5 - if hours_occupied > 0: - actual_qty = hours_occupied / service_unit_type.no_of_hours - floor = math.floor(actual_qty) - decimal_part = actual_qty - floor - if decimal_part > 0.5: - qty = rounded(floor + 1, 1) - elif decimal_part < 0.5 and decimal_part > 0: - qty = rounded(floor + 0.5, 1) - if qty <= 0: - qty = 0.5 - item_to_invoice.append({'reference_type': 'Inpatient Occupancy', 'reference_name': inpatient_occupancy.name, - 'service': service_unit_type.item, 'qty': qty}) - - return item_to_invoice + items_to_invoice = [] + for appointment in patient_appointments: + if appointment.procedure_template: + if frappe.db.get_value('Clinical Procedure Template', appointment.procedure_template, 'is_billable'): + items_to_invoice.append({ + 'reference_type': 'Patient Appointment', + 'reference_name': appointment.name, + 'service': appointment.procedure_template + }) else: - frappe.throw(_("The Patient {0} do not have customer refrence to invoice").format(patient.name)) + fee_validity = frappe.db.exists('Fee Validity Reference', {'appointment': appointment.name}) + if not fee_validity: + practitioner_charge = 0 + income_account = None + service_item = None + if appointment.practitioner: + service_item, practitioner_charge = get_service_item_and_practitioner_charge(appointment) + income_account = get_income_account(appointment.practitioner, appointment.company) + items_to_invoice.append({ + 'reference_type': 'Patient Appointment', + 'reference_name': appointment.name, + 'service': service_item, + 'rate': practitioner_charge, + 'income_account': income_account + }) -def service_item_and_practitioner_charge(doc): - is_ip = doc_is_ip(doc) - if is_ip: - service_item = get_practitioner_service_item(doc.practitioner, "inpatient_visit_charge_item") + return items_to_invoice + + +def get_encounters_to_invoice(patient): + encounters_to_invoice = [] + encounters = frappe.get_list( + 'Patient Encounter', + fields=['*'], + filters={'patient': patient.name, 'invoiced': False, 'docstatus': 1} + ) + if encounters: + for encounter in encounters: + if not encounter.appointment: + practitioner_charge = 0 + income_account = None + service_item = None + if encounter.practitioner: + service_item, practitioner_charge = get_service_item_and_practitioner_charge(encounter) + income_account = get_income_account(encounter.practitioner, encounter.company) + + encounters_to_invoice.append({ + 'reference_type': 'Patient Encounter', + 'reference_name': encounter.name, + 'service': service_item, + 'rate': practitioner_charge, + 'income_account': income_account + }) + + return encounters_to_invoice + + +def get_lab_tests_to_invoice(patient): + lab_tests_to_invoice = [] + lab_tests = frappe.get_list( + 'Lab Test', + fields=['name', 'template'], + filters={'patient': patient.name, 'invoiced': False, 'docstatus': 1} + ) + for lab_test in lab_tests: + item, is_billable = frappe.get_cached_value('Lab Test Template', lab_test.lab_test_code, ['item', 'is_billable']) + if is_billable: + lab_tests_to_invoice.append({ + 'reference_type': 'Lab Test', + 'reference_name': lab_test.name, + 'service': item + }) + + lab_prescriptions = frappe.db.sql( + ''' + SELECT + lp.name, lp.lab_test_code + FROM + `tabPatient Encounter` et, `tabLab Prescription` lp + WHERE + et.patient=%s + and lp.parent=et.name + and lp.lab_test_created=0 + and lp.invoiced=0 + ''', (patient.name), as_dict=1) + + for prescription in lab_prescriptions: + item, is_billable = frappe.get_cached_value('Lab Test Template', prescription.lab_test_code, ['item', 'is_billable']) + if prescription.lab_test_code and is_billable: + lab_tests_to_invoice.append({ + 'reference_type': 'Lab Prescription', + 'reference_name': prescription.name, + 'service': item + }) + + return lab_tests_to_invoice + + +def get_clinical_procedures_to_invoice(patient): + clinical_procedures_to_invoice = [] + procedures = frappe.get_list( + 'Clinical Procedure', + fields='*', + filters={'patient': patient.name, 'invoiced': False} + ) + for procedure in procedures: + if not procedure.appointment: + item, is_billable = frappe.get_cached_value('Clinical Procedure Template', procedure.procedure_template, ['item', 'is_billable']) + if procedure.procedure_template and is_billable: + clinical_procedures_to_invoice.append({ + 'reference_type': 'Clinical Procedure', + 'reference_name': procedure.name, + 'service': item + }) + + # consumables + if procedure.invoice_separately_as_consumables and procedure.consume_stock \ + and procedure.status == 'Completed' and not procedure.consumption_invoiced: + + service_item = get_healthcare_service_item('clinical_procedure_consumable_item') + if not service_item: + msg = _('Please Configure Clinical Procedure Consumable Item in ') + msg += '''Healthcare Settings''' + frappe.throw(msg, title=_('Missing Configuration')) + + clinical_procedures_to_invoice.append({ + 'reference_type': 'Clinical Procedure', + 'reference_name': procedure.name, + 'service': service_item, + 'rate': procedure.consumable_total_amount, + 'description': procedure.consumption_details + }) + + procedure_prescriptions = frappe.db.sql( + ''' + SELECT + pp.name, pp.procedure + FROM + `tabPatient Encounter` et, `tabProcedure Prescription` pp + WHERE + et.patient=%s + and pp.parent=et.name + and pp.procedure_created=0 + and pp.invoiced=0 + and pp.appointment_booked=0 + ''', (patient.name), as_dict=1) + + for prescription in procedure_prescriptions: + item, is_billable = frappe.get_cached_value('Clinical Procedure Template', prescription.procedure, ['item', 'is_billable']) + if is_billable: + clinical_procedures_to_invoice.append({ + 'reference_type': 'Procedure Prescription', + 'reference_name': prescription.name, + 'service': item + }) + + return clinical_procedures_to_invoice + + +def get_inpatient_services_to_invoice(patient): + services_to_invoice = [] + inpatient_services = frappe.db.sql( + ''' + SELECT + io.* + FROM + `tabInpatient Record` ip, `tabInpatient Occupancy` io + WHERE + ip.patient=%s + and io.parent=ip.name + and io.left=1 + and io.invoiced=0 + ''', (patient.name), as_dict=1) + + for inpatient_occupancy in inpatient_services: + service_unit_type = frappe.db.get_value('Healthcare Service Unit', inpatient_occupancy.service_unit, 'service_unit_type') + service_unit_type = frappe.get_cached_doc('Healthcare Service Unit Type', service_unit_type) + if service_unit_type and service_unit_type.is_billable: + hours_occupied = time_diff_in_hours(inpatient_occupancy.check_out, inpatient_occupancy.check_in) + qty = 0.5 + if hours_occupied > 0: + actual_qty = hours_occupied / service_unit_type.no_of_hours + floor = math.floor(actual_qty) + decimal_part = actual_qty - floor + if decimal_part > 0.5: + qty = rounded(floor + 1, 1) + elif decimal_part < 0.5 and decimal_part > 0: + qty = rounded(floor + 0.5, 1) + if qty <= 0: + qty = 0.5 + services_to_invoice.append({ + 'reference_type': 'Inpatient Occupancy', + 'reference_name': inpatient_occupancy.name, + 'service': service_unit_type.item, 'qty': qty + }) + + return services_to_invoice + + +def get_service_item_and_practitioner_charge(doc): + is_inpatient = doc.inpatient_record + if is_inpatient: + service_item = get_practitioner_service_item(doc.practitioner, 'inpatient_visit_charge_item') if not service_item: - service_item = get_healthcare_service_item("inpatient_visit_charge_item") + service_item = get_healthcare_service_item('inpatient_visit_charge_item') else: - service_item = get_practitioner_service_item(doc.practitioner, "op_consulting_charge_item") + service_item = get_practitioner_service_item(doc.practitioner, 'op_consulting_charge_item') if not service_item: - service_item = get_healthcare_service_item("op_consulting_charge_item") + service_item = get_healthcare_service_item('op_consulting_charge_item') if not service_item: - throw_config_service_item(is_ip) + throw_config_service_item(is_inpatient) - practitioner_charge = get_practitioner_charge(doc.practitioner, is_ip) + practitioner_charge = get_practitioner_charge(doc.practitioner, is_inpatient) if not practitioner_charge: - throw_config_practitioner_charge(is_ip, doc.practitioner) + throw_config_practitioner_charge(is_inpatient, doc.practitioner) return service_item, practitioner_charge -def throw_config_service_item(is_ip): - service_item_lable = "Out Patient Consulting Charge Item" - if is_ip: - service_item_lable = "Inpatient Visit Charge Item" - msg = _(("Please Configure {0} in ").format(service_item_lable) \ - + """Healthcare Settings""") - frappe.throw(msg) +def throw_config_service_item(is_inpatient): + service_item_label = _('Out Patient Consulting Charge Item') + if is_inpatient: + service_item_label = _('Inpatient Visit Charge Item') -def throw_config_practitioner_charge(is_ip, practitioner): - charge_name = "OP Consulting Charge" - if is_ip: - charge_name = "Inpatient Visit Charge" + msg = _(('Please Configure {0} in ').format(service_item_label) \ + + '''Healthcare Settings''') + frappe.throw(msg, title=_('Missing Configuration')) + + +def throw_config_practitioner_charge(is_inpatient, practitioner): + charge_name = _('OP Consulting Charge') + if is_inpatient: + charge_name = _('Inpatient Visit Charge') + + msg = _(('Please Configure {0} for Healthcare Practitioner').format(charge_name) \ + + ''' {0}'''.format(practitioner)) + frappe.throw(msg, title=_('Missing Configuration')) - msg = _(("Please Configure {0} for Healthcare Practitioner").format(charge_name) \ - + """ {0}""".format(practitioner)) - frappe.throw(msg) def get_practitioner_service_item(practitioner, service_item_field): - return frappe.db.get_value("Healthcare Practitioner", practitioner, service_item_field) + return frappe.db.get_value('Healthcare Practitioner', practitioner, service_item_field) + def get_healthcare_service_item(service_item_field): - return frappe.db.get_value("Healthcare Settings", None, service_item_field) + return frappe.db.get_single_value('Healthcare Settings', service_item_field) -def doc_is_ip(doc): - is_ip = False - if doc.inpatient_record: - is_ip = True - return is_ip -def get_practitioner_charge(practitioner, is_ip): - if is_ip: - practitioner_charge = frappe.db.get_value("Healthcare Practitioner", practitioner, "inpatient_visit_charge") +def get_practitioner_charge(practitioner, is_inpatient): + if is_inpatient: + practitioner_charge = frappe.db.get_value('Healthcare Practitioner', practitioner, 'inpatient_visit_charge') else: - practitioner_charge = frappe.db.get_value("Healthcare Practitioner", practitioner, "op_consulting_charge") + practitioner_charge = frappe.db.get_value('Healthcare Practitioner', practitioner, 'op_consulting_charge') if practitioner_charge: return practitioner_charge return False + def manage_invoice_submit_cancel(doc, method): if doc.items: for item in doc.items: - if item.get("reference_dt") and item.get("reference_dn"): - if frappe.get_meta(item.reference_dt).has_field("invoiced"): + if item.get('reference_dt') and item.get('reference_dn'): + if frappe.get_meta(item.reference_dt).has_field('invoiced'): set_invoiced(item, method, doc.name) - if method=="on_submit" and frappe.db.get_value("Healthcare Settings", None, "create_test_on_si_submit") == '1': - create_multiple("Sales Invoice", doc.name) + if method=='on_submit' and frappe.db.get_single_value('Healthcare Settings', 'create_lab_test_on_si_submit'): + create_multiple('Sales Invoice', doc.name) + def set_invoiced(item, method, ref_invoice=None): invoiced = False - if(method=="on_submit"): + if method=='on_submit': validate_invoiced_on_submit(item) invoiced = True if item.reference_dt == 'Clinical Procedure': if get_healthcare_service_item('clinical_procedure_consumable_item') == item.item_code: - frappe.db.set_value(item.reference_dt, item.reference_dn, "consumption_invoiced", invoiced) + frappe.db.set_value(item.reference_dt, item.reference_dn, 'consumption_invoiced', invoiced) else: - frappe.db.set_value(item.reference_dt, item.reference_dn, "invoiced", invoiced) + frappe.db.set_value(item.reference_dt, item.reference_dn, 'invoiced', invoiced) else: - frappe.db.set_value(item.reference_dt, item.reference_dn, "invoiced", invoiced) + frappe.db.set_value(item.reference_dt, item.reference_dn, 'invoiced', invoiced) if item.reference_dt == 'Patient Appointment': if frappe.db.get_value('Patient Appointment', item.reference_dn, 'procedure_template'): - dt_from_appointment = "Clinical Procedure" + dt_from_appointment = 'Clinical Procedure' else: - manage_fee_validity(item.reference_dn, method, ref_invoice) - dt_from_appointment = "Patient Encounter" - manage_doc_for_appoitnment(dt_from_appointment, item.reference_dn, invoiced) + dt_from_appointment = 'Patient Encounter' + manage_doc_for_appointment(dt_from_appointment, item.reference_dn, invoiced) elif item.reference_dt == 'Lab Prescription': - manage_prescriptions(invoiced, item.reference_dt, item.reference_dn, "Lab Test", "lab_test_created") + manage_prescriptions(invoiced, item.reference_dt, item.reference_dn, 'Lab Test', 'lab_test_created') elif item.reference_dt == 'Procedure Prescription': - manage_prescriptions(invoiced, item.reference_dt, item.reference_dn, "Clinical Procedure", "procedure_created") + manage_prescriptions(invoiced, item.reference_dt, item.reference_dn, 'Clinical Procedure', 'procedure_created') + def validate_invoiced_on_submit(item): if item.reference_dt == 'Clinical Procedure' and get_healthcare_service_item('clinical_procedure_consumable_item') == item.item_code: - is_invoiced = frappe.db.get_value(item.reference_dt, item.reference_dn, "consumption_invoiced") + is_invoiced = frappe.db.get_value(item.reference_dt, item.reference_dn, 'consumption_invoiced') else: - is_invoiced = frappe.db.get_value(item.reference_dt, item.reference_dn, "invoiced") - if is_invoiced == 1: - frappe.throw(_("The item referenced by {0} - {1} is already invoiced"\ + 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)) + def manage_prescriptions(invoiced, ref_dt, ref_dn, dt, created_check_field): created = frappe.db.get_value(ref_dt, ref_dn, created_check_field) - if created == 1: + if created: # Fetch the doc created for the prescription doc_created = frappe.db.get_value(dt, {'prescription': ref_dn}) frappe.db.set_value(dt, doc_created, 'invoiced', invoiced) -def validity_exists(practitioner, patient): - return frappe.db.exists({ - "doctype": "Fee Validity", - "practitioner": practitioner, - "patient": patient}) -def manage_fee_validity(appointment_name, method, ref_invoice=None): - appointment_doc = frappe.get_doc("Patient Appointment", appointment_name) - validity_exist = validity_exists(appointment_doc.practitioner, appointment_doc.patient) - do_not_update = False - visited = 0 - if validity_exist: - fee_validity = frappe.get_doc("Fee Validity", validity_exist[0][0]) - # Check if the validity is valid - if (fee_validity.valid_till >= appointment_doc.appointment_date): - if (method == "on_cancel" and appointment_doc.status != "Closed"): - if ref_invoice == fee_validity.ref_invoice: - visited = fee_validity.visited - 1 - if visited < 0: - visited = 0 - frappe.db.set_value("Fee Validity", fee_validity.name, "visited", visited) - do_not_update = True - elif (method == "on_submit" and fee_validity.visited < fee_validity.max_visit): - visited = fee_validity.visited + 1 - frappe.db.set_value("Fee Validity", fee_validity.name, "visited", visited) - do_not_update = True - else: - do_not_update = False +def check_fee_validity(appointment): + if not frappe.db.get_single_value('Healthcare Settings', 'enable_free_follow_ups'): + return - if not do_not_update: - fee_validity = update_fee_validity(fee_validity, appointment_doc.appointment_date, ref_invoice) - visited = fee_validity.visited + validity = frappe.db.exists('Fee Validity', { + 'practitioner': appointment.practitioner, + 'patient': appointment.patient, + 'valid_till': ('>=', appointment.appointment_date) + }) + if not validity: + return + + validity = frappe.get_doc('Fee Validity', validity) + return validity + + +def manage_fee_validity(appointment): + fee_validity = check_fee_validity(appointment) + if fee_validity: + if appointment.status == 'Cancelled' and fee_validity.visited > 0: + fee_validity.visited -= 1 + frappe.db.delete('Fee Validity Reference', {'appointment': appointment.name}) + elif fee_validity.status == 'Completed': + return + else: + fee_validity.visited += 1 + fee_validity.append('ref_appointments', { + 'appointment': appointment.name + }) + fee_validity.save(ignore_permissions=True) else: - fee_validity = create_fee_validity(appointment_doc.practitioner, appointment_doc.patient, appointment_doc.appointment_date, ref_invoice) - visited = fee_validity.visited + fee_validity = create_fee_validity(appointment) + return fee_validity - # Mark All Patient Appointment invoiced = True in the validity range do not cross the max visit - if (method == "on_cancel"): - invoiced = True - else: - invoiced = False - patient_appointments = appointments_valid_in_fee_validity(appointment_doc, invoiced) - if patient_appointments and fee_validity: - visit = visited - for appointment in patient_appointments: - if (method == "on_cancel" and appointment.status != "Closed"): - if ref_invoice == fee_validity.ref_invoice: - visited = visited - 1 - if visited < 0: - visited = 0 - frappe.db.set_value("Fee Validity", fee_validity.name, "visited", visited) - frappe.db.set_value("Patient Appointment", appointment.name, "invoiced", False) - manage_doc_for_appoitnment("Patient Encounter", appointment.name, False) - elif method == "on_submit" and int(fee_validity.max_visit) > visit: - if ref_invoice == fee_validity.ref_invoice: - visited = visited + 1 - frappe.db.set_value("Fee Validity", fee_validity.name, "visited", visited) - frappe.db.set_value("Patient Appointment", appointment.name, "invoiced", True) - manage_doc_for_appoitnment("Patient Encounter", appointment.name, True) - if ref_invoice == fee_validity.ref_invoice: - visit = visit + 1 - - if method == "on_cancel": - ref_invoice_in_fee_validity = frappe.db.get_value("Fee Validity", fee_validity.name, 'ref_invoice') - if ref_invoice_in_fee_validity == ref_invoice: - frappe.delete_doc("Fee Validity", fee_validity.name) - -def appointments_valid_in_fee_validity(appointment, invoiced): - valid_days = frappe.db.get_value("Healthcare Settings", None, "valid_days") - max_visit = frappe.db.get_value("Healthcare Settings", None, "max_visit") - if int(max_visit) < 1: - max_visit = 1 - valid_days_date = add_days(getdate(appointment.appointment_date), int(valid_days)) - return frappe.get_list("Patient Appointment",{'patient': appointment.patient, 'invoiced': invoiced, - 'appointment_date':("<=", valid_days_date), 'appointment_date':(">=", getdate(appointment.appointment_date)), - 'practitioner': appointment.practitioner}, order_by="appointment_date", limit=int(max_visit)-1) - -def manage_doc_for_appoitnment(dt_from_appointment, appointment, invoiced): - dn_from_appointment = frappe.db.exists( +def manage_doc_for_appointment(dt_from_appointment, appointment, invoiced): + dn_from_appointment = frappe.db.get_value( dt_from_appointment, - { - "appointment": appointment - } + filters={'appointment': appointment} ) if dn_from_appointment: - frappe.db.set_value(dt_from_appointment, dn_from_appointment, "invoiced", invoiced) + frappe.db.set_value(dt_from_appointment, dn_from_appointment, 'invoiced', invoiced) + @frappe.whitelist() def get_drugs_to_invoice(encounter): - encounter = frappe.get_doc("Patient Encounter", encounter) + encounter = frappe.get_doc('Patient Encounter', encounter) if encounter: - patient = frappe.get_doc("Patient", encounter.patient) - if patient and patient.customer: - item_to_invoice = [] + patient = frappe.get_doc('Patient', encounter.patient) + if patient: + if patient.customer: + items_to_invoice = [] for drug_line in encounter.drug_prescription: if drug_line.drug_code: qty = 1 - if frappe.db.get_value("Item", drug_line.drug_code, "stock_uom") == "Nos": + if frappe.db.get_value('Item', drug_line.drug_code, 'stock_uom') == 'Nos': qty = drug_line.get_quantity() - description = False - if drug_line.dosage: - description = drug_line.dosage - if description and drug_line.period: - description += " for "+drug_line.period - if not description: - description = "" - item_to_invoice.append({'drug_code': drug_line.drug_code, 'quantity': qty, - 'description': description}) - return item_to_invoice + + description = '' + if drug_line.dosage and drug_line.period: + description = _('{0} for {1}').format(drug_line.dosage, drug_line.period) + + items_to_invoice.append({ + 'drug_code': drug_line.drug_code, + 'quantity': qty, + 'description': description + }) + return items_to_invoice + else: + validate_customer_created(patient) + @frappe.whitelist() def get_children(doctype, parent, company, is_root=False): - parent_fieldname = 'parent_' + doctype.lower().replace(' ', '_') + parent_fieldname = "parent_" + doctype.lower().replace(" ", "_") fields = [ - 'name as value', - 'is_group as expandable', - 'lft', - 'rgt' + "name as value", + "is_group as expandable", + "lft", + "rgt" ] - # fields = [ 'name', 'is_group', 'lft', 'rgt' ] - filters = [['ifnull(`{0}`,"")'.format(parent_fieldname), '=', '' if is_root else parent]] + # fields = [ "name", "is_group", "lft", "rgt" ] + filters = [["ifnull(`{0}`,'')".format(parent_fieldname), "=", "" if is_root else parent]] if is_root: - fields += ['service_unit_type'] if doctype == 'Healthcare Service Unit' else [] - filters.append(['company', '=', company]) + fields += ["service_unit_type"] if doctype == "Healthcare Service Unit" else [] + filters.append(["company", "=", company]) else: - fields += ['service_unit_type', 'allow_appointments', 'inpatient_occupancy', 'occupancy_status'] if doctype == 'Healthcare Service Unit' else [] - fields += [parent_fieldname + ' as parent'] + fields += ["service_unit_type", "allow_appointments", "inpatient_occupancy", "occupancy_status"] if doctype == "Healthcare Service Unit" else [] + fields += [parent_fieldname + " as parent"] hc_service_units = frappe.get_list(doctype, fields=fields, filters=filters) - if doctype == 'Healthcare Service Unit': + if doctype == "Healthcare Service Unit": for each in hc_service_units: occupancy_msg = "" - if each['expandable'] == 1: + if each["expandable"] == 1: occupied = False vacant = False - child_list = frappe.db.sql(""" - select name, occupancy_status from `tabHealthcare Service Unit` - where inpatient_occupancy = 1 and - lft > %s and rgt < %s""", - (each['lft'], each['rgt'])) + child_list = frappe.db.sql( + ''' + SELECT + name, occupancy_status + FROM + `tabHealthcare Service Unit` + WHERE + inpatient_occupancy = 1 + and lft > %s and rgt < %s + ''', (each['lft'], each['rgt'])) + for child in child_list: if not occupied: occupied = 0 @@ -425,39 +479,44 @@ def get_children(doctype, parent, company, is_root=False): if child[1] == "Vacant": vacant += 1 if vacant and occupied: - occupancy_total = vacant+occupied + occupancy_total = vacant + occupied occupancy_msg = str(occupied) + " Occupied out of " + str(occupancy_total) each["occupied_out_of_vacant"] = occupancy_msg return hc_service_units + @frappe.whitelist() def get_patient_vitals(patient, from_date=None, to_date=None): if not patient: return - vitals = frappe.db.sql("""select * from `tabVital Signs` where \ - docstatus=1 and patient=%s order by signs_date, signs_time""", \ - (patient), as_dict=1) - if vitals and vitals[0]: + + vitals = frappe.db.get_all('Vital Signs', { + 'docstatus': 1, + 'patient': patient + }, order_by='signs_date, signs_time') + + if len(vitals): return vitals - else: - return False + return False + @frappe.whitelist() def render_docs_as_html(docs): # docs key value pair {doctype: docname} docs_html = "
" for doc in docs: - docs_html += render_doc_as_html(doc['doctype'], doc['docname'])['html'] + "
" + docs_html += render_doc_as_html(doc['doctype'], doc['docname'])['html'] + '
' return {'html': docs_html} + @frappe.whitelist() def render_doc_as_html(doctype, docname, exclude_fields = []): #render document as html, three column layout will break doc = frappe.get_doc(doctype, docname) meta = frappe.get_meta(doctype) doc_html = "
" - section_html = "" - section_label = "" - html = "" + section_html = '' + section_label = '' + html = '' sec_on = False col_on = 0 has_data = False @@ -476,8 +535,8 @@ def render_doc_as_html(doctype, docname, exclude_fields = []): sec_on = True has_data= False col_on = 0 - section_html = "" - html = "" + section_html = '' + html = '' if df.label: section_label = df.label continue @@ -493,19 +552,19 @@ def render_doc_as_html(doctype, docname, exclude_fields = []): d-6 col-sm-6'>" + html + "
" elif sec_on and not col_on: section_html += "
" - html = "" + html = '' col_on += 1 if df.label: html += '
' + df.label continue #on table iterate in items and create table based on in_list_view, append to section html or doc html - if df.fieldtype == "Table": + if df.fieldtype == 'Table': items = doc.get(df.fieldname) if not items: continue child_meta = frappe.get_meta(df.options) if not has_data : has_data = True - table_head = "" - table_row = "" + table_head = '' + table_row = '' create_head = True for item in items: table_row += '' @@ -521,24 +580,24 @@ def render_doc_as_html(doctype, docname, exclude_fields = []): create_head = False table_row += '' if sec_on: - section_html += '' + table_head + table_row + '
' + section_html += "" + table_head + table_row + '
' else: - html += '' \ - + table_head + table_row + '
' + html += "" \ + + table_head + table_row + "
" continue #on other field types add label and value to html if not df.hidden and not df.print_hide and doc.get(df.fieldname) and df.fieldname not in exclude_fields: - html += "
{0} : {1}".format(df.label or df.fieldname, \ + html += '
{0} : {1}'.format(df.label or df.fieldname, \ doc.get(df.fieldname)) if not has_data : has_data = True if sec_on and col_on and has_data: - doc_html += section_html + html + "
" + doc_html += section_html + html + '
' elif sec_on and not col_on and has_data: doc_html += "
" \ - + section_html + html +"
" + + section_html + html +'
' if doc_html: - doc_html = "
" %(doctype, docname) + doc_html + "
" + doc_html = "
" %(doctype, docname) + doc_html + '
' return {'html': doc_html} diff --git a/erpnext/healthcare/web_form/patient_registration/__init__.py b/erpnext/healthcare/web_form/patient_registration/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/healthcare/web_form/patient_registration/patient_registration.js b/erpnext/healthcare/web_form/patient_registration/patient_registration.js new file mode 100644 index 0000000000..7da3f1fb41 --- /dev/null +++ b/erpnext/healthcare/web_form/patient_registration/patient_registration.js @@ -0,0 +1,3 @@ +frappe.ready(function() { + // bind events here +}); \ No newline at end of file diff --git a/erpnext/healthcare/web_form/patient_registration/patient_registration.json b/erpnext/healthcare/web_form/patient_registration/patient_registration.json new file mode 100644 index 0000000000..9ed92de16f --- /dev/null +++ b/erpnext/healthcare/web_form/patient_registration/patient_registration.json @@ -0,0 +1,397 @@ +{ + "accept_payment": 0, + "allow_comments": 0, + "allow_delete": 0, + "allow_edit": 1, + "allow_incomplete": 0, + "allow_multiple": 0, + "allow_print": 0, + "amount": 0.0, + "amount_based_on_field": 0, + "button_label": "Register", + "creation": "2020-03-03 01:01:16.250607", + "currency": "INR", + "doc_type": "Patient", + "docstatus": 0, + "doctype": "Web Form", + "idx": 0, + "introduction_text": "", + "is_standard": 1, + "login_required": 0, + "max_attachment_size": 0, + "modified": "2020-03-26 17:25:15.361918", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "patient-registration", + "owner": "Administrator", + "payment_button_label": "Buy Now", + "published": 1, + "route": "patient-registration", + "route_to_success_link": 0, + "show_attachments": 0, + "show_in_grid": 0, + "show_sidebar": 1, + "sidebar_items": [], + "success_message": "Registration Successfully. Thank You!", + "success_url": "/patient-registration", + "title": "Patient Registration", + "web_form_fields": [ + { + "allow_read_on_all_link_options": 0, + "fieldname": "basic_info", + "fieldtype": "Section Break", + "hidden": 0, + "label": "Patient Demographics", + "max_length": 0, + "max_value": 0, + "options": "fa fa-user", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "first_name", + "fieldtype": "Data", + "hidden": 0, + "label": "First Name", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 1, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "middle_name", + "fieldtype": "Data", + "hidden": 0, + "label": "Middle Name (optional)", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "last_name", + "fieldtype": "Data", + "hidden": 0, + "label": "Last Name", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 1, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "sex", + "fieldtype": "Link", + "hidden": 0, + "label": "Gender", + "max_length": 0, + "max_value": 0, + "options": "Gender", + "read_only": 0, + "reqd": 1, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "blood_group", + "fieldtype": "Select", + "hidden": 0, + "label": "Blood Group", + "max_length": 0, + "max_value": 0, + "options": "\nA Positive\nA Negative\nAB Positive\nAB Negative\nB Positive\nB Negative\nO Positive\nO Negative", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "", + "fieldtype": "Column Break", + "hidden": 0, + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "dob", + "fieldtype": "Date", + "hidden": 0, + "label": "Date of birth", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "mobile", + "fieldtype": "Data", + "hidden": 0, + "label": "Mobile", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "email", + "fieldtype": "Data", + "hidden": 0, + "label": "Email", + "max_length": 0, + "max_value": 0, + "options": "Email", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "phone", + "fieldtype": "Data", + "hidden": 0, + "label": "Phone", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "", + "fieldtype": "Section Break", + "hidden": 0, + "label": "Personal Details", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "occupation", + "fieldtype": "Data", + "hidden": 0, + "label": "Occupation", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "", + "fieldtype": "Column Break", + "hidden": 0, + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "marital_status", + "fieldtype": "Select", + "hidden": 0, + "label": "Marital Status", + "max_length": 0, + "max_value": 0, + "options": "\nSingle\nMarried\nDivorced\nWidow", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "allergy_medical_and_surgical_history", + "fieldtype": "Section Break", + "hidden": 0, + "label": "Allergies, Medical and Surgical History", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "allergies", + "fieldtype": "Small Text", + "hidden": 0, + "label": "Allergies", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "medication", + "fieldtype": "Small Text", + "hidden": 0, + "label": "Medication", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "column_break_20", + "fieldtype": "Column Break", + "hidden": 0, + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "medical_history", + "fieldtype": "Small Text", + "hidden": 0, + "label": "Medical History", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "surgical_history", + "fieldtype": "Small Text", + "hidden": 0, + "label": "Surgical History", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "risk_factors", + "fieldtype": "Section Break", + "hidden": 0, + "label": "Risk Factors", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "default": "0", + "fieldname": "tobacco_past_use", + "fieldtype": "Check", + "hidden": 0, + "label": "Check if you have a history of Tobacco Consumption", + "max_length": 0, + "max_value": 0, + "options": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "default": "0", + "fieldname": "tobacco_current_use", + "fieldtype": "Check", + "hidden": 0, + "label": "Check if you consume Tobacco", + "max_length": 0, + "max_value": 0, + "options": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "default": "0", + "fieldname": "alcohol_past_use", + "fieldtype": "Check", + "hidden": 0, + "label": "Check if you have a history of Alcohol Consumption", + "max_length": 0, + "max_value": 0, + "options": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "default": "0", + "fieldname": "alcohol_current_use", + "fieldtype": "Check", + "hidden": 0, + "label": "Check if you consume Alcohol", + "max_length": 0, + "max_value": 0, + "options": "", + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "column_break_32", + "fieldtype": "Column Break", + "hidden": 0, + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "surrounding_factors", + "fieldtype": "Small Text", + "hidden": 0, + "label": "Occupational Hazards and Environmental Factors", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + }, + { + "allow_read_on_all_link_options": 0, + "fieldname": "other_risk_factors", + "fieldtype": "Small Text", + "hidden": 0, + "label": "Other Risk Factors", + "max_length": 0, + "max_value": 0, + "read_only": 0, + "reqd": 0, + "show_in_filter": 0 + } + ] +} \ No newline at end of file diff --git a/erpnext/healthcare/web_form/patient_registration/patient_registration.py b/erpnext/healthcare/web_form/patient_registration/patient_registration.py new file mode 100644 index 0000000000..1bc4d1874c --- /dev/null +++ b/erpnext/healthcare/web_form/patient_registration/patient_registration.py @@ -0,0 +1,5 @@ +from __future__ import unicode_literals + +def get_context(context): + # do your magic here + pass diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 6199cb2264..2f07e15f1e 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -269,7 +269,8 @@ auto_cancel_exempted_doctypes= [ scheduler_events = { "all": [ - "erpnext.projects.doctype.project.project.project_status_update_reminder" + "erpnext.projects.doctype.project.project.project_status_update_reminder", + "erpnext.healthcare_healthcare.doctype.patient_appointment.patient_appointment.send_appointment_reminder" ], "hourly": [ 'erpnext.hr.doctype.daily_work_summary_group.daily_work_summary_group.trigger_emails', @@ -304,21 +305,22 @@ scheduler_events = { "erpnext.support.doctype.service_level_agreement.service_level_agreement.check_agreement_status", "erpnext.crm.doctype.email_campaign.email_campaign.send_email_to_leads_or_contacts", "erpnext.crm.doctype.email_campaign.email_campaign.set_email_campaign_status", - "erpnext.selling.doctype.quotation.quotation.set_expired_status" + "erpnext.selling.doctype.quotation.quotation.set_expired_status", + "erpnext.healthcare.doctype.patient_appointment.patient_appointment.update_appointment_status" ], "daily_long": [ "erpnext.setup.doctype.email_digest.email_digest.send", "erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.update_latest_price_in_all_boms", "erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry.process_expired_allocation", "erpnext.hr.utils.generate_leave_encashment", - "erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall.check_for_ltv_shortfall", - "erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual.make_accrual_interest_entry_for_term_loans" + "erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall.create_process_loan_security_shortfall", + "erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual.process_loan_interest_accrual_for_term_loans" ], "monthly_long": [ "erpnext.accounts.deferred_revenue.convert_deferred_revenue_to_income", "erpnext.accounts.deferred_revenue.convert_deferred_expense_to_expense", "erpnext.hr.utils.allocate_earned_leaves", - "erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual.process_loan_interest_accrual" + "erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual.process_loan_interest_accrual_for_demand_loans" ] } diff --git a/erpnext/hr/doctype/employee/employee.js b/erpnext/hr/doctype/employee/employee.js index 7d153d432c..c21d4b893c 100755 --- a/erpnext/hr/doctype/employee/employee.js +++ b/erpnext/hr/doctype/employee/employee.js @@ -55,8 +55,8 @@ frappe.ui.form.on('Employee',{ }; }); }, - prefered_contact_email:function(frm){ - frm.events.update_contact(frm) + prefered_contact_email:function(frm){ + frm.events.update_contact(frm) }, personal_email:function(frm){ frm.events.update_contact(frm) diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py index afd52de397..c441751525 100755 --- a/erpnext/hr/doctype/leave_application/leave_application.py +++ b/erpnext/hr/doctype/leave_application/leave_application.py @@ -580,19 +580,22 @@ def get_leaves_for_period(employee, leave_type, from_date, to_date): return leave_days def skip_expiry_leaves(leave_entry, date): - ''' Checks whether the expired leaves coincide with the to_date of leave balance check ''' + ''' Checks whether the expired leaves coincide with the to_date of leave balance check. + This allows backdated leave entry creation for non carry forwarded allocation ''' end_date = frappe.db.get_value("Leave Allocation", {'name': leave_entry.transaction_name}, ['to_date']) return True if end_date == date and not leave_entry.is_carry_forward else False def get_leave_entries(employee, leave_type, from_date, to_date): - ''' Returns leave entries between from_date and to_date ''' + ''' Returns leave entries between from_date and to_date. ''' return frappe.db.sql(""" SELECT employee, leave_type, from_date, to_date, leaves, transaction_name, transaction_type, is_carry_forward, is_expired FROM `tabLeave Ledger Entry` WHERE employee=%(employee)s AND leave_type=%(leave_type)s - AND docstatus=1 AND leaves<0 + AND docstatus=1 + AND (leaves<0 + OR is_expired=1) AND (from_date between %(from_date)s AND %(to_date)s OR to_date between %(from_date)s AND %(to_date)s OR (from_date < %(from_date)s AND to_date > %(to_date)s)) diff --git a/erpnext/hr/doctype/leave_encashment/leave_encashment.py b/erpnext/hr/doctype/leave_encashment/leave_encashment.py index ad2cc02fd7..7d6fd422c0 100644 --- a/erpnext/hr/doctype/leave_encashment/leave_encashment.py +++ b/erpnext/hr/doctype/leave_encashment/leave_encashment.py @@ -8,7 +8,6 @@ from frappe import _ from frappe.model.document import Document from frappe.utils import getdate, nowdate, flt from erpnext.hr.utils import set_employee_name -from erpnext.hr.doctype.leave_application.leave_application import get_leave_balance_on from erpnext.hr.doctype.salary_structure_assignment.salary_structure_assignment import get_assigned_salary_structure from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import create_leave_ledger_entry from erpnext.hr.doctype.leave_allocation.leave_allocation import get_unused_leaves diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py index bfc6d95d17..9ed58c9e59 100644 --- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py +++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py @@ -141,6 +141,7 @@ def expire_allocation(allocation, expiry_date=None): leaves = get_remaining_leaves(allocation) expiry_date = expiry_date if expiry_date else allocation.to_date + # allows expired leaves entry to be created/reverted if leaves: args = dict( leaves=flt(leaves) * -1, @@ -160,6 +161,8 @@ def expire_carried_forward_allocation(allocation): from erpnext.hr.doctype.leave_application.leave_application import get_leaves_for_period leaves_taken = get_leaves_for_period(allocation.employee, allocation.leave_type, allocation.from_date, allocation.to_date) leaves = flt(allocation.leaves) + flt(leaves_taken) + + # allow expired leaves entry to be created if leaves > 0: args = frappe._dict( transaction_name=allocation.name, diff --git a/erpnext/hr/doctype/payroll_entry/test_payroll_entry.py b/erpnext/hr/doctype/payroll_entry/test_payroll_entry.py index 35f5a57a1c..49671d5e22 100644 --- a/erpnext/hr/doctype/payroll_entry/test_payroll_entry.py +++ b/erpnext/hr/doctype/payroll_entry/test_payroll_entry.py @@ -13,7 +13,7 @@ from erpnext.hr.doctype.salary_slip.test_salary_slip import get_salary_component make_earning_salary_component, make_deduction_salary_component from erpnext.hr.doctype.salary_structure.test_salary_structure import make_salary_structure from erpnext.loan_management.doctype.loan.test_loan import create_loan, make_loan_disbursement_entry -from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import make_accrual_interest_entry_for_term_loans +from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_term_loans class TestPayrollEntry(unittest.TestCase): def setUp(self): @@ -81,7 +81,7 @@ class TestPayrollEntry(unittest.TestCase): make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=add_months(nowdate(), -1)) - make_accrual_interest_entry_for_term_loans(posting_date=nowdate()) + process_loan_interest_accrual_for_term_loans(posting_date=nowdate()) dates = get_start_end_dates('Monthly', nowdate()) diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.json b/erpnext/hr/doctype/salary_slip/salary_slip.json index e73d41a28e..097d3a096b 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.json +++ b/erpnext/hr/doctype/salary_slip/salary_slip.json @@ -372,8 +372,7 @@ "fieldtype": "Table", "label": "Employee Loan", "options": "Salary Slip Loan", - "print_hide": 1, - "read_only": 1 + "print_hide": 1 }, { "fieldname": "section_break_43", @@ -464,7 +463,7 @@ "idx": 9, "is_submittable": 1, "links": [], - "modified": "2019-12-31 17:13:45.146271", + "modified": "2020-04-09 20:02:53.159827", "modified_by": "Administrator", "module": "HR", "name": "Salary Slip", diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py index c637215e96..b3c803b564 100644 --- a/erpnext/hr/doctype/salary_slip/salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/salary_slip.py @@ -755,30 +755,43 @@ class SalarySlip(TransactionBase): d.amount = self.get_amount_based_on_payment_days(d, joining_date, relieving_date)[0] def set_loan_repayment(self): - self.set('loans', []) self.total_loan_repayment = 0 self.total_interest_amount = 0 self.total_principal_amount = 0 - for loan in self.get_loan_details(): + if not self.get('loans'): + for loan in self.get_loan_details(): - amounts = calculate_amounts(loan.name, self.posting_date, "Regular Payment") + amounts = calculate_amounts(loan.name, self.posting_date, "Regular Payment") - total_payment = amounts['interest_amount'] + amounts['payable_principal_amount'] + if amounts['interest_amount'] or amounts['payable_principal_amount']: + self.append('loans', { + 'loan': loan.name, + 'total_payment': amounts['interest_amount'] + amounts['payable_principal_amount'], + 'interest_amount': amounts['interest_amount'], + 'principal_amount': amounts['payable_principal_amount'], + 'loan_account': loan.loan_account, + 'interest_income_account': loan.interest_income_account + }) - if total_payment: - self.append('loans', { - 'loan': loan.name, - 'total_payment': total_payment, - 'interest_amount': amounts['interest_amount'], - 'principal_amount': amounts['payable_principal_amount'], - 'loan_account': loan.loan_account, - 'interest_income_account': loan.interest_income_account - }) + for payment in self.get('loans'): + amounts = calculate_amounts(payment.loan, self.posting_date, "Regular Payment") - self.total_loan_repayment += total_payment - self.total_interest_amount += amounts['interest_amount'] - self.total_principal_amount += amounts['payable_principal_amount'] + if payment.interest_amount > amounts['interest_amount']: + frappe.throw(_("""Row {0}: Paid Interest amount {1} is greater than pending interest amount {2} + against loan {3}""").format(payment.idx, frappe.bold(payment.interest_amount), + frappe.bold(amounts['interest_amount']), frappe.bold(payment.loan))) + + if payment.principal_amount > amounts['payable_principal_amount']: + frappe.throw(_("""Row {0}: Paid Principal amount {1} is greater than pending principal amount {2} + against loan {3}""").format(payment.idx, frappe.bold(payment.principal_amount), + frappe.bold(amounts['payable_principal_amount']), frappe.bold(payment.loan))) + + payment.total_payment = payment.interest_amount + payment.principal_amount + self.total_interest_amount += payment.interest_amount + self.total_principal_amount += payment.principal_amount + + self.total_loan_repayment = self.total_interest_amount + self.total_principal_amount def get_loan_details(self): diff --git a/erpnext/hr/doctype/salary_slip/test_salary_slip.py b/erpnext/hr/doctype/salary_slip/test_salary_slip.py index 9acfd1f5c6..ecccac7d41 100644 --- a/erpnext/hr/doctype/salary_slip/test_salary_slip.py +++ b/erpnext/hr/doctype/salary_slip/test_salary_slip.py @@ -146,7 +146,7 @@ class TestSalarySlip(unittest.TestCase): def test_loan_repayment_salary_slip(self): from erpnext.loan_management.doctype.loan.test_loan import create_loan_type, create_loan, make_loan_disbursement_entry, create_loan_accounts - from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import make_accrual_interest_entry_for_term_loans + from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_term_loans applicant = make_employee("test_loanemployee@salary.com", company="_Test Company") @@ -166,7 +166,7 @@ class TestSalarySlip(unittest.TestCase): make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=add_months(nowdate(), -1)) - make_accrual_interest_entry_for_term_loans(posting_date=nowdate()) + process_loan_interest_accrual_for_term_loans(posting_date=nowdate()) ss = make_employee_salary_slip("test_loanemployee@salary.com", "Monthly") ss.submit() diff --git a/erpnext/loan_management/doctype/loan/loan.js b/erpnext/loan_management/doctype/loan/loan.js index 8b220171e8..9cd8b2e90a 100644 --- a/erpnext/loan_management/doctype/loan/loan.js +++ b/erpnext/loan_management/doctype/loan/loan.js @@ -97,6 +97,8 @@ frappe.ui.form.on('Loan', { "company": frm.doc.company, "applicant_type": frm.doc.applicant_type, "applicant": frm.doc.applicant, + "pending_amount": frm.doc.loan_amount - frm.doc.disbursed_amount > 0 ? + frm.doc.loan_amount - frm.doc.disbursed_amount : 0, "as_dict": 1 }, method: "erpnext.loan_management.doctype.loan.loan.make_loan_disbursement", @@ -149,10 +151,10 @@ frappe.ui.form.on('Loan', { return frappe.call({ method: "erpnext.loan_management.doctype.loan.loan.get_loan_application", args: { - "loan_application": frm.doc.loan_application - }, - callback: function (r) { - if (!r.exc && r.message) { + "loan_application": frm.doc.loan_application + }, + callback: function (r) { + if (!r.exc && r.message) { let loan_fields = ["loan_type", "loan_amount", "repayment_method", "monthly_repayment_amount", "repayment_periods", "rate_of_interest", "is_secured_loan"] diff --git a/erpnext/loan_management/doctype/loan/loan.json b/erpnext/loan_management/doctype/loan/loan.json index 2834e5b655..b04e82274e 100644 --- a/erpnext/loan_management/doctype/loan/loan.json +++ b/erpnext/loan_management/doctype/loan/loan.json @@ -126,7 +126,7 @@ "depends_on": "eval:doc.applicant_type==\"Employee\"", "fieldname": "repay_from_salary", "fieldtype": "Check", - "label": "Repay from Salary" + "label": "Repay From Salary" }, { "fieldname": "section_break_8", @@ -178,6 +178,8 @@ }, { "depends_on": "is_term_loan", + "fetch_from": "loan_application.repayment_amount", + "fetch_if_empty": 1, "fieldname": "monthly_repayment_amount", "fieldtype": "Currency", "label": "Monthly Repayment Amount", @@ -350,7 +352,7 @@ ], "is_submittable": 1, "links": [], - "modified": "2020-02-07 01:31:25.172173", + "modified": "2020-04-13 13:16:10.192624", "modified_by": "Administrator", "module": "Loan Management", "name": "Loan", diff --git a/erpnext/loan_management/doctype/loan/loan.py b/erpnext/loan_management/doctype/loan/loan.py index 696410b7bb..c7a2fba878 100644 --- a/erpnext/loan_management/doctype/loan/loan.py +++ b/erpnext/loan_management/doctype/loan/loan.py @@ -19,6 +19,7 @@ class Loan(AccountsController): self.validate_loan_security_pledge() self.validate_loan_amount() self.check_sanctioned_amount_limit() + self.validate_repay_from_salary() if self.is_term_loan: validate_repayment_method(self.repayment_method, self.loan_amount, self.monthly_repayment_amount, @@ -77,6 +78,10 @@ class Loan(AccountsController): if sanctioned_amount_limit and flt(self.loan_amount) + flt(total_loan_amount) > flt(sanctioned_amount_limit): frappe.throw(_("Sanctioned Amount limit crossed for {0} {1}").format(self.applicant_type, frappe.bold(self.applicant))) + def validate_repay_from_salary(self): + if not self.is_term_loan and self.repay_from_salary: + frappe.throw(_("Repay From Salary can be selected only for term loans")) + def make_repayment_schedule(self): if not self.repayment_start_date: @@ -198,7 +203,7 @@ def close_loan(loan, total_amount_paid): frappe.db.set_value("Loan", loan, "status", "Closed") @frappe.whitelist() -def make_loan_disbursement(loan, company, applicant_type, applicant, disbursed_amount=0, as_dict=0): +def make_loan_disbursement(loan, company, applicant_type, applicant, pending_amount=0, as_dict=0): disbursement_entry = frappe.new_doc("Loan Disbursement") disbursement_entry.against_loan = loan disbursement_entry.applicant_type = applicant_type @@ -206,8 +211,7 @@ def make_loan_disbursement(loan, company, applicant_type, applicant, disbursed_a disbursement_entry.company = company disbursement_entry.disbursement_date = nowdate() - if disbursed_amount: - disbursement_entry.disbursed_amount = disbursed_amount + disbursement_entry.disbursed_amount = pending_amount if as_dict: return disbursement_entry.as_dict() else: diff --git a/erpnext/loan_management/doctype/loan/test_loan.py b/erpnext/loan_management/doctype/loan/test_loan.py index 759b0d8e09..108672b25a 100644 --- a/erpnext/loan_management/doctype/loan/test_loan.py +++ b/erpnext/loan_management/doctype/loan/test_loan.py @@ -10,10 +10,10 @@ from frappe.utils import (nowdate, add_days, getdate, now_datetime, add_to_date, add_months, get_first_day, get_last_day, flt, date_diff) from erpnext.selling.doctype.customer.test_customer import get_customer_dict from erpnext.hr.doctype.salary_structure.test_salary_structure import make_employee -from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual -from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import (make_accrual_interest_entry_for_term_loans, days_in_year) - -from erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall import check_for_ltv_shortfall +from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import (process_loan_interest_accrual_for_demand_loans, + process_loan_interest_accrual_for_term_loans) +from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year +from erpnext.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall import create_process_loan_security_shortfall class TestLoan(unittest.TestCase): def setUp(self): @@ -145,7 +145,7 @@ class TestLoan(unittest.TestCase): make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date) - process_loan_interest_accrual(posting_date = last_date) + process_loan_interest_accrual_for_demand_loans(posting_date = last_date) repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 10), "Regular Payment", 111118.68) repayment_entry.save() @@ -186,7 +186,7 @@ class TestLoan(unittest.TestCase): / (days_in_year(get_datetime(first_date).year) * 100) make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date) - process_loan_interest_accrual(posting_date = last_date) + process_loan_interest_accrual_for_demand_loans(posting_date = last_date) repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5), "Loan Closure", 13315.0681) @@ -224,7 +224,7 @@ class TestLoan(unittest.TestCase): make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=add_months(nowdate(), -1)) - make_accrual_interest_entry_for_term_loans(posting_date=nowdate()) + process_loan_interest_accrual_for_term_loans(posting_date=nowdate()) repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(get_last_day(nowdate()), 5), "Regular Payment", 89768.7534247) @@ -264,8 +264,8 @@ class TestLoan(unittest.TestCase): make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date) - process_loan_interest_accrual(posting_date = add_days(first_date, 15)) - process_loan_interest_accrual(posting_date = add_days(first_date, 30)) + process_loan_interest_accrual_for_demand_loans(posting_date = add_days(first_date, 15)) + process_loan_interest_accrual_for_demand_loans(posting_date = add_days(first_date, 30)) repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 1), "Regular Payment", 6500) repayment_entry.save() @@ -297,7 +297,7 @@ class TestLoan(unittest.TestCase): frappe.db.sql(""" UPDATE `tabLoan Security Price` SET loan_security_price = 100 where loan_security='Test Security 2'""") - check_for_ltv_shortfall() + create_process_loan_security_shortfall() loan_security_shortfall = frappe.get_doc("Loan Security Shortfall", {"loan": loan.name}) self.assertTrue(loan_security_shortfall) diff --git a/erpnext/loan_management/doctype/loan_application/loan_application.js b/erpnext/loan_management/doctype/loan_application/loan_application.js index 57050d86c6..aba5f4260c 100644 --- a/erpnext/loan_management/doctype/loan_application/loan_application.js +++ b/erpnext/loan_management/doctype/loan_application/loan_application.js @@ -31,13 +31,15 @@ frappe.ui.form.on('Loan Application', { add_toolbar_buttons: function(frm) { if (frm.doc.status == "Approved") { - frappe.db.get_value("Loan Security Pledge", {"loan_application": frm.doc.name, "docstatus": 1}, "name", (r) => { - if (!r) { - frm.add_custom_button(__('Loan Security Pledge'), function() { - frm.trigger('create_loan_security_pledge') - },__('Create')) - } - }); + if (frm.doc.is_secured) { + frappe.db.get_value("Loan Security Pledge", {"loan_application": frm.doc.name, "docstatus": 1}, "name", (r) => { + if (!r) { + frm.add_custom_button(__('Loan Security Pledge'), function() { + frm.trigger('create_loan_security_pledge') + },__('Create')) + } + }); + } frappe.db.get_value("Loan", {"loan_application": frm.doc.name, "docstatus": 1}, "name", (r) => { if (!r) { @@ -61,6 +63,11 @@ frappe.ui.form.on('Loan Application', { }); }, create_loan_security_pledge: function(frm) { + + if(!frm.doc.is_secured_loan) { + frappe.throw(__("Loan Security Pledge can only be created for secured loans")); + } + frappe.call({ method: "erpnext.loan_management.doctype.loan_application.loan_application.create_pledge", args: { diff --git a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json index 72a4ddcc8f..2d9c45d122 100644 --- a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json +++ b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json @@ -1,4 +1,5 @@ { + "actions": [], "autoname": "LM-DIS-.#####", "creation": "2019-09-07 12:44:49.125452", "doctype": "DocType", @@ -13,7 +14,6 @@ "applicant_type", "applicant", "section_break_7", - "pending_amount_for_disbursal", "disbursed_amount", "accounting_dimensions_section", "cost_center", @@ -83,13 +83,6 @@ "label": "Posting Date", "read_only": 1 }, - { - "fieldname": "pending_amount_for_disbursal", - "fieldtype": "Currency", - "label": "Pending Amount For Disbursal", - "options": "Company:company:default_currency", - "read_only": 1 - }, { "fieldname": "column_break_4", "fieldtype": "Column Break" @@ -99,6 +92,7 @@ "fieldtype": "Section Break" }, { + "collapsible": 1, "fieldname": "section_break_13", "fieldtype": "Section Break" }, @@ -123,7 +117,8 @@ } ], "is_submittable": 1, - "modified": "2019-10-24 12:32:32.230881", + "links": [], + "modified": "2020-04-09 14:44:28.527271", "modified_by": "Administrator", "module": "Loan Management", "name": "Loan Disbursement", diff --git a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py index fa7db2d565..2918486ebd 100644 --- a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py +++ b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py @@ -4,21 +4,24 @@ from __future__ import unicode_literals import frappe, erpnext +from frappe import _ from frappe.model.document import Document from frappe.utils import nowdate, getdate, add_days, flt from erpnext.controllers.accounts_controller import AccountsController from erpnext.accounts.general_ledger import make_gl_entries -from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual +from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_demand_loans class LoanDisbursement(AccountsController): def validate(self): self.set_missing_values() - self.set_pending_amount_for_disbursal() def before_submit(self): self.set_status_and_amounts() + def before_cancel(self): + self.set_status_and_amounts(cancel=1) + def on_submit(self): self.make_gl_entries() @@ -38,13 +41,7 @@ class LoanDisbursement(AccountsController): if not self.bank_account and self.applicant_type == "Customer": self.bank_account = frappe.db.get_value("Customer", self.applicant, "default_bank_account") - def set_pending_amount_for_disbursal(self): - loan_amount, disbursed_amount = frappe.db.get_value('Loan', - {'name': self.against_loan}, ['loan_amount', 'disbursed_amount']) - - self.pending_amount_for_disbursal = loan_amount - disbursed_amount - - def set_status_and_amounts(self): + def set_status_and_amounts(self, cancel=0): loan_details = frappe.get_all("Loan", fields = ["loan_amount", "disbursed_amount", "total_principal_paid", "status", "is_term_loan"], @@ -52,26 +49,32 @@ class LoanDisbursement(AccountsController): )[0] if loan_details.status == "Disbursed" and not loan_details.is_term_loan: - process_loan_interest_accrual(posting_date=add_days(self.disbursement_date, -1), + process_loan_interest_accrual_for_demand_loans(posting_date=add_days(self.disbursement_date, -1), loan=self.against_loan) - disbursed_amount = self.disbursed_amount + loan_details.disbursed_amount - - if flt(disbursed_amount) - flt(loan_details.total_principal_paid) > flt(loan_details.loan_amount): - frappe.throw(_("Disbursed Amount cannot be greater than loan amount")) - - if flt(disbursed_amount) > flt(loan_details.loan_amount): - total_principal_paid = loan_details.total_principal_paid - (disbursed_amount - loan_details.loan_amount) - frappe.db.set_value("Loan", self.against_loan, "total_principal_paid", total_principal_paid) - - if flt(loan_details.loan_amount) == flt(disbursed_amount): - frappe.db.set_value("Loan", self.against_loan, "status", "Disbursed") + if cancel: + disbursed_amount = loan_details.disbursed_amount - self.disbursed_amount + if disbursed_amount == 0: + status = "Sanctioned" + elif disbursed_amount >= loan_details.disbursed_amount: + status = "Disbursed" + else: + status = "Partially Disbursed" else: - frappe.db.set_value("Loan", self.against_loan, "status", "Partially Disbursed") + disbursed_amount = self.disbursed_amount + loan_details.disbursed_amount + + if flt(disbursed_amount) - flt(loan_details.total_principal_paid) > flt(loan_details.loan_amount): + frappe.throw(_("Disbursed Amount cannot be greater than loan amount")) + + if flt(disbursed_amount) >= loan_details.disbursed_amount: + status = "Disbursed" + else: + status = "Partially Disbursed" frappe.db.set_value("Loan", self.against_loan, { "disbursement_date": self.disbursement_date, - "disbursed_amount": disbursed_amount + "disbursed_amount": disbursed_amount, + "status": status }) def make_gl_entries(self, cancel=0, adv_adj=0): diff --git a/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py b/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py index 968e377fcc..189b2f5aff 100644 --- a/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py +++ b/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py @@ -7,8 +7,8 @@ import unittest from frappe.utils import (nowdate, add_days, get_datetime, get_first_day, get_last_day, date_diff, flt, add_to_date) from erpnext.loan_management.doctype.loan.test_loan import (create_loan_type, create_loan_security_pledge, create_repayment_entry, make_loan_disbursement_entry, create_loan_accounts, create_loan_security_type, create_loan_security, create_demand_loan, create_loan_security_price) -from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual -from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import (make_accrual_interest_entry_for_term_loans, days_in_year) +from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_demand_loans +from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year from erpnext.selling.doctype.customer.test_customer import get_customer_dict class TestLoanDisbursement(unittest.TestCase): @@ -56,7 +56,7 @@ class TestLoanDisbursement(unittest.TestCase): make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date) - process_loan_interest_accrual(posting_date=add_days(last_date, 1)) + process_loan_interest_accrual_for_demand_loans(posting_date=add_days(last_date, 1)) # Paid 511095.89 amount includes 5,00,000 principal amount and 11095.89 interest amount repayment_entry = create_repayment_entry(loan.name, self.applicant, add_days(get_last_day(nowdate()), 5), diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.json b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.json index 33f496fc3e..a26112011c 100644 --- a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.json +++ b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.json @@ -23,6 +23,7 @@ "interest_amount", "section_break_15", "process_loan_interest_accrual", + "repayment_schedule_name", "amended_from" ], "fields": [ @@ -135,12 +136,19 @@ { "fieldname": "column_break_14", "fieldtype": "Column Break" + }, + { + "fieldname": "repayment_schedule_name", + "fieldtype": "Data", + "hidden": 1, + "label": "Repayment Schedule Name", + "read_only": 1 } ], "in_create": 1, "is_submittable": 1, "links": [], - "modified": "2020-02-07 01:22:06.924125", + "modified": "2020-04-10 18:31:02.369857", "modified_by": "Administrator", "module": "Loan Management", "name": "Loan Interest Accrual", diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py index b8e6dabba7..094b9c698c 100644 --- a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py +++ b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py @@ -27,8 +27,14 @@ class LoanInterestAccrual(AccountsController): self.make_gl_entries() def on_cancel(self): + if self.repayment_schedule_name: + self.update_is_accrued() + self.make_gl_entries(cancel=1) + def update_is_accrued(self): + frappe.db.set_value('Repayment Schedule', self.repayment_schedule_name, 'is_accrued', 0) + def make_gl_entries(self, cancel=0, adv_adj=0): gle_map = [] @@ -83,9 +89,19 @@ def calculate_accrual_amount_for_demand_loans(loan, posting_date, process_loan_i interest_per_day = (pending_principal_amount * loan.rate_of_interest) / (days_in_year(get_datetime(posting_date).year) * 100) payable_interest = interest_per_day * no_of_days - make_loan_interest_accrual_entry(loan.name, loan.applicant_type, loan.applicant,loan.interest_income_account, - loan.loan_account, pending_principal_amount, payable_interest, process_loan_interest = process_loan_interest, - posting_date=posting_date) + args = frappe._dict({ + 'loan': loan.name, + 'applicant_type': loan.applicant_type, + 'applicant': loan.applicant, + 'interest_income_account': loan.interest_income_account, + 'loan_account': loan.loan_account, + 'pending_principal_amount': pending_principal_amount, + 'interest_amount': payable_interest, + 'process_loan_interest': process_loan_interest, + 'posting_date': posting_date + }) + + make_loan_interest_accrual_entry(args) def make_accrual_interest_entry_for_demand_loans(posting_date, process_loan_interest, open_loans=None, loan_type=None): query_filters = { @@ -107,49 +123,71 @@ def make_accrual_interest_entry_for_demand_loans(posting_date, process_loan_inte for loan in open_loans: calculate_accrual_amount_for_demand_loans(loan, posting_date, process_loan_interest) -def make_accrual_interest_entry_for_term_loans(posting_date=None): +def make_accrual_interest_entry_for_term_loans(posting_date, process_loan_interest, term_loan=None, loan_type=None): curr_date = posting_date or add_days(nowdate(), 1) - term_loans = frappe.db.sql("""SELECT l.name, l.total_payment, l.total_amount_paid, l.loan_account, - l.interest_income_account, l.is_term_loan, l.disbursement_date, l.applicant_type, l.applicant, - l.rate_of_interest, l.total_interest_payable, l.repayment_start_date, rs.name as payment_entry, - rs.payment_date, rs.principal_amount, rs.interest_amount, rs.is_accrued , rs.balance_loan_amount - FROM `tabLoan` l, `tabRepayment Schedule` rs - WHERE rs.parent = l.name - AND l.docstatus=1 - AND l.is_term_loan =1 - AND rs.payment_date <= %s - AND rs.is_accrued=0 - AND l.status = 'Disbursed'""", (curr_date), as_dict=1) + term_loans = get_term_loans(curr_date, term_loan, loan_type) accrued_entries = [] for loan in term_loans: accrued_entries.append(loan.payment_entry) - make_loan_interest_accrual_entry(loan.name, loan.applicant_type, loan.applicant,loan.interest_income_account, - loan.loan_account, loan.principal_amount + loan.balance_loan_amount, loan.interest_amount, - payable_principal = loan.principal_amount , posting_date=posting_date) + args = frappe._dict({ + 'loan': loan.name, + 'applicant_type': loan.applicant_type, + 'applicant': loan.applicant, + 'interest_income_account': loan.interest_income_account, + 'loan_account': loan.loan_account, + 'interest_amount': loan.interest_amount, + 'payable_principal': loan.principal_amount, + 'process_loan_interest': process_loan_interest, + 'repayment_schedule_name': loan.payment_entry, + 'posting_date': posting_date + }) + + make_loan_interest_accrual_entry(args) if accrued_entries: frappe.db.sql("""UPDATE `tabRepayment Schedule` SET is_accrued = 1 where name in (%s)""" #nosec % ", ".join(['%s']*len(accrued_entries)), tuple(accrued_entries)) -def make_loan_interest_accrual_entry(loan, applicant_type, applicant, interest_income_account, loan_account, - pending_principal_amount, interest_amount, payable_principal=None, process_loan_interest=None, posting_date=None): - loan_interest_accrual = frappe.new_doc("Loan Interest Accrual") - loan_interest_accrual.loan = loan - loan_interest_accrual.applicant_type = applicant_type - loan_interest_accrual.applicant = applicant - loan_interest_accrual.interest_income_account = interest_income_account - loan_interest_accrual.loan_account = loan_account - loan_interest_accrual.pending_principal_amount = flt(pending_principal_amount, 2) - loan_interest_accrual.interest_amount = flt(interest_amount, 2) - loan_interest_accrual.posting_date = posting_date or nowdate() - loan_interest_accrual.process_loan_interest_accrual = process_loan_interest +def get_term_loans(date, term_loan=None, loan_type=None): + condition = '' - if payable_principal: - loan_interest_accrual.payable_principal_amount = payable_principal + if term_loan: + condition +=' AND l.name = %s' % frappe.db.escape(term_loan) + + if loan_type: + condition += ' AND l.loan_type = %s' % frappe.db.escape(loan_type) + + term_loans = frappe.db.sql("""SELECT l.name, l.total_payment, l.total_amount_paid, l.loan_account, + l.interest_income_account, l.is_term_loan, l.disbursement_date, l.applicant_type, l.applicant, + l.rate_of_interest, l.total_interest_payable, l.repayment_start_date, rs.name as payment_entry, + rs.payment_date, rs.principal_amount, rs.interest_amount, rs.is_accrued , rs.balance_loan_amount + FROM `tabLoan` l, `tabRepayment Schedule` rs + WHERE rs.parent = l.name + AND l.docstatus=1 + AND l.is_term_loan =1 + AND rs.payment_date <= %s + AND rs.is_accrued=0 {0} + AND l.status = 'Disbursed'""".format(condition), (getdate(date)), as_dict=1) + + return term_loans + +def make_loan_interest_accrual_entry(args): + loan_interest_accrual = frappe.new_doc("Loan Interest Accrual") + loan_interest_accrual.loan = args.loan + loan_interest_accrual.applicant_type = args.applicant_type + loan_interest_accrual.applicant = args.applicant + loan_interest_accrual.interest_income_account = args.interest_income_account + loan_interest_accrual.loan_account = args.loan_account + loan_interest_accrual.pending_principal_amount = flt(args.pending_principal_amount, 2) + loan_interest_accrual.interest_amount = flt(args.interest_amount, 2) + loan_interest_accrual.posting_date = args.posting_date or nowdate() + loan_interest_accrual.process_loan_interest_accrual = args.process_loan_interest + loan_interest_accrual.repayment_schedule_name = args.repayment_schedule_name + loan_interest_accrual.payable_principal_amount = args.payable_principal loan_interest_accrual.save() loan_interest_accrual.submit() diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py b/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py index e681ae42c3..2afed08e18 100644 --- a/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py +++ b/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py @@ -7,8 +7,8 @@ import unittest from frappe.utils import (nowdate, add_days, get_datetime, get_first_day, get_last_day, date_diff, flt, add_to_date) from erpnext.loan_management.doctype.loan.test_loan import (create_loan_type, create_loan_security_pledge, create_loan_security_price, make_loan_disbursement_entry, create_loan_accounts, create_loan_security_type, create_loan_security, create_demand_loan) -from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual -from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import (make_accrual_interest_entry_for_term_loans, days_in_year) +from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_demand_loans +from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year from erpnext.selling.doctype.customer.test_customer import get_customer_dict class TestLoanInterestAccrual(unittest.TestCase): @@ -54,7 +54,7 @@ class TestLoanInterestAccrual(unittest.TestCase): make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date) - process_loan_interest_accrual(posting_date=last_date) + process_loan_interest_accrual_for_demand_loans(posting_date=last_date) loan_interest_accural = frappe.get_doc("Loan Interest Accrual", {'loan': loan.name}) diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py index a70e312880..2d2ca4c2f4 100644 --- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py +++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py @@ -210,7 +210,7 @@ class LoanRepayment(AccountsController): ) if gle_map: - make_gl_entries(gle_map, cancel=cancel, adv_adj=adv_adj) + make_gl_entries(gle_map, cancel=cancel, adv_adj=adv_adj, merge_entries=False) def create_repayment_entry(loan, applicant, company, posting_date, loan_type, payment_type, interest_payable, payable_principal_amount, amount_paid, penalty_amount=None): @@ -223,7 +223,7 @@ def create_repayment_entry(loan, applicant, company, posting_date, loan_type, "posting_date": posting_date, "applicant": applicant, "penalty_amount": penalty_amount, - "interets_payable": interest_payable, + "interst_payable": interest_payable, "payable_principal_amount": payable_principal_amount, "amount_paid": amount_paid, "loan_type": loan_type @@ -236,7 +236,8 @@ def get_accrued_interest_entries(against_loan): fields=["name", "interest_amount", "posting_date", "payable_principal_amount"], filters = { "loan": against_loan, - "is_paid": 0 + "is_paid": 0, + "docstatus": 1 }, order_by="posting_date") return accrued_interest_entries @@ -272,7 +273,9 @@ def get_amounts(amounts, against_loan, posting_date, payment_type): total_pending_interest += entry.interest_amount payable_principal_amount += entry.payable_principal_amount - pending_accrual_entries.setdefault(entry.name, entry.interest_amount) + pending_accrual_entries.setdefault(entry.name, + flt(entry.interest_amount) + flt(entry.payable_principal_amount)) + final_due_date = due_date pending_principal_amount = against_loan_doc.total_payment - against_loan_doc.total_principal_paid - against_loan_doc.total_interest_payable diff --git a/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py b/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py index b7be84f836..ab040f1d33 100644 --- a/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py +++ b/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py @@ -37,17 +37,10 @@ def add_security(loan): return loan_security_pledge.as_dict() -def check_for_ltv_shortfall(process_loan_security_shortfall=None): +def check_for_ltv_shortfall(process_loan_security_shortfall): update_time = get_datetime() - if not process_loan_security_shortfall: - process = frappe.new_doc("Process Loan Security Shortfall") - process.update_time = update_time - process.submit() - - process_loan_security_shortfall = process.name - loan_security_price_map = frappe._dict(frappe.get_all("Loan Security Price", fields=["loan_security", "loan_security_price"], filters = { diff --git a/erpnext/loan_management/doctype/loan_type/loan_type.py b/erpnext/loan_management/doctype/loan_type/loan_type.py index 14b18ab57a..208cb19c88 100644 --- a/erpnext/loan_management/doctype/loan_type/loan_type.py +++ b/erpnext/loan_management/doctype/loan_type/loan_type.py @@ -19,3 +19,6 @@ class LoanType(Document): frappe.throw(_("Account {0} does not belong to company {1}").format(frappe.bold(self.get(fieldname)), frappe.bold(self.company))) + if self.get('loan_account') == self.get('payment_account'): + frappe.throw(_('Loan Account and Payment Account cannot be same')) + diff --git a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.json b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.json index 7f79cb1fd9..0ef098f278 100644 --- a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.json +++ b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.json @@ -9,6 +9,7 @@ "posting_date", "loan_type", "loan", + "process_type", "amended_from" ], "fields": [ @@ -39,11 +40,18 @@ "fieldtype": "Link", "label": "Loan ", "options": "Loan" + }, + { + "fieldname": "process_type", + "fieldtype": "Data", + "hidden": 1, + "label": "Process Type", + "read_only": 1 } ], "is_submittable": 1, "links": [], - "modified": "2020-02-01 08:14:33.978636", + "modified": "2020-04-09 22:52:53.911416", "modified_by": "Administrator", "module": "Loan Management", "name": "Process Loan Interest Accrual", @@ -74,7 +82,6 @@ "write": 1 } ], - "quick_entry": 1, "sort_field": "modified", "sort_order": "DESC", "track_changes": 1 diff --git a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py index 0f33da918d..cd3cf7ec96 100644 --- a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py +++ b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py @@ -6,7 +6,8 @@ from __future__ import unicode_literals import frappe from frappe.utils import nowdate from frappe.model.document import Document -from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import make_accrual_interest_entry_for_demand_loans +from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import (make_accrual_interest_entry_for_demand_loans, + make_accrual_interest_entry_for_term_loans) class ProcessLoanInterestAccrual(Document): def on_submit(self): @@ -14,16 +15,45 @@ class ProcessLoanInterestAccrual(Document): if self.loan: loan_doc = frappe.get_doc('Loan', self.loan) - open_loans.append(loan_doc) + if loan_doc: + open_loans.append(loan_doc) - make_accrual_interest_entry_for_demand_loans(self.posting_date, self.name, - open_loans = open_loans, loan_type = self.loan_type) + if (not self.loan or not loan_doc.is_term_loan) and self.process_type != 'Term Loans': + make_accrual_interest_entry_for_demand_loans(self.posting_date, self.name, + open_loans = open_loans, loan_type = self.loan_type) -def process_loan_interest_accrual(posting_date=None, loan_type=None, loan=None): + if (not self.loan or loan_doc.is_term_loan) and self.process_type != 'Demand Loans': + make_accrual_interest_entry_for_term_loans(self.posting_date, self.name, term_loan=self.loan, + loan_type=self.loan_type) + + +def process_loan_interest_accrual_for_demand_loans(posting_date=None, loan_type=None, loan=None): loan_process = frappe.new_doc('Process Loan Interest Accrual') loan_process.posting_date = posting_date or nowdate() loan_process.loan_type = loan_type + loan_process.process_type = 'Demand Loans' loan_process.loan = loan loan_process.submit() +def process_loan_interest_accrual_for_term_loans(posting_date=None, loan_type=None, loan=None): + + if not term_loan_accrual_pending(posting_date or nowdate()): + return + + loan_process = frappe.new_doc('Process Loan Interest Accrual') + loan_process.posting_date = posting_date or nowdate() + loan_process.loan_type = loan_type + loan_process.process_type = 'Term Loans' + loan_process.loan = loan + + loan_process.submit() + +def term_loan_accrual_pending(date): + pending_accrual = frappe.db.get_value('Repayment Schedule', { + 'payment_date': ('<=', date), + 'is_accrued': 0 + }) + + return pending_accrual + diff --git a/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall.py b/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall.py index 417e3678c9..b4aad25ac8 100644 --- a/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall.py +++ b/erpnext/loan_management/doctype/process_loan_security_shortfall/process_loan_security_shortfall.py @@ -14,4 +14,13 @@ class ProcessLoanSecurityShortfall(Document): self.set_onload('update_time', get_datetime()) def on_submit(self): - check_for_ltv_shortfall(process_loan_security_shortfall = self.name) + check_for_ltv_shortfall(self.name) + +def create_process_loan_security_shortfall(): + if check_for_secured_loans(): + process = frappe.new_doc("Process Loan Security Shortfall") + process.update_time = get_datetime() + process.submit() + +def check_for_secured_loans(): + return frappe.db.count('Loan', {'docstatus': 1, 'is_secured_loan': 1}) diff --git a/erpnext/loan_management/doctype/salary_slip_loan/salary_slip_loan.json b/erpnext/loan_management/doctype/salary_slip_loan/salary_slip_loan.json index ce020fff07..f7e211656e 100644 --- a/erpnext/loan_management/doctype/salary_slip_loan/salary_slip_loan.json +++ b/erpnext/loan_management/doctype/salary_slip_loan/salary_slip_loan.json @@ -1,4 +1,5 @@ { + "actions": [], "creation": "2019-08-29 18:11:36.829526", "doctype": "DocType", "editable_grid": 1, @@ -49,16 +50,14 @@ "fieldtype": "Currency", "in_list_view": 1, "label": "Principal Amount", - "options": "Company:company:default_currency", - "read_only": 1 + "options": "Company:company:default_currency" }, { "fieldname": "interest_amount", "fieldtype": "Currency", "in_list_view": 1, "label": "Interest Amount", - "options": "Company:company:default_currency", - "read_only": 1 + "options": "Company:company:default_currency" }, { "fieldname": "total_payment", @@ -79,11 +78,13 @@ "fieldname": "loan_type", "fieldtype": "Link", "label": "Loan Type", - "options": "Loan Type" + "options": "Loan Type", + "read_only": 1 } ], "istable": 1, - "modified": "2019-10-28 09:15:31.174244", + "links": [], + "modified": "2020-04-09 20:01:53.546364", "modified_by": "Administrator", "module": "Loan Management", "name": "Salary Slip Loan", diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 9b5e5d02fb..9ef0b8d510 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -663,6 +663,7 @@ erpnext.patches.v12_0.move_bank_account_swift_number_to_bank erpnext.patches.v12_0.rename_bank_reconciliation_fields # 2020-01-22 erpnext.patches.v12_0.set_received_qty_in_material_request_as_per_stock_uom erpnext.patches.v12_0.recalculate_requested_qty_in_bin +erpnext.patches.v12_0.update_healthcare_refactored_changes erpnext.patches.v12_0.set_total_batch_quantity erpnext.patches.v12_0.rename_mws_settings_fields erpnext.patches.v12_0.set_updated_purpose_in_pick_list diff --git a/erpnext/patches/v12_0/set_against_blanket_order_in_sales_and_purchase_order.py b/erpnext/patches/v12_0/set_against_blanket_order_in_sales_and_purchase_order.py index 3fccbfa700..85202bff4d 100644 --- a/erpnext/patches/v12_0/set_against_blanket_order_in_sales_and_purchase_order.py +++ b/erpnext/patches/v12_0/set_against_blanket_order_in_sales_and_purchase_order.py @@ -1,10 +1,11 @@ import frappe + def execute(): - frappe.reload_doc('selling', 'doctype', frappe.scrub('Sales Order Item')) - frappe.reload_doc('buying', 'doctype', frappe.scrub('Purchase Order Item')) + frappe.reload_doc('selling', 'doctype', 'sales_order_item', force=True) + frappe.reload_doc('buying', 'doctype', 'purchase_order_item', force=True) - for doctype in ['Sales Order Item', 'Purchase Order Item']: + for doctype in ('Sales Order Item', 'Purchase Order Item'): frappe.db.sql(""" UPDATE `tab{0}` SET against_blanket_order = 1 diff --git a/erpnext/patches/v12_0/update_healthcare_refactored_changes.py b/erpnext/patches/v12_0/update_healthcare_refactored_changes.py new file mode 100644 index 0000000000..02378e0922 --- /dev/null +++ b/erpnext/patches/v12_0/update_healthcare_refactored_changes.py @@ -0,0 +1,137 @@ +from __future__ import unicode_literals +import frappe +from frappe.model.utils.rename_field import rename_field +from frappe.modules import scrub, get_doctype_module + +field_rename_map = { + 'Healthcare Settings': [ + ['patient_master_name', 'patient_name_by'], + ['max_visit', 'max_visits'], + ['reg_sms', 'send_registration_msg'], + ['reg_msg', 'registration_msg'], + ['app_con', 'send_appointment_confirmation'], + ['app_con_msg', 'appointment_confirmation_msg'], + ['no_con', 'avoid_confirmation'], + ['app_rem', 'send_appointment_reminder'], + ['app_rem_msg', 'appointment_reminder_msg'], + ['rem_before', 'remind_before'], + ['manage_customer', 'link_customer_to_patient'], + ['create_test_on_si_submit', 'create_lab_test_on_si_submit'], + ['require_sample_collection', 'create_sample_collection_for_lab_test'], + ['require_test_result_approval', 'lab_test_approval_required'], + ['manage_appointment_invoice_automatically', 'automate_appointment_invoicing'] + ], + 'Drug Prescription':[ + ['use_interval', 'usage_interval'], + ['in_every', 'interval_uom'] + ], + 'Lab Test Template':[ + ['sample_quantity', 'sample_qty'], + ['sample_collection_details', 'sample_details'] + ], + 'Sample Collection':[ + ['sample_quantity', 'sample_qty'], + ['sample_collection_details', 'sample_details'] + ], + 'Fee Validity': [ + ['max_visit', 'max_visits'] + ] +} + +def execute(): + for dn in field_rename_map: + if frappe.db.exists('DocType', dn): + if dn == 'Healthcare Settings': + frappe.reload_doctype('Healthcare Settings') + else: + frappe.reload_doc(get_doctype_module(dn), "doctype", scrub(dn)) + + for dt, field_list in field_rename_map.items(): + if frappe.db.exists('DocType', dt): + for field in field_list: + if dt == 'Healthcare Settings': + rename_field(dt, field[0], field[1]) + elif frappe.db.has_column(dt, field[0]): + rename_field(dt, field[0], field[1]) + + # first name mandatory in Patient + if frappe.db.exists('DocType', 'Patient'): + patients = frappe.db.sql("select name, patient_name from `tabPatient`", as_dict=1) + frappe.reload_doc('healthcare', 'doctype', 'patient') + for entry in patients: + name = entry.patient_name.split(' ') + frappe.db.set_value('Patient', entry.name, 'first_name', name[0]) + + # mark Healthcare Practitioner status as Disabled + if frappe.db.exists('DocType', 'Healthcare Practitioner'): + practitioners = frappe.db.sql("select name from `tabHealthcare Practitioner` where 'active'= 0", as_dict=1) + practitioners_lst = [p.name for p in practitioners] + frappe.reload_doc('healthcare', 'doctype', 'healthcare_practitioner') + if practitioners_lst: + frappe.db.sql("update `tabHealthcare Practitioner` set status = 'Disabled' where name IN %(practitioners)s""", {"practitioners": practitioners_lst}) + + # set Clinical Procedure status + if frappe.db.exists('DocType', 'Clinical Procedure'): + frappe.reload_doc('healthcare', 'doctype', 'clinical_procedure') + frappe.db.sql(""" + UPDATE + `tabClinical Procedure` + SET + docstatus = (CASE WHEN status = 'Cancelled' THEN 2 + WHEN status = 'Draft' THEN 0 + ELSE 1 + END) + """) + + # set complaints and diagnosis in table multiselect in Patient Encounter + if frappe.db.exists('DocType', 'Patient Encounter'): + field_list = [ + ['visit_department', 'medical_department'], + ['type', 'appointment_type'] + ] + encounter_details = frappe.db.sql("""select symptoms, diagnosis, name from `tabPatient Encounter`""", as_dict=True) + frappe.reload_doc('healthcare', 'doctype', 'patient_encounter') + frappe.reload_doc('healthcare', 'doctype', 'patient_encounter_symptom') + frappe.reload_doc('healthcare', 'doctype', 'patient_encounter_diagnosis') + + for field in field_list: + if frappe.db.has_column(dt, field[0]): + rename_field(dt, field[0], field[1]) + + for entry in encounter_details: + doc = frappe.get_doc('Patient Encounter', entry.name) + symptoms = entry.symptoms.split('\n') + for symptom in symptoms: + if not frappe.db.exists('Complaint', symptom): + frappe.get_doc({ + 'doctype': 'Complaint', + 'complaints': symptom + }).insert() + row = doc.append('symptoms', { + 'complaint': symptom + }) + row.db_update() + + diagnosis = entry.diagnosis.split('\n') + for d in diagnosis: + if not frappe.db.exists('Diagnosis', d): + frappe.get_doc({ + 'doctype': 'Diagnosis', + 'diagnosis': d + }).insert() + row = doc.append('diagnosis', { + 'diagnosis': d + }) + row.db_update() + doc.db_update() + + if frappe.db.exists('DocType', 'Fee Validity'): + # update fee validity status + frappe.db.sql(""" + UPDATE + `tabFee Validity` + SET + status = (CASE WHEN visited >= max_visits THEN 'Completed' + ELSE 'Pending' + END) + """) \ No newline at end of file diff --git a/erpnext/projects/doctype/project/project.json b/erpnext/projects/doctype/project/project.json index 7d47db371d..49abab1c13 100644 --- a/erpnext/projects/doctype/project/project.json +++ b/erpnext/projects/doctype/project/project.json @@ -1,4 +1,5 @@ { + "actions": [], "allow_import": 1, "allow_rename": 1, "autoname": "field:project_name", @@ -435,16 +436,18 @@ }, { "depends_on": "collect_progress", - "description": "Message will sent to users to get their status on the project", + "description": "Message will be sent to the users to get their status on the Project", "fieldname": "message", "fieldtype": "Text", - "label": "Message" + "label": "Message", + "mandatory_depends_on": "collect_progress" } ], "icon": "fa fa-puzzle-piece", "idx": 29, + "links": [], "max_attachments": 4, - "modified": "2019-09-24 15:02:50.208301", + "modified": "2020-04-08 22:11:14.552615", "modified_by": "Administrator", "module": "Projects", "name": "Project", @@ -487,4 +490,4 @@ "sort_order": "DESC", "timeline_field": "customer", "track_seen": 1 -} \ No newline at end of file +} diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index 02667e8c23..50e719f02e 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -150,7 +150,7 @@ class Customer(TransactionBase): contact.save() else: - lead.lead_name = lead.lead_name.split(" ") + lead.lead_name = lead.lead_name.lstrip().split(" ") lead.first_name = lead.lead_name[0] lead.last_name = " ".join(lead.lead_name[1:]) diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py index 0d3e33164a..dab5a7beb8 100644 --- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py +++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py @@ -72,7 +72,7 @@ class StockLedgerEntry(Document): frappe.throw(_("Actual Qty is mandatory")) def validate_item(self): - item_det = frappe.db.sql("""select name, has_batch_no, docstatus, + item_det = frappe.db.sql("""select name, item_name, has_batch_no, docstatus, is_stock_item, has_variants, stock_uom, create_new_batch from tabItem where name=%s""", self.item_code, as_dict=True) @@ -87,10 +87,11 @@ class StockLedgerEntry(Document): # check if batch number is required if self.voucher_type != 'Stock Reconciliation': if item_det.has_batch_no ==1: + batch_item = self.item_code if self.item_code == item_det.item_name else self.item_code + ":" + item_det.item_name if not self.batch_no: - frappe.throw(_("Batch number is mandatory for Item {0}").format(self.item_code)) + frappe.throw(_("Batch number is mandatory for Item {0}").format(batch_item)) elif not frappe.db.get_value("Batch",{"item": self.item_code, "name": self.batch_no}): - frappe.throw(_("{0} is not a valid Batch Number for Item {1}").format(self.batch_no, self.item_code)) + frappe.throw(_("{0} is not a valid Batch Number for Item {1}").format(self.batch_no, batch_item)) elif item_det.has_batch_no ==0 and self.batch_no and self.is_cancelled == "No": frappe.throw(_("The Item {0} cannot have Batch").format(self.item_code))