Merge branch 'develop' of https://github.com/frappe/erpnext into rebrand-ui
diff --git a/erpnext/healthcare/desk_page/healthcare/healthcare.json b/erpnext/healthcare/desk_page/healthcare/healthcare.json
index cd63e0f..c77d082 100644
--- a/erpnext/healthcare/desk_page/healthcare/healthcare.json
+++ b/erpnext/healthcare/desk_page/healthcare/healthcare.json
@@ -32,13 +32,18 @@
   },
   {
    "hidden": 0,
+   "label": "Inpatient",
+   "links": "[\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Inpatient Record\",\n\t\t\"label\": \"Inpatient Record\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Inpatient Medication Order\",\n\t\t\"label\": \"Inpatient Medication Order\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Inpatient Medication Entry\",\n\t\t\"label\": \"Inpatient Medication Entry\"\n\t}\n]"
+  },
+  {
+   "hidden": 0,
    "label": "Rehabilitation and Physiotherapy",
    "links": "[\n    {\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Exercise Type\",\n\t\t\"label\": \"Exercise Type\",\n\t\t\"onboard\": 1\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Therapy Type\",\n\t\t\"label\": \"Therapy Type\",\n\t\t\"onboard\": 1\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Therapy Plan\",\n\t\t\"label\": \"Therapy Plan\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Therapy Session\",\n\t\t\"label\": \"Therapy Session\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Assessment Template\",\n\t\t\"label\": \"Patient Assessment Template\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Assessment\",\n\t\t\"label\": \"Patient Assessment\"\n\t}\n]"
   },
   {
    "hidden": 0,
    "label": "Records and History",
-   "links": "[\n\t{\n\t\t\"type\": \"page\",\n\t\t\"name\": \"patient_history\",\n\t\t\"label\": \"Patient History\"\n\t},\n\t{\n\t\t\"type\": \"page\",\n\t\t\"name\": \"patient-progress\",\n\t\t\"label\": \"Patient Progress\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Medical Record\",\n\t\t\"label\": \"Patient Medical Record\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Inpatient Record\",\n\t\t\"label\": \"Inpatient Record\"\n\t}\n]"
+   "links": "[\n\t{\n\t\t\"type\": \"page\",\n\t\t\"name\": \"patient_history\",\n\t\t\"label\": \"Patient History\"\n\t},\n\t{\n\t\t\"type\": \"page\",\n\t\t\"name\": \"patient-progress\",\n\t\t\"label\": \"Patient Progress\"\n\t},\n\t{\n\t\t\"type\": \"doctype\",\n\t\t\"name\": \"Patient Medical Record\",\n\t\t\"label\": \"Patient Medical Record\"\n\t}\n]"
   },
   {
    "hidden": 0,
@@ -65,7 +70,7 @@
  "idx": 0,
  "is_standard": 1,
  "label": "Healthcare",
- "modified": "2020-11-23 23:00:48.764377",
+ "modified": "2020-11-26 22:09:09.164584",
  "modified_by": "Administrator",
  "module": "Healthcare",
  "name": "Healthcare",
diff --git a/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.js b/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.js
index f523cf2..ca97489 100644
--- a/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.js
+++ b/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.js
@@ -29,6 +29,29 @@
 				}
 			};
 		});
+
+		if (frm.doc.__islocal || frm.doc.docstatus !== 0 || !frm.doc.update_stock)
+			return;
+
+		frm.add_custom_button(__('Make Stock Entry'), function() {
+			frappe.call({
+				method: 'erpnext.healthcare.doctype.inpatient_medication_entry.inpatient_medication_entry.make_difference_stock_entry',
+				args: {	docname: frm.doc.name },
+				freeze: true,
+				callback: function(r) {
+					if (r.message) {
+						var doclist = frappe.model.sync(r.message);
+						frappe.set_route('Form', doclist[0].doctype, doclist[0].name);
+					} else {
+						frappe.msgprint({
+							title: __('No Drug Shortage'),
+							message: __('All the drugs are available with sufficient qty to process this Inpatient Medication Entry.'),
+							indicator: 'green'
+						});
+					}
+				}
+			});
+		});
 	},
 
 	patient: function(frm) {
diff --git a/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.py b/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.py
index 5dac23a..70ae713 100644
--- a/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.py
+++ b/erpnext/healthcare/doctype/inpatient_medication_entry/inpatient_medication_entry.py
@@ -142,25 +142,32 @@
 		return orders, order_entry_map
 
 	def check_stock_qty(self):
-		from erpnext.stock.stock_ledger import NegativeStockError
+		drug_shortage = get_drug_shortage_map(self.medication_orders, self.warehouse)
 
-		drug_availability = dict()
-		for d in self.medication_orders:
-			if not drug_availability.get(d.drug_code):
-				drug_availability[d.drug_code] = 0
-			drug_availability[d.drug_code] += flt(d.dosage)
+		if drug_shortage:
+			message = _('Quantity not available for the following items in warehouse {0}. ').format(frappe.bold(self.warehouse))
+			message += _('Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.')
 
-		for drug, dosage in drug_availability.items():
-			available_qty = get_latest_stock_qty(drug, self.warehouse)
+			formatted_item_rows = ''
 
-			# validate qty
-			if flt(available_qty) < flt(dosage):
-				frappe.throw(_('Quantity not available for {0} in warehouse {1}').format(
-					frappe.bold(drug), frappe.bold(self.warehouse))
-					+ '<br><br>' + _('Available quantity is {0}, you need {1}').format(
-					frappe.bold(available_qty), frappe.bold(dosage))
-					+ '<br><br>' + _('Please enable Allow Negative Stock in Stock Settings or create Stock Entry to proceed.'),
-					NegativeStockError, title=_('Insufficient Stock'))
+			for drug, shortage_qty in drug_shortage.items():
+				item_link = get_link_to_form('Item', drug)
+				formatted_item_rows += """
+					<td>{0}</td>
+					<td>{1}</td>
+				</tr>""".format(item_link, frappe.bold(shortage_qty))
+
+			message += """
+				<table class='table'>
+					<thead>
+						<th>{0}</th>
+						<th>{1}</th>
+					</thead>
+					{2}
+				</table>
+			""".format(_('Drug Code'), _('Shortage Qty'), formatted_item_rows)
+
+			frappe.throw(message, title=_('Insufficient Stock'), is_minimizable=True, wide=True)
 
 	def make_stock_entry(self):
 		stock_entry = frappe.new_doc('Stock Entry')
@@ -223,7 +230,8 @@
 
 	for doc in data:
 		inpatient_record = doc.inpatient_record
-		doc['service_unit'] = get_current_healthcare_service_unit(inpatient_record)
+		if inpatient_record:
+			doc['service_unit'] = get_current_healthcare_service_unit(inpatient_record)
 
 		if entry.service_unit and doc.service_unit != entry.service_unit:
 			to_remove.append(doc)
@@ -276,4 +284,55 @@
 	ip_record = frappe.get_doc('Inpatient Record', inpatient_record)
 	if ip_record.inpatient_occupancies:
 		return ip_record.inpatient_occupancies[-1].service_unit
-	return
\ No newline at end of file
+	return
+
+
+def get_drug_shortage_map(medication_orders, warehouse):
+	"""
+		Returns a dict like { drug_code: shortage_qty }
+	"""
+	drug_requirement = dict()
+	for d in medication_orders:
+		if not drug_requirement.get(d.drug_code):
+			drug_requirement[d.drug_code] = 0
+		drug_requirement[d.drug_code] += flt(d.dosage)
+
+	drug_shortage = dict()
+	for drug, required_qty in drug_requirement.items():
+		available_qty = get_latest_stock_qty(drug, warehouse)
+		if flt(required_qty) > flt(available_qty):
+			drug_shortage[drug] = flt(flt(required_qty) - flt(available_qty))
+
+	return drug_shortage
+
+
+@frappe.whitelist()
+def make_difference_stock_entry(docname):
+	doc = frappe.get_doc('Inpatient Medication Entry', docname)
+	drug_shortage = get_drug_shortage_map(doc.medication_orders, doc.warehouse)
+
+	if not drug_shortage:
+		return None
+
+	stock_entry = frappe.new_doc('Stock Entry')
+	stock_entry.purpose = 'Material Transfer'
+	stock_entry.set_stock_entry_type()
+	stock_entry.to_warehouse = doc.warehouse
+	stock_entry.company = doc.company
+	cost_center = frappe.get_cached_value('Company',  doc.company,  'cost_center')
+	expense_account = get_account(None, 'expense_account', 'Healthcare Settings', doc.company)
+
+	for drug, shortage_qty in drug_shortage.items():
+		se_child = stock_entry.append('items')
+		se_child.item_code = drug
+		se_child.item_name = frappe.db.get_value('Item', drug, 'stock_uom')
+		se_child.uom = frappe.db.get_value('Item', drug, 'stock_uom')
+		se_child.stock_uom = se_child.uom
+		se_child.qty = flt(shortage_qty)
+		se_child.t_warehouse = doc.warehouse
+		# in stock uom
+		se_child.conversion_factor = 1
+		se_child.cost_center = cost_center
+		se_child.expense_account = expense_account
+
+	return stock_entry
diff --git a/erpnext/healthcare/doctype/inpatient_medication_entry/test_inpatient_medication_entry.py b/erpnext/healthcare/doctype/inpatient_medication_entry/test_inpatient_medication_entry.py
index 2f1bb6b..7cb5a48 100644
--- a/erpnext/healthcare/doctype/inpatient_medication_entry/test_inpatient_medication_entry.py
+++ b/erpnext/healthcare/doctype/inpatient_medication_entry/test_inpatient_medication_entry.py
@@ -9,6 +9,7 @@
 from erpnext.healthcare.doctype.inpatient_record.test_inpatient_record import create_patient, create_inpatient, get_healthcare_service_unit, mark_invoiced_inpatient_occupancy
 from erpnext.healthcare.doctype.inpatient_record.inpatient_record import admit_patient, discharge_patient, schedule_discharge
 from erpnext.healthcare.doctype.inpatient_medication_order.test_inpatient_medication_order import create_ipmo, create_ipme
+from erpnext.healthcare.doctype.inpatient_medication_entry.inpatient_medication_entry import get_drug_shortage_map, make_difference_stock_entry
 from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_account
 
 class TestInpatientMedicationEntry(unittest.TestCase):
@@ -82,6 +83,39 @@
 		self.assertEqual(stock_entry.items[0].patient, self.patient)
 		self.assertEqual(stock_entry.items[0].inpatient_medication_entry_child, ipme.medication_orders[0].name)
 
+	def test_drug_shortage_stock_entry(self):
+		ipmo = create_ipmo(self.patient)
+		ipmo.submit()
+		ipmo.reload()
+
+		date = add_days(getdate(), -1)
+		filters = frappe._dict(
+			from_date=date,
+			to_date=date,
+			from_time='',
+			to_time='',
+			item_code='Dextromethorphan',
+			patient=self.patient
+		)
+
+		# check drug shortage
+		ipme = create_ipme(filters, update_stock=1)
+		ipme.warehouse = 'Finished Goods - _TC'
+		ipme.save()
+		drug_shortage = get_drug_shortage_map(ipme.medication_orders, ipme.warehouse)
+		self.assertEqual(drug_shortage.get('Dextromethorphan'), 3)
+
+		# check material transfer for drug shortage
+		make_stock_entry()
+		stock_entry = make_difference_stock_entry(ipme.name)
+		self.assertEqual(stock_entry.items[0].item_code, 'Dextromethorphan')
+		self.assertEqual(stock_entry.items[0].qty, 3)
+		stock_entry.from_warehouse = 'Stores - _TC'
+		stock_entry.submit()
+
+		ipme.reload()
+		ipme.submit()
+
 	def tearDown(self):
 		# cleanup - Discharge
 		schedule_discharge(frappe.as_json({'patient': self.patient}))
@@ -94,15 +128,12 @@
 		for entry in frappe.get_all('Inpatient Medication Entry'):
 			doc = frappe.get_doc('Inpatient Medication Entry', entry.name)
 			doc.cancel()
-			frappe.db.delete('Stock Entry', {'inpatient_medication_entry': doc.name})
-			doc.delete()
 
 		for entry in frappe.get_all('Inpatient Medication Order'):
 			doc = frappe.get_doc('Inpatient Medication Order', entry.name)
 			doc.cancel()
-			doc.delete()
 
-def make_stock_entry():
+def make_stock_entry(warehouse=None):
 	frappe.db.set_value('Company', '_Test Company', {
 		'stock_adjustment_account': 'Stock Adjustment - _TC',
 		'default_inventory_account': 'Stock In Hand - _TC'
@@ -110,7 +141,7 @@
 	stock_entry = frappe.new_doc('Stock Entry')
 	stock_entry.stock_entry_type = 'Material Receipt'
 	stock_entry.company = '_Test Company'
-	stock_entry.to_warehouse = 'Stores - _TC'
+	stock_entry.to_warehouse = warehouse or 'Stores - _TC'
 	expense_account = get_account(None, 'expense_account', 'Healthcare Settings', '_Test Company')
 	se_child = stock_entry.append('items')
 	se_child.item_code = 'Dextromethorphan'
diff --git a/erpnext/healthcare/doctype/patient/patient_dashboard.py b/erpnext/healthcare/doctype/patient/patient_dashboard.py
index e3def72..39603f7 100644
--- a/erpnext/healthcare/doctype/patient/patient_dashboard.py
+++ b/erpnext/healthcare/doctype/patient/patient_dashboard.py
@@ -18,6 +18,10 @@
 			{
 				'label': _('Billing'),
 				'items': ['Sales Invoice']
+			},
+			{
+				'label': _('Orders'),
+				'items': ['Inpatient Medication Order']
 			}
 		]
 	}