Merge branch 'develop' of https://github.com/frappe/erpnext into asset_purchase_receipt_gl
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index ae54b80..4b2c922 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -73,11 +73,6 @@
 					gl_entries = self.get_gl_entries(warehouse_account)
 				make_gl_entries(gl_entries, from_repost=from_repost)
 
-		elif self.doctype in ["Purchase Receipt", "Purchase Invoice"] and self.docstatus == 1:
-			gl_entries = []
-			gl_entries = self.get_asset_gl_entry(gl_entries)
-			make_gl_entries(gl_entries, from_repost=from_repost)
-
 	def validate_serialized_batch(self):
 		from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
 
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index de0db1a..c2c4d0f 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -144,8 +144,8 @@
 			if item.is_fixed_asset and is_cwip_accounting_enabled(item.asset_category):
 				# check cwip accounts before making auto assets
 				# Improves UX by not giving messages of "Assets Created" before throwing error of not finding arbnb account
-				arbnb_account = self.get_company_default("asset_received_but_not_billed")
-				cwip_account = get_asset_account(
+				self.get_company_default("asset_received_but_not_billed")
+				get_asset_account(
 					"capital_work_in_progress_account", asset_category=item.asset_category, company=self.company
 				)
 				break
@@ -313,7 +313,6 @@
 
 		self.make_item_gl_entries(gl_entries, warehouse_account=warehouse_account)
 		self.make_tax_gl_entries(gl_entries)
-		self.get_asset_gl_entry(gl_entries)
 
 		return process_gl_map(gl_entries)
 
@@ -322,11 +321,19 @@
 			get_purchase_document_details,
 		)
 
-		stock_rbnb = None
+		is_asset_pr = any(d.is_fixed_asset for d in self.get("items"))
+		stock_asset_rbnb = None
+		remarks = self.get("remarks") or _("Accounting Entry for {0}").format(
+			"Asset" if is_asset_pr else "Stock"
+		)
+
 		if erpnext.is_perpetual_inventory_enabled(self.company):
-			stock_rbnb = self.get_company_default("stock_received_but_not_billed")
+			stock_asset_rbnb = (
+				self.get_company_default("asset_received_but_not_billed")
+				if is_asset_pr
+				else self.get_company_default("stock_received_but_not_billed")
+			)
 			landed_cost_entries = get_item_account_wise_additional_cost(self.name)
-			expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
 
 		warehouse_with_no_account = []
 		stock_items = self.get_stock_items()
@@ -338,236 +345,195 @@
 
 		exchange_rate_map, net_rate_map = get_purchase_document_details(self)
 
-		for d in self.get("items"):
-			if d.item_code in stock_items and flt(d.qty) and (flt(d.valuation_rate) or self.is_return):
-				if warehouse_account.get(d.warehouse):
-					stock_value_diff = frappe.db.get_value(
-						"Stock Ledger Entry",
-						{
-							"voucher_type": "Purchase Receipt",
-							"voucher_no": self.name,
-							"voucher_detail_no": d.name,
-							"warehouse": d.warehouse,
-							"is_cancelled": 0,
-						},
-						"stock_value_difference",
-					)
+		def make_item_asset_inward_entries(item, stock_value_diff, stock_asset_account_name):
+			account_currency = get_account_currency(stock_asset_account_name)
+			self.add_gl_entry(
+				gl_entries=gl_entries,
+				account=stock_asset_account_name,
+				cost_center=d.cost_center,
+				debit=stock_value_diff,
+				credit=0.0,
+				remarks=remarks,
+				against_account=stock_asset_rbnb,
+				account_currency=account_currency,
+				item=item,
+			)
 
-					warehouse_account_name = warehouse_account[d.warehouse]["account"]
-					warehouse_account_currency = warehouse_account[d.warehouse]["account_currency"]
-					supplier_warehouse_account = warehouse_account.get(self.supplier_warehouse, {}).get("account")
-					supplier_warehouse_account_currency = warehouse_account.get(self.supplier_warehouse, {}).get(
-						"account_currency"
-					)
-					remarks = self.get("remarks") or _("Accounting Entry for Stock")
+		def make_stock_received_but_not_billed_entry(item):
+			account = (
+				warehouse_account[item.from_warehouse]["account"] if item.from_warehouse else stock_asset_rbnb
+			)
+			account_currency = get_account_currency(account)
 
