Clinical Procedure - Consumables Invoice Separately
diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js
index 9fc5b37..7f866e1 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js
+++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.js
@@ -264,21 +264,20 @@
 		let args = null;
 		if(d.item_code) {
 			args = {
-				'item_code'			: d.item_code,
-				'transfer_qty'		: d.transfer_qty,
-				'company'			: frm.doc.company,
-				'quantity'				: d.qty
+				'doctype' : "Clinical Procedure",
+				'item_code' : d.item_code,
+				'company' : frm.doc.company,
+				'warehouse': frm.doc.warehouse
 			};
 			return frappe.call({
-				doc: frm.doc,
-				method: "get_item_details",
-				args: args,
+				method: "erpnext.stock.get_item_details.get_item_details",
+				args: {args: args},
 				callback: function(r) {
 					if(r.message) {
-						var d = locals[cdt][cdn];
-						$.each(r.message, function(k, v){
-							d[k] = v;
-						});
+						frappe.model.set_value(cdt, cdn, "item_name", r.message.item_name);
+						frappe.model.set_value(cdt, cdn, "stock_uom", r.message.stock_uom);
+						frappe.model.set_value(cdt, cdn, "conversion_factor", r.message.conversion_factor);
+						frappe.model.set_value(cdt, cdn, "actual_qty", r.message.actual_qty);
 						refresh_field("items");
 					}
 				}
diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json
index 0856606..a830c37 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json
+++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.json
@@ -711,6 +711,139 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
+   "default": "0", 
+   "fieldname": "invoice_separately_as_consumables", 
+   "fieldtype": "Check", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Consumables Invoice Separately", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 1, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "depends_on": "invoice_separately_as_consumables", 
+   "fieldname": "consumable_total_amount", 
+   "fieldtype": "Currency", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Consumable Total Amount", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 1, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "depends_on": "invoice_separately_as_consumables", 
+   "fieldname": "consumption_details", 
+   "fieldtype": "Small Text", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Consumption Details", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "default": "0", 
+   "depends_on": "invoice_separately_as_consumables", 
+   "fieldname": "consumption_invoiced", 
+   "fieldtype": "Check", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Consumption Invoiced", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 1, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_in_quick_entry": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
    "default": "", 
    "fieldname": "status", 
    "fieldtype": "Select", 
diff --git a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
index d51d062..4a4bd39 100644
--- a/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
+++ b/erpnext/healthcare/doctype/clinical_procedure/clinical_procedure.py
@@ -10,6 +10,7 @@
 from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_account
 from erpnext.healthcare.doctype.lab_test.lab_test import create_sample_doc
 from erpnext.stock.stock_ledger import get_previous_sle
+from erpnext.stock.get_item_details import get_item_details
 
 class ClinicalProcedure(Document):
 	def validate(self):
@@ -18,6 +19,12 @@
 				frappe.throw(("Set warehouse for Procedure {0} ").format(self.name))
 			self.set_actual_qty()
 
+		if self.items:
+			self.invoice_separately_as_consumables = False
+			for item in self.items:
+				if item.invoice_separately_as_consumables == 1:
+					self.invoice_separately_as_consumables = True
+
 	def before_insert(self):
 		if self.consume_stock:
 			set_stock_items(self, self.procedure_template, "Clinical Procedure Template")
@@ -40,6 +47,36 @@
 			create_stock_entry(self)
 		frappe.db.set_value("Clinical Procedure", self.name, "status", 'Completed')
 
+		if self.items:
+			consumable_total_amount = 0
+			consumption_details = False
+			for item in self.items:
+				if item.invoice_separately_as_consumables:
+					price_list, price_list_currency = frappe.db.get_values("Price List", {"selling": 1}, ['name', 'currency'])[0]
+					args = {
+						'doctype': "Sales Invoice",
+						'item_code': item.item_code,
+						'company': self.company,
+						'warehouse': self.warehouse,
+						'customer': frappe.db.get_value("Patient", self.patient, "customer"),
+						'selling_price_list': price_list,
+						'price_list_currency': price_list_currency,
+						'plc_conversion_rate': 1.0,
+						'conversion_rate': 1.0
+					}
+					item_details = get_item_details(args)
+					item_price = item_details.price_list_rate * item.transfer_qty
+					item_consumption_details = item_details.item_name+"\t"+str(item.qty)+" "+item.uom+"\t"+str(item_price)
+					consumable_total_amount += item_price
+					if not consumption_details:
+						consumption_details = "Clinical Procedure ("+self.name+"):\n\t"+item_consumption_details
+					else:
+						consumption_details += "\n\t"+item_consumption_details
+			if consumable_total_amount > 0:
+				frappe.db.set_value("Clinical Procedure", self.name, "consumable_total_amount", consumable_total_amount)
+				frappe.db.set_value("Clinical Procedure", self.name, "consumption_details", consumption_details)
+
+
 	def start(self):
 		allow_start = self.set_actual_qty()
 		if allow_start:
@@ -54,16 +91,7 @@
 
 		allow_start = True
 		for d in self.get('items'):
-			previous_sle = get_previous_sle({
-				"item_code": d.item_code,
-				"warehouse": self.warehouse,
-				"posting_date": nowdate(),
-				"posting_time": nowtime()
-			})
-
-			# get actual stock at source warehouse
-			d.actual_qty = previous_sle.get("qty_after_transaction") or 0
-
+			d.actual_qty = get_stock_qty(d.item_code, self.warehouse)
 			# validate qty
 			if not allow_negative_stock and d.actual_qty < d.qty:
 				allow_start = False
@@ -93,28 +121,14 @@
 				se_child.expense_account = expense_account
 		return stock_entry.as_dict()
 
-	def get_item_details(self, args=None):
-		item = frappe.db.sql("""select stock_uom, description, image, item_name,
-			expense_account, buying_cost_center, item_group from `tabItem`
-			where name = %s
-				and disabled=0
-				and (end_of_life is null or end_of_life='0000-00-00' or end_of_life > %s)""",
-			(args.get('item_code'), nowdate()), as_dict = 1)
-		if not item:
-			frappe.throw(_("Item {0} is not active or end of life has been reached").format(args.get('item_code')))
-
-		item = item[0]
-
-		ret = {
-			'uom'			      	: item.stock_uom,
-			'stock_uom'			  	: item.stock_uom,
-			'item_name' 		  	: item.item_name,
-			'quantity'				: 0,
-			'transfer_qty'			: 0,
-			'conversion_factor'		: 1
-		}
-		return ret
-
+@frappe.whitelist()
+def get_stock_qty(item_code, warehouse):
+	return get_previous_sle({
+		"item_code": item_code,
+		"warehouse": warehouse,
+		"posting_date": nowdate(),
+		"posting_time": nowtime()
+	}).get("qty_after_transaction") or 0
 
 @frappe.whitelist()
 def set_stock_items(doc, stock_detail_parent, parenttype):