From 665b48773f042f4dc4a0c55631f4814637e5f150 Mon Sep 17 00:00:00 2001 From: Jamsheer Date: Thu, 8 Mar 2018 13:08:35 +0530 Subject: [PATCH] Healthcare - Patient Appointment - Service unit based scheduling and booking (#13211) * New Document - Patient Service Unit * Physician - schedule based on patient service unit * Consultation - Remove validation on submit * Consultation - Label changed from Drug Prescription to Medication * Availability check and book appointment based on service unit, appointment invoice creation optimized * patch fixes * Patient Service Unit - field - overlap_appointments * Patient Appointment - Service Unit based scheduling and booking * Patient Appointment - issue fixed #13016 Healthcare Patient Appointment Save Button Issue - remove validation on save and enable save on book appointment * Codacy fixes on PR #13211 * Codacy fixes on PR #13211 * Fee validity test -fixes * Fee Validity - test - fixes --- erpnext/config/healthcare.py | 5 + .../doctype/consultation/consultation.json | 6 +- .../doctype/consultation/consultation.py | 5 - .../doctype/fee_validity/test_fee_validity.py | 25 +- .../patient_appointment.js | 93 +++-- .../patient_appointment.json | 269 ++++++++----- .../patient_appointment.py | 108 +++--- .../doctype/patient_service_unit/__init__.py | 0 .../patient_service_unit.js | 15 + .../patient_service_unit.json | 358 ++++++++++++++++++ .../patient_service_unit.py | 14 + .../patient_service_unit_tree.js | 3 + .../test_patient_service_unit.js | 23 ++ .../test_patient_service_unit.py | 8 + .../healthcare/doctype/physician/physician.js | 7 + .../doctype/physician/physician.json | 70 +--- .../healthcare/doctype/physician/physician.py | 10 - .../doctype/physician/test_physician.py | 17 - .../__init__.py | 0 .../physician_service_unit_schedule.json | 103 +++++ .../physician_service_unit_schedule.py | 9 + erpnext/patches.txt | 1 + .../remove_and_copy_fields_in_physician.py | 12 + 23 files changed, 878 insertions(+), 283 deletions(-) create mode 100644 erpnext/healthcare/doctype/patient_service_unit/__init__.py create mode 100644 erpnext/healthcare/doctype/patient_service_unit/patient_service_unit.js create mode 100644 erpnext/healthcare/doctype/patient_service_unit/patient_service_unit.json create mode 100644 erpnext/healthcare/doctype/patient_service_unit/patient_service_unit.py create mode 100644 erpnext/healthcare/doctype/patient_service_unit/patient_service_unit_tree.js create mode 100644 erpnext/healthcare/doctype/patient_service_unit/test_patient_service_unit.js create mode 100644 erpnext/healthcare/doctype/patient_service_unit/test_patient_service_unit.py create mode 100644 erpnext/healthcare/doctype/physician_service_unit_schedule/__init__.py create mode 100644 erpnext/healthcare/doctype/physician_service_unit_schedule/physician_service_unit_schedule.json create mode 100644 erpnext/healthcare/doctype/physician_service_unit_schedule/physician_service_unit_schedule.py create mode 100644 erpnext/patches/v10_0/remove_and_copy_fields_in_physician.py diff --git a/erpnext/config/healthcare.py b/erpnext/config/healthcare.py index 34a9b70c51..4e8bb483a2 100644 --- a/erpnext/config/healthcare.py +++ b/erpnext/config/healthcare.py @@ -86,6 +86,11 @@ def get_data(): "type": "doctype", "name": "Medical Code", "label": _("Medical Code"), + }, + { + "type": "doctype", + "name": "Patient Service Unit", + "label": _("Patient Service Unit") } ] }, diff --git a/erpnext/healthcare/doctype/consultation/consultation.json b/erpnext/healthcare/doctype/consultation/consultation.json index 184f484e24..c1bd37a3d2 100644 --- a/erpnext/healthcare/doctype/consultation/consultation.json +++ b/erpnext/healthcare/doctype/consultation/consultation.json @@ -767,7 +767,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Drug Prescription", + "label": "Medication", "length": 0, "no_copy": 0, "permlevel": 0, @@ -797,7 +797,7 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, - "label": "Drug Prescription", + "label": "Medication", "length": 0, "no_copy": 0, "options": "Drug Prescription", @@ -945,7 +945,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-12-28 11:25:35.256848", + "modified": "2018-02-19 11:35:13.826577", "modified_by": "Administrator", "module": "Healthcare", "name": "Consultation", diff --git a/erpnext/healthcare/doctype/consultation/consultation.py b/erpnext/healthcare/doctype/consultation/consultation.py index 7d41afe65e..451c4914b0 100755 --- a/erpnext/healthcare/doctype/consultation/consultation.py +++ b/erpnext/healthcare/doctype/consultation/consultation.py @@ -4,7 +4,6 @@ from __future__ import unicode_literals import frappe -from frappe import _ from frappe.model.document import Document from frappe.utils import getdate import json @@ -19,10 +18,6 @@ class Consultation(Document): def after_insert(self): insert_consultation_to_medical_record(self) - def on_submit(self): - if not self.diagnosis or not self.symptoms: - frappe.throw(_("Diagnosis and Complaints cannot be left blank")) - def on_cancel(self): if(self.appointment): frappe.db.set_value("Patient Appointment", self.appointment, "status", "Open") diff --git a/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py b/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py index 53f82e034c..7ad673d535 100644 --- a/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py +++ b/erpnext/healthcare/doctype/fee_validity/test_fee_validity.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import frappe import unittest -from erpnext.healthcare.doctype.patient_appointment.patient_appointment import create_invoice +from erpnext.healthcare.doctype.patient_appointment.patient_appointment import invoice_appointment from frappe.utils.make_random import get_random from frappe.utils import nowdate, add_days # test_records = frappe.get_test_records('Fee Validity') @@ -14,6 +14,7 @@ class TestFeeValidity(unittest.TestCase): def test_fee_validity(self): patient = get_random("Patient") physician = get_random("Physician") + department = get_random("Medical Department") if not patient: patient = frappe.new_doc("Patient") @@ -22,33 +23,43 @@ class TestFeeValidity(unittest.TestCase): patient.save(ignore_permissions=True) patient = patient.name + 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 physician: physician = frappe.new_doc("Physician") physician.first_name = "Amit Jain" + physician.department = department physician.save(ignore_permissions=True) physician = physician.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, physician, nowdate()) + appointment = create_appointment(patient, physician, nowdate(), department) invoice = frappe.db.get_value("Patient Appointment", appointment.name, "sales_invoice") self.assertEqual(invoice, None) - create_invoice(frappe.defaults.get_global_default("company"), physician, patient, appointment.name, appointment.appointment_date) - appointment = create_appointment(patient, physician, add_days(nowdate(), 4)) + invoice_appointment(appointment) + appointment = create_appointment(patient, physician, add_days(nowdate(), 4), department) invoice = frappe.db.get_value("Patient Appointment", appointment.name, "sales_invoice") self.assertTrue(invoice) - appointment = create_appointment(patient, physician, add_days(nowdate(), 5)) + appointment = create_appointment(patient, physician, add_days(nowdate(), 5), department) invoice = frappe.db.get_value("Patient Appointment", appointment.name, "sales_invoice") self.assertEqual(invoice, None) - appointment = create_appointment(patient, physician, add_days(nowdate(), 10)) + appointment = create_appointment(patient, physician, add_days(nowdate(), 10), department) invoice = frappe.db.get_value("Patient Appointment", appointment.name, "sales_invoice") self.assertEqual(invoice, None) -def create_appointment(patient, physician, appointment_date): +def create_appointment(patient, physician, appointment_date, department): appointment = frappe.new_doc("Patient Appointment") appointment.patient = patient appointment.physician = physician + appointment.department = department appointment.appointment_date = appointment_date appointment.save(ignore_permissions=True) return appointment diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js index 89121573f6..f34f7cfe1a 100644 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js +++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js @@ -15,6 +15,20 @@ frappe.ui.form.on('Patient Appointment', { filters: {"disabled": 0} }; }); + frm.set_query("physician", function() { + return { + filters: { + 'department': frm.doc.department + } + }; + }); + frm.set_query("service_unit", function(){ + return { + filters: { + "is_group": false, + } + }; + }); if(frm.doc.patient){ frm.add_custom_button(__('Medical Record'), function() { frappe.route_options = {"patient": frm.doc.patient}; @@ -83,11 +97,10 @@ frappe.ui.form.on('Patient Appointment', { date: appointment_date }, callback: (r) => { - // console.log(r); var data = r.message; - if(data.available_slots.length > 0) { + if(data.slot_details.length > 0){ show_availability(data); - } else { + }else{ show_empty_state(); } } @@ -108,48 +121,71 @@ frappe.ui.form.on('Patient Appointment', { primary_action_label: __("Book"), primary_action: function() { // book slot - frm.set_value('appointment_time', selected_slot); - frm.set_value('duration', data.time_per_appointment); + var btn_selected = $wrapper.find('button.btn-selected-slot'); + frm.set_value('appointment_time', btn_selected.attr('data-name')); + frm.set_value('service_unit', btn_selected.attr('data-service-unit') || ''); + frm.set_value('duration', btn_selected.attr('data-duration')); d.hide(); frm.save(); + frm.enable_save(); } }); var $wrapper = d.fields_dict.available_slots.$wrapper; - var selected_slot = null; // disable dialog action initially d.get_primary_btn().attr('disabled', true); - // make buttons for each slot - var slot_html = data.available_slots.map(slot => { - return ``; - }).join(""); + var slot_details = data.slot_details; + var slot_html = ""; + $.each(slot_details, function(i, slot_detail){ + slot_html = slot_html + ``; + slot_html = slot_html + `
` + slot_detail['avail_slot'].map(slot => { + let disabled = ''; + let start_str = slot.from_time; + let start_time = moment(slot.from_time, 'HH:mm:ss'); + let to_time = moment(slot.to_time, 'HH:mm:ss'); + let interval = (to_time - start_time)/60000 | 0; + // iterate in all booked appointments, update the start time and duration + slot_detail['appointments'].forEach(function(booked) { + let booked_moment = moment(booked.appointment_time, 'HH:mm:ss'); + if(booked_moment.isSame(start_time) || booked_moment.isBetween(start_time, to_time)){ + if(booked.duration == 0){ + disabled = 'disabled="disabled"'; + return false; + } + start_time = booked_moment; + let end_time = booked_moment.add(booked.duration, 'minutes'); + if(end_time.isSameOrAfter(to_time)){ + disabled = 'disabled="disabled"'; + return false; + }else{ + start_str = end_time.format('HH:mm:ss'); + } + } + }); + return ``; + }).join(""); + slot_html = slot_html + `
`; + }); $wrapper .css('margin-bottom', 0) .addClass('text-center') .html(slot_html); - // disable buttons for which appointments are booked - data.appointments.map(slot => { - if(slot.status == "Scheduled" || slot.status == "Open" || slot.status == "Closed"){ - $wrapper - .find(`button[data-name="${slot.appointment_time}"]`) - .attr('disabled', true); - } - }); - // blue button when clicked $wrapper.on('click', 'button', function() { var $btn = $(this); $wrapper.find('button').removeClass('btn-primary'); + $wrapper.find('button').removeClass('btn-selected-slot'); $btn.addClass('btn-primary'); - selected_slot = $btn.attr('data-name'); - + $btn.addClass('btn-selected-slot'); // enable dialog action d.get_primary_btn().attr('disabled', null); }); @@ -209,12 +245,9 @@ var btn_update_status = function(frm, status){ }; var btn_invoice_consultation = function(frm){ - var doc = frm.doc; frappe.call({ - method: - "erpnext.healthcare.doctype.patient_appointment.patient_appointment.create_invoice", - args: {company: doc.company, physician:doc.physician, patient: doc.patient, - appointment_id: doc.name, appointment_date:doc.appointment_date }, + doc: frm.doc, + method:"create_invoice", callback: function(data){ if(!data.exc){ if(data.message){ diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json index 1dcdbb57f1..022a9d6d49 100644 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json +++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.json @@ -42,6 +42,39 @@ "reqd": 1, "search_index": 1, "set_only_once": 1, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 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": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 1, + "set_only_once": 1, + "translatable": 0, "unique": 0 }, { @@ -73,6 +106,7 @@ "reqd": 1, "search_index": 1, "set_only_once": 1, + "translatable": 0, "unique": 0 }, { @@ -103,6 +137,71 @@ "reqd": 1, "search_index": 1, "set_only_once": 1, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 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": 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 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "depends_on": "eval:!doc.__islocal", + "description": "In Minutes", + "fieldname": "duration", + "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": "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 }, { @@ -134,6 +233,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -151,8 +251,42 @@ "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 + }, + { + "allow_bulk_edit": 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": "Patient Service Unit", "permlevel": 0, "precision": "", "print_hide": 0, @@ -162,7 +296,8 @@ "report_hide": 0, "reqd": 0, "search_index": 0, - "set_only_once": 0, + "set_only_once": 1, + "translatable": 0, "unique": 0 }, { @@ -195,6 +330,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -226,6 +362,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -257,6 +394,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -271,7 +409,7 @@ "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, - "in_filter": 0, + "in_filter": 1, "in_global_search": 0, "in_list_view": 1, "in_standard_filter": 0, @@ -289,6 +427,7 @@ "reqd": 0, "search_index": 1, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -319,7 +458,8 @@ "report_hide": 0, "reqd": 0, "search_index": 0, - "set_only_once": 1, + "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -349,68 +489,8 @@ "report_hide": 0, "reqd": 0, "search_index": 0, - "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 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": 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": 0, - "search_index": 0, "set_only_once": 1, - "unique": 0 - }, - { - "allow_bulk_edit": 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": 0, - "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 }, { @@ -441,6 +521,7 @@ "reqd": 0, "search_index": 1, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -470,37 +551,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, - "unique": 0 - }, - { - "allow_bulk_edit": 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": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 1, - "set_only_once": 1, + "translatable": 0, "unique": 0 }, { @@ -532,6 +583,7 @@ "reqd": 0, "search_index": 1, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -563,6 +615,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -593,6 +646,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -623,6 +677,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 }, { @@ -654,6 +709,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 1, + "translatable": 0, "unique": 0 }, { @@ -685,6 +741,7 @@ "reqd": 0, "search_index": 0, "set_only_once": 0, + "translatable": 0, "unique": 0 } ], @@ -698,7 +755,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2017-12-28 11:26:20.262978", + "modified": "2018-02-26 12:44:33.756124", "modified_by": "Administrator", "module": "Healthcare", "name": "Patient Appointment", @@ -744,6 +801,26 @@ "share": 1, "submit": 0, "write": 1 + }, + { + "amend": 0, + "apply_user_permissions": 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, diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py index 90d4d0ea20..626774bd58 100755 --- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py +++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py @@ -6,7 +6,7 @@ from __future__ import unicode_literals import frappe from frappe.model.document import Document import json -from frappe.utils import getdate, cint +from frappe.utils import getdate from frappe import _ import datetime from frappe.core.doctype.sms_settings.sms_settings import send_sms @@ -40,13 +40,8 @@ class PatientAppointment(Document): frappe.msgprint(_("{0} has fee validity till {1}").format(appointment.patient, fee_validity.valid_till)) confirm_sms(self) - def save(self, *args, **kwargs): - # duration is the only changeable field in the document - if not self.is_new(): - self.db_set('duration', cint(self.duration)) - else: - super(PatientAppointment, self).save(*args, **kwargs) - + def create_invoice(self): + return invoice_appointment(self) def appointment_cancel(appointment_id): appointment = frappe.get_doc("Patient Appointment", appointment_id) @@ -79,9 +74,9 @@ def get_availability_data(date, physician): weekday = date.strftime("%A") available_slots = [] - physician_schedule_name = None + slot_details = [] physician_schedule = None - time_per_appointment = None + employee = None physician_obj = frappe.get_doc("Physician", physician) @@ -112,43 +107,56 @@ def get_availability_data(date, physician): frappe.throw(_("Dr {0} on Leave on {1}").format(physician, date)) # get physicians schedule - physician_schedule_name = frappe.db.get_value("Physician", physician, "physician_schedule") - if physician_schedule_name: - physician_schedule = frappe.get_doc("Physician Schedule", physician_schedule_name) - time_per_appointment = frappe.db.get_value("Physician", physician, "time_per_appointment") + if physician_obj.physician_schedules: + for schedule in physician_obj.physician_schedules: + if schedule.schedule: + physician_schedule = frappe.get_doc("Physician Schedule", schedule.schedule) + else: + frappe.throw(_("Dr {0} does not have a Physician Schedule. Add it in Physician master".format(physician))) + + if physician_schedule: + available_slots = [] + for t in physician_schedule.time_slots: + if weekday == t.day: + available_slots.append(t) + + if available_slots: + appointments = [] + if schedule.service_unit: + slot_name = schedule.schedule+" - "+schedule.service_unit + allow_overlap = frappe.get_value('Patient Service Unit', schedule.service_unit, 'overlap_appointments') + if allow_overlap: + # fetch all appointments to physician by service unit + appointments = frappe.get_all( + "Patient Appointment", + filters={"physician": physician, "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 physician without service unit + appointments = frappe.get_all( + "Patient Appointment", + filters={"physician": physician, "service_unit": '', "appointment_date": date, "status": ["not in",["Cancelled"]]}, + fields=["name", "appointment_time", "duration", "status"]) + + slot_details.append({"slot_name":slot_name, "service_unit":schedule.service_unit, + "avail_slot":available_slots, 'appointments': appointments}) + else: frappe.throw(_("Dr {0} does not have a Physician Schedule. Add it in Physician master".format(physician))) - if physician_schedule: - for t in physician_schedule.time_slots: - if weekday == t.day: - available_slots.append(t) - - # `time_per_appointment` should never be None since validation in `Patient` is supposed to prevent - # that. However, it isn't impossible so we'll prepare for that. - if not time_per_appointment: - frappe.throw(_('"Time Per Appointment" hasn"t been set for Dr {0}. Add it in Physician master.').format(physician)) - - # if physician not available return - if not available_slots: + if not available_slots and not slot_details: # TODO: return available slots in nearby dates frappe.throw(_("Physician not available on {0}").format(weekday)) - # if physician on leave return - - # if holiday return - # if is_holiday(weekday): - - # get appointments on that day for physician - appointments = frappe.get_all( - "Patient Appointment", - filters={"physician": physician, "appointment_date": date}, - fields=["name", "appointment_time", "duration", "status"]) - return { - "available_slots": available_slots, - "appointments": appointments, - "time_per_appointment": time_per_appointment + "slot_details": slot_details } @@ -182,25 +190,25 @@ def confirm_sms(doc): @frappe.whitelist() -def create_invoice(company, physician, patient, appointment_id, appointment_date): - if not appointment_id: +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", patient, "customer") - sales_invoice.appointment = appointment_id + 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 = '0' - sales_invoice.debit_to = get_receivable_account(company) + sales_invoice.debit_to = get_receivable_account(appointment_doc.company) - fee_validity = get_fee_validity(physician, patient, appointment_date) - create_invoice_items(appointment_id, physician, company, sales_invoice) + fee_validity = get_fee_validity(appointment_doc.physician, appointment_doc.patient, appointment_doc.appointment_date) + create_invoice_items(appointment_doc.physician, appointment_doc.company, sales_invoice) sales_invoice.save(ignore_permissions=True) - frappe.db.sql("""update `tabPatient Appointment` set sales_invoice=%s where name=%s""", (sales_invoice.name, appointment_id)) + frappe.db.sql("""update `tabPatient Appointment` set sales_invoice=%s where name=%s""", (sales_invoice.name, appointment_doc.name)) frappe.db.set_value("Fee Validity", fee_validity.name, "ref_invoice", sales_invoice.name) consultation = frappe.db.exists({ "doctype": "Consultation", - "appointment": appointment_id}) + "appointment": appointment_doc.name}) if consultation: frappe.db.set_value("Consultation", consultation[0][0], "invoice", sales_invoice.name) return sales_invoice.name @@ -247,7 +255,7 @@ def create_fee_validity(physician, patient, date): return fee_validity -def create_invoice_items(appointment_id, physician, company, invoice): +def create_invoice_items(physician, company, invoice): item_line = invoice.append("items") item_line.item_name = "Consulting Charges" item_line.description = "Consulting Charges: " + physician diff --git a/erpnext/healthcare/doctype/patient_service_unit/__init__.py b/erpnext/healthcare/doctype/patient_service_unit/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/healthcare/doctype/patient_service_unit/patient_service_unit.js b/erpnext/healthcare/doctype/patient_service_unit/patient_service_unit.js new file mode 100644 index 0000000000..197b4e5dbc --- /dev/null +++ b/erpnext/healthcare/doctype/patient_service_unit/patient_service_unit.js @@ -0,0 +1,15 @@ +// Copyright (c) 2017, earthians and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Patient Service Unit', { +}); + +// get query select patient service unit +cur_frm.fields_dict['parent_patient_service_unit'].get_query = function(doc) { + return{ + filters:[ + ['Patient Service Unit', 'is_group', '=', 1], + ['Patient Service Unit', 'name', '!=', doc.patient_service_unit_name] + ] + }; +}; diff --git a/erpnext/healthcare/doctype/patient_service_unit/patient_service_unit.json b/erpnext/healthcare/doctype/patient_service_unit/patient_service_unit.json new file mode 100644 index 0000000000..0ca1a53e76 --- /dev/null +++ b/erpnext/healthcare/doctype/patient_service_unit/patient_service_unit.json @@ -0,0 +1,358 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 1, + "autoname": "field:patient_service_unit_name", + "beta": 1, + "creation": "2016-09-21 13:48:14.731437", + "custom": 0, + "description": "Patinet Service Unit", + "docstatus": 0, + "doctype": "DocType", + "document_type": "Setup", + "editable_grid": 1, + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "patient_service_unit_name", + "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": "Service Unit", + "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 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 1, + "collapsible": 0, + "columns": 0, + "fieldname": "parent_patient_service_unit", + "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": "Parent Service Unit", + "length": 0, + "no_copy": 0, + "options": "Patient 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": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 1, + "collapsible": 0, + "columns": 0, + "fieldname": "is_group", + "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": "Is Group", + "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_on_submit": 0, + "bold": 1, + "collapsible": 0, + "columns": 0, + "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": 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_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "company", + "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": "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 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "lft", + "fieldtype": "Int", + "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": "lft", + "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": 1, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "rgt", + "fieldtype": "Int", + "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": "rgt", + "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": 1, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "old_parent", + "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": "Old Parent", + "length": 0, + "no_copy": 1, + "options": "Patient Service Unit", + "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 + } + ], + "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-03-07 13:25:51.163029", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Patient Service Unit", + "name_case": "", + "owner": "Administrator", + "permissions": [ + { + "amend": 0, + "apply_user_permissions": 1, + "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, + "user_permission_doctypes": "[\"Service Unit\"]", + "write": 0 + }, + { + "amend": 0, + "apply_user_permissions": 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": "Medical Administrator", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + }, + { + "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": "Physician", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + } + ], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "restrict_to_domain": "Healthcare", + "search_fields": "patient_service_unit_name", + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "title_field": "patient_service_unit_name", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/patient_service_unit/patient_service_unit.py b/erpnext/healthcare/doctype/patient_service_unit/patient_service_unit.py new file mode 100644 index 0000000000..6c177d82d2 --- /dev/null +++ b/erpnext/healthcare/doctype/patient_service_unit/patient_service_unit.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, earthians and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals + +from frappe.utils.nestedset import NestedSet + +class PatientServiceUnit(NestedSet): + nsm_parent_field = 'parent_patient_service_unit' + + def on_update(self): + super(PatientServiceUnit, self).on_update() + self.validate_one_root() diff --git a/erpnext/healthcare/doctype/patient_service_unit/patient_service_unit_tree.js b/erpnext/healthcare/doctype/patient_service_unit/patient_service_unit_tree.js new file mode 100644 index 0000000000..0b03f2db8b --- /dev/null +++ b/erpnext/healthcare/doctype/patient_service_unit/patient_service_unit_tree.js @@ -0,0 +1,3 @@ +frappe.treeview_settings["Patient Service Unit"] = { + ignore_fields:["parent_patient_service_unit"] +}; diff --git a/erpnext/healthcare/doctype/patient_service_unit/test_patient_service_unit.js b/erpnext/healthcare/doctype/patient_service_unit/test_patient_service_unit.js new file mode 100644 index 0000000000..320388a1fd --- /dev/null +++ b/erpnext/healthcare/doctype/patient_service_unit/test_patient_service_unit.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Patient Service Unit", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Patient Service Unit + () => frappe.tests.make('Patient Service Unit', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/erpnext/healthcare/doctype/patient_service_unit/test_patient_service_unit.py b/erpnext/healthcare/doctype/patient_service_unit/test_patient_service_unit.py new file mode 100644 index 0000000000..ceb49fd4c6 --- /dev/null +++ b/erpnext/healthcare/doctype/patient_service_unit/test_patient_service_unit.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, earthians and Contributors +# See license.txt +from __future__ import unicode_literals +import unittest + +class TestPatientServiceUnit(unittest.TestCase): + pass diff --git a/erpnext/healthcare/doctype/physician/physician.js b/erpnext/healthcare/doctype/physician/physician.js index c224b5d36e..6ce01991f3 100755 --- a/erpnext/healthcare/doctype/physician/physician.js +++ b/erpnext/healthcare/doctype/physician/physician.js @@ -19,6 +19,13 @@ frappe.ui.form.on('Physician', { if(!frm.is_new()) { frappe.contacts.render_address_and_contact(frm); } + frm.set_query("service_unit", "physician_schedules", function(){ + return { + filters: { + "is_group": false, + } + }; + }); } }); diff --git a/erpnext/healthcare/doctype/physician/physician.json b/erpnext/healthcare/doctype/physician/physician.json index 1d9794e6de..e29561e91e 100644 --- a/erpnext/healthcare/doctype/physician/physician.json +++ b/erpnext/healthcare/doctype/physician/physician.json @@ -435,45 +435,14 @@ "set_only_once": 0, "unique": 0 }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 1, - "collapsible": 0, - "columns": 0, - "fieldname": "physician_schedule", - "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": "Physician Schedule", - "length": 0, - "no_copy": 0, - "options": "Physician 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, - "unique": 0 - }, { "allow_bulk_edit": 0, "allow_on_submit": 0, "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "column_break_17", - "fieldtype": "Column Break", + "fieldname": "physician_schedules", + "fieldtype": "Table", "hidden": 0, "ignore_user_permissions": 0, "ignore_xss_filter": 0, @@ -481,39 +450,10 @@ "in_global_search": 0, "in_list_view": 0, "in_standard_filter": 0, + "label": "Physician Schedules", "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 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "In minutes", - "fieldname": "time_per_appointment", - "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": "Time per Appointment", - "length": 0, - "no_copy": 0, + "options": "Physician Service Unit Schedule", "permlevel": 0, "precision": "", "print_hide": 0, @@ -811,7 +751,7 @@ "istable": 0, "max_attachments": 0, "modified": "2018-01-19 15:25:43.166877", - "modified_by": "jams@hcf.com", + "modified_by": "Administrator", "module": "Healthcare", "name": "Physician", "name_case": "", diff --git a/erpnext/healthcare/doctype/physician/physician.py b/erpnext/healthcare/doctype/physician/physician.py index 4d035d39f6..eb03083a49 100644 --- a/erpnext/healthcare/doctype/physician/physician.py +++ b/erpnext/healthcare/doctype/physician/physician.py @@ -20,7 +20,6 @@ class Physician(Document): [cstr(self.get(f)).strip() for f in ["first_name","middle_name","last_name"]])) def validate(self): - self.validate_schedule_and_time() validate_party_accounts(self) if self.user_id: @@ -37,15 +36,6 @@ class Physician(Document): frappe.permissions.remove_user_permission( "Physician", self.name, existing_user_id) - def validate_schedule_and_time(self): - if (self.physician_schedule or self.time_per_appointment) and \ - not (self.physician_schedule and self.time_per_appointment): - frappe.msgprint( - _('Both "Physician Schedule" and Time Per Appointment" must be set for Dr {0}').format( - self.first_name), - title='Error', raise_exception=1, indicator='red' - ) - def on_update(self): if self.user_id: frappe.permissions.add_user_permission("Physician", self.name, self.user_id) diff --git a/erpnext/healthcare/doctype/physician/test_physician.py b/erpnext/healthcare/doctype/physician/test_physician.py index 4bd497a4e9..2fbf5741cf 100644 --- a/erpnext/healthcare/doctype/physician/test_physician.py +++ b/erpnext/healthcare/doctype/physician/test_physician.py @@ -12,23 +12,6 @@ class TestPhysician(unittest.TestCase): def tearDown(self): frappe.delete_doc_if_exists('Physician', '_Testdoctor2', force=1) - def test_schedule_and_time(self): - physician = frappe.new_doc('Physician') - physician.first_name = '_Testdoctor2' - physician.physician_schedule = '_Testdoctor2 Schedule' - - self.assertRaises(frappe.ValidationError, physician.insert) - - physician.physician_schedule = '' - physician.time_per_appointment = 15 - - self.assertRaises(frappe.ValidationError, physician.insert) - - physician.physician_schedule = '_Testdoctor2 Schedule' - physician.time_per_appointment = 15 - - physician.insert() - def test_new_physician_without_schedule(self): physician = frappe.new_doc('Physician') physician.first_name = '_Testdoctor2' diff --git a/erpnext/healthcare/doctype/physician_service_unit_schedule/__init__.py b/erpnext/healthcare/doctype/physician_service_unit_schedule/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/healthcare/doctype/physician_service_unit_schedule/physician_service_unit_schedule.json b/erpnext/healthcare/doctype/physician_service_unit_schedule/physician_service_unit_schedule.json new file mode 100644 index 0000000000..69fe7b3104 --- /dev/null +++ b/erpnext/healthcare/doctype/physician_service_unit_schedule/physician_service_unit_schedule.json @@ -0,0 +1,103 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 1, + "creation": "2017-11-16 12:19:17.163786", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "schedule", + "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": "Schedule", + "length": 0, + "no_copy": 0, + "options": "Physician 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": 1, + "search_index": 0, + "set_only_once": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 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": 1, + "in_standard_filter": 0, + "label": "Service Unit", + "length": 0, + "no_copy": 0, + "options": "Patient 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": 0, + "unique": 0 + } + ], + "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-12-27 10:57:42.301295", + "modified_by": "Administrator", + "module": "Healthcare", + "name": "Physician Service Unit Schedule", + "name_case": "", + "owner": "Administrator", + "permissions": [], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "DESC", + "track_changes": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/healthcare/doctype/physician_service_unit_schedule/physician_service_unit_schedule.py b/erpnext/healthcare/doctype/physician_service_unit_schedule/physician_service_unit_schedule.py new file mode 100644 index 0000000000..7aaec4de13 --- /dev/null +++ b/erpnext/healthcare/doctype/physician_service_unit_schedule/physician_service_unit_schedule.py @@ -0,0 +1,9 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +from frappe.model.document import Document + +class PhysicianServiceUnitSchedule(Document): + pass diff --git a/erpnext/patches.txt b/erpnext/patches.txt index c2c565d544..e049a81d29 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -504,6 +504,7 @@ execute:frappe.delete_doc('DocType', 'Production Planning Tool', ignore_missing= erpnext.patches.v10_0.migrate_daily_work_summary_settings_to_daily_work_summary_group erpnext.patches.v10_0.add_default_cash_flow_mappers erpnext.patches.v11_0.make_quality_inspection_template +erpnext.patches.v10_0.remove_and_copy_fields_in_physician erpnext.patches.v10_0.update_status_for_multiple_source_in_po erpnext.patches.v10_0.set_auto_created_serial_no_in_stock_entry erpnext.patches.v10_0.update_territory_and_customer_group diff --git a/erpnext/patches/v10_0/remove_and_copy_fields_in_physician.py b/erpnext/patches/v10_0/remove_and_copy_fields_in_physician.py new file mode 100644 index 0000000000..bf286449c4 --- /dev/null +++ b/erpnext/patches/v10_0/remove_and_copy_fields_in_physician.py @@ -0,0 +1,12 @@ +import frappe + +def execute(): + if frappe.db.exists("DocType", "Physician"): + frappe.reload_doc("healthcare", "doctype", "physician") + frappe.reload_doc("healthcare", "doctype", "physician_service_unit_schedule") + if frappe.db.has_column('Physician', 'physician_schedule'): + for doc in frappe.get_all('Physician'): + _doc = frappe.get_doc('Physician', doc.name) + if _doc.physician_schedule: + _doc.append('physician_schedules', {'schedule': _doc.physician_schedule}) + _doc.save()