Merge pull request #25545 from rohitwaghchaure/fixed-depost-withdrwal-values-has-not-updated

fix: rename field has not updated value of deposit and withdrawal fields
diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml
index 824b74e..84ecfb1 100644
--- a/.github/workflows/ci-tests.yml
+++ b/.github/workflows/ci-tests.yml
@@ -80,14 +80,29 @@
         env:
           TYPE: ${{ matrix.TYPE }}
 
-      - name: Coverage
-        if: matrix.TYPE == 'server'
+      - 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==3.0.1
-          pip install coverage==5.5
+          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/erpnext/__init__.py b/erpnext/__init__.py
index 4da0605..a988d72 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -5,7 +5,7 @@
 from erpnext.hooks import regional_overrides
 from frappe.utils import getdate
 
-__version__ = '13.1.0'
+__version__ = '13.2.0'
 
 def get_default_company(user=None):
 	'''Get default company for user'''
diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
index 6d2cffc..4d5472d 100644
--- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
+++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
@@ -235,11 +235,11 @@
 
 	return pos_invoice_customer_map
 
-def consolidate_pos_invoices(pos_invoices=[], closing_entry={}):
-	invoices = pos_invoices or closing_entry.get('pos_transactions') or get_all_unconsolidated_invoices()
+def consolidate_pos_invoices(pos_invoices=None, closing_entry=None):
+	invoices = pos_invoices or (closing_entry and closing_entry.get('pos_transactions')) or get_all_unconsolidated_invoices()
 	invoice_by_customer = get_invoice_customer_map(invoices)
 
-	if len(invoices) >= 5 and closing_entry:
+	if len(invoices) >= 1 and closing_entry:
 		closing_entry.set_status(update=True, status='Queued')
 		enqueue_job(create_merge_logs, invoice_by_customer=invoice_by_customer, closing_entry=closing_entry)
 	else:
@@ -252,18 +252,18 @@
 		pluck='name'
 	)
 
-	if len(merge_logs) >= 5:
+	if len(merge_logs) >= 1:
 		closing_entry.set_status(update=True, status='Queued')
 		enqueue_job(cancel_merge_logs, merge_logs=merge_logs, closing_entry=closing_entry)
 	else:
 		cancel_merge_logs(merge_logs, closing_entry)
 
-def create_merge_logs(invoice_by_customer, closing_entry={}):
+def create_merge_logs(invoice_by_customer, closing_entry=None):
 	for customer, invoices in iteritems(invoice_by_customer):
 		merge_log = frappe.new_doc('POS Invoice Merge Log')
-		merge_log.posting_date = getdate(closing_entry.get('posting_date'))
+		merge_log.posting_date = getdate(closing_entry.get('posting_date')) if closing_entry else nowdate()
 		merge_log.customer = customer
-		merge_log.pos_closing_entry = closing_entry.get('name', None)
+		merge_log.pos_closing_entry = closing_entry.get('name') if closing_entry else None
 
 		merge_log.set('pos_invoices', invoices)
 		merge_log.save(ignore_permissions=True)
@@ -273,7 +273,7 @@
 		closing_entry.set_status(update=True, status='Submitted')
 		closing_entry.update_opening_entry()
 
-def cancel_merge_logs(merge_logs, closing_entry={}):
+def cancel_merge_logs(merge_logs, closing_entry=None):
 	for log in merge_logs:
 		merge_log = frappe.get_doc('POS Invoice Merge Log', log)
 		merge_log.flags.ignore_permissions = True
@@ -283,20 +283,20 @@
 		closing_entry.set_status(update=True, status='Cancelled')
 		closing_entry.update_opening_entry(for_cancel=True)
 
-def enqueue_job(job, merge_logs=None, invoice_by_customer=None, closing_entry=None):
+def enqueue_job(job, **kwargs):
 	check_scheduler_status()
 
+	closing_entry = kwargs.get('closing_entry') or {}
+
 	job_name = closing_entry.get("name")
 	if not job_already_enqueued(job_name):
 		enqueue(
 			job,
+			**kwargs,
 			queue="long",
 			timeout=10000,
 			event="processing_merge_logs",
 			job_name=job_name,
-			closing_entry=closing_entry,
-			invoice_by_customer=invoice_by_customer,
-			merge_logs=merge_logs,
 			now=frappe.conf.developer_mode or frappe.flags.in_test
 		)
 
diff --git a/erpnext/accounts/doctype/pos_search_fields/__init__.py b/erpnext/accounts/doctype/pos_search_fields/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/doctype/pos_search_fields/__init__.py
diff --git a/erpnext/accounts/doctype/pos_search_fields/pos_search_fields.json b/erpnext/accounts/doctype/pos_search_fields/pos_search_fields.json
new file mode 100644
index 0000000..a627f5b
--- /dev/null
+++ b/erpnext/accounts/doctype/pos_search_fields/pos_search_fields.json
@@ -0,0 +1,37 @@
+{
+ "actions": [],
+ "creation": "2021-04-19 14:56:06.652327",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "field",
+  "fieldname"
+ ],
+ "fields": [
+  {
+   "fieldname": "fieldname",
+   "fieldtype": "Data",
+   "hidden": 1,
+   "label": "Fieldname"
+  },
+  {
+   "fieldname": "field",
+   "fieldtype": "Select",
+   "in_list_view": 1,
+   "label": "Field"
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-04-21 11:12:54.632093",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "POS Search Fields",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/pos_search_fields/pos_search_fields.py b/erpnext/accounts/doctype/pos_search_fields/pos_search_fields.py
new file mode 100644
index 0000000..720ea77
--- /dev/null
+++ b/erpnext/accounts/doctype/pos_search_fields/pos_search_fields.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+# import frappe
+from frappe.model.document import Document
+
+class POSSearchFields(Document):
+	pass
diff --git a/erpnext/accounts/doctype/pos_settings/pos_settings.js b/erpnext/accounts/doctype/pos_settings/pos_settings.js
index 3625393..9003af5 100644
--- a/erpnext/accounts/doctype/pos_settings/pos_settings.js
+++ b/erpnext/accounts/doctype/pos_settings/pos_settings.js
@@ -1,9 +1,17 @@
 // Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
 // For license information, please see license.txt
 
+let search_fields_datatypes = ['Data', 'Link', 'Dynamic Link', 'Long Text', 'Select', 'Small Text', 'Text', 'Text Editor'];
+let do_not_include_fields = ["naming_series", "item_code", "item_name", "stock_uom", "hub_sync_id", "asset_naming_series",
+	"default_material_request_type", "valuation_method", "warranty_period", "weight_uom", "batch_number_series",
+	"serial_no_series", "purchase_uom", "customs_tariff_number", "sales_uom", "deferred_revenue_account",
+	"deferred_expense_account", "quality_inspection_template", "route", "slideshow", "website_image_alt", "thumbnail",
+	"web_long_description", "hub_sync_id"]
+
 frappe.ui.form.on('POS Settings', {
 	onload: function(frm) {
 		frm.trigger("get_invoice_fields");
+		frm.trigger("add_search_options");
 	},
 
 	get_invoice_fields: function(frm) {
@@ -21,6 +29,38 @@
 			);
 		});
 
+	},
+
+	add_search_options: function(frm) {
+		frappe.model.with_doctype("Item", () => {
+			var fields = $.map(frappe.get_doc("DocType", "Item").fields, function(d) {
+				if (search_fields_datatypes.includes(d.fieldtype) && !(do_not_include_fields.includes(d.fieldname))) {
+					return [d.label];
+				} else {
+					return null;
+				}
+			});
+
+			fields.unshift('');
+			frm.fields_dict.pos_search_fields.grid.update_docfield_property('field', 'options', fields);
+		});
+
+	}
+});
+
+frappe.ui.form.on("POS Search Fields", {
+	field: function(frm, doctype, name) {
+		var doc = frappe.get_doc(doctype, name);
+		var df = $.map(frappe.get_doc("DocType", "Item").fields, function(d) {
+			if (doc.field == d.label && search_fields_datatypes.includes(d.fieldtype)) {
+				return d;
+			} else {
+				return null;
+			}
+		})[0];
+
+		doc.fieldname = df.fieldname;
+		frm.refresh_field("fields");
 	}
 });
 
diff --git a/erpnext/accounts/doctype/pos_settings/pos_settings.json b/erpnext/accounts/doctype/pos_settings/pos_settings.json
index 3539588..962eb94 100644
--- a/erpnext/accounts/doctype/pos_settings/pos_settings.json
+++ b/erpnext/accounts/doctype/pos_settings/pos_settings.json
@@ -5,7 +5,8 @@
  "editable_grid": 1,
  "engine": "InnoDB",
  "field_order": [
-  "invoice_fields"
+  "invoice_fields",
+  "pos_search_fields"
  ],
  "fields": [
   {
@@ -13,11 +14,17 @@
    "fieldtype": "Table",
    "label": "POS Field",
    "options": "POS Field"
+  },
+  {
+   "fieldname": "pos_search_fields",
+   "fieldtype": "Table",
+   "label": "POS Search Fields",
+   "options": "POS Search Fields"
   }
  ],
  "issingle": 1,
  "links": [],
- "modified": "2020-06-01 15:46:41.478928",
+ "modified": "2021-04-19 14:56:24.465218",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "POS Settings",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index e61cde8..f58c8f4 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -514,6 +514,28 @@
 		}
 	},
 
