refactor: Patient Appointment
diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
index 7c6f4d5..510849f 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
+++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
@@ -174,35 +174,42 @@
 	stock_entry.insert(ignore_permissions = True)
 	stock_entry.submit()
 
-@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
+
+	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)
diff --git a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json b/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json
index 6e3fdee..fafec22 100644
--- a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json
+++ b/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.json
@@ -13,7 +13,7 @@
   "column_break_9",
   "collect_registration_fee",
   "registration_fee",
-  "manage_appointment_invoice_automatically",
+  "automate_appointment_invoicing",
   "max_visit",
   "valid_days",
   "healthcare_service_items",
@@ -32,15 +32,15 @@
   "lab_test_approval_required",
   "custom_signature_in_print",
   "out_patient_sms_alerts",
-  "reg_msg",
-  "reg_sms",
-  "app_con",
-  "app_con_msg",
-  "no_con",
+  "send_registration_msg",
+  "registration_msg",
+  "send_appointment_confirmation",
+  "appointment_confirmation_msg",
+  "avoid_confirmation",
   "column_break_16",
-  "app_rem",
-  "app_rem_msg",
-  "rem_before",
+  "send_appointment_reminder",
+  "appointment_reminder_msg",
+  "remind_before",
   "laboratory_sms_alerts",
   "sms_printed",
   "column_break_28",
@@ -78,13 +78,6 @@
    "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"
-  },
-  {
    "description": "The number of free follow ups (Patient Encounters in valid days) allowed",
    "fieldname": "max_visit",
    "fieldtype": "Int",
@@ -132,66 +125,10 @@
    "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,
    "fieldname": "sb_in_ac",
    "fieldtype": "Section Break",
@@ -291,11 +228,74 @@
    "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"
   }
  ],
  "issingle": 1,
  "links": [],
- "modified": "2020-01-29 14:31:56.983534",
+ "modified": "2020-02-24 10:51:23.015896",
  "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 c26ab0c..a16fceb 100644
--- a/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.py
+++ b/erpnext/healthcare/doctype/healthcare_settings/healthcare_settings.py
@@ -46,12 +46,12 @@
 	return sms_text
 
 def send_registration_sms(doc):
-	if frappe.db.get_single_value('Healthcare Settings', 'reg_sms'):
+	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', 'reg_msg')
+			messages = frappe.db.get_single_value('Healthcare Settings', 'registration_msg')
 			messages = frappe.render_template(messages, context)
 			number = [doc.mobile]
 			send_sms(number,messages)
diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js
index a332d4c..7c6b011 100644
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js
+++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js
@@ -40,8 +40,8 @@
 
 		if (frm.is_new()) {
 			frm.page.set_primary_action(__('Check Availability'), function() {
-				frappe.db.get_value('Healthcare Settings', {name: 'Healthcare Settings'}, 'manage_appointment_invoice_automatically', (settings) => {
-					if (settings.manage_appointment_invoice_automatically) {
+				frappe.db.get_value('Healthcare Settings', {name: 'Healthcare Settings'}, 'automate_appointment_invoicing', (settings) => {
+					if (settings.automate_appointment_invoicing) {
 						if (!frm.doc.mode_of_payment) {
 							frappe.msgprint({
 								title: __('Not Allowed'),
@@ -76,7 +76,7 @@
 			frm.add_custom_button(__('Patient History'), function() {
 				frappe.route_options = {'patient': frm.doc.patient};
 				frappe.set_route('patient_history');
-			},__('View'));
+			}, __('View'));
 		}
 
 		if (frm.doc.status == 'Open' || (frm.doc.status == 'Scheduled' && !frm.doc.__islocal)) {
@@ -88,18 +88,24 @@
 			});
 
 			if (frm.doc.procedure_template) {
-				frm.add_custom_button(__('Procedure'), function(){
-					create_procedure(frm);
-				},'Create');
+				frm.add_custom_button(__('Clinical Procedure'), function(){
+					frappe.model.open_mapped_doc({
+						method: 'erpnext.healthcare.doctype.clinical_procedure.clinical_procedure.create_procedure',
+						frm: frm,
+					});
+				}, __('Create'));
 			} else {
 				frm.add_custom_button(__('Patient Encounter'), function() {
-					create_encounter(frm);
-				},'Create');
+					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() {
 				create_vital_signs(frm);
-			},'Create');
+			}, __('Create'));
 		}
 
 		if (frm.doc.status == 'Pending') {
@@ -111,8 +117,8 @@
 			});
 		}
 
-		frappe.db.get_value('Healthcare Settings', {name: 'Healthcare Settings'}, 'manage_appointment_invoice_automatically', (settings) => {
-			if (settings.manage_appointment_invoice_automatically) {
+		frappe.db.get_value('Healthcare Settings', {name: 'Healthcare Settings'}, 'automate_appointment_invoicing', (settings) => {
+			if (settings.automate_appointment_invoicing) {
 				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);
@@ -373,34 +379,6 @@
 	d.show();
 };
 
-let create_procedure = function(frm) {
-	let 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) {
-				let doclist = frappe.model.sync(data.message);
-				frappe.set_route('Form', doclist[0].doctype, doclist[0].name);
-			}
-		}
-	});
-};
-
-let create_encounter = function(frm) {
-	let 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) {
-				let doclist = frappe.model.sync(data.message);
-				frappe.set_route('Form', doclist[0].doctype, doclist[0].name);
-			}
-		}
-	});
-};
-
 let create_vital_signs = function(frm) {
 	if (!frm.doc.patient) {
 		frappe.throw(__('Please select patient'));
diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py
index 1a4b7df..76feb22 100755
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py
+++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py
@@ -7,25 +7,37 @@
 from frappe.model.document import Document
 import json
 from frappe.utils import getdate, add_days, 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_validity_exists, get_service_item_and_practitioner_charge
 
 class PatientAppointment(Document):
+	def validate(self):
+		self.validate_overlaps()
+
+	def after_insert(self):
+		invoice_appointment(self)
+		self.update_prescription_details()
+		self.check_fee_validity()
+		send_confirmation_msg(self)
+
 	def on_update(self):
-		today = datetime.date.today()
+		today = getdate()
 		appointment_date = getdate(self.appointment_date)
 
-		# If appointment created for today set as open
+		# If appointment is created for today set status as Open
 		if today == appointment_date:
-			frappe.db.set_value("Patient Appointment", self.name, "status", "Open")
+			frappe.db.set_value('Patient Appointment', self.name, 'status', 'Open')
 			self.reload()
 
-	def validate(self):
-		end_time = datetime.datetime.combine(getdate(self.appointment_date), get_time(self.appointment_time)) + datetime.timedelta(minutes=float(self.duration))
+	def validate_overlaps(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,133 +53,145 @@
 		self.appointment_time, end_time.time(), self.appointment_time, end_time.time(), self.appointment_time))
 
 		if overlaps:
-			frappe.throw(_("""Appointment overlaps with {0}.<br> {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 {0}').format(overlaps[0][0])
+			overlapping_details += '<br>'
+			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))
 
-	def after_insert(self):
+	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)
+					frappe.db.set_value('Patient Appointment', self.name, 'notes', comments)
+
+	def check_fee_validity(self):
 		# 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])
+		validity_exists = check_validity_exists(self.practitioner, self.patient)
+		if validity_exists:
+			fee_validity = frappe.get_doc('Fee Validity', validity_exists[0][0])
 
 			# Check if the validity is valid
-			appointment_date = getdate(appointment.appointment_date)
+			appointment_date = getdate(self.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)
+				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)
+					frappe.db.set_value('Patient Appointment', self.name, 'invoiced', True)
+				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)
+		return
 
-	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
+	if frappe.db.get_single_value('Healthcare Settings', 'automate_appointment_invoicing') and \
+			not frappe.db.get_value('Patient Appointment', appointment_doc.name, 'invoiced'):
+		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)
 
-	payments_line = sales_invoice.append("payments")
-	payments_line.mode_of_payment = appointment_doc.mode_of_payment
-	payments_line.amount = appointment_doc.paid_amount
+		item = sales_invoice.append('items', {})
+		item = get_appointment_item(appointment_doc, item)
 
-	sales_invoice.set_missing_values(for_validate = True)
+		payment = sales_invoice.append('payments', {})
+		payments_line.mode_of_payment = appointment_doc.mode_of_payment
+		payments_line.amount = appointment_doc.paid_amount
 
-	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, 'ref_sales_invoice', sales_invoice.name)
+		sales_invoice.set_missing_values(for_validate=True)
 
-def appointment_cancel(appointment_id):
-	appointment = frappe.get_doc("Patient Appointment", appointment_id)
-	# If invoiced --> fee_validity update with -1 visit
+		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, 'ref_sales_invoice', sales_invoice.name)
+
+
+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.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 invoiced --> fee_validity update visit as -1
 	if appointment.invoiced:
-		sales_invoice = exists_sales_invoice(appointment)
+		sales_invoice = check_sales_invoice_exists(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))
+				_('Appointment {0} and Sales Invoice {1} cancelled'.format(appointment.name, sales_invoice.name))
 			)
 		else:
-			validity = validity_exists(appointment.practitioner, appointment.patient)
+			validity = check_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):
+				fee_validity = frappe.get_doc('Fee Validity', validity)
+				if validate_appointment_in_fee_validity(appointment, fee_validity.valid_till, fee_validity.ref_invoice):
 					visited = fee_validity.visited - 1
-					frappe.db.set_value("Fee Validity", fee_validity.name, "visited", visited)
+					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))
+						_('Appointment cancelled. Please review and cancel the invoice {0}'.format(fee_validity.ref_invoice))
 					)
 				else:
-					frappe.msgprint(_("Appointment cancelled"))
+					frappe.msgprint(_('Appointment Cancelled'))
 			else:
-				frappe.msgprint(_("Appointment cancelled"))
+				frappe.msgprint(_('Appointment Cancelled'))
 	else:
-		frappe.msgprint(_("Appointment cancelled"))
+		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")
+def validate_appointment_in_fee_validity(appointment, valid_end_date, ref_invoice):
+	valid_days = frappe.db.get_single_value('Healthcare Settings', 'valid_days')
+	max_visit = frappe.db.get_single_value('Healthcare Settings', '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))
+	# Appointments which have same fee validity range with the appointment
+	appointments = frappe.get_list('Patient Appointment', {
+		'patient': appointment.patient,
+		'invoiced': True,
+		'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)
+		sales_invoice = check_sales_invoice_exists(appointment_obj)
 		if sales_invoice.name == ref_invoice:
 			return True
 	return False
 
 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):
+def check_si_item_exists(appointment):
 	return frappe.db.exists(
-		"Sales Invoice Item",
+		'Sales Invoice Item',
 		{
-			"reference_dt": "Patient Appointment",
-			"reference_dn": appointment.name
+			'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):
+	si_item = check_si_item_exists(appointment)
+	if si_item:
+		sales_invoice = frappe.get_doc('Sales Invoice', frappe.db.get_value('Sales Invoice Item', si_item, 'parent'))
 		return sales_invoice
 	return False
 
@@ -181,176 +205,164 @@
 	"""
 
 	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.practitioner_schedules, date)
+	else:
+		frappe.throw(_('{0} does not have a Healthcare Practitioner Schedule. Add it in Healthcare Practitioner master'.format(practitioner)))
+
+
+	if not slot_details:
+		# TODO: return available slots in nearby dates
+		frappe.throw(_('Healthcare Practitioner not available on {0}').format(weekday))
+
+	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 company holiday'.format(date)))
 
-		# 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))
 			else:
-				frappe.throw(_("{0} on Leave on {1}").format(practitioner, date))
+				frappe.throw(_('{0} is on Leave on {1}').format(practitioner_doc.name, date))
 
-	# 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)))
+def get_available_slots(practitioner_schedules, date):
+	available_slots = []
+	slot_details = []
+	weekday = date.strftime('%A')
+	practitioner = None
 
-			if practitioner_schedule:
-				available_slots = []
-				for t in practitioner_schedule.time_slots:
-					if weekday == t.day:
-						available_slots.append(t)
+	for schedule_entry in 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)))
 
