Merge pull request #27240 from ankush/ubuntu_ci

ci: switch to latest LTS Ubuntu version
diff --git a/.github/workflows/patch.yml b/.github/workflows/patch.yml
index e654481..92a1962 100644
--- a/.github/workflows/patch.yml
+++ b/.github/workflows/patch.yml
@@ -7,6 +7,9 @@
       - '**.md'
   workflow_dispatch:
 
+concurrency:
+  group: patch-develop-${{ github.event.number }}
+  cancel-in-progress: true
 
 jobs:
   test:
diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml
index 7af0d02..71e9c2c 100644
--- a/.github/workflows/server-tests.yml
+++ b/.github/workflows/server-tests.yml
@@ -12,6 +12,10 @@
       - '**.js'
       - '**.md'
 
+concurrency:
+  group: server-develop-${{ github.event.number }}
+  cancel-in-progress: true
+
 jobs:
   test:
     runs-on: ubuntu-latest
diff --git a/.github/workflows/ui-tests.yml b/.github/workflows/ui-tests.yml
index 3520f5c..658892c 100644
--- a/.github/workflows/ui-tests.yml
+++ b/.github/workflows/ui-tests.yml
@@ -6,6 +6,10 @@
       - '**.md'
   workflow_dispatch:
 
+concurrency:
+  group: ui-develop-${{ github.event.number }}
+  cancel-in-progress: true
+
 jobs:
   test:
     runs-on: ubuntu-latest
diff --git a/cypress/integration/test_organizational_chart_desktop.js b/cypress/integration/test_organizational_chart_desktop.js
index 820a23a..39b00d3 100644
--- a/cypress/integration/test_organizational_chart_desktop.js
+++ b/cypress/integration/test_organizational_chart_desktop.js
@@ -2,8 +2,11 @@
 	before(() => {
 		cy.login();
 		cy.visit('/app/website');
+	});
+
+	it('navigates to org chart', () => {
+		cy.visit('/app');
 		cy.awesomebar('Organizational Chart');
-		cy.wait(500);
 		cy.url().should('include', '/organizational-chart');
 
 		cy.window().its('frappe.csrf_token').then(csrf_token => {
diff --git a/cypress/integration/test_organizational_chart_mobile.js b/cypress/integration/test_organizational_chart_mobile.js
index df90dbf..6e75151 100644
--- a/cypress/integration/test_organizational_chart_mobile.js
+++ b/cypress/integration/test_organizational_chart_mobile.js
@@ -1,9 +1,14 @@
 context('Organizational Chart Mobile', () => {
 	before(() => {
 		cy.login();
-		cy.viewport(375, 667);
 		cy.visit('/app/website');
+	});
+
+	it('navigates to org chart', () => {
+		cy.viewport(375, 667);
+		cy.visit('/app');
 		cy.awesomebar('Organizational Chart');
+		cy.url().should('include', '/organizational-chart');
 
 		cy.window().its('frappe.csrf_token').then(csrf_token => {
 			return cy.request({
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index 7264875..dc341d7 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -66,6 +66,7 @@
 		self.update_expense_claim()
 		self.update_inter_company_jv()
 		self.update_invoice_discounting()
+		self.update_status_for_full_and_final_statement()
 		check_if_stock_and_account_balance_synced(self.posting_date,
 			self.company, self.doctype, self.name)
 
@@ -83,6 +84,7 @@
 		self.unlink_inter_company_jv()
 		self.unlink_asset_adjustment_entry()
 		self.update_invoice_discounting()
+		self.update_status_for_full_and_final_statement()
 
 	def get_title(self):
 		return self.pay_to_recd_from or self.accounts[0].account
@@ -98,6 +100,15 @@
 			for voucher_no in list(set(order_list)):
 				frappe.get_doc(voucher_type, voucher_no).set_total_advance_paid()
 
+	def update_status_for_full_and_final_statement(self):
+		for entry in self.accounts:
+			if entry.reference_type == "Full and Final Statement":
+				if self.docstatus == 1:
+					frappe.db.set_value("Full and Final Statement", entry.reference_name, "status", "Paid")
+				elif self.docstatus == 2:
+					frappe.db.set_value("Full and Final Statement", entry.reference_name, "status", "Unpaid")
+
+
 	def validate_inter_company_accounts(self):
 		if self.voucher_type == "Inter Company Journal Entry" and self.inter_company_journal_entry_reference:
 			doc = frappe.get_doc("Journal Entry", self.inter_company_journal_entry_reference)
diff --git a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
index a89fefd..dff883a 100644
--- a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
+++ b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
@@ -202,7 +202,7 @@
    "fieldname": "reference_type",
    "fieldtype": "Select",
    "label": "Reference Type",
-   "options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nLoan\nPayroll Entry\nEmployee Advance\nExchange Rate Revaluation\nInvoice Discounting\nFees"
+   "options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nLoan\nPayroll Entry\nEmployee Advance\nExchange Rate Revaluation\nInvoice Discounting\nFees\nFull and Final Statement"
   },
   {
    "fieldname": "reference_name",
@@ -280,7 +280,7 @@
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-06-26 14:06:54.833738",
+ "modified": "2021-08-30 21:27:32.200299",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Journal Entry Account",
diff --git a/erpnext/buying/doctype/supplier/supplier.js b/erpnext/buying/doctype/supplier/supplier.js
index 1766c2c..7ee9196 100644
--- a/erpnext/buying/doctype/supplier/supplier.js
+++ b/erpnext/buying/doctype/supplier/supplier.js
@@ -24,7 +24,26 @@
 				}
 			}
 		});
+
+		frm.set_query("supplier_primary_contact", function(doc) {
+			return {
+				query: "erpnext.buying.doctype.supplier.supplier.get_supplier_primary_contact",
+				filters: {
+					"supplier": doc.name
+				}
+			};
+		});
+
+		frm.set_query("supplier_primary_address", function(doc) {
+			return {
+				filters: {
+					"link_doctype": "Supplier",
+					"link_name": doc.name
+				}
+			};
+		});
 	},
+
 	refresh: function (frm) {
 		frappe.dynamic_link = { doc: frm.doc, fieldname: 'name', doctype: 'Supplier' }
 
@@ -78,6 +97,30 @@
 		});
 	},
 
+	supplier_primary_address: function(frm) {
+		if (frm.doc.supplier_primary_address) {
+			frappe.call({
+				method: 'frappe.contacts.doctype.address.address.get_address_display',
+				args: {
+					"address_dict": frm.doc.supplier_primary_address
+				},
+				callback: function(r) {
+					frm.set_value("primary_address", r.message);
+				}
+			});
+		}
+		if (!frm.doc.supplier_primary_address) {
+			frm.set_value("primary_address", "");
+		}
+	},
+
+	supplier_primary_contact: function(frm) {
+		if (!frm.doc.supplier_primary_contact) {
+			frm.set_value("mobile_no", "");
+			frm.set_value("email_id", "");
+		}
+	},
+
 	is_internal_supplier: function(frm) {
 		if (frm.doc.is_internal_supplier == 1) {
 			frm.toggle_reqd("represents_company", true);
diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json
index 38b8dfd..c7a5db5 100644
--- a/erpnext/buying/doctype/supplier/supplier.json
+++ b/erpnext/buying/doctype/supplier/supplier.json
@@ -49,6 +49,13 @@
   "address_html",
   "column_break1",
   "contact_html",
+  "primary_address_and_contact_detail_section",
+  "supplier_primary_contact",
+  "mobile_no",
+  "email_id",
+  "column_break_44",
+  "supplier_primary_address",
+  "primary_address",
   "default_payable_accounts",
   "accounts",
   "default_tax_withholding_config",
@@ -378,6 +385,47 @@
    "fieldname": "allow_purchase_invoice_creation_without_purchase_receipt",
    "fieldtype": "Check",
    "label": "Allow Purchase Invoice Creation Without Purchase Receipt"
+  },
+  {
+   "fieldname": "primary_address_and_contact_detail_section",
+   "fieldtype": "Section Break",
+   "label": "Primary Address and Contact Detail"
+  },
+  {
+   "description": "Reselect, if the chosen contact is edited after save",
+   "fieldname": "supplier_primary_contact",
+   "fieldtype": "Link",
+   "label": "Supplier Primary Contact",
+   "options": "Contact"
+  },
+  {
+   "fetch_from": "supplier_primary_contact.mobile_no",
+   "fieldname": "mobile_no",
+   "fieldtype": "Read Only",
+   "label": "Mobile No"
+  },
+  {
+   "fetch_from": "supplier_primary_contact.email_id",
+   "fieldname": "email_id",
+   "fieldtype": "Read Only",
+   "label": "Email Id"
+  },
+  {
+   "fieldname": "column_break_44",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "primary_address",
+   "fieldtype": "Text",
+   "label": "Primary Address",
+   "read_only": 1
+  },
+  {
+   "description": "Reselect, if the chosen address is edited after save",
+   "fieldname": "supplier_primary_address",
+   "fieldtype": "Link",
+   "label": "Supplier Primary Address",
+   "options": "Address"
   }
  ],
  "icon": "fa fa-user",
@@ -390,7 +438,7 @@
    "link_fieldname": "supplier"
   }
  ],
- "modified": "2021-05-18 15:10:11.087191",
+ "modified": "2021-08-27 18:02:44.314077",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Supplier",
diff --git a/erpnext/buying/doctype/supplier/supplier.py b/erpnext/buying/doctype/supplier/supplier.py
index fd16b23..c9750ca 100644
--- a/erpnext/buying/doctype/supplier/supplier.py
+++ b/erpnext/buying/doctype/supplier/supplier.py
@@ -42,7 +42,12 @@
 		if not self.naming_series:
 			self.naming_series = ''
 
+		self.create_primary_contact()
+		self.create_primary_address()
+
 	def validate(self):
+		self.flags.is_new_doc = self.is_new()
+
 		# validation for Naming Series mandatory field...
 		if frappe.defaults.get_global_default('supp_master_name') == 'Naming Series':
 			if not self.naming_series:
@@ -76,7 +81,39 @@
 			frappe.throw(_("Internal Supplier for company {0} already exists").format(
 				frappe.bold(self.represents_company)))
 
+	def create_primary_contact(self):
+		from erpnext.selling.doctype.customer.customer import make_contact
+
+		if not self.supplier_primary_contact:
+			if self.mobile_no or self.email_id:
+				contact = make_contact(self)
+				self.db_set('supplier_primary_contact', contact.name)
+				self.db_set('mobile_no', self.mobile_no)
+				self.db_set('email_id', self.email_id)
+
+	def create_primary_address(self):
+		from erpnext.selling.doctype.customer.customer import make_address
+		from frappe.contacts.doctype.address.address import get_address_display
+
+		if self.flags.is_new_doc and self.get('address_line1'):
+			address = make_address(self)
+			address_display = get_address_display(address.name)
+
+			self.db_set("supplier_primary_address", address.name)
+			self.db_set("primary_address", address_display)
+
 	def on_trash(self):
+		if self.supplier_primary_contact:
+			frappe.db.sql("""
+				UPDATE `tabSupplier`
+				SET
+					supplier_primary_contact=null,
+					supplier_primary_address=null,
+					mobile_no=null,
+					email_id=null,
+					primary_address=null
+				WHERE name=%(name)s""", {"name": self.name})
+
 		delete_contact_and_address('Supplier', self.name)
 
 	def after_rename(self, olddn, newdn, merge=False):
@@ -104,3 +141,21 @@
 							doc.name, args.get('supplier_email_' + str(i)))
 				except frappe.NameError:
 					pass
+
+@frappe.whitelist()
+@frappe.validate_and_sanitize_search_inputs
+def get_supplier_primary_contact(doctype, txt, searchfield, start, page_len, filters):
+	supplier = filters.get("supplier")
+	return frappe.db.sql("""
+		SELECT
+			`tabContact`.name from `tabContact`,
+			`tabDynamic Link`
+		WHERE
+			`tabContact`.name = `tabDynamic Link`.parent
+			and `tabDynamic Link`.link_name = %(supplier)s
+			and `tabDynamic Link`.link_doctype = 'Supplier'
+			and `tabContact`.name like %(txt)s
+		""", {
+			'supplier': supplier,
+			'txt': '%%%s%%' % txt
+		})
diff --git a/erpnext/healthcare/dashboard_chart/clinical_procedures/clinical_procedures.json b/erpnext/healthcare/dashboard_chart/clinical_procedures/clinical_procedures.json
index a59f149..6803528 100644
--- a/erpnext/healthcare/dashboard_chart/clinical_procedures/clinical_procedures.json
+++ b/erpnext/healthcare/dashboard_chart/clinical_procedures/clinical_procedures.json
@@ -12,15 +12,15 @@
  "idx": 0,
  "is_public": 1,
  "is_standard": 1,
- "last_synced_on": "2020-07-22 13:22:47.008622",
- "modified": "2020-07-22 13:36:48.114479",
+ "last_synced_on": "2021-01-30 21:03:30.086891",
+ "modified": "2021-02-01 13:36:04.469863",
  "modified_by": "Administrator",
  "module": "Healthcare",
  "name": "Clinical Procedures",
  "number_of_groups": 0,
  "owner": "Administrator",
  "timeseries": 0,
- "type": "Percentage",
+ "type": "Bar",
  "use_report_chart": 0,
  "y_axis": []
 }
\ No newline at end of file
diff --git a/erpnext/healthcare/dashboard_chart/clinical_procedures_status/clinical_procedures_status.json b/erpnext/healthcare/dashboard_chart/clinical_procedures_status/clinical_procedures_status.json
index 6d560f7..dae9db1 100644
--- a/erpnext/healthcare/dashboard_chart/clinical_procedures_status/clinical_procedures_status.json
+++ b/erpnext/healthcare/dashboard_chart/clinical_procedures_status/clinical_procedures_status.json
@@ -12,15 +12,15 @@
  "idx": 0,
  "is_public": 1,
  "is_standard": 1,
- "last_synced_on": "2020-07-22 13:22:46.691764",
- "modified": "2020-07-22 13:40:17.215775",
+ "last_synced_on": "2021-02-01 13:36:38.787783",
+ "modified": "2021-02-01 13:37:18.718275",
  "modified_by": "Administrator",
  "module": "Healthcare",
  "name": "Clinical Procedures Status",
  "number_of_groups": 0,
  "owner": "Administrator",
  "timeseries": 0,
- "type": "Pie",
+ "type": "Bar",
  "use_report_chart": 0,
  "y_axis": []
 }
\ No newline at end of file
diff --git a/erpnext/healthcare/dashboard_chart/diagnoses/diagnoses.json b/erpnext/healthcare/dashboard_chart/diagnoses/diagnoses.json
index 0195aac..82145d6 100644
--- a/erpnext/healthcare/dashboard_chart/diagnoses/diagnoses.json
+++ b/erpnext/healthcare/dashboard_chart/diagnoses/diagnoses.json
@@ -5,21 +5,22 @@
  "docstatus": 0,
  "doctype": "Dashboard Chart",
  "document_type": "Patient Encounter Diagnosis",
+ "dynamic_filters_json": "",
  "filters_json": "[]",
  "group_by_based_on": "diagnosis",
  "group_by_type": "Count",
  "idx": 0,
  "is_public": 1,
  "is_standard": 1,
- "last_synced_on": "2020-07-22 13:22:47.895521",
- "modified": "2020-07-22 13:43:32.369481",
+ "last_synced_on": "2021-01-30 21:03:33.729487",
+ "modified": "2021-02-01 13:34:57.385335",
  "modified_by": "Administrator",
  "module": "Healthcare",
  "name": "Diagnoses",
  "number_of_groups": 0,
  "owner": "Administrator",
  "timeseries": 0,
- "type": "Percentage",
+ "type": "Bar",
  "use_report_chart": 0,
  "y_axis": []
 }
\ No newline at end of file
diff --git a/erpnext/healthcare/dashboard_chart/lab_tests/lab_tests.json b/erpnext/healthcare/dashboard_chart/lab_tests/lab_tests.json
index 0524835..70293b1 100644
--- a/erpnext/healthcare/dashboard_chart/lab_tests/lab_tests.json
+++ b/erpnext/healthcare/dashboard_chart/lab_tests/lab_tests.json
@@ -12,15 +12,15 @@
  "idx": 0,
  "is_public": 1,
  "is_standard": 1,
- "last_synced_on": "2020-07-22 13:22:47.344055",
- "modified": "2020-07-22 13:37:34.490129",
+ "last_synced_on": "2021-01-30 21:03:28.272914",
+ "modified": "2021-02-01 13:36:08.391433",
  "modified_by": "Administrator",
  "module": "Healthcare",
  "name": "Lab Tests",
  "number_of_groups": 0,
  "owner": "Administrator",
  "timeseries": 0,
- "type": "Percentage",
+ "type": "Bar",
  "use_report_chart": 0,
  "y_axis": []
 }
\ No newline at end of file
diff --git a/erpnext/healthcare/dashboard_chart/symptoms/symptoms.json b/erpnext/healthcare/dashboard_chart/symptoms/symptoms.json
index 8fc86a1..65e5472 100644
--- a/erpnext/healthcare/dashboard_chart/symptoms/symptoms.json
+++ b/erpnext/healthcare/dashboard_chart/symptoms/symptoms.json
@@ -12,15 +12,15 @@
  "idx": 0,
  "is_public": 1,
  "is_standard": 1,
- "last_synced_on": "2020-07-22 13:22:47.296748",
- "modified": "2020-07-22 13:40:59.655129",
+ "last_synced_on": "2021-01-30 21:03:32.067473",
+ "modified": "2021-02-01 13:35:30.953718",
  "modified_by": "Administrator",
  "module": "Healthcare",
  "name": "Symptoms",
  "number_of_groups": 0,
  "owner": "Administrator",
  "timeseries": 0,
- "type": "Percentage",
+ "type": "Bar",
  "use_report_chart": 0,
  "y_axis": []
 }
\ No newline at end of file
diff --git a/erpnext/healthcare/doctype/lab_test/lab_test.py b/erpnext/healthcare/doctype/lab_test/lab_test.py
index 4b57cd0..74495a8 100644
--- a/erpnext/healthcare/doctype/lab_test/lab_test.py
+++ b/erpnext/healthcare/doctype/lab_test/lab_test.py
@@ -34,7 +34,7 @@
 			frappe.db.set_value('Lab Prescription', self.prescription, 'lab_test_created', 1)
 			if frappe.db.get_value('Lab Prescription', self.prescription, 'invoiced'):
 				self.invoiced = True
-		if not self.lab_test_name and self.template:
+		if self.template:
 			self.load_test_from_template()
 			self.reload()
 
@@ -50,7 +50,7 @@
 					item.secondary_uom_result = float(item.result_value) * float(item.conversion_factor)
 				except:
 					item.secondary_uom_result = ''
-					frappe.msgprint(_('Row #{0}: Result for Secondary UOM not calculated'.format(item.idx)), title = _('Warning'))
+					frappe.msgprint(_('Row #{0}: Result for Secondary UOM not calculated').format(item.idx), title = _('Warning'))
 
 	def validate_result_values(self):
 		if self.normal_test_items:
@@ -229,9 +229,9 @@
 			sample_collection = frappe.get_doc('Sample Collection', sample_exists[0][0])
 			quantity = int(sample_collection.sample_qty) + int(template.sample_qty)
 			if template.sample_details:
-				sample_details = sample_collection.sample_details + '\n-\n' + _('Test: ')
+				sample_details = sample_collection.sample_details + '\n-\n' + _('Test :')
 				sample_details += (template.get('lab_test_name') or template.get('template')) +	'\n'
-				sample_details += _('Collection Details: ') + '\n\t' + template.sample_details
+				sample_details += _('Collection Details:') + '\n\t' + template.sample_details
 				frappe.db.set_value('Sample Collection', sample_collection.name, 'sample_details', sample_details)
 
 			frappe.db.set_value('Sample Collection', sample_collection.name, 'sample_qty', quantity)
diff --git a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
index f5477c0..36ef2d1 100644
--- a/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
+++ b/erpnext/healthcare/doctype/patient_appointment/test_patient_appointment.py
@@ -66,7 +66,7 @@
 		medical_department = create_medical_department()
 		frappe.db.set_value('Healthcare Settings', None, 'enable_free_follow_ups', 0)
 		frappe.db.set_value('Healthcare Settings', None, 'automate_appointment_invoicing', 1)
-		appointment_type = create_appointment_type()
+		appointment_type = create_appointment_type({'medical_department': medical_department})
 
 		appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2),
 			invoice=1, appointment_type=appointment_type.name, department=medical_department)
@@ -91,9 +91,9 @@
 				'op_consulting_charge': 300
 		}]
 		appointment_type = create_appointment_type(args={
-				'name': 'Generic Appointment Type charge',
-				'items': items
-			})
+			'name': 'Generic Appointment Type charge',
+			'items': items
+		})
 
 		appointment = create_appointment(patient, practitioner, add_days(nowdate(), 2),
 			invoice=1, appointment_type=appointment_type.name)