-					# If PR is sub-contracted and fg item rate is zero
-					# in that case if account for source and target warehouse are same,
-					# then GL entries should not be posted
+			outgoing_amount = item.base_net_amount
+			# GL Entry for from warehouse or Stock Received but not billed
+			# Intentionally passed negative debit amount to avoid incorrect GL Entry validation
+			credit_amount = (
+				flt(item.base_net_amount, item.precision("base_net_amount"))
+				if account_currency == self.company_currency
+				else flt(item.net_amount, item.precision("net_amount"))
+			)
+
+			if self.is_internal_transfer() and item.valuation_rate:
+				outgoing_amount = abs(get_stock_value_difference(self.name, item.name, item.from_warehouse))
+				credit_amount = outgoing_amount
+
+			if credit_amount:
+				self.add_gl_entry(
+					gl_entries=gl_entries,
+					account=account,
+					cost_center=item.cost_center,
+					debit=-1 * flt(outgoing_amount, item.precision("base_net_amount")),
+					credit=0.0,
+					remarks=remarks,
+					against_account=stock_asset_account_name,
+					debit_in_account_currency=-1 * credit_amount,
+					account_currency=account_currency,
+					item=item,
+				)
+
+				# check if the exchange rate has changed
+				if d.get("purchase_invoice"):
 					if (
-						flt(stock_value_diff) == flt(d.rm_supp_cost)
-						and warehouse_account.get(self.supplier_warehouse)
-						and warehouse_account_name == supplier_warehouse_account
+						exchange_rate_map[item.purchase_invoice]
+						and self.conversion_rate != exchange_rate_map[item.purchase_invoice]
+						and item.net_rate == net_rate_map[item.purchase_invoice_item]
 					):
-						continue
 