-				if available_slots:
-					appointments = []
+		if practitioner_schedule:
+			available_slots = []
+			for time_slot in practitioner_schedule.time_slots:
+				if weekday == time_slot.day:
+					available_slots.append(time_slot)
 
-					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 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']]
+				}
 
-					slot_details.append({"slot_name":slot_name, "service_unit":schedule.service_unit,
-						"avail_slot":available_slots, 'appointments': appointments})
+				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['service_unit'] = ''
 
-	else:
-		frappe.throw(_("{0} does not have a Healthcare Practitioner Schedule. Add it in Healthcare Practitioner master".format(practitioner)))
+				appointments = frappe.get_all(
+					'Patient Appointment',
+					filters=filters,
+					fields=['name', 'appointment_time', 'duration', 'status'])
 
-	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))
+				slot_details.append({'slot_name':slot_name, 'service_unit':schedule_entry.service_unit,
+					'avail_slot':available_slots, 'appointments': appointments})
 
-	return {
-		"slot_details": slot_details
-	}
+	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'],
+				['visit_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)
+	if frappe.db.get_single_value('Healthcare Settings', 'send_appointment_reminder'):
+		remind_before = datetime.datetime.strptime(frappe.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)
+			'select name from `tabPatient Appointment` where start_dt between %s and %s and reminded = 0 ',
+			(datetime.datetime.now(), reminder_dt)
 		)
 
 		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")