@@ -408,9 +408,9 @@
 	else:
 		item = create_healthcare_service_items()
 		items = [{
-				'medical_department': '_Test Medical Department',
-				'op_consulting_charge_item': item,
-				'op_consulting_charge': 200
+			'medical_department': args.get('medical_department') or '_Test Medical Department',
+			'op_consulting_charge_item': item,
+			'op_consulting_charge': 200
 		}]
 		return frappe.get_doc({
 			'doctype': 'Appointment Type',
diff --git a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py b/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py
index 63b0085..9e0d3c3 100644
--- a/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py
+++ b/erpnext/healthcare/doctype/patient_history_settings/patient_history_settings.py
@@ -18,7 +18,7 @@
 	def validate_submittable_doctypes(self):
 		for entry in self.custom_doctypes:
 			if not cint(frappe.db.get_value('DocType', entry.document_type, 'is_submittable')):
-				msg = _('Row #{0}: Document Type {1} is not submittable. ').format(
+				msg = _('Row #{0}: Document Type {1} is not submittable.').format(
 					entry.idx, frappe.bold(entry.document_type))
 				msg += _('Patient Medical Record can only be created for submittable document types.')
 				frappe.throw(msg)
@@ -116,12 +116,12 @@
 		fieldname = entry.get('fieldname')
 		if entry.get('fieldtype') == 'Table' and doc.get(fieldname):
 			formatted_value = get_formatted_value_for_table_field(doc.get(fieldname), meta.get_field(fieldname))
-			subject += frappe.bold(_(entry.get('label')) + ': ') + '<br>' + cstr(formatted_value) + '<br>'
+			subject += frappe.bold(_(entry.get('label')) + ':') + '<br>' + cstr(formatted_value) + '<br>'
 
 		else:
 			if doc.get(fieldname):
 				formatted_value = format_value(doc.get(fieldname), meta.get_field(fieldname), doc)
-				subject += frappe.bold(_(entry.get('label')) + ': ') + cstr(formatted_value) + '<br>'
+				subject += frappe.bold(_(entry.get('label')) + ':') + cstr(formatted_value) + '<br>'
 
 	return subject
 
diff --git a/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py b/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py
index 33119d8..9169ea6 100644
--- a/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py
+++ b/erpnext/healthcare/doctype/patient_history_settings/test_patient_history_settings.py
@@ -38,13 +38,12 @@
 		# tests for medical record creation of standard doctypes in test_patient_medical_record.py
 		patient = create_patient()
 		doc = create_doc(patient)
-
 		# check for medical record
 		medical_rec = frappe.db.exists("Patient Medical Record", {"status": "Open", "reference_name": doc.name})
 		self.assertTrue(medical_rec)
 
 		medical_rec = frappe.get_doc("Patient Medical Record", medical_rec)
-		expected_subject = "Date: {0}Rating: 3Feedback: Test Patient History Settings".format(
+		expected_subject = "Date:{0}Rating:3Feedback:Test Patient History Settings".format(
 			frappe.utils.format_date(getdate()))
 		self.assertEqual(strip_html(medical_rec.subject), expected_subject)
 		self.assertEqual(medical_rec.patient, patient)
diff --git a/erpnext/healthcare/module_onboarding/healthcare/healthcare.json b/erpnext/healthcare/module_onboarding/healthcare/healthcare.json
index 56c3c13..0aa8f9a 100644
--- a/erpnext/healthcare/module_onboarding/healthcare/healthcare.json
+++ b/erpnext/healthcare/module_onboarding/healthcare/healthcare.json
@@ -10,7 +10,7 @@
  "documentation_url": "https://docs.erpnext.com/docs/user/manual/en/healthcare",
  "idx": 0,
  "is_complete": 0,
- "modified": "2020-07-08 14:06:19.512946",
+ "modified": "2021-01-30 19:22:20.273766",
  "modified_by": "Administrator",
  "module": "Healthcare",
  "name": "Healthcare",
diff --git a/erpnext/healthcare/onboarding_step/create_healthcare_practitioner/create_healthcare_practitioner.json b/erpnext/healthcare/onboarding_step/create_healthcare_practitioner/create_healthcare_practitioner.json
index c45a347..3f25a9d 100644
--- a/erpnext/healthcare/onboarding_step/create_healthcare_practitioner/create_healthcare_practitioner.json
+++ b/erpnext/healthcare/onboarding_step/create_healthcare_practitioner/create_healthcare_practitioner.json
@@ -5,14 +5,14 @@
  "doctype": "Onboarding Step",
  "idx": 0,
  "is_complete": 0,
- "is_mandatory": 1,
  "is_single": 0,
  "is_skipped": 0,
- "modified": "2020-05-26 23:16:31.965521",
+ "modified": "2021-01-30 12:02:22.849260",
  "modified_by": "Administrator",
  "name": "Create Healthcare Practitioner",
  "owner": "Administrator",
  "reference_document": "Healthcare Practitioner",
+ "show_form_tour": 0,
  "show_full_form": 1,
  "title": "Create Healthcare Practitioner",
  "validate_action": 1
diff --git a/erpnext/healthcare/onboarding_step/create_patient/create_patient.json b/erpnext/healthcare/onboarding_step/create_patient/create_patient.json
index 77bc5bd..b46bb15 100644
--- a/erpnext/healthcare/onboarding_step/create_patient/create_patient.json
+++ b/erpnext/healthcare/onboarding_step/create_patient/create_patient.json
@@ -5,14 +5,14 @@
  "doctype": "Onboarding Step",
  "idx": 0,
  "is_complete": 0,
- "is_mandatory": 1,
  "is_single": 0,
  "is_skipped": 0,
- "modified": "2020-05-19 12:26:24.023418",
- "modified_by": "Administrator",
+ "modified": "2021-01-30 00:09:28.786428",
+ "modified_by": "ruchamahabal2@gmail.com",
  "name": "Create Patient",
  "owner": "Administrator",
  "reference_document": "Patient",
+ "show_form_tour": 0,
  "show_full_form": 1,
  "title": "Create Patient",
  "validate_action": 1
diff --git a/erpnext/healthcare/onboarding_step/create_practitioner_schedule/create_practitioner_schedule.json b/erpnext/healthcare/onboarding_step/create_practitioner_schedule/create_practitioner_schedule.json
index 65980ef..7ce122d 100644
--- a/erpnext/healthcare/onboarding_step/create_practitioner_schedule/create_practitioner_schedule.json
+++ b/erpnext/healthcare/onboarding_step/create_practitioner_schedule/create_practitioner_schedule.json
@@ -5,14 +5,14 @@
  "doctype": "Onboarding Step",
  "idx": 0,
  "is_complete": 0,
- "is_mandatory": 1,
  "is_single": 0,
  "is_skipped": 0,
- "modified": "2020-05-19 12:27:09.437825",
- "modified_by": "Administrator",
+ "modified": "2021-01-30 00:09:28.794602",
+ "modified_by": "ruchamahabal2@gmail.com",
  "name": "Create Practitioner Schedule",
  "owner": "Administrator",
  "reference_document": "Practitioner Schedule",
+ "show_form_tour": 0,
  "show_full_form": 1,
  "title": "Create Practitioner Schedule",
  "validate_action": 1
diff --git a/erpnext/healthcare/onboarding_step/explore_clinical_procedure_templates/explore_clinical_procedure_templates.json b/erpnext/healthcare/onboarding_step/explore_clinical_procedure_templates/explore_clinical_procedure_templates.json
index 697b761..dfe9f71 100644
--- a/erpnext/healthcare/onboarding_step/explore_clinical_procedure_templates/explore_clinical_procedure_templates.json
+++ b/erpnext/healthcare/onboarding_step/explore_clinical_procedure_templates/explore_clinical_procedure_templates.json
@@ -5,14 +5,14 @@
  "doctype": "Onboarding Step",
  "idx": 0,
  "is_complete": 0,
- "is_mandatory": 0,
  "is_single": 0,
  "is_skipped": 0,
- "modified": "2020-05-26 23:10:24.504030",
+ "modified": "2021-01-30 19:22:08.257160",
  "modified_by": "Administrator",
  "name": "Explore Clinical Procedure Templates",
  "owner": "Administrator",
  "reference_document": "Clinical Procedure Template",
+ "show_form_tour": 0,
  "show_full_form": 0,
  "title": "Explore Clinical Procedure Templates",
  "validate_action": 1
diff --git a/erpnext/healthcare/onboarding_step/explore_healthcare_settings/explore_healthcare_settings.json b/erpnext/healthcare/onboarding_step/explore_healthcare_settings/explore_healthcare_settings.json
index b2d5aef..2d952f3 100644
--- a/erpnext/healthcare/onboarding_step/explore_healthcare_settings/explore_healthcare_settings.json
+++ b/erpnext/healthcare/onboarding_step/explore_healthcare_settings/explore_healthcare_settings.json
@@ -5,14 +5,14 @@
  "doctype": "Onboarding Step",
  "idx": 0,
  "is_complete": 0,
- "is_mandatory": 1,
  "is_single": 1,
  "is_skipped": 0,
- "modified": "2020-05-26 23:10:24.507648",
+ "modified": "2021-01-30 19:22:07.275735",
  "modified_by": "Administrator",
  "name": "Explore Healthcare Settings",
  "owner": "Administrator",
  "reference_document": "Healthcare Settings",
+ "show_form_tour": 0,
  "show_full_form": 0,
  "title": "Explore Healthcare Settings",
  "validate_action": 1
diff --git a/erpnext/healthcare/onboarding_step/introduction_to_healthcare_practitioner/introduction_to_healthcare_practitioner.json b/erpnext/healthcare/onboarding_step/introduction_to_healthcare_practitioner/introduction_to_healthcare_practitioner.json
index fa4c903..baa8358 100644
--- a/erpnext/healthcare/onboarding_step/introduction_to_healthcare_practitioner/introduction_to_healthcare_practitioner.json
+++ b/erpnext/healthcare/onboarding_step/introduction_to_healthcare_practitioner/introduction_to_healthcare_practitioner.json
@@ -6,14 +6,14 @@
  "field": "schedule",
  "idx": 0,
  "is_complete": 0,
- "is_mandatory": 1,
  "is_single": 0,
  "is_skipped": 0,
- "modified": "2020-05-26 22:07:07.482530",
- "modified_by": "Administrator",
+ "modified": "2021-01-30 00:09:28.807129",
+ "modified_by": "ruchamahabal2@gmail.com",
  "name": "Introduction to Healthcare Practitioner",
  "owner": "Administrator",
  "reference_document": "Healthcare Practitioner",
+ "show_form_tour": 0,
  "show_full_form": 0,
  "title": "Introduction to Healthcare Practitioner",
  "validate_action": 0
diff --git a/erpnext/healthcare/page/patient_history/patient_history.css b/erpnext/healthcare/page/patient_history/patient_history.css
index 1bb5891..74b5e7e 100644
--- a/erpnext/healthcare/page/patient_history/patient_history.css
+++ b/erpnext/healthcare/page/patient_history/patient_history.css
@@ -9,6 +9,26 @@
 	cursor: pointer;
 }
 
+.patient-image-container {
+	margin-top: 17px;
+  }
+
+.patient-image {
+	display: inline-block;
+	width: 100%;
+	height: 0;
+	padding: 50% 0px;
+	background-size: cover;
+	background-repeat: no-repeat;
+	background-position: center center;
+	border-radius: 4px;
+}
+
+.patient-name {
+	font-size: 20px;
+	margin-top: 25px;
+}
+
 .medical_record-label {
 	max-width: 100px;
 	margin-bottom: -4px;
@@ -19,19 +39,19 @@
 }
 
 .date-indicator {
-    background:none;
-    font-size:12px;
-    vertical-align:middle;
-    font-weight:bold;
-    color:#6c7680;
+	background:none;
+	font-size:12px;
+	vertical-align:middle;
+	font-weight:bold;
+	color:#6c7680;
 }
 .date-indicator::after {
-    margin:0 -4px 0 12px;
-    content:'';
-    display:inline-block;
-    height:8px;
-    width:8px;
-    border-radius:8px;
+	margin:0 -4px 0 12px;
+	content:'';
+	display:inline-block;
+	height:8px;
+	width:8px;
+	border-radius:8px;
 	background: #d1d8dd;
 }
 
diff --git a/erpnext/healthcare/page/patient_history/patient_history.html b/erpnext/healthcare/page/patient_history/patient_history.html
index f170655..d16b386 100644
--- a/erpnext/healthcare/page/patient_history/patient_history.html
+++ b/erpnext/healthcare/page/patient_history/patient_history.html
@@ -1,26 +1,18 @@
-<div class="col-sm-12">
-	<div class="col-sm-3">
-	<p class="patient" style="margin: auto; max-width: 300px; margin-bottom: 20px;"></p>
-	<div class="patient_details" style="z-index=0"></div>
+<div class="row patient-documents">
+	<div class="col-sm-12">
+		<div class="col-sm-12 show_chart_btns" align="center">
+		</div>
+		<div id="chart" class="col-sm-12 patient_vital_charts">
+		</div>
 	</div>
-	<div class="col-sm-9 patient_documents">
-		<div class="col-sm-12">
-			<div class="col-sm-12 show_chart_btns" align="center">
-			</div>
-			<div id="chart" class="col-sm-12 patient_vital_charts">
-			</div>
-		</div>
-		<div class="header-separator col-sm-12 d-flex border-bottom py-3" style="display:none"></div>
-		<div class="row">
-			<div class="col-sm-12 d-flex">
-				<div class="patient-history-filter doctype-filter"></div>
-				<div class="patient-history-filter date-filter"></div>
-			</div>
-		</div>
-		<div class="col-sm-12 patient_documents_list">
-		</div>
-		<div class="col-sm-12 text-center py-3">
-			<a class="btn btn-sm btn-default btn-get-records" style="display:none">More..</a>
-		</div>
+	<div class="header-separator col-sm-12 d-flex border-bottom py-3" style="display:none"></div>
+	<div class="col-sm-12 d-flex">
+		<div class="patient-history-filter doctype-filter"></div>
+		<div class="patient-history-filter date-filter"></div>
+	</div>
+	<div class="col-sm-12 patient_documents_list">
+	</div>
+	<div class="col-sm-12 text-center py-3">
+		<a class="btn btn-sm btn-default btn-get-records" style="display:none">More..</a>
 	</div>
 </div>
diff --git a/erpnext/healthcare/page/patient_history/patient_history.js b/erpnext/healthcare/page/patient_history/patient_history.js
index 54343aa..bf947ca 100644
--- a/erpnext/healthcare/page/patient_history/patient_history.js
+++ b/erpnext/healthcare/page/patient_history/patient_history.js
@@ -1,403 +1,455 @@
 frappe.provide('frappe.patient_history');
 frappe.pages['patient_history'].on_page_load = function(wrapper) {
-	let me = this;
-	let page = frappe.ui.make_app_page({
+	frappe.ui.make_app_page({
 		parent: wrapper,
-		title: 'Patient History',
-		single_column: true
+		title: __('Patient History')
 	});
 
-	frappe.breadcrumbs.add('Healthcare');
-	let pid = '';
-	page.main.html(frappe.render_template('patient_history', {}));
-	page.main.find('.header-separator').hide();
-
-	let patient = frappe.ui.form.make_control({
-		parent: page.main.find('.patient'),
-		df: {
-			fieldtype: 'Link',
-			options: 'Patient',
-			fieldname: 'patient',
-			placeholder: __('Select Patient'),
-			only_select: true,
-			change: function() {
-				let patient_id = patient.get_value();
-				if (pid != patient_id && patient_id) {
-					me.start = 0;
-					me.page.main.find('.patient_documents_list').html('');
-					setup_filters(patient_id, me);
-					get_documents(patient_id, me);
-					show_patient_info(patient_id, me);
-					show_patient_vital_charts(patient_id, me, 'bp', 'mmHg', 'Blood Pressure');
-				}
-				pid = patient_id;
-			}
-		},
-	});
-	patient.refresh();
-
-	if (frappe.route_options) {
-		patient.set_value(frappe.route_options.patient);
-	}
-
-	this.page.main.on('click', '.btn-show-chart', function() {
-		let	btn_show_id = $(this).attr('data-show-chart-id'), pts = $(this).attr('data-pts');
-		let title = $(this).attr('data-title');
-		show_patient_vital_charts(patient.get_value(), me, btn_show_id, pts, title);
-	});
-
-	this.page.main.on('click', '.btn-more', function() {
-		let	doctype = $(this).attr('data-doctype'), docname = $(this).attr('data-docname');
-		if (me.page.main.find('.'+docname).parent().find('.document-html').attr('data-fetched') == '1') {
-			me.page.main.find('.'+docname).hide();
-			me.page.main.find('.'+docname).parent().find('.document-html').show();
-		} else {
-			if (doctype && docname) {
-				let exclude = ['patient', 'patient_name', 'patient_sex', 'encounter_date'];
-				frappe.call({
-					method: 'erpnext.healthcare.utils.render_doc_as_html',
-					args:{
-						doctype: doctype,
-						docname: docname,
-						exclude_fields: exclude
-					},
-					freeze: true,
-					callback: function(r) {
-						if (r.message) {
-							me.page.main.find('.' + docname).hide();
-
-							me.page.main.find('.' + docname).parent().find('.document-html').html(
-								`${r.message.html}
-									<div align='center'>
-										<a class='btn octicon octicon-chevron-up btn-default btn-xs btn-less'
-											data-doctype='${doctype}'
-											data-docname='${docname}'>
-										</a>
-									</div>
-								`);
-
-							me.page.main.find('.' + docname).parent().find('.document-html').show();
-							me.page.main.find('.' + docname).parent().find('.document-html').attr('data-fetched', '1');
-						}
-					}
-				});
-			}
-		}
-	});
-
-	this.page.main.on('click', '.btn-less', function() {
-		let docname = $(this).attr('data-docname');
-		me.page.main.find('.' + docname).parent().find('.document-id').show();
-		me.page.main.find('.' + docname).parent().find('.document-html').hide();
-	});
-	me.start = 0;
-	me.page.main.on('click', '.btn-get-records', function() {
-		get_documents(patient.get_value(), me);
+	let patient_history = new PatientHistory(wrapper);
+	$(wrapper).bind('show', ()=> {
+		patient_history.show();
 	});
 };
 
-let setup_filters = function(patient, me) {
-	$('.doctype-filter').empty();
-	frappe.xcall(
-		'erpnext.healthcare.page.patient_history.patient_history.get_patient_history_doctypes'
-	).then(document_types => {
-		let doctype_filter = frappe.ui.form.make_control({
-			parent: $('.doctype-filter'),
+class PatientHistory {
+	constructor(wrapper) {
+		this.wrapper = $(wrapper);
+		this.page = wrapper.page;
+		this.sidebar = this.wrapper.find('.layout-side-section');
+		this.main_section = this.wrapper.find('.layout-main-section');
+		this.start = 0;
+	}
+
+	show() {
+		frappe.breadcrumbs.add('Healthcare');
+		this.sidebar.empty();
+
+		let me = this;
+		let patient = frappe.ui.form.make_control({
+			parent: me.sidebar,
 			df: {
-				fieldtype: 'MultiSelectList',
-				fieldname: 'document_type',
-				placeholder: __('Select Document Type'),
-				input_class: 'input-xs',
+				fieldtype: 'Link',
+				options: 'Patient',
+				fieldname: 'patient',
+				placeholder: __('Select Patient'),
+				only_select: true,
 				change: () => {
-					me.start = 0;
-					me.page.main.find('.patient_documents_list').html('');
-					get_documents(patient, me, doctype_filter.get_value(), date_range_field.get_value());
-				},
-				get_data: () => {
-					return document_types.map(document_type => {
-						return {
-							description: document_type,
-							value: document_type
-						};
-					});
-				},
+					me.patient_id = '';
+					if (me.patient_id != patient.get_value() && patient.get_value()) {
+						me.start = 0;
+						me.patient_id = patient.get_value();
+						me.make_patient_profile();
+					}
+				}
 			}
 		});
-		doctype_filter.refresh();
+		patient.refresh();
 
-		$('.date-filter').empty();
-		let date_range_field = frappe.ui.form.make_control({
-			df: {
-				fieldtype: 'DateRange',
-				fieldname: 'date_range',
-				placeholder: __('Date Range'),
-				input_class: 'input-xs',
-				change: () => {
-					let selected_date_range = date_range_field.get_value();
-					if (selected_date_range && selected_date_range.length === 2) {
+		if (frappe.route_options && !this.patient_id) {
+			patient.set_value(frappe.route_options.patient);
+			this.patient_id = frappe.route_options.patient;
+		}
+
+		this.sidebar.find('[data-fieldname="patient"]').append('<div class="patient-info"></div>');
+	}
+
+	make_patient_profile() {
+		this.page.set_title(__('Patient History'));
+		this.main_section.empty().append(frappe.render_template('patient_history'));
+		this.setup_filters();
+		this.setup_documents();
+		this.show_patient_info();
+		this.setup_buttons();
+		this.show_patient_vital_charts('bp', 'mmHg', 'Blood Pressure');
+	}
+
+	setup_filters() {
+		$('.doctype-filter').empty();
+		let me = this;
+
+		frappe.xcall(
+			'erpnext.healthcare.page.patient_history.patient_history.get_patient_history_doctypes'
+		).then(document_types => {
+			let doctype_filter = frappe.ui.form.make_control({
+				parent: $('.doctype-filter'),
+				df: {
+					fieldtype: 'MultiSelectList',
+					fieldname: 'document_type',
+					placeholder: __('Select Document Type'),
+					change: () => {
 						me.start = 0;
 						me.page.main.find('.patient_documents_list').html('');
-						get_documents(patient, me, doctype_filter.get_value(), selected_date_range);
-					}
+						this.setup_documents(doctype_filter.get_value(), date_range_field.get_value());
+					},
+					get_data: () => {
+						return document_types.map(document_type => {
+							return {
+								description: document_type,
+								value: document_type
+							};
+						});
+					},
 				}
-			},
-			parent: $('.date-filter')
+			});
+			doctype_filter.refresh();
+
+			$('.date-filter').empty();
+			let date_range_field = frappe.ui.form.make_control({
+				df: {
+					fieldtype: 'DateRange',
+					fieldname: 'date_range',
+					placeholder: __('Date Range'),
+					input_class: 'input-xs',
+					change: () => {
+						let selected_date_range = date_range_field.get_value();
+						if (selected_date_range && selected_date_range.length === 2) {
+							me.start = 0;
+							me.page.main.find('.patient_documents_list').html('');
+							this.setup_documents(doctype_filter.get_value(), date_range_field.get_value());
+						}
+					}
+				},
+				parent: $('.date-filter')
+			});
+			date_range_field.refresh();
 		});
-		date_range_field.refresh();
-	});
-};
+	}
 
-let get_documents = function(patient, me, document_types="", selected_date_range="") {
-	let filters = {
-		name: patient,
-		start: me.start,
-		page_length: 20
-	};
-	if (document_types)
-		filters['document_types'] = document_types;
-	if (selected_date_range)
-		filters['date_range'] = selected_date_range;
+	setup_documents(document_types="", selected_date_range="") {
+		let filters = {
+			name: this.patient_id,
+			start: this.start,
+			page_length: 20
+		};
+		if (document_types)
+			filters['document_types'] = document_types;
+		if (selected_date_range)
+			filters['date_range'] = selected_date_range;
 
-	frappe.call({
-		'method': 'erpnext.healthcare.page.patient_history.patient_history.get_feed',
-		args: filters,
-		callback: function(r) {
-			let data = r.message;
-			if (data.length) {
-				add_to_records(me, data);
-			} else {
-				me.page.main.find('.patient_documents_list').append(`
-					<div class='text-muted' align='center'>
-						<br><br>${__('No more records..')}<br><br>
-					</div>`);
-				me.page.main.find('.btn-get-records').hide();
+		let me = this;
+		frappe.call({
+			'method': 'erpnext.healthcare.page.patient_history.patient_history.get_feed',
+			args: filters,
+			callback: function(r) {
+				let data = r.message;
+				if (data.length) {
+					me.add_to_records(data);
+				} else {
+					me.page.main.find('.patient_documents_list').append(`
+						<div class='text-muted' align='center'>
+							<br><br>${__('No more records..')}<br><br>
+						</div>`);
+					me.page.main.find('.btn-get-records').hide();
+				}
 			}
-		}
-	});
-};
+		});
+	}
 
-let add_to_records = function(me, data) {
-	let details = "<ul class='nav nav-pills nav-stacked'>";
-	let i;
-	for (i=0; i<data.length; i++) {
-		if (data[i].reference_doctype) {
-			let label = '';
-			if (data[i].subject) {
-				label += "<br/>" + data[i].subject;
-			}
-			data[i] = add_date_separator(data[i]);
+	add_to_records(data) {
+		let details = "";
+		let i;
+		for (i=0; i<data.length; i++) {
+			if (data[i].reference_doctype) {
+				let label = '';
+				if (data[i].subject) {
+					label += "<br/>" + data[i].subject;
+				}
+				data[i] = this.add_date_separator(data[i]);
 
-			if (frappe.user_info(data[i].owner).image) {
-				data[i].imgsrc = frappe.utils.get_file_link(frappe.user_info(data[i].owner).image);
-			} else {
-				data[i].imgsrc = false;
-			}
+				if (frappe.user_info(data[i].owner).image) {
+					data[i].imgsrc = frappe.utils.get_file_link(frappe.user_info(data[i].owner).image);
+				} else {
+					data[i].imgsrc = false;
+				}
 
-			let time_line_heading = data[i].practitioner ? `${data[i].practitioner} ` : ``;
-			time_line_heading += data[i].reference_doctype + " - " +
-				`<a onclick="frappe.set_route('Form', '${data[i].reference_doctype}', '${data[i].reference_name}');">
-					${data[i].reference_name}
-				</a>`;
+				let time_line_heading = data[i].practitioner ? `${data[i].practitioner} ` : ``;
+				time_line_heading += data[i].reference_doctype + " - " +
+					`<a onclick="frappe.set_route('Form', '${data[i].reference_doctype}', '${data[i].reference_name}');">
+						${data[i].reference_name}
+					</a>`;
 
-			details += `
-				<li data-toggle='pill' class='patient_doc_menu'
-					data-doctype='${data[i].reference_doctype}' data-docname='${data[i].reference_name}'>
-					<div class='col-sm-12 d-flex border-bottom py-3'>`;
-
-			if (data[i].imgsrc) {
 				details += `
-					<span class='mr-3'>
-						<img class='avtar' src='${data[i].imgsrc}' width='32' height='32'></img>
-					</span>`;
-			} else {
-				details += `<span class='mr-3 avatar avatar-small' style='width:32px; height:32px;'>
-					<div align='center' class='standard-image' style='background-color: #fafbfc;'>
-						${data[i].practitioner ? data[i].practitioner.charAt(0) : 'U'}
-					</div>
-				</span>`;
-			}
+					<div data-toggle='pill' class='patient_doc_menu'
+						data-doctype='${data[i].reference_doctype}' data-docname='${data[i].reference_name}'>
+						<div class='col-sm-12 d-flex border-bottom py-3'>`;
 
-			details += `<div class='d-flex flex-column width-full'>
-					<div>
-						`+time_line_heading+`
-							<span>
-								${data[i].date_sep}
+				if (data[i].imgsrc) {
+					details += `<span class='mr-3 avatar avatar-small' style='width:32px; height:32px;'>
+							<img class='avatar-frame' src='${data[i].imgsrc}' width='32' height='32'></img>
+						</span>`;
+				} else {
+					details += `<span class='mr-3 avatar avatar-small' style='width:32px; height:32px;'>
+						<div align='center' class='avatar-frame' style='background-color: #fafbfc;'>
+							${data[i].practitioner ? data[i].practitioner.charAt(0) : 'U'}
+						</div>
+					</span>`;
+				}
+
+				details += `<div class='d-flex flex-column width-full'>
+						<div>
+							`+time_line_heading+`
+								<span>
+									${data[i].date_sep}
+								</span>
+						</div>
+						<div class='frappe-card p-5 mt-3'>
+							<span class='${data[i].reference_name} document-id'>${label}
+							<br>
+								<div align='center'>
+									<a class='btn octicon octicon-chevron-down btn-default btn-xs btn-more'
+										data-doctype='${data[i].reference_doctype}' data-docname='${data[i].reference_name}'>
+									</a>
+								</div>
 							</span>
-					</div>
-					<div class='Box p-3 mt-2'>
-						<span class='${data[i].reference_name} document-id'>${label}
-							<div align='center'>
-								<a class='btn octicon octicon-chevron-down btn-default btn-xs btn-more'
-									data-doctype='${data[i].reference_doctype}' data-docname='${data[i].reference_name}'>
-								</a>
-							</div>
-						</span>
-						<span class='document-html' hidden  data-fetched="0">
-						</span>
+
+							<span class='document-html' hidden data-fetched='0'>
+							</span>
+						</div>
 					</div>
 				</div>
-			</div>
-			</li>`;
+				</div>`;
+			}
+		}
+
+		this.page.main.find('.patient_documents_list').append(details);
+		this.start += data.length;
+
+		if (data.length === 20) {
+			this.page.main.find(".btn-get-records").show();
+		} else {
+			this.page.main.find(".btn-get-records").hide();
+			this.page.main.find(".patient_documents_list").append(`
+				<div class='text-muted' align='center'>
+					<br><br>${__('No more records..')}<br><br>
+				</div>`);
 		}
 	}
 
-	details += '</ul>';
-	me.page.main.find('.patient_documents_list').append(details);
-	me.start += data.length;
+	add_date_separator(data) {
+		let date = frappe.datetime.str_to_obj(data.communication_date);
+		let pdate = '';
+		let diff = frappe.datetime.get_day_diff(frappe.datetime.get_today(),
+			frappe.datetime.obj_to_str(date));
 
-	if (data.length === 20) {
-		me.page.main.find(".btn-get-records").show();
-	} else {
-		me.page.main.find(".btn-get-records").hide();
-		me.page.main.find(".patient_documents_list").append(`
-			<div class='text-muted' align='center'>
-				<br><br>${__('No more records..')}<br><br>
-			</div>`);
-	}
-};
-
-let add_date_separator = function(data) {
-	let date = frappe.datetime.str_to_obj(data.communication_date);
-	let pdate = '';
-	let diff = frappe.datetime.get_day_diff(frappe.datetime.get_today(), frappe.datetime.obj_to_str(date));
-
-	if (diff < 1) {
-		pdate = __('Today');
-	} else if (diff < 2) {
-		pdate = __('Yesterday');
-	} else {
-		pdate = __('on ') + frappe.datetime.global_date_format(date);
-	}
-	data.date_sep = pdate;
-	return data;
-};
-
-let show_patient_info = function(patient, me) {
-	frappe.call({
-		'method': 'erpnext.healthcare.doctype.patient.patient.get_patient_detail',
-		args: {
-			patient: patient
-		},
-		callback: function(r) {
-			let data = r.message;
-			let details = '';
-			if (data.image) {
-				details += `<div><img class='thumbnail' width=75% src='${data.image}'></div>`;
-			}
-
-			details += `<b> ${data.patient_name} </b><br> ${data.sex}`;
-			if (data.email) details += `<br> ${data.email}`;
-			if (data.mobile) details += `<br> ${data.mobile}`;
-			if (data.occupation) details += `<br><br><b> ${__('Occupation')} : </b> ${data.occupation}`;
-			if (data.blood_group) details += `<br><b> ${__('Blood Group')} : </b> ${data.blood_group}`;
-			if (data.allergies) details +=  `<br><br><b> ${__('Allerigies')} : </b> ${data.allergies.replace("\n", ", ")}`;
-			if (data.medication) details +=  `<br><b> ${__('Medication')} : </b> ${data.medication.replace("\n", ", ")}`;
-			if (data.alcohol_current_use) details +=  `<br><br><b> ${__('Alcohol use')} : </b> ${data.alcohol_current_use}`;
-			if (data.alcohol_past_use) details +=  `<br><b> ${__('Alcohol past use')} : </b> ${data.alcohol_past_use}`;
-			if (data.tobacco_current_use) details +=  `<br><b> ${__('Tobacco use')} : </b> ${data.tobacco_current_use}`;
-			if (data.tobacco_past_use) details +=  `<br><b> ${__('Tobacco past use')} : </b> ${data.tobacco_past_use}`;
-			if (data.medical_history) details +=  `<br><br><b> ${__('Medical history')} : </b> ${data.medical_history.replace("\n", ", ")}`;
-			if (data.surgical_history) details +=  `<br><b> ${__('Surgical history')} : </b> ${data.surgical_history.replace("\n", ", ")}`;
-			if (data.surrounding_factors) details +=  `<br><br><b> ${__('Occupational hazards')} : </b> ${data.surrounding_factors.replace("\n", ", ")}`;
-			if (data.other_risk_factors) details += `<br><b> ${__('Other risk factors')} : </b> ${data.other_risk_factors.replace("\n", ", ")}`;
-			if (data.patient_details) details += `<br><br><b> ${__('More info')} : </b> ${data.patient_details.replace("\n", ", ")}`;
-
-			if (details) {
-				details = `<div style='padding-left:10px; font-size:13px;' align='left'>` + details + `</div>`;
-			}
-			me.page.main.find('.patient_details').html(details);
+		if (diff < 1) {
+			pdate = __('Today');
+		} else if (diff < 2) {
+			pdate = __('Yesterday');
+		} else {
+			pdate = __('on {0}', [frappe.datetime.global_date_format(date)]);
 		}
-	});
-};
+		data.date_sep = pdate;
+		return data;
+	}
 
-let show_patient_vital_charts = function(patient, me, btn_show_id, pts, title) {
-	frappe.call({
-		method: 'erpnext.healthcare.utils.get_patient_vitals',
-		args:{
-			patient: patient
-		},
-		callback: function(r) {
-			if (r.message) {
-				let show_chart_btns_html = `
-					<div style='padding-top:10px;'>
-						<a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='bp' data-pts='mmHg' data-title='Blood Pressure'>
-							${__('Blood Pressure')}
-						</a>
-						<a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='pulse_rate' data-pts='per Minutes' data-title='Respiratory/Pulse Rate'>
-							${__('Respiratory/Pulse Rate')}
-						</a>
-						<a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='temperature' data-pts='°C or °F' data-title='Temperature'>
-							${__('Temperature')}
-						</a>
-						<a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='bmi' data-pts='' data-title='BMI'>
-							${__('BMI')}
-						</a>
-					</div>`;
+	show_patient_info() {
+		this.get_patient_info().then(() => {
+			$('.patient-info').empty().append(frappe.render_template('patient_history_sidebar', {
+				patient_image: this.patient.image,
+				patient_name: this.patient.patient_name,
+				patient_gender: this.patient.sex,
+				patient_mobile: this.patient.mobile
+			}));
+			this.show_patient_details();
+		});
+	}
 
-				me.page.main.find('.show_chart_btns').html(show_chart_btns_html);
+	show_patient_details() {
+		let me = this;
+		frappe.call({
+			'method': 'erpnext.healthcare.doctype.patient.patient.get_patient_detail',
+			args: {
+				patient: me.patient_id
+			},
+			callback: function(r) {
 				let data = r.message;
-				let labels = [], datasets = [];
-				let bp_systolic = [], bp_diastolic = [], temperature = [];
-				let pulse = [], respiratory_rate = [], bmi = [], height = [], weight = [];
+				let details = ``;
 
-				for (let i=0; i<data.length; i++) {
-					labels.push(data[i].signs_date+'||'+data[i].signs_time);
+				if (data.occupation) details += `<br><br><b> ${__('Occupation')} : </b> ${data.occupation}`;
+				if (data.blood_group) details += `<br><b> ${__('Blood Group')} : </b> ${data.blood_group}`;
+				if (data.allergies) details +=  `<br><br><b> ${__('Allerigies')} : </b> ${data.allergies.replace("\n", ", ")}`;
+				if (data.medication) details +=  `<br><b> ${__('Medication')} : </b> ${data.medication.replace("\n", ", ")}`;
+				if (data.alcohol_current_use) details +=  `<br><br><b> ${__('Alcohol use')} : </b> ${data.alcohol_current_use}`;
+				if (data.alcohol_past_use) details +=  `<br><b> ${__('Alcohol past use')} : </b> ${data.alcohol_past_use}`;
+				if (data.tobacco_current_use) details +=  `<br><b> ${__('Tobacco use')} : </b> ${data.tobacco_current_use}`;
+				if (data.tobacco_past_use) details +=  `<br><b> ${__('Tobacco past use')} : </b> ${data.tobacco_past_use}`;
+				if (data.medical_history) details +=  `<br><br><b> ${__('Medical history')} : </b> ${data.medical_history.replace("\n", ", ")}`;
+				if (data.surgical_history) details +=  `<br><b> ${__('Surgical history')} : </b> ${data.surgical_history.replace("\n", ", ")}`;
+				if (data.surrounding_factors) details +=  `<br><br><b> ${__('Occupational hazards')} : </b> ${data.surrounding_factors.replace("\n", ", ")}`;
+				if (data.other_risk_factors) details += `<br><b> ${__('Other risk factors')} : </b> ${data.other_risk_factors.replace("\n", ", ")}`;
+				if (data.patient_details) details += `<br><br><b> ${__('More info')} : </b> ${data.patient_details.replace("\n", ", ")}`;
 
-					if (btn_show_id === 'bp') {
-						bp_systolic.push(data[i].bp_systolic);
-						bp_diastolic.push(data[i].bp_diastolic);
-					}
-					if (btn_show_id === 'temperature') {
-						temperature.push(data[i].temperature);
-					}
-					if (btn_show_id === 'pulse_rate') {
-						pulse.push(data[i].pulse);
-						respiratory_rate.push(data[i].respiratory_rate);
-					}
-					if (btn_show_id === 'bmi') {
-						bmi.push(data[i].bmi);
-						height.push(data[i].height);
-						weight.push(data[i].weight);
-					}
+				if (details) {
+					details = `<div style='font-size:13px;' align='left'>` + details + `</div>`;
 				}
-				if (btn_show_id === 'temperature') {
-					datasets.push({name: 'Temperature', values: temperature, chartType: 'line'});
-				}
-				if (btn_show_id === 'bmi') {
-					datasets.push({name: 'BMI', values: bmi, chartType: 'line'});
-					datasets.push({name: 'Height', values: height, chartType: 'line'});
-					datasets.push({name: 'Weight', values: weight, chartType: 'line'});
-				}
-				if (btn_show_id === 'bp') {
-					datasets.push({name: 'BP Systolic', values: bp_systolic, chartType: 'line'});
-					datasets.push({name: 'BP Diastolic', values: bp_diastolic, chartType: 'line'});
-				}
-				if (btn_show_id === 'pulse_rate') {
-					datasets.push({name: 'Heart Rate / Pulse', values: pulse, chartType: 'line'});
-					datasets.push({name: 'Respiratory Rate', values: respiratory_rate, chartType: 'line'});
-				}
-				new frappe.Chart('.patient_vital_charts', {
-					data: {
-						labels: labels,
-						datasets: datasets
-					},
 
-					title: title,
-					type: 'axis-mixed',
-					height: 200,
-					colors: ['purple', '#ffa3ef', 'light-blue'],
-
-					tooltipOptions: {
-						formatTooltipX: d => (d + '').toUpperCase(),
-						formatTooltipY: d => d + ' ' + pts,
-					}
-				});
-				me.page.main.find('.header-separator').show();
-			} else {
-				me.page.main.find('.patient_vital_charts').html('');
-				me.page.main.find('.show_chart_btns').html('');
-				me.page.main.find('.header-separator').hide();
+				me.sidebar.find('.patient-details').html(details);
 			}
-		}
-	});
-};
+		});
+	}
+
+	get_patient_info() {
+		return frappe.xcall('frappe.client.get', {
+			doctype: 'Patient',
+			name: this.patient_id,
+		}).then((patient) => {
+			if (patient) {
+				this.patient = patient;
+			}
+		});
+	}
+
+	setup_buttons() {
+		let me = this;
+		this.page.main.on("click", ".btn-show-chart", function() {
+			let btn_id = $(this).attr("data-show-chart-id"), scale_unit = $(this).attr("data-pts");
+			let title = $(this).attr("data-title");
+			me.show_patient_vital_charts(btn_id, scale_unit, title);
+		});
+
+		this.page.main.on('click', '.btn-more', function() {
+			let	doctype = $(this).attr('data-doctype'), docname = $(this).attr('data-docname');
+			if (me.page.main.find('.'+docname).parent().find('.document-html').attr('data-fetched') == '1') {
+				me.page.main.find('.'+docname).hide();
+				me.page.main.find('.'+docname).parent().find('.document-html').show();
+			} else {
+				if (doctype && docname) {
+					let exclude = ['patient', 'patient_name', 'patient_sex', 'encounter_date', 'naming_series'];
+					frappe.call({
+						method: 'erpnext.healthcare.utils.render_doc_as_html',
+						args: {
+							doctype: doctype,
+							docname: docname,
+							exclude_fields: exclude
+						},
+						freeze: true,
+						callback: function(r) {
+							if (r.message) {
+								me.page.main.find('.' + docname).hide();
+
+								me.page.main.find('.' + docname).parent().find('.document-html').html(
+									`${r.message.html}
+									<br>
+										<div align='center'>
+											<a class='btn octicon octicon-chevron-up btn-default btn-xs btn-less'
+												data-doctype='${doctype}'
+												data-docname='${docname}'>
+											</a>
+										</div>
+									`);
+
+								me.page.main.find('.' + docname).parent().find('.document-html').attr('hidden', false);
+								me.page.main.find('.' + docname).parent().find('.document-html').attr('data-fetched', '1');
+							}
+						}
+					});
+				}
+			}
+		});
+
+		this.page.main.on('click', '.btn-less', function() {
+			let docname = $(this).attr('data-docname');
+			me.page.main.find('.' + docname).parent().find('.document-id').show();
+			me.page.main.find('.' + docname).parent().find('.document-html').hide();
+		});
+
+		me.page.main.on('click', '.btn-get-records', function() {
+			this.setup_documents();
+		});
+	}
+
+	show_patient_vital_charts(btn_id, scale_unit, title) {
+		let me = this;
+
+		frappe.call({
+			method: 'erpnext.healthcare.utils.get_patient_vitals',
+			args: {
+				patient: me.patient_id
+			},
+			callback: function(r) {
+				if (r.message) {
+					let show_chart_btns_html = `
+						<div style='padding-top:10px;'>
+							<a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='bp' data-pts='mmHg' data-title='Blood Pressure'>
+								${__('Blood Pressure')}
+							</a>
+							<a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='pulse_rate' data-pts='per Minutes' data-title='Respiratory/Pulse Rate'>
+								${__('Respiratory/Pulse Rate')}
+							</a>
+							<a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='temperature' data-pts='°C or °F' data-title='Temperature'>
+								${__('Temperature')}
+							</a>
+							<a class='btn btn-default btn-xs btn-show-chart' data-show-chart-id='bmi' data-pts='' data-title='BMI'>
+								${__('BMI')}
+							</a>
+						</div>`;
+
+					me.page.main.find('.show_chart_btns').html(show_chart_btns_html);
+					let data = r.message;
+					let labels = [], datasets = [];
+					let bp_systolic = [], bp_diastolic = [], temperature = [];
+					let pulse = [], respiratory_rate = [], bmi = [], height = [], weight = [];
+
+					for (let i=0; i<data.length; i++) {
+						labels.push(data[i].signs_date+' | '+data[i].signs_time);
+
+						if (btn_id === 'bp') {
+							bp_systolic.push(data[i].bp_systolic);
+							bp_diastolic.push(data[i].bp_diastolic);
+						}
+						if (btn_id === 'temperature') {
+							temperature.push(data[i].temperature);
+						}
+						if (btn_id === 'pulse_rate') {
+							pulse.push(data[i].pulse);
+							respiratory_rate.push(data[i].respiratory_rate);
+						}
+						if (btn_id === 'bmi') {
+							bmi.push(data[i].bmi);
+							height.push(data[i].height);
+							weight.push(data[i].weight);
+						}
+					}
+					if (btn_id === 'temperature') {
+						datasets.push({name: 'Temperature', values: temperature, chartType: 'line'});
+					}
+					if (btn_id === 'bmi') {
+						datasets.push({name: 'BMI', values: bmi, chartType: 'line'});
+						datasets.push({name: 'Height', values: height, chartType: 'line'});
+						datasets.push({name: 'Weight', values: weight, chartType: 'line'});
+					}
+					if (btn_id === 'bp') {
+						datasets.push({name: 'BP Systolic', values: bp_systolic, chartType: 'line'});
+						datasets.push({name: 'BP Diastolic', values: bp_diastolic, chartType: 'line'});
+					}
+					if (btn_id === 'pulse_rate') {
+						datasets.push({name: 'Heart Rate / Pulse', values: pulse, chartType: 'line'});
+						datasets.push({name: 'Respiratory Rate', values: respiratory_rate, chartType: 'line'});
+					}
+
+					new frappe.Chart('.patient_vital_charts', {
+						data: {
+							labels: labels,
+							datasets: datasets
+						},
+
+						title: title,
+						type: 'axis-mixed',
+						height: 200,
+						colors: ['purple', '#ffa3ef', 'light-blue'],
+
+						tooltipOptions: {
+							formatTooltipX: d => (d + '').toUpperCase(),
+							formatTooltipY: d => d + ' ' + scale_unit,
+						}
+					});
+					me.page.main.find('.header-separator').show();
+				} else {
+					me.page.main.find('.patient_vital_charts').html('');
+					me.page.main.find('.show_chart_btns').html('');
+					me.page.main.find('.header-separator').hide();
+				}
+			}
+		});
+	}
+}
\ No newline at end of file
diff --git a/erpnext/healthcare/page/patient_history/patient_history_sidebar.html b/erpnext/healthcare/page/patient_history/patient_history_sidebar.html
new file mode 100644
index 0000000..4560e7e
--- /dev/null
+++ b/erpnext/healthcare/page/patient_history/patient_history_sidebar.html
@@ -0,0 +1,21 @@
+<div class="patient-history-sidebar">
+    <div class="patient-image-container">
+		{% if patient_image %}
+			<div class="patient-image" src={{patient_image}} style="background-image: url(\'{%= patient_image %}\')"></div>
+		{% endif %}
+    </div>
+    <div class="patient-intro">
+		{% if patient_name %}
+		<p class="patient-name bold">{{patient_name}}</p>
+		{% endif %}
+		{% if patient_gender %}
+		<p class="patient-gender text-muted">{%=__("Gender: ") %} {{patient_gender}}</p>
+		{% endif %}
+		{% if patient_mobile %}
+		<p class="patient-mobile text-muted">{%=__("Contact: ") %} {{patient_mobile}}</p>
+		{% endif %}
+	</div>
+    <div class="patient-details">
+    </div>
+</div>
+
diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.css b/erpnext/healthcare/page/patient_progress/patient_progress.css
index 5d85a74..737b2e0 100644
--- a/erpnext/healthcare/page/patient_progress/patient_progress.css
+++ b/erpnext/healthcare/page/patient_progress/patient_progress.css
@@ -29,6 +29,7 @@
 
 .patient-name {
   font-size: 20px;
+  margin-top: 25px;
 }
 
 /* heatmap */
@@ -55,6 +56,7 @@
 }
 
 .heatmap-container .chart-filter {
+  z-index: 1;
   position: relative;
   top: 5px;
   margin-right: 10px;
@@ -111,10 +113,13 @@
 }
 
 .chart-column-container {
-  border-bottom: 1px solid #d1d8dd;
   margin: 5px 0;
 }
 
+.progress-graphs .progress-container {
+  margin-bottom: var(--margin-xl);
+}
+
 .line-chart-container .frappe-chart {
   margin-top: -20px;
 }
@@ -146,6 +151,7 @@
   }
 
   .percentage-chart-container .chart-filter {
+    z-index: 1;
     position: relative;
     top: 12px;
     margin-right: 10px;
diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.html b/erpnext/healthcare/page/patient_progress/patient_progress.html
index 30064bd..ee60065 100644
--- a/erpnext/healthcare/page/patient_progress/patient_progress.html
+++ b/erpnext/healthcare/page/patient_progress/patient_progress.html
@@ -1,14 +1,15 @@
 <div class="row patient-progress">
 	<div class="col-md-12">
 		<div class="progress-graphs">
-			<div class="chart-column-container heatmap-container hidden-xs hidden-sm">
+			<div class="progress-container chart-column-container heatmap-container hidden-xs hidden-sm frappe-card">
 				<div class="patient-heatmap"></div>
 			</div>
-			<div class="chart-column-container percentage-chart-container">
+
+			<div class="progress-container chart-column-container percentage-chart-container frappe-card">
 				<div class="therapy-session-percentage-chart"></div>
 			</div>
 
-			<div class="therapy-progress">
+			<div class="progress-container therapy-progress frappe-card">
 				<div class="chart-head">
 					<text class="title" text-anchor="start">Therapy Progress</text>
 					<div class="chart-control pull-right"></div>
@@ -22,7 +23,7 @@
 				</div>
 			</div>
 
-			<div class="assessment-results">
+			<div class="progress-container assessment-results frappe-card">
 				<div class="chart-head">
 					<text class="title" text-anchor="start">Assessment Results</text>
 					<div class="chart-control pull-right"></div>
@@ -36,7 +37,7 @@
 				</div>
 			</div>
 
-			<div class="therapy-assessment-correlation progress-line-chart">
+			<div class="progress-container therapy-assessment-correlation progress-line-chart frappe-card">
 				<div class="chart-head">
 					<text class="title" text-anchor="start">Therapy Type and Assessment Correlation</text>
 					<div class="chart-control pull-right"></div>
@@ -50,7 +51,7 @@
 				</div>
 			</div>
 
-			<div class="assessment-parameter-progress progress-line-chart">
+			<div class="progress-container assessment-parameter-progress progress-line-chart frappe-card">
 				<div class="chart-head">
 					<text class="title" text-anchor="start">Assessment Parameter Wise Progress</text>
 					<div class="chart-control pull-right"></div>
diff --git a/erpnext/healthcare/page/patient_progress/patient_progress.js b/erpnext/healthcare/page/patient_progress/patient_progress.js
index 4b7599d..3f06f1f 100644
--- a/erpnext/healthcare/page/patient_progress/patient_progress.js
+++ b/erpnext/healthcare/page/patient_progress/patient_progress.js
@@ -133,8 +133,11 @@
 			type: 'heatmap',
 			countLabel: 'Interactions',
 			data: {},
-			discreteDomains: 0
+			discreteDomains: 1,
+			radius: 3,
+			height: 150
 		});
+
 		this.update_heatmap_data();
 		this.create_heatmap_chart_filters();
 	}
@@ -164,33 +167,35 @@
 	}
 
 	render_percentage_chart(field, title) {
-		frappe.xcall(
-			'erpnext.healthcare.page.patient_progress.patient_progress.get_therapy_sessions_distribution_data', {
-				patient: this.patient_id,
-				field: field
-			}
-		).then(chart => {
-			if (chart.labels.length) {
-				this.percentage_chart = new frappe.Chart('.therapy-session-percentage-chart', {
-					title: title,
-					type: 'percentage',
-					data: {
-						labels: chart.labels,
-						datasets: chart.datasets
-					},
-					truncateLegends: 1,
-					barOptions: {
-						height: 11,
-						depth: 1
-					},
-					height: 160,
-					maxSlices: 8,
-					colors: ['#5e64ff', '#743ee2', '#ff5858', '#ffa00a', '#feef72', '#28a745', '#98d85b', '#a9a7ac'],
-				});
-			} else {
-				this.wrapper.find('.percentage-chart-container').hide();
-			}
-		});
+		// REDESIGN-TODO: chart seems to be broken. Enable this once fixed.
+		this.wrapper.find('.percentage-chart-container').hide();
+		// frappe.xcall(
+		// 	'erpnext.healthcare.page.patient_progress.patient_progress.get_therapy_sessions_distribution_data', {
+		// 		patient: this.patient_id,
+		// 		field: field
+		// 	}
+		// ).then(chart => {
+		// 	if (chart.labels.length) {
+		// 		this.percentage_chart = new frappe.Chart('.therapy-session-percentage-chart', {
+		// 			title: title,
+		// 			type: 'percentage',
+		// 			data: {
+		// 				labels: chart.labels,
+		// 				datasets: chart.datasets
+		// 			},
+		// 			truncateLegends: 1,
+		// 			barOptions: {
+		// 				height: 11,
+		// 				depth: 1
+		// 			},
+		// 			height: 160,
+		// 			maxSlices: 8,
+		// 			colors: ['#5e64ff', '#743ee2', '#ff5858', '#ffa00a', '#feef72', '#28a745', '#98d85b', '#a9a7ac'],
+		// 		});
+		// 	} else {
+		// 		this.wrapper.find('.percentage-chart-container').hide();
+		// 	}
+		// });
 	}
 
 	create_percentage_chart_filters() {
@@ -311,7 +316,7 @@
 						},
 						axisOptions: {
 							xIsSeries: 1
-						},
+						}
 					});
 				} else {
 					$(parent).find('.chart-container').show();
@@ -377,7 +382,7 @@
 							xIsSeries: 1
 						},
 						tooltipOptions: {
-							formatTooltipY: d => d + __(' out of ') + chart.max_score
+							formatTooltipY: d => __('{0} out of {1}', [d, chart.max_score])
 						}
 					});
 				} else {
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 2e59bed..ba4ca41 100644
--- a/erpnext/healthcare/report/lab_test_report/lab_test_report.py
+++ b/erpnext/healthcare/report/lab_test_report/lab_test_report.py
@@ -169,7 +169,7 @@
 			'labels': labels,
 			'datasets': datasets
 		},
-		'type': 'donut',
+		'type': 'bar',
 		'height': 300,
 	}
 
diff --git a/erpnext/healthcare/utils.py b/erpnext/healthcare/utils.py
index ffecf4d..7c80bdb 100644
--- a/erpnext/healthcare/utils.py
+++ b/erpnext/healthcare/utils.py
@@ -8,8 +8,7 @@
 import json
 from frappe import _
 from frappe.utils.formatters import format_value
-from frappe.utils import time_diff_in_hours, rounded
-from six import string_types
+from frappe.utils import time_diff_in_hours, rounded, cstr
 from erpnext.healthcare.doctype.healthcare_settings.healthcare_settings import get_income_account
 from erpnext.healthcare.doctype.fee_validity.fee_validity import create_fee_validity
 from erpnext.healthcare.doctype.lab_test.lab_test import create_multiple
@@ -181,9 +180,9 @@
 
 			service_item = frappe.db.get_single_value('Healthcare Settings', 'clinical_procedure_consumable_item')
 			if not service_item:
-				msg = _('Please Configure Clinical Procedure Consumable Item in ')
-				msg += '''<b><a href='/app/Form/Healthcare Settings'>Healthcare Settings</a></b>'''
-				frappe.throw(msg, title=_('Missing Configuration'))
+				frappe.throw(_('Please configure Clinical Procedure Consumable Item in {0}').format(
+					frappe.utils.get_link_to_form('Healthcare Settings', 'Healthcare Settings')),
+					title=_('Missing Configuration'))
 
 			clinical_procedures_to_invoice.append({
 				'reference_type': 'Clinical Procedure',
@@ -312,7 +311,7 @@
 
 @frappe.whitelist()
 def get_service_item_and_practitioner_charge(doc):
-	if isinstance(doc, string_types):
+	if isinstance(doc, str):
 		doc = json.loads(doc)
 		doc = frappe.get_doc(doc)
 
@@ -607,101 +606,147 @@
 
 @frappe.whitelist()
 def render_doc_as_html(doctype, docname, exclude_fields = []):
-	#render document as html, three column layout will break
+	"""
+		Render document as HTML
+	"""
+
 	doc = frappe.get_doc(doctype, docname)
 	meta = frappe.get_meta(doctype)
-	doc_html = "<div class='col-md-12 col-sm-12'>"
-	section_html = ''
-	section_label = ''
-	html = ''
-	sec_on = False
+	doc_html = section_html = section_label = html = ""
+	sec_on = has_data = False
 	col_on = 0
-	has_data = False
+
 	for df in meta.fields:
-		#on section break append append previous section and html to doc html
+		# on section break append previous section and html to doc html
 		if df.fieldtype == "Section Break":
 			if has_data and col_on and sec_on:
 				doc_html += section_html + html + "</div>"
+
 			elif has_data and not col_on and sec_on:
-				doc_html += "<div class='col-md-12 col-sm-12'\
-				><div class='col-md-12 col-sm-12'>" \
-				+ section_html + html +"</div></div>"
+				doc_html += """
+					<br>
+					<div class='row'>
+						<div class='col-md-12 col-sm-12'>
+							<b>{0}</b>
+						</div>
+					</div>
+					<div class='row'>
+						<div class='col-md-12 col-sm-12'>
+							{1} {2}
+						</div>
+					</div>
+				""".format(section_label, section_html, html)
+
+			# close divs for columns
 			while col_on:
 				doc_html += "</div>"
 				col_on -= 1
+
 			sec_on = True
-			has_data= False
+			has_data = False
 			col_on = 0
-			section_html = ''
-			html = ''
+			section_html = html = ""
+
 			if df.label:
 				section_label = df.label
 			continue
-		#on column break append html to section html or doc html
+
+		# on column break append html to section html or doc html
 		if df.fieldtype == "Column Break":
-			if sec_on and has_data:
-				section_html += "<div class='col-md-12 col-sm-12'\
-				><div class='col-md-6 col\
-				-sm-6'><b>" + section_label + "</b>" + html + "</div><div \
-				class='col-md-6 col-sm-6'>"
-			elif has_data:
-				doc_html += "<div class='col-md-12 col-sm-12'><div class='col-m\
-				d-6 col-sm-6'>" + html + "</div><div class='col-md-6 col-sm-6'>"
-			elif sec_on and not col_on:
-				section_html += "<div class='col-md-6 col-sm-6'>"
-			html = ''
+			if sec_on and not col_on and has_data:
+				section_html += """
+					<br>
+					<div class='row'>
+						<div class='col-md-12 col-sm-12'>
+							<b>{0}</b>
+						</div>
+					</div>
+					<div class='row'>
+						<div class='col-md-4 col-sm-4'>
+							{1}
+						</div>
+				""".format(section_label, html)
+			elif col_on == 1 and has_data:
+				section_html += "<div class='col-md-4 col-sm-4'>" + html + "</div>"
+			elif col_on > 1 and has_data:
+				doc_html += "<div class='col-md-4 col-sm-4'>" + html + "</div>"
+			else:
+				doc_html += """
+					<div class='row'>
+						<div class='col-md-12 col-sm-12'>
+							{0}
+						</div>
+					</div>
+				""".format(html)
+
+			html = ""
 			col_on += 1
+
 			if df.label:
-				html += '<br>' + df.label
+				html += "<br>" + df.label
 			continue
-		#on table iterate in items and create table based on in_list_view, append to section html or doc html
-		if df.fieldtype == 'Table':
+
+		# on table iterate through items and create table
+		# based on the in_list_view property
+		# append to section html or doc html
+		if df.fieldtype == "Table":
 			items = doc.get(df.fieldname)
-			if not items: continue
+			if not items:
+				continue
 			child_meta = frappe.get_meta(df.options)
-			if not has_data : has_data = True
-			table_head = ''
-			table_row = ''
+
+			if not has_data:
+				has_data = True
+			table_head = table_row = ""
 			create_head = True
+
 			for item in items:
-				table_row += '<tr>'
+				table_row += "<tr>"
 				for cdf in child_meta.fields:
 					if cdf.in_list_view:
 						if create_head:
-							table_head += '<th>' + cdf.label + '</th>'
+							table_head += "<th class='text-muted'>" + cdf.label + "</th>"
 						if item.get(cdf.fieldname):
-							table_row += '<td>' + str(item.get(cdf.fieldname)) \
-							+ '</td>'
+							table_row += "<td>" + cstr(item.get(cdf.fieldname)) + "</td>"
 						else:
-							table_row += '<td></td>'
+							table_row += "<td></td>"
+
 				create_head = False
-				table_row += '</tr>'
+				table_row += "</tr>"
+
 			if sec_on:
-				section_html += "<table class='table table-condensed \
-				bordered'>" + table_head +  table_row + '</table>'
+				section_html += """
+					<table class='table table-condensed bordered'>
+						{0} {1}
+					</table>
+				""".format(table_head, table_row)
 			else:
-				html += "<table class='table table-condensed table-bordered'>" \
-				+ table_head +  table_row + "</table>"
+				html += """
+					<table class='table table-condensed table-bordered'>
+						{0} {1}
+					</table>
+				""".format(table_head, table_row)
 			continue
 
-		#on other field types add label and value to html
+		# on any other field type add label and value to html
 		if not df.hidden and not df.print_hide and doc.get(df.fieldname) and df.fieldname not in exclude_fields:
-			if doc.get(df.fieldname):
-				formatted_value = format_value(doc.get(df.fieldname), meta.get_field(df.fieldname), doc)
-				html +=  '<br>{0} : {1}'.format(df.label or df.fieldname, formatted_value)
+			formatted_value = format_value(doc.get(df.fieldname), meta.get_field(df.fieldname), doc)
+			html += "<br>{0} : {1}".format(df.label or df.fieldname, formatted_value)
 
 			if not has_data : has_data = True
 
 	if sec_on and col_on and has_data:
-		doc_html += section_html + html + '</div></div>'
+		doc_html += section_html + html + "</div></div>"
 	elif sec_on and not col_on and has_data:
-		doc_html += "<div class='col-md-12 col-sm-12'\
-		><div class='col-md-12 col-sm-12'>" \
-		+ section_html + html +'</div></div>'
-	if doc_html:
-		doc_html = "<div class='small'><div class='col-md-12 text-right'><a class='btn btn-default btn-xs' href='/app/Form/%s/%s'></a></div>" %(doctype, docname) + doc_html + '</div>'
+		doc_html += """
+			<div class='col-md-12 col-sm-12'>
+				<div class='col-md-12 col-sm-12'>
+					{0} {1}
+				</div>
+			</div>
+		""".format(section_html, html)
 
-	return {'html': doc_html}
+	return {"html": doc_html}
 
 
 def update_address_links(address, method):
diff --git a/erpnext/healthcare/workspace/healthcare/healthcare.json b/erpnext/healthcare/workspace/healthcare/healthcare.json
index 55132f3..f69604c 100644
--- a/erpnext/healthcare/workspace/healthcare/healthcare.json
+++ b/erpnext/healthcare/workspace/healthcare/healthcare.json
@@ -7,7 +7,7 @@
   }
  ],
  "charts_label": "",
- "content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"Healthcare\", \"col\": 12}}, {\"type\": \"chart\", \"data\": {\"chart_name\": \"Patient Appointments\", \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Patient Appointment\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Patient\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Healthcare Service Unit\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Healthcare Practitioner\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Patient History\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Masters\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Consultation Setup\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Consultation\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Laboratory Setup\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Laboratory\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Rehabilitation and Physiotherapy\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Records and History\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Reports\", \"col\": 4}}]",
+ "content": "[{\"type\": \"onboarding\", \"data\": {\"onboarding_name\":\"Healthcare\", \"col\": 12}}, {\"type\": \"chart\", \"data\": {\"chart_name\": \"Patient Appointments\", \"col\": 12}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Your Shortcuts\", \"level\": 4, \"col\": 12}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Patient Appointment\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Patient\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Healthcare Service Unit\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Healthcare Practitioner\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Patient History\", \"col\": 4}}, {\"type\": \"shortcut\", \"data\": {\"shortcut_name\": \"Dashboard\", \"col\": 4}}, {\"type\": \"spacer\", \"data\": {\"col\": 12}}, {\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Masters\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Consultation Setup\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Consultation\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Facility Management\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Settings\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Inpatient\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Laboratory Setup\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Laboratory\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Rehabilitation and Physiotherapy\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Records and History\", \"col\": 4}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Reports\", \"col\": 4}}]",
  "creation": "2020-03-02 17:23:17.919682",
  "developer_mode_only": 0,
  "disable_user_customization": 0,
@@ -76,54 +76,9 @@
    "type": "Link"
   },
   {
-   "dependencies": "",
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Healthcare Service Unit Type",
-   "link_count": 0,
-   "link_to": "Healthcare Service Unit Type",
-   "link_type": "DocType",
-   "onboard": 0,
-   "type": "Link"
-  },
-  {
-   "dependencies": "",
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Healthcare Service Unit",
-   "link_count": 0,
-   "link_to": "Healthcare Service Unit",
-   "link_type": "DocType",
-   "onboard": 0,
-   "type": "Link"
-  },
-  {
-   "dependencies": "",
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Medical Code Standard",
-   "link_count": 0,
-   "link_to": "Medical Code Standard",
-   "link_type": "DocType",
-   "onboard": 0,
-   "type": "Link"
-  },
-  {
-   "dependencies": "",
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Medical Code",
-   "link_count": 0,
-   "link_to": "Medical Code",
-   "link_type": "DocType",
-   "onboard": 0,
-   "type": "Link"
-  },
-  {
    "hidden": 0,
    "is_query_report": 0,
    "label": "Consultation Setup",
-   "link_count": 0,
    "onboard": 0,
    "type": "Card Break"
   },
@@ -132,7 +87,6 @@
    "hidden": 0,
    "is_query_report": 0,
    "label": "Appointment Type",
-   "link_count": 0,
    "link_to": "Appointment Type",
    "link_type": "DocType",
    "onboard": 0,
@@ -143,7 +97,6 @@
    "hidden": 0,
    "is_query_report": 0,
    "label": "Clinical Procedure Template",
-   "link_count": 0,
    "link_to": "Clinical Procedure Template",
    "link_type": "DocType",
    "onboard": 0,
@@ -154,7 +107,6 @@
    "hidden": 0,
    "is_query_report": 0,
    "label": "Prescription Dosage",
-   "link_count": 0,
    "link_to": "Prescription Dosage",
    "link_type": "DocType",
    "onboard": 0,
@@ -165,7 +117,6 @@
    "hidden": 0,
    "is_query_report": 0,
    "label": "Prescription Duration",
-   "link_count": 0,
    "link_to": "Prescription Duration",
    "link_type": "DocType",
    "onboard": 0,
@@ -176,70 +127,16 @@
    "hidden": 0,
    "is_query_report": 0,
    "label": "Antibiotic",
-   "link_count": 0,
    "link_to": "Antibiotic",
    "link_type": "DocType",
    "onboard": 0,
    "type": "Link"
   },
   {
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Consultation",
-   "link_count": 0,
-   "onboard": 0,
-   "type": "Card Break"
-  },
-  {
-   "dependencies": "",
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Patient Appointment",
-   "link_count": 0,
-   "link_to": "Patient Appointment",
-   "link_type": "DocType",
-   "onboard": 0,
-   "type": "Link"
-  },
-  {
-   "dependencies": "",
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Clinical Procedure",
-   "link_count": 0,
-   "link_to": "Clinical Procedure",
-   "link_type": "DocType",
-   "onboard": 0,
-   "type": "Link"
-  },
-  {
-   "dependencies": "",
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Patient Encounter",
-   "link_count": 0,
-   "link_to": "Patient Encounter",
-   "link_type": "DocType",
-   "onboard": 0,
-   "type": "Link"
-  },
-  {
-   "dependencies": "",
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Vital Signs",
-   "link_count": 0,
-   "link_to": "Vital Signs",
-   "link_type": "DocType",
-   "onboard": 0,
-   "type": "Link"
-  },
-  {
    "dependencies": "",
    "hidden": 0,
    "is_query_report": 0,
    "label": "Complaint",
-   "link_count": 0,
    "link_to": "Complaint",
    "link_type": "DocType",
    "onboard": 0,
@@ -250,18 +147,63 @@
    "hidden": 0,
    "is_query_report": 0,
    "label": "Diagnosis",
-   "link_count": 0,
    "link_to": "Diagnosis",
    "link_type": "DocType",
    "onboard": 0,
    "type": "Link"
   },
   {
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Consultation",
+   "onboard": 0,
+   "type": "Card Break"
+  },
+  {
+   "dependencies": "",
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Patient Appointment",
+   "link_to": "Patient Appointment",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "dependencies": "",
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Clinical Procedure",
+   "link_to": "Clinical Procedure",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "dependencies": "",
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Patient Encounter",
+   "link_to": "Patient Encounter",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "dependencies": "",
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Vital Signs",
+   "link_to": "Vital Signs",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
    "dependencies": "",
    "hidden": 0,
    "is_query_report": 0,
    "label": "Fee Validity",
-   "link_count": 0,
    "link_to": "Fee Validity",
    "link_type": "DocType",
    "onboard": 0,
@@ -270,6 +212,62 @@
   {
    "hidden": 0,
    "is_query_report": 0,
+   "label": "Facility Management",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Card Break"
+  },
+  {
+   "dependencies": "",
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Healthcare Service Unit Type",
+   "link_to": "Healthcare Service Unit Type",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "dependencies": "",
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Healthcare Service Unit",
+   "link_to": "Healthcare Service Unit",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Medical Coding",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Card Break"
+  },
+  {
+   "dependencies": "",
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Medical Code Standard",
+   "link_to": "Medical Code Standard",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "dependencies": "",
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Medical Code",
+   "link_to": "Medical Code",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "hidden": 0,
+   "is_query_report": 0,
    "label": "Settings",
    "link_count": 0,
    "onboard": 0,
@@ -339,6 +337,16 @@
    "type": "Link"
   },
   {
+   "dependencies": "",
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Dosage Form",
+   "link_to": "Dosage Form",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
    "hidden": 0,
    "is_query_report": 0,
    "label": "Laboratory",
@@ -369,12 +377,36 @@
    "type": "Link"
   },
   {
-   "dependencies": "",
    "hidden": 0,
    "is_query_report": 0,
-   "label": "Dosage Form",
-   "link_count": 0,
-   "link_to": "Dosage Form",
+   "label": "Inpatient",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Card Break"
+  },
+  {
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Inpatient Medication Order",
+   "link_to": "Inpatient Medication Order",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Inpatient Record",
+   "link_to": "Inpatient Record",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Inpatient Medication Entry",
+   "link_to": "Inpatient Medication Entry",
    "link_type": "DocType",
    "onboard": 0,
    "type": "Link"
@@ -536,7 +568,7 @@
    "type": "Link"
   }
  ],
- "modified": "2021-08-05 12:15:59.434612",
+ "modified": "2021-08-30 17:37:45.316999",
  "modified_by": "Administrator",
  "module": "Healthcare",
  "name": "Healthcare",
diff --git a/erpnext/hr/doctype/employee_referral/employee_referral.js b/erpnext/hr/doctype/employee_referral/employee_referral.js
index 9c99bbb..8722019 100644
--- a/erpnext/hr/doctype/employee_referral/employee_referral.js
+++ b/erpnext/hr/doctype/employee_referral/employee_referral.js
@@ -43,8 +43,6 @@
 			});
 		}
 
-
-
 	},
 	create_job_applicant: function(frm) {
 		frappe.model.open_mapped_doc({
diff --git a/erpnext/hr/doctype/full_and_final_asset/__init__.py b/erpnext/hr/doctype/full_and_final_asset/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_asset/__init__.py
diff --git a/erpnext/hr/doctype/full_and_final_asset/full_and_final_asset.js b/erpnext/hr/doctype/full_and_final_asset/full_and_final_asset.js
new file mode 100644
index 0000000..1965b46
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_asset/full_and_final_asset.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Full and Final Asset', {
+	// refresh: function(frm) {
+
+	// }
+});
diff --git a/erpnext/hr/doctype/full_and_final_asset/full_and_final_asset.json b/erpnext/hr/doctype/full_and_final_asset/full_and_final_asset.json
new file mode 100644
index 0000000..3ad8335
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_asset/full_and_final_asset.json
@@ -0,0 +1,64 @@
+{
+ "actions": [],
+ "creation": "2021-06-28 13:36:58.658985",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "reference",
+  "asset_name",
+  "date",
+  "status",
+  "description"
+ ],
+ "fields": [
+  {
+   "fieldname": "reference",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Reference",
+   "options": "Asset Movement",
+   "read_only": 1,
+   "reqd": 1
+  },
+  {
+   "fieldname": "status",
+   "fieldtype": "Select",
+   "in_list_view": 1,
+   "label": "Status",
+   "options": "Owned\nReturned",
+   "reqd": 1
+  },
+  {
+   "fieldname": "description",
+   "fieldtype": "Small Text",
+   "label": "Description"
+  },
+  {
+   "fieldname": "asset_name",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Asset Name",
+   "read_only": 1
+  },
+  {
+   "fieldname": "date",
+   "fieldtype": "Datetime",
+   "in_list_view": 1,
+   "label": "Date",
+   "read_only": 1
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-07-15 15:17:31.309834",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Full and Final Asset",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/full_and_final_asset/full_and_final_asset.py b/erpnext/hr/doctype/full_and_final_asset/full_and_final_asset.py
new file mode 100644
index 0000000..2337224
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_asset/full_and_final_asset.py
@@ -0,0 +1,8 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+class FullandFinalAsset(Document):
+	pass
diff --git a/erpnext/hr/doctype/full_and_final_asset/test_full_and_final_asset.py b/erpnext/hr/doctype/full_and_final_asset/test_full_and_final_asset.py
new file mode 100644
index 0000000..6d59c99
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_asset/test_full_and_final_asset.py
@@ -0,0 +1,8 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+
+# import frappe
+import unittest
+
+class TestFullandFinalAsset(unittest.TestCase):
+	pass
diff --git a/erpnext/hr/doctype/full_and_final_outstanding_statement/__init__.py b/erpnext/hr/doctype/full_and_final_outstanding_statement/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_outstanding_statement/__init__.py
diff --git a/erpnext/hr/doctype/full_and_final_outstanding_statement/full_and_final_outstanding_statement.json b/erpnext/hr/doctype/full_and_final_outstanding_statement/full_and_final_outstanding_statement.json
new file mode 100644
index 0000000..be242e2
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_outstanding_statement/full_and_final_outstanding_statement.json
@@ -0,0 +1,96 @@
+{
+ "actions": [],
+ "creation": "2021-06-28 13:32:02.167317",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "component",
+  "reference_document_type",
+  "reference_document",
+  "account",
+  "paid_via_salary_slip",
+  "column_break_4",
+  "amount",
+  "status",
+  "remark"
+ ],
+ "fields": [
+  {
+   "fieldname": "column_break_4",
+   "fieldtype": "Column Break"
+  },
+  {
+   "columns": 2,
+   "default": "Unsettled",
+   "fieldname": "status",
+   "fieldtype": "Select",
+   "in_list_view": 1,
+   "label": "Status",
+   "options": "Settled\nUnsettled"
+  },
+  {
+   "fieldname": "remark",
+   "fieldtype": "Small Text",
+   "label": "Remark"
+  },
+  {
+   "columns": 2,
+   "depends_on": "reference_document_type",
+   "fieldname": "reference_document",
+   "fieldtype": "Dynamic Link",
+   "in_list_view": 1,
+   "label": "Reference Document",
+   "mandatory_depends_on": "reference_document_type",
+   "options": "reference_document_type",
+   "search_index": 1
+  },
+  {
+   "columns": 2,
+   "fieldname": "component",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Component",
+   "reqd": 1
+  },
+  {
+   "fieldname": "account",
+   "fieldtype": "Link",
+   "label": "Account",
+   "options": "Account"
+  },
+  {
+   "columns": 2,
+   "fieldname": "amount",
+   "fieldtype": "Currency",
+   "in_list_view": 1,
+   "label": "Amount"
+  },
+  {
+   "columns": 2,
+   "fieldname": "reference_document_type",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Reference Document Type",
+   "options": "DocType"
+  },
+  {
+   "default": "0",
+   "fieldname": "paid_via_salary_slip",
+   "fieldtype": "Check",
+   "label": "Paid via Salary Slip"
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-07-20 16:59:34.447934",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Full and Final Outstanding Statement",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/full_and_final_outstanding_statement/full_and_final_outstanding_statement.py b/erpnext/hr/doctype/full_and_final_outstanding_statement/full_and_final_outstanding_statement.py
new file mode 100644
index 0000000..d53cd91
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_outstanding_statement/full_and_final_outstanding_statement.py
@@ -0,0 +1,8 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+class FullandFinalOutstandingStatement(Document):
+	pass
diff --git a/erpnext/hr/doctype/full_and_final_statement/__init__.py b/erpnext/hr/doctype/full_and_final_statement/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_statement/__init__.py
diff --git a/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement.js b/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement.js
new file mode 100644
index 0000000..074d85b
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement.js
@@ -0,0 +1,115 @@
+// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Full and Final Statement', {
+	refresh: function(frm) {
+		frm.events.set_queries(frm, "payables");
+		frm.events.set_queries(frm, "receivables");
+
+		if (frm.doc.docstatus == 1 && frm.doc.status == "Unpaid") {
+			frm.add_custom_button(__("Create Journal Entry"), function () {
+				frm.events.create_journal_entry(frm);
+			});
+		}
+	},
+
+	set_queries: function(frm, type) {
+		frm.set_query("reference_document_type", type, function () {
+			let modules = ["HR", "Payroll", "Loan Management"];
+			return {
+				filters: {
+					istable: 0,
+					issingle: 0,
+					module: ["In", modules]
+				}
+			};
+		});
+
+		let filters = {};
+
+		frm.set_query('reference_document', type, function(doc, cdt, cdn) {
+			let fnf_doc = frappe.get_doc(cdt, cdn);
+
+			frappe.model.with_doctype(fnf_doc.reference_document_type, function() {
+				if (frappe.model.is_tree(fnf_doc.reference_document_type)) {
+					filters['is_group'] = 0;
+				}
+
+				if (frappe.meta.has_field(fnf_doc.reference_document_type, 'company')) {
+					filters['company'] = frm.doc.company;
+				}
+
+				if (frappe.meta.has_field(fnf_doc.reference_document_type, 'employee')) {
+					filters['employee'] = frm.doc.employee;
+				}
+			});
+
+			return {
+				filters: filters
+			};
+		});
+	},
+
+	employee: function(frm) {
+		frm.events.get_outstanding_statements(frm);
+	},
+
+	get_outstanding_statements: function(frm) {
+		if (frm.doc.employee) {
+			frappe.call({
+				method: "get_outstanding_statements",
+				doc: frm.doc,
+				callback: function() {
+					frm.refresh();
+				}
+			});
+		}
+	},
+
+	create_journal_entry: function(frm) {
+		frappe.call({
+			method: "create_journal_entry",
+			doc: frm.doc,
+			callback: function(r) {
+				var doclist = frappe.model.sync(r.message);
+				frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
+			}
+		});
+	}
+});
+
+frappe.ui.form.on("Full and Final Outstanding Statement", {
+	reference_document: function(frm, cdt, cdn) {
+		var child = locals[cdt][cdn];
+		if (child.reference_document_type && child.reference_document) {
+			frappe.call({
+				method: "erpnext.hr.doctype.full_and_final_statement.full_and_final_statement.get_account_and_amount",
+				args: {
+					ref_doctype: child.reference_document_type,
+					ref_document: child.reference_document
+				},
+				callback: function(r) {
+					if (r.message) {
+						frappe.model.set_value(cdt, cdn, "account", r.message[0]);
+						frappe.model.set_value(cdt, cdn, "amount", r.message[1]);
+					}
+				}
+			});
+		}
+	},
+
+	amount: function(frm) {
+		var total_payable_amount = 0;
+		var total_receivable_amount = 0;
+
+		frm.doc.payables.forEach(element => {
+			total_payable_amount = total_payable_amount + element.amount;
+		});
+
+		frm.doc.receivables.forEach(element => {
+			total_receivable_amount = total_receivable_amount + element.amount;
+		});
+		frm.set_value("total_payable_amount", flt(total_payable_amount));
+		frm.set_value("total_receivable_amount", flt(total_receivable_amount));
+	}
+});
diff --git a/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement.json b/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement.json
new file mode 100644
index 0000000..ebcf36d
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement.json
@@ -0,0 +1,231 @@
+{
+ "actions": [],
+ "autoname": "HR-FNF-.YYYY.-.#####",
+ "creation": "2021-06-28 13:17:36.050459",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "employee",
+  "employee_name",
+  "transaction_date",
+  "column_break_12",
+  "company",
+  "status",
+  "amended_from",
+  "employee_details_section",
+  "date_of_joining",
+  "relieving_date",
+  "column_break_4",
+  "designation",
+  "department",
+  "section_break_8",
+  "payables",
+  "section_break_10",
+  "receivables",
+  "totals_section",
+  "total_payable_amount",
+  "column_break_21",
+  "total_receivable_amount",
+  "section_break_15",
+  "assets_allocated"
+ ],
+ "fields": [
+  {
+   "fieldname": "employee",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Employee",
+   "options": "Employee",
+   "reqd": 1
+  },
+  {
+   "fetch_from": "employee.employee_name",
+   "fieldname": "employee_name",
+   "fieldtype": "Data",
+   "label": "Employee Name",
+   "read_only": 1
+  },
+  {
+   "fetch_from": "employee.designation",
+   "fieldname": "designation",
+   "fieldtype": "Link",
+   "label": "Designation",
+   "options": "Designation",
+   "read_only": 1
+  },
+  {
+   "fieldname": "column_break_4",
+   "fieldtype": "Column Break"
+  },
+  {
+   "default": "Unpaid",
+   "fieldname": "status",
+   "fieldtype": "Select",
+   "label": "Status",
+   "options": "Paid\nUnpaid",
+   "read_only": 1
+  },
+  {
+   "fetch_from": "employee.department",
+   "fieldname": "department",
+   "fieldtype": "Link",
+   "label": "Department",
+   "options": "Department",
+   "read_only": 1
+  },
+  {
+   "fieldname": "amended_from",
+   "fieldtype": "Link",
+   "label": "Amended From",
+   "no_copy": 1,
+   "options": "Full and Final Statement",
+   "print_hide": 1,
+   "read_only": 1
+  },
+  {
+   "fieldname": "section_break_8",
+   "fieldtype": "Section Break",
+   "label": "Payables"
+  },
+  {
+   "fieldname": "section_break_10",
+   "fieldtype": "Section Break",
+   "label": "Receivables"
+  },
+  {
+   "fieldname": "assets_allocated",
+   "fieldtype": "Table",
+   "options": "Full and Final Asset"
+  },
+  {
+   "fetch_from": "employee.relieving_date",
+   "fieldname": "relieving_date",
+   "fieldtype": "Date",
+   "label": "Relieving Date ",
+   "read_only": 1,
+   "reqd": 1
+  },
+  {
+   "fetch_from": "employee.date_of_joining",
+   "fieldname": "date_of_joining",
+   "fieldtype": "Date",
+   "label": "Date of Joining",
+   "read_only": 1
+  },
+  {
+   "fieldname": "section_break_15",
+   "fieldtype": "Section Break",
+   "label": "Assets Allocated"
+  },
+  {
+   "fetch_from": "employee.company",
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "in_standard_filter": 1,
+   "label": "Company",
+   "options": "Company",
+   "read_only": 1
+  },
+  {
+   "fieldname": "column_break_12",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "payables",
+   "fieldtype": "Table",
+   "options": "Full and Final Outstanding Statement"
+  },
+  {
+   "fieldname": "receivables",
+   "fieldtype": "Table",
+   "options": "Full and Final Outstanding Statement"
+  },
+  {
+   "fieldname": "employee_details_section",
+   "fieldtype": "Section Break",
+   "label": "Employee Details"
+  },
+  {
+   "fieldname": "transaction_date",
+   "fieldtype": "Date",
+   "in_standard_filter": 1,
+   "label": "Transaction Date",
+   "reqd": 1
+  },
+  {
+   "fieldname": "totals_section",
+   "fieldtype": "Section Break",
+   "label": "Totals"
+  },
+  {
+   "fieldname": "total_payable_amount",
+   "fieldtype": "Currency",
+   "in_list_view": 1,
+   "label": "Total Payable Amount",
+   "read_only": 1
+  },
+  {
+   "fieldname": "column_break_21",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "total_receivable_amount",
+   "fieldtype": "Currency",
+   "in_list_view": 1,
+   "label": "Total Receivable Amount",
+   "read_only": 1
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2021-08-30 21:11:09.892560",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Full and Final Statement",
+ "owner": "Administrator",
+ "permissions": [
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "HR User",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "HR Manager",
+   "share": 1,
+   "write": 1
+  }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "employee_name",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement.py b/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement.py
new file mode 100644
index 0000000..4c98cf1
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement.py
@@ -0,0 +1,176 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+import frappe
+from frappe import _
+from frappe.utils import get_link_to_form, today, flt
+from frappe.model.document import Document
+
+class FullandFinalStatement(Document):
+	def validate(self):
+		self.get_outstanding_statements()
+		if self.docstatus == 1:
+			self.validate_settlement("payables")
+			self.validate_settlement("receivables")
+			self.validate_asset()
+
+	def validate_settlement(self, component_type):
+		for data in self.get(component_type, []):
+			if data.status == "Unsettled":
+				frappe.throw(_("Settle all Payables and Receivables before submission"))
+
+	def validate_asset(self):
+		for data in self.assets_allocated:
+			if data.status == "Owned":
+				frappe.throw(_("All allocated assets should be returned before submission"))
+
+	@frappe.whitelist()
+	def get_outstanding_statements(self):
+		if self.relieving_date:
+			if not len(self.get("payables", [])):
+				components = self.get_payable_component()
+				self.create_component_row(components, "payables")
+			if not len(self.get("receivables", [])):
+				components = self.get_receivable_component()
+				self.create_component_row(components, "receivables")
+
+			if not len(self.get("assets_allocated", [])):
+				for data in self.get_assets_movement():
+					self.append("assets_allocated", data)
+		else:
+			frappe.throw(_("Set Relieving Date for Employee: {0}").format(get_link_to_form("Employee", self.employee)))
+
+	def create_component_row(self, components, component_type):
+		for component in components:
+			self.append(component_type, {
+				"status": "Unsettled",
+				"reference_document_type": component if component != "Bonus" else "Additional Salary",
+				"component": component
+			})
+
+
+	def get_payable_component(self):
+		return [
+			"Salary Slip",
+			"Gratuity",
+			"Expense Claim",
+			"Bonus",
+			"Leave Encashment",
+		]
+
+	def get_receivable_component(self):
+		return [
+			"Loan",
+			"Employee Advance",
+		]
+
+	def get_assets_movement(self):
+		asset_movements = frappe.get_all("Asset Movement Item",
+			filters = {"docstatus": 1},
+			fields = ["asset", "from_employee", "to_employee", "parent", "asset_name"],
+			or_filters = {
+				"from_employee": self.employee,
+				"to_employee": self.employee
+			}
+		)
+
+		data = []
+		inward_movements = []
+		outward_movements = []
+		for movement in asset_movements:
+			if movement.to_employee and movement.to_employee == self.employee:
+				inward_movements.append(movement)
+
+			if movement.from_employee and movement.from_employee == self.employee:
+				outward_movements.append(movement)
+
+		for movement in inward_movements:
+			outwards_count = [movement.asset for movement in outward_movements].count(movement.asset)
+			inwards_counts = [movement.asset for movement in inward_movements].count(movement.asset)
+
+			if inwards_counts > outwards_count:
+				data.append({
+					"reference": movement.parent,
+					"asset_name": movement.asset_name,
+					"date": frappe.db.get_value("Asset Movement", movement.parent, "transaction_date"),
+					"status": "Owned"
+				})
+		return data
+
+	@frappe.whitelist()
+	def create_journal_entry(self):
+		precision = frappe.get_precision("Journal Entry Account", "debit_in_account_currency")
+		jv = frappe.new_doc("Journal Entry")
+		jv.company = self.company
+		jv.voucher_type = "Bank Entry"
+		jv.posting_date = today()
+
+		difference = self.total_payable_amount - self.total_receivable_amount
+
+		for data in self.payables:
+			if data.amount > 0 and not data.paid_via_salary_slip:
+				account_dict = {
+					"account": data.account,
+					"debit_in_account_currency": flt(data.amount, precision)
+				}
+				if data.reference_document_type == "Expense Claim":
+					account_dict["party_type"] = "Employee"
+					account_dict["party"] = self.employee
+
+				jv.append("accounts", account_dict)
+
+		for data in self.receivables:
+			if data.amount > 0:
+				account_dict = {
+					"account": data.account,
+					"credit_in_account_currency": flt(data.amount, precision)
+				}
+				if data.reference_document_type == "Employee Advance":
+					account_dict["party_type"] = "Employee"
+					account_dict["party"] = self.employee
+
+				jv.append("accounts", account_dict)
+
+		jv.append("accounts", {
+			"credit_in_account_currency": difference if difference > 0 else 0,
+			"debit_in_account_currency": -(difference) if difference < 0 else 0,
+			"reference_type": self.doctype,
+			"reference_name": self.name
+		})
+		return jv
+
+@frappe.whitelist()
+def get_account_and_amount(ref_doctype, ref_document):
+	if not ref_doctype or not ref_document:
+		return None
+
+	if ref_doctype == "Salary Slip":
+		salary_details = frappe.db.get_value("Salary Slip", ref_document, ["payroll_entry", "net_pay"], as_dict=1)
+		amount = salary_details.net_pay
+		payable_account = frappe.db.get_value("Payroll Entry", salary_details.payroll_entry, "payroll_payable_account") if salary_details.payroll_entry else None
+		return [payable_account, amount]
+
+	if ref_doctype == "Gratuity":
+		payable_account, amount = frappe.db.get_value("Gratuity", ref_document, ["payable_account", "amount"])
+		return [payable_account, amount]
+
+	if ref_doctype == "Expense Claim":
+		details = frappe.db.get_value("Expense Claim", ref_document,
+			["payable_account", "grand_total", "total_amount_reimbursed", "total_advance_amount"], as_dict=True)
+		payable_account = details.payable_account
+		amount = details.grand_total - (details.total_amount_reimbursed + details.total_advance_amount)
+		return [payable_account, amount]
+
+	if ref_doctype == "Loan":
+		details = frappe.db.get_value("Loan", ref_document,
+			["payment_account", "total_payment", "total_amount_paid"], as_dict=1)
+		payment_account = details.payment_account
+		amount = details.total_payment - details.total_amount_paid
+		return [payment_account, amount]
+
+	if ref_doctype == "Employee Advance":
+		details = frappe.db.get_value("Employee Advance", ref_document,
+			["advance_account","paid_amount", "claimed_amount", "return_amount"], as_dict = 1)
+		payment_account = details.advance_account
+		amount = details.paid_amount - (details.claimed_amount + details.return_amount)
+		return [payment_account, amount]
diff --git a/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement_list.js b/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement_list.js
new file mode 100644
index 0000000..4aedec7
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement_list.js
@@ -0,0 +1,11 @@
+frappe.listview_settings["Full and Final Statement"] = {
+	get_indicator: function(doc) {
+		var colors = {
+			"Draft": "red",
+			"Unpaid": "orange",
+			"Paid": "green",
+			"Cancelled": "red"
+		};
+		return [__(doc.status), colors[doc.status], "status,=," + doc.status];
+	}
+};
diff --git a/erpnext/hr/doctype/full_and_final_statement/test_full_and_final_statement.py b/erpnext/hr/doctype/full_and_final_statement/test_full_and_final_statement.py
new file mode 100644
index 0000000..8ecc129
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_statement/test_full_and_final_statement.py
@@ -0,0 +1,71 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+
+import frappe
+from erpnext.hr.doctype.employee.test_employee import make_employee
+from erpnext.assets.doctype.asset.test_asset import create_asset_data
+from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
+from frappe.utils import today, add_days
+import unittest
+
+class TestFullandFinalStatement(unittest.TestCase):
+
+	def setUp(self):
+		create_asset_data()
+
+	def tearDown(self):
+		frappe.db.sql("Delete from `tabFull and Final Statement`")
+		frappe.db.sql("Delete from `tabAsset`")
+		frappe.db.sql("Delete from `tabAsset Movement`")
+
+	def test_check_bootstraped_data_asset_movement_and_jv_creation(self):
+		employee = make_employee("test_fnf@example.com", company="_Test Company")
+		movement = create_asset_movement(employee)
+		frappe.db.set_value("Employee", employee, "relieving_date", add_days(today(), 30))
+		fnf = create_full_and_final_statement(employee)
+
+		payables_bootstraped_component = ["Salary Slip", "Gratuity",
+			"Expense Claim", "Bonus", "Leave Encashment"]
+
+		receivable_bootstraped_component = ["Loan", "Employee Advance"]
+
+		#checking payable s and receivables bootstraped value
+		self.assertEqual([payable.component for payable in fnf.payables], payables_bootstraped_component)
+		self.assertEqual([receivable.component for receivable in fnf.receivables], receivable_bootstraped_component)
+
+		#checking allocated asset
+		self.assertIn(movement, [asset.reference for asset in fnf.assets_allocated])
+
+def create_full_and_final_statement(employee):
+	fnf = frappe.new_doc("Full and Final Statement")
+	fnf.employee = employee
+	fnf.transaction_date = today()
+	fnf.save()
+	return fnf
+
+def create_asset_movement(employee):
+	asset_name = create_asset()
+	movement = frappe.new_doc("Asset Movement")
+	movement.company = "_Test Company"
+	movement.purpose = "Issue"
+	movement.transaction_date = today()
+
+	movement.append("assets", {
+		"asset": asset_name,
+		"to_employee": employee
+	})
+
+	movement.save()
+	movement.submit()
+	return movement.name
+
+def create_asset():
+	pr = make_purchase_receipt(item_code="Macbook Pro",
+			qty=1, rate=100000.0, location="Test Location")
+
+	asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, "name")
+	asset = frappe.get_doc("Asset", asset_name)
+	asset.calculate_depreciation = 0
+	asset.available_for_use_date = today()
+	asset.submit()
+	return asset_name
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 93fb19f..2e37c13 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -662,26 +662,30 @@
 
 @frappe.whitelist()
 def get_events(start, end, filters=None):
+	from frappe.desk.reportview import get_filters_cond
 	events = []
 
-	employee = frappe.db.get_value("Employee", {"user_id": frappe.session.user}, ["name", "company"],
-		as_dict=True)
+	employee = frappe.db.get_value("Employee",
+		filters={"user_id": frappe.session.user},
+		fieldname=["name", "company"],
+		as_dict=True
+	)
+
 	if employee:
 		employee, company = employee.name, employee.company
 	else:
-		employee=''
-		company=frappe.db.get_value("Global Defaults", None, "default_company")
+		employee = ''
+		company = frappe.db.get_value("Global Defaults", None, "default_company")
 
-	from frappe.desk.reportview import get_filters_cond
 	conditions = get_filters_cond("Leave Application", filters, [])
 	# show department leaves for employee
 	if "Employee" in frappe.get_roles():
 		add_department_leaves(events, start, end, employee, company)
 
 	add_leaves(events, start, end, conditions)
-
 	add_block_dates(events, start, end, employee, company)
 	add_holidays(events, start, end, employee, company)
+
 	return events
 
 def add_department_leaves(events, start, end, employee, company):
@@ -697,26 +701,37 @@
 	filter_conditions = " and employee in (\"%s\")" % '", "'.join(department_employees)
 	add_leaves(events, start, end, filter_conditions=filter_conditions)
 
+
 def add_leaves(events, start, end, filter_conditions=None):
+	from frappe.desk.reportview import build_match_conditions
 	conditions = []
 
-
 	if not cint(frappe.db.get_value("HR Settings", None, "show_leaves_of_all_department_members_in_calendar")):
-		from frappe.desk.reportview import build_match_conditions
 		match_conditions = build_match_conditions("Leave Application")
 
 		if match_conditions:
 			conditions.append(match_conditions)
 
-	query = """select name, from_date, to_date, employee_name, half_day,
-		status, employee, docstatus
-		from `tabLeave Application` where
-		from_date <= %(end)s and to_date >= %(start)s <= to_date
-		and docstatus < 2
-		and status!='Rejected' """
+	query = """SELECT
+		docstatus,
+		name,
+		employee,
+		employee_name,
+		leave_type,
+		from_date,
+		to_date,
+		half_day,
+		status,
+		color
+	FROM `tabLeave Application`
+	WHERE
+		from_date <= %(end)s AND to_date >= %(start)s <= to_date
+		AND docstatus < 2
+		AND status != 'Rejected'
+	"""
 
 	if conditions:
-		query += ' and ' + ' and '.join(conditions)
+		query += ' AND ' + ' AND '.join(conditions)
 
 	if filter_conditions:
 		query += filter_conditions
@@ -729,11 +744,13 @@
 			"to_date": d.to_date,
 			"docstatus": d.docstatus,
 			"color": d.color,
-			"title": cstr(d.employee_name) + (' ' + _('(Half Day)') if d.half_day else ''),
+			"all_day": int(not d.half_day),
+			"title": cstr(d.employee_name) + f' ({cstr(d.leave_type)})' + (' ' + _('(Half Day)') if d.half_day else ''),
 		}
 		if e not in events:
 			events.append(e)
 
+
 def add_block_dates(events, start, end, employee, company):
 	# block days
 	from erpnext.hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates
diff --git a/erpnext/hr/doctype/leave_application/leave_application_calendar.js b/erpnext/hr/doctype/leave_application/leave_application_calendar.js
index 31faadb..0ba0285 100644
--- a/erpnext/hr/doctype/leave_application/leave_application_calendar.js
+++ b/erpnext/hr/doctype/leave_application/leave_application_calendar.js
@@ -7,7 +7,9 @@
 		"end": "to_date",
 		"id": "name",
 		"title": "title",
-		"docstatus": 1
+		"docstatus": 1,
+		"color": "color",
+		"allDay": "all_day"
 	},
 	options: {
 		header: {
diff --git a/erpnext/hr/workspace/hr/hr.json b/erpnext/hr/workspace/hr/hr.json
index 575fa7b..9c5d0c1 100644
--- a/erpnext/hr/workspace/hr/hr.json
+++ b/erpnext/hr/workspace/hr/hr.json
@@ -224,6 +224,17 @@
    "type": "Link"
   },
   {
+   "dependencies": "Employee",
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Full and Final Statement",
+   "link_count": 0,
+   "link_to": "Full and Final Statement",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
    "hidden": 0,
    "is_query_report": 0,
    "label": "Shift Management",
@@ -931,7 +942,7 @@
    "type": "Link"
   }
  ],
- "modified": "2021-08-05 12:15:59.842918",
+ "modified": "2021-08-31 12:18:59.842918",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "HR",
diff --git a/erpnext/payroll/doctype/gratuity/gratuity.js b/erpnext/payroll/doctype/gratuity/gratuity.js
index 377f3c6..d4f7c9c 100644
--- a/erpnext/payroll/doctype/gratuity/gratuity.js
+++ b/erpnext/payroll/doctype/gratuity/gratuity.js
@@ -3,13 +3,6 @@
 
 frappe.ui.form.on('Gratuity', {
 	setup: function (frm) {
-		frm.set_query('salary_component', function () {
-			return {
-				filters: {
-					type: "Earning"
-				}
-			};
-		});
 		frm.set_query("expense_account", function () {
 			return {
 				filters: {
@@ -31,7 +24,7 @@
 		});
 	},
 	refresh: function (frm) {
-		if (frm.doc.docstatus === 1 && frm.doc.pay_via_salary_slip === 0 && frm.doc.status === "Unpaid") {
+		if (frm.doc.docstatus == 1 && frm.doc.status == "Unpaid") {
 			frm.add_custom_button(__("Create Payment Entry"), function () {
 				return frappe.call({
 					method: 'erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry',
diff --git a/erpnext/payroll/doctype/gratuity/gratuity.json b/erpnext/payroll/doctype/gratuity/gratuity.json
index 5cffd7e..48a9ce4 100644
--- a/erpnext/payroll/doctype/gratuity/gratuity.json
+++ b/erpnext/payroll/doctype/gratuity/gratuity.json
@@ -16,9 +16,6 @@
   "company",
   "gratuity_rule",
   "section_break_5",
-  "pay_via_salary_slip",
-  "payroll_date",
-  "salary_component",
   "payable_account",
   "expense_account",
   "mode_of_payment",
@@ -50,26 +47,12 @@
    "reqd": 1
   },
   {
-   "default": "1",
-   "fieldname": "pay_via_salary_slip",
-   "fieldtype": "Check",
-   "label": "Pay via Salary Slip"
-  },
-  {
    "fieldname": "posting_date",
    "fieldtype": "Date",
    "label": "Posting date",
    "reqd": 1
   },
   {
-   "depends_on": "eval: doc.pay_via_salary_slip == 1",
-   "fieldname": "salary_component",
-   "fieldtype": "Link",
-   "label": "Salary Component",
-   "mandatory_depends_on": "eval: doc.pay_via_salary_slip == 1",
-   "options": "Salary Component"
-  },
-  {
    "default": "0",
    "fieldname": "current_work_experience",
    "fieldtype": "Int",
@@ -95,20 +78,18 @@
    "reqd": 1
   },
   {
-   "depends_on": "eval: doc.pay_via_salary_slip == 0",
    "fieldname": "expense_account",
    "fieldtype": "Link",
    "label": "Expense Account",
-   "mandatory_depends_on": "eval: doc.pay_via_salary_slip == 0",
-   "options": "Account"
+   "options": "Account",
+   "reqd": 1
   },
   {
-   "depends_on": "eval: doc.pay_via_salary_slip == 0",
    "fieldname": "mode_of_payment",
    "fieldtype": "Link",
    "label": "Mode of Payment",
-   "mandatory_depends_on": "eval: doc.pay_via_salary_slip == 0",
-   "options": "Mode of Payment"
+   "options": "Mode of Payment",
+   "reqd": 1
   },
   {
    "fieldname": "gratuity_rule",
@@ -162,13 +143,6 @@
    "fieldtype": "Column Break"
   },
   {
-   "depends_on": "eval: doc.pay_via_salary_slip == 1",
-   "fieldname": "payroll_date",
-   "fieldtype": "Date",
-   "label": "Payroll Date",
-   "mandatory_depends_on": "eval: doc.pay_via_salary_slip == 1"
-  },
-  {
    "default": "0",
    "depends_on": "eval:doc.pay_via_salary_slip == 0",
    "fieldname": "paid_amount",
@@ -177,26 +151,23 @@
    "read_only": 1
   },
   {
-   "depends_on": "eval: doc.pay_via_salary_slip == 0",
    "fieldname": "payable_account",
    "fieldtype": "Link",
    "label": "Payable Account",
-   "mandatory_depends_on": "eval: doc.pay_via_salary_slip == 0",
-   "options": "Account"
+   "options": "Account",
+   "reqd": 1
   },
   {
-   "depends_on": "eval: doc.pay_via_salary_slip == 0",
    "fieldname": "cost_center",
    "fieldtype": "Link",
    "label": "Cost Center",
-   "mandatory_depends_on": "eval: doc.pay_via_salary_slip == 0",
    "options": "Cost Center"
   }
  ],
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-11-02 18:21:11.971488",
+ "modified": "2021-07-02 15:05:57.396398",
  "modified_by": "Administrator",
  "module": "Payroll",
  "name": "Gratuity",
diff --git a/erpnext/payroll/doctype/gratuity/gratuity.py b/erpnext/payroll/doctype/gratuity/gratuity.py
index 8cb804d..8217bc3 100644
--- a/erpnext/payroll/doctype/gratuity/gratuity.py
+++ b/erpnext/payroll/doctype/gratuity/gratuity.py
@@ -19,10 +19,7 @@
 			self.status = "Unpaid"
 
 	def on_submit(self):
-		if self.pay_via_salary_slip:
-			self.create_additional_salary()
-		else:
-			self.create_gl_entries()
+		self.create_gl_entries()
 
 	def on_cancel(self):
 		self.ignore_linked_doctypes = ['GL Entry']
@@ -65,19 +62,6 @@
 
 		return gl_entry
 
-	def create_additional_salary(self):
-		if self.pay_via_salary_slip:
-			additional_salary = frappe.new_doc('Additional Salary')
-			additional_salary.employee = self.employee
-			additional_salary.salary_component = self.salary_component
-			additional_salary.overwrite_salary_structure_amount = 0
-			additional_salary.amount = self.amount
-			additional_salary.payroll_date = self.payroll_date
-			additional_salary.company = self.company
-			additional_salary.ref_doctype = self.doctype
-			additional_salary.ref_docname = self.name
-			additional_salary.submit()
-
 	def set_total_advance_paid(self):
 		paid_amount = frappe.db.sql("""
 			select ifnull(sum(debit_in_account_currency), 0) as paid_amount
@@ -242,7 +226,11 @@
 		order_by = "from_date desc")[0].salary_structure
 
 def get_last_salary_slip(employee):
-	return frappe.get_list("Salary Slip", filters = {
+	salary_slips = frappe.get_list("Salary Slip", filters = {
 			"employee": employee, 'docstatus': 1
 		},
-		order_by = "start_date desc")[0].name
+		order_by = "start_date desc"
+	)
+	if not salary_slips:
+		return
+	return salary_slips[0].name
diff --git a/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py b/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py
index 483e346..23c99b1 100644
--- a/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py
+++ b/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py
@@ -11,10 +11,6 @@
 			{
 				'label': _('Payment'),
 				'items': ['Payment Entry']
-			},
-			{
-				'label': _('Additional Salary'),
-				'items': ['Additional Salary']
 			}
 		]
 	}
diff --git a/erpnext/payroll/doctype/gratuity/test_gratuity.py b/erpnext/payroll/doctype/gratuity/test_gratuity.py
index 7daea2d..8cb4728 100644
--- a/erpnext/payroll/doctype/gratuity/test_gratuity.py
+++ b/erpnext/payroll/doctype/gratuity/test_gratuity.py
@@ -22,14 +22,18 @@
 
 	def setUp(self):
 		frappe.db.sql("DELETE FROM `tabGratuity`")
-		frappe.db.sql("DELETE FROM `tabAdditional Salary` WHERE ref_doctype = 'Gratuity'")
 
-	def test_check_gratuity_amount_based_on_current_slab_and_additional_salary_creation(self):
+	def test_get_last_salary_slip_should_return_none_for_new_employee(self):
+		new_employee = make_employee("new_employee@salary.com", company='_Test Company')
+		salary_slip = get_last_salary_slip(new_employee)
+		assert salary_slip is None
+
+	def test_check_gratuity_amount_based_on_current_slab(self):
 		employee, sal_slip = create_employee_and_get_last_salary_slip()
 
 		rule = get_gratuity_rule("Rule Under Unlimited Contract on termination (UAE)")
 
-		gratuity = create_gratuity(pay_via_salary_slip = 1, employee=employee, rule=rule.name)
+		gratuity = create_gratuity(employee=employee, rule=rule.name)
 
 		#work experience calculation
 		date_of_joining, relieving_date = frappe.db.get_value('Employee', employee, ['date_of_joining', 'relieving_date'])
@@ -57,9 +61,6 @@
 
 		self.assertEqual(flt(gratuity_amount, 2), flt(gratuity.amount, 2))
 
-		#additional salary creation (Pay via salary slip)
-		self.assertTrue(frappe.db.exists("Additional Salary", {"ref_docname": gratuity.name}))
-
 	def test_check_gratuity_amount_based_on_all_previous_slabs(self):
 		employee, sal_slip = create_employee_and_get_last_salary_slip()
 		rule = get_gratuity_rule("Rule Under Limited Contract (UAE)")
@@ -137,14 +138,9 @@
 	gratuity.employee = args.employee
 	gratuity.posting_date = getdate()
 	gratuity.gratuity_rule = args.rule or "Rule Under Limited Contract (UAE)"
-	gratuity.pay_via_salary_slip = args.pay_via_salary_slip or 0
-	if gratuity.pay_via_salary_slip:
-		gratuity.payroll_date = getdate()
-		gratuity.salary_component = "Performance Bonus"
-	else:
-		gratuity.expense_account =  args.expense_account or 'Payment Account - _TC'
-		gratuity.payable_account = args.payable_account or get_payable_account("_Test Company")
-		gratuity.mode_of_payment = args.mode_of_payment or 'Cash'
+	gratuity.expense_account = args.expense_account or 'Payment Account - _TC'
+	gratuity.payable_account = args.payable_account or get_payable_account("_Test Company")
+	gratuity.mode_of_payment = args.mode_of_payment or 'Cash'
 
 	gratuity.save()
 	gratuity.submit()
diff --git a/erpnext/public/build.json b/erpnext/public/build.json
index 3c60e3e..6b70dab 100644
--- a/erpnext/public/build.json
+++ b/erpnext/public/build.json
@@ -38,6 +38,7 @@
 		"public/js/templates/item_quick_entry.html",
 		"public/js/utils/item_quick_entry.js",
 		"public/js/utils/customer_quick_entry.js",
+		"public/js/utils/supplier_quick_entry.js",
 		"public/js/education/student_button.html",
 		"public/js/education/assessment_result_tool.html",
 		"public/js/hub/hub_factory.js",
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 2538852..5f8966f 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -866,21 +866,25 @@
 
 		if (frappe.meta.get_docfield(this.frm.doctype, "shipping_address") &&
 			in_list(['Purchase Order', 'Purchase Receipt', 'Purchase Invoice'], this.frm.doctype)) {
-			erpnext.utils.get_shipping_address(this.frm, function(){
+			erpnext.utils.get_shipping_address(this.frm, function() {
 				set_party_account(set_pricing);
 			});
 
 			// Get default company billing address in Purchase Invoice, Order and Receipt
-			frappe.call({
-				'method': 'frappe.contacts.doctype.address.address.get_default_address',
-				'args': {
-					'doctype': 'Company',
-					'name': this.frm.doc.company
-				},
-				'callback': function(r) {
-					me.frm.set_value('billing_address', r.message);
-				}
-			});
+			if (this.frm.doc.company && frappe.meta.get_docfield(this.frm.doctype, "billing_address")) {
+				frappe.call({
+					method: "erpnext.setup.doctype.company.company.get_default_company_address",
+					args: {name: this.frm.doc.company, existing_address: this.frm.doc.billing_address || ""},
+					debounce: 2000,
+					callback: function(r) {
+						if (r.message) {
+							me.frm.set_value("billing_address", r.message);
+						} else {
+							me.frm.set_value("company_address", "");
+						}
+					}
+				});
+			}
 
 		} else {
 			set_party_account(set_pricing);
diff --git a/erpnext/public/js/erpnext.bundle.js b/erpnext/public/js/erpnext.bundle.js
index 9f7f29a..febdb24 100644
--- a/erpnext/public/js/erpnext.bundle.js
+++ b/erpnext/public/js/erpnext.bundle.js
@@ -15,6 +15,7 @@
 import "./templates/item_quick_entry.html";
 import "./utils/item_quick_entry";
 import "./utils/customer_quick_entry";
+import "./utils/supplier_quick_entry";
 import "./education/student_button.html";
 import "./education/assessment_result_tool.html";
 import "./hub/hub_factory";
diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js
index 4d432e3..a492b32 100644
--- a/erpnext/public/js/utils/party.js
+++ b/erpnext/public/js/utils/party.js
@@ -289,8 +289,8 @@
 				company: frm.doc.company,
 				address: frm.doc.shipping_address
 			},
-			callback: function(r){
-				if (r.message){
+			callback: function(r) {
+				if (r.message) {
 					frm.set_value("shipping_address", r.message[0]) //Address title or name
 					frm.set_value("shipping_address_display", r.message[1]) //Address to be displayed on the page
 				}
diff --git a/erpnext/public/js/utils/supplier_quick_entry.js b/erpnext/public/js/utils/supplier_quick_entry.js
new file mode 100644
index 0000000..8d591a9
--- /dev/null
+++ b/erpnext/public/js/utils/supplier_quick_entry.js
@@ -0,0 +1,77 @@
+frappe.provide('frappe.ui.form');
+
+frappe.ui.form.SupplierQuickEntryForm = class SupplierQuickEntryForm extends frappe.ui.form.QuickEntryForm {
+	constructor(doctype, after_insert, init_callback, doc, force) {
+		super(doctype, after_insert, init_callback, doc, force);
+		this.skip_redirect_on_error = true;
+	}
+
+	render_dialog() {
+		this.mandatory = this.mandatory.concat(this.get_variant_fields());
+		super.render_dialog();
+	}
+
+	get_variant_fields() {
+		var variant_fields = [
+			{
+				fieldtype: "Section Break",
+				label: __("Primary Contact Details"),
+				collapsible: 1
+			},
+			{
+				label: __("Email Id"),
+				fieldname: "email_id",
+				fieldtype: "Data"
+			},
+			{
+				fieldtype: "Column Break"
+			},
+			{
+				label: __("Mobile Number"),
+				fieldname: "mobile_no",
+				fieldtype: "Data"
+			},
+			{
+				fieldtype: "Section Break",
+				label: __("Primary Address Details"),
+				collapsible: 1
+			},
+			{
+				label: __("Address Line 1"),
+				fieldname: "address_line1",
+				fieldtype: "Data"
+			},
+			{
+				label: __("Address Line 2"),
+				fieldname: "address_line2",
+				fieldtype: "Data"
+			},
+			{
+				label: __("ZIP Code"),
+				fieldname: "pincode",
+				fieldtype: "Data"
+			},
+			{
+				fieldtype: "Column Break"
+			},
+			{
+				label: __("City"),
+				fieldname: "city",
+				fieldtype: "Data"
+			},
+			{
+				label: __("State"),
+				fieldname: "state",
+				fieldtype: "Data"
+			},
+			{
+				label: __("Country"),
+				fieldname: "country",
+				fieldtype: "Link",
+				options: "Country"
+			}
+		];
+
+		return variant_fields;
+	}
+};
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index abf146c..1164f40 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -150,8 +150,14 @@
 				self.db_set('email_id', self.email_id)
 
 	def create_primary_address(self):
+		from frappe.contacts.doctype.address.address import get_address_display
+
 		if self.flags.is_new_doc and self.get('address_line1'):
-			make_address(self)
+			address = make_address(self)
+			address_display = get_address_display(address.name)
+
+			self.db_set("customer_primary_address", address.name)
+			self.db_set("primary_address", address_display)
 
 	def update_lead_status(self):
 		'''If Customer created from Lead, update lead status to "Converted"
@@ -246,9 +252,15 @@
 
 	def on_trash(self):
 		if self.customer_primary_contact:
-			frappe.db.sql("""update `tabCustomer`
-				set customer_primary_contact=null, mobile_no=null, email_id=null
-				where name=%s""", self.name)
+			frappe.db.sql("""
+				UPDATE `tabCustomer`
+				SET
+					customer_primary_contact=null,
+					customer_primary_address=null,
+					mobile_no=null,
+					email_id=null,
+					primary_address=null
+				WHERE name=%(name)s""", {"name": self.name})
 
 		delete_contact_and_address('Customer', self.name)
 		if self.lead_name:
diff --git a/erpnext/setup/doctype/currency_exchange/test_currency_exchange.py b/erpnext/setup/doctype/currency_exchange/test_currency_exchange.py
index 4ff2dd7..0eb7e7b 100644
--- a/erpnext/setup/doctype/currency_exchange/test_currency_exchange.py
+++ b/erpnext/setup/doctype/currency_exchange/test_currency_exchange.py
@@ -1,14 +1,14 @@
 # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
 # License: GNU General Public License v3. See license.txt
-from __future__ import unicode_literals
+
 import frappe, unittest
+from unittest import mock
 from frappe.utils import flt
 from erpnext.setup.utils import get_exchange_rate
 from frappe.utils import cint
 
 test_records = frappe.get_test_records('Currency Exchange')
 
-
 def save_new_records(test_records):
 	for record in test_records:
 		# If both selling and buying enabled
@@ -37,18 +37,45 @@
 			curr_exchange.for_selling = record["for_selling"]
 			curr_exchange.insert()
 
+test_exchange_values = {
+	'2015-12-15': '66.999',
+	'2016-01-15': '65.1'
+}
 
+# Removing API call from get_exchange_rate
+def patched_requests_get(*args, **kwargs):
+	class PatchResponse:
+		def __init__(self, json_data, status_code):
+			self.json_data = json_data
+			self.status_code = status_code
+
+		def raise_for_status(self):
+			if self.status_code != 200:
+				raise frappe.DoesNotExistError
+
+		def json(self):
+			return self.json_data
+
+	if args[0] == "https://api.exchangerate.host/convert" and kwargs.get('params'):
+		if kwargs['params'].get('date') and kwargs['params'].get('from') and kwargs['params'].get('to'):
+			if test_exchange_values.get(kwargs['params']['date']):
+				return PatchResponse({'result': test_exchange_values[kwargs['params']['date']]}, 200)
+
+	return PatchResponse({'result': None}, 404)
+
+@mock.patch('requests.get', side_effect=patched_requests_get)
 class TestCurrencyExchange(unittest.TestCase):
 	def clear_cache(self):
 		cache = frappe.cache()
-		key = "currency_exchange_rate:{0}:{1}".format("USD", "INR")
-		cache.delete(key)
+		for date in test_exchange_values.keys():
+			key = "currency_exchange_rate_{0}:{1}:{2}".format(date, "USD", "INR")
+			cache.delete(key)
 
 	def tearDown(self):
 		frappe.db.set_value("Accounts Settings", None, "allow_stale", 1)
 		self.clear_cache()
 
-	def test_exchange_rate(self):
+	def test_exchange_rate(self, mock_get):
 		save_new_records(test_records)
 
 		frappe.db.set_value("Accounts Settings", None, "allow_stale", 1)
@@ -69,7 +96,11 @@
 		self.assertFalse(exchange_rate == 60)
 		self.assertEqual(flt(exchange_rate, 3), 66.999)
 
-	def test_exchange_rate_strict(self):
+		exchange_rate = get_exchange_rate("USD", "INR", "2016-01-20", "for_buying")
+		self.assertFalse(exchange_rate == 60)
+		self.assertEqual(flt(exchange_rate, 3), 65.1)
+
+	def test_exchange_rate_strict(self, mock_get):
 		# strict currency settings
 		frappe.db.set_value("Accounts Settings", None, "allow_stale", 0)
 		frappe.db.set_value("Accounts Settings", None, "stale_days", 1)
@@ -79,7 +110,7 @@
 
 		self.clear_cache()
 		exchange_rate = get_exchange_rate("USD", "INR", "2016-01-15", "for_buying")
-		self.assertEqual(flt(exchange_rate, 3), 67.235)
+		self.assertEqual(flt(exchange_rate, 3), 65.100)
 
 		exchange_rate = get_exchange_rate("USD", "INR", "2016-01-30", "for_selling")
 		self.assertEqual(exchange_rate, 62.9)
@@ -89,7 +120,7 @@
 		exchange_rate = get_exchange_rate("USD", "INR", "2015-12-15", "for_buying")
 		self.assertEqual(flt(exchange_rate, 3), 66.999)
 
-	def test_exchange_rate_strict_switched(self):
+	def test_exchange_rate_strict_switched(self, mock_get):
 		# Start with allow_stale is True
 		exchange_rate = get_exchange_rate("USD", "INR", "2016-01-15", "for_buying")
 		self.assertEqual(exchange_rate, 65.1)
@@ -97,7 +128,7 @@
 		frappe.db.set_value("Accounts Settings", None, "allow_stale", 0)
 		frappe.db.set_value("Accounts Settings", None, "stale_days", 1)
 
-		# Will fetch from fixer.io
 		self.clear_cache()
-		exchange_rate = get_exchange_rate("USD", "INR", "2016-01-15", "for_buying")
-		self.assertEqual(flt(exchange_rate, 3), 67.235)
+		exchange_rate = get_exchange_rate("USD", "INR", "2016-01-30", "for_buying")
+		self.assertFalse(exchange_rate == 65)
+		self.assertEqual(flt(exchange_rate, 3), 62.9)
diff --git a/erpnext/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py
index 6fbd4cd..217829f 100644
--- a/erpnext/setup/doctype/email_digest/email_digest.py
+++ b/erpnext/setup/doctype/email_digest/email_digest.py
@@ -60,9 +60,6 @@
 						reference_name = self.name,
 						unsubscribe_message = _("Unsubscribe from this Email Digest"))
 
-		frappe.set_user(original_user)
-		frappe.set_user_lang(original_user)
-
 	def get_msg_html(self):
 		"""Build email digest content"""
 		frappe.flags.ignore_account_permission = True
diff --git a/erpnext/stock/report/process_loss_report/process_loss_report.py b/erpnext/stock/report/process_loss_report/process_loss_report.py
index 7494328..3d48ebd 100644
--- a/erpnext/stock/report/process_loss_report/process_loss_report.py
+++ b/erpnext/stock/report/process_loss_report/process_loss_report.py
@@ -2,6 +2,7 @@
 # For license information, please see license.txt
 
 import frappe
+from frappe import _
 from typing import Dict, List, Tuple
 
 Filters = frappe._dict
@@ -24,57 +25,57 @@
 def get_columns() -> Columns:
 	return [
 		{
-			'label': 'Work Order',
+			'label': _('Work Order'),
 			'fieldname': 'name',
 			'fieldtype': 'Link',
 			'options': 'Work Order',
 			'width': '200'
 		},
 		{
-			'label': 'Item',
+			'label': _('Item'),
 			'fieldname': 'production_item',
 			'fieldtype': 'Link',
 			'options': 'Item',
 			'width': '100'
 		},
 		{
-			'label': 'Status',
+			'label': _('Status'),
 			'fieldname': 'status',
 			'fieldtype': 'Data',
 			'width': '100'
 		},
 		{
-			'label': 'Manufactured Qty',
+			'label': _('Manufactured Qty'),
 			'fieldname': 'produced_qty',
 			'fieldtype': 'Float',
 			'width': '150'
 		},
 		{
-			'label': 'Loss Qty',
+			'label': _('Loss Qty'),
 			'fieldname': 'process_loss_qty',
 			'fieldtype': 'Float',
 			'width': '150'
 		},
 		{
-			'label': 'Actual Manufactured Qty',
+			'label': _('Actual Manufactured Qty'),
 			'fieldname': 'actual_produced_qty',
 			'fieldtype': 'Float',
 			'width': '150'
 		},
 		{
-			'label': 'Loss Value',
+			'label': _('Loss Value'),
 			'fieldname': 'total_pl_value',
 			'fieldtype': 'Float',
 			'width': '150'
 		},
 		{
-			'label': 'FG Value',
+			'label': _('FG Value'),
 			'fieldname': 'total_fg_value',
 			'fieldtype': 'Float',
 			'width': '150'
 		},
 		{
-			'label': 'Raw Material Value',
+			'label': _('Raw Material Value'),
 			'fieldname': 'total_rm_value',
 			'fieldtype': 'Float',
 			'width': '150'
diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.py b/erpnext/stock/report/stock_ageing/stock_ageing.py
index 623dc2f..8a9f0a5 100644
--- a/erpnext/stock/report/stock_ageing/stock_ageing.py
+++ b/erpnext/stock/report/stock_ageing/stock_ageing.py
@@ -26,7 +26,7 @@
 		average_age = get_average_age(fifo_queue, to_date)
 		earliest_age = date_diff(to_date, fifo_queue[0][1])
 		latest_age = date_diff(to_date, fifo_queue[-1][1])
-		range1, range2, range3, above_range3 = get_range_age(filters, fifo_queue, to_date)
+		range1, range2, range3, above_range3 = get_range_age(filters, fifo_queue, to_date, item_dict)
 
 		row = [details.name, details.item_name,
 			details.description, details.item_group, details.brand]
@@ -58,19 +58,21 @@
 
 	return flt(age_qty / total_qty, 2) if total_qty else 0.0
 
-def get_range_age(filters, fifo_queue, to_date):
+def get_range_age(filters, fifo_queue, to_date, item_dict):
 	range1 = range2 = range3 = above_range3 = 0.0
+
 	for item in fifo_queue:
 		age = date_diff(to_date, item[1])
+		qty = flt(item[0]) if not item_dict["has_serial_no"] else 1.0
 
 		if age <= filters.range1:
-			range1 += flt(item[0])
+			range1 += qty
 		elif age <= filters.range2:
-			range2 += flt(item[0])
+			range2 += qty
 		elif age <= filters.range3:
-			range3 += flt(item[0])
+			range3 += qty
 		else:
-			above_range3 += flt(item[0])
+			above_range3 += qty
 
 	return range1, range2, range3, above_range3
 
@@ -197,9 +199,7 @@
 					fifo_queue.append([d.actual_qty, d.posting_date])
 		else:
 			if serial_no_list:
-				for serial_no in fifo_queue:
-					if serial_no[0] in serial_no_list:
-						fifo_queue.remove(serial_no)
+				fifo_queue[:] = [serial_no for serial_no in fifo_queue if serial_no[0] not in serial_no_list]
 			else:
 				qty_to_pop = abs(d.actual_qty)
 				while qty_to_pop:
@@ -222,14 +222,16 @@
 		else:
 			item_details[key]["total_qty"] += d.actual_qty
 
+		item_details[key]["has_serial_no"] = d.has_serial_no
+
 	return item_details
 
 def get_stock_ledger_entries(filters):
 	return frappe.db.sql("""select
-			item.name, item.item_name, item_group, brand, description, item.stock_uom,
+			item.name, item.item_name, item_group, brand, description, item.stock_uom, item.has_serial_no,
 			actual_qty, posting_date, voucher_type, voucher_no, serial_no, batch_no, qty_after_transaction, warehouse
 		from `tabStock Ledger Entry` sle,
-			(select name, item_name, description, stock_uom, brand, item_group
+			(select name, item_name, description, stock_uom, brand, item_group, has_serial_no
 				from `tabItem` {item_conditions}) item
 		where item_code = item.name and
 			company = %(company)s and