+	refresh: function(frm) {
+		frm.events.add_custom_buttons(frm);
+	},
+
+	add_custom_buttons: function(frm) {
+		if (frm.doc.per_received < 100) {
+			frm.add_custom_button(__('Purchase Receipt'), () => {
+				frm.events.make_purchase_receipt(frm);
+			}, __('Create'));
+		}
+
+		if (frm.doc.docstatus == 1 && frm.doc.per_received > 0) {
+			frm.add_custom_button(__('Purchase Receipt'), () => {
+				frappe.route_options = {
+					'purchase_invoice': frm.doc.name
+				}
+
+				frappe.set_route("List", "Purchase Receipt", "List")
+			}, __('View'));
+		}
+	},
+
 	onload: function(frm) {
 		if(frm.doc.__onload && frm.is_new()) {
 			if(frm.doc.supplier) {
@@ -539,5 +561,13 @@
 	update_stock: function(frm) {
 		hide_fields(frm.doc);
 		frm.fields_dict.items.grid.toggle_reqd("item_code", frm.doc.update_stock? true: false);
+	},
+
+	make_purchase_receipt: function(frm) {
+		frappe.model.open_mapped_doc({
+			method: "erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_purchase_receipt",
+			frm: frm,
+			freeze_message: __("Creating Purchase Receipt ...")
+		})
 	}
 })
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index 2d5760b..24e67fe 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -163,7 +163,8 @@
   "to_date",
   "column_break_114",
   "auto_repeat",
-  "update_auto_repeat_reference"
+  "update_auto_repeat_reference",
+  "per_received"
  ],
  "fields": [
   {
@@ -1364,6 +1365,15 @@
    "print_hide": 1,
    "print_width": "50px",
    "width": "50px"
+  },
+  {
+   "fieldname": "per_received",
+   "fieldtype": "Percent",
+   "hidden": 1,
+   "label": "Per Received",
+   "no_copy": 1,
+   "print_hide": 1,
+   "read_only": 1
   }
  ],
  "icon": "fa fa-file-text",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 5c4e32e..83e9f75 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -1207,3 +1207,41 @@
 
 def on_doctype_update():
 	frappe.db.add_index("Purchase Invoice", ["supplier", "is_return", "return_against"])
+
+@frappe.whitelist()
+def make_purchase_receipt(source_name, target_doc=None):
+	def update_item(obj, target, source_parent):
+		target.qty = flt(obj.qty) - flt(obj.received_qty)
+		target.received_qty = flt(obj.qty) - flt(obj.received_qty)
+		target.stock_qty = (flt(obj.qty) - flt(obj.received_qty)) * flt(obj.conversion_factor)
+		target.amount = (flt(obj.qty) - flt(obj.received_qty)) * flt(obj.rate)
+		target.base_amount = (flt(obj.qty) - flt(obj.received_qty)) * \
+			flt(obj.rate) * flt(source_parent.conversion_rate)
+
+	doc = get_mapped_doc("Purchase Invoice", source_name, {
+		"Purchase Invoice": {
+			"doctype": "Purchase Receipt",
+			"validation": {
+				"docstatus": ["=", 1],
+			}
+		},
+		"Purchase Invoice Item": {
+			"doctype": "Purchase Receipt Item",
+			"field_map": {
+				"name": "purchase_invoice_item",
+				"parent": "purchase_invoice",
+				"bom": "bom",
+				"purchase_order": "purchase_order",
+				"po_detail": "purchase_order_item",
+				"material_request": "material_request",
+				"material_request_item": "material_request_item"
+			},
+			"postprocess": update_item,
+			"condition": lambda doc: abs(doc.received_qty) < abs(doc.qty)
+		},
+		"Purchase Taxes and Charges": {
+			"doctype": "Purchase Taxes and Charges"
+		}
+	}, target_doc)
+
+	return doc
diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
index 96ad0fd..10e1c73 100644
--- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
+++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
@@ -607,6 +607,7 @@
    "oldfieldname": "purchase_order",
    "oldfieldtype": "Link",
    "options": "Purchase Order",
+   "print_hide": 1,
    "read_only": 1,
    "search_index": 1
   },
@@ -853,7 +854,7 @@
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2021-02-23 00:59:52.614805",
+ "modified": "2021-03-30 09:02:39.256602",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Purchase Invoice Item",
diff --git a/erpnext/accounts/doctype/subscription/subscription.json b/erpnext/accounts/doctype/subscription/subscription.json
index e80df2a..c4e4be7 100644
--- a/erpnext/accounts/doctype/subscription/subscription.json
+++ b/erpnext/accounts/doctype/subscription/subscription.json
@@ -36,6 +36,7 @@
   "additional_discount_percentage",
   "additional_discount_amount",
   "sb_3",
+  "submit_invoice",
   "invoices",
   "accounting_dimensions_section",
   "cost_center",
@@ -45,9 +46,7 @@
   {
    "allow_on_submit": 1,
    "fieldname": "cb_1",
-   "fieldtype": "Column Break",
-   "show_days": 1,
-   "show_seconds": 1
+   "fieldtype": "Column Break"
   },
   {
    "fieldname": "status",
@@ -55,97 +54,73 @@
    "label": "Status",
    "no_copy": 1,
    "options": "\nTrialling\nActive\nPast Due Date\nCancelled\nUnpaid\nCompleted",
-   "read_only": 1,
-   "show_days": 1,
-   "show_seconds": 1
+   "read_only": 1
   },
   {
    "fieldname": "subscription_period",
    "fieldtype": "Section Break",
-   "label": "Subscription Period",
-   "show_days": 1,
-   "show_seconds": 1
+   "label": "Subscription Period"
   },
   {
    "fieldname": "cancelation_date",
    "fieldtype": "Date",
    "label": "Cancelation Date",
-   "read_only": 1,
-   "show_days": 1,
-   "show_seconds": 1
+   "read_only": 1
   },
   {
    "allow_on_submit": 1,
    "fieldname": "trial_period_start",
    "fieldtype": "Date",
    "label": "Trial Period Start Date",
-   "set_only_once": 1,
-   "show_days": 1,
-   "show_seconds": 1
+   "set_only_once": 1
   },
   {
    "depends_on": "eval:doc.trial_period_start",
    "fieldname": "trial_period_end",
    "fieldtype": "Date",
    "label": "Trial Period End Date",
-   "set_only_once": 1,
-   "show_days": 1,
-   "show_seconds": 1
+   "set_only_once": 1
   },
   {
    "fieldname": "column_break_11",
-   "fieldtype": "Column Break",
-   "show_days": 1,
-   "show_seconds": 1
+   "fieldtype": "Column Break"
   },
   {
    "fieldname": "current_invoice_start",
    "fieldtype": "Date",
    "label": "Current Invoice Start Date",
-   "read_only": 1,
-   "show_days": 1,
-   "show_seconds": 1
+   "read_only": 1
   },
   {
    "fieldname": "current_invoice_end",
    "fieldtype": "Date",
    "label": "Current Invoice End Date",
-   "read_only": 1,
-   "show_days": 1,
-   "show_seconds": 1
+   "read_only": 1
   },
   {
    "default": "0",
    "description": "Number of days that the subscriber has to pay invoices generated by this subscription",
    "fieldname": "days_until_due",
    "fieldtype": "Int",
-   "label": "Days Until Due",
-   "show_days": 1,
-   "show_seconds": 1
+   "label": "Days Until Due"
   },
   {
    "default": "0",
    "fieldname": "cancel_at_period_end",
    "fieldtype": "Check",
-   "label": "Cancel At End Of Period",
-   "show_days": 1,
-   "show_seconds": 1
+   "label": "Cancel At End Of Period"
   },
   {
    "default": "0",
    "fieldname": "generate_invoice_at_period_start",
    "fieldtype": "Check",
-   "label": "Generate Invoice At Beginning Of Period",
-   "show_days": 1,
-   "show_seconds": 1
+   "label": "Generate Invoice At Beginning Of Period"
   },
   {
    "allow_on_submit": 1,
    "fieldname": "sb_4",
    "fieldtype": "Section Break",
-   "label": "Plans",
-   "show_days": 1,
-   "show_seconds": 1
+   "label": "Plans"
   },
   {
    "allow_on_submit": 1,
@@ -153,84 +128,62 @@
    "fieldtype": "Table",
    "label": "Plans",
    "options": "Subscription Plan Detail",
-   "reqd": 1,
-   "show_days": 1,
-   "show_seconds": 1
+   "reqd": 1
   },
   {
    "depends_on": "eval:['Customer', 'Supplier'].includes(doc.party_type)",
    "fieldname": "sb_1",
    "fieldtype": "Section Break",
-   "label": "Taxes",
-   "show_days": 1,
-   "show_seconds": 1
+   "label": "Taxes"
   },
   {
    "fieldname": "sb_2",
    "fieldtype": "Section Break",
-   "label": "Discounts",
-   "show_days": 1,
-   "show_seconds": 1
+   "label": "Discounts"
   },
   {
    "fieldname": "apply_additional_discount",
    "fieldtype": "Select",
    "label": "Apply Additional Discount On",
-   "options": "\nGrand Total\nNet Total",
-   "show_days": 1,
-   "show_seconds": 1
+   "options": "\nGrand Total\nNet Total"
   },
   {
    "fieldname": "cb_2",
-   "fieldtype": "Column Break",
-   "show_days": 1,
-   "show_seconds": 1
+   "fieldtype": "Column Break"
   },
   {
    "fieldname": "additional_discount_percentage",
    "fieldtype": "Percent",
-   "label": "Additional DIscount Percentage",
-   "show_days": 1,
-   "show_seconds": 1
+   "label": "Additional DIscount Percentage"
   },
   {
    "collapsible": 1,
    "fieldname": "additional_discount_amount",
    "fieldtype": "Currency",
-   "label": "Additional DIscount Amount",
-   "show_days": 1,
-   "show_seconds": 1
+   "label": "Additional DIscount Amount"
   },
   {
    "depends_on": "eval:doc.invoices",
    "fieldname": "sb_3",
    "fieldtype": "Section Break",
-   "label": "Invoices",
-   "show_days": 1,
-   "show_seconds": 1
+   "label": "Invoices"
   },
   {
    "collapsible": 1,
    "fieldname": "invoices",
    "fieldtype": "Table",
    "label": "Invoices",
-   "options": "Subscription Invoice",
-   "show_days": 1,
-   "show_seconds": 1
+   "options": "Subscription Invoice"
   },
   {
    "collapsible": 1,
    "fieldname": "accounting_dimensions_section",
    "fieldtype": "Section Break",
-   "label": "Accounting Dimensions",
-   "show_days": 1,
-   "show_seconds": 1
+   "label": "Accounting Dimensions"
   },
   {
    "fieldname": "dimension_col_break",
-   "fieldtype": "Column Break",
-   "show_days": 1,
-   "show_seconds": 1
+   "fieldtype": "Column Break"
   },
   {
    "fieldname": "party_type",
@@ -238,9 +191,7 @@
    "label": "Party Type",
    "options": "DocType",
    "reqd": 1,
-   "set_only_once": 1,
-   "show_days": 1,
-   "show_seconds": 1
+   "set_only_once": 1
   },
   {
    "fieldname": "party",
@@ -249,27 +200,21 @@
    "label": "Party",
    "options": "party_type",
    "reqd": 1,
-   "set_only_once": 1,
-   "show_days": 1,
-   "show_seconds": 1
+   "set_only_once": 1
   },
   {
    "depends_on": "eval:doc.party_type === 'Customer'",
    "fieldname": "sales_tax_template",
    "fieldtype": "Link",
    "label": "Sales Taxes and Charges Template",
-   "options": "Sales Taxes and Charges Template",
-   "show_days": 1,
-   "show_seconds": 1
+   "options": "Sales Taxes and Charges Template"
   },
   {
    "depends_on": "eval:doc.party_type === 'Supplier'",
    "fieldname": "purchase_tax_template",
    "fieldtype": "Link",
    "label": "Purchase Taxes and Charges Template",
-   "options": "Purchase Taxes and Charges Template",
-   "show_days": 1,
-   "show_seconds": 1
+   "options": "Purchase Taxes and Charges Template"
   },
   {
    "default": "0",
@@ -277,55 +222,49 @@
    "fieldname": "follow_calendar_months",
    "fieldtype": "Check",
    "label": "Follow Calendar Months",
-   "set_only_once": 1,
-   "show_days": 1,
-   "show_seconds": 1
+   "set_only_once": 1
   },
   {
    "default": "0",
    "description": "New invoices will be generated as per schedule even if current invoices are unpaid or past due date",
    "fieldname": "generate_new_invoices_past_due_date",
    "fieldtype": "Check",
-   "label": "Generate New Invoices Past Due Date",
-   "show_days": 1,
-   "show_seconds": 1
+   "label": "Generate New Invoices Past Due Date"
   },
   {
    "fieldname": "end_date",
    "fieldtype": "Date",
    "label": "Subscription End Date",
-   "set_only_once": 1,
-   "show_days": 1,
-   "show_seconds": 1
+   "set_only_once": 1
   },
   {
    "fieldname": "start_date",
    "fieldtype": "Date",
    "label": "Subscription Start Date",
-   "set_only_once": 1,
-   "show_days": 1,
-   "show_seconds": 1
+   "set_only_once": 1
   },
   {
    "fieldname": "cost_center",
    "fieldtype": "Link",
    "label": "Cost Center",
-   "options": "Cost Center",
-   "show_days": 1,
-   "show_seconds": 1
+   "options": "Cost Center"
   },
   {
    "fieldname": "company",
    "fieldtype": "Link",
    "label": "Company",
-   "options": "Company",
-   "show_days": 1,
-   "show_seconds": 1
+   "options": "Company"
+  },
+  {
+   "default": "1",
+   "fieldname": "submit_invoice",
+   "fieldtype": "Check",
+   "label": "Submit Invoice Automatically"
   }
  ],
  "index_web_pages_for_search": 1,
  "links": [],
- "modified": "2021-02-09 15:44:20.024789",
+ "modified": "2021-04-19 15:24:27.550797",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Subscription",
diff --git a/erpnext/accounts/doctype/subscription/subscription.py b/erpnext/accounts/doctype/subscription/subscription.py
index 826044a..7c4ff73 100644
--- a/erpnext/accounts/doctype/subscription/subscription.py
+++ b/erpnext/accounts/doctype/subscription/subscription.py
@@ -276,7 +276,7 @@
 				frappe.throw(_('Subscription End Date is mandatory to follow calendar months'))
 
 			if billing_info[0]['billing_interval'] != 'Month':
-				frappe.throw('Billing Interval in Subscription Plan must be Month to follow calendar months')
+				frappe.throw(_('Billing Interval in Subscription Plan must be Month to follow calendar months'))
 
 	def after_insert(self):
 		# todo: deal with users who collect prepayments. Maybe a new Subscription Invoice doctype?
@@ -383,7 +383,9 @@
 
 		invoice.flags.ignore_mandatory = True
 		invoice.save()
-		invoice.submit()
+
+		if self.submit_invoice:
+			invoice.submit()
 
 		return invoice
 
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index 85bff10..f1717c5 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -171,7 +171,7 @@
 	else:
 		allowance = .5
 
-	if abs(debit_credit_diff) >= allowance:
+	if abs(debit_credit_diff) > allowance:
 		frappe.throw(_("Debit and Credit not equal for {0} #{1}. Difference is {2}.")
 			.format(gl_map[0].voucher_type, gl_map[0].voucher_no, debit_credit_diff))
 
diff --git a/erpnext/accounts/report/billed_items_to_be_received/__init__.py b/erpnext/accounts/report/billed_items_to_be_received/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/report/billed_items_to_be_received/__init__.py
diff --git a/erpnext/accounts/report/billed_items_to_be_received/billed_items_to_be_received.js b/erpnext/accounts/report/billed_items_to_be_received/billed_items_to_be_received.js
new file mode 100644
index 0000000..e1fccb6
--- /dev/null
+++ b/erpnext/accounts/report/billed_items_to_be_received/billed_items_to_be_received.js
@@ -0,0 +1,29 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports['Billed Items To Be Received'] = {
+	'filters': [
+		{
+			'label': __('Company'),
+			'fieldname': 'company',
+			'fieldtype': 'Link',
+			'options': 'Company',
+			'reqd': 1,
+			'default': frappe.defaults.get_default('Company')
+		},
+		{
+			'label': __('As on Date'),
+			'fieldname': 'posting_date',
+			'fieldtype': 'Date',
+			'reqd': 1,
+			'default': get_today()
+		},
+		{
+			'label': __('Purchase Invoice'),
+			'fieldname': 'purchase_invoice',
+			'fieldtype': 'Link',
+			'options': 'Purchase Invoice'
+		}
+	]
+};
diff --git a/erpnext/accounts/report/billed_items_to_be_received/billed_items_to_be_received.json b/erpnext/accounts/report/billed_items_to_be_received/billed_items_to_be_received.json
new file mode 100644
index 0000000..de09b33
--- /dev/null
+++ b/erpnext/accounts/report/billed_items_to_be_received/billed_items_to_be_received.json
@@ -0,0 +1,39 @@
+{
+ "add_total_row": 0,
+ "columns": [],
+ "creation": "2021-03-30 09:35:38.683028",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "filters": [],
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2021-03-31 08:48:30.944429",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Billed Items To Be Received",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "query": "",
+ "ref_doctype": "Purchase Invoice",
+ "report_name": "Billed Items To Be Received",
+ "report_type": "Script Report",
+ "roles": [
+  {
+   "role": "Accounts User"
+  },
+  {
+   "role": "Purchase User"
+  },
+  {
+   "role": "Accounts Manager"
+  },
+  {
+   "role": "Auditor"
+  },
+  {
+   "role": "Stock User"
+  }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/accounts/report/billed_items_to_be_received/billed_items_to_be_received.py b/erpnext/accounts/report/billed_items_to_be_received/billed_items_to_be_received.py
new file mode 100644
index 0000000..2ce5d50
--- /dev/null
+++ b/erpnext/accounts/report/billed_items_to_be_received/billed_items_to_be_received.py
@@ -0,0 +1,107 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+
+def execute(filters=None):
+	data = get_data(filters) or []
+	columns = get_columns()
+
+	return columns, data
+
+def get_data(report_filters):
+	filters = get_report_filters(report_filters)
+	fields = get_report_fields()
+
+	return frappe.get_all('Purchase Invoice',
+		fields= fields, filters=filters)
+
+def get_report_filters(report_filters):
+	filters = [['Purchase Invoice','company','=',report_filters.get('company')],
+		['Purchase Invoice','posting_date','<=',report_filters.get('posting_date')], ['Purchase Invoice','docstatus','=',1],
+		['Purchase Invoice','per_received','<',100], ['Purchase Invoice','update_stock','=',0]]
+
+	if report_filters.get('purchase_invoice'):
+		filters.append(['Purchase Invoice','per_received','in',[report_filters.get('purchase_invoice')]])
+
+	return filters
+
+def get_report_fields():
+	fields = []
+	for p_field in ['name', 'supplier', 'company', 'posting_date', 'currency']:
+		fields.append('`tabPurchase Invoice`.`{}`'.format(p_field))
+
+	for c_field in ['item_code', 'item_name', 'uom', 'qty', 'received_qty', 'rate', 'amount']:
+		fields.append('`tabPurchase Invoice Item`.`{}`'.format(c_field))
+
+	return fields
+
+def get_columns():
+	return [
+		{
+			'label': _('Purchase Invoice'),
+			'fieldname': 'name',
+			'fieldtype': 'Link',
+			'options': 'Purchase Invoice',
+			'width': 170
+		},
+		{
+			'label': _('Supplier'),
+			'fieldname': 'supplier',
+			'fieldtype': 'Link',
+			'options': 'Supplier',
+			'width': 120
+		},
+		{
+			'label': _('Posting Date'),
+			'fieldname': 'posting_date',
+			'fieldtype': 'Date',
+			'width': 100
+		},
+		{
+			'label': _('Item Code'),
+			'fieldname': 'item_code',
+			'fieldtype': 'Link',
+			'options': 'Item',
+			'width': 100
+		},
+		{
+			'label': _('Item Name'),
+			'fieldname': 'item_name',
+			'fieldtype': 'Data',
+			'width': 100
+		},
+		{
+			'label': _('UOM'),
+			'fieldname': 'uom',
+			'fieldtype': 'Link',
+			'options': 'UOM',
+			'width': 100
+		},
+		{
+			'label': _('Invoiced Qty'),
+			'fieldname': 'qty',
+			'fieldtype': 'Float',
+			'width': 100
+		},
+		{
+			'label': _('Received Qty'),
+			'fieldname': 'received_qty',
+			'fieldtype': 'Float',
+			'width': 100
+		},
+		{
+			'label': _('Rate'),
+			'fieldname': 'rate',
+			'fieldtype': 'Currency',
+			'width': 100
+		},
+		{
+			'label': _('Amount'),
+			'fieldname': 'amount',
+			'fieldtype': 'Currency',
+			'width': 100
+		}
+	]
\ No newline at end of file
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index 3c4f908..42f4472 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -435,6 +435,35 @@
 		po.load_from_db()
 		self.assertEqual(po.get("items")[0].received_qty, 5)
 
+	def test_purchase_order_invoice_receipt_workflow(self):
+		from erpnext.accounts.doctype.purchase_invoice.purchase_invoice import make_purchase_receipt
+
+		po = create_purchase_order()
+		pi = make_pi_from_po(po.name)
+
+		pi.submit()
+
+		pr = make_purchase_receipt(pi.name)
+		pr.submit()
+
+		pi.load_from_db()
+
+		self.assertEquals(pi.per_received, 100.00)
+		self.assertEquals(pi.items[0].qty, pi.items[0].received_qty)
+
+		po.load_from_db()
+
+		self.assertEquals(po.per_received, 100.00)
+		self.assertEquals(po.per_billed, 100.00)
+
+		pr.cancel()
+
+		pi.load_from_db()
+		pi.cancel()
+
+		po.load_from_db()
+		po.cancel()
+
 	def test_make_purchase_invoice(self):
 		po = create_purchase_order(do_not_submit=True)
 
diff --git a/erpnext/change_log/v13/v13_2_0.md b/erpnext/change_log/v13/v13_2_0.md
new file mode 100644
index 0000000..eb9499d
--- /dev/null
+++ b/erpnext/change_log/v13/v13_2_0.md
@@ -0,0 +1,56 @@
+# Version 13.2.0 Release Notes
+
+### Features & Enhancements
+
+- Employee Hours Utilization Report ([#25209](https://github.com/frappe/erpnext/pull/25209))
+- Delayed Tasks Summary Report ([#25024](https://github.com/frappe/erpnext/pull/25024))
+- Project Profitability Report ([#24944](https://github.com/frappe/erpnext/pull/24944))
+- Timer in LMS Quiz ([#24246](https://github.com/frappe/erpnext/pull/24246))
+- Role to allow over billing, delivery, receipt ([#24854](https://github.com/frappe/erpnext/pull/24854))
+- Auto calculate distance for e-way bill generations ([#25480](https://github.com/frappe/erpnext/pull/25480))
+- Add total available stock field in PO ([#24878](https://github.com/frappe/erpnext/pull/24878))
+- Refactored Setup Taxes and Charges ([#24805](https://github.com/frappe/erpnext/pull/24805))
+- Inpatient Occupancy Table Editable for Healthcare Admin ([#24989](https://github.com/frappe/erpnext/pull/24989))
+- Added Disable Rounded Total in sales transactions ([#25362](https://github.com/frappe/erpnext/pull/25362))
+
+
+### Fixes
+
+- Incorrect GL Entry validation ([#25474](https://github.com/frappe/erpnext/pull/25474))
+- Cannot create item variants ([#25433](https://github.com/frappe/erpnext/pull/25433))
+- Leave policy in leave allocation ([#25334](https://github.com/frappe/erpnext/pull/25334))
+- Let Administrator delete company transactions ([#25300](https://github.com/frappe/erpnext/pull/25300))
+- Display reconcile tool when closing balance 0 ([#25417](https://github.com/frappe/erpnext/pull/25417))
+- Bulk Salary Structure Assignment ([#25389](https://github.com/frappe/erpnext/pull/25389))
+- Payment amount showing in foreign currency ([#25518](https://github.com/frappe/erpnext/pull/25518))
+- Commit changes to shipment status in database ([#25374](https://github.com/frappe/erpnext/pull/25374))
+- Add amend perm for loan and system manager for loan doctypes ([#25393](https://github.com/frappe/erpnext/pull/25393))
+- Cashier query in POS Opening/Closing Entry ([#25398](https://github.com/frappe/erpnext/pull/25398))
+- Apply single transaction threshold on net_total instead of supplier credit amount ([#25243](https://github.com/frappe/erpnext/pull/25243))
+- Update allocated amount after paid amount is changed in PE ([#25528](https://github.com/frappe/erpnext/pull/25528))
+- Remove non-standard module cards from Home Workspace ([#25391](https://github.com/frappe/erpnext/pull/25391))
+- Cannot scan spacebar character in pos ([#25479](https://github.com/frappe/erpnext/pull/25479))
+- Permission error after submitting exchange rate revaluation ([#25432](https://github.com/frappe/erpnext/pull/25432))
+- Equality check instead of assignment in cart ([#25372](https://github.com/frappe/erpnext/pull/25372))
+- Disable auto naming of customer during import ([#25152](https://github.com/frappe/erpnext/pull/25152))
+- Additional Salary component amount not getting set ([#25355](https://github.com/frappe/erpnext/pull/25355))
+- Round off values near to zero ([#25304](https://github.com/frappe/erpnext/pull/25304))
+- Allow to cancel loan with cancelled repayment entry ([#25508](https://github.com/frappe/erpnext/pull/25508))
+- Currency symbol in bank transaction list view ([#25336](https://github.com/frappe/erpnext/pull/25336))
+- Incorrect batch picked in subcontracted purchase receipt ([#25186](https://github.com/frappe/erpnext/pull/25186))
+- Issue in project custom status ([#25452](https://github.com/frappe/erpnext/pull/25452))
+- Shipment pickup_to, pickup_from functionality. ([#25359](https://github.com/frappe/erpnext/pull/25359))
+- Stock ledger entry created against draft stock entry ([#25539](https://github.com/frappe/erpnext/pull/25539))
+- Ageing errors in PSOA ([#25529](https://github.com/frappe/erpnext/pull/25529))
+- Permission error while adding weekly holidays ([#25450](https://github.com/frappe/erpnext/pull/25450))
+- Filter for employees in salary slip ([#25360](https://github.com/frappe/erpnext/pull/25360))
+- Backward compatibility for GSTR-1 report ([#25444](https://github.com/frappe/erpnext/pull/25444))
+- Incorrect incoming rate for the sales return ([#25145](https://github.com/frappe/erpnext/pull/25145))
+- POS print receipt ([#25328](https://github.com/frappe/erpnext/pull/25328))
+- Laboratory Module patch ([#25431](https://github.com/frappe/erpnext/pull/25431))
+- Performance: fetching exchange rate on every line item slows down PO ([#25345](https://github.com/frappe/erpnext/pull/25345))
+- Presentation currency in statement of accounts ([#25367](https://github.com/frappe/erpnext/pull/25367))
+- Serial No not updated correctly via Inter Company Stock Transfer ([#25006](https://github.com/frappe/erpnext/pull/25006))
+- Ignore Customer Group Perm on All Products page ([#25396](https://github.com/frappe/erpnext/pull/25396))
+- Change subcontracted item display ([#25425](https://github.com/frappe/erpnext/pull/25425))
+- Add company validation for e-invoicing ([#25348](https://github.com/frappe/erpnext/pull/25348))
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.js b/erpnext/hr/doctype/employee_advance/employee_advance.js
index 5037ceb..fa4b06a 100644
--- a/erpnext/hr/doctype/employee_advance/employee_advance.js
+++ b/erpnext/hr/doctype/employee_advance/employee_advance.js
@@ -34,7 +34,7 @@
 			};
 		});
 
-		frm.set_query('salary_component', function(doc) {
+		frm.set_query('salary_component', function() {
 			return {
 				filters: {
 					"type": "Deduction"
@@ -44,48 +44,49 @@
 	},
 
 	refresh: function(frm) {
-		if (frm.doc.docstatus===1
-			&& (flt(frm.doc.paid_amount) < flt(frm.doc.advance_amount))
-			&& frappe.model.can_create("Payment Entry")) {
+		if (frm.doc.docstatus === 1 &&
+			(flt(frm.doc.paid_amount) < flt(frm.doc.advance_amount)) &&
+			frappe.model.can_create("Payment Entry")) {
 			frm.add_custom_button(__('Payment'),
-				function() { frm.events.make_payment_entry(frm); }, __('Create'));
-		}
-		else if (
-			frm.doc.docstatus === 1
-			&& flt(frm.doc.claimed_amount) < flt(frm.doc.paid_amount) - flt(frm.doc.return_amount)
-			&& frappe.model.can_create("Expense Claim")
+				function () {
+					frm.events.make_payment_entry(frm);
+				}, __('Create'));
+		} else if (
+			frm.doc.docstatus === 1 &&
+			flt(frm.doc.claimed_amount) < flt(frm.doc.paid_amount) - flt(frm.doc.return_amount) &&
+			frappe.model.can_create("Expense Claim")
 		) {
 			frm.add_custom_button(
 				__("Expense Claim"),
-				function() {
+				function () {
 					frm.events.make_expense_claim(frm);
 				},
 				__('Create')
 			);
 		}
 
-		if (frm.doc.docstatus === 1
-			&& (flt(frm.doc.claimed_amount) < flt(frm.doc.paid_amount) && flt(frm.doc.paid_amount) != flt(frm.doc.return_amount))) {
+		if (frm.doc.docstatus === 1 &&
+			(flt(frm.doc.claimed_amount) < flt(frm.doc.paid_amount) && flt(frm.doc.paid_amount) != flt(frm.doc.return_amount))) {
 
-			if (frm.doc.repay_unclaimed_amount_from_salary == 0 && frappe.model.can_create("Journal Entry")){
-				frm.add_custom_button(__("Return"),  function() {
+			if (frm.doc.repay_unclaimed_amount_from_salary == 0 && frappe.model.can_create("Journal Entry")) {
+				frm.add_custom_button(__("Return"), function() {
 					frm.trigger('make_return_entry');
 				}, __('Create'));
-			}else if (frm.doc.repay_unclaimed_amount_from_salary == 1 && frappe.model.can_create("Additional Salary")){
-				frm.add_custom_button(__("Deduction from salary"),  function() {
+			} else if (frm.doc.repay_unclaimed_amount_from_salary == 1 && frappe.model.can_create("Additional Salary")) {
+				frm.add_custom_button(__("Deduction from salary"), function() {
 					frm.events.make_deduction_via_additional_salary(frm);
 				}, __('Create'));
 			}
 		}
 	},
 
-	make_deduction_via_additional_salary: function(frm){
+	make_deduction_via_additional_salary: function(frm) {
 		frappe.call({
 			method: "erpnext.hr.doctype.employee_advance.employee_advance.create_return_through_additional_salary",
 			args: {
 				doc: frm.doc
 			},
-			callback: function (r){
+			callback: function(r) {
 				var doclist = frappe.model.sync(r.message);
 				frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
 			}
@@ -94,7 +95,7 @@
 
 	make_payment_entry: function(frm) {
 		var method = "erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry";
-		if(frm.doc.__onload && frm.doc.__onload.make_payment_via_journal_entry) {
+		if (frm.doc.__onload && frm.doc.__onload.make_payment_via_journal_entry) {
 			method = "erpnext.hr.doctype.employee_advance.employee_advance.make_bank_entry";
 		}
 		return frappe.call({
@@ -148,11 +149,11 @@
 		});
 	},
 
-	employee: function (frm) {
+	employee: function(frm) {
 		if (frm.doc.employee) {
 			frappe.run_serially([
-				() => 	frm.trigger('get_employee_currency'),
-				() => 	frm.trigger('get_pending_amount')
+				() => frm.trigger('get_employee_currency'),
+				() => frm.trigger('get_pending_amount')
 			]);
 		}
 	},
@@ -199,7 +200,7 @@
 			} else {
 				frm.set_value("exchange_rate", 1.0);
 				frm.set_df_property('exchange_rate', 'hidden', 1);
-				frm.set_df_property("exchange_rate", "description", "" );
+				frm.set_df_property("exchange_rate", "description", "");
 			}
 			frm.refresh_fields();
 		}
@@ -215,8 +216,8 @@
 			callback: function(r) {
 				frm.set_value("exchange_rate", flt(r.message));
 				frm.set_df_property('exchange_rate', 'hidden', 0);
-				frm.set_df_property("exchange_rate", "description", "1 " + frm.doc.currency
-					+ " = [?] " + company_currency);
+				frm.set_df_property("exchange_rate", "description", "1 " + frm.doc.currency +
+					" = [?] " + company_currency);
 			}
 		});
 	}
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance_dashboard.py b/erpnext/hr/doctype/employee_advance/employee_advance_dashboard.py
index c3b4a3a..2f493e2 100644
--- a/erpnext/hr/doctype/employee_advance/employee_advance_dashboard.py
+++ b/erpnext/hr/doctype/employee_advance/employee_advance_dashboard.py
@@ -4,10 +4,10 @@
 def get_data():
 	return {
 		'fieldname': 'employee_advance',
-        'non_standard_fieldnames': {
-            'Payment Entry': 'reference_name',
-            'Journal Entry': 'reference_name'
-        },
+		'non_standard_fieldnames': {
+			'Payment Entry': 'reference_name',
+			'Journal Entry': 'reference_name'
+		},
 		'transactions': [
 			{
 				'items': ['Expense Claim']
diff --git a/erpnext/hr/doctype/employee_referral/__init__.py b/erpnext/hr/doctype/employee_referral/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/hr/doctype/employee_referral/__init__.py
diff --git a/erpnext/hr/doctype/employee_referral/employee_referral.js b/erpnext/hr/doctype/employee_referral/employee_referral.js
new file mode 100644
index 0000000..9c99bbb
--- /dev/null
+++ b/erpnext/hr/doctype/employee_referral/employee_referral.js
@@ -0,0 +1,68 @@
+// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on("Employee Referral", {
+	refresh: function(frm) {
+		if (frm.doc.docstatus === 1 && frm.doc.status === "Pending") {
+			frm.add_custom_button(__("Reject Employee Referral"), function() {
+				frappe.confirm(
+					__("Are you sure you want to reject the Employee Referral?"),
+					function() {
+						frm.doc.status = "Rejected";
+						frm.dirty();
+						frm.save_or_update();
+					},
+					function() {
+						window.close();
+					}
+				);
+			});
+
+			frm.add_custom_button(__("Create Job Applicant"), function() {
+				frm.events.create_job_applicant(frm);
+			}).addClass("btn-primary");
+		}
+
+		// To check whether Payment is done or not
+		if (frm.doc.docstatus === 1 && frm.doc.status === "Accepted") {
+			frappe.db.get_list("Additional Salary", {
+				filters: {
+					ref_docname: cur_frm.doc.name,
+					docstatus: 1
+				},
+				fields: ["count(name) as additional_salary_count"]
+			}).then((data) => {
+
+				let additional_salary_count = data[0].additional_salary_count;
+
+				if (frm.doc.is_applicable_for_referral_bonus && !additional_salary_count) {
+					frm.add_custom_button(__("Create Additional Salary"), function() {
+						frm.events.create_additional_salary(frm);
+					}).addClass("btn-primary");
+				}
+			});
+		}
+
+
+
+	},
+	create_job_applicant: function(frm) {
+		frappe.model.open_mapped_doc({
+			method: "erpnext.hr.doctype.employee_referral.employee_referral.create_job_applicant",
+			frm: frm
+		});
+	},
+
+	create_additional_salary: function(frm) {
+		frappe.call({
+			method: "erpnext.hr.doctype.employee_referral.employee_referral.create_additional_salary",
+			args: {
+				doc: frm.doc
+			},
+			callback: function (r) {
+				var doclist = frappe.model.sync(r.message);
+				frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
+			}
+		});
+	},
+});
diff --git a/erpnext/hr/doctype/employee_referral/employee_referral.json b/erpnext/hr/doctype/employee_referral/employee_referral.json
new file mode 100644
index 0000000..bfd404b
--- /dev/null
+++ b/erpnext/hr/doctype/employee_referral/employee_referral.json
@@ -0,0 +1,294 @@
+{
+ "actions": [],
+ "autoname": "format:HR-REF-{####}",
+ "creation": "2021-03-23 14:54:45.047051",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "first_name",
+  "last_name",
+  "full_name",
+  "email",
+  "contact_no",
+  "resume",
+  "resume_link",
+  "column_break_6",
+  "date",
+  "status",
+  "for_designation",
+  "current_employer",
+  "current_job_title",
+  "referrer_details_section",
+  "referrer",
+  "referrer_name",
+  "column_break_14",
+  "is_applicable_for_referral_bonus",
+  "referral_payment_status",
+  "department",
+  "additional_information_section",
+  "qualification_reason",
+  "work_references",
+  "amended_from"
+ ],
+ "fields": [
+  {
+   "fieldname": "first_name",
+   "fieldtype": "Data",
+   "label": "First Name ",
+   "reqd": 1
+  },
+  {
+   "fieldname": "last_name",
+   "fieldtype": "Data",
+   "label": "Last Name",
+   "reqd": 1
+  },
+  {
+   "fieldname": "full_name",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Full Name",
+   "read_only": 1
+  },
+  {
+   "fieldname": "contact_no",
+   "fieldtype": "Data",
+   "in_standard_filter": 1,
+   "label": "Contact No.",
+   "options": "Phone"
+  },
+  {
+   "fieldname": "current_employer",
+   "fieldtype": "Data",
+   "label": "Current Employer "
+  },
+  {
+   "fieldname": "column_break_6",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "date",
+   "fieldtype": "Date",
+   "in_standard_filter": 1,
+   "label": "Date",
+   "reqd": 1
+  },
+  {
+   "allow_on_submit": 1,
+   "fieldname": "status",
+   "fieldtype": "Select",
+   "in_standard_filter": 1,
+   "label": "Status",
+   "no_copy": 1,
+   "options": "Pending\nIn Process\nAccepted\nRejected",
+   "permlevel": 1,
+   "read_only": 1,
+   "reqd": 1
+  },
+  {
+   "fieldname": "current_job_title",
+   "fieldtype": "Data",
+   "label": "Current Job Title"
+  },
+  {
+   "fieldname": "resume",
+   "fieldtype": "Attach",
+   "label": "Resume"
+  },
+  {
+   "fieldname": "referrer_details_section",
+   "fieldtype": "Section Break",
+   "label": "Referrer Details"
+  },
+  {
+   "fetch_from": "employee.department",
+   "fieldname": "department",
+   "fieldtype": "Link",
+   "label": "Department",
+   "options": "Department",
+   "read_only": 1
+  },
+  {
+   "fieldname": "additional_information_section",
+   "fieldtype": "Section Break",
+   "label": "Additional Information "
+  },
+  {
+   "fieldname": "work_references",
+   "fieldtype": "Text Editor",
+   "label": "Work References"
+  },
+  {
+   "fieldname": "amended_from",
+   "fieldtype": "Link",
+   "label": "Amended From",
+   "no_copy": 1,
+   "options": "Employee Referral",
+   "print_hide": 1,
+   "read_only": 1
+  },
+  {
+   "fieldname": "column_break_14",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "for_designation",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "in_standard_filter": 1,
+   "label": "For Designation ",
+   "options": "Designation",
+   "reqd": 1
+  },
+  {
+   "fieldname": "email",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "in_standard_filter": 1,
+   "label": "Email",
+   "options": "Email",
+   "reqd": 1,
+   "unique": 1
+  },
+  {
+   "default": "1",
+   "fieldname": "is_applicable_for_referral_bonus",
+   "fieldtype": "Check",
+   "label": "Is Applicable for Referral Bonus"
+  },
+  {
+   "fieldname": "qualification_reason",
+   "fieldtype": "Text Editor",
+   "label": "Why is this Candidate Qualified for this Position?"
+  },
+  {
+   "fieldname": "referrer",
+   "fieldtype": "Link",
+   "in_standard_filter": 1,
+   "label": "Referrer",
+   "options": "Employee",
+   "reqd": 1
+  },
+  {
+   "fetch_from": "referrer.employee_name",
+   "fieldname": "referrer_name",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Referrer Name",
+   "read_only": 1
+  },
+  {
+   "fieldname": "resume_link",
+   "fieldtype": "Data",
+   "label": "Resume Link"
+  },
+  {
+   "fieldname": "referral_payment_status",
+   "fieldtype": "Select",
+   "label": "Referral Bonus Payment Status",
+   "options": "\nUnpaid\nPaid",
+   "read_only": 1
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2021-04-26 21:21:38.094086",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Employee Referral",
+ "owner": "Administrator",
+ "permissions": [
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "amend": 1,
+   "create": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Employee",
+   "share": 1,
+   "submit": 1,
+   "write": 1
+  },
+  {
+   "amend": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "HR Manager",
+   "share": 1,
+   "submit": 1,
+   "write": 1
+  },
+  {
+   "amend": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "HR User",
+   "share": 1,
+   "submit": 1,
+   "write": 1
+  },
+  {
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "permlevel": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "HR Manager",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "permlevel": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "HR User",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "email": 1,
+   "export": 1,
+   "permlevel": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Employee",
+   "share": 1
+  }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "full_name"
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_referral/employee_referral.py b/erpnext/hr/doctype/employee_referral/employee_referral.py
new file mode 100644
index 0000000..45d6872
--- /dev/null
+++ b/erpnext/hr/doctype/employee_referral/employee_referral.py
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+from frappe.utils import get_link_to_form
+from frappe.model.document import Document
+
+class EmployeeReferral(Document):
+	def validate(self):
+		self.set_full_name()
+		self.set_referral_bonus_payment_status()
+
+	def set_full_name(self):
+		self.full_name = " ".join(filter(None, [self.first_name, self.last_name]))
+
+	def set_referral_bonus_payment_status(self):
+		if not self.is_applicable_for_referral_bonus:
+			self.referral_payment_status = ""
+		else:
+			if not self.referral_payment_status:
+				self.referral_payment_status = "Unpaid"
+
+
+@frappe.whitelist()
+def create_job_applicant(source_name, target_doc=None):
+	emp_ref = frappe.get_doc("Employee Referral", source_name)
+	#just for Api call if some set status apart from default Status
+	status = emp_ref.status
+	if emp_ref.status in ["Pending", "In process"]:
+		status = "Open"
+
+	job_applicant = frappe.new_doc("Job Applicant")
+	job_applicant.employee_referral = emp_ref.name
+	job_applicant.status = status
+	job_applicant.applicant_name = emp_ref.full_name
+	job_applicant.email_id = emp_ref.email
+	job_applicant.phone_number = emp_ref.contact_no
+	job_applicant.resume_attachment = emp_ref.resume
+	job_applicant.resume_link = emp_ref.resume_link
+	job_applicant.save()
+
+	frappe.msgprint(_("Job Applicant {0} created successfully.").format(
+		get_link_to_form("Job Applicant", job_applicant.name)),
+		title=_("Success"), indicator="green")
+
+	emp_ref.db_set("status", "In Process")
+
+	return job_applicant
+
+
+@frappe.whitelist()
+def create_additional_salary(doc):
+	import json
+	from six import string_types
+
+	if isinstance(doc, string_types):
+		doc = frappe._dict(json.loads(doc))
+
+	if not frappe.db.exists("Additional Salary", {"ref_docname": doc.name}):
+		additional_salary = frappe.new_doc("Additional Salary")
+		additional_salary.employee = doc.referrer
+		additional_salary.company = frappe.db.get_value("Employee", doc.referrer, "company")
+		additional_salary.overwrite_salary_structure_amount = 0
+		additional_salary.ref_doctype = doc.doctype
+		additional_salary.ref_docname = doc.name
+
+	return additional_salary
+
diff --git a/erpnext/hr/doctype/employee_referral/employee_referral_dashboard.py b/erpnext/hr/doctype/employee_referral/employee_referral_dashboard.py
new file mode 100644
index 0000000..afa2a1f
--- /dev/null
+++ b/erpnext/hr/doctype/employee_referral/employee_referral_dashboard.py
@@ -0,0 +1,15 @@
+from __future__ import unicode_literals
+
+def get_data():
+	return {
+		'fieldname': 'employee_referral',
+		'non_standard_fieldnames': {
+			'Additional Salary': 'ref_docname'
+		},
+		'transactions': [
+			{
+				'items': ['Job Applicant', 'Additional Salary']
+			},
+
+		]
+	}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_referral/employee_referral_list.js b/erpnext/hr/doctype/employee_referral/employee_referral_list.js
new file mode 100644
index 0000000..7533ab6
--- /dev/null
+++ b/erpnext/hr/doctype/employee_referral/employee_referral_list.js
@@ -0,0 +1,14 @@
+frappe.listview_settings['Employee Referral'] = {
+	add_fields: ["status"],
+	get_indicator: function (doc) {
+		if (doc.status == "Pending") {
+			return [__(doc.status), "grey", "status,=," + doc.status];
+		} else if (doc.status == "In Process") {
+			return [__(doc.status), "orange", "status,=," + doc.status];
+		} else if (doc.status == "Accepted") {
+			return [__(doc.status), "green", "status,=," + doc.status];
+		} else if (doc.status == "Rejected") {
+			return [__(doc.status), "red", "status,=," + doc.status];
+		}
+	},
+};
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_referral/test_employee_referral.py b/erpnext/hr/doctype/employee_referral/test_employee_referral.py
new file mode 100644
index 0000000..a674f39
--- /dev/null
+++ b/erpnext/hr/doctype/employee_referral/test_employee_referral.py
@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import frappe
+from frappe.utils import today
+from erpnext.hr.doctype.designation.test_designation import create_designation
+from erpnext.hr.doctype.employee_referral.employee_referral import create_job_applicant, create_additional_salary
+from erpnext.hr.doctype.employee.test_employee import make_employee
+import unittest
+
+class TestEmployeeReferral(unittest.TestCase):
+	def test_workflow_and_status_sync(self):
+		emp_ref = create_employee_referral()
+
+		#Check Initial status
+		self.assertTrue(emp_ref.status, "Pending")
+
+		job_applicant = create_job_applicant(emp_ref.name)
+
+
+		#Check status sync
+		emp_ref.reload()
+		self.assertTrue(emp_ref.status, "In Process")
+
+		job_applicant.reload()
+		job_applicant.status = "Rejected"
+		job_applicant.save()
+
+		emp_ref.reload()
+		self.assertTrue(emp_ref.status, "Rejected")
+
+		job_applicant.reload()
+		job_applicant.status = "Accepted"
+		job_applicant.save()
+
+		emp_ref.reload()
+		self.assertTrue(emp_ref.status, "Accepted")
+
+
+		# Check for Referral reference in additional salary
+
+		add_sal = create_additional_salary(emp_ref)
+		self.assertTrue(add_sal.ref_docname, emp_ref.name)
+
+
+def create_employee_referral():
+	emp_ref = frappe.new_doc("Employee Referral")
+	emp_ref.first_name = "Mahesh"
+	emp_ref.last_name = "Singh"
+	emp_ref.email = "a@b.c"
+	emp_ref.date = today()
+	emp_ref.for_designation = create_designation().name
+	emp_ref.referrer = make_employee("testassetmovemp@example.com", company="_Test Company")
+	emp_ref.is_applicable_for_employee_referral_compensation = 1
+	emp_ref.save()
+	emp_ref.submit()
+
+	return emp_ref
\ No newline at end of file
diff --git a/erpnext/hr/doctype/job_applicant/job_applicant.json b/erpnext/hr/doctype/job_applicant/job_applicant.json
index 1360fd1..bcea5f5 100644
--- a/erpnext/hr/doctype/job_applicant/job_applicant.json
+++ b/erpnext/hr/doctype/job_applicant/job_applicant.json
@@ -18,6 +18,7 @@
   "job_title",
   "source",
   "source_name",
+  "employee_referral",
   "applicant_rating",
   "section_break_6",
   "notes",
@@ -152,13 +153,20 @@
    "fieldtype": "Link",
    "label": "Currency",
    "options": "Currency"
+  },
+  {
+   "fieldname": "employee_referral",
+   "fieldtype": "Link",
+   "label": "Employee Referral",
+   "options": "Employee Referral",
+   "read_only": 1
   }
  ],
  "icon": "fa fa-user",
  "idx": 1,
  "index_web_pages_for_search": 1,
  "links": [],
- "modified": "2020-09-18 12:39:02.557563",
+ "modified": "2021-03-24 15:51:11.117517",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Job Applicant",
diff --git a/erpnext/hr/doctype/job_applicant/job_applicant.py b/erpnext/hr/doctype/job_applicant/job_applicant.py
index a6aef04..0594ba3 100644
--- a/erpnext/hr/doctype/job_applicant/job_applicant.py
+++ b/erpnext/hr/doctype/job_applicant/job_applicant.py
@@ -28,10 +28,21 @@
 		if self.email_id:
 			validate_email_address(self.email_id, True)
 
+		if self.employee_referral:
+			self.set_status_for_employee_referral()
+
 		if not self.applicant_name and self.email_id:
 			guess = self.email_id.split('@')[0]
 			self.applicant_name = ' '.join([p.capitalize() for p in guess.split('.')])
 
+	def set_status_for_employee_referral(self):
+		emp_ref = frappe.get_doc("Employee Referral", self.employee_referral)
+		if self.status in ["Open", "Replied", "Hold"]:
+			emp_ref.db_set("status", "In Process")
+		elif self.status in ["Accepted", "Rejected"]:
+			emp_ref.db_set("status", self.status)
+
+
 	def check_email_id_is_unique(self):
 		if self.email_id:
 			names = frappe.db.sql_list("""select name from `tabJob Applicant`
diff --git a/erpnext/hr/workspace/hr/hr.json b/erpnext/hr/workspace/hr/hr.json
index f4b56a0..c5201c2 100644
--- a/erpnext/hr/workspace/hr/hr.json
+++ b/erpnext/hr/workspace/hr/hr.json
@@ -521,6 +521,15 @@
    "type": "Link"
   },
   {
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Employee Referral",
+   "link_to": "Employee Referral",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
    "dependencies": "",
    "hidden": 0,
    "is_query_report": 0,
@@ -814,7 +823,7 @@
    "type": "Link"
   }
  ],
- "modified": "2021-03-24 17:35:21.483297",
+ "modified": "2021-04-26 13:36:15.413819",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "HR",
diff --git a/erpnext/payroll/doctype/additional_salary/additional_salary.py b/erpnext/payroll/doctype/additional_salary/additional_salary.py
index 13b6c05..ebeddf9 100644
--- a/erpnext/payroll/doctype/additional_salary/additional_salary.py
+++ b/erpnext/payroll/doctype/additional_salary/additional_salary.py
@@ -13,12 +13,19 @@
 		if self.ref_doctype == "Employee Advance" and self.ref_docname:
 			frappe.db.set_value("Employee Advance", self.ref_docname, "return_amount", self.amount)
 
+		self.update_employee_referral()
+
+	def on_cancel(self):
+		self.update_employee_referral(cancel=True)
+
 	def validate(self):
 		self.validate_dates()
 		self.validate_salary_structure()
 		self.validate_recurring_additional_salary_overlap()
+		self.validate_employee_referral()
+
 		if self.amount < 0:
-			frappe.throw(_("Amount should not be less than zero."))
+			frappe.throw(_("Amount should not be less than zero"))
 
 	def validate_salary_structure(self):
 		if not frappe.db.exists('Salary Structure Assignment', {'employee': self.employee}):
@@ -70,6 +77,27 @@
 			if self.payroll_date and getdate(self.payroll_date) > getdate(relieving_date):
 				frappe.throw(_("Payroll date can not be greater than employee's relieving date."))
 
+	def validate_employee_referral(self):
+		if self.ref_doctype == "Employee Referral":
+			referral_details = frappe.db.get_value("Employee Referral", self.ref_docname,
+				["is_applicable_for_referral_bonus", "status"], as_dict=1)
+
+			if not referral_details.is_applicable_for_referral_bonus:
+				frappe.throw(_("Employee Referral {0} is not applicable for referral bonus.").format(
+					self.ref_docname))
+
+			if self.type == "Deduction":
+				frappe.throw(_("Earning Salary Component is required for Employee Referral Bonus."))
+
+			if referral_details.status != "Accepted":
+				frappe.throw(_("Additional Salary for referral bonus can only be created against Employee Referral with status {0}").format(
+					frappe.bold("Accepted")))
+
+	def update_employee_referral(self, cancel=False):
+		if self.ref_doctype == "Employee Referral":
+			status = "Unpaid" if cancel else "Paid"
+			frappe.db.set_value("Employee Referral", self.ref_docname, "referral_payment_status", status)
+
 	def get_amount(self, sal_start_date, sal_end_date):
 		start_date = getdate(sal_start_date)
 		end_date = getdate(sal_end_date)
@@ -110,8 +138,7 @@
 	for d in additional_salary_list:
 		if d.overwrite:
 			if d.component in components_to_overwrite:
-				frappe.throw(_("Multiple Additional Salaries with overwrite "
-					"property exist for Salary Component {0} between {1} and {2}.").format(
+				frappe.throw(_("Multiple Additional Salaries with overwrite property exist for Salary Component {0} between {1} and {2}.").format(
 					frappe.bold(d.component), start_date, end_date), title=_("Error"))
 
 			components_to_overwrite.append(d.component)
diff --git a/erpnext/payroll/doctype/salary_structure/salary_structure.js b/erpnext/payroll/doctype/salary_structure/salary_structure.js
index e00bd87..d5c20dc 100755
--- a/erpnext/payroll/doctype/salary_structure/salary_structure.js
+++ b/erpnext/payroll/doctype/salary_structure/salary_structure.js
@@ -16,11 +16,11 @@
 	onload: function(frm) {
 
 		let help_button = $(`<a class = 'control-label'>
-			Condition and Formula Help
+			${__("Condition and Formula Help")}
 		</a>`).click(()=>{
 
 			let d = new frappe.ui.Dialog({
-				title: 'Condition and Formula Help',
+				title: __('Condition and Formula Help'),
 				fields: [
 					{
 						fieldname: 'msg_wrapper',
diff --git a/erpnext/projects/report/project_summary/project_summary.py b/erpnext/projects/report/project_summary/project_summary.py
index ea7f1ab..2c7bb49 100644
--- a/erpnext/projects/report/project_summary/project_summary.py
+++ b/erpnext/projects/report/project_summary/project_summary.py
@@ -131,25 +131,25 @@
 		{
 			"value": avg_completion,
 			"indicator": "Green" if avg_completion > 50 else "Red",
-			"label": "Average Completion",
+			"label": _("Average Completion"),
 			"datatype": "Percent",
 		},
 		{
 			"value": total,
 			"indicator": "Blue",
-			"label": "Total Tasks",
+			"label": _("Total Tasks"),
 			"datatype": "Int",
 		},
 		{
 			"value": completed,
 			"indicator": "Green",
-			"label": "Completed Tasks",
+			"label": _("Completed Tasks"),
 			"datatype": "Int",
 		},
 		{
 			"value": total_overdue,
 			"indicator": "Green" if total_overdue == 0 else "Red",
-			"label": "Overdue Tasks",
+			"label": _("Overdue Tasks"),
 			"datatype": "Int",
 		}
 	]
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 062cba1..750a1a6 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.py
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.py
@@ -23,7 +23,7 @@
 
 	if search_value:
 		data = search_serial_or_batch_or_barcode_number(search_value)
-	
+
 	item_code = data.get("item_code") if data.get("item_code") else search_value
 	serial_no = data.get("serial_no") if data.get("serial_no") else ""
 	batch_no = data.get("batch_no") if data.get("batch_no") else ""
@@ -31,7 +31,7 @@
 
 	if data:
 		item_info = frappe.db.get_value(
-			"Item", data.get("item_code"), 
+			"Item", data.get("item_code"),
 			["name as item_code", "item_name", "description", "stock_uom", "image as item_image", "is_stock_item"]
 		, as_dict=1)
 		item_info.setdefault('serial_no', serial_no)
@@ -139,8 +139,24 @@
 	if serial_no or batch_no or barcode:
 		return "item.name = {0}".format(frappe.db.escape(item_code))
 
-	return """(item.name like {item_code}
-		or item.item_name like {item_code})""".format(item_code = frappe.db.escape('%' + item_code + '%'))
+	return make_condition(item_code)
+
+def make_condition(item_code):
+	condition = "("
+	condition += """item.name like {item_code}
+		or item.item_name like {item_code}""".format(item_code = frappe.db.escape('%' + item_code + '%'))
+	condition += add_search_fields_condition(item_code)
+	condition += ")"
+
+	return condition
+
+def add_search_fields_condition(item_code):
+	condition = ''
+	search_fields = frappe.get_all('POS Search Fields', fields = ['fieldname'])
+	if search_fields:
+		for field in search_fields:
+			condition += " or item.{0} like {1}".format(field['fieldname'], frappe.db.escape('%' + item_code + '%'))
+	return condition
 
 def get_item_group_condition(pos_profile):
 	cond = "and 1=1"
@@ -257,4 +273,4 @@
 	elif fieldname == 'mobile_no':
 		contact_doc.set('phone_nos', [{ 'phone': value, 'is_primary_mobile_no': 1}])
 		frappe.db.set_value('Customer', customer, 'mobile_no', value)
-	contact_doc.save()
\ No newline at end of file
+	contact_doc.save()
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index 2079cf8..8aec893 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -46,9 +46,6 @@
 			}, __("View"));
 		}
 
-		if (!frm.doc.is_fixed_asset) {
-			erpnext.item.make_dashboard(frm);
-		}
 
 		if (frm.doc.is_fixed_asset) {
 			frm.trigger('is_fixed_asset');
@@ -96,6 +93,10 @@
 
 		erpnext.item.edit_prices_button(frm);
 		erpnext.item.toggle_attributes(frm);
+		
+		if (!frm.doc.is_fixed_asset) {
+			erpnext.item.make_dashboard(frm);
+		}
 
 		frm.add_custom_button(__('Duplicate'), function() {
 			var new_item = frappe.model.copy_doc(frm.doc);
@@ -473,11 +474,15 @@
 								me.multiple_variant_dialog.get_primary_btn().html(__('Create Variants'));
 								me.multiple_variant_dialog.disable_primary_action();
 							} else {
+
 								let no_of_combinations = lengths.reduce((a, b) => a * b, 1);
-								me.multiple_variant_dialog.get_primary_btn()
-									.html(__(
-										`Make ${no_of_combinations} Variant${no_of_combinations === 1 ? '' : 's'}`
-									));
+								let msg;
+								if (no_of_combinations === 1) {
+									msg = __("Make {0} Variant", [no_of_combinations]);
+								} else {
+									msg = __("Make {0} Variants", [no_of_combinations]);
+								}
+								me.multiple_variant_dialog.get_primary_btn().html(msg);
 								me.multiple_variant_dialog.enable_primary_action();
 							}
 						}
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
index 4d1a514..befdad9 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -73,6 +73,34 @@
 				})
 			}, __('Create'));
 		}
+
+		frm.events.add_custom_buttons(frm);
+	},
+
+	add_custom_buttons: function(frm) {
+		if (frm.doc.docstatus == 0) {
+			frm.add_custom_button(__('Purchase Invoice'), function () {
+				if (!frm.doc.supplier) {
+					frappe.throw({
+						title: __("Mandatory"),
+						message: __("Please Select a Supplier")
+					});
+				}
+				erpnext.utils.map_current_doc({
+					method: "erpnext.accounts.doctype.purchase_invoice.purchase_invoice.make_purchase_receipt",
+					source_doctype: "Purchase Invoice",
+					target: frm,
+					setters: {
+						supplier: frm.doc.supplier,
+					},
+					get_query_filters: {
+						docstatus: 1,
+						per_received: ["<", 100],
+						company: frm.doc.company
+					}
+				})
+			}, __("Get Items From"));
+		}
 	},
 
 	company: function(frm) {
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index d8d8310..61e60f3 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -53,7 +53,20 @@
 			'target_ref_field': 'stock_qty',
 			'source_field': 'stock_qty',
 			'percent_join_field': 'material_request'
+		},
+		{
+			'source_dt': 'Purchase Receipt Item',
+			'target_dt': 'Purchase Invoice Item',
+			'join_field': 'purchase_invoice_item',
+			'target_field': 'received_qty',
+			'target_parent_dt': 'Purchase Invoice',
+			'target_parent_field': 'per_received',
+			'target_ref_field': 'qty',
+			'source_field': 'received_qty',
+			'percent_join_field': 'purchase_invoice',
+			'overflow_type': 'receipt'
 		}]
+
 		if cint(self.is_return):
 			self.status_updater.extend([
 				{
@@ -514,7 +527,9 @@
 	def update_billing_status(self, update_modified=True):
 		updated_pr = [self.name]
 		for d in self.get("items"):
-			if d.purchase_order_item:
+			if d.purchase_invoice and d.purchase_invoice_item:
+				d.db_set('billed_amt', d.amount, update_modified=update_modified)
+			elif d.purchase_order_item:
 				updated_pr += update_billed_amount_based_on_po(d.purchase_order_item, update_modified)
 
 		for pr in set(updated_pr):
diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
index efe3642..82cc98e 100644
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
@@ -72,16 +72,18 @@
   "warehouse",
   "rejected_warehouse",
   "from_warehouse",
-  "purchase_order",
   "material_request",
+  "purchase_order",
+  "purchase_invoice",
   "column_break_40",
   "is_fixed_asset",
   "asset_location",
   "asset_category",
   "schedule_date",
   "quality_inspection",
-  "purchase_order_item",
   "material_request_item",
+  "purchase_order_item",
+  "purchase_invoice_item",
   "purchase_receipt_item",
   "delivery_note_item",
   "putaway_rule",
@@ -937,7 +939,21 @@
    "fieldname": "base_rate_with_margin",
    "fieldtype": "Currency",
    "label": "Rate With Margin (Company Currency)",
-   "options": "Company:company:default_currency",
+   "options": "Company:company:default_currency"
+  },
+  {
+   "fieldname": "purchase_invoice",
+   "fieldtype": "Link",
+   "label": "Purchase Invoice",
+   "options": "Purchase Invoice",
+   "read_only": 1
+  },
+  {
+   "fieldname": "purchase_invoice_item",
+   "fieldtype": "Data",
+   "hidden": 1,
+   "label": "Purchase Invoice Item",
+   "no_copy": 1,
    "print_hide": 1,
    "read_only": 1
   }
@@ -945,7 +961,7 @@
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2021-02-23 00:59:14.360847",
+ "modified": "2021-03-29 04:17:00.336298",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Purchase Receipt Item",
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 985901f..bbfcb7a 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -416,7 +416,7 @@
 		frappe.db.set_value("Stock Entry Detail", sle.voucher_detail_no, "basic_rate", outgoing_rate)
 
 		# Update outgoing item's rate, recalculate FG Item's rate and total incoming/outgoing amount
-		stock_entry = frappe.get_doc("Stock Entry", sle.voucher_no)
+		stock_entry = frappe.get_doc("Stock Entry", sle.voucher_no, for_update=True)
 		stock_entry.calculate_rate_and_amount(reset_outgoing_rate=False, raise_error_if_no_rate=False)
 		stock_entry.db_update()
 		for d in stock_entry.items:
diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py
index 0af3d90..034d3eb 100644
--- a/erpnext/stock/utils.py
+++ b/erpnext/stock/utils.py
@@ -172,7 +172,7 @@
 		bin_obj.flags.ignore_permissions = 1
 		bin_obj.insert()
 	else:
-		bin_obj = frappe.get_cached_doc('Bin', bin)
+		bin_obj = frappe.get_doc('Bin', bin, for_update=True)
 	bin_obj.flags.ignore_permissions = True
 	return bin_obj
 
diff --git a/requirements.txt b/requirements.txt
index 377fd7d..f1ffeb8 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,4 @@
-frappe
+# frappe   # https://github.com/frappe/frappe is installed during bench-init
 gocardless-pro~=1.22.0
 googlemaps  # used in ERPNext, but dependency is defined in Frappe
 pandas~=1.1.5