-					self.add_gl_entry(
-						gl_entries=gl_entries,
-						account=warehouse_account_name,
-						cost_center=d.cost_center,
-						debit=stock_value_diff,
-						credit=0.0,
-						remarks=remarks,
-						against_account=stock_rbnb,
-						account_currency=warehouse_account_currency,
-						item=d,
-					)
-
-					# GL Entry for from warehouse or Stock Received but not billed
-					# Intentionally passed negative debit amount to avoid incorrect GL Entry validation
-					credit_currency = (
-						get_account_currency(warehouse_account[d.from_warehouse]["account"])
-						if d.from_warehouse
-						else get_account_currency(stock_rbnb)
-					)
-
-					credit_amount = (
-						flt(d.base_net_amount, d.precision("base_net_amount"))
-						if credit_currency == self.company_currency
-						else flt(d.net_amount, d.precision("net_amount"))
-					)
-
-					outgoing_amount = d.base_net_amount
-					if self.is_internal_transfer() and d.valuation_rate:
-						outgoing_amount = abs(
-							frappe.db.get_value(
-								"Stock Ledger Entry",
-								{
-									"voucher_type": "Purchase Receipt",
-									"voucher_no": self.name,
-									"voucher_detail_no": d.name,
-									"warehouse": d.from_warehouse,
-									"is_cancelled": 0,
-								},
-								"stock_value_difference",
-							)
+						discrepancy_caused_by_exchange_rate_difference = (item.qty * item.net_rate) * (
+							exchange_rate_map[item.purchase_invoice] - self.conversion_rate
 						)
-						credit_amount = outgoing_amount
-
-					if credit_amount:
-						account = warehouse_account[d.from_warehouse]["account"] if d.from_warehouse else stock_rbnb
 
 						self.add_gl_entry(
 							gl_entries=gl_entries,
 							account=account,
-							cost_center=d.cost_center,
-							debit=-1 * flt(outgoing_amount, d.precision("base_net_amount")),
-							credit=0.0,
-							remarks=remarks,
-							against_account=warehouse_account_name,
-							debit_in_account_currency=-1 * credit_amount,
-							account_currency=credit_currency,
-							item=d,
-						)
-
-						# check if the exchange rate has changed
-						if d.get("purchase_invoice"):
-							if (
-								exchange_rate_map[d.purchase_invoice]
-								and self.conversion_rate != exchange_rate_map[d.purchase_invoice]
-								and d.net_rate == net_rate_map[d.purchase_invoice_item]
-							):
-
-								discrepancy_caused_by_exchange_rate_difference = (d.qty * d.net_rate) * (
-									exchange_rate_map[d.purchase_invoice] - self.conversion_rate
-								)
-
-								self.add_gl_entry(
-									gl_entries=gl_entries,
-									account=account,
-									cost_center=d.cost_center,
-									debit=0.0,
-									credit=discrepancy_caused_by_exchange_rate_difference,
-									remarks=remarks,
-									against_account=self.supplier,
-									debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference,
-									account_currency=credit_currency,
-									item=d,
-								)
-
-								self.add_gl_entry(
-									gl_entries=gl_entries,
-									account=self.get_company_default("exchange_gain_loss_account"),
-									cost_center=d.cost_center,
-									debit=discrepancy_caused_by_exchange_rate_difference,
-									credit=0.0,
-									remarks=remarks,
-									against_account=self.supplier,
-									debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference,
-									account_currency=credit_currency,
-									item=d,
-								)
-
-					# Amount added through landed-cos-voucher
-					if d.landed_cost_voucher_amount and landed_cost_entries:
-						if (d.item_code, d.name) in landed_cost_entries:
-							for account, amount in landed_cost_entries[(d.item_code, d.name)].items():
-								account_currency = get_account_currency(account)
-								credit_amount = (
-									flt(amount["base_amount"])
-									if (amount["base_amount"] or account_currency != self.company_currency)
-									else flt(amount["amount"])
-								)
-
-								self.add_gl_entry(
-									gl_entries=gl_entries,
-									account=account,
-									cost_center=d.cost_center,
-									debit=0.0,
-									credit=credit_amount,
-									remarks=remarks,
-									against_account=warehouse_account_name,
-									credit_in_account_currency=flt(amount["amount"]),
-									account_currency=account_currency,
-									project=d.project,
-									item=d,
-								)
-
-					if d.rate_difference_with_purchase_invoice and stock_rbnb:
-						account_currency = get_account_currency(stock_rbnb)
-						self.add_gl_entry(
-							gl_entries=gl_entries,
-							account=stock_rbnb,
-							cost_center=d.cost_center,
+							cost_center=item.cost_center,
 							debit=0.0,
-							credit=flt(d.rate_difference_with_purchase_invoice),
-							remarks=_("Adjustment based on Purchase Invoice rate"),
-							against_account=warehouse_account_name,
+							credit=discrepancy_caused_by_exchange_rate_difference,
+							remarks=remarks,
+							against_account=self.supplier,
+							debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference,
 							account_currency=account_currency,
-							project=d.project,
-							item=d,
+							item=item,
 						)
 
-					# sub-contracting warehouse
-					if flt(d.rm_supp_cost) and warehouse_account.get(self.supplier_warehouse):
 						self.add_gl_entry(
 							gl_entries=gl_entries,
-							account=supplier_warehouse_account,
+							account=self.get_company_default("exchange_gain_loss_account"),
 							cost_center=d.cost_center,
-							debit=0.0,
-							credit=flt(d.rm_supp_cost),
-							remarks=remarks,
-							against_account=warehouse_account_name,
-							account_currency=supplier_warehouse_account_currency,
-							item=d,
-						)
-
-					# divisional loss adjustment
-					valuation_amount_as_per_doc = (
-						flt(outgoing_amount, d.precision("base_net_amount"))
-						+ flt(d.landed_cost_voucher_amount)
-						+ flt(d.rm_supp_cost)
-						+ flt(d.item_tax_amount)
-						+ flt(d.rate_difference_with_purchase_invoice)
-					)
-
-					divisional_loss = flt(
-						valuation_amount_as_per_doc - flt(stock_value_diff), d.precision("base_net_amount")
-					)
-
-					if divisional_loss:
-						if self.is_return or flt(d.item_tax_amount):
-							loss_account = expenses_included_in_valuation
-						else:
-							loss_account = (
-								self.get_company_default("default_expense_account", ignore_validation=True) or stock_rbnb
-							)
-
-						cost_center = d.cost_center or frappe.get_cached_value(
-							"Company", self.company, "cost_center"
-						)
-
-						self.add_gl_entry(
-							gl_entries=gl_entries,
-							account=loss_account,
-							cost_center=cost_center,
-							debit=divisional_loss,
+							debit=discrepancy_caused_by_exchange_rate_difference,
 							credit=0.0,
 							remarks=remarks,
-							against_account=warehouse_account_name,
-							account_currency=credit_currency,
-							project=d.project,
-							item=d,
+							against_account=self.supplier,
+							debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference,
+							account_currency=account_currency,
+							item=item,
 						)
 
-				elif (
-					d.warehouse not in warehouse_with_no_account
-					or d.rejected_warehouse not in warehouse_with_no_account
-				):
-					warehouse_with_no_account.append(d.warehouse)
-			elif (
+		def make_landed_cost_gl_entries(item):
+			# Amount added through landed-cos-voucher
+			if item.landed_cost_voucher_amount and landed_cost_entries:
+				if (item.item_code, item.name) in landed_cost_entries:
+					for account, amount in landed_cost_entries[(item.item_code, item.name)].items():
+						account_currency = get_account_currency(account)
+						credit_amount = (
+							flt(amount["base_amount"])
+							if (amount["base_amount"] or account_currency != self.company_currency)
+							else flt(amount["amount"])
+						)
+
+						self.add_gl_entry(
+							gl_entries=gl_entries,
+							account=account,
+							cost_center=item.cost_center,
+							debit=0.0,
+							credit=credit_amount,
+							remarks=remarks,
+							against_account=stock_asset_account_name,
+							credit_in_account_currency=flt(amount["amount"]),
+							account_currency=account_currency,
+							project=item.project,
+							item=item,
+						)
+
+		def make_rate_difference_entry(item):
+			if item.rate_difference_with_purchase_invoice and stock_asset_rbnb:
+				account_currency = get_account_currency(stock_asset_rbnb)
+				self.add_gl_entry(
+					gl_entries=gl_entries,
+					account=stock_asset_rbnb,
+					cost_center=item.cost_center,
+					debit=0.0,
+					credit=flt(item.rate_difference_with_purchase_invoice),
+					remarks=_("Adjustment based on Purchase Invoice rate"),
+					against_account=stock_asset_account_name,
+					account_currency=account_currency,
+					project=item.project,
+					item=item,
+				)
+
+		def make_sub_contracting_gl_entries(item):
+			# sub-contracting warehouse
+			if flt(item.rm_supp_cost) and warehouse_account.get(self.supplier_warehouse):
+				self.add_gl_entry(
+					gl_entries=gl_entries,
+					account=supplier_warehouse_account,
+					cost_center=item.cost_center,
+					debit=0.0,
+					credit=flt(item.rm_supp_cost),
+					remarks=remarks,
+					against_account=stock_asset_account_name,
+					account_currency=supplier_warehouse_account_currency,
+					item=item,
+				)
+
+		def make_divisional_loss_gl_entry(item):
+			if item.is_fixed_asset:
+				return
+
+			# divisional loss adjustment
+			expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
+			valuation_amount_as_per_doc = (
+				flt(item.base_net_amount, d.precision("base_net_amount"))
+				+ flt(item.landed_cost_voucher_amount)
+				+ flt(item.rm_supp_cost)
+				+ flt(item.item_tax_amount)
+				+ flt(item.rate_difference_with_purchase_invoice)
+			)
+
+			divisional_loss = flt(
+				valuation_amount_as_per_doc - flt(stock_value_diff), item.precision("base_net_amount")
+			)
+
+			if divisional_loss:
+				if self.is_return or flt(item.item_tax_amount):
+					loss_account = expenses_included_in_valuation
+				else:
+					loss_account = (
+						self.get_company_default("default_expense_account", ignore_validation=True)
+						or stock_asset_rbnb
+					)
+
+				cost_center = item.cost_center or frappe.get_cached_value(
+					"Company", self.company, "cost_center"
+				)
+				account_currency = get_account_currency(loss_account)
+				self.add_gl_entry(
+					gl_entries=gl_entries,
+					account=loss_account,
+					cost_center=cost_center,
+					debit=divisional_loss,
+					credit=0.0,
+					remarks=remarks,
+					against_account=stock_asset_account_name,
+					account_currency=account_currency,
+					project=item.project,
+					item=item,
+				)
+
+		for d in self.get("items"):
+			if (
 				d.item_code not in stock_items
-				and not d.is_fixed_asset
 				and flt(d.qty)
 				and provisional_accounting_for_non_stock_items
 				and d.get("provisional_expense_account")
@@ -575,6 +541,57 @@
 				self.add_provisional_gl_entry(
 					d, gl_entries, self.posting_date, d.get("provisional_expense_account")
 				)
+			elif flt(d.qty) and (flt(d.valuation_rate) or self.is_return):
+				if d.is_fixed_asset:
+					stock_asset_account_name = (
+						get_asset_category_account(
+							asset_category=d.asset_category,
+							fieldname="capital_work_in_progress_account",
+							company=self.company,
+						)
+						if is_cwip_accounting_enabled(d.asset_category)
+						else get_asset_category_account(
+							asset_category=d.asset_category, fieldname="fixed_asset_account", company=self.company
+						)
+					)
+
+					stock_value_diff = flt(d.net_amount) + flt(d.item_tax_amount / self.conversion_rate)
+				elif (
+					(flt(d.valuation_rate) or self.is_return)
+					and flt(d.qty)
+					and warehouse_account.get(d.warehouse)
+				):
+					stock_value_diff = get_stock_value_difference(self.name, d.name, d.warehouse)
+					stock_asset_account_name = warehouse_account[d.warehouse]["account"]
+					supplier_warehouse_account = warehouse_account.get(self.supplier_warehouse, {}).get("account")
+					supplier_warehouse_account_currency = warehouse_account.get(self.supplier_warehouse, {}).get(
+						"account_currency"
+					)
+
+					# If PR is sub-contracted and fg item rate is zero
+					# in that case if account for source and target warehouse are same,
+					# then GL entries should not be posted
+					if (
+						flt(stock_value_diff) == flt(d.rm_supp_cost)
+						and warehouse_account.get(self.supplier_warehouse)
+						and stock_asset_account_name == supplier_warehouse_account
+					):
+						continue
+
+				make_item_asset_inward_entries(d, stock_value_diff, stock_asset_account_name)
+				make_stock_received_but_not_billed_entry(d)
+				make_landed_cost_gl_entries(d)
+				make_rate_difference_entry(d)
+				make_sub_contracting_gl_entries(d)
+				make_divisional_loss_gl_entry(d)
+			elif (
+				d.warehouse not in warehouse_with_no_account
+				or d.rejected_warehouse not in warehouse_with_no_account
+			):
+				warehouse_with_no_account.append(d.warehouse)
+
+			if d.is_fixed_asset:
+				self.update_assets(d, d.valuation_rate)
 
 		if warehouse_with_no_account:
 			frappe.msgprint(
@@ -700,103 +717,6 @@
 
 					i += 1
 
-	def get_asset_gl_entry(self, gl_entries):
-		for item in self.get("items"):
-			if item.is_fixed_asset:
-				if is_cwip_accounting_enabled(item.asset_category):
-					self.add_asset_gl_entries(item, gl_entries)
-				if flt(item.landed_cost_voucher_amount):
-					self.add_lcv_gl_entries(item, gl_entries)
-					# update assets gross amount by its valuation rate
-					# valuation rate is total of net rate, raw mat supp cost, tax amount, lcv amount per item
-					self.update_assets(item, item.valuation_rate)
-		return gl_entries
-
-	def add_asset_gl_entries(self, item, gl_entries):
-		arbnb_account = self.get_company_default("asset_received_but_not_billed")
-		# This returns category's cwip account if not then fallback to company's default cwip account
-		cwip_account = get_asset_account(
-			"capital_work_in_progress_account", asset_category=item.asset_category, company=self.company
-		)
-
-		asset_amount = flt(item.net_amount) + flt(item.item_tax_amount / self.conversion_rate)
-		base_asset_amount = flt(item.base_net_amount + item.item_tax_amount)
-		remarks = self.get("remarks") or _("Accounting Entry for Asset")
-
-		cwip_account_currency = get_account_currency(cwip_account)
-		# debit cwip account
-		debit_in_account_currency = (
-			base_asset_amount if cwip_account_currency == self.company_currency else asset_amount
-		)
-
-		self.add_gl_entry(
-			gl_entries=gl_entries,
-			account=cwip_account,
-			cost_center=item.cost_center,
-			debit=base_asset_amount,
-			credit=0.0,
-			remarks=remarks,
-			against_account=arbnb_account,
-			debit_in_account_currency=debit_in_account_currency,
-			item=item,
-		)
-
-		asset_rbnb_currency = get_account_currency(arbnb_account)
-		# credit arbnb account
-		credit_in_account_currency = (
-			base_asset_amount if asset_rbnb_currency == self.company_currency else asset_amount
-		)
-
-		self.add_gl_entry(
-			gl_entries=gl_entries,
-			account=arbnb_account,
-			cost_center=item.cost_center,
-			debit=0.0,
-			credit=base_asset_amount,
-			remarks=remarks,
-			against_account=cwip_account,
-			credit_in_account_currency=credit_in_account_currency,
-			item=item,
-		)
-
-	def add_lcv_gl_entries(self, item, gl_entries):
-		expenses_included_in_asset_valuation = self.get_company_default(
-			"expenses_included_in_asset_valuation"
-		)
-		if not is_cwip_accounting_enabled(item.asset_category):
-			asset_account = get_asset_category_account(
-				asset_category=item.asset_category, fieldname="fixed_asset_account", company=self.company
-			)
-		else:
-			# This returns company's default cwip account
-			asset_account = get_asset_account("capital_work_in_progress_account", company=self.company)
-
-		remarks = self.get("remarks") or _("Accounting Entry for Stock")
-
-		self.add_gl_entry(
-			gl_entries=gl_entries,
-			account=expenses_included_in_asset_valuation,
-			cost_center=item.cost_center,
-			debit=0.0,
-			credit=flt(item.landed_cost_voucher_amount),
-			remarks=remarks,
-			against_account=asset_account,
-			project=item.project,
-			item=item,
-		)
-
-		self.add_gl_entry(
-			gl_entries=gl_entries,
-			account=asset_account,
-			cost_center=item.cost_center,
-			debit=flt(item.landed_cost_voucher_amount),
-			credit=0.0,
-			remarks=remarks,
-			against_account=expenses_included_in_asset_valuation,
-			project=item.project,
-			item=item,
-		)
-
 	def update_assets(self, item, valuation_rate):
 		assets = frappe.db.get_all(
 			"Asset", filters={"purchase_receipt": self.name, "item_code": item.item_code}
@@ -830,6 +750,20 @@
 		self.load_from_db()
 
 
+def get_stock_value_difference(voucher_no, voucher_detail_no, warehouse):
+	return frappe.db.get_value(
+		"Stock Ledger Entry",
+		{
+			"voucher_type": "Purchase Receipt",
+			"voucher_no": voucher_no,
+			"voucher_detail_no": voucher_detail_no,
+			"warehouse": warehouse,
+			"is_cancelled": 0,
+		},
+		"stock_value_difference",
+	)
+
+
 def update_billed_amount_based_on_po(po_details, update_modified=True):
 	po_billed_amt_details = get_billed_amount_against_po(po_details)
 
diff --git a/erpnext/templates/pages/integrations/__init__.py b/erpnext/templates/pages/integrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/templates/pages/integrations/__init__.py