Healthcare Service - Invoice Work Flow - Redesign
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 619776c..daf1bfe 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -16,7 +16,8 @@
 	},
 	onload: function() {
 		var me = this;
-		this._super();		
+		this._super();
+		console.log("class erpnext.accounts.SalesInvoiceController, onload this->", this);
 
 		if(!this.frm.doc.__islocal && !this.frm.doc.customer && this.frm.doc.debit_to) {
 			// show debit_to in print format
@@ -466,7 +467,7 @@
 	}
 }
 
-//project name
+// project name
 //--------------------------
 cur_frm.fields_dict['project'].get_query = function(doc, cdt, cdn) {
 	return{
@@ -543,7 +544,7 @@
 
 frappe.ui.form.on('Sales Invoice', {
 	setup: function(frm){
-		
+
 		frm.custom_make_buttons = {
 			'Delivery Note': 'Delivery',
 			'Sales Invoice': 'Sales Return',
@@ -625,7 +626,7 @@
 			}
 		};
 	},
-	//When multiple companies are set up. in case company name is changed set default company address
+	// When multiple companies are set up. in case company name is changed set default company address
 	company:function(frm){
 		if (frm.doc.company)
 		{
@@ -712,8 +713,41 @@
 			}
 			frm.set_value("loyalty_amount", loyalty_amount);
 		}
-	}
+	},
 
+	// Healthcare
+	patient: function(frm) {
+		if (frappe.boot.active_domains.includes("Healthcare")){
+			if(frm.doc.patient){
+				frappe.call({
+					method: "frappe.client.get_value",
+					args:{
+						doctype: "Patient",
+						filters: {"name": frm.doc.patient},
+						fieldname: "customer"
+					},
+					callback:function(patient_customer) {
+						if(patient_customer){
+							frm.set_value("customer", patient_customer.message.customer);
+							frm.refresh_fields();
+						}
+					}
+				});
+			}
+			else{
+					frm.set_value("customer", '');
+			}
+		}
+	},
+	refresh: function(frm) {
+		if (frappe.boot.active_domains.includes("Healthcare")){
+			if (cint(frm.doc.docstatus==0) && cur_frm.page.current_view_name!=="pos" && !frm.doc.is_return) {
+				frm.add_custom_button(__('Healthcare Services'), function() {
+					get_healthcare_services_to_invoice(frm);
+				},"Get items from");
+			}
+		}
+	}
 })
 
 frappe.ui.form.on('Sales Invoice Timesheet', {
@@ -816,3 +850,169 @@
 
 	dialog.show();
 }
+
+var get_healthcare_services_to_invoice = function(frm) {
+	var me = this;
+	let selected_patient = '';
+	var dialog = new frappe.ui.Dialog({
+		title: __("Get Items from Healthcare Services"),
+		fields:[
+			{
+				fieldtype: 'Link',
+				options: 'Patient',
+				label: 'Patient',
+				fieldname: "patient",
+				reqd: true
+			},
+			{ fieldtype: 'Section Break'	},
+			{ fieldtype: 'HTML', fieldname: 'results_area' }
+		]
+	});
+	var $wrapper;
+	var $results;
+	var $placeholder;
+	dialog.set_values({
+		'patient': frm.doc.patient
+	});
+	dialog.fields_dict["patient"].df.onchange = () => {
+		var patient = dialog.fields_dict.patient.input.value;
+		if(patient && patient!=selected_patient){
+			selected_patient = patient;
+			get_services(frm, patient, $results, $placeholder)
+		}
+		else if(!patient){
+			selected_patient = '';
+			$results.empty();
+			$results.append($placeholder);
+		}
+	}
+	$wrapper = dialog.fields_dict.results_area.$wrapper.append(`<div class="results"
+		style="border: 1px solid #d1d8dd; border-radius: 3px; height: 300px; overflow: auto;"></div>`);
+	$results = $wrapper.find('.results');
+	$placeholder = $(`<div class="multiselect-empty-state">
+				<span class="text-center" style="margin-top: -40px;">
+					<i class="fa fa-2x fa-heartbeat text-extra-muted"></i>
+					<p class="text-extra-muted">No billable Healthcare Services found</p>
+				</span>
+			</div>`);
+	$results.on('click', '.list-item--head :checkbox', (e) => {
+		$results.find('.list-item-container .list-row-check')
+			.prop("checked", ($(e.target).is(':checked')));
+	});
+	set_primary_action(frm, dialog, $results);
+	dialog.show();
+};
+
+var get_services= function(frm, patient_id, $results, $placeholder) {
+	var me = this;
+	$results.empty();
+	frappe.call({
+		method:"erpnext.healthcare.utils.get_healthcare_services_to_invoice",
+		args: {
+			patient: patient_id
+		},
+		callback: function(data) {
+			if(data.message){
+				$results.append(make_list_row());
+				for(let i=0; i<data.message.length; i++){
+					$results.append(make_list_row(data.message[i]));
+				}
+			}else {
+				$results.append($placeholder);
+			}
+		}
+	});
+};
+
+var make_list_row= function(result={}) {
+	var me = this;
+	// Make a head row by default (if result not passed)
+	let head = Object.keys(result).length === 0;
+	let contents = ``;
+	let columns = (["service", "reference_name", "reference_type"]);
+	columns.forEach(function(column) {
+		contents += `<div class="list-item__content ellipsis">
+			${
+				head ? `<span class="ellipsis">${__(frappe.model.unscrub(column))}</span>`
+
+				:(column !== "name" ? `<span class="ellipsis">${__(result[column])}</span>`
+					: `<a class="list-id ellipsis">
+						${__(result[column])}</a>`)
+			}
+		</div>`;
+	})
+
+	let $row = $(`<div class="list-item">
+		<div class="list-item__content" style="flex: 0 0 10px;">
+			<input type="checkbox" class="list-row-check" ${result.checked ? 'checked' : ''}>
+		</div>
+		${contents}
+	</div>`);
+
+	head ? $row.addClass('list-item--head')
+		: $row = $(`<div class="list-item-container"
+			data-dn= "${result.reference_name}" data-dt= "${result.reference_type}" data-item= "${result.service}"
+			data-rate = ${result.rate}
+			data-income-account = "${result.income_account}"
+			data-qty = ${result.qty}>
+			</div>`).append($row);
+	return $row;
+};
+
+var set_primary_action= function(frm, dialog, $results) {
+	var me = this;
+	dialog.set_primary_action(__('Add'), function() {
+		// TODO: Get checked items
+		let checked_values = get_checked_values($results);
+		if(checked_values.length > 0){
+			frm.set_value("patient", dialog.fields_dict.patient.input.value);
+			frm.set_value("items", []);
+			for(let i=0; i<checked_values.length; i++){
+				var si_item = frappe.model.add_child(frm.doc, 'Sales Invoice Item', 'items');
+				if(checked_values[i]['item'] == "Consulting Charges"){
+					frappe.model.set_value(si_item.doctype, si_item.name, 'item_name', checked_values[i]['item']);
+					frappe.model.set_value(si_item.doctype, si_item.name, 'description', checked_values[i]['item']);
+					frappe.model.set_value(si_item.doctype, si_item.name, 'rate', checked_values[i]['rate']);
+					frappe.model.set_value(si_item.doctype, si_item.name, 'income_account', checked_values[i]['income_account']);
+					frappe.model.set_value(si_item.doctype, si_item.name, 'uom', 'Nos');
+					frappe.model.set_value(si_item.doctype, si_item.name, 'conversion_factor', 1);
+				}
+				else{
+					frappe.model.set_value(si_item.doctype, si_item.name, 'item_code', checked_values[i]['item']);
+				}
+				frappe.model.set_value(si_item.doctype, si_item.name, 'reference_dt', checked_values[i]['dt']);
+				frappe.model.set_value(si_item.doctype, si_item.name, 'reference_dn', checked_values[i]['dn']);
+				frappe.model.set_value(si_item.doctype, si_item.name, 'qty', 1);
+				if(checked_values[i]['qty'] > 1){
+					frappe.model.set_value(si_item.doctype, si_item.name, 'qty', checked_values[i]['qty']);
+				}
+			}
+			frm.refresh_fields();
+			dialog.hide();
+		}
+		else{
+			frappe.msgprint(__("Please select Healthcare Service"));
+		}
+	});
+};
+
+var get_checked_values= function($results) {
+	return $results.find('.list-item-container').map(function() {
+		let checked_values = {};
+		if ($(this).find('.list-row-check:checkbox:checked').length > 0 ) {
+			checked_values['dn'] = $(this).attr('data-dn');
+			checked_values['dt'] = $(this).attr('data-dt');
+			checked_values['item'] = $(this).attr('data-item');
+			if($(this).attr('data-rate')){
+				checked_values['rate'] = $(this).attr('data-rate');
+			}
+			if($(this).attr('data-income-account')){
+				checked_values['income_account'] = $(this).attr('data-income-account');
+			}
+			if($(this).attr('data-qty')){
+				checked_values['qty'] = $(this).attr('data-qty');
+			}
+			return checked_values;
+		}
+	}).get();
+};
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index a45b953..7aeb86d 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -24,6 +24,8 @@
 from erpnext.accounts.doctype.loyalty_program.loyalty_program import \
 	get_loyalty_program_details_with_points, get_loyalty_details, validate_loyalty_points
 
+from erpnext.healthcare.utils import manage_invoice_submit_cancel
+
 from six import iteritems
 
 form_grid_templates = {
@@ -179,6 +181,13 @@
 		if self.redeem_loyalty_points and self.loyalty_points:
 			self.apply_loyalty_points()
 
+		# Healthcare Service Invoice.
+		domain_settings = frappe.get_doc('Domain Settings')
+		active_domains = [d.domain for d in domain_settings.active_domains]
+
+		if "Healthcare" in active_domains:
+			manage_invoice_submit_cancel(self, "on_submit")
+
 	def validate_pos_paid_amount(self):
 		if len(self.payments) == 0 and self.is_pos:
 			frappe.throw(_("At least one mode of payment is required for POS invoice."))
@@ -227,6 +236,13 @@
 
 		unlink_inter_company_invoice(self.doctype, self.name, self.inter_company_invoice_reference)
 
+		# Healthcare Service Invoice.
+		domain_settings = frappe.get_doc('Domain Settings')
+		active_domains = [d.domain for d in domain_settings.active_domains]
+
+		if "Healthcare" in active_domains:
+			manage_invoice_submit_cancel(self, "on_cancel")
+
 	def update_status_updater_args(self):
 		if cint(self.update_stock):
 			self.status_updater.extend([{
diff --git a/erpnext/domains/healthcare.py b/erpnext/domains/healthcare.py
index 5a54cf6..57f30f6 100644
--- a/erpnext/domains/healthcare.py
+++ b/erpnext/domains/healthcare.py
@@ -21,9 +21,30 @@
 		'Patient'
 	],
 	'custom_fields': {
-		'Sales Invoice': dict(fieldname='appointment', label='Patient Appointment',
-			fieldtype='Link', options='Patient Appointment',
-			insert_after='customer')
+		'Sales Invoice': [
+			{
+				'fieldname': 'patient', 'label': 'Patient', 'fieldtype': 'Link', 'options': 'Patient',
+				'insert_after': 'naming_series'
+			},
+			{
+				'fieldname': 'patient_name', 'label': 'Patient Name', 'fieldtype': 'Data', 'fetch_from': 'patient.patient_name',
+				'insert_after': 'patient', 'read_only': True
+			},
+			{
+				'fieldname': 'ref_practitioner', 'label': 'Referring Practitioner', 'fieldtype': 'Link', 'options': 'Practitioner',
+				'insert_after': 'customer'
+			}
+		],
+		'Sales Invoice Item': [
+			{
+				'fieldname': 'reference_dt', 'label': 'Reference DocType', 'fieldtype': 'Link', 'options': 'DocType',
+				'insert_after': 'edit_references'
+			},
+			{
+				'fieldname': 'reference_dn', 'label': 'Reference Name', 'fieldtype': 'Dynamic Link', 'options': 'reference_dt',
+				'insert_after': 'reference_dt'
+			}
+		]
 	},
 	'on_setup': 'erpnext.healthcare.setup.setup_healthcare'
 }
diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
index 97d8a02..d51d062 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
+++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
@@ -24,6 +24,8 @@
 			self.set_actual_qty();
 
 	def after_insert(self):
+		if self.prescription:
+			frappe.db.set_value("Procedure Prescription", self.prescription, "procedure_created", 1)
 		if self.appointment:
 			frappe.db.set_value("Patient Appointment", self.appointment, "status", "Closed")
 		template = frappe.get_doc("Clinical Procedure Template", self.procedure_template)
@@ -130,6 +132,8 @@
 		se_child.conversion_factor = flt(d["conversion_factor"])
 		if d["batch_no"]:
 			se_child.batch_no = d["batch_no"]
+		if parenttype == "Clinical Procedure Template":
+			se_child.invoice_separately_as_consumables = d["invoice_separately_as_consumables"]
 	return doc
 
 def get_item_dict(table, parent, parenttype):
@@ -165,6 +169,8 @@
 	procedure.patient_age = appointment.patient_age
 	procedure.patient_sex = appointment.patient_sex
 	procedure.procedure_template = appointment.procedure_template
+	procedure.procedure_prescription = appointment.procedure_prescription
+	procedure.invoiced = appointment.invoiced
 	procedure.medical_department = appointment.department
 	procedure.start_date = appointment.appointment_date
 	procedure.start_time = appointment.appointment_time
diff --git a/erpnext/healthcare/doctype/fee_validity/fee_validity.py b/erpnext/healthcare/doctype/fee_validity/fee_validity.py
index 53a1741..a707236 100644
--- a/erpnext/healthcare/doctype/fee_validity/fee_validity.py
+++ b/erpnext/healthcare/doctype/fee_validity/fee_validity.py
@@ -4,6 +4,32 @@
 
 from __future__ import unicode_literals
 from frappe.model.document import Document
+import frappe
+from frappe.utils import getdate
+import datetime
 
 class FeeValidity(Document):
 	pass
+
+def update_fee_validity(fee_validity, date):
+	max_visit = frappe.db.get_value("Healthcare Settings", None, "max_visit")
+	valid_days = frappe.db.get_value("Healthcare Settings", None, "valid_days")
+	if not valid_days:
+		valid_days = 1
+	if not max_visit:
+		max_visit = 1
+	date = getdate(date)
+	valid_till = date + datetime.timedelta(days=int(valid_days))
+	fee_validity.max_visit = max_visit
+	fee_validity.visited = 1
+	fee_validity.valid_till = valid_till
+	fee_validity.save(ignore_permissions=True)
+	return fee_validity
+
+
+def create_fee_validity(practitioner, patient, date):
+	fee_validity = frappe.new_doc("Fee Validity")
+	fee_validity.practitioner = practitioner
+	fee_validity.patient = patient
+	fee_validity = update_fee_validity(fee_validity, date)
+	return fee_validity
diff --git a/erpnext/healthcare/doctype/lab_test/lab_test.js b/erpnext/healthcare/doctype/lab_test/lab_test.js
index c3b069d..06637bc 100644
--- a/erpnext/healthcare/doctype/lab_test/lab_test.js
+++ b/erpnext/healthcare/doctype/lab_test/lab_test.js
@@ -24,11 +24,6 @@
 	refresh :  function(frm){
 		refresh_field('normal_test_items');
 		refresh_field('special_test_items');
-		if(!frm.doc.__islocal && !frm.doc.invoice && frappe.user.has_role("Accounts User")){
-			frm.add_custom_button(__('Make Invoice'), function() {
-				make_invoice(frm);
-			});
-		}
 		if(frm.doc.__islocal){
 			frm.add_custom_button(__('Get from Patient Encounter'), function () {
 				get_lab_test_prescribed(frm);
@@ -166,8 +161,8 @@
 		<div class="col-xs-1">\
 		<a data-name="%(name)s" data-lab-test="%(lab_test)s"\
 		data-encounter="%(encounter)s" data-practitioner="%(practitioner)s"\
-		data-invoice="%(invoice)s" href="#"><button class="btn btn-default btn-xs">Get Lab Test\
-		</button></a></div></div>', {name:y[0], lab_test: y[1], encounter:y[2], invoice:y[3], practitioner:y[4], date:y[5]})).appendTo(html_field);
+		data-invoiced="%(invoiced)s" href="#"><button class="btn btn-default btn-xs">Get Lab Test\
+		</button></a></div></div>', {name:y[0], lab_test: y[1], encounter:y[2], invoiced:y[3], practitioner:y[4], date:y[5]})).appendTo(html_field);
 		row.find("a").click(function() {
 			frm.doc.template = $(this).attr("data-lab-test");
 			frm.doc.prescription = $(this).attr("data-name");
@@ -175,14 +170,11 @@
 			frm.set_df_property("template", "read_only", 1);
 			frm.set_df_property("patient", "read_only", 1);
 			frm.set_df_property("practitioner", "read_only", 1);
-			if($(this).attr("data-invoice") != 'null'){
-				frm.doc.invoice = $(this).attr("data-invoice");
-				refresh_field("invoice");
-			}else {
-				frm.doc.invoice = "";
-				refresh_field("invoice");
+			frm.doc.invoiced = 0;
+			if($(this).attr("data-invoiced") == 1){
+				frm.doc.invoiced = 1;
 			}
-
+			refresh_field("invoiced");
 			refresh_field("template");
 			d.hide();
 			return false;
@@ -195,24 +187,6 @@
 	d.show();
 };
 
-var make_invoice = function(frm){
-	var doc = frm.doc;
-	frappe.call({
-		method: "erpnext.healthcare.doctype.lab_test.lab_test.create_invoice",
-		args: {company:doc.company, patient:doc.patient, lab_tests: [doc.name], prescriptions:[]},
-		callback: function(r){
-			if(!r.exc){
-				if(r.message){
-					/*	frappe.show_alert(__('Sales Invoice {0} created',
-					['<a href="#Form/Sales Invoice/'+r.message+'">' + r.message+ '</a>']));	*/
-					frappe.set_route("Form", "Sales Invoice", r.message);
-				}
-				cur_frm.reload_doc();
-			}
-		}
-	});
-};
-
 cur_frm.cscript.custom_before_submit =  function(doc) {
 	if(doc.normal_test_items){
 		for(let result in doc.normal_test_items){
diff --git a/erpnext/healthcare/doctype/lab_test/lab_test.py b/erpnext/healthcare/doctype/lab_test/lab_test.py
index 767581f..9cba34c 100644
--- a/erpnext/healthcare/doctype/lab_test/lab_test.py
+++ b/erpnext/healthcare/doctype/lab_test/lab_test.py
@@ -5,10 +5,7 @@
 from __future__ import unicode_literals
 import frappe
 from frappe.model.document import Document
-import json
 from frappe.utils import getdate, cstr
-from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_receivable_account
-from frappe import _
 
 class LabTest(Document):
 	def on_submit(self):
@@ -31,6 +28,8 @@
 	def after_insert(self):
 		if(self.prescription):
 			frappe.db.set_value("Lab Prescription", self.prescription, "test_created", 1)
+			if frappe.db.get_value("Lab Prescription", self.prescription, 'invoiced') == 1:
+				self.invoiced = True
 		if not self.test_name and self.template:
 			self.load_test_from_template()
 			self.reload()
@@ -64,7 +63,7 @@
 	#create Test Result for template, copy vals from Invoice
 	lab_test = frappe.new_doc("Lab Test")
 	if(invoice):
-		lab_test.invoice = invoice
+		lab_test.invoiced = True
 	if(encounter):
 		lab_test.practitioner = encounter.practitioner
 	lab_test.patient = patient.name
@@ -133,7 +132,7 @@
 			#create Sample Collection for template, copy vals from Invoice
 			sample_collection = frappe.new_doc("Sample Collection")
 			if(invoice):
-				sample_collection.invoice = invoice
+				sample_collection.invoiced = True
 			sample_collection.patient = patient.name
 			sample_collection.patient_age = patient.get_age()
 			sample_collection.patient_sex = patient.sex
@@ -211,7 +210,7 @@
 		if(prescription):
 			lab_test.prescription = prescription
 			if(invoice):
-				frappe.db.set_value("Lab Prescription", prescription, "invoice", invoice)
+				frappe.db.set_value("Lab Prescription", prescription, "invoiced", True)
 		lab_test.save(ignore_permissions=True) # insert the result
 		return lab_test
 
@@ -248,49 +247,7 @@
 	if medical_record_id and medical_record_id[0][0]:
 		frappe.delete_doc("Patient Medical Record", medical_record_id[0][0])
 
-def create_item_line(test_code, sales_invoice):
-	if test_code:
-		item = frappe.get_doc("Item", test_code)
-		if item:
-			if not item.disabled:
-				sales_invoice_line = sales_invoice.append("items")
-				sales_invoice_line.item_code = item.item_code
-				sales_invoice_line.item_name =  item.item_name
-				sales_invoice_line.qty = 1.0
-				sales_invoice_line.description = item.description
-
-@frappe.whitelist()
-def create_invoice(company, patient, lab_tests, prescriptions):
-	test_ids = json.loads(lab_tests)
-	line_ids = json.loads(prescriptions)
-	if not test_ids and not line_ids:
-		return
-	sales_invoice = frappe.new_doc("Sales Invoice")
-	sales_invoice.customer = frappe.get_value("Patient", patient, "customer")
-	sales_invoice.due_date = getdate()
-	sales_invoice.is_pos = '0'
-	sales_invoice.debit_to = get_receivable_account(company)
-	for line in line_ids:
-		test_code = frappe.get_value("Lab Prescription", line, "test_code")
-		create_item_line(test_code, sales_invoice)
-	for test in test_ids:
-		template = frappe.get_value("Lab Test", test, "template")
-		test_code = frappe.get_value("Lab Test Template", template, "item")
-		create_item_line(test_code, sales_invoice)
-	sales_invoice.set_missing_values()
-	sales_invoice.save()
-	#set invoice in lab test
-	for test in test_ids:
-		frappe.db.set_value("Lab Test", test, "invoice", sales_invoice.name)
-		prescription = frappe.db.get_value("Lab Test", test, "prescription")
-		if prescription:
-			frappe.db.set_value("Lab Prescription", prescription, "invoice", sales_invoice.name)
-	#set invoice in prescription
-	for line in line_ids:
-		frappe.db.set_value("Lab Prescription", line, "invoice", sales_invoice.name)
-	return sales_invoice.name
-
 @frappe.whitelist()
 def get_lab_test_prescribed(patient):
-	return frappe.db.sql("""select cp.name, cp.test_code, cp.parent, cp.invoice, ct.practitioner, ct.encounter_date from `tabPatient Encounter` ct,
+	return frappe.db.sql("""select cp.name, cp.test_code, cp.parent, cp.invoiced, ct.practitioner, ct.encounter_date from `tabPatient Encounter` ct,
 	`tabLab Prescription` cp where ct.patient=%s and cp.parent=ct.name and cp.test_created=0""", (patient))
diff --git a/erpnext/healthcare/doctype/lab_test/lab_test_list.js b/erpnext/healthcare/doctype/lab_test/lab_test_list.js
index c36c115..1d65e5b 100644
--- a/erpnext/healthcare/doctype/lab_test/lab_test_list.js
+++ b/erpnext/healthcare/doctype/lab_test/lab_test_list.js
@@ -2,7 +2,7 @@
 (c) ESS 2015-16
 */
 frappe.listview_settings['Lab Test'] = {
-	add_fields: ["name", "status", "invoice"],
+	add_fields: ["name", "status", "invoiced"],
 	filters:[["docstatus","=","0"]],
 	get_indicator: function(doc) {
 		if(doc.status=="Approved"){
diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js
index 9799018..c0e5cd0 100644
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js
+++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js
@@ -4,7 +4,6 @@
 frappe.ui.form.on('Patient Appointment', {
 	setup: function(frm) {
 		frm.custom_make_buttons = {
-			'Sales Invoice': 'Invoice',
 			'Vital Signs': 'Vital Signs',
 			'Patient Encounter': 'Patient Encounter'
 		};
@@ -84,19 +83,6 @@
 				btn_update_status(frm, "Cancelled");
 			});
 		}
-
-		if(!frm.doc.__islocal){
-			if(frm.doc.sales_invoice && frappe.user.has_role("Accounts User")){
-				frm.add_custom_button(__('Invoice'), function() {
-					frappe.set_route("Form", "Sales Invoice", frm.doc.sales_invoice);
-				},__("View") );
-			}
-			else if(frm.doc.status != "Cancelled" && frappe.user.has_role("Accounts User")){
-				frm.add_custom_button(__('Invoice'), function() {
-					btn_invoice_encounter(frm);
-				},__("Create"));
-			}
-		}
 		frm.set_df_property("get_procedure_from_encounter", "read_only", frm.doc.__islocal ? 0 : 1);
 	},
 	check_availability: function(frm) {
@@ -339,21 +325,6 @@
 	);
 };
 
-var btn_invoice_encounter = function(frm){
-	frappe.call({
-		doc: frm.doc,
-		method:"create_invoice",
-		callback: function(data){
-			if(!data.exc){
-				if(data.message){
-					frappe.set_route("Form", "Sales Invoice", data.message);
-				}
-				cur_frm.reload_doc();
-			}
-		}
-	});
-};
-
 frappe.ui.form.on("Patient Appointment", "practitioner", function(frm) {
 	if(frm.doc.practitioner){
 		frappe.call({
diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py
index ad2a933..7d0dade 100755
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py
+++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.py
@@ -10,7 +10,6 @@
 from frappe import _
 import datetime
 from frappe.core.doctype.sms_settings.sms_settings import send_sms
-from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_receivable_account,get_income_account
 from erpnext.hr.doctype.employee.employee import is_holiday
 
 class PatientAppointment(Document):
@@ -38,26 +37,23 @@
 				visited = fee_validity.visited + 1
 				frappe.db.set_value("Fee Validity", fee_validity.name, "visited", visited)
 				if fee_validity.ref_invoice:
-					frappe.db.set_value("Patient Appointment", appointment.name, "sales_invoice", fee_validity.ref_invoice)
+					frappe.db.set_value("Patient Appointment", appointment.name, "invoiced", True)
 				frappe.msgprint(_("{0} has fee validity till {1}").format(appointment.patient, fee_validity.valid_till))
 		confirm_sms(self)
 
-	def create_invoice(self):
-		return invoice_appointment(self)
-
 def appointment_cancel(appointment_id):
 	appointment = frappe.get_doc("Patient Appointment", appointment_id)
 
-	# If invoice --> fee_validity update with -1 visit
-	if appointment.sales_invoice:
-		validity = frappe.db.exists({"doctype": "Fee Validity", "ref_invoice": appointment.sales_invoice})
+	# If invoiced --> fee_validity update with -1 visit
+	if appointment.invoiced:
+		validity = validity_exists(appointment.practitioner, appointment.patient)
 		if validity:
 			fee_validity = frappe.get_doc("Fee Validity", validity[0][0])
 			visited = fee_validity.visited - 1
 			frappe.db.set_value("Fee Validity", fee_validity.name, "visited", visited)
 			if visited <= 0:
 				frappe.msgprint(
-					_("Appointment cancelled, Please review and cancel the invoice {0}".format(appointment.sales_invoice))
+					_("Appointment cancelled, Please review and cancel the invoice {0}".format(fee_validity.ref_invoice))
 				)
 			else:
 				frappe.msgprint(_("Appointment cancelled"))
@@ -198,99 +194,12 @@
 		send_message(doc, message)
 
 
-@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 = '0'
-	sales_invoice.company = appointment_doc.company
-	sales_invoice.debit_to = get_receivable_account(appointment_doc.company)
-
-	fee_validity = get_fee_validity(appointment_doc.practitioner, appointment_doc.patient, appointment_doc.appointment_date)
-	procedure_template = False
-	if appointment_doc.procedure_template:
-		procedure_template = appointment_doc.procedure_template
-	create_invoice_items(appointment_doc.practitioner, appointment_doc.company, sales_invoice, procedure_template)
-
-	sales_invoice.save(ignore_permissions=True)
-	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)
-	encounter = frappe.db.exists({
-			"doctype": "Patient Encounter",
-			"appointment": appointment_doc.name})
-	if encounter:
-		frappe.db.set_value("Patient Encounter", encounter[0][0], "invoice", sales_invoice.name)
-	return sales_invoice.name
-
-
-def get_fee_validity(practitioner, patient, date):
-	validity_exist = validity_exists(practitioner, patient)
-	if validity_exist:
-		fee_validity = frappe.get_doc("Fee Validity", validity_exist[0][0])
-		fee_validity = update_fee_validity(fee_validity, date)
-	else:
-		fee_validity = create_fee_validity(practitioner, patient, date)
-	return fee_validity
-
-
 def validity_exists(practitioner, patient):
 	return frappe.db.exists({
 			"doctype": "Fee Validity",
 			"practitioner": practitioner,
 			"patient": patient})
 
-
-def update_fee_validity(fee_validity, date):
-	max_visit = frappe.db.get_value("Healthcare Settings", None, "max_visit")
-	valid_days = frappe.db.get_value("Healthcare Settings", None, "valid_days")
-	if not valid_days:
-		valid_days = 1
-	if not max_visit:
-		max_visit = 1
-	date = getdate(date)
-	valid_till = date + datetime.timedelta(days=int(valid_days))
-	fee_validity.max_visit = max_visit
-	fee_validity.visited = 1
-	fee_validity.valid_till = valid_till
-	fee_validity.save(ignore_permissions=True)
-	return fee_validity
-
-
-def create_fee_validity(practitioner, patient, date):
-	fee_validity = frappe.new_doc("Fee Validity")
-	fee_validity.practitioner = practitioner
-	fee_validity.patient = patient
-	fee_validity = update_fee_validity(fee_validity, date)
-	return fee_validity
-
-
-def create_invoice_items(practitioner, company, invoice, procedure_template):
-	item_line = invoice.append("items")
-	if procedure_template:
-		procedure_template_obj = frappe.get_doc("Clinical Procedure Template", procedure_template)
-		item_line.item_code = procedure_template_obj.item_code
-		item_line.item_name = procedure_template_obj.template
-		item_line.description = procedure_template_obj.description
-	else:
-		item_line.item_name = "Consulting Charges"
-		item_line.description = "Consulting Charges:  " + practitioner
-		item_line.uom = "Nos"
-		item_line.conversion_factor = 1
-		item_line.income_account = get_income_account(practitioner, company)
-		op_consulting_charge = frappe.db.get_value("Healthcare Practitioner", practitioner, "op_consulting_charge")
-		if op_consulting_charge:
-			item_line.rate = op_consulting_charge
-			item_line.amount = op_consulting_charge
-	item_line.qty = 1
-
-
-	return invoice
-
-
 @frappe.whitelist()
 def create_encounter(appointment):
 	appointment = frappe.get_doc("Patient Appointment", appointment)
@@ -301,8 +210,8 @@
 	encounter.visit_department = appointment.department
 	encounter.patient_sex = appointment.patient_sex
 	encounter.encounter_date = appointment.appointment_date
-	if appointment.sales_invoice:
-		encounter.invoice = appointment.sales_invoice
+	if appointment.invoiced:
+		encounter.invoiced = True
 	return encounter.as_dict()
 
 
@@ -359,6 +268,7 @@
 		item.appointment_datetime = item.appointment_date + datetime.timedelta(minutes = item.duration)
 
 	return data
+
 @frappe.whitelist()
 def get_procedure_prescribed(patient):
 	return frappe.db.sql("""select pp.name, pp.procedure, pp.parent, ct.practitioner,
diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment_dashboard.py b/erpnext/healthcare/doctype/patient_appointment/patient_appointment_dashboard.py
index f9ef1cb..a030f19 100644
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment_dashboard.py
+++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment_dashboard.py
@@ -10,10 +10,6 @@
 			{
 				'label': _('Consultations'),
 				'items': ['Patient Encounter', 'Vital Signs', 'Patient Medical Record']
-			},
-			{
-				'label': _('Billing'),
-				'items': ['Sales Invoice']
 			}
 		]
 	}
diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js
index 47c9cad..2dd3512 100644
--- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js
+++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.js
@@ -94,11 +94,6 @@
 				}
 			};
 		});
-		if(!frm.doc.__islocal && !frm.doc.invoice && (frappe.user.has_role("Accounts User"))){
-			frm.add_custom_button(__('Invoice'), function() {
-				btn_invoice_encounter(frm);
-			},__("Create"));
-		}
 		frm.set_df_property("appointment", "read_only", frm.doc.__islocal ? 0:1);
 		frm.set_df_property("patient", "read_only", frm.doc.__islocal ? 0:1);
 		frm.set_df_property("patient_age", "read_only", frm.doc.__islocal ? 0:1);
@@ -139,23 +134,6 @@
 	});
 };
 
-var btn_invoice_encounter = function(frm){
-	var doc = frm.doc;
-	frappe.call({
-		method:
-		"erpnext.healthcare.doctype.encounter.encounter.create_invoice",
-		args: {company: doc.company, patient: doc.patient, practitioner: doc.practitioner, encounter_id: doc.name },
-		callback: function(data){
-			if(!data.exc){
-				if(data.message){
-					frappe.set_route("Form", "Sales Invoice", data.message);
-				}
-				cur_frm.reload_doc();
-			}
-		}
-	});
-};
-
 var create_medical_record = function (frm) {
 	if(!frm.doc.patient){
 		frappe.throw(__("Please select patient"));
@@ -203,10 +181,16 @@
 				frappe.model.set_value(frm.doctype,frm.docname, "patient", data.message.patient);
 				frappe.model.set_value(frm.doctype,frm.docname, "type", data.message.appointment_type);
 				frappe.model.set_value(frm.doctype,frm.docname, "practitioner", data.message.practitioner);
-				frappe.model.set_value(frm.doctype,frm.docname, "invoice", data.message.sales_invoice);
+				frappe.model.set_value(frm.doctype,frm.docname, "invoiced", data.message.invoiced);
 			}
 		});
 	}
+	else{
+		frappe.model.set_value(frm.doctype,frm.docname, "patient", "");
+		frappe.model.set_value(frm.doctype,frm.docname, "type", "");
+		frappe.model.set_value(frm.doctype,frm.docname, "practitioner", "");
+		frappe.model.set_value(frm.doctype,frm.docname, "invoiced", 0);
+	}
 });
 
 frappe.ui.form.on("Patient Encounter", "practitioner", function(frm) {
diff --git a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py
index 3d8f952..5aa7867 100644
--- a/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py
+++ b/erpnext/healthcare/doctype/patient_encounter/patient_encounter.py
@@ -7,7 +7,6 @@
 from frappe.model.document import Document
 from frappe.utils import getdate, cstr
 import json
-from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_receivable_account, get_income_account
 
 class PatientEncounter(Document):
 	def on_update(self):
@@ -23,77 +22,6 @@
 			frappe.db.set_value("Patient Appointment", self.appointment, "status", "Open")
 		delete_medical_record(self)
 
-def set_sales_invoice_fields(company, patient):
-	sales_invoice = frappe.new_doc("Sales Invoice")
-	sales_invoice.customer = frappe.get_value("Patient", patient, "customer")
-	# patient is custom field in sales inv.
-	sales_invoice.due_date = getdate()
-	sales_invoice.is_pos = '0'
-	sales_invoice.debit_to = get_receivable_account(company)
-
-	return sales_invoice
-
-def create_sales_invoice_item_lines(item, sales_invoice):
-	sales_invoice_line = sales_invoice.append("items")
-	sales_invoice_line.item_code = item.item_code
-	sales_invoice_line.item_name =  item.item_name
-	sales_invoice_line.qty = 1.0
-	sales_invoice_line.description = item.description
-	return sales_invoice_line
-
-@frappe.whitelist()
-def create_drug_invoice(company, patient, prescriptions):
-	list_ids = json.loads(prescriptions)
-	if not (company or patient or prescriptions):
-		return False
-
-	sales_invoice = set_sales_invoice_fields(company, patient)
-	sales_invoice.update_stock = 1
-
-	for line_id in list_ids:
-		line_obj = frappe.get_doc("Drug Prescription", line_id)
-		if line_obj:
-			if(line_obj.drug_code):
-				item = frappe.get_doc("Item", line_obj.drug_code)
-				sales_invoice_line = create_sales_invoice_item_lines(item, sales_invoice)
-				sales_invoice_line.qty = line_obj.get_quantity()
-	#income_account and cost_center in itemlines - by set_missing_values()
-	sales_invoice.set_missing_values()
-	return sales_invoice.as_dict()
-
-@frappe.whitelist()
-def create_invoice(company, patient, practitioner, encounter_id):
-	if not encounter_id:
-		return False
-	sales_invoice = frappe.new_doc("Sales Invoice")
-	sales_invoice.customer = frappe.get_value("Patient", patient, "customer")
-	sales_invoice.due_date = getdate()
-	sales_invoice.is_pos = '0'
-	sales_invoice.debit_to = get_receivable_account(company)
-
-	create_invoice_items(practitioner, sales_invoice, company)
-
-	sales_invoice.save(ignore_permissions=True)
-	frappe.db.sql("""update `tabPatient Encounter` set invoice=%s where name=%s""", (sales_invoice.name, encounter_id))
-	appointment = frappe.db.get_value("Patient Encounter", encounter_id, "appointment")
-	if appointment:
-		frappe.db.set_value("Patient Appointment", appointment, "sales_invoice", sales_invoice.name)
-	return sales_invoice.name
-
-def create_invoice_items(practitioner, invoice, company):
-	item_line = invoice.append("items")
-	item_line.item_name = "Consulting Charges"
-	item_line.description = "Consulting Charges:  " + practitioner
-	item_line.qty = 1
-	item_line.uom = "Nos"
-	item_line.conversion_factor = 1
-	item_line.income_account = get_income_account(practitioner, company)
-	op_consulting_charge = frappe.get_value("Healthcare Practitioner", practitioner, "op_consulting_charge")
-	if op_consulting_charge:
-		item_line.rate = op_consulting_charge
-		item_line.amount = op_consulting_charge
-	return invoice
-
 def insert_encounter_to_medical_record(doc):
 	subject = set_subject_field(doc)
 	medical_record = frappe.new_doc("Patient Medical Record")
diff --git a/erpnext/healthcare/report/lab_test_report/lab_test_report.py b/erpnext/healthcare/report/lab_test_report/lab_test_report.py
index e4771c5..b9a26df 100644
--- a/erpnext/healthcare/report/lab_test_report/lab_test_report.py
+++ b/erpnext/healthcare/report/lab_test_report/lab_test_report.py
@@ -17,7 +17,7 @@
 
 	data = []
 	for lab_test in lab_test_list:
-		row = [ lab_test.test_name, lab_test.patient, lab_test.practitioner, lab_test.invoice, lab_test.status, lab_test.result_date, lab_test.department]
+		row = [ lab_test.test_name, lab_test.patient, lab_test.practitioner, lab_test.invoiced, lab_test.status, lab_test.result_date, lab_test.department]
 		data.append(row)
 
 	return columns, data
@@ -28,7 +28,7 @@
 		_("Test") + ":Data:120",
 		_("Patient") + ":Link/Patient:180",
 		_("Healthcare Practitioner") + ":Link/Healthcare Practitioner:120",
-		_("Invoice") + ":Link/Sales Invoice:120",
+		_("Invoiced") + ":Check:100",
 		_("Status") + ":Data:120",
 		_("Result Date") + ":Date:120",
 		_("Department") + ":Data:120",
@@ -52,7 +52,7 @@
 
 def get_lab_test(filters):
 	conditions = get_conditions(filters)
-	return frappe.db.sql("""select name, patient, test_name, patient_name, status, result_date, practitioner, invoice, department
+	return frappe.db.sql("""select name, patient, test_name, patient_name, status, result_date, practitioner, invoiced, department
 		from `tabLab Test`
 		where docstatus<2 %s order by submitted_date desc, name desc""" %
 		conditions, filters, as_dict=1)
diff --git a/erpnext/healthcare/utils.py b/erpnext/healthcare/utils.py
new file mode 100644
index 0000000..5a7c7e3
--- /dev/null
+++ b/erpnext/healthcare/utils.py
@@ -0,0 +1,232 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, earthians and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+import datetime
+from frappe import _
+from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_income_account
+from erpnext.healthcare.doctype.patient_appointment.patient_appointment import validity_exists
+from erpnext.healthcare.doctype.fee_validity.fee_validity import create_fee_validity, update_fee_validity
+
+@frappe.whitelist()
+def get_healthcare_services_to_invoice(patient):
+	patient = frappe.get_doc("Patient", patient)
+	if patient:
+		if patient.customer:
+			item_to_invoice = []
+			patient_appointments = frappe.get_list("Patient Appointment",{'patient': patient.name, 'invoiced': False},
+			order_by="appointment_date")
+			if patient_appointments:
+				fee_validity_details = []
+				valid_days = frappe.db.get_value("Healthcare Settings", None, "valid_days")
+				max_visit = frappe.db.get_value("Healthcare Settings", None, "max_visit")
+				for patient_appointment in patient_appointments:
+					patient_appointment_obj = frappe.get_doc("Patient Appointment", patient_appointment['name'])
+
+					if patient_appointment_obj.procedure_template:
+						if frappe.db.get_value("Clinical Procedure Template", patient_appointment_obj.procedure_template, "is_billable") == 1:
+							item_to_invoice.append({'reference_type': 'Patient Appointment', 'reference_name': patient_appointment_obj.name, 'service': patient_appointment_obj.procedure_template})
+					else:
+						practitioner_exist_in_list = False
+						skip_invoice = False
+						if fee_validity_details:
+							for validity in fee_validity_details:
+								if validity['practitioner'] == patient_appointment_obj.practitioner:
+									practitioner_exist_in_list = True
+									if validity['valid_till'] >= patient_appointment_obj.appointment_date:
+										validity['visits'] = validity['visits']+1
+										if int(max_visit) > validity['visits']:
+											skip_invoice = True
+									if not skip_invoice:
+										validity['visits'] = 1
+										validity['valid_till'] = patient_appointment_obj.appointment_date + datetime.timedelta(days=int(valid_days))
+						if not practitioner_exist_in_list:
+							valid_till = patient_appointment_obj.appointment_date + datetime.timedelta(days=int(valid_days))
+							visits = 0
+							validity_exist = validity_exists(patient_appointment_obj.practitioner, patient_appointment_obj.patient)
+							if validity_exist:
+								fee_validity = frappe.get_doc("Fee Validity", validity_exist[0][0])
+								valid_till = fee_validity.valid_till
+								visits = fee_validity.visited
+							fee_validity_details.append({'practitioner': patient_appointment_obj.practitioner,
+							'valid_till': valid_till, 'visits': visits})
+
+						if not skip_invoice:
+							practitioner_charge = 0
+							income_account = None
+							if patient_appointment_obj.practitioner:
+								practitioner_charge = get_practitioner_charge(patient_appointment_obj.practitioner)
+								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': 'Consulting Charges', 'rate': practitioner_charge,
+							'income_account': income_account})
+
+			encounters = frappe.get_list("Patient Encounter", {'patient': patient.name, 'invoiced': False, 'docstatus': 1})
+			if encounters:
+				for encounter in encounters:
+					encounter_obj = frappe.get_doc("Patient Encounter", encounter['name'])
+					if not encounter_obj.appointment:
+						practitioner_charge = 0
+						income_account = None
+						if encounter_obj.practitioner:
+							practitioner_charge = get_practitioner_charge(encounter_obj.practitioner)
+							income_account = get_income_account(encounter_obj.practitioner, encounter_obj.company)
+						item_to_invoice.append({'reference_type': 'Patient Encounter', 'reference_name': encounter_obj.name,
+						'service': 'Consulting Charges', 'rate': practitioner_charge,
+						'income_account': income_account})
+
+			lab_tests = frappe.get_list("Lab Test", {'patient': patient.name, 'invoiced': False})
+			if lab_tests:
+				for lab_test in lab_tests:
+					lab_test_obj = frappe.get_doc("Lab Test", lab_test['name'])
+					if frappe.db.get_value("Lab Test Template", lab_test_obj.template, "is_billable") == 1:
+						item_to_invoice.append({'reference_type': 'Lab Test', 'reference_name': lab_test_obj.name, 'service': lab_test_obj.template})
+
+			lab_rxs = frappe.db.sql("""select lp.name from `tabPatient Encounter` et,
+			`tabLab Prescription` lp where et.patient=%s and lp.parent=et.name and lp.test_created=0 and lp.invoiced=0""", (patient.name))
+			if lab_rxs:
+				for lab_rx in lab_rxs:
+					rx_obj = frappe.get_doc("Lab Prescription", lab_rx[0])
+					if rx_obj.test_code and (frappe.db.get_value("Lab Test Template", rx_obj.test_code, "is_billable") == 1):
+						item_to_invoice.append({'reference_type': 'Lab Prescription', 'reference_name': rx_obj.name, 'service': rx_obj.test_code})
+
+			procedures = frappe.get_list("Clinical Procedure", {'patient': patient.name, 'invoiced': False})
+			if procedures:
+				for procedure in procedures:
+					procedure_obj = frappe.get_doc("Clinical Procedure", procedure['name'])
+					if not procedure_obj.appointment:
+						if procedure_obj.procedure_template and (frappe.db.get_value("Clinical Procedure Template", procedure_obj.procedure_template, "is_billable") == 1):
+							item_to_invoice.append({'reference_type': 'Clinical Procedure', 'reference_name': procedure_obj.name, 'service': procedure_obj.procedure_template})
+
+			procedure_rxs = frappe.db.sql("""select pp.name from `tabPatient Encounter` et,
+			`tabProcedure Prescription` pp where et.patient=%s and pp.parent=et.name and
+			pp.procedure_created=0 and pp.invoiced=0 and pp.appointment_booked=0""", (patient.name))
+			if procedure_rxs:
+				for procedure_rx in procedure_rxs:
+					rx_obj = frappe.get_doc("Procedure Prescription", procedure_rx[0])
+					if frappe.db.get_value("Clinical Procedure Template", rx_obj.procedure, "is_billable") == 1:
+						item_to_invoice.append({'reference_type': 'Procedure Prescription', 'reference_name': rx_obj.name, 'service': rx_obj.procedure})
+
+			procedure_consumables = frappe.db.sql("""select pc.name from `tabClinical Procedure` cp,
+			`tabClinical Procedure Item` pc where cp.patient=%s and pc.parent=cp.name and
+			pc.invoice_separately_as_consumables=1 and pc.invoiced=0""", (patient.name))
+			if procedure_consumables:
+				for procedure_consumable in procedure_consumables:
+					procedure_consumable_obj = frappe.get_doc("Clinical Procedure Item", procedure_consumable[0])
+					item_to_invoice.append({'reference_type': 'Clinical Procedure Item', 'reference_name': procedure_consumable_obj.name,
+					'service': procedure_consumable_obj.item_code, 'qty': procedure_consumable_obj.qty})
+
+			return item_to_invoice
+		else:
+			frappe.throw(_("The Patient {0} do not have customer refrence to invoice").format(patient.name))
+
+def get_practitioner_charge(practitioner):
+	practitioner_charge = frappe.db.get_value("Healthcare Practitioner", practitioner, "op_consulting_charge")
+	if practitioner_charge:
+		return practitioner_charge
+
+def manage_invoice_submit_cancel(doc, method):
+	if doc.items:
+		for item in doc.items:
+			if item.reference_dt and item.reference_dn:
+				if frappe.get_meta(item.reference_dt).has_field("invoiced"):
+					set_invoiced(item, method)
+
+def set_invoiced(item, method):
+	invoiced = False
+	if(method=="on_submit"):
+		validate_invoiced_on_submit(item)
+		invoiced = True
+
+	frappe.db.set_value(item.reference_dt, item.reference_dn, "invoiced", invoiced)
+	if item.reference_dt == 'Patient Appointment':
+		if frappe.db.get_value('Patient Appointment', item.reference_dn, 'procedure_template'):
+			dt_from_appointment = "Clinical Procedure"
+		else:
+			manage_fee_validity(item.reference_dn, method)
+			dt_from_appointment = "Patient Encounter"
+		manage_doc_for_appoitnment(dt_from_appointment, item.reference_dn, invoiced)
+
+	elif item.reference_dt == 'Lab Prescription':
+		manage_prescriptions(invoiced, item.reference_dt, item.reference_dn, "Lab Test", "test_created")
+
+	elif item.reference_dt == 'Procedure Prescription':
+		manage_prescriptions(invoiced, item.reference_dt, item.reference_dn, "Clinical Procedure", "procedure_created")
+
+def validate_invoiced_on_submit(item):
+	is_invoiced = frappe.db.get_value(item.reference_dt, item.reference_dn, "invoiced")
+	if is_invoiced == 1:
+		frappe.throw(_("The item referenced by {0} - {1} is already invoiced"\
+		).format(item.reference_dt, item.reference_dn))
+
+def manage_prescriptions(invoiced, ref_dt, ref_dn, dt, created_check_field):
+	created = frappe.db.get_value(ref_dt, ref_dn, created_check_field)
+	if created == 1:
+		# Fetch the doc created for the prescription
+		doc_created = frappe.db.get_value(dt, {'prescription': item.reference_dn})
+		frappe.db.set_value(dt, doc_created, 'invoiced', invoiced)
+
+def manage_fee_validity(appointment_name, method):
+	appointment_doc = frappe.get_doc("Patient Appointment", appointment_name)
+	validity_exist = validity_exists(appointment_doc.practitioner, appointment_doc.patient)
+	do_not_update = False
+	visited = 0
+	if validity_exist:
+		fee_validity = frappe.get_doc("Fee Validity", validity_exist[0][0])
+		# Check if the validity is valid
+		if (fee_validity.valid_till >= appointment_doc.appointment_date):
+			if (method == "on_cancel" and appointment_doc.status != "Closed"):
+				visited = fee_validity.visited - 1
+				if visited < 0:
+					visited = 0
+				frappe.db.set_value("Fee Validity", fee_validity.name, "visited", visited)
+				do_not_update = True
+			elif (fee_validity.visited < fee_validity.max_visit):
+				visited = fee_validity.visited + 1
+				frappe.db.set_value("Fee Validity", fee_validity.name, "visited", visited)
+				do_not_update = True
+			else:
+				do_not_update = False
+
+		if not do_not_update:
+			fee_validity = update_fee_validity(fee_validity, appointment_doc.appointment_date)
+			visited = fee_validity.visited
+	else:
+		fee_validity = create_fee_validity(appointment_doc.practitioner, appointment_doc.patient, appointment_doc.appointment_date)
+		visited = fee_validity.visited
+
+	# Mark All Patient Appointment invoiced = True in the validity range do not cross the max visit
+	if (method == "on_cancel"):
+		invoiced = True
+	else:
+		invoiced = False
+	patient_appointments = frappe.get_list("Patient Appointment",{'patient': fee_validity.patient, 'invoiced': invoiced,
+	'appointment_date':("<=", fee_validity.valid_till), 'practitioner': fee_validity.practitioner}, order_by="appointment_date")
+	if patient_appointments and fee_validity:
+		visit = visited
+		for appointment in patient_appointments:
+			if (method == "on_cancel" and appointment.status != "Closed"):
+				visited = visited - 1
+				if visited < 0:
+					visited = 0
+				frappe.db.set_value("Fee Validity", fee_validity.name, "visited", visited)
+				frappe.db.set_value("Patient Appointment", appointment.name, "invoiced", False)
+				manage_doc_for_appoitnment("Patient Encounter", appointment.name, False)
+			elif int(fee_validity.max_visit) > visit:
+				visited = visited + 1
+				frappe.db.set_value("Fee Validity", fee_validity.name, "visited", visited)
+				frappe.db.set_value("Patient Appointment", appointment.name, "invoiced", True)
+				manage_doc_for_appoitnment("Patient Encounter", appointment.name, True)
+			visit = visit + 1
+
+def manage_doc_for_appoitnment(dt_from_appointment, appointment, invoiced):
+	dn_from_appointment = frappe.db.exists(
+		dt_from_appointment,
+		{
+			"appointment": appointment
+		}
+	)
+	if dn_from_appointment:
+		frappe.db.set_value(dt_from_appointment, dn_from_appointment, "invoiced", invoiced)