+			doc = frappe.get_doc('Patient Appointment', appointment_list[i][0])
+			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)
 		number = [patient.mobile]
 		send_sms(number, message)
 
-
 @frappe.whitelist()
 def get_events(start, end, filters=None):
 	"""Returns events for Gantt / Calendar view rendering.
diff --git a/erpnext/healthcare/utils.py b/erpnext/healthcare/utils.py
index bae0e4d..3a08e33 100644
--- a/erpnext/healthcare/utils.py
+++ b/erpnext/healthcare/utils.py
@@ -47,7 +47,7 @@
 						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)
+							validity_exist = check_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
@@ -60,7 +60,7 @@
 							income_account = None
 							service_item = None
 							if patient_appointment_obj.practitioner:
-								service_item, practitioner_charge = service_item_and_practitioner_charge(patient_appointment_obj)
+								service_item, practitioner_charge = get_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,
@@ -75,7 +75,7 @@
 						income_account = None
 						service_item = None
 						if encounter_obj.practitioner:
-							service_item, practitioner_charge = service_item_and_practitioner_charge(encounter_obj)
+							service_item, practitioner_charge = get_service_item_and_practitioner_charge(encounter_obj)
 							income_account = get_income_account(encounter_obj.practitioner, encounter_obj.company)
 
 						item_to_invoice.append({'reference_type': 'Patient Encounter', 'reference_name': encounter_obj.name,
@@ -159,9 +159,9 @@
 		else:
 			frappe.throw(_("The Patient {0} do not have customer refrence to invoice").format(patient.name))
 
-def service_item_and_practitioner_charge(doc):
-	is_ip = doc_is_ip(doc)
-	if is_ip:
+def get_service_item_and_practitioner_charge(doc):
+	is_inpatient = doc_is_inpatient(doc)
+	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")
@@ -170,26 +170,26 @@
 		if not service_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):
+def throw_config_service_item(is_inpatient):
 	service_item_lable = "Out Patient Consulting Charge Item"
-	if is_ip:
+	if is_inpatient:
 		service_item_lable = "Inpatient Visit Charge Item"
 
 	msg = _(("Please Configure {0} in ").format(service_item_lable) \
 		+ """<b><a href="#Form/Healthcare Settings">Healthcare Settings</a></b>""")
 	frappe.throw(msg)
 
-def throw_config_practitioner_charge(is_ip, practitioner):
+def throw_config_practitioner_charge(is_inpatient, practitioner):
 	charge_name = "OP Consulting Charge"
-	if is_ip:
+	if is_inpatient:
 		charge_name = "Inpatient Visit Charge"
 
 	msg = _(("Please Configure {0} for Healthcare Practitioner").format(charge_name) \
@@ -202,14 +202,14 @@
 def get_healthcare_service_item(service_item_field):
 	return frappe.db.get_value("Healthcare Settings", None, service_item_field)
 
-def doc_is_ip(doc):
-	is_ip = False
+def doc_is_inpatient(doc):
+	is_inpatient = False
 	if doc.inpatient_record:
-		is_ip = True
-	return is_ip
+		is_inpatient = True
+	return is_inpatient
 
-def get_practitioner_charge(practitioner, is_ip):
-	if is_ip:
+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")
@@ -271,7 +271,7 @@
 		doc_created = frappe.db.get_value(dt, {'prescription': ref_dn})
 		frappe.db.set_value(dt, doc_created, 'invoiced', invoiced)
 
-def validity_exists(practitioner, patient):
+def check_validity_exists(practitioner, patient):
 	return frappe.db.exists({
 			"doctype": "Fee Validity",
 			"practitioner": practitioner,
@@ -279,7 +279,7 @@
 
 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)
+	validity_exist = check_validity_exists(appointment_doc.practitioner, appointment_doc.patient)
 	do_not_update = False
 	visited = 0
 	if validity_exist: