Merge remote-tracking branch 'upstream/version-13-hotfix' into dev-quality-inspection-accounts
diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml
deleted file mode 100644
index 84ecfb1..0000000
--- a/.github/workflows/ci-tests.yml
+++ /dev/null
@@ -1,108 +0,0 @@
-name: CI
-
-on: [pull_request, workflow_dispatch, push]
-
-jobs:
-  test:
-    runs-on: ubuntu-18.04
-
-    strategy:
-      fail-fast: false
-
-      matrix:
-       include:
-        - TYPE: "server"
-          JOB_NAME: "Server"
-          RUN_COMMAND: cd ~/frappe-bench/ && bench --site test_site run-tests --app erpnext --coverage
-        - TYPE: "patch"
-          JOB_NAME: "Patch"
-          RUN_COMMAND: cd ~/frappe-bench/ && wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz &&  bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz && bench --site test_site migrate
-
-    name: ${{ matrix.JOB_NAME }}
-
-    services:
-      mysql:
-        image: mariadb:10.3
-        env:
-          MYSQL_ALLOW_EMPTY_PASSWORD: YES
-        ports:
-          - 3306:3306
-        options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
-
-    steps:
-      - name: Clone
-        uses: actions/checkout@v2
-
-      - name: Setup Python
-        uses: actions/setup-python@v2
-        with:
-          python-version: 3.6
-
-      - name: Add to Hosts
-        run: echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts
-
-      - name: Cache pip
-        uses: actions/cache@v2
-        with:
-          path: ~/.cache/pip
-          key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
-          restore-keys: |
-            ${{ runner.os }}-pip-
-            ${{ runner.os }}-
-      - name: Cache node modules
-        uses: actions/cache@v2
-        env:
-          cache-name: cache-node-modules
-        with:
-          path: ~/.npm
-          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
-          restore-keys: |
-            ${{ runner.os }}-build-${{ env.cache-name }}-
-            ${{ runner.os }}-build-
-            ${{ runner.os }}-
-      - name: Get yarn cache directory path
-        id: yarn-cache-dir-path
-        run: echo "::set-output name=dir::$(yarn cache dir)"
-
-      - uses: actions/cache@v2
-        id: yarn-cache
-        with:
-          path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
-          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
-          restore-keys: |
-            ${{ runner.os }}-yarn-
-
-      - name: Install
-        run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
-
-      - name: Run Tests
-        run: ${{ matrix.RUN_COMMAND }}
-        env:
-          TYPE: ${{ matrix.TYPE }}
-
-      - name: Coverage - Pull Request
-        if: matrix.TYPE == 'server' && github.event_name == 'pull_request'
-        run: |
-          cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE}
-          cd ${GITHUB_WORKSPACE}
-          pip install coveralls==2.2.0
-          pip install coverage==4.5.4
-          coveralls --service=github
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-          COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
-          COVERALLS_SERVICE_NAME: github
-          
-      - name: Coverage - Push
-        if: matrix.TYPE == 'server' && github.event_name == 'push'
-        run: |
-          cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE}
-          cd ${GITHUB_WORKSPACE}
-          pip install coveralls==2.2.0
-          pip install coverage==4.5.4
-          coveralls --service=github-actions
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-          COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_TOKEN }}
-          COVERALLS_SERVICE_NAME: github-actions
-
diff --git a/.github/workflows/patch.yml b/.github/workflows/patch.yml
new file mode 100644
index 0000000..7c9e027
--- /dev/null
+++ b/.github/workflows/patch.yml
@@ -0,0 +1,69 @@
+name: Patch
+
+on: [pull_request, workflow_dispatch]
+
+jobs:
+  test:
+    runs-on: ubuntu-18.04
+
+    name: Patch Test
+
+    services:
+      mysql:
+        image: mariadb:10.3
+        env:
+          MYSQL_ALLOW_EMPTY_PASSWORD: YES
+        ports:
+          - 3306:3306
+        options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
+
+    steps:
+      - name: Clone
+        uses: actions/checkout@v2
+
+      - name: Setup Python
+        uses: actions/setup-python@v2
+        with:
+          python-version: 3.6
+
+      - name: Add to Hosts
+        run: echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts
+
+      - name: Cache pip
+        uses: actions/cache@v2
+        with:
+          path: ~/.cache/pip
+          key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
+          restore-keys: |
+            ${{ runner.os }}-pip-
+            ${{ runner.os }}-
+
+      - name: Cache node modules
+        uses: actions/cache@v2
+        env:
+          cache-name: cache-node-modules
+        with:
+          path: ~/.npm
+          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
+          restore-keys: |
+            ${{ runner.os }}-build-${{ env.cache-name }}-
+            ${{ runner.os }}-build-
+            ${{ runner.os }}-
+
+      - name: Get yarn cache directory path
+        id: yarn-cache-dir-path
+        run: echo "::set-output name=dir::$(yarn cache dir)"
+
+      - uses: actions/cache@v2
+        id: yarn-cache
+        with:
+          path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
+          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
+          restore-keys: |
+            ${{ runner.os }}-yarn-
+
+      - name: Install
+        run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
+
+      - name: Run Patch Tests
+        run: cd ~/frappe-bench/ && wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz &&  bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz && bench --site test_site migrate
diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml
new file mode 100644
index 0000000..92685e2
--- /dev/null
+++ b/.github/workflows/server-tests.yml
@@ -0,0 +1,110 @@
+name: Server
+
+on: [pull_request, workflow_dispatch]
+
+jobs:
+  test:
+    runs-on: ubuntu-18.04
+
+    strategy:
+      fail-fast: false
+
+      matrix:
+        container: [1, 2, 3]
+
+    name: Python Unit Tests
+
+    services:
+      mysql:
+        image: mariadb:10.3
+        env:
+          MYSQL_ALLOW_EMPTY_PASSWORD: YES
+        ports:
+          - 3306:3306
+        options: --health-cmd="mysqladmin ping" --health-interval=5s --health-timeout=2s --health-retries=3
+
+    steps:
+      - name: Clone
+        uses: actions/checkout@v2
+
+      - name: Setup Python
+        uses: actions/setup-python@v2
+        with:
+          python-version: 3.7
+
+      - name: Add to Hosts
+        run: echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts
+
+      - name: Cache pip
+        uses: actions/cache@v2
+        with:
+          path: ~/.cache/pip
+          key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
+          restore-keys: |
+            ${{ runner.os }}-pip-
+            ${{ runner.os }}-
+
+      - name: Cache node modules
+        uses: actions/cache@v2
+        env:
+          cache-name: cache-node-modules
+        with:
+          path: ~/.npm
+          key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
+          restore-keys: |
+            ${{ runner.os }}-build-${{ env.cache-name }}-
+            ${{ runner.os }}-build-
+            ${{ runner.os }}-
+
+      - name: Get yarn cache directory path
+        id: yarn-cache-dir-path
+        run: echo "::set-output name=dir::$(yarn cache dir)"
+
+      - uses: actions/cache@v2
+        id: yarn-cache
+        with:
+          path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
+          key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
+          restore-keys: |
+            ${{ runner.os }}-yarn-
+
+      - name: Install
+        run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
+
+      - name: Run Tests
+        run: cd ~/frappe-bench/ && bench --site test_site run-parallel-tests --app erpnext --use-orchestrator --with-coverage
+        env:
+          TYPE: server
+          CI_BUILD_ID: ${{ github.run_id }}
+          ORCHESTRATOR_URL: http://test-orchestrator.frappe.io
+
+      - name: Upload Coverage Data
+        run: |
+          cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE}
+          cd ${GITHUB_WORKSPACE}
+          pip3 install coverage==5.5
+          pip3 install coveralls==3.0.1
+          coveralls
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          COVERALLS_FLAG_NAME: run-${{ matrix.container }}
+          COVERALLS_SERVICE_NAME: ${{ github.event_name == 'pull_request' && 'github' || 'github-actions' }}
+          COVERALLS_PARALLEL: true
+
+  coveralls:
+    name: Coverage Wrap Up
+    needs: test
+    container: python:3-slim
+    runs-on: ubuntu-18.04
+    steps:
+      - name: Clone
+        uses: actions/checkout@v2
+
+      - name: Coveralls Finished
+        run: |
+          cd ${GITHUB_WORKSPACE}
+          pip3 install coverage==5.5
+          pip3 install coveralls==3.0.1
+          coveralls --finish
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
index fc1d7e3..e657a9a 100644
--- a/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/test_accounting_dimension.py
@@ -7,7 +7,8 @@
 import unittest
 from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
 from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
-from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import delete_accounting_dimension
+
+test_dependencies = ['Cost Center', 'Location', 'Warehouse', 'Department']
 
 class TestAccountingDimension(unittest.TestCase):
 	def setUp(self):
diff --git a/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py b/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py
index 7877abd..7f6254f 100644
--- a/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py
+++ b/erpnext/accounts/doctype/accounting_dimension_filter/test_accounting_dimension_filter.py
@@ -9,6 +9,8 @@
 from erpnext.accounts.doctype.accounting_dimension.test_accounting_dimension import create_dimension, disable_dimension
 from erpnext.exceptions import InvalidAccountDimensionError, MandatoryAccountDimensionError
 
+test_dependencies = ['Location', 'Cost Center', 'Department']
+
 class TestAccountingDimensionFilter(unittest.TestCase):
 	def setUp(self):
 		create_dimension()
diff --git a/erpnext/accounts/doctype/accounting_period/test_accounting_period.py b/erpnext/accounts/doctype/accounting_period/test_accounting_period.py
index 10cd939..dc472c7 100644
--- a/erpnext/accounts/doctype/accounting_period/test_accounting_period.py
+++ b/erpnext/accounts/doctype/accounting_period/test_accounting_period.py
@@ -10,6 +10,8 @@
 from erpnext.accounts.doctype.accounting_period.accounting_period import OverlapError
 from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
 
+test_dependencies = ['Item']
+
 class TestAccountingPeriod(unittest.TestCase):
 	def test_overlap(self):
 		ap1 = create_accounting_period(start_date = "2018-04-01",
@@ -38,7 +40,7 @@
 	accounting_period.start_date = args.start_date or nowdate()
 	accounting_period.end_date = args.end_date or add_months(nowdate(), 1)
 	accounting_period.company = args.company or "_Test Company"
-	accounting_period.period_name =args.period_name or  "_Test_Period_Name_1"
+	accounting_period.period_name = args.period_name or "_Test_Period_Name_1"
 	accounting_period.append("closed_documents", {
 		"document_type": 'Sales Invoice', "closed": 1
 	})
diff --git a/erpnext/accounts/doctype/bank/bank.js b/erpnext/accounts/doctype/bank/bank.js
index 059e1d3..19041a3 100644
--- a/erpnext/accounts/doctype/bank/bank.js
+++ b/erpnext/accounts/doctype/bank/bank.js
@@ -120,4 +120,4 @@
 	plaid_success(token, response) {
 		frappe.show_alert({ message: __('Plaid Link Updated'), indicator: 'green' });
 	}
-};
+};
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/budget/test_budget.py b/erpnext/accounts/doctype/budget/test_budget.py
index c5ec23c..603e21e 100644
--- a/erpnext/accounts/doctype/budget/test_budget.py
+++ b/erpnext/accounts/doctype/budget/test_budget.py
@@ -11,6 +11,8 @@
 from erpnext.accounts.doctype.budget.budget import get_actual_expense, BudgetError
 from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
 
+test_dependencies = ['Monthly Distribution']
+
 class TestBudget(unittest.TestCase):
 	def test_monthly_budget_crossed_ignore(self):
 		set_total_expense_zero(nowdate(), "cost_center")
diff --git a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py
index ef44626..3b764aa 100644
--- a/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py
+++ b/erpnext/accounts/doctype/chart_of_accounts_importer/chart_of_accounts_importer.py
@@ -293,7 +293,7 @@
 	accounts_dict = {}
 	for account in accounts:
 		accounts_dict.setdefault(account["account_name"], account)
-		if not hasattr(account, "parent_account"):
+		if "parent_account" not in account:
 			msg = _("Please make sure the file you are using has 'Parent Account' column present in the header.")
 			msg += "<br><br>"
 			msg += _("Alternatively, you can download the template and fill your data in.")
diff --git a/erpnext/accounts/doctype/dunning/test_dunning.py b/erpnext/accounts/doctype/dunning/test_dunning.py
index c5ce514..e2d4d82 100644
--- a/erpnext/accounts/doctype/dunning/test_dunning.py
+++ b/erpnext/accounts/doctype/dunning/test_dunning.py
@@ -29,7 +29,7 @@
 		self.assertEqual(round(amounts.get('interest_amount'), 2), 0.44)
 		self.assertEqual(round(amounts.get('dunning_amount'), 2), 20.44)
 		self.assertEqual(round(amounts.get('grand_total'), 2), 120.44)
-	
+
 	def test_gl_entries(self):
 		dunning = create_dunning()
 		dunning.submit()
diff --git a/erpnext/accounts/doctype/journal_entry/regional/india.js b/erpnext/accounts/doctype/journal_entry/regional/india.js
new file mode 100644
index 0000000..75a69ac
--- /dev/null
+++ b/erpnext/accounts/doctype/journal_entry/regional/india.js
@@ -0,0 +1,17 @@
+frappe.ui.form.on("Journal Entry", {
+	refresh: function(frm) {
+		frm.set_query('company_address', function(doc) {
+			if(!doc.company) {
+				frappe.throw(__('Please set Company'));
+			}
+
+			return {
+				query: 'frappe.contacts.doctype.address.address.address_query',
+				filters: {
+					link_doctype: 'Company',
+					link_name: doc.company
+				}
+			};
+		});
+	}
+});
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
index 8c5a34a..6418d73 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
+++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
@@ -107,7 +107,7 @@
 		frm.set_value("taxes", []);
 
 		for (let row of frm.doc.payment_reconciliation) {
-			row.expected_amount = 0;
+			row.expected_amount = row.opening_amount;
 		}
 
 		for (let row of frm.doc.pos_transactions) {
@@ -154,6 +154,9 @@
 function refresh_payments(d, frm) {
 	d.payments.forEach(p => {
 		const payment = frm.doc.payment_reconciliation.find(pay => pay.mode_of_payment === p.mode_of_payment);
+		if (p.account == d.account_for_change_amount) {
+			p.amount -= flt(d.change_amount);
+		}
 		if (payment) {
 			payment.expected_amount += flt(p.amount);
 			payment.difference = payment.closing_amount - payment.expected_amount;
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
index f55fdab..8ec4ef2 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
@@ -140,6 +140,7 @@
 					return
 
 				available_stock = get_stock_availability(d.item_code, d.warehouse)
+
 				item_code, warehouse, qty = frappe.bold(d.item_code), frappe.bold(d.warehouse), frappe.bold(d.qty)
 				if flt(available_stock) <= 0:
 					frappe.throw(_('Row #{}: Item Code: {} is not available under warehouse {}.')
@@ -213,8 +214,9 @@
 		for d in self.get("items"):
 			is_stock_item = frappe.get_cached_value("Item", d.get("item_code"), "is_stock_item")
 			if not is_stock_item:
-				frappe.throw(_("Row #{}: Item {} is a non stock item. You can only include stock items in a POS Invoice. ")
-					.format(d.idx, frappe.bold(d.item_code)), title=_("Invalid Item"))
+				if not frappe.db.exists('Product Bundle', d.item_code):
+					frappe.throw(_("Row #{}: Item {} is a non stock item. You can only include stock items in a POS Invoice.")
+						.format(d.idx, frappe.bold(d.item_code)), title=_("Invalid Item"))
 
 	def validate_mode_of_payment(self):
 		if len(self.payments) == 0:
@@ -455,15 +457,36 @@
 
 @frappe.whitelist()
 def get_stock_availability(item_code, warehouse):
+	if frappe.db.get_value('Item', item_code, 'is_stock_item'):
+		bin_qty = get_bin_qty(item_code, warehouse)
+		pos_sales_qty = get_pos_reserved_qty(item_code, warehouse)
+		return bin_qty - pos_sales_qty
+	else:
+		if frappe.db.exists('Product Bundle', item_code):
+			return get_bundle_availability(item_code, warehouse)
+
+def get_bundle_availability(bundle_item_code, warehouse):
+	product_bundle = frappe.get_doc('Product Bundle', bundle_item_code)
+
+	bundle_bin_qty = 1000000
+	for item in product_bundle.items:
+		item_bin_qty = get_bin_qty(item.item_code, warehouse)
+		item_pos_reserved_qty = get_pos_reserved_qty(item.item_code, warehouse)
+		available_qty = item_bin_qty - item_pos_reserved_qty
+
+		max_available_bundles = available_qty / item.qty
+		if bundle_bin_qty > max_available_bundles:
+			bundle_bin_qty = max_available_bundles
+
+	pos_sales_qty = get_pos_reserved_qty(bundle_item_code, warehouse)
+	return bundle_bin_qty - pos_sales_qty
+
+def get_bin_qty(item_code, warehouse):
 	bin_qty = frappe.db.sql("""select actual_qty from `tabBin`
 		where item_code = %s and warehouse = %s
 		limit 1""", (item_code, warehouse), as_dict=1)
 
-	pos_sales_qty = get_pos_reserved_qty(item_code, warehouse)
-
-	bin_qty = bin_qty[0].actual_qty or 0 if bin_qty else 0
-
-	return bin_qty - pos_sales_qty
+	return bin_qty[0].actual_qty or 0 if bin_qty else 0
 
 def get_pos_reserved_qty(item_code, warehouse):
 	reserved_qty = frappe.db.sql("""select sum(p_item.qty) as qty
@@ -522,4 +545,4 @@
 		mode_of_payment = pos_payment_method.mode_of_payment
 		if pos_payment_method.allow_in_returns and not [d for d in doc.get('payments') if d.mode_of_payment == mode_of_payment]:
 			payment_mode = get_mode_of_payment_info(mode_of_payment, doc.company)
-			append_payment(payment_mode[0])
\ No newline at end of file
+			append_payment(payment_mode[0])
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
index aedf1c6..556f49d 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
@@ -152,7 +152,7 @@
 			frappe.throw(_("Valid from date must be less than valid upto date"))
 
 	def validate_condition(self):
-		if self.condition and ("=" in self.condition) and re.match("""[\w\.:_]+\s*={1}\s*[\w\.@'"]+""", self.condition):
+		if self.condition and ("=" in self.condition) and re.match(r'[\w\.:_]+\s*={1}\s*[\w\.@\'"]+', self.condition):
 			frappe.throw(_("Invalid condition expression"))
 
 #--------------------------------------------------------------------------------
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
index 2ad455c..0b0ee90 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.py
@@ -94,7 +94,7 @@
 			continue
 
 		html = frappe.render_template(template_path, \
-			{"filters": filters, "data": res, "ageing": ageing[0] if doc.include_ageing else None,
+			{"filters": filters, "data": res, "ageing": ageing[0] if (doc.include_ageing and ageing) else None,
 				"letter_head": letter_head if doc.letter_head else None,
 				"terms_and_conditions": frappe.db.get_value('Terms and Conditions', doc.terms_and_conditions, 'terms')
 					if doc.terms_and_conditions else None})
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index 66be11f..53db689 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -636,8 +636,8 @@
 
 	def test_rejected_serial_no(self):
 		pi = make_purchase_invoice(item_code="_Test Serialized Item With Series", received_qty=2, qty=1,
-			rejected_qty=1, rate=500, update_stock=1,
-			rejected_warehouse = "_Test Rejected Warehouse - _TC")
+			rejected_qty=1, rate=500, update_stock=1, rejected_warehouse = "_Test Rejected Warehouse - _TC",
+			allow_zero_valuation_rate=1)
 
 		self.assertEqual(frappe.db.get_value("Serial No", pi.get("items")[0].serial_no, "warehouse"),
 			pi.get("items")[0].warehouse)
@@ -994,7 +994,8 @@
 		"project": args.project,
 		"rejected_warehouse": args.rejected_warehouse or "",
 		"rejected_serial_no": args.rejected_serial_no or "",
-		"asset_location": args.location or ""
+		"asset_location": args.location or "",
+		"allow_zero_valuation_rate": args.get("allow_zero_valuation_rate") or 0
 	})
 
 	if args.get_taxes_and_charges:
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index 30a270c..3cd4b80 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -566,7 +566,7 @@
 		doc = make_invoice(pr.name)
 
 		self.assertEqual('Asset Received But Not Billed - _TC', doc.items[0].expense_account)
-	
+
 	def test_asset_cwip_toggling_cases(self):
 		cwip = frappe.db.get_value("Asset Category", "Computers", "enable_cwip_accounting")
 		name = frappe.db.get_value("Asset Category Account", filters={"parent": "Computers"}, fieldname=["name"])
diff --git a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py
index 6900938..c1fc6fb 100644
--- a/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py
+++ b/erpnext/buying/report/subcontracted_raw_materials_to_be_transferred/test_subcontracted_raw_materials_to_be_transferred.py
@@ -9,12 +9,12 @@
 from erpnext.buying.report.subcontracted_raw_materials_to_be_transferred.subcontracted_raw_materials_to_be_transferred import execute
 import json, frappe, unittest
 
-class TestSubcontractedItemToBeReceived(unittest.TestCase):
+class TestSubcontractedItemToBeTransferred(unittest.TestCase):
 
-	def test_pending_and_received_qty(self):
+	def test_pending_and_transferred_qty(self):
 		po = create_purchase_order(item_code='_Test FG Item', is_subcontracted='Yes')
-		make_stock_entry(item_code='_Test Item', target='_Test Warehouse 1 - _TC', qty=100, basic_rate=100)
-		make_stock_entry(item_code='_Test Item Home Desktop 100', target='_Test Warehouse 1 - _TC', qty=100, basic_rate=100)
+		make_stock_entry(item_code='_Test Item', target='_Test Warehouse - _TC', qty=100, basic_rate=100)
+		make_stock_entry(item_code='_Test Item Home Desktop 100', target='_Test Warehouse - _TC', qty=100, basic_rate=100)
 		transfer_subcontracted_raw_materials(po.name)
 		col, data = execute(filters=frappe._dict({'supplier': po.supplier,
 		   'from_date': frappe.utils.get_datetime(frappe.utils.add_to_date(po.transaction_date, days=-10)),
@@ -38,7 +38,8 @@
 		'warehouse': '_Test Warehouse - _TC', 'rate': 100, 'amount': 200, 'stock_uom': 'Nos'}]
 	rm_item_string = json.dumps(rm_item)
 	se = frappe.get_doc(make_rm_stock_entry(po, rm_item_string))
+	se.from_warehouse = '_Test Warehouse 1 - _TC'
 	se.to_warehouse = '_Test Warehouse 1 - _TC'
 	se.stock_entry_type = 'Send to Subcontractor'
 	se.save()
-	se.submit()
\ No newline at end of file
+	se.submit()
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index c77ea55..401dfdf 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1011,7 +1011,6 @@
 				else:
 					grand_total -= self.get("total_advance")
 					base_grand_total = flt(grand_total * self.get("conversion_rate"), self.precision("base_grand_total"))
-
 			if total != flt(grand_total, self.precision("grand_total")) or \
 				base_total != flt(base_grand_total, self.precision("base_grand_total")):
 				frappe.throw(_("Total Payment Amount in Payment Schedule must be equal to Grand / Rounded Total"))
diff --git a/erpnext/education/doctype/fees/test_fees.py b/erpnext/education/doctype/fees/test_fees.py
index eedc2ae..c6bb704 100644
--- a/erpnext/education/doctype/fees/test_fees.py
+++ b/erpnext/education/doctype/fees/test_fees.py
@@ -9,8 +9,7 @@
 from frappe.utils.make_random import get_random
 from erpnext.education.doctype.program.test_program import make_program_and_linked_courses
 
-# test_records = frappe.get_test_records('Fees')
-
+test_dependencies = ['Company']
 class TestFees(unittest.TestCase):
 
 	def test_fees(self):
diff --git a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py
index d370fbc..3c2e59a 100644
--- a/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py
+++ b/erpnext/erpnext_integrations/doctype/mpesa_settings/test_mpesa_settings.py
@@ -81,7 +81,7 @@
 		integration_request.reload()
 		self.assertEqual(pos_invoice.mpesa_receipt_number, "LGR7OWQX0R")
 		self.assertEqual(integration_request.status, "Completed")
-		
+
 		frappe.db.set_value("Customer", "_Test Customer", "default_currency", "")
 		integration_request.delete()
 		pr.reload()
@@ -139,7 +139,7 @@
 		pr.cancel()
 		pr.delete()
 		pos_invoice.delete()
-	
+
 	def test_processing_of_only_one_succes_callback_payload(self):
 		create_mpesa_settings(payment_gateway_name="Payment")
 		mpesa_account = frappe.db.get_value("Payment Gateway Account", {"payment_gateway": 'Mpesa-Payment'}, "payment_account")
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
index 5f990cd..42d4b9b 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
@@ -99,5 +99,7 @@
 				response = self.client.Transactions.get(self.access_token, start_date=start_date, end_date=end_date, offset=len(transactions))
 				transactions.extend(response["transactions"])
 			return transactions
+		except ItemError as e:
+			raise e
 		except Exception:
 			frappe.log_error(frappe.get_traceback(), _("Plaid transactions sync error"))
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js
index bbc2ca8..37bf282 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js
@@ -16,6 +16,10 @@
 				new erpnext.integrations.plaidLink(frm);
 			});
 
+			frm.add_custom_button(__('Reset Plaid Link'), () => {
+				new erpnext.integrations.plaidLink(frm);
+			});
+
 			frm.add_custom_button(__("Sync Now"), () => {
 				frappe.call({
 					method: "erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.enqueue_synchronization",
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
index ce15e47..3ef069b 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
@@ -12,6 +12,7 @@
 from frappe.model.document import Document
 from frappe.utils import add_months, formatdate, getdate, today
 
+from plaid.errors import ItemError
 
 class PlaidSettings(Document):
 	@staticmethod
@@ -51,7 +52,7 @@
 			})
 			bank.insert()
 		except Exception:
-			frappe.throw(frappe.get_traceback())
+			frappe.log_error(frappe.get_traceback(), title=_('Plaid Link Error'))
 	else:
 		bank = frappe.get_doc("Bank", response["institution"]["name"])
 		bank.plaid_access_token = access_token
@@ -83,7 +84,12 @@
 		if not acc_subtype:
 			add_account_subtype(account["subtype"])
 
-		if not frappe.db.exists("Bank Account", dict(integration_id=account["id"])):
+		existing_bank_account = frappe.db.exists("Bank Account", {
+			'account_name': account["name"],
+			'bank': bank["bank_name"]
+		})
+
+		if not existing_bank_account:
 			try:
 				new_account = frappe.get_doc({
 					"doctype": "Bank Account",
@@ -103,10 +109,27 @@
 			except frappe.UniqueValidationError:
 				frappe.msgprint(_("Bank account {0} already exists and could not be created again").format(account["name"]))
 			except Exception:
-				frappe.throw(frappe.get_traceback())
+				frappe.log_error(frappe.get_traceback(), title=_("Plaid Link Error"))
+				frappe.throw(_("There was an error creating Bank Account while linking with Plaid."), 
+					title=_("Plaid Link Failed"))
 
 		else:
-			result.append(frappe.db.get_value("Bank Account", dict(integration_id=account["id"]), "name"))
+			try:
+				existing_account = frappe.get_doc('Bank Account', existing_bank_account)
+				existing_account.update({
+					"bank": bank["bank_name"],
+					"account_name": account["name"],
+					"account_type": account.get("type", ""),
+					"account_subtype": account.get("subtype", ""),
+					"mask": account.get("mask", ""),
+					"integration_id": account["id"]
+				})
+				existing_account.save()
+				result.append(existing_bank_account)
+			except Exception:
+				frappe.log_error(frappe.get_traceback(), title=_("Plaid Link Error"))
+				frappe.throw(_("There was an error updating Bank Account {} while linking with Plaid.").format(
+					existing_bank_account), title=_("Plaid Link Failed"))
 
 	return result
 
@@ -172,9 +195,16 @@
 		account_id = None
 
 	plaid = PlaidConnector(access_token)
-	transactions = plaid.get_transactions(start_date=start_date, end_date=end_date, account_id=account_id)
 
-	return transactions
+	try:
+		transactions = plaid.get_transactions(start_date=start_date, end_date=end_date, account_id=account_id)
+	except ItemError as e:
+		if e.code == "ITEM_LOGIN_REQUIRED":
+			msg = _("There was an error syncing transactions.") + " "
+			msg += _("Please refresh or reset the Plaid linking of the Bank {}.").format(bank) + " "
+			frappe.log_error(msg, title=_("Plaid Link Refresh Required"))
+
+	return transactions or []
 
 
 def new_bank_transaction(transaction):
diff --git a/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py b/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
index d079bed..113fa51 100644
--- a/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
+++ b/erpnext/healthcare/doctype/therapy_plan/test_therapy_plan.py
@@ -29,7 +29,7 @@
 		self.assertEqual(frappe.db.get_value('Therapy Plan', plan.name, 'status'), 'Completed')
 
 		patient, medical_department, practitioner = create_healthcare_docs()
-		appointment = create_appointment(patient, practitioner, nowdate())		
+		appointment = create_appointment(patient, practitioner, nowdate())
 		session = make_therapy_session(plan.name, plan.patient, 'Basic Rehab', '_Test Company', appointment.name)
 		session = frappe.get_doc(session)
 		session.submit()
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 0bf551e..cee6f37 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -4,8 +4,7 @@
 from __future__ import unicode_literals
 import frappe
 from frappe import _
-from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, get_link_to_form, \
-	comma_or, get_fullname, add_days, nowdate, get_datetime_str
+from frappe.utils import cint, cstr, date_diff, flt, formatdate, getdate, get_link_to_form, get_fullname, add_days, nowdate
 from erpnext.hr.utils import set_employee_name, get_leave_period, share_doc_with_approver
 from erpnext.hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates
 from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
@@ -85,7 +84,7 @@
 
 	def validate_dates(self):
 		if frappe.db.get_single_value("HR Settings", "restrict_backdated_leave_application"):
-			if self.from_date and self.from_date < frappe.utils.today():
+			if self.from_date and getdate(self.from_date) < getdate():
 				allowed_role = frappe.db.get_single_value("HR Settings", "role_allowed_to_create_backdated_leave_application")
 				if allowed_role not in frappe.get_roles():
 					frappe.throw(_("Only users with the {0} role can create backdated leave applications").format(allowed_role))
@@ -248,9 +247,9 @@
 				self.throw_overlap_error(d)
 
 	def throw_overlap_error(self, d):
-		msg = _("Employee {0} has already applied for {1} between {2} and {3} : ").format(self.employee,
-			d['leave_type'], formatdate(d['from_date']), formatdate(d['to_date'])) \
-			+ """ <b><a href="/app/Form/Leave Application/{0}">{0}</a></b>""".format(d["name"])
+		form_link = get_link_to_form("Leave Application", d.name)
+		msg = _("Employee {0} has already applied for {1} between {2} and {3} : {4}").format(self.employee,
+			d['leave_type'], formatdate(d['from_date']), formatdate(d['to_date']), form_link)
 		frappe.throw(msg, OverlapError)
 
 	def get_total_leaves_on_half_day(self):
@@ -356,7 +355,7 @@
 
 			sender      	    = dict()
 			sender['email']     = frappe.get_doc('User', frappe.session.user).email
-			sender['full_name'] = frappe.utils.get_fullname(sender['email'])
+			sender['full_name'] = get_fullname(sender['email'])
 
 			try:
 				frappe.sendmail(
@@ -823,4 +822,4 @@
 		leave_approver = frappe.db.get_value('Department Approver', {'parent': department,
 			'parentfield': 'leave_approvers', 'idx': 1}, 'approver')
 
-	return leave_approver
\ No newline at end of file
+	return leave_approver
diff --git a/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py b/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py
index 6e151d0..03b0cf3 100644
--- a/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py
+++ b/erpnext/hr/doctype/upload_attendance/test_upload_attendance.py
@@ -5,11 +5,18 @@
 
 import frappe
 import unittest
+import erpnext
 from frappe.utils import getdate
 from erpnext.hr.doctype.upload_attendance.upload_attendance import get_data
 from erpnext.hr.doctype.employee.test_employee import make_employee
 
+test_dependencies = ['Holiday List']
+
 class TestUploadAttendance(unittest.TestCase):
+	@classmethod
+	def setUpClass(cls):
+		frappe.db.set_value("Company", erpnext.get_default_company(), "default_holiday_list", '_Test Holiday List')
+
 	def test_date_range(self):
 		employee = make_employee("test_employee@company.com")
 		employee_doc = frappe.get_doc("Employee", employee)
diff --git a/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py b/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py
index cf0048c..ed52c4e 100644
--- a/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py
+++ b/erpnext/hr/doctype/vehicle_log/test_vehicle_log.py
@@ -5,7 +5,7 @@
 
 import frappe
 import unittest
-from frappe.utils import nowdate,flt, cstr,random_string
+from frappe.utils import nowdate, flt, cstr, random_string
 from erpnext.hr.doctype.employee.test_employee import make_employee
 from erpnext.hr.doctype.vehicle_log.vehicle_log import make_expense_claim
 
@@ -18,23 +18,13 @@
 			self.employee_id = make_employee("testdriver@example.com", company="_Test Company")
 
 		self.license_plate = get_vehicle(self.employee_id)
-	
+
 	def tearDown(self):
 		frappe.delete_doc("Vehicle", self.license_plate, force=1)
 		frappe.delete_doc("Employee", self.employee_id, force=1)
 
 	def test_make_vehicle_log_and_syncing_of_odometer_value(self):
-		vehicle_log = frappe.get_doc({
-			"doctype": "Vehicle Log",
-			"license_plate": cstr(self.license_plate),
-			"employee": self.employee_id,
-			"date":frappe.utils.nowdate(),
-			"odometer":5010,
-			"fuel_qty":frappe.utils.flt(50),
-			"price": frappe.utils.flt(500)
-		})
-		vehicle_log.save()
-		vehicle_log.submit()
+		vehicle_log = make_vehicle_log(self.license_plate, self.employee_id)
 
 		#checking value of vehicle odometer value on submit.
 		vehicle = frappe.get_doc("Vehicle", self.license_plate)
@@ -51,19 +41,9 @@
 		self.assertEqual(vehicle.last_odometer, current_odometer - distance_travelled)
 
 		vehicle_log.delete()
-	
+
 	def test_vehicle_log_fuel_expense(self):
-		vehicle_log = frappe.get_doc({
-			"doctype": "Vehicle Log",
-			"license_plate": cstr(self.license_plate),
-			"employee": self.employee_id,
-			"date": frappe.utils.nowdate(),
-			"odometer":5010,
-			"fuel_qty":frappe.utils.flt(50),
-			"price": frappe.utils.flt(500)
-		})
-		vehicle_log.save()
-		vehicle_log.submit()
+		vehicle_log = make_vehicle_log(self.license_plate, self.employee_id)
 
 		expense_claim = make_expense_claim(vehicle_log.name)
 		fuel_expense = expense_claim.expenses[0].amount
@@ -73,6 +53,18 @@
 		frappe.delete_doc("Expense Claim", expense_claim.name)
 		frappe.delete_doc("Vehicle Log", vehicle_log.name)
 
+	def test_vehicle_log_with_service_expenses(self):
+		vehicle_log = make_vehicle_log(self.license_plate, self.employee_id, with_services=True)
+
+		expense_claim = make_expense_claim(vehicle_log.name)
+		expenses = expense_claim.expenses[0].amount
+		self.assertEqual(expenses, 27000)
+
+		vehicle_log.cancel()
+		frappe.delete_doc("Expense Claim", expense_claim.name)
+		frappe.delete_doc("Vehicle Log", vehicle_log.name)
+
+
 def get_vehicle(employee_id):
 	license_plate=random_string(10).upper()
 	vehicle = frappe.get_doc({
@@ -81,15 +73,46 @@
 			"make": "Maruti",
 			"model": "PCM",
 			"employee": employee_id,
-			"last_odometer":5000,
-			"acquisition_date":frappe.utils.nowdate(),
+			"last_odometer": 5000,
+			"acquisition_date": nowdate(),
 			"location": "Mumbai",
 			"chassis_no": "1234ABCD",
 			"uom": "Litre",
-			"vehicle_value":frappe.utils.flt(500000)
+			"vehicle_value": flt(500000)
 		})
 	try:
 		vehicle.insert()
 	except frappe.DuplicateEntryError:
 		pass
-	return license_plate
\ No newline at end of file
+	return license_plate
+
+
+def make_vehicle_log(license_plate, employee_id, with_services=False):
+	vehicle_log = frappe.get_doc({
+		"doctype": "Vehicle Log",
+		"license_plate": cstr(license_plate),
+		"employee": employee_id,
+		"date": nowdate(),
+		"odometer": 5010,
+		"fuel_qty": flt(50),
+		"price": flt(500)
+	})
+
+	if with_services:
+		vehicle_log.append("service_detail", {
+			"service_item": "Oil Change",
+			"type": "Inspection",
+			"frequency": "Mileage",
+			"expense_amount": flt(500)
+		})
+		vehicle_log.append("service_detail", {
+			"service_item": "Wheels",
+			"type": "Change",
+			"frequency": "Half Yearly",
+			"expense_amount": flt(1500)
+		})
+
+	vehicle_log.save()
+	vehicle_log.submit()
+
+	return vehicle_log
\ No newline at end of file
diff --git a/erpnext/hr/doctype/vehicle_log/vehicle_log.json b/erpnext/hr/doctype/vehicle_log/vehicle_log.json
index 619e295..4ea9045 100644
--- a/erpnext/hr/doctype/vehicle_log/vehicle_log.json
+++ b/erpnext/hr/doctype/vehicle_log/vehicle_log.json
@@ -1,4 +1,5 @@
 {
+ "actions": [],
  "autoname": "naming_series:",
  "creation": "2016-09-03 14:14:51.788550",
  "doctype": "DocType",
@@ -10,7 +11,6 @@
   "naming_series",
   "license_plate",
   "employee",
-  "column_break_4",
   "column_break_7",
   "model",
   "make",
@@ -66,10 +66,6 @@
    "reqd": 1
   },
   {
-   "fieldname": "column_break_4",
-   "fieldtype": "Column Break"
-  },
-  {
    "fieldname": "column_break_7",
    "fieldtype": "Column Break"
   },
@@ -142,7 +138,6 @@
   {
    "fieldname": "service_detail",
    "fieldtype": "Table",
-   "label": "Service Detail",
    "options": "Vehicle Service"
   },
   {
@@ -158,7 +153,7 @@
    "fetch_from": "license_plate.last_odometer",
    "fieldname": "last_odometer",
    "fieldtype": "Int",
-   "label": "last Odometer Value ",
+   "label": "Last Odometer Value ",
    "read_only": 1,
    "reqd": 1
   },
@@ -168,7 +163,8 @@
   }
  ],
  "is_submittable": 1,
- "modified": "2020-03-18 16:45:45.060761",
+ "links": [],
+ "modified": "2021-05-17 00:10:21.188352",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Vehicle Log",
diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js
index 05728a2..8bb3457 100644
--- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js
+++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.js
@@ -37,5 +37,22 @@
 			"fieldtype": "Link",
 			"options": "Employee",
 		}
-	]
+	],
+
+	onload: () => {
+		frappe.call({
+			type: "GET",
+			method: "erpnext.hr.utils.get_leave_period",
+			args: {
+				"from_date": frappe.defaults.get_default("year_start_date"),
+				"to_date": frappe.defaults.get_default("year_end_date"),
+				"company": frappe.defaults.get_user_default("Company")
+			},
+			freeze: true,
+			callback: (data) => {
+				frappe.query_report.set_filter_value("from_date", data.message[0].from_date);
+				frappe.query_report.set_filter_value("to_date", data.message[0].to_date);
+			}
+		});
+	}
 }
diff --git a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
index 06f9160..4dd4570 100644
--- a/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
+++ b/erpnext/hr/report/employee_leave_balance/employee_leave_balance.py
@@ -6,15 +6,16 @@
 from frappe.utils import flt, add_days
 from frappe import _
 from erpnext.hr.doctype.leave_application.leave_application import get_leaves_for_period, get_leave_balance_on
+from itertools import groupby
 
 def execute(filters=None):
 	if filters.to_date <= filters.from_date:
-		frappe.throw(_('"From date" can not be greater than or equal to "To date"'))
+		frappe.throw(_('"From Date" can not be greater than or equal to "To Date"'))
 
 	columns = get_columns()
 	data = get_data(filters)
-
-	return columns, data
+	charts = get_chart_data(data)
+	return columns, data, None, charts
 
 def get_columns():
 	columns = [{
@@ -31,9 +32,10 @@
 		'options': 'Employee'
 	}, {
 		'label': _('Employee Name'),
-		'fieldtype': 'Data',
+		'fieldtype': 'Dynamic Link',
 		'fieldname': 'employee_name',
 		'width': 100,
+		'options': 'employee'
 	}, {
 		'label': _('Opening Balance'),
 		'fieldtype': 'float',
@@ -64,8 +66,7 @@
 	return columns
 
 def get_data(filters):
-	leave_types = frappe.db.sql_list("SELECT `name` FROM `tabLeave Type` ORDER BY `name` ASC")
-
+	leave_types = frappe.db.get_list('Leave Type', pluck='name', order_by='name')
 	conditions = get_conditions(filters)
 
 	user = frappe.session.user
@@ -113,12 +114,8 @@
 
 				# not be shown on the basis of days left it create in user mind for carry_forward leave
 				row.closing_balance = (new_allocation + opening - (row.leaves_expired + leaves_taken))
-
-
 				row.indent = 1
 				data.append(row)
-				new_leaves_allocated = 0
-
 
 	return data
 
@@ -129,27 +126,37 @@
 	if filters.get('employee'):
 		conditions['name'] = filters.get('employee')
 
-	if filters.get('employee'):
-		conditions['name'] = filters.get('employee')
-
 	if filters.get('company'):
 		conditions['company'] = filters.get('company')
 
+	if filters.get('department'):
+		conditions['department'] = filters.get('department')
+
 	return conditions
 
 def get_department_leave_approver_map(department=None):
-	conditions=''
-	if department:
-		conditions="and (department_name = '%(department)s' or parent_department = '%(department)s')"%{'department': department}
 
 	# get current department and all its child
-	department_list = frappe.db.sql_list(""" SELECT name FROM `tabDepartment` WHERE disabled=0 {0}""".format(conditions)) #nosec
-
+	department_list = frappe.get_list('Department',
+						filters={
+							'disabled': 0
+						},
+						or_filters={
+							'name': department,
+							'parent_department': department
+						},
+						fields=['name'],
+						pluck='name'
+					)
 	# retrieve approvers list from current department and from its subsequent child departments
-	approver_list = frappe.get_all('Department Approver', filters={
-		'parentfield': 'leave_approvers',
-		'parent': ('in', department_list)
-	}, fields=['parent', 'approver'], as_list=1)
+	approver_list = frappe.get_all('Department Approver',
+						filters={
+							'parentfield': 'leave_approvers',
+							'parent': ('in', department_list)
+						},
+						fields=['parent', 'approver'],
+						as_list=1
+					)
 
 	approvers = {}
 
@@ -190,3 +197,40 @@
 			new_allocation += record.leaves
 
 	return new_allocation, expired_leaves
+
+def get_chart_data(data):
+	labels = []
+	datasets = []
+	employee_data = data
+
+	if data and data[0].get('employee_name'):
+		get_dataset_for_chart(employee_data, datasets, labels)
+
+	chart = {
+		'data': {
+			'labels': labels,
+			'datasets': datasets
+		},
+		'type': 'bar',
+		'colors': ['#456789', '#EE8888', '#7E77BF']
+	}
+
+	return chart
+
+def get_dataset_for_chart(employee_data, datasets, labels):
+	leaves = []
+	employee_data = sorted(employee_data, key=lambda k: k['employee_name'])
+
+	for key, group in groupby(employee_data, lambda x: x['employee_name']):
+		for grp in group:
+			if grp.closing_balance:
+				leaves.append(frappe._dict({
+					'leave_type': grp.leave_type,
+					'closing_balance': grp.closing_balance
+				}))
+
+		if leaves:
+			labels.append(key)
+
+	for leave in leaves:
+		datasets.append({'name': leave.leave_type, 'values': [leave.closing_balance]})
diff --git a/erpnext/hr/report/vehicle_expenses/test_vehicle_expenses.py b/erpnext/hr/report/vehicle_expenses/test_vehicle_expenses.py
new file mode 100644
index 0000000..26e0f26
--- /dev/null
+++ b/erpnext/hr/report/vehicle_expenses/test_vehicle_expenses.py
@@ -0,0 +1,73 @@
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import unittest
+import frappe
+from frappe.utils import getdate
+from erpnext.hr.doctype.employee.test_employee import make_employee
+from erpnext.hr.doctype.vehicle_log.vehicle_log import make_expense_claim
+from erpnext.hr.doctype.vehicle_log.test_vehicle_log import get_vehicle, make_vehicle_log
+from erpnext.hr.report.vehicle_expenses.vehicle_expenses import execute
+from erpnext.accounts.utils import get_fiscal_year
+
+class TestVehicleExpenses(unittest.TestCase):
+	@classmethod
+	def setUpClass(self):
+		frappe.db.sql('delete from `tabVehicle Log`')
+
+		employee_id = frappe.db.sql('''select name from `tabEmployee` where name="testdriver@example.com"''')
+		self.employee_id = employee_id[0][0] if employee_id else None
+		if not self.employee_id:
+			self.employee_id = make_employee('testdriver@example.com', company='_Test Company')
+
+		self.license_plate = get_vehicle(self.employee_id)
+
+	def test_vehicle_expenses_based_on_fiscal_year(self):
+		vehicle_log = make_vehicle_log(self.license_plate, self.employee_id, with_services=True)
+		expense_claim = make_expense_claim(vehicle_log.name)
+
+		# Based on Fiscal Year
+		filters = {
+			'filter_based_on': 'Fiscal Year',
+			'fiscal_year': get_fiscal_year(getdate())[0]
+		}
+
+		report = execute(filters)
+
+		expected_data = [{
+			'vehicle': self.license_plate,
+			'make': 'Maruti',
+			'model': 'PCM',
+			'location': 'Mumbai',
+			'log_name': vehicle_log.name,
+			'odometer': 5010,
+			'date': getdate(),
+			'fuel_qty': 50.0,
+			'fuel_price': 500.0,
+			'fuel_expense': 25000.0,
+			'service_expense': 2000.0,
+			'employee': self.employee_id
+		}]
+
+		self.assertEqual(report[1], expected_data)
+
+		# Based on Date Range
+		fiscal_year = get_fiscal_year(getdate(), as_dict=True)
+		filters = {
+			'filter_based_on': 'Date Range',
+			'from_date': fiscal_year.year_start_date,
+			'to_date': fiscal_year.year_end_date
+		}
+
+		report = execute(filters)
+		self.assertEqual(report[1], expected_data)
+
+		# clean up
+		vehicle_log.cancel()
+		frappe.delete_doc('Expense Claim', expense_claim.name)
+		frappe.delete_doc('Vehicle Log', vehicle_log.name)
+
+	def tearDown(self):
+		frappe.delete_doc('Vehicle', self.license_plate, force=1)
+		frappe.delete_doc('Employee', self.employee_id, force=1)
diff --git a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.js b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.js
index b66bebb..879acd1 100644
--- a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.js
+++ b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.js
@@ -1,31 +1,52 @@
 // Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
 // For license information, please see license.txt
-frappe.require("assets/erpnext/js/financial_statements.js", function() {
-	frappe.query_reports["Vehicle Expenses"] = {
-		"filters": [
-			{
-				"fieldname": "fiscal_year",
-				"label": __("Fiscal Year"),
-				"fieldtype": "Link",
-				"options": "Fiscal Year",
-				"default": frappe.defaults.get_user_default("fiscal_year"),
-				"reqd": 1,
-				"on_change": function(query_report) {
-					var fiscal_year = query_report.get_values().fiscal_year;
-					if (!fiscal_year) {
-						return;
-					}
-					frappe.model.with_doc("Fiscal Year", fiscal_year, function(r) {
-						var fy = frappe.model.get_doc("Fiscal Year", fiscal_year);
-
-						frappe.query_report.set_filter({
-							from_date: fy.year_start_date,
-							to_date: fy.year_end_date
-						});
-					});
-				}
-			}
-		]
-	}
-});
+frappe.query_reports["Vehicle Expenses"] = {
+	"filters": [
+		{
+			"fieldname": "filter_based_on",
+			"label": __("Filter Based On"),
+			"fieldtype": "Select",
+			"options": ["Fiscal Year", "Date Range"],
+			"default": ["Fiscal Year"],
+			"reqd": 1
+		},
+		{
+			"fieldname": "fiscal_year",
+			"label": __("Fiscal Year"),
+			"fieldtype": "Link",
+			"options": "Fiscal Year",
+			"default": frappe.defaults.get_user_default("fiscal_year"),
+			"depends_on": "eval: doc.filter_based_on == 'Fiscal Year'",
+			"reqd": 1
+		},
+		{
+			"fieldname": "from_date",
+			"label": __("From Date"),
+			"fieldtype": "Date",
+			"reqd": 1,
+			"depends_on": "eval: doc.filter_based_on == 'Date Range'",
+			"default": frappe.datetime.add_months(frappe.datetime.nowdate(), -12)
+		},
+		{
+			"fieldname": "to_date",
+			"label": __("To Date"),
+			"fieldtype": "Date",
+			"reqd": 1,
+			"depends_on": "eval: doc.filter_based_on == 'Date Range'",
+			"default": frappe.datetime.nowdate()
+		},
+		{
+			"fieldname": "vehicle",
+			"label": __("Vehicle"),
+			"fieldtype": "Link",
+			"options": "Vehicle"
+		},
+		{
+			"fieldname": "employee",
+			"label": __("Employee"),
+			"fieldtype": "Link",
+			"options": "Employee"
+		}
+	]
+};
 
diff --git a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.json b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.json
index 2ab0c14..1a3e5a9 100644
--- a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.json
+++ b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.json
@@ -1,20 +1,23 @@
 {
- "add_total_row": 0, 
- "apply_user_permissions": 1, 
- "creation": "2016-09-09 03:33:40.605734", 
- "disabled": 0, 
- "docstatus": 0, 
- "doctype": "Report", 
- "idx": 2, 
- "is_standard": "Yes", 
- "modified": "2017-02-24 19:59:18.641284", 
- "modified_by": "Administrator", 
- "module": "HR", 
- "name": "Vehicle Expenses", 
- "owner": "Administrator", 
- "ref_doctype": "Vehicle", 
- "report_name": "Vehicle Expenses", 
- "report_type": "Script Report", 
+ "add_total_row": 1,
+ "columns": [],
+ "creation": "2016-09-09 03:33:40.605734",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "filters": [],
+ "idx": 2,
+ "is_standard": "Yes",
+ "modified": "2021-05-16 22:48:22.767535",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Vehicle Expenses",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Vehicle",
+ "report_name": "Vehicle Expenses",
+ "report_type": "Script Report",
  "roles": [
   {
    "role": "Fleet Manager"
diff --git a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py
index eab58ff..d847cbb 100644
--- a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py
+++ b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py
@@ -5,86 +5,209 @@
 import frappe
 import erpnext
 from frappe import _
-from frappe.utils import flt,cstr
+from frappe.utils import flt
 from erpnext.accounts.report.financial_statements import get_period_list
 
 def execute(filters=None):
-	columns, data, chart = [], [], []
-	if filters.get('fiscal_year'):
-		company = erpnext.get_default_company()
-		period_list = get_period_list(filters.get('fiscal_year'), filters.get('fiscal_year'),
-		'', '', 'Fiscal Year', 'Monthly', company=company)
-		columns=get_columns()
-		data=get_log_data(filters)
-		chart=get_chart_data(data,period_list)
+	filters = frappe._dict(filters or {})
+
+	columns = get_columns()
+	data = get_vehicle_log_data(filters)
+	chart = get_chart_data(data, filters)
+
 	return columns, data, None, chart
 
 def get_columns():
-	columns = [_("License") + ":Link/Vehicle:100", _('Create') + ":data:50",
-		_("Model") + ":data:50", _("Location") + ":data:100",
-		_("Log") + ":Link/Vehicle Log:100", _("Odometer") + ":Int:80",
-		_("Date") + ":Date:100", _("Fuel Qty") + ":Float:80",
-		_("Fuel Price") + ":Float:100",_("Fuel Expense") + ":Float:100",
-		_("Service Expense") + ":Float:100"
+	return [
+		{
+			'fieldname': 'vehicle',
+			'fieldtype': 'Link',
+			'label': _('Vehicle'),
+			'options': 'Vehicle',
+			'width': 150
+		},
+		{
+			'fieldname': 'make',
+			'fieldtype': 'Data',
+			'label': _('Make'),
+			'width': 100
+		},
+		{
+			'fieldname': 'model',
+			'fieldtype': 'Data',
+			'label': _('Model'),
+			'width': 80
+		},
+		{
+			'fieldname': 'location',
+			'fieldtype': 'Data',
+			'label': _('Location'),
+			'width': 100
+		},
+		{
+			'fieldname': 'log_name',
+			'fieldtype': 'Link',
+			'label': _('Vehicle Log'),
+			'options': 'Vehicle Log',
+			'width': 100
+		},
+		{
+			'fieldname': 'odometer',
+			'fieldtype': 'Int',
+			'label': _('Odometer Value'),
+			'width': 120
+		},
+		{
+			'fieldname': 'date',
+			'fieldtype': 'Date',
+			'label': _('Date'),
+			'width': 100
+		},
+		{
+			'fieldname': 'fuel_qty',
+			'fieldtype': 'Float',
+			'label': _('Fuel Qty'),
+			'width': 80
+		},
+		{
+			'fieldname': 'fuel_price',
+			'fieldtype': 'Float',
+			'label': _('Fuel Price'),
+			'width': 100
+		},
+		{
+			'fieldname': 'fuel_expense',
+			'fieldtype': 'Currency',
+			'label': _('Fuel Expense'),
+			'width': 150
+		},
+		{
+			'fieldname': 'service_expense',
+			'fieldtype': 'Currency',
+			'label': _('Service Expense'),
+			'width': 150
+		},
+		{
+			'fieldname': 'employee',
+			'fieldtype': 'Link',
+			'label': _('Employee'),
+			'options': 'Employee',
+			'width': 150
+		}
 	]
+
 	return columns
 
-def get_log_data(filters):
-	fy = frappe.db.get_value('Fiscal Year', filters.get('fiscal_year'), ['year_start_date', 'year_end_date'], as_dict=True)
-	data = frappe.db.sql("""select
-			vhcl.license_plate as "License", vhcl.make as "Make", vhcl.model as "Model",
-			vhcl.location as "Location", log.name as "Log", log.odometer as "Odometer",
-			log.date as "Date", log.fuel_qty as "Fuel Qty", log.price as "Fuel Price",
-			log.fuel_qty * log.price as "Fuel Expense"
-		from
+
+def get_vehicle_log_data(filters):
+	start_date, end_date = get_period_dates(filters)
+	conditions, values = get_conditions(filters)
+
+	data = frappe.db.sql("""
+		SELECT
+			vhcl.license_plate as vehicle, vhcl.make, vhcl.model,
+			vhcl.location, log.name as log_name, log.odometer,
+			log.date, log.employee, log.fuel_qty,
+			log.price as fuel_price,
+			log.fuel_qty * log.price as fuel_expense
+		FROM
 			`tabVehicle` vhcl,`tabVehicle Log` log
-		where
-			vhcl.license_plate = log.license_plate and log.docstatus = 1 and date between %s and %s
-		order by date""" ,(fy.year_start_date, fy.year_end_date), as_dict=1)
-	dl=list(data)
-	for row in dl:
-		row["Service Expense"]= get_service_expense(row["Log"])
-	return dl
+		WHERE
+			vhcl.license_plate = log.license_plate
+			and log.docstatus = 1
+			and date between %(start_date)s and %(end_date)s
+			{0}
+		ORDER BY date""".format(conditions), values, as_dict=1)
+
+	for row in data:
+		row['service_expense'] = get_service_expense(row.log_name)
+
+	return data
+
+
+def get_conditions(filters):
+	conditions = ''
+
+	start_date, end_date = get_period_dates(filters)
+	values = {
+		'start_date': start_date,
+		'end_date': end_date
+	}
+
+	if filters.employee:
+		conditions += ' and log.employee = %(employee)s'
+		values['employee'] = filters.employee
+
+	if filters.vehicle:
+		conditions += ' and vhcl.license_plate = %(vehicle)s'
+		values['vehicle'] = filters.vehicle
+
+	return conditions, values
+
+
+def get_period_dates(filters):
+	if filters.filter_based_on == 'Fiscal Year' and filters.fiscal_year:
+		fy = frappe.db.get_value('Fiscal Year', filters.fiscal_year,
+			['year_start_date', 'year_end_date'], as_dict=True)
+		return fy.year_start_date, fy.year_end_date
+	else:
+		return filters.from_date, filters.to_date
+
 
 def get_service_expense(logname):
-	expense_amount = frappe.db.sql("""select sum(expense_amount)
-		from `tabVehicle Log` log,`tabVehicle Service` ser
-		where ser.parent=log.name and log.name=%s""",logname)
-	return flt(expense_amount[0][0]) if expense_amount else 0
+	expense_amount = frappe.db.sql("""
+		SELECT sum(expense_amount)
+		FROM
+			`tabVehicle Log` log, `tabVehicle Service` service
+		WHERE
+			service.parent=log.name and log.name=%s
+	""", logname)
 
-def get_chart_data(data,period_list):
-	fuel_exp_data,service_exp_data,fueldata,servicedata = [],[],[],[]
-	service_exp_data = []
-	fueldata = []
+	return flt(expense_amount[0][0]) if expense_amount else 0.0
+
+
+def get_chart_data(data, filters):
+	period_list = get_period_list(filters.fiscal_year, filters.fiscal_year,
+		filters.from_date, filters.to_date, filters.filter_based_on, 'Monthly')
+
+	fuel_data, service_data = [], []
+
 	for period in period_list:
-		total_fuel_exp=0
-		total_ser_exp=0
-		for row in data:
-			if row["Date"] <= period.to_date and row["Date"] >= period.from_date:
-				total_fuel_exp+=flt(row["Fuel Expense"])
-				total_ser_exp+=flt(row["Service Expense"])
-		fueldata.append([period.key,total_fuel_exp])
-		servicedata.append([period.key,total_ser_exp])
+		total_fuel_exp = 0
+		total_service_exp = 0
 
-	labels = [period.key for period in period_list]
-	fuel_exp_data= [row[1] for row in fueldata]
-	service_exp_data= [row[1] for row in servicedata]
+		for row in data:
+			if row.date <= period.to_date and row.date >= period.from_date:
+				total_fuel_exp += flt(row.fuel_expense)
+				total_service_exp += flt(row.service_expense)
+
+		fuel_data.append([period.key, total_fuel_exp])
+		service_data.append([period.key, total_service_exp])
+
+	labels = [period.label for period in period_list]
+	fuel_exp_data= [row[1] for row in fuel_data]
+	service_exp_data= [row[1] for row in service_data]
+
 	datasets = []
 	if fuel_exp_data:
 		datasets.append({
-			'name': 'Fuel Expenses',
+			'name': _('Fuel Expenses'),
 			'values': fuel_exp_data
 		})
+
 	if service_exp_data:
 		datasets.append({
-			'name': 'Service Expenses',
+			'name': _('Service Expenses'),
 			'values': service_exp_data
 		})
+
 	chart = {
-		"data": {
+		'data': {
 			'labels': labels,
 			'datasets': datasets
-		}
+		},
+		'type': 'line',
+		'fieldtype': 'Currency'
 	}
-	chart["type"] = "line"
+
 	return chart
diff --git a/erpnext/hr/utils.py b/erpnext/hr/utils.py
index 80189e8..ebb1734 100644
--- a/erpnext/hr/utils.py
+++ b/erpnext/hr/utils.py
@@ -269,6 +269,7 @@
 	total_exemption_amount = sum([flt(d.total_exemption_amount) for d in exemptions.values()])
 	return total_exemption_amount
 
+@frappe.whitelist()
 def get_leave_period(from_date, to_date, company):
 	leave_period = frappe.db.sql("""
 		select name, from_date, to_date
diff --git a/erpnext/loan_management/workspace/loan_management/loan_management.json b/erpnext/loan_management/workspace/loan_management/loan_management.json
index 18559dc..d0b67f7 100644
--- a/erpnext/loan_management/workspace/loan_management/loan_management.json
+++ b/erpnext/loan_management/workspace/loan_management/loan_management.json
@@ -12,7 +12,7 @@
  "idx": 0,
  "is_default": 0,
  "is_standard": 1,
- "label": "Loan Management",
+ "label": "Loans",
  "links": [
   {
    "hidden": 0,
@@ -220,10 +220,10 @@
    "type": "Link"
   }
  ],
- "modified": "2021-02-18 17:31:53.586508",
+ "modified": "2021-05-25 17:31:53.586508",
  "modified_by": "Administrator",
  "module": "Loan Management",
- "name": "Loan Management",
+ "name": "Loans",
  "owner": "Administrator",
  "pin_to_bottom": 0,
  "pin_to_top": 0,
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js
index ddbcdfd..44712d5 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js
+++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.js
@@ -2,40 +2,36 @@
 // License: GNU General Public License v3. See license.txt
 
 frappe.provide("erpnext.maintenance");
-
 frappe.ui.form.on('Maintenance Schedule', {
-	setup: function(frm) {
+	setup: function (frm) {
 		frm.set_query('contact_person', erpnext.queries.contact_query);
 		frm.set_query('customer_address', erpnext.queries.address_query);
 		frm.set_query('customer', erpnext.queries.customer);
-
-		frm.add_fetch('item_code', 'item_name', 'item_name');
-		frm.add_fetch('item_code', 'description', 'description');
 	},
-	onload: function(frm) {
+	onload: function (frm) {
 		if (!frm.doc.status) {
-			frm.set_value({status:'Draft'});
+			frm.set_value({ status: 'Draft' });
 		}
 		if (frm.doc.__islocal) {
-			frm.set_value({transaction_date: frappe.datetime.get_today()});
+			frm.set_value({ transaction_date: frappe.datetime.get_today() });
 		}
 	},
-	refresh: function(frm) {
+	refresh: function (frm) {
 		setTimeout(() => {
 			frm.toggle_display('generate_schedule', !(frm.is_new()));
 			frm.toggle_display('schedule', !(frm.is_new()));
-		},10);
+		}, 10);
 	},
-	customer: function(frm) {
+	customer: function (frm) {
 		erpnext.utils.get_party_details(frm)
 	},
-	customer_address: function(frm) {
+	customer_address: function (frm) {
 		erpnext.utils.get_address_display(frm, 'customer_address', 'address_display');
 	},
-	contact_person: function(frm) {
+	contact_person: function (frm) {
 		erpnext.utils.get_contact_details(frm);
 	},
-	generate_schedule: function(frm) {
+	generate_schedule: function (frm) {
 		if (frm.is_new()) {
 			frappe.msgprint(__('Please save first'));
 		} else {
@@ -46,14 +42,14 @@
 
 // TODO commonify this code
 erpnext.maintenance.MaintenanceSchedule = frappe.ui.form.Controller.extend({
-	refresh: function() {
-		frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer'}
+	refresh: function () {
+		frappe.dynamic_link = { doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer' };
 
 		var me = this;
 
 		if (this.frm.doc.docstatus === 0) {
 			this.frm.add_custom_button(__('Sales Order'),
-				function() {
+				function () {
 					erpnext.utils.map_current_doc({
 						method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_schedule",
 						source_doctype: "Sales Order",
@@ -68,52 +64,107 @@
 					});
 				}, __("Get Items From"));
 		} else if (this.frm.doc.docstatus === 1) {
-			this.frm.add_custom_button(__('Create Maintenance Visit'), function() {
-				frappe.model.open_mapped_doc({
-					method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.make_maintenance_visit",
-					source_name: me.frm.doc.name,
-					frm: me.frm
+			let schedules = me.frm.doc.schedules;
+			let flag = schedules.some(schedule => schedule.completion_status === "Pending");
+			if (flag) {
+				this.frm.add_custom_button(__('Maintenance Visit'), function () {
+					let options = "";
+					
+					me.frm.call('get_pending_data', {data_type: "items"}).then(r => {
+						options = r.message;
+						
+						let schedule_id = "";
+						let d = new frappe.ui.Dialog({
+							title: __("Enter Visit Details"),
+							fields: [{
+								fieldtype: "Select",
+								fieldname: "item_name",
+								label: __("Item Name"),
+								options: options,
+								reqd: 1,
+								onchange: function () {
+									let field = d.get_field("scheduled_date");
+									me.frm.call('get_pending_data',
+										{
+											item_name: this.value, 
+											data_type: "date"
+										}).then(r => {
+										field.df.options = r.message;
+										field.refresh();
+									});
+								}
+							},
+							{
+								label: __('Scheduled Date'),
+								fieldname: 'scheduled_date',
+								fieldtype: 'Select',
+								options: "",
+								reqd: 1,
+								onchange: function () {
+									let field = d.get_field('item_name');
+									me.frm.call(
+										'get_pending_data',
+										{
+											item_name: field.value,
+											s_date: this.value,
+											data_type: "id"
+										}).then(r => {
+										schedule_id = r.message;
+									});
+								}
+							},
+							],
+							primary_action_label: 'Create Visit',
+							primary_action(values) {
+								frappe.call({
+									method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.make_maintenance_visit",
+									args: {
+										item_name: values.item_name,
+										s_id: schedule_id,
+										source_name: me.frm.doc.name,
+									},
+									callback: function (r) {
+										if (!r.exc) {
+											frappe.model.sync(r.message);
+											frappe.set_route("Form", r.message.doctype, r.message.name);
+										}
+									}
+								});
+								d.hide();
+							}
+						});
+						d.show();
 				});
-			}, __('Create'));
+				}, __('Create'));
+			}
 		}
 	},
 
-	start_date: function(doc, cdt, cdn) {
+	start_date: function (doc, cdt, cdn) {
 		this.set_no_of_visits(doc, cdt, cdn);
 	},
 
-	end_date: function(doc, cdt, cdn) {
+	end_date: function (doc, cdt, cdn) {
 		this.set_no_of_visits(doc, cdt, cdn);
 	},
 
-	periodicity: function(doc, cdt, cdn) {
+	periodicity: function (doc, cdt, cdn) {
+		this.set_no_of_visits(doc, cdt, cdn);
+
+	},
+	no_of_visits: function (doc, cdt, cdn) {
 		this.set_no_of_visits(doc, cdt, cdn);
 	},
 
-	set_no_of_visits: function(doc, cdt, cdn) {
+	set_no_of_visits: function (doc, cdt, cdn) {
 		var item = frappe.get_doc(cdt, cdn);
-
-		if (item.start_date && item.end_date && item.periodicity) {
-			if(item.start_date > item.end_date) {
-				frappe.msgprint(__("Row {0}:Start Date must be before End Date", [item.idx]));
-				return;
-			}
-
-			var date_diff = frappe.datetime.get_diff(item.end_date, item.start_date) + 1;
-
-			var days_in_period = {
-				"Weekly": 7,
-				"Monthly": 30,
-				"Quarterly": 91,
-				"Half Yearly": 182,
-				"Yearly": 365
-			}
-
-			var no_of_visits = cint(date_diff / days_in_period[item.periodicity]);
-			frappe.model.set_value(item.doctype, item.name, "no_of_visits", no_of_visits);
+		let me = this;
+		if (item.start_date && item.periodicity) {
+			me.frm.call('validate_end_date_visits');
+			
 		}
 	},
 });
 
-$.extend(cur_frm.cscript, new erpnext.maintenance.MaintenanceSchedule({frm: cur_frm}));
+$.extend(cur_frm.cscript, new erpnext.maintenance.MaintenanceSchedule({ frm: cur_frm }));
 
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json
index 606d22f..4f89a67 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json
+++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.json
@@ -1,852 +1,264 @@
 {
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 0, 
- "autoname": "naming_series:", 
- "beta": 0, 
- "creation": "2013-01-10 16:34:30", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "Document", 
- "editable_grid": 0, 
+ "actions": [],
+ "autoname": "naming_series:",
+ "creation": "2013-01-10 16:34:30",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "engine": "InnoDB",
+ "field_order": [
+  "customer_details",
+  "naming_series",
+  "customer",
+  "column_break0",
+  "status",
+  "transaction_date",
+  "items_section",
+  "items",
+  "schedule",
+  "generate_schedule",
+  "schedules",
+  "contact_info",
+  "customer_name",
+  "contact_person",
+  "contact_mobile",
+  "contact_email",
+  "contact_display",
+  "column_break_17",
+  "customer_address",
+  "address_display",
+  "territory",
+  "customer_group",
+  "company",
+  "amended_from"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "customer_details", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldtype": "Section Break", 
-   "options": "fa fa-user", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "customer_details",
+   "fieldtype": "Section Break",
+   "oldfieldtype": "Section Break",
+   "options": "fa fa-user"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "default": "", 
-   "fieldname": "naming_series", 
-   "fieldtype": "Select", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Series", 
-   "length": 0, 
-   "no_copy": 1, 
-   "options": "MAT-MSH-.YYYY.-", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 1, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "naming_series",
+   "fieldtype": "Select",
+   "label": "Series",
+   "no_copy": 1,
+   "options": "MAT-MSH-.YYYY.-",
+   "print_hide": 1,
+   "reqd": 1,
+   "set_only_once": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "customer", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 1, 
-   "label": "Customer", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "customer", 
-   "oldfieldtype": "Link", 
-   "options": "Customer", 
-   "permlevel": 0, 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 1, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "customer",
+   "fieldtype": "Link",
+   "in_standard_filter": 1,
+   "label": "Customer",
+   "oldfieldname": "customer",
+   "oldfieldtype": "Link",
+   "options": "Customer",
+   "print_hide": 1,
+   "search_index": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "column_break0", 
-   "fieldtype": "Column Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldtype": "Column Break", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "column_break0",
+   "fieldtype": "Column Break",
+   "oldfieldtype": "Column Break"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "default": "Draft", 
-   "fieldname": "status", 
-   "fieldtype": "Select", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 1, 
-   "label": "Status", 
-   "length": 0, 
-   "no_copy": 1, 
-   "oldfieldname": "status", 
-   "oldfieldtype": "Select", 
-   "options": "\nDraft\nSubmitted\nCancelled", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "default": "Draft",
+   "fieldname": "status",
+   "fieldtype": "Select",
+   "in_standard_filter": 1,
+   "label": "Status",
+   "no_copy": 1,
+   "oldfieldname": "status",
+   "oldfieldtype": "Select",
+   "options": "\nDraft\nSubmitted\nCancelled",
+   "read_only": 1,
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "transaction_date", 
-   "fieldtype": "Date", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Transaction Date", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "transaction_date", 
-   "oldfieldtype": "Date", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "transaction_date",
+   "fieldtype": "Date",
+   "label": "Transaction Date",
+   "oldfieldname": "transaction_date",
+   "oldfieldtype": "Date",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "items_section", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldtype": "Section Break", 
-   "options": "fa fa-shopping-cart", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "items_section",
+   "fieldtype": "Section Break",
+   "oldfieldtype": "Section Break",
+   "options": "fa fa-shopping-cart"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "items", 
-   "fieldtype": "Table", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Items", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "item_maintenance_detail", 
-   "oldfieldtype": "Table", 
-   "options": "Maintenance Schedule Item", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "items",
+   "fieldtype": "Table",
+   "label": "Items",
+   "oldfieldname": "item_maintenance_detail",
+   "oldfieldtype": "Table",
+   "options": "Maintenance Schedule Item",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "schedule", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Schedule", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldtype": "Section Break", 
-   "options": "fa fa-time", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "schedule",
+   "fieldtype": "Section Break",
+   "label": "Schedule",
+   "oldfieldtype": "Section Break",
+   "options": "fa fa-time"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "generate_schedule", 
-   "fieldtype": "Button", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Generate Schedule", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldtype": "Button", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "generate_schedule",
+   "fieldtype": "Button",
+   "label": "Generate Schedule",
+   "oldfieldtype": "Button"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "schedules", 
-   "fieldtype": "Table", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Schedules", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "schedules", 
-   "oldfieldtype": "Table", 
-   "options": "Maintenance Schedule Detail", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "schedules",
+   "fieldtype": "Table",
+   "label": "Schedules",
+   "oldfieldname": "schedules",
+   "oldfieldtype": "Table",
+   "options": "Maintenance Schedule Detail"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "contact_info", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Contact Info", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "contact_info",
+   "fieldtype": "Section Break",
+   "label": "Contact Info"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 1, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "depends_on": "customer", 
-   "fieldname": "customer_name", 
-   "fieldtype": "Data", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 1, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Customer Name", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "customer_name", 
-   "oldfieldtype": "Data", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "bold": 1,
+   "depends_on": "customer",
+   "fieldname": "customer_name",
+   "fieldtype": "Data",
+   "in_global_search": 1,
+   "in_list_view": 1,
+   "label": "Customer Name",
+   "oldfieldname": "customer_name",
+   "oldfieldtype": "Data",
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "depends_on": "customer", 
-   "fieldname": "contact_person", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Contact Person", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Contact", 
-   "permlevel": 0, 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "depends_on": "customer",
+   "fieldname": "contact_person",
+   "fieldtype": "Link",
+   "label": "Contact Person",
+   "options": "Contact",
+   "print_hide": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "depends_on": "customer", 
-   "fieldname": "contact_mobile", 
-   "fieldtype": "Data", 
-   "hidden": 1, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Mobile No", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "depends_on": "customer",
+   "fieldname": "contact_mobile",
+   "fieldtype": "Data",
+   "hidden": 1,
+   "label": "Mobile No",
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "depends_on": "customer", 
-   "fieldname": "contact_email", 
-   "fieldtype": "Data", 
-   "hidden": 1, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Contact Email", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "depends_on": "customer",
+   "fieldname": "contact_email",
+   "fieldtype": "Data",
+   "hidden": 1,
+   "label": "Contact Email",
+   "print_hide": 1,
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "contact_display", 
-   "fieldtype": "Small Text", 
-   "hidden": 1, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 1, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Contact", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "contact_display",
+   "fieldtype": "Small Text",
+   "hidden": 1,
+   "in_global_search": 1,
+   "label": "Contact",
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "column_break_17", 
-   "fieldtype": "Column Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "column_break_17",
+   "fieldtype": "Column Break"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "depends_on": "customer", 
-   "fieldname": "customer_address", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Customer Address", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Address", 
-   "permlevel": 0, 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "depends_on": "customer",
+   "fieldname": "customer_address",
+   "fieldtype": "Link",
+   "label": "Customer Address",
+   "options": "Address",
+   "print_hide": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "address_display", 
-   "fieldtype": "Small Text", 
-   "hidden": 1, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Address", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "address_display",
+   "fieldtype": "Small Text",
+   "hidden": 1,
+   "label": "Address",
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "depends_on": "customer", 
-   "description": "", 
-   "fieldname": "territory", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Territory", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "territory", 
-   "oldfieldtype": "Link", 
-   "options": "Territory", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "depends_on": "customer",
+   "fieldname": "territory",
+   "fieldtype": "Link",
+   "label": "Territory",
+   "oldfieldname": "territory",
+   "oldfieldtype": "Link",
+   "options": "Territory"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "depends_on": "customer", 
-   "description": "", 
-   "fieldname": "customer_group", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Customer Group", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Customer Group", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "depends_on": "customer",
+   "fieldname": "customer_group",
+   "fieldtype": "Link",
+   "label": "Customer Group",
+   "options": "Customer Group"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "company", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Company", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "company", 
-   "oldfieldtype": "Link", 
-   "options": "Company", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 1, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "label": "Company",
+   "oldfieldname": "company",
+   "oldfieldtype": "Link",
+   "options": "Company",
+   "remember_last_selected_value": 1,
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "amended_from", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Amended From", 
-   "length": 0, 
-   "no_copy": 1, 
-   "options": "Maintenance Schedule", 
-   "permlevel": 0, 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
+   "fieldname": "amended_from",
+   "fieldtype": "Link",
+   "label": "Amended From",
+   "no_copy": 1,
+   "options": "Maintenance Schedule",
+   "print_hide": 1,
+   "read_only": 1
   }
- ], 
- "has_web_view": 0, 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "icon": "fa fa-calendar", 
- "idx": 1, 
- "image_view": 0, 
- "in_create": 0, 
- "is_submittable": 1, 
- "issingle": 0, 
- "istable": 0, 
- "max_attachments": 0, 
- "modified": "2020-09-18 17:26:09.703215", 
- "modified_by": "Administrator", 
- "module": "Maintenance", 
- "name": "Maintenance Schedule", 
- "owner": "Administrator", 
+ ],
+ "icon": "fa fa-calendar",
+ "idx": 1,
+ "is_submittable": 1,
+ "links": [
+  {
+   "group": "Visits",
+   "link_doctype": "Maintenance Visit",
+   "link_fieldname": "maintenance_schedule"
+  }
+ ],
+ "modified": "2021-05-27 16:05:10.746465",
+ "modified_by": "Administrator",
+ "module": "Maintenance",
+ "name": "Maintenance Schedule",
+ "owner": "Administrator",
  "permissions": [
   {
-   "amend": 1, 
-   "cancel": 1, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 0, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Maintenance Manager", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 1, 
+   "amend": 1,
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Maintenance Manager",
+   "share": 1,
+   "submit": 1,
    "write": 1
   }
- ], 
- "quick_entry": 0, 
- "read_only": 0, 
- "read_only_onload": 0, 
- "search_fields": "status,customer,customer_name", 
- "show_name_in_global_search": 0, 
- "sort_order": "DESC", 
- "timeline_field": "customer", 
- "track_changes": 0, 
- "track_seen": 0, 
- "track_views": 0
+ ],
+ "search_fields": "status,customer,customer_name",
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "timeline_field": "customer"
 }
\ No newline at end of file
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
index 0aefe19..d6e42f3 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
+++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
@@ -4,12 +4,13 @@
 from __future__ import unicode_literals
 import frappe
 
-from frappe.utils import add_days, getdate, cint, cstr
+from frappe.utils import add_days, getdate, cint, cstr, date_diff, formatdate
 
 from frappe import throw, _
 from erpnext.utilities.transaction_base import TransactionBase, delete_events
 from erpnext.stock.utils import get_valid_serial_nos
 from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
+from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
 
 class MaintenanceSchedule(TransactionBase):
 	@frappe.whitelist()
@@ -32,8 +33,40 @@
 				child.idx = count
 				count = count + 1
 				child.sales_person = d.sales_person
+				child.completion_status = "Pending"
+				child.item_reference = d.name
 
-		self.save()
+	@frappe.whitelist()
+	def validate_end_date_visits(self):
+		days_in_period = {
+			"Weekly": 7,
+			"Monthly": 30,
+			"Quarterly": 91,
+			"Half Yearly": 182,
+			"Yearly": 365
+		}
+		for item in self.items:
+			if item.periodicity and item.start_date:
+				if not item.end_date:
+					if item.no_of_visits:
+						item.end_date = add_days(item.start_date, item.no_of_visits * days_in_period[item.periodicity])
+					else:
+						item.end_date = add_days(item.start_date, days_in_period[item.periodicity])
+						
+				diff = date_diff(item.end_date, item.start_date) + 1
+				no_of_visits = cint(diff / days_in_period[item.periodicity])
+				
+				if not item.no_of_visits or item.no_of_visits == 0:
+					item.end_date = add_days(item.start_date, days_in_period[item.periodicity])
+					diff = date_diff(item.end_date, item.start_date) + 1
+					item.no_of_visits = cint(diff / days_in_period[item.periodicity])
+					
+				elif item.no_of_visits > no_of_visits:
+					item.end_date = add_days(item.start_date, item.no_of_visits * days_in_period[item.periodicity])
+
+				elif item.no_of_visits < no_of_visits:
+					item.end_date = add_days(item.start_date, item.no_of_visits * days_in_period[item.periodicity])
+
 
 	def on_submit(self):
 		if not self.get('schedules'):
@@ -58,9 +91,10 @@
 
 			if no_email_sp:
 				frappe.msgprint(
-					frappe._("Setting Events to {0}, since the Employee attached to the below Sales Persons does not have a User ID{1}").format(
+					_("Setting Events to {0}, since the Employee attached to the below Sales Persons does not have a User ID{1}").format(
 						self.owner, "<br>" + "<br>".join(no_email_sp)
-				))
+					)
+				)
 
 			scheduled_date = frappe.db.sql("""select scheduled_date from
 				`tabMaintenance Schedule Detail` where sales_person=%s and item_code=%s and
@@ -106,7 +140,7 @@
 		if employee:
 			holiday_list = get_holiday_list_for_employee(employee)
 		else:
-			holiday_list = frappe.get_cached_value('Company',  self.company,  "default_holiday_list")
+			holiday_list = frappe.get_cached_value('Company', self.company, "default_holiday_list")
 
 		holidays = frappe.db.sql_list('''select holiday_date from `tabHoliday` where parent=%s''', holiday_list)
 
@@ -135,8 +169,7 @@
 				}
 
 				if date_diff < days_in_period[d.periodicity]:
-					throw(_("Row {0}: To set {1} periodicity, difference between from and to date \
-						must be greater than or equal to {2}")
+					throw(_("Row {0}: To set {1} periodicity, difference between from and to date must be greater than or equal to {2}")
 						.format(d.idx, d.periodicity, days_in_period[d.periodicity]))
 
 	def validate_maintenance_detail(self):
@@ -166,13 +199,15 @@
 					throw(_("Maintenance Schedule {0} exists against {1}").format(chk[0][0], d.sales_order))
 
 	def validate(self):
+		self.validate_end_date_visits()
 		self.validate_maintenance_detail()
 		self.validate_dates_with_periodicity()
 		self.validate_sales_order()
+		self.generate_schedule()
 
 	def on_update(self):
 		frappe.db.set(self, 'status', 'Draft')
-
+	
 	def update_amc_date(self, serial_nos, amc_expiry_date=None):
 		for serial_no in serial_nos:
 			serial_no_doc = frappe.get_doc("Serial No", serial_no)
@@ -202,8 +237,8 @@
 
 			if not sr_details.warehouse and sr_details.delivery_date and \
 				getdate(sr_details.delivery_date) >= getdate(amc_start_date):
-					throw(_("Maintenance start date can not be before delivery date for Serial No {0}")
-						.format(serial_no))
+				throw(_("Maintenance start date can not be before delivery date for Serial No {0}")
+					.format(serial_no))
 
 	def validate_schedule(self):
 		item_lst1 =[]
@@ -245,13 +280,50 @@
 	def on_trash(self):
 		delete_events(self.doctype, self.name)
 
+	@frappe.whitelist()
+	def get_pending_data(self, data_type, s_date=None, item_name=None):
+		if data_type == "date":
+			dates = ""
+			for schedule in self.schedules:
+				if schedule.item_name == item_name and schedule.completion_status == "Pending":
+					dates = dates + "\n" + formatdate(schedule.scheduled_date, "dd-MM-yyyy")
+			return dates
+		elif data_type == "items":
+			items = ""
+			for item in self.items:
+				for schedule in self.schedules:
+					if item.item_name == schedule.item_name and schedule.completion_status == "Pending":
+						items = items + "\n" + item.item_name
+						break
+			return items
+		elif data_type == "id":
+			for schedule in self.schedules:
+				if schedule.item_name == item_name and s_date == formatdate(schedule.scheduled_date, "dd-mm-yyyy"):
+					return schedule.name
+				
 @frappe.whitelist()
-def make_maintenance_visit(source_name, target_doc=None):
+def update_serial_nos(s_id):
+	serial_nos = frappe.db.get_value('Maintenance Schedule Detail', s_id, 'serial_no')
+	if serial_nos:
+		serial_nos = get_serial_nos(serial_nos)
+		return serial_nos
+	else:
+		return False
+
+@frappe.whitelist()
+def make_maintenance_visit(source_name, target_doc=None, item_name=None, s_id=None):
 	from frappe.model.mapper import get_mapped_doc
 
-	def update_status(source, target, parent):
+	def update_status_and_detail(source, target, parent):
 		target.maintenance_type = "Scheduled"
-
+		target.maintenance_schedule = source.name
+		target.maintenance_schedule_detail = s_id
+		
+	def update_sales(source, target, parent):
+		sales_person = frappe.db.get_value('Maintenance Schedule Detail', s_id, 'sales_person')
+		target.service_person = sales_person
+		target.serial_no = ''
+	
 	doclist = get_mapped_doc("Maintenance Schedule", source_name, {
 		"Maintenance Schedule": {
 			"doctype": "Maintenance Visit",
@@ -261,15 +333,12 @@
 			"validation": {
 				"docstatus": ["=", 1]
 			},
-			"postprocess": update_status
+			"postprocess": update_status_and_detail
 		},
 		"Maintenance Schedule Item": {
 			"doctype": "Maintenance Visit Purpose",
-			"field_map": {
-				"parent": "prevdoc_docname",
-				"parenttype": "prevdoc_doctype",
-				"sales_person": "service_person"
-			}
+			"condition": lambda doc: doc.item_name == item_name,
+			"postprocess": update_sales
 		}
 	}, target_doc)
 
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py
index 3c307e9..09981ba 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py
+++ b/erpnext/maintenance/doctype/maintenance_schedule/test_maintenance_schedule.py
@@ -2,7 +2,8 @@
 # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
 # See license.txt
 from __future__ import unicode_literals
-from frappe.utils.data import get_datetime, add_days
+from frappe.utils.data import add_days, today, formatdate
+from erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule import make_maintenance_visit
 
 import frappe
 import unittest
@@ -21,7 +22,57 @@
 		ms.cancel()
 		events_after_cancel = get_events(ms)
 		self.assertTrue(len(events_after_cancel) == 0)
+	
+	def test_make_schedule(self):
+		ms = make_maintenance_schedule()
+		ms.save()
+		i = ms.items[0]
+		expected_dates = []
+		expected_end_date = add_days(i.start_date, i.no_of_visits * 7)
+		self.assertEqual(i.end_date, expected_end_date)
 
+		i.no_of_visits = 2
+		ms.save()
+		expected_end_date = add_days(i.start_date, i.no_of_visits * 7)
+		self.assertEqual(i.end_date, expected_end_date)
+
+		items = ms.get_pending_data(data_type = "items")
+		items = items.split('\n')
+		items.pop(0)
+		expected_items = ['_Test Item']
+		self.assertTrue(items, expected_items)
+
+		# "dates" contains all generated schedule dates
+		dates = ms.get_pending_data(data_type = "date", item_name = i.item_name)
+		dates = dates.split('\n')
+		dates.pop(0)
+		expected_dates.append(formatdate(add_days(i.start_date, 7), "dd-MM-yyyy"))
+		expected_dates.append(formatdate(add_days(i.start_date, 14), "dd-MM-yyyy"))
+
+		# test for generated schedule dates
+		self.assertEqual(dates, expected_dates)
+
+		ms.submit()
+		s_id = ms.get_pending_data(data_type = "id", item_name = i.item_name, s_date = expected_dates[1])
+		test = make_maintenance_visit(source_name = ms.name, item_name = "_Test Item", s_id = s_id)
+		visit = frappe.new_doc('Maintenance Visit')
+		visit = test
+		visit.maintenance_schedule = ms.name
+		visit.maintenance_schedule_detail = s_id
+		visit.completion_status = "Partially Completed"
+		visit.set('purposes', [{
+			'item_code': i.item_code,
+			'description': "test",
+			'work_done': "test",
+			'service_person': "Sales Team",
+		}])
+		visit.save()
+		visit.submit()
+		ms = frappe.get_doc('Maintenance Schedule', ms.name)
+
+		#checks if visit status is back updated in schedule
+		self.assertTrue(ms.schedules[1].completion_status, "Partially Completed")
+	
 def get_events(ms):
 	return frappe.get_all("Event Participants", filters={
 			"reference_doctype": ms.doctype,
@@ -33,12 +84,11 @@
 	ms = frappe.new_doc("Maintenance Schedule")
 	ms.company = "_Test Company"
 	ms.customer = "_Test Customer"
-	ms.transaction_date = get_datetime()
+	ms.transaction_date = today()
 
 	ms.append("items", {
 		"item_code": "_Test Item",
-		"start_date": get_datetime(),
-		"end_date": add_days(get_datetime(), 32),
+		"start_date": today(),
 		"periodicity": "Weekly",
 		"no_of_visits": 4,
 		"sales_person": "Sales Team",
diff --git a/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json b/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json
index 7cd3086..8ccef6a 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json
+++ b/erpnext/maintenance/doctype/maintenance_schedule_detail/maintenance_schedule_detail.json
@@ -1,222 +1,137 @@
 {
- "allow_copy": 0, 
- "allow_import": 0, 
- "allow_rename": 0, 
- "autoname": "hash", 
- "beta": 0, 
- "creation": "2013-02-22 01:28:05", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "Document", 
- "editable_grid": 1, 
- "engine": "InnoDB", 
+ "actions": [],
+ "autoname": "hash",
+ "creation": "2013-02-22 01:28:05",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "item_code",
+  "item_name",
+  "column_break_3",
+  "scheduled_date",
+  "actual_date",
+  "section_break_6",
+  "sales_person",
+  "column_break_8",
+  "completion_status",
+  "section_break_10",
+  "serial_no",
+  "item_reference"
+ ],
  "fields": [
   {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "item_code", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Item Code", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "item_code", 
-   "oldfieldtype": "Link", 
-   "options": "Item", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 1, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "columns": 2,
+   "fieldname": "item_code",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Item Code",
+   "oldfieldname": "item_code",
+   "oldfieldtype": "Link",
+   "options": "Item",
+   "read_only": 1,
+   "search_index": 1
+  },
   {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "item_name", 
-   "fieldtype": "Data", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 1, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Item Name", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "item_name", 
-   "oldfieldtype": "Data", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "item_name",
+   "fieldtype": "Data",
+   "in_global_search": 1,
+   "label": "Item Name",
+   "oldfieldname": "item_name",
+   "oldfieldtype": "Data",
+   "read_only": 1
+  },
   {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "scheduled_date", 
-   "fieldtype": "Date", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Scheduled Date", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "scheduled_date", 
-   "oldfieldtype": "Date", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 1, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "columns": 2,
+   "fieldname": "scheduled_date",
+   "fieldtype": "Date",
+   "in_list_view": 1,
+   "label": "Scheduled Date",
+   "oldfieldname": "scheduled_date",
+   "oldfieldtype": "Date",
+   "reqd": 1,
+   "search_index": 1
+  },
   {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "actual_date", 
-   "fieldtype": "Date", 
-   "hidden": 1, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Actual Date", 
-   "length": 0, 
-   "no_copy": 1, 
-   "oldfieldname": "actual_date", 
-   "oldfieldtype": "Date", 
-   "permlevel": 0, 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 1, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "actual_date",
+   "fieldtype": "Date",
+   "in_list_view": 1,
+   "label": "Actual Date",
+   "no_copy": 1,
+   "oldfieldname": "actual_date",
+   "oldfieldtype": "Date",
+   "print_hide": 1,
+   "read_only": 1,
+   "report_hide": 1
+  },
   {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "sales_person", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Sales Person", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "incharge_name", 
-   "oldfieldtype": "Link", 
-   "options": "Sales Person", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "allow_on_submit": 1,
+   "columns": 2,
+   "fieldname": "sales_person",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Sales Person",
+   "oldfieldname": "incharge_name",
+   "oldfieldtype": "Link",
+   "options": "Sales Person",
+   "read_only_depends_on": "eval:doc.completion_status != \"Pending\""
+  },
   {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "serial_no", 
-   "fieldtype": "Small Text", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Serial No", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "serial_no", 
-   "oldfieldtype": "Small Text", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "print_width": "160px", 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0, 
+   "fieldname": "serial_no",
+   "fieldtype": "Small Text",
+   "in_list_view": 1,
+   "label": "Serial No",
+   "oldfieldname": "serial_no",
+   "oldfieldtype": "Small Text",
+   "print_width": "160px",
+   "read_only": 1,
    "width": "160px"
+  },
+  {
+   "columns": 2,
+   "fieldname": "completion_status",
+   "fieldtype": "Select",
+   "in_list_view": 1,
+   "label": "Completion Status",
+   "options": "Pending\nPartially Completed\nFully Completed",
+   "read_only": 1
+  },
+  {
+   "fieldname": "column_break_3",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "section_break_6",
+   "fieldtype": "Section Break"
+  },
+  {
+   "fieldname": "column_break_8",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "section_break_10",
+   "fieldtype": "Section Break"
+  },
+  {
+   "fieldname": "item_reference",
+   "fieldtype": "Link",
+   "hidden": 1,
+   "label": "Item Reference",
+   "options": "Maintenance Schedule Item",
+   "read_only": 1
   }
- ], 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "idx": 1, 
- "image_view": 0, 
- "in_create": 0, 
-
- "is_submittable": 0, 
- "issingle": 0, 
- "istable": 1, 
- "max_attachments": 0, 
- "modified": "2017-02-17 17:05:44.644663", 
- "modified_by": "Administrator", 
- "module": "Maintenance", 
- "name": "Maintenance Schedule Detail", 
- "owner": "Administrator", 
- "permissions": [], 
- "quick_entry": 0, 
- "read_only": 0, 
- "read_only_onload": 0, 
- "show_name_in_global_search": 0, 
- "track_changes": 1, 
- "track_seen": 0
+ ],
+ "idx": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-05-27 16:07:25.905015",
+ "modified_by": "Administrator",
+ "module": "Maintenance",
+ "name": "Maintenance Schedule Detail",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/maintenance/doctype/maintenance_schedule_item/maintenance_schedule_item.json b/erpnext/maintenance/doctype/maintenance_schedule_item/maintenance_schedule_item.json
index b371dfc..3dacdea 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule_item/maintenance_schedule_item.json
+++ b/erpnext/maintenance/doctype/maintenance_schedule_item/maintenance_schedule_item.json
@@ -1,431 +1,160 @@
 {
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 0, 
- "autoname": "hash", 
- "beta": 0, 
- "creation": "2013-02-22 01:28:05", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "Document", 
- "editable_grid": 1, 
- "engine": "InnoDB", 
+ "actions": [],
+ "autoname": "hash",
+ "creation": "2013-02-22 01:28:05",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "item_code",
+  "item_name",
+  "description",
+  "column_break_4",
+  "start_date",
+  "end_date",
+  "periodicity",
+  "schedule_details",
+  "no_of_visits",
+  "column_break_10",
+  "sales_person",
+  "reference",
+  "serial_no",
+  "sales_order"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "item_code", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Item Code", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "item_code", 
-   "oldfieldtype": "Link", 
-   "options": "Item", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 1, 
-   "set_only_once": 0, 
-   "translatable": 0,
-   "unique": 0
-  }, 
+   "columns": 2,
+   "fieldname": "item_code",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Item Code",
+   "oldfieldname": "item_code",
+   "oldfieldtype": "Link",
+   "options": "Item",
+   "reqd": 1,
+   "search_index": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
+   "columns": 1,
    "fetch_from": "item_code.item_name",
-   "fieldname": "item_name", 
-   "fieldtype": "Data", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 1, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Item Name", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "item_name", 
-   "oldfieldtype": "Data", 
-   "options": "", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0,
-   "unique": 0
-  }, 
+   "fieldname": "item_name",
+   "fieldtype": "Data",
+   "in_global_search": 1,
+   "in_list_view": 1,
+   "label": "Item Name",
+   "oldfieldname": "item_name",
+   "oldfieldtype": "Data",
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
    "fetch_from": "item_code.description",
-   "fieldname": "description", 
-   "fieldtype": "Text Editor", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Description", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "description", 
-   "oldfieldtype": "Data", 
-   "options": "", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "print_width": "300px", 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0,
-   "unique": 0, 
+   "fieldname": "description",
+   "fieldtype": "Text Editor",
+   "label": "Description",
+   "oldfieldname": "description",
+   "oldfieldtype": "Data",
+   "print_width": "300px",
+   "read_only": 1,
    "width": "300px"
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "schedule_details", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0,
-   "unique": 0
-  }, 
+   "fieldname": "schedule_details",
+   "fieldtype": "Section Break"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "start_date", 
-   "fieldtype": "Date", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Start Date", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "start_date", 
-   "oldfieldtype": "Date", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 1, 
-   "set_only_once": 0, 
-   "translatable": 0,
-   "unique": 0
-  }, 
+   "columns": 2,
+   "fieldname": "start_date",
+   "fieldtype": "Date",
+   "in_list_view": 1,
+   "label": "Start Date",
+   "oldfieldname": "start_date",
+   "oldfieldtype": "Date",
+   "reqd": 1,
+   "search_index": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "end_date", 
-   "fieldtype": "Date", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "End Date", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "end_date", 
-   "oldfieldtype": "Date", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 1, 
-   "set_only_once": 0, 
-   "translatable": 0,
-   "unique": 0
-  }, 
+   "columns": 2,
+   "fieldname": "end_date",
+   "fieldtype": "Date",
+   "label": "End Date",
+   "oldfieldname": "end_date",
+   "oldfieldtype": "Date",
+   "reqd": 1,
+   "search_index": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "periodicity", 
-   "fieldtype": "Select", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Periodicity", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "periodicity", 
-   "oldfieldtype": "Select", 
-   "options": "\nWeekly\nMonthly\nQuarterly\nHalf Yearly\nYearly\nRandom", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0,
-   "unique": 0
-  }, 
+   "columns": 1,
+   "fieldname": "periodicity",
+   "fieldtype": "Select",
+   "in_list_view": 1,
+   "label": "Periodicity",
+   "oldfieldname": "periodicity",
+   "oldfieldtype": "Select",
+   "options": "\nWeekly\nMonthly\nQuarterly\nHalf Yearly\nYearly\nRandom"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "no_of_visits", 
-   "fieldtype": "Int", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "No of Visits", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "no_of_visits", 
-   "oldfieldtype": "Int", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0,
-   "unique": 0
-  }, 
+   "columns": 1,
+   "fieldname": "no_of_visits",
+   "fieldtype": "Int",
+   "in_list_view": 1,
+   "label": "No of Visits",
+   "oldfieldname": "no_of_visits",
+   "oldfieldtype": "Int",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "sales_person", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Sales Person", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "incharge_name", 
-   "oldfieldtype": "Link", 
-   "options": "Sales Person", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0,
-   "unique": 0
-  }, 
+   "fieldname": "sales_person",
+   "fieldtype": "Link",
+   "label": "Sales Person",
+   "oldfieldname": "incharge_name",
+   "oldfieldtype": "Link",
+   "options": "Sales Person"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "reference", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Reference", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0,
-   "unique": 0
-  }, 
+   "fieldname": "reference",
+   "fieldtype": "Section Break",
+   "label": "Reference"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "serial_no", 
-   "fieldtype": "Small Text", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Serial No", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "serial_no", 
-   "oldfieldtype": "Small Text", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0,
-   "unique": 0
-  }, 
+   "fieldname": "serial_no",
+   "fieldtype": "Small Text",
+   "label": "Serial No",
+   "oldfieldname": "serial_no",
+   "oldfieldtype": "Small Text"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "sales_order", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Sales Order", 
-   "length": 0, 
-   "no_copy": 1, 
-   "oldfieldname": "prevdoc_docname", 
-   "oldfieldtype": "Data", 
-   "options": "Sales Order", 
-   "permlevel": 0, 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "print_width": "150px", 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 1, 
-   "set_only_once": 0, 
-   "translatable": 0,
-   "unique": 0, 
+   "fieldname": "sales_order",
+   "fieldtype": "Link",
+   "label": "Sales Order",
+   "no_copy": 1,
+   "oldfieldname": "prevdoc_docname",
+   "oldfieldtype": "Data",
+   "options": "Sales Order",
+   "print_hide": 1,
+   "print_width": "150px",
+   "read_only": 1,
+   "search_index": 1,
    "width": "150px"
+  },
+  {
+   "fieldname": "column_break_4",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "column_break_10",
+   "fieldtype": "Column Break"
   }
- ], 
- "has_web_view": 0, 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "idx": 1, 
- "image_view": 0, 
- "in_create": 0, 
- "is_submittable": 0, 
- "issingle": 0, 
- "istable": 1, 
- "max_attachments": 0, 
- "modified": "2018-05-16 22:43:14.260729",
- "modified_by": "Administrator", 
- "module": "Maintenance", 
- "name": "Maintenance Schedule Item", 
- "owner": "Administrator", 
- "permissions": [], 
- "quick_entry": 0, 
- "read_only": 0, 
- "read_only_onload": 0, 
- "show_name_in_global_search": 0, 
- "track_changes": 0, 
- "track_seen": 0
+ ],
+ "idx": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-04-15 16:09:47.311994",
+ "modified_by": "Administrator",
+ "module": "Maintenance",
+ "name": "Maintenance Schedule Item",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC"
 }
\ No newline at end of file
diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
index 4cbb02a..d6105c6 100644
--- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
+++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.js
@@ -2,39 +2,62 @@
 // License: GNU General Public License v3. See license.txt
 
 frappe.provide("erpnext.maintenance");
-
+var serial_nos = [];
 frappe.ui.form.on('Maintenance Visit', {
-	refresh: function(frm) {
+	refresh: function (frm) {
 		//filters for serial_no based on item_code
-		frm.set_query('serial_no', 'purposes', function(frm, cdt, cdn) {
+		frm.set_query('serial_no', 'purposes', function (frm, cdt, cdn) {
 			let item = locals[cdt][cdn];
-			return {
-				filters: {
-					'item_code': item.item_code
-				}
-			};
+			if (serial_nos) {
+				return {
+					filters: {
+						'item_code': item.item_code,
+						'name': ["in", serial_nos]
+					}
+				};
+			} else {
+				return {
+					filters: {
+						'item_code': item.item_code
+					}
+				};
+			}
 		});
 	},
-	setup: function(frm) {
+	setup: function (frm) {
 		frm.set_query('contact_person', erpnext.queries.contact_query);
 		frm.set_query('customer_address', erpnext.queries.address_query);
 		frm.set_query('customer', erpnext.queries.customer);
 	},
-	onload: function(frm) {
+	onload: function (frm, cdt, cdn) {
+		let item = locals[cdt][cdn];
+		if (frm.maintenance_type == 'Scheduled') {
+			let schedule_id = item.purposes[0].prevdoc_detail_docname;
+			frappe.call({
+				method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.update_serial_nos",
+				args: {
+					s_id: schedule_id
+				},
+				callback: function (r) {
+					serial_nos = r.message;
+				}
+			});
+		}
+
 		if (!frm.doc.status) {
-			frm.set_value({status:'Draft'});
+			frm.set_value({ status: 'Draft' });
 		}
 		if (frm.doc.__islocal) {
-			frm.set_value({mntc_date: frappe.datetime.get_today()});
+			frm.set_value({ mntc_date: frappe.datetime.get_today() });
 		}
 	},
-	customer: function(frm) {
+	customer: function (frm) {
 		erpnext.utils.get_party_details(frm);
 	},
-	customer_address: function(frm) {
+	customer_address: function (frm) {
 		erpnext.utils.get_address_display(frm, 'customer_address', 'address_display');
 	},
-	contact_person: function(frm) {
+	contact_person: function (frm) {
 		erpnext.utils.get_contact_details(frm);
 	}
 
@@ -42,14 +65,14 @@
 
 // TODO commonify this code
 erpnext.maintenance.MaintenanceVisit = frappe.ui.form.Controller.extend({
-	refresh: function() {
-		frappe.dynamic_link = {doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer'}
+	refresh: function () {
+		frappe.dynamic_link = { doc: this.frm.doc, fieldname: 'customer', doctype: 'Customer' };
 
 		var me = this;
 
-		if (this.frm.doc.docstatus===0) {
+		if (this.frm.doc.docstatus === 0) {
 			this.frm.add_custom_button(__('Maintenance Schedule'),
-				function() {
+				function () {
 					erpnext.utils.map_current_doc({
 						method: "erpnext.maintenance.doctype.maintenance_schedule.maintenance_schedule.make_maintenance_visit",
 						source_doctype: "Maintenance Schedule",
@@ -64,7 +87,7 @@
 					})
 				}, __("Get Items From"));
 			this.frm.add_custom_button(__('Warranty Claim'),
-				function() {
+				function () {
 					erpnext.utils.map_current_doc({
 						method: "erpnext.support.doctype.warranty_claim.warranty_claim.make_maintenance_visit",
 						source_doctype: "Warranty Claim",
@@ -80,7 +103,7 @@
 					})
 				}, __("Get Items From"));
 			this.frm.add_custom_button(__('Sales Order'),
-				function() {
+				function () {
 					erpnext.utils.map_current_doc({
 						method: "erpnext.selling.doctype.sales_order.sales_order.make_maintenance_visit",
 						source_doctype: "Sales Order",
@@ -99,4 +122,4 @@
 	},
 });
 
-$.extend(cur_frm.cscript, new erpnext.maintenance.MaintenanceVisit({frm: cur_frm}));
\ No newline at end of file
+$.extend(cur_frm.cscript, new erpnext.maintenance.MaintenanceVisit({ frm: cur_frm }));
\ No newline at end of file
diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.json b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.json
index 32bfa0e..ec32239 100644
--- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.json
+++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.json
@@ -1,1042 +1,324 @@
 {
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 0, 
- "autoname": "naming_series:", 
- "beta": 0, 
- "creation": "2013-01-10 16:34:31", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "Document", 
- "editable_grid": 0, 
+ "actions": [],
+ "autoname": "naming_series:",
+ "creation": "2013-01-10 16:34:31",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "engine": "InnoDB",
+ "field_order": [
+  "customer_details",
+  "column_break0",
+  "naming_series",
+  "customer",
+  "customer_name",
+  "address_display",
+  "contact_display",
+  "contact_mobile",
+  "contact_email",
+  "maintenance_schedule",
+  "maintenance_schedule_detail",
+  "column_break1",
+  "mntc_date",
+  "mntc_time",
+  "maintenance_details",
+  "completion_status",
+  "column_break_14",
+  "maintenance_type",
+  "section_break0",
+  "purposes",
+  "more_info",
+  "customer_feedback",
+  "col_break3",
+  "status",
+  "amended_from",
+  "company",
+  "contact_info_section",
+  "customer_address",
+  "contact_person",
+  "col_break4",
+  "territory",
+  "customer_group"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "customer_details", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldtype": "Section Break", 
-   "options": "fa fa-user", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "customer_details",
+   "fieldtype": "Section Break",
+   "oldfieldtype": "Section Break",
+   "options": "fa fa-user"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "column_break0", 
-   "fieldtype": "Column Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldtype": "Column Break", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "column_break0",
+   "fieldtype": "Column Break",
+   "oldfieldtype": "Column Break"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "default": "", 
-   "fieldname": "naming_series", 
-   "fieldtype": "Select", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Series", 
-   "length": 0, 
-   "no_copy": 1, 
-   "options": "MAT-MVS-.YYYY.-", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 1, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "naming_series",
+   "fieldtype": "Select",
+   "label": "Series",
+   "no_copy": 1,
+   "options": "MAT-MVS-.YYYY.-",
+   "print_hide": 1,
+   "reqd": 1,
+   "set_only_once": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "customer", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 1, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Customer", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "customer", 
-   "oldfieldtype": "Link", 
-   "options": "Customer", 
-   "permlevel": 0, 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "customer",
+   "fieldtype": "Link",
+   "in_global_search": 1,
+   "label": "Customer",
+   "oldfieldname": "customer",
+   "oldfieldtype": "Link",
+   "options": "Customer",
+   "print_hide": 1,
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 1, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "customer_name", 
-   "fieldtype": "Data", 
-   "hidden": 1, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 1, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Customer Name", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "bold": 1,
+   "fieldname": "customer_name",
+   "fieldtype": "Data",
+   "hidden": 1,
+   "in_global_search": 1,
+   "label": "Customer Name",
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "address_display", 
-   "fieldtype": "Small Text", 
-   "hidden": 1, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Address", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "address_display",
+   "fieldtype": "Small Text",
+   "hidden": 1,
+   "label": "Address",
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "contact_display", 
-   "fieldtype": "Small Text", 
-   "hidden": 1, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 1, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Contact", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "contact_display",
+   "fieldtype": "Small Text",
+   "hidden": 1,
+   "in_global_search": 1,
+   "label": "Contact",
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "contact_mobile", 
-   "fieldtype": "Data", 
-   "hidden": 1, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Mobile No", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "contact_mobile",
+   "fieldtype": "Data",
+   "hidden": 1,
+   "label": "Mobile No",
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "contact_email", 
-   "fieldtype": "Data", 
-   "hidden": 1, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Contact Email", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "contact_email",
+   "fieldtype": "Data",
+   "hidden": 1,
+   "label": "Contact Email",
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "column_break1", 
-   "fieldtype": "Column Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldtype": "Column Break", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0, 
+   "fieldname": "column_break1",
+   "fieldtype": "Column Break",
+   "oldfieldtype": "Column Break",
    "width": "50%"
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "default": "Today", 
-   "fieldname": "mntc_date", 
-   "fieldtype": "Date", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Maintenance Date", 
-   "length": 0, 
-   "no_copy": 1, 
-   "oldfieldname": "mntc_date", 
-   "oldfieldtype": "Date", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "default": "Today",
+   "fieldname": "mntc_date",
+   "fieldtype": "Date",
+   "label": "Maintenance Date",
+   "no_copy": 1,
+   "oldfieldname": "mntc_date",
+   "oldfieldtype": "Date",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "mntc_time", 
-   "fieldtype": "Time", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Maintenance Time", 
-   "length": 0, 
-   "no_copy": 1, 
-   "oldfieldname": "mntc_time", 
-   "oldfieldtype": "Time", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "mntc_time",
+   "fieldtype": "Time",
+   "label": "Maintenance Time",
+   "no_copy": 1,
+   "oldfieldname": "mntc_time",
+   "oldfieldtype": "Time"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "maintenance_details", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldtype": "Section Break", 
-   "options": "fa fa-wrench", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "maintenance_details",
+   "fieldtype": "Section Break",
+   "oldfieldtype": "Section Break",
+   "options": "fa fa-wrench"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "completion_status", 
-   "fieldtype": "Select", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 1, 
-   "label": "Completion Status", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "completion_status", 
-   "oldfieldtype": "Select", 
-   "options": "\nPartially Completed\nFully Completed", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "completion_status",
+   "fieldtype": "Select",
+   "in_list_view": 1,
+   "in_standard_filter": 1,
+   "label": "Completion Status",
+   "oldfieldname": "completion_status",
+   "oldfieldtype": "Select",
+   "options": "\nPartially Completed\nFully Completed",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "column_break_14", 
-   "fieldtype": "Column Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "column_break_14",
+   "fieldtype": "Column Break"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "default": "Unscheduled", 
-   "fieldname": "maintenance_type", 
-   "fieldtype": "Select", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 1, 
-   "label": "Maintenance Type", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "maintenance_type", 
-   "oldfieldtype": "Select", 
-   "options": "\nScheduled\nUnscheduled\nBreakdown", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "default": "Unscheduled",
+   "fieldname": "maintenance_type",
+   "fieldtype": "Select",
+   "in_list_view": 1,
+   "in_standard_filter": 1,
+   "label": "Maintenance Type",
+   "oldfieldname": "maintenance_type",
+   "oldfieldtype": "Select",
+   "options": "\nScheduled\nUnscheduled\nBreakdown",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "section_break0", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldtype": "Section Break", 
-   "options": "fa fa-wrench", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "section_break0",
+   "fieldtype": "Section Break",
+   "oldfieldtype": "Section Break",
+   "options": "fa fa-wrench"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "purposes", 
-   "fieldtype": "Table", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Purposes", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "maintenance_visit_details", 
-   "oldfieldtype": "Table", 
-   "options": "Maintenance Visit Purpose", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "purposes",
+   "fieldtype": "Table",
+   "label": "Purposes",
+   "oldfieldname": "maintenance_visit_details",
+   "oldfieldtype": "Table",
+   "options": "Maintenance Visit Purpose",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "more_info", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "More Information", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldtype": "Section Break", 
-   "options": "fa fa-file-text", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "more_info",
+   "fieldtype": "Section Break",
+   "label": "More Information",
+   "oldfieldtype": "Section Break",
+   "options": "fa fa-file-text"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "customer_feedback", 
-   "fieldtype": "Small Text", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Customer Feedback", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "customer_feedback", 
-   "oldfieldtype": "Small Text", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "customer_feedback",
+   "fieldtype": "Small Text",
+   "label": "Customer Feedback",
+   "oldfieldname": "customer_feedback",
+   "oldfieldtype": "Small Text"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "col_break3", 
-   "fieldtype": "Column Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "col_break3",
+   "fieldtype": "Column Break"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "default": "Draft", 
-   "fieldname": "status", 
-   "fieldtype": "Select", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Status", 
-   "length": 0, 
-   "no_copy": 1, 
-   "oldfieldname": "status", 
-   "oldfieldtype": "Data", 
-   "options": "\nDraft\nCancelled\nSubmitted", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "default": "Draft",
+   "fieldname": "status",
+   "fieldtype": "Select",
+   "label": "Status",
+   "no_copy": 1,
+   "oldfieldname": "status",
+   "oldfieldtype": "Data",
+   "options": "\nDraft\nCancelled\nSubmitted",
+   "read_only": 1,
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "amended_from", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 1, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Amended From", 
-   "length": 0, 
-   "no_copy": 1, 
-   "oldfieldname": "amended_from", 
-   "oldfieldtype": "Data", 
-   "options": "Maintenance Visit", 
-   "permlevel": 0, 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0, 
+   "fieldname": "amended_from",
+   "fieldtype": "Link",
+   "ignore_user_permissions": 1,
+   "label": "Amended From",
+   "no_copy": 1,
+   "oldfieldname": "amended_from",
+   "oldfieldtype": "Data",
+   "options": "Maintenance Visit",
+   "print_hide": 1,
+   "read_only": 1,
    "width": "150px"
-  }, 
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "company", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Company", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "company", 
-   "oldfieldtype": "Select", 
-   "options": "Company", 
-   "permlevel": 0, 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 1, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "label": "Company",
+   "oldfieldname": "company",
+   "oldfieldtype": "Select",
+   "options": "Company",
+   "print_hide": 1,
+   "remember_last_selected_value": 1,
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "depends_on": "customer", 
-   "fieldname": "contact_info_section", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Contact Info", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "fa fa-bullhorn", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "depends_on": "customer",
+   "fieldname": "contact_info_section",
+   "fieldtype": "Section Break",
+   "label": "Contact Info",
+   "options": "fa fa-bullhorn"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "customer_address", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Customer Address", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Address", 
-   "permlevel": 0, 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "customer_address",
+   "fieldtype": "Link",
+   "label": "Customer Address",
+   "options": "Address",
+   "print_hide": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "contact_person", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Contact Person", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Contact", 
-   "permlevel": 0, 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "contact_person",
+   "fieldtype": "Link",
+   "label": "Contact Person",
+   "options": "Contact",
+   "print_hide": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "col_break4", 
-   "fieldtype": "Column Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "col_break4",
+   "fieldtype": "Column Break"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "description": "", 
-   "fieldname": "territory", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Territory", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Territory", 
-   "permlevel": 0, 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "territory",
+   "fieldtype": "Link",
+   "label": "Territory",
+   "options": "Territory",
+   "print_hide": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "description": "", 
-   "fieldname": "customer_group", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Customer Group", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Customer Group", 
-   "permlevel": 0, 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
+   "fieldname": "customer_group",
+   "fieldtype": "Link",
+   "label": "Customer Group",
+   "options": "Customer Group",
+   "print_hide": 1
+  },
+  {
+   "fieldname": "maintenance_schedule",
+   "fieldtype": "Link",
+   "label": "Maintenance Schedule",
+   "options": "Maintenance Schedule",
+   "read_only": 1
+  },
+  {
+   "fieldname": "maintenance_schedule_detail",
+   "fieldtype": "Link",
+   "hidden": 1,
+   "label": "Maintenance Schedule Detail",
+   "options": "Maintenance Schedule Detail"
   }
- ], 
- "has_web_view": 0, 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "icon": "fa fa-file-text", 
- "idx": 1, 
- "image_view": 0, 
- "in_create": 0, 
- "is_submittable": 1, 
- "issingle": 0, 
- "istable": 0, 
- "max_attachments": 0, 
- "modified": "2020-09-18 17:26:09.703215", 
- "modified_by": "Administrator", 
- "module": "Maintenance", 
- "name": "Maintenance Visit", 
- "owner": "Administrator", 
+ ],
+ "icon": "fa fa-file-text",
+ "idx": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2021-05-27 16:06:17.352572",
+ "modified_by": "Administrator",
+ "module": "Maintenance",
+ "name": "Maintenance Visit",
+ "owner": "Administrator",
  "permissions": [
   {
-   "amend": 1, 
-   "cancel": 1, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 0, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Maintenance User", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 1, 
+   "amend": 1,
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Maintenance User",
+   "share": 1,
+   "submit": 1,
    "write": 1
   }
- ], 
- "quick_entry": 0, 
- "read_only": 0, 
- "read_only_onload": 0, 
- "search_fields": "status,maintenance_type,customer,customer_name,mntc_date,company", 
- "show_name_in_global_search": 1, 
- "sort_field": "modified", 
- "sort_order": "DESC", 
- "timeline_field": "customer", 
- "title_field": "customer_name", 
- "track_changes": 0, 
- "track_seen": 0, 
- "track_views": 0
+ ],
+ "search_fields": "status,maintenance_type,customer,customer_name,mntc_date,company",
+ "show_name_in_global_search": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "timeline_field": "customer",
+ "title_field": "customer_name"
 }
\ No newline at end of file
diff --git a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py
index 2f2ad00..7fffc94 100644
--- a/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py
+++ b/erpnext/maintenance/doctype/maintenance_visit/maintenance_visit.py
@@ -4,6 +4,7 @@
 from __future__ import unicode_literals
 import frappe
 from frappe import _
+from frappe.utils import get_datetime
 
 from erpnext.utilities.transaction_base import TransactionBase
 
@@ -16,44 +17,62 @@
 			if d.serial_no and not frappe.db.exists("Serial No", d.serial_no):
 				frappe.throw(_("Serial No {0} does not exist").format(d.serial_no))
 
+	def validate_maintenance_date(self):
+		if self.maintenance_type == "Scheduled" and self.maintenance_schedule_detail:
+			item_ref = frappe.db.get_value('Maintenance Schedule Detail', self.maintenance_schedule_detail, 'item_reference')
+			if item_ref:
+				start_date, end_date = frappe.db.get_value('Maintenance Schedule Item', item_ref, ['start_date', 'end_date'])
+				if get_datetime(self.mntc_date) < get_datetime(start_date) or get_datetime(self.mntc_date) > get_datetime(end_date):
+					frappe.throw(_("Date must be between {0} and {1}").format(start_date, end_date))
+
 	def validate(self):
 		self.validate_serial_no()
+		self.validate_maintenance_date()
+	
+	def update_completion_status(self):
+		if self.maintenance_schedule_detail:
+			frappe.db.set_value('Maintenance Schedule Detail', self.maintenance_schedule_detail, 'completion_status', self.completion_status)
+	
+	def update_actual_date(self):
+		if self.maintenance_schedule_detail:
+			frappe.db.set_value('Maintenance Schedule Detail', self.maintenance_schedule_detail, 'actual_date', self.mntc_date)
 
 	def update_customer_issue(self, flag):
-		for d in self.get('purposes'):
-			if d.prevdoc_docname and d.prevdoc_doctype == 'Warranty Claim' :
-				if flag==1:
-					mntc_date = self.mntc_date
-					service_person = d.service_person
-					work_done = d.work_done
-					status = "Open"
-					if self.completion_status == 'Fully Completed':
-						status = 'Closed'
-					elif self.completion_status == 'Partially Completed':
-						status = 'Work In Progress'
-				else:
-					nm = frappe.db.sql("select t1.name, t1.mntc_date, t2.service_person, t2.work_done from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t1.completion_status = 'Partially Completed' and t2.prevdoc_docname = %s and t1.name!=%s and t1.docstatus = 1 order by t1.name desc limit 1", (d.prevdoc_docname, self.name))
-
-					if nm:
-						status = 'Work In Progress'
-						mntc_date = nm and nm[0][1] or ''
-						service_person = nm and nm[0][2] or ''
-						work_done = nm and nm[0][3] or ''
+		if not self.maintenance_schedule:
+			for d in self.get('purposes'):
+				if d.prevdoc_docname and d.prevdoc_doctype == 'Warranty Claim' :
+					if flag==1:
+						mntc_date = self.mntc_date
+						service_person = d.service_person
+						work_done = d.work_done
+						status = "Open"
+						if self.completion_status == 'Fully Completed':
+							status = 'Closed'
+						elif self.completion_status == 'Partially Completed':
+							status = 'Work In Progress'
 					else:
-						status = 'Open'
-						mntc_date = None
-						service_person = None
-						work_done = None
+						nm = frappe.db.sql("select t1.name, t1.mntc_date, t2.service_person, t2.work_done from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent = t1.name and t1.completion_status = 'Partially Completed' and t2.prevdoc_docname = %s and t1.name!=%s and t1.docstatus = 1 order by t1.name desc limit 1", (d.prevdoc_docname, self.name))
 
-				wc_doc = frappe.get_doc('Warranty Claim', d.prevdoc_docname)
-				wc_doc.update({
-					'resolution_date': mntc_date,
-					'resolved_by': service_person,
-					'resolution_details': work_done,
-					'status': status
-				})
+						if nm:
+							status = 'Work In Progress'
+							mntc_date = nm and nm[0][1] or ''
+							service_person = nm and nm[0][2] or ''
+							work_done = nm and nm[0][3] or ''
+						else:
+							status = 'Open'
+							mntc_date = None
+							service_person = None
+							work_done = None
 
-				wc_doc.db_update()
+					wc_doc = frappe.get_doc('Warranty Claim', d.prevdoc_docname)
+					wc_doc.update({
+						'resolution_date': mntc_date,
+						'resolved_by': service_person,
+						'resolution_details': work_done,
+						'status': status
+					})
+
+					wc_doc.db_update()
 
 	def check_if_last_visit(self):
 		"""check if last maintenance visit against same sales order/ Warranty Claim"""
@@ -77,6 +96,8 @@
 	def on_submit(self):
 		self.update_customer_issue(1)
 		frappe.db.set(self, 'status', 'Submitted')
+		self.update_completion_status()
+		self.update_actual_date()
 
 	def on_cancel(self):
 		self.check_if_last_visit()
diff --git a/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json b/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json
index 467441d..158f143 100644
--- a/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json
+++ b/erpnext/maintenance/doctype/maintenance_visit_purpose/maintenance_visit_purpose.json
@@ -1,4 +1,5 @@
 {
+ "actions": [],
  "autoname": "hash",
  "creation": "2013-02-22 01:28:06",
  "doctype": "DocType",
@@ -8,14 +9,15 @@
  "field_order": [
   "item_code",
   "item_name",
+  "column_break_3",
+  "service_person",
   "serial_no",
+  "section_break_6",
   "description",
   "work_details",
-  "service_person",
   "work_done",
   "prevdoc_doctype",
-  "prevdoc_docname",
-  "prevdoc_detail_docname"
+  "prevdoc_docname"
  ],
  "fields": [
   {
@@ -62,6 +64,8 @@
    "fieldtype": "Section Break"
   },
   {
+   "fetch_from": "prevdoc_detail_docname.sales_person",
+   "fetch_if_empty": 1,
    "fieldname": "service_person",
    "fieldtype": "Link",
    "in_list_view": 1,
@@ -83,49 +87,30 @@
   {
    "fieldname": "prevdoc_doctype",
    "fieldtype": "Link",
+   "hidden": 1,
    "label": "Document Type",
-   "no_copy": 1,
-   "oldfieldname": "prevdoc_doctype",
-   "oldfieldtype": "Data",
-   "options": "DocType",
-   "print_hide": 1,
-   "print_width": "150px",
-   "read_only": 1,
-   "report_hide": 1,
-   "width": "150px"
+   "options": "DocType"
   },
   {
    "fieldname": "prevdoc_docname",
    "fieldtype": "Dynamic Link",
+   "hidden": 1,
    "label": "Against Document No",
-   "no_copy": 1,
-   "oldfieldname": "prevdoc_docname",
-   "oldfieldtype": "Data",
-   "options": "prevdoc_doctype",
-   "print_hide": 1,
-   "print_width": "160px",
-   "read_only": 1,
-   "report_hide": 1,
-   "width": "160px"
+   "options": "prevdoc_doctype"
   },
   {
-   "fieldname": "prevdoc_detail_docname",
-   "fieldtype": "Data",
-   "hidden": 1,
-   "label": "Against Document Detail No",
-   "no_copy": 1,
-   "oldfieldname": "prevdoc_detail_docname",
-   "oldfieldtype": "Data",
-   "print_hide": 1,
-   "print_width": "160px",
-   "read_only": 1,
-   "report_hide": 1,
-   "width": "160px"
+   "fieldname": "column_break_3",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "section_break_6",
+   "fieldtype": "Section Break"
   }
  ],
  "idx": 1,
  "istable": 1,
- "modified": "2020-09-18 17:26:09.703215",
+ "links": [],
+ "modified": "2021-05-27 17:47:21.474282",
  "modified_by": "Administrator",
  "module": "Maintenance",
  "name": "Maintenance Visit Purpose",
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js
index a6086fb..3e5a72d 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.js
+++ b/erpnext/manufacturing/doctype/work_order/work_order.js
@@ -76,9 +76,9 @@
 		frm.set_query("production_item", function() {
 			return {
 				query: "erpnext.controllers.queries.item_query",
-				filters:[
-					['is_stock_item', '=',1]
-				]
+				filters: {
+					"is_stock_item": 1,
+				}
 			};
 		});
 
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 1e8ce3c..93689a0 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -779,5 +779,7 @@
 erpnext.patches.v13_0.germany_make_custom_fields
 erpnext.patches.v13_0.germany_fill_debtor_creditor_number
 erpnext.patches.v13_0.set_pos_closing_as_failed
+execute:frappe.rename_doc("Workspace", "Loan Management", "Loans", force=True)
 erpnext.patches.v13_0.update_timesheet_changes
 erpnext.patches.v13_0.set_training_event_attendance
+erpnext.patches.v13_0.rename_issue_status_hold_to_on_hold
diff --git a/erpnext/patches/v12_0/purchase_receipt_status.py b/erpnext/patches/v12_0/purchase_receipt_status.py
index 1a99b31..459221e 100644
--- a/erpnext/patches/v12_0/purchase_receipt_status.py
+++ b/erpnext/patches/v12_0/purchase_receipt_status.py
@@ -19,6 +19,9 @@
 	logger.info("purchase_receipt_status: begin patch, PR count: {}"
 				.format(len(affected_purchase_receipts)))
 
+	frappe.reload_doc("stock", "doctype", "Purchase Receipt")
+	frappe.reload_doc("stock", "doctype", "Purchase Receipt Item")
+
 
 	for pr in affected_purchase_receipts:
 		pr_name = pr[0]
diff --git a/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py b/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py
new file mode 100644
index 0000000..48325fc
--- /dev/null
+++ b/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py
@@ -0,0 +1,20 @@
+# Copyright (c) 2020, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+	if frappe.db.exists('DocType', 'Issue'):
+		frappe.reload_doc("support", "doctype", "issue")
+		rename_status()
+
+def rename_status():
+	frappe.db.sql("""
+		UPDATE
+			`tabIssue`
+		SET
+			status = 'On Hold'
+		WHERE
+			status = 'Hold'
+	""")
\ No newline at end of file
diff --git a/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py b/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py
index 7528bf7..b80b320 100644
--- a/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py
+++ b/erpnext/payroll/doctype/payroll_entry/test_payroll_entry.py
@@ -15,7 +15,13 @@
 from erpnext.loan_management.doctype.loan.test_loan import create_loan, make_loan_disbursement_entry, create_loan_type, create_loan_accounts
 from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_term_loans
 
+test_dependencies = ['Holiday List']
+
 class TestPayrollEntry(unittest.TestCase):
+	@classmethod
+	def setUpClass(cls):
+		frappe.db.set_value("Company", erpnext.get_default_company(), "default_holiday_list", '_Test Holiday List')
+
 	def setUp(self):
 		for dt in ["Salary Slip", "Salary Component", "Salary Component Account",
 			"Payroll Entry", "Salary Structure", "Salary Structure Assignment", "Payroll Employee Detail", "Additional Salary"]:
diff --git a/erpnext/public/js/help_links.js b/erpnext/public/js/help_links.js
index e789923..aa9bba1 100644
--- a/erpnext/public/js/help_links.js
+++ b/erpnext/public/js/help_links.js
@@ -644,14 +644,14 @@
 frappe.help.help_links["List/Asset"] = [
 	{
 		label: "Managing Fixed Assets",
-		url: docsUrl + "user/manual/en/accounts/managing-fixed-assets",
+		url: docsUrl + "user/manual/en/accounts/opening-balance/fixed_assets",
 	},
 ];
 
 frappe.help.help_links["List/Asset Category"] = [
 	{
 		label: "Asset Category",
-		url: docsUrl + "user/manual/en/accounts/managing-fixed-assets",
+		url: docsUrl + "user/manual/en/asset/asset-category",
 	},
 ];
 
@@ -663,7 +663,7 @@
 	{ label: "Item", url: docsUrl + "user/manual/en/stock/item" },
 	{
 		label: "Item Price",
-		url: docsUrl + "user/manual/en/stock/item/item-price",
+		url: docsUrl + "user/manual/en/stock/item-price",
 	},
 	{
 		label: "Barcode",
@@ -672,25 +672,25 @@
 	},
 	{
 		label: "Item Wise Taxation",
-		url: docsUrl + "user/manual/en/accounts/item-wise-taxation",
+		url: docsUrl + "user/manual/en/accounts/item-tax-template",
 	},
 	{
 		label: "Managing Fixed Assets",
-		url: docsUrl + "user/manual/en/accounts/managing-fixed-assets",
+		url: docsUrl + "user/manual/en/accounts/opening-balance/fixed_assets",
 	},
 	{
 		label: "Item Codification",
-		url: docsUrl + "user/manual/en/stock/item/item-codification",
+		url: docsUrl + "user/manual/en/stock/articles/item-codification",
 	},
 	{
 		label: "Item Variants",
-		url: docsUrl + "user/manual/en/stock/item/item-variants",
+		url: docsUrl + "user/manual/en/stock/item-variants",
 	},
 	{
 		label: "Item Valuation",
 		url:
 			docsUrl +
-			"user/manual/en/stock/item/item-valuation-fifo-and-moving-average",
+			"user/manual/en/stock/articles/item-valuation-fifo-and-moving-average",
 	},
 ];
 
@@ -698,7 +698,7 @@
 	{ label: "Item", url: docsUrl + "user/manual/en/stock/item" },
 	{
 		label: "Item Price",
-		url: docsUrl + "user/manual/en/stock/item/item-price",
+		url: docsUrl + "user/manual/en/stock/item-price",
 	},
 	{
 		label: "Barcode",
@@ -707,19 +707,19 @@
 	},
 	{
 		label: "Item Wise Taxation",
-		url: docsUrl + "user/manual/en/accounts/item-wise-taxation",
+		url: docsUrl + "user/manual/en/accounts/item-tax-template",
 	},
 	{
 		label: "Managing Fixed Assets",
-		url: docsUrl + "user/manual/en/accounts/managing-fixed-assets",
+		url: docsUrl + "user/manual/en/accounts/opening-balance/fixed_assets",
 	},
 	{
 		label: "Item Codification",
-		url: docsUrl + "user/manual/en/stock/item/item-codification",
+		url: docsUrl + "user/manual/en/stock/articles/item-codification",
 	},
 	{
 		label: "Item Variants",
-		url: docsUrl + "user/manual/en/stock/item/item-variants",
+		url: docsUrl + "user/manual/en/stock/item-variants",
 	},
 	{
 		label: "Item Valuation",
diff --git a/erpnext/public/scss/shopping_cart.scss b/erpnext/public/scss/shopping_cart.scss
index 159a8a4..9402cf9 100644
--- a/erpnext/public/scss/shopping_cart.scss
+++ b/erpnext/public/scss/shopping_cart.scss
@@ -1,4 +1,3 @@
-@import "frappe/public/scss/desk/variables";
 @import "frappe/public/scss/common/mixins";
 
 body.product-page {
@@ -74,15 +73,6 @@
 		}
 	}
 
-	// .card-body {
-	// 	text-align: center;
-	// }
-
-	// .featured-item {
-	// 	.card-body {
-	// 		text-align: left;
-	// 	}
-	// }
 	.card-img-container {
 		height: 210px;
 		width: 100%;
@@ -217,12 +207,12 @@
 		border-color: var(--table-border-color) !important;
 		padding: 15px;
 
-		@include media-breakpoint-between(xs, md) {
+		@media (max-width: var(--md-width)) {
 			height: 300px;
 			width: 300px;
 		}
 
-		@include media-breakpoint-up(lg) {
+		@media (min-width: var(--lg-width)) {
 			height: 350px;
 			width: 350px;
 		}
@@ -233,11 +223,12 @@
 	}
 
 	.item-slideshow {
-		@include media-breakpoint-between(xs, md) {
+
+		@media (max-width: var(--md-width)) {
 			max-height: 320px;
 		}
 
-		@include media-breakpoint-up(lg) {
+		@media (min-width: var(--lg-width)) {
 			max-height: 430px;
 		}
 
@@ -254,7 +245,7 @@
 		cursor: pointer;
 
 		&:hover, &.active {
-			border-color: $primary;
+			border-color: var(--primary);
 		}
 	}
 
@@ -316,12 +307,9 @@
 }
 
 .item-group-slideshow {
-	.item-group-description {
-		// max-width: 900px;
-	}
 
 	.carousel-inner.rounded-carousel {
-		border-radius: $card-border-radius;
+		border-radius: var(--card-border-radius);
 	}
 }
 
diff --git a/erpnext/public/scss/website.scss b/erpnext/public/scss/website.scss
index 56b717c..f4325c0 100644
--- a/erpnext/public/scss/website.scss
+++ b/erpnext/public/scss/website.scss
@@ -1,4 +1,3 @@
-@import "frappe/public/scss/website/variables";
 
 .filter-options {
 	max-height: 300px;
@@ -14,7 +13,7 @@
 	}
 
 	&.active {
-		border-color: $primary;
+		border-color: var(--primary);
 
 		.check {
 			display: inline-flex;
@@ -25,7 +24,7 @@
 .check {
 	display: inline-flex;
 	padding: 0.25rem;
-	background: $primary;
+	background: var(--primary);
 	color: white;
 	border-radius: 50%;
 	font-size: 12px;
@@ -38,12 +37,12 @@
 }
 
 .result {
-	border-bottom: 1px solid $border-color;
+	border-bottom: 1px solid var(--border-color);
 }
 
 .transaction-list-item {
 	padding: 1rem 0;
-	border-top: 1px solid $border-color;
+	border-top: 1px solid var(--border-color);
 	position: relative;
 
 	a.transaction-item-link {
diff --git a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
index 3ddcc58..6415204 100644
--- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
+++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
@@ -310,7 +310,7 @@
 								self.report_dict['sup_details']['osup_det']['txval'] += taxable_value
 
 								gst_category = self.invoice_detail_map.get(inv, {}).get('gst_category')
-								place_of_supply = self.invoice_detail_map.get(inv, {}).get('place_of_supply', '00-Other Territory')
+								place_of_supply = self.invoice_detail_map.get(inv, {}).get('place_of_supply') or '00-Other Territory'
 
 								if gst_category in ['Unregistered', 'Registered Composition', 'UIN Holders'] and \
 								self.gst_details.get("gst_state") != place_of_supply.split("-")[1]:
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index fc227de..075c698 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -500,7 +500,7 @@
 
 		if not isinstance(docname, list):
 			# removes characters not allowed in a filename (https://stackoverflow.com/a/38766141/4767738)
-			filename_prefix = re.sub('[^\w_.)( -]', '', docname)
+			filename_prefix = re.sub(r'[^\w_.)( -]', '', docname)
 
 	frappe.local.response.filename = '{0}_e-WayBill_Data_{1}.json'.format(filename_prefix, frappe.utils.random_string(5))
 
diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.py b/erpnext/selling/page/point_of_sale/point_of_sale.py
index 750a1a6..cb811df 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.py
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.py
@@ -15,7 +15,6 @@
 	data = dict()
 	result = []
 
-	allow_negative_stock = frappe.db.get_single_value('Stock Settings', 'allow_negative_stock')
 	warehouse, hide_unavailable_items = frappe.db.get_value('POS Profile', pos_profile, ['warehouse', 'hide_unavailable_items'])
 
 	if not frappe.db.exists('Item Group', item_group):
@@ -62,7 +61,6 @@
 			`tabItem` item {bin_join_selection}
 		WHERE
 			item.disabled = 0
-			AND item.is_stock_item = 1
 			AND item.has_variants = 0
 			AND item.is_sales_item = 1
 			AND item.is_fixed_asset = 0
@@ -84,6 +82,7 @@
 		), {'warehouse': warehouse}, as_dict=1)
 
 	if items_data:
+		items_data = filter_service_items(items_data)
 		items = [d.item_code for d in items_data]
 		item_prices_data = frappe.get_all("Item Price",
 			fields = ["item_code", "price_list_rate", "currency"],
@@ -96,10 +95,7 @@
 		for item in items_data:
 			item_code = item.item_code
 			item_price = item_prices.get(item_code) or {}
-			if allow_negative_stock:
-				item_stock_qty = frappe.db.sql("""select ifnull(sum(actual_qty), 0) from `tabBin` where item_code = %s""", item_code)[0][0]
-			else:
-				item_stock_qty = get_stock_availability(item_code, warehouse)
+			item_stock_qty = get_stock_availability(item_code, warehouse)
 
 			row = {}
 			row.update(item)
@@ -135,6 +131,14 @@
 
 	return {}
 
+def filter_service_items(items):
+	for item in items:
+		if not item['is_stock_item']:
+			if not frappe.db.exists('Product Bundle', item['item_code']):
+				items.remove(item)
+	
+	return items
+
 def get_conditions(item_code, serial_no, batch_no, barcode):
 	if serial_no or batch_no or barcode:
 		return "item.name = {0}".format(frappe.db.escape(item_code))
diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js
index 4f4f1b2..ae3f9e3 100644
--- a/erpnext/selling/page/point_of_sale/pos_controller.js
+++ b/erpnext/selling/page/point_of_sale/pos_controller.js
@@ -241,10 +241,8 @@
 			events: {
 				get_frm: () => this.frm,
 
-				cart_item_clicked: (item_code, batch_no, uom) => {
-					const search_field = batch_no ? 'batch_no' : 'item_code';
-					const search_value = batch_no || item_code;
-					const item_row = this.frm.doc.items.find(i => i[search_field] === search_value && i.uom === uom);
+				cart_item_clicked: (item_code, batch_no, uom, rate) => {
+					const item_row = this.get_item_from_frm(item_code, batch_no, uom, rate);
 					this.item_details.toggle_item_details_section(item_row);
 				},
 
@@ -275,18 +273,25 @@
 					this.cart.toggle_numpad(minimize);
 				},
 
-				form_updated: async (cdt, cdn, fieldname, value) => {
+				form_updated: (cdt, cdn, fieldname, value) => {
 					const item_row = frappe.model.get_doc(cdt, cdn);
 					if (item_row && item_row[fieldname] != value) {
 
-						const { item_code, batch_no, uom } = this.item_details.current_item;
+						const { item_code, batch_no, uom, rate } = this.item_details.current_item;
 						const event = {
 							field: fieldname,
 							value,
-							item: { item_code, batch_no, uom }
+							item: { item_code, batch_no, uom, rate }
 						}
 						return this.on_cart_update(event)
 					}
+
+					return Promise.resolve();
+				},
+
+				highlight_cart_item: (item) => {
+					const cart_item = this.cart.get_cart_item(item);
+					this.cart.toggle_item_highlight(cart_item);
 				},
 
 				item_field_focused: (fieldname) => {
@@ -501,8 +506,8 @@
 		let item_row = undefined;
 		try {
 			let { field, value, item } = args;
-			const { item_code, batch_no, serial_no, uom } = item;
-			item_row = this.get_item_from_frm(item_code, batch_no, uom);
+			const { item_code, batch_no, serial_no, uom, rate } = item;
+			item_row = this.get_item_from_frm(item_code, batch_no, uom, rate);
 
 			const item_selected_from_selector = field === 'qty' && value === "+1"
 
@@ -535,7 +540,7 @@
 
 				item_selected_from_selector && (value = flt(value))
 
-				const args = { item_code, batch_no, [field]: value };
+				const args = { item_code, batch_no, rate, [field]: value };
 
 				if (serial_no) {
 					await this.check_serial_no_availablilty(item_code, this.frm.doc.set_warehouse, serial_no);
@@ -550,9 +555,11 @@
 					await this.check_stock_availability(item_row, value, this.frm.doc.set_warehouse);
 
 				await this.trigger_new_item_events(item_row);
-
-				this.check_serial_batch_selection_needed(item_row) && this.edit_item_details_of(item_row);
+				
 				this.update_cart_html(item_row);
+
+				this.item_details.$component.is(':visible') && this.edit_item_details_of(item_row);
+				this.check_serial_batch_selection_needed(item_row) && this.edit_item_details_of(item_row);
 			}
 
 		} catch (error) {
@@ -563,12 +570,13 @@
 		}
 	}
 
-	get_item_from_frm(item_code, batch_no, uom) {
+	get_item_from_frm(item_code, batch_no, uom, rate) {
 		const has_batch_no = batch_no;
 		return this.frm.doc.items.find(
 			i => i.item_code === item_code
 				&& (!has_batch_no || (has_batch_no && i.batch_no === batch_no))
 				&& (i.uom === uom)
+				&& (i.rate == rate)
 		);
 	}
 
diff --git a/erpnext/selling/page/point_of_sale/pos_item_cart.js b/erpnext/selling/page/point_of_sale/pos_item_cart.js
index 11a63b3..f5019f5 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_cart.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_cart.js
@@ -184,7 +184,8 @@
 			const item_code = unescape($cart_item.attr('data-item-code'));
 			const batch_no = unescape($cart_item.attr('data-batch-no'));
 			const uom = unescape($cart_item.attr('data-uom'));
-			me.events.cart_item_clicked(item_code, batch_no, uom);
+			const rate = unescape($cart_item.attr('data-rate'));
+			me.events.cart_item_clicked(item_code, batch_no, uom, rate);
 			this.numpad_value = '';
 		});
 
@@ -520,28 +521,34 @@
 		}
 	}
 
-	get_cart_item({ item_code, batch_no, uom }) {
+	get_cart_item({ item_code, batch_no, uom, rate }) {
 		const batch_attr = `[data-batch-no="${escape(batch_no)}"]`;
 		const item_code_attr = `[data-item-code="${escape(item_code)}"]`;
 		const uom_attr = `[data-uom="${escape(uom)}"]`;
+		const rate_attr = `[data-rate="${escape(rate)}"]`;
 
 		const item_selector = batch_no ?
-			`.cart-item-wrapper${batch_attr}${uom_attr}` : `.cart-item-wrapper${item_code_attr}${uom_attr}`;
+			`.cart-item-wrapper${batch_attr}${uom_attr}${rate_attr}` : `.cart-item-wrapper${item_code_attr}${uom_attr}${rate_attr}`;
 
 		return this.$cart_items_wrapper.find(item_selector);
 	}
 
+	get_item_from_frm(item) {
+		const doc = this.events.get_frm().doc;
+		const { item_code, batch_no, uom, rate } = item;
+		const search_field = batch_no ? 'batch_no' : 'item_code';
+		const search_value = batch_no || item_code;
+
+		return doc.items.find(i => i[search_field] === search_value && i.uom === uom && i.rate === rate);
+	}
+
 	update_item_html(item, remove_item) {
 		const $item = this.get_cart_item(item);
 
 		if (remove_item) {
 			$item && $item.next().remove() && $item.remove();
 		} else {
-			const { item_code, batch_no, uom } = item;
-			const search_field = batch_no ? 'batch_no' : 'item_code';
-			const search_value = batch_no || item_code;
-			const item_row = this.events.get_frm().doc.items.find(i => i[search_field] === search_value && i.uom === uom);
-
+			const item_row = this.get_item_from_frm(item);
 			this.render_cart_item(item_row, $item);
 		}
 
@@ -559,7 +566,7 @@
 			this.$cart_items_wrapper.append(
 				`<div class="cart-item-wrapper"
 						data-item-code="${escape(item_data.item_code)}" data-uom="${escape(item_data.uom)}"
-						data-batch-no="${escape(item_data.batch_no || '')}">
+						data-batch-no="${escape(item_data.batch_no || '')}" data-rate="${escape(item_data.rate)}">
 				</div>
 				<div class="seperator"></div>`
 			)
@@ -636,13 +643,23 @@
 		function get_item_image_html() {
 			const { image, item_name } = item_data;
 			if (image) {
-				return `<div class="item-image"><img src="${image}" alt="${image}""></div>`;
+				return `
+					<div class="item-image">
+						<img
+							onerror="cur_pos.cart.handle_broken_image(this)"
+							src="${image}" alt="${frappe.get_abbr(item_name)}"">
+					</div>`;
 			} else {
 				return `<div class="item-image item-abbr">${frappe.get_abbr(item_name)}</div>`;
 			}
 		}
 	}
 
+	handle_broken_image($img) {
+		const item_abbr = $($img).attr('alt');
+		$($img).parent().replaceWith(`<div class="item-image item-abbr">${item_abbr}</div>`);
+	}
+
 	scroll_to_item($item) {
 		if ($item.length === 0) return;
 		const scrollTop = $item.offset().top - this.$cart_items_wrapper.offset().top + this.$cart_items_wrapper.scrollTop();
diff --git a/erpnext/selling/page/point_of_sale/pos_item_details.js b/erpnext/selling/page/point_of_sale/pos_item_details.js
index 32a4556..df62696 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_details.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_details.js
@@ -54,13 +54,24 @@
 		this.$dicount_section = this.$component.find('.discount-section');
 	}
 
-	toggle_item_details_section(item) {
-		const { item_code, batch_no, uom } = this.current_item;
+	has_item_has_changed(item) {
+		const { item_code, batch_no, uom, rate } = this.current_item;
 		const item_code_is_same = item && item_code === item.item_code;
 		const batch_is_same = item && batch_no == item.batch_no;
 		const uom_is_same = item && uom === item.uom;
+		const rate_is_same = item && rate === item.rate;
+		
+		if (!item)
+			return false;
 
-		this.item_has_changed = !item ? false : item_code_is_same && batch_is_same && uom_is_same ? false : true;
+		if (item_code_is_same && batch_is_same && uom_is_same && rate_is_same)
+			return false;
+
+		return true;
+	}
+
+	toggle_item_details_section(item) {
+		this.item_has_changed = this.has_item_has_changed(item);
 
 		this.events.toggle_item_selector(this.item_has_changed);
 		this.toggle_component(this.item_has_changed);
@@ -72,11 +83,12 @@
 			this.item_row = item;
 			this.currency = this.events.get_frm().doc.currency;
 
-			this.current_item = { item_code: item.item_code, batch_no: item.batch_no, uom: item.uom };
+			this.current_item = { item_code: item.item_code, batch_no: item.batch_no, uom: item.uom, rate: item.rate };
 
 			this.render_dom(item);
 			this.render_discount_dom(item);
 			this.render_form(item);
+			this.events.highlight_cart_item(item);
 		} else {
 			this.validate_serial_batch_item();
 			this.current_item = {};
@@ -198,12 +210,14 @@
 			if (this.allow_rate_change) {
 				this.rate_control.df.onchange = function() {
 					if (this.value || flt(this.value) === 0) {
+						me.events.set_value_in_current_cart_item('rate', this.value);
 						me.events.form_updated(me.doctype, me.name, 'rate', this.value).then(() => {
 							const item_row = frappe.get_doc(me.doctype, me.name);
 							const doc = me.events.get_frm().doc;
 							me.$item_price.html(format_currency(item_row.rate, doc.currency));
 							me.render_discount_dom(item_row);
 						});
+						me.current_item.rate = this.value;
 					}
 				};
 			} else {
@@ -292,11 +306,7 @@
 
 		frappe.model.on("POS Invoice Item", "*", (fieldname, value, item_row) => {
 			const field_control = this[`${fieldname}_control`];
-			const { item_code, batch_no, uom } = this.current_item;
-			const item_code_is_same = item_code === item_row.item_code;
-			const batch_is_same = batch_no == item_row.batch_no;
-			const uom_is_same = uom === item_row.uom;
-			const item_is_same = item_code_is_same && batch_is_same && uom_is_same ? true : false;
+			const item_is_same = !this.has_item_has_changed(item_row);
 
 			if (item_is_same && field_control && field_control.get_value() !== value) {
 				field_control.set_value(value);
diff --git a/erpnext/selling/page/point_of_sale/pos_item_selector.js b/erpnext/selling/page/point_of_sale/pos_item_selector.js
index b8a82a9..5b48725 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_selector.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_selector.js
@@ -78,7 +78,7 @@
 	get_item_html(item) {
 		const me = this;
 		// eslint-disable-next-line no-unused-vars
-		const { item_image, serial_no, batch_no, barcode, actual_qty, stock_uom } = item;
+		const { item_image, serial_no, batch_no, barcode, actual_qty, stock_uom, price_list_rate } = item;
 		const indicator_color = actual_qty > 10 ? "green" : actual_qty <= 0 ? "red" : "orange";
 
 		let qty_to_display = actual_qty;
@@ -94,7 +94,11 @@
 							<span class="indicator-pill whitespace-nowrap ${indicator_color}">${qty_to_display}</span>
 						</div>
 						<div class="flex items-center justify-center h-32 border-b-grey text-6xl text-grey-100">
-							<img class="h-full" src="${item_image}" alt="${frappe.get_abbr(item.item_name)}" style="object-fit: cover;">
+							<img 
+								onerror="cur_pos.item_selector.handle_broken_image(this)"
+								class="h-full" src="${item_image}"
+								alt="${frappe.get_abbr(item.item_name)}"
+								style="object-fit: cover;">
 						</div>`;
 			} else {
 				return `<div class="item-qty-pill">
@@ -108,6 +112,7 @@
 			`<div class="item-wrapper"
 				data-item-code="${escape(item.item_code)}" data-serial-no="${escape(serial_no)}"
 				data-batch-no="${escape(batch_no)}" data-uom="${escape(stock_uom)}"
+				data-rate="${escape(price_list_rate)}"
 				title="${item.item_name}">
 
 				${get_item_image_html()}
@@ -116,12 +121,17 @@
 					<div class="item-name">
 						${frappe.ellipsis(item.item_name, 18)}
 					</div>
-					<div class="item-rate">${format_currency(item.price_list_rate, item.currency, 0) || 0}</div>
+					<div class="item-rate">${format_currency(price_list_rate, item.currency, 0) || 0}</div>
 				</div>
 			</div>`
 		);
 	}
 
+	handle_broken_image($img) {
+		const item_abbr = $($img).attr('alt');
+		$($img).parent().replaceWith(`<div class="item-display abbr">${item_abbr}</div>`);
+	}
+
 	make_search_bar() {
 		const me = this;
 		const doc = me.events.get_frm().doc;
@@ -213,13 +223,15 @@
 			let batch_no = unescape($item.attr('data-batch-no'));
 			let serial_no = unescape($item.attr('data-serial-no'));
 			let uom = unescape($item.attr('data-uom'));
+			let rate = unescape($item.attr('data-rate'));
 
 			// escape(undefined) returns "undefined" then unescape returns "undefined"
 			batch_no = batch_no === "undefined" ? undefined : batch_no;
 			serial_no = serial_no === "undefined" ? undefined : serial_no;
 			uom = uom === "undefined" ? undefined : uom;
+			rate = rate === "undefined" ? undefined : rate;
 
-			me.events.item_selected({ field: 'qty', value: "+1", item: { item_code, batch_no, serial_no, uom }});
+			me.events.item_selected({ field: 'qty', value: "+1", item: { item_code, batch_no, serial_no, uom, rate }});
 			me.set_search_value('');
 		});
 
diff --git a/erpnext/setup/doctype/email_digest/email_digest.py b/erpnext/setup/doctype/email_digest/email_digest.py
index 8c97322..340d89b 100644
--- a/erpnext/setup/doctype/email_digest/email_digest.py
+++ b/erpnext/setup/doctype/email_digest/email_digest.py
@@ -249,7 +249,7 @@
 				card = cache.get(cache_key)
 
 				if card:
-					card = eval(card)
+					card = frappe.safe_eval(card)
 
 				else:
 					card = frappe._dict(getattr(self, "get_" + key)())
@@ -808,7 +808,6 @@
 			val = balance_on_to_date - balance_before_from_date
 		else:
 			last_year_closing_balance = get_balance_on(account, date=fy_start_date - timedelta(days=1))
-			print(fy_start_date - timedelta(days=1), last_year_closing_balance)
 			val = balance_on_to_date + (last_year_closing_balance - balance_before_from_date)
 
 		return val
@@ -837,4 +836,4 @@
 	elif frequency == "Monthly":
 		to_date = add_to_date(from_date, months=1)
 
-	return from_date, to_date
\ No newline at end of file
+	return from_date, to_date
diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py
index 429a558..5019837 100644
--- a/erpnext/setup/setup_wizard/operations/taxes_setup.py
+++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py
@@ -106,6 +106,9 @@
 			'charge_type': 'On Net Total'
 		}
 
+		if doctype == 'Purchase Taxes and Charges Template':
+			tax_row_defaults['add_deduct_tax'] = 'Add'
+
 		# if account_head is a dict, search or create the account and get it's name
 		if isinstance(account_data, dict):
 			tax_row_defaults['description'] = '{0} @ {1}'.format(account_data.get('account_name'), account_data.get('tax_rate'))
diff --git a/erpnext/shopping_cart/test_shopping_cart.py b/erpnext/shopping_cart/test_shopping_cart.py
index d857bf5..ac61aeb 100644
--- a/erpnext/shopping_cart/test_shopping_cart.py
+++ b/erpnext/shopping_cart/test_shopping_cart.py
@@ -7,7 +7,7 @@
 from frappe.utils import nowdate, add_months
 from erpnext.shopping_cart.cart import _get_cart_quotation, update_cart, get_party
 from erpnext.tests.utils import create_test_contact_and_address
-
+from erpnext.accounts.doctype.tax_rule.tax_rule import  ConflictingTaxRule
 
 # test_dependencies = ['Payment Terms Template']
 
@@ -125,7 +125,7 @@
 		tax_rule = frappe.get_test_records("Tax Rule")[0]
 		try:
 			frappe.get_doc(tax_rule).insert()
-		except frappe.DuplicateEntryError:
+		except (frappe.DuplicateEntryError, ConflictingTaxRule):
 			pass
 
 	def create_quotation(self):
diff --git a/erpnext/stock/doctype/packed_item/packed_item.json b/erpnext/stock/doctype/packed_item/packed_item.json
index f1d7f8c..bb396e8 100644
--- a/erpnext/stock/doctype/packed_item/packed_item.json
+++ b/erpnext/stock/doctype/packed_item/packed_item.json
@@ -13,6 +13,7 @@
   "section_break_6",
   "warehouse",
   "target_warehouse",
+  "conversion_factor",
   "column_break_9",
   "qty",
   "uom",
@@ -209,13 +210,18 @@
    "no_copy": 1,
    "print_hide": 1,
    "read_only": 1
+  },
+  {
+   "fieldname": "conversion_factor",
+   "fieldtype": "Float",
+   "label": "Conversion Factor"
   }
  ],
  "idx": 1,
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-09-24 09:25:13.050151",
+ "modified": "2021-05-26 07:08:05.111385",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Packed Item",
diff --git a/erpnext/stock/doctype/packed_item/packed_item.py b/erpnext/stock/doctype/packed_item/packed_item.py
index 5341f29..4ab71bd 100644
--- a/erpnext/stock/doctype/packed_item/packed_item.py
+++ b/erpnext/stock/doctype/packed_item/packed_item.py
@@ -53,6 +53,7 @@
 	pi.parent_detail_docname = main_item_row.name
 	pi.uom = item.stock_uom
 	pi.qty = flt(qty)
+	pi.conversion_factor = main_item_row.conversion_factor
 	if description and not pi.description:
 		pi.description = description
 	if not pi.warehouse and not doc.amended_from:
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index e5ef978..5095a80 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -297,6 +297,8 @@
 			item_code = "Test Extra Item 1", qty=10, basic_rate=100)
 		se2 = make_stock_entry(target="_Test Warehouse - _TC",
 			item_code = "_Test FG Item", qty=1, basic_rate=100)
+		se3 = make_stock_entry(target="_Test Warehouse - _TC",
+			item_code = "Test Extra Item 2", qty=1, basic_rate=100)
 		rm_items = [
 			{
 				"item_code": item_code,
@@ -331,6 +333,7 @@
 		se.cancel()
 		se1.cancel()
 		se2.cancel()
+		se3.cancel()
 		po.reload()
 		po.cancel()
 
diff --git a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
index 3296f5b..ba31ad7 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
@@ -15,10 +15,12 @@
 from erpnext.stock.doctype.landed_cost_voucher.test_landed_cost_voucher import create_landed_cost_voucher
 from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
 from erpnext.stock.doctype.stock_ledger_entry.stock_ledger_entry import BackDatedStockTransaction
+from frappe.core.page.permission_manager.permission_manager import reset
 
 class TestStockLedgerEntry(unittest.TestCase):
 	def setUp(self):
 		items = create_items()
+		reset('Stock Entry')
 
 		# delete SLE and BINs for all items
 		frappe.db.sql("delete from `tabStock Ledger Entry` where item_code in (%s)" % (', '.join(['%s']*len(items))), items)
@@ -314,10 +316,11 @@
 		# Set User with Stock User role but not Stock Manager
 		try:
 			user = frappe.get_doc("User", "test@example.com")
-			frappe.set_user(user.name)
 			user.add_roles("Stock User")
 			user.remove_roles("Stock Manager")
 
+			frappe.set_user(user.name)
+
 			stock_entry_on_today = make_stock_entry(target="_Test Warehouse - _TC", qty=10, basic_rate=100)
 			back_dated_se_1 = make_stock_entry(target="_Test Warehouse - _TC", qty=10, basic_rate=100,
 				posting_date=add_days(today(), -1), do_not_submit=True)
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index 7e216d6..32e0ccb 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -477,19 +477,19 @@
 def get_items(warehouse, posting_date, posting_time, company):
 	lft, rgt = frappe.db.get_value("Warehouse", warehouse, ["lft", "rgt"])
 	items = frappe.db.sql("""
-		select i.name, i.item_name, bin.warehouse
+		select i.name, i.item_name, bin.warehouse, i.has_serial_no
 		from tabBin bin, tabItem i
 		where i.name=bin.item_code and i.disabled=0 and i.is_stock_item = 1
-		and i.has_variants = 0 and i.has_serial_no = 0 and i.has_batch_no = 0
+		and i.has_variants = 0 and i.has_batch_no = 0
 		and exists(select name from `tabWarehouse` where lft >= %s and rgt <= %s and name=bin.warehouse)
 	""", (lft, rgt))
 
 	items += frappe.db.sql("""
-		select i.name, i.item_name, id.default_warehouse
+		select i.name, i.item_name, id.default_warehouse, i.has_serial_no
 		from tabItem i, `tabItem Default` id
 		where i.name = id.parent
 			and exists(select name from `tabWarehouse` where lft >= %s and rgt <= %s and name=id.default_warehouse)
-			and i.is_stock_item = 1 and i.has_serial_no = 0 and i.has_batch_no = 0
+			and i.is_stock_item = 1 and i.has_batch_no = 0
 			and i.has_variants = 0 and i.disabled = 0 and id.company=%s
 		group by i.name
 	""", (lft, rgt, company))
@@ -497,7 +497,7 @@
 	res = []
 	for d in set(items):
 		stock_bal = get_stock_balance(d[0], d[2], posting_date, posting_time,
-			with_valuation_rate=True)
+			with_valuation_rate=True , with_serial_no=cint(d[3]))
 
 		if frappe.db.get_value("Item", d[0], "disabled") == 0:
 			res.append({
@@ -507,7 +507,9 @@
 				"item_name": d[1],
 				"valuation_rate": stock_bal[1],
 				"current_qty": stock_bal[0],
-				"current_valuation_rate": stock_bal[1]
+				"current_valuation_rate": stock_bal[1],
+				"current_serial_no": stock_bal[2] if cint(d[3]) else '',
+				"serial_no": stock_bal[2] if cint(d[3]) else ''
 			})
 
 	return res
diff --git a/erpnext/stock/stock_balance.py b/erpnext/stock/stock_balance.py
index 8ba1f1c..8917bfe 100644
--- a/erpnext/stock/stock_balance.py
+++ b/erpnext/stock/stock_balance.py
@@ -194,9 +194,6 @@
 		serial_nos = frappe.db.sql("""select count(name) from `tabSerial No`
 			where item_code=%s and warehouse=%s and docstatus < 2""", (d[0], d[1]))
 
-		if serial_nos and flt(serial_nos[0][0]) != flt(d[2]):
-			print(d[0], d[1], d[2], serial_nos[0][0])
-
 		sle = frappe.db.sql("""select valuation_rate, company from `tabStock Ledger Entry`
 			where item_code = %s and warehouse = %s and is_cancelled = 0
 			order by posting_date desc limit 1""", (d[0], d[1]))
@@ -230,7 +227,7 @@
 		})
 
 		update_bin(args)
-		
+
 		create_repost_item_valuation_entry({
 			"item_code": d[0],
 			"warehouse": d[1],
diff --git a/erpnext/support/doctype/issue/issue.json b/erpnext/support/doctype/issue/issue.json
index a43381c..bc29821 100644
--- a/erpnext/support/doctype/issue/issue.json
+++ b/erpnext/support/doctype/issue/issue.json
@@ -119,7 +119,7 @@
    "no_copy": 1,
    "oldfieldname": "status",
    "oldfieldtype": "Select",
-   "options": "Open\nReplied\nHold\nResolved\nClosed",
+   "options": "Open\nReplied\nOn Hold\nResolved\nClosed",
    "search_index": 1
   },
   {
@@ -410,7 +410,7 @@
  "icon": "fa fa-ticket",
  "idx": 7,
  "links": [],
- "modified": "2020-08-11 18:49:07.574769",
+ "modified": "2021-05-26 10:49:07.574769",
  "modified_by": "Administrator",
  "module": "Support",
  "name": "Issue",
diff --git a/erpnext/support/report/issue_summary/issue_summary.js b/erpnext/support/report/issue_summary/issue_summary.js
index eb0e06c..a5122d0 100644
--- a/erpnext/support/report/issue_summary/issue_summary.js
+++ b/erpnext/support/report/issue_summary/issue_summary.js
@@ -42,6 +42,7 @@
 				"",
 				{label: __('Open'), value: 'Open'},
 				{label: __('Replied'), value: 'Replied'},
+				{label: __('On Hold'), value: 'On Hold'},
 				{label: __('Resolved'), value: 'Resolved'},
 				{label: __('Closed'), value: 'Closed'}
 			]
diff --git a/erpnext/support/report/issue_summary/issue_summary.py b/erpnext/support/report/issue_summary/issue_summary.py
index 7861e30..bba25b8 100644
--- a/erpnext/support/report/issue_summary/issue_summary.py
+++ b/erpnext/support/report/issue_summary/issue_summary.py
@@ -62,7 +62,7 @@
 				'width': 200
 			})
 
-		self.statuses = ['Open', 'Replied', 'Resolved', 'Closed']
+		self.statuses = ['Open', 'Replied', 'On Hold', 'Resolved', 'Closed']
 		for status in self.statuses:
 			self.columns.append({
 				'label': _(status),
@@ -265,6 +265,7 @@
 		labels = []
 		open_issues = []
 		replied_issues = []
+		on_hold_issues = []
 		resolved_issues = []
 		closed_issues = []
 
@@ -277,6 +278,7 @@
 			labels.append(entry.get(entity_field))
 			open_issues.append(entry.get('open'))
 			replied_issues.append(entry.get('replied'))
+			on_hold_issues.append(entry.get('on_hold'))
 			resolved_issues.append(entry.get('resolved'))
 			closed_issues.append(entry.get('closed'))
 
@@ -293,6 +295,10 @@
 						'values': replied_issues[:30]
 					},
 					{
+						'name': 'On Hold',
+						'values': on_hold_issues[:30]
+					},
+					{
 						'name': 'Resolved',
 						'values': resolved_issues[:30]
 					},
@@ -313,12 +319,14 @@
 
 		open_issues = 0
 		replied = 0
+		on_hold = 0
 		resolved = 0
 		closed = 0
 
 		for entry in self.data:
 			open_issues += entry.get('open')
 			replied += entry.get('replied')
+			on_hold += entry.get('on_hold')
 			resolved += entry.get('resolved')
 			closed += entry.get('closed')
 
@@ -336,6 +344,12 @@
 				'datatype': 'Int',
 			},
 			{
+				'value': on_hold,
+				'indicator': 'Grey',
+				'label': _('On Hold'),
+				'datatype': 'Int',
+			},
+			{
 				'value': resolved,
 				'indicator': 'Green',
 				'label': _('Resolved'),
diff --git a/erpnext/tests/__init__.py b/erpnext/tests/__init__.py
index e69de29..a504340 100644
--- a/erpnext/tests/__init__.py
+++ b/erpnext/tests/__init__.py
@@ -0,0 +1 @@
+global_test_dependencies = ['User', 'Company', 'Item']
diff --git a/erpnext/utilities/__init__.py b/erpnext/utilities/__init__.py
index 618cc98..0a5aa3c 100644
--- a/erpnext/utilities/__init__.py
+++ b/erpnext/utilities/__init__.py
@@ -12,7 +12,6 @@
 
 		for f in dt.fields:
 			if f.fieldname == d.fieldname and f.fieldtype in ("Text", "Small Text"):
-				print(f.parent, f.fieldname)
 				f.fieldtype = "Text Editor"
 				dt.save()
 				break