Merge branch 'develop' into fix/v14/stock-entry/send-to-subcontractor
diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js
index a964965..f745620 100644
--- a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js
+++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.js
@@ -141,7 +141,7 @@
 	},
 
 	show_import_status(frm) {
-		let import_log = JSON.parse(frm.doc.import_log || "[]");
+		let import_log = JSON.parse(frm.doc.statement_import_log || "[]");
 		let successful_records = import_log.filter((log) => log.success);
 		let failed_records = import_log.filter((log) => !log.success);
 		if (successful_records.length === 0) return;
@@ -309,7 +309,7 @@
 	// method: 'frappe.core.doctype.data_import.data_import.get_preview_from_template',
 
 	show_import_preview(frm, preview_data) {
-		let import_log = JSON.parse(frm.doc.import_log || "[]");
+		let import_log = JSON.parse(frm.doc.statement_import_log || "[]");
 
 		if (
 			frm.import_preview &&
@@ -439,7 +439,7 @@
 	},
 
 	show_import_log(frm) {
-		let import_log = JSON.parse(frm.doc.import_log || "[]");
+		let import_log = JSON.parse(frm.doc.statement_import_log || "[]");
 		let logs = import_log;
 		frm.toggle_display("import_log", false);
 		frm.toggle_display("import_log_section", logs.length > 0);
diff --git a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.json b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.json
index 7ffff02..eede3bd 100644
--- a/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.json
+++ b/erpnext/accounts/doctype/bank_statement_import/bank_statement_import.json
@@ -24,7 +24,7 @@
   "section_import_preview",
   "import_preview",
   "import_log_section",
-  "import_log",
+  "statement_import_log",
   "show_failed_logs",
   "import_log_preview",
   "reference_doctype",
@@ -91,12 +91,6 @@
    "read_only": 1
   },
   {
-   "fieldname": "import_log",
-   "fieldtype": "Code",
-   "label": "Import Log",
-   "options": "JSON"
-  },
-  {
    "fieldname": "import_log_section",
    "fieldtype": "Section Break",
    "label": "Import Log"
@@ -198,11 +192,17 @@
   {
    "fieldname": "column_break_4",
    "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "statement_import_log",
+   "fieldtype": "Code",
+   "label": "Statement Import Log",
+   "options": "JSON"
   }
  ],
  "hide_toolbar": 1,
  "links": [],
- "modified": "2021-05-12 14:17:37.777246",
+ "modified": "2022-09-07 11:11:40.293317",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Bank Statement Import",
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html
index 82705a9..0da44a4 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html
@@ -25,7 +25,7 @@
 	</div>
 	<br>
 
-	<table class="table table-bordered">
+	<table class="table table-bordered" style="font-size: 10px">
 		<thead>
 			<tr>
 				<th style="width: 12%">{{ _("Date") }}</th>
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index d4f9aba..9149b4d 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -700,6 +700,47 @@
 			else:
 				create_repost_item_valuation_entry(args)
 
+	def add_gl_entry(
+		self,
+		gl_entries,
+		account,
+		cost_center,
+		debit,
+		credit,
+		remarks,
+		against_account,
+		debit_in_account_currency=None,
+		credit_in_account_currency=None,
+		account_currency=None,
+		project=None,
+		voucher_detail_no=None,
+		item=None,
+		posting_date=None,
+	):
+
+		gl_entry = {
+			"account": account,
+			"cost_center": cost_center,
+			"debit": debit,
+			"credit": credit,
+			"against": against_account,
+			"remarks": remarks,
+		}
+
+		if voucher_detail_no:
+			gl_entry.update({"voucher_detail_no": voucher_detail_no})
+
+		if debit_in_account_currency:
+			gl_entry.update({"debit_in_account_currency": debit_in_account_currency})
+
+		if credit_in_account_currency:
+			gl_entry.update({"credit_in_account_currency": credit_in_account_currency})
+
+		if posting_date:
+			gl_entry.update({"posting_date": posting_date})
+
+		gl_entries.append(self.get_gl_dict(gl_entry, item=item))
+
 
 def repost_required_for_queue(doc: StockController) -> bool:
 	"""check if stock document contains repeated item-warehouse with queue based valuation.
diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py
index 2150477..bbd950e 100644
--- a/erpnext/controllers/subcontracting_controller.py
+++ b/erpnext/controllers/subcontracting_controller.py
@@ -877,6 +877,7 @@
 		{
 			order_doctype: {
 				"doctype": "Stock Entry",
+				"field_no_map": ["purchase_order", "subcontracting_order"],
 			},
 		},
 		ignore_child_tables=True,
diff --git a/erpnext/controllers/tests/test_subcontracting_controller.py b/erpnext/controllers/tests/test_subcontracting_controller.py
index bc503f5..8490d14 100644
--- a/erpnext/controllers/tests/test_subcontracting_controller.py
+++ b/erpnext/controllers/tests/test_subcontracting_controller.py
@@ -897,7 +897,7 @@
 			"item_name": row.item_code,
 			"rate": row.rate or 100,
 			"stock_uom": row.stock_uom or "Nos",
-			"warehouse": row.warehuose or "_Test Warehouse - _TC",
+			"warehouse": row.warehouse or "_Test Warehouse - _TC",
 		}
 
 		item_details = args.itemwise_details.get(row.item_code)
@@ -1031,9 +1031,9 @@
 	if not args.service_items:
 		service_items = [
 			{
-				"warehouse": "_Test Warehouse - _TC",
+				"warehouse": args.warehouse or "_Test Warehouse - _TC",
 				"item_code": "Subcontracted Service Item 7",
-				"qty": 5,
+				"qty": 10,
 				"rate": 100,
 				"fg_item": "Subcontracted Item SA7",
 				"fg_item_qty": 10,
@@ -1046,6 +1046,7 @@
 		rm_items=service_items,
 		is_subcontracted=1,
 		supplier_warehouse=args.supplier_warehouse or "_Test Warehouse 1 - _TC",
+		company=args.company,
 	)
 
 	return create_subcontracting_order(po_name=po.name, **args)
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 4729add..d780213 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -312,4 +312,5 @@
 erpnext.patches.v14_0.remove_hr_and_payroll_modules # 20-07-2022
 erpnext.patches.v14_0.fix_crm_no_of_employees
 erpnext.patches.v14_0.create_accounting_dimensions_in_subcontracting_doctypes
+erpnext.patches.v14_0.fix_subcontracting_receipt_gl_entries
 erpnext.patches.v14_0.migrate_remarks_from_gl_to_payment_ledger
diff --git a/erpnext/patches/v14_0/fix_subcontracting_receipt_gl_entries.py b/erpnext/patches/v14_0/fix_subcontracting_receipt_gl_entries.py
new file mode 100644
index 0000000..159c6dc
--- /dev/null
+++ b/erpnext/patches/v14_0/fix_subcontracting_receipt_gl_entries.py
@@ -0,0 +1,30 @@
+# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+import frappe
+
+from erpnext.stock.report.stock_and_account_value_comparison.stock_and_account_value_comparison import (
+	get_data,
+)
+
+
+def execute():
+	data = []
+
+	for company in frappe.db.get_list("Company", pluck="name"):
+		data += get_data(
+			frappe._dict(
+				{
+					"company": company,
+				}
+			)
+		)
+
+	if data:
+		for d in data:
+			if d and d.get("voucher_type") == "Subcontracting Receipt":
+				doc = frappe.new_doc("Repost Item Valuation")
+				doc.voucher_type = d.get("voucher_type")
+				doc.voucher_no = d.get("voucher_no")
+				doc.save()
+				doc.submit()
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index f2bea58..6d64625 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -226,7 +226,7 @@
 						if (!found) {
 							filters.splice(index, 0, {
 								"fieldname": dimension["fieldname"],
-								"label": __(dimension["label"]),
+								"label": __(dimension["doctype"]),
 								"fieldtype": "MultiSelectList",
 								get_data: function(txt) {
 									return frappe.db.get_link_options(dimension["doctype"], txt);
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 84da3cc..f85c478 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -362,6 +362,12 @@
 						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_supplier and d.valuation_rate:
+						outgoing_amount = d.valuation_rate * d.stock_qty
+						credit_amount = outgoing_amount
+
 					if credit_amount:
 						account = warehouse_account[d.from_warehouse]["account"] if d.from_warehouse else stock_rbnb
 
@@ -369,7 +375,7 @@
 							gl_entries=gl_entries,
 							account=account,
 							cost_center=d.cost_center,
-							debit=-1 * flt(d.base_net_amount, d.precision("base_net_amount")),
+							debit=-1 * flt(outgoing_amount, d.precision("base_net_amount")),
 							credit=0.0,
 							remarks=remarks,
 							against_account=warehouse_account_name,
@@ -456,7 +462,7 @@
 
 					# divisional loss adjustment
 					valuation_amount_as_per_doc = (
-						flt(d.base_net_amount, d.precision("base_net_amount"))
+						flt(outgoing_amount, d.precision("base_net_amount"))
 						+ flt(d.landed_cost_voucher_amount)
 						+ flt(d.rm_supp_cost)
 						+ flt(d.item_tax_amount)
@@ -631,47 +637,6 @@
 
 					i += 1
 
-	def add_gl_entry(
-		self,
-		gl_entries,
-		account,
-		cost_center,
-		debit,
-		credit,
-		remarks,
-		against_account,
-		debit_in_account_currency=None,
-		credit_in_account_currency=None,
-		account_currency=None,
-		project=None,
-		voucher_detail_no=None,
-		item=None,
-		posting_date=None,
-	):
-
-		gl_entry = {
-			"account": account,
-			"cost_center": cost_center,
-			"debit": debit,
-			"credit": credit,
-			"against": against_account,
-			"remarks": remarks,
-		}
-
-		if voucher_detail_no:
-			gl_entry.update({"voucher_detail_no": voucher_detail_no})
-
-		if debit_in_account_currency:
-			gl_entry.update({"debit_in_account_currency": debit_in_account_currency})
-
-		if credit_in_account_currency:
-			gl_entry.update({"credit_in_account_currency": credit_in_account_currency})
-
-		if posting_date:
-			gl_entry.update({"posting_date": posting_date})
-
-		gl_entries.append(self.get_gl_dict(gl_entry, item=item))
-
 	def get_asset_gl_entry(self, gl_entries):
 		for item in self.get("items"):
 			if item.is_fixed_asset:
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index d0d115d..b77c3a5 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -5,6 +5,7 @@
 import frappe
 from frappe.tests.utils import FrappeTestCase, change_settings
 from frappe.utils import add_days, cint, cstr, flt, today
+from pypika import functions as fn
 
 import erpnext
 from erpnext.accounts.doctype.account.test_account import get_inventory_account
@@ -1156,6 +1157,125 @@
 			if gle.account == account:
 				self.assertEqual(gle.credit, 50)
 
+	def test_backdated_transaction_for_internal_transfer(self):
+		from erpnext.stock.doctype.delivery_note.delivery_note import make_inter_company_purchase_receipt
+		from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
+
+		prepare_data_for_internal_transfer()
+		customer = "_Test Internal Customer 2"
+		company = "_Test Company with perpetual inventory"
+
+		from_warehouse = create_warehouse("_Test Internal From Warehouse New", company=company)
+		to_warehouse = create_warehouse("_Test Internal To Warehouse New", company=company)
+		item_doc = create_item("Test Internal Transfer Item")
+
+		target_warehouse = create_warehouse("_Test Internal GIT Warehouse New", company=company)
+
+		make_purchase_receipt(
+			item_code=item_doc.name,
+			company=company,
+			posting_date=add_days(today(), -1),
+			warehouse=from_warehouse,
+			qty=1,
+			rate=100,
+		)
+
+		dn1 = create_delivery_note(
+			item_code=item_doc.name,
+			company=company,
+			customer=customer,
+			cost_center="Main - TCP1",
+			expense_account="Cost of Goods Sold - TCP1",
+			qty=1,
+			rate=500,
+			warehouse=from_warehouse,
+			target_warehouse=target_warehouse,
+		)
+
+		self.assertEqual(dn1.items[0].rate, 100)
+
+		pr1 = make_inter_company_purchase_receipt(dn1.name)
+		pr1.items[0].warehouse = to_warehouse
+		self.assertEqual(pr1.items[0].rate, 100)
+		pr1.submit()
+
+		# Backdated purchase receipt entry, the valuation rate should be updated for DN1 and PR1
+		make_purchase_receipt(
+			item_code=item_doc.name,
+			company=company,
+			posting_date=add_days(today(), -2),
+			warehouse=from_warehouse,
+			qty=1,
+			rate=200,
+		)
+
+		dn_value = frappe.db.get_value(
+			"Stock Ledger Entry",
+			{"voucher_type": "Delivery Note", "voucher_no": dn1.name, "warehouse": target_warehouse},
+			"stock_value_difference",
+		)
+
+		self.assertEqual(abs(dn_value), 200.00)
+
+		pr_value = frappe.db.get_value(
+			"Stock Ledger Entry",
+			{"voucher_type": "Purchase Receipt", "voucher_no": pr1.name, "warehouse": to_warehouse},
+			"stock_value_difference",
+		)
+
+		self.assertEqual(abs(pr_value), 200.00)
+		pr1.load_from_db()
+
+		self.assertEqual(pr1.items[0].valuation_rate, 200)
+		self.assertEqual(pr1.items[0].rate, 100)
+
+		Gl = frappe.qb.DocType("GL Entry")
+
+		query = (
+			frappe.qb.from_(Gl)
+			.select(
+				(fn.Sum(Gl.debit) - fn.Sum(Gl.credit)).as_("value"),
+			)
+			.where((Gl.voucher_type == pr1.doctype) & (Gl.voucher_no == pr1.name))
+		).run(as_dict=True)
+
+		self.assertEqual(query[0].value, 0)
+
+
+def prepare_data_for_internal_transfer():
+	from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier
+	from erpnext.selling.doctype.customer.test_customer import create_internal_customer
+
+	company = "_Test Company with perpetual inventory"
+
+	create_internal_customer(
+		"_Test Internal Customer 2",
+		company,
+		company,
+	)
+
+	create_internal_supplier(
+		"_Test Internal Supplier 2",
+		company,
+		company,
+	)
+
+	if not frappe.db.get_value("Company", company, "unrealized_profit_loss_account"):
+		account = "Unrealized Profit and Loss - TCP1"
+		if not frappe.db.exists("Account", account):
+			frappe.get_doc(
+				{
+					"doctype": "Account",
+					"account_name": "Unrealized Profit and Loss",
+					"parent_account": "Direct Income - TCP1",
+					"company": company,
+					"is_group": 0,
+					"account_type": "Income Account",
+				}
+			).insert()
+
+		frappe.db.set_value("Company", company, "unrealized_profit_loss_account", account)
+
 
 def get_sl_entries(voucher_type, voucher_no):
 	return frappe.db.sql(
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js
index eae7305..d595a80 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.js
@@ -58,6 +58,21 @@
 		}
 
 		frm.trigger('show_reposting_progress');
+
+		if (frm.doc.status === 'Queued' && frm.doc.docstatus === 1) {
+			frm.trigger('execute_reposting');
+		}
+	},
+
+	execute_reposting(frm) {
+		frm.add_custom_button(__("Start Reposting"), () => {
+			frappe.call({
+				method: 'erpnext.stock.doctype.repost_item_valuation.repost_item_valuation.execute_repost_item_valuation',
+				callback: function() {
+					frappe.msgprint(__('Reposting has been started in the background.'));
+				}
+			});
+		});
 	},
 
 	show_reposting_progress: function(frm) {
diff --git a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
index 7c57ecd..c470524 100644
--- a/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
+++ b/erpnext/stock/doctype/repost_item_valuation/repost_item_valuation.py
@@ -307,3 +307,9 @@
 		return end_time >= now_time >= start_time
 	else:
 		return now_time >= start_time or now_time <= end_time
+
+
+@frappe.whitelist()
+def execute_repost_item_valuation():
+	"""Execute repost item valuation via scheduler."""
+	frappe.get_doc("Scheduled Job Type", "repost_item_valuation.repost_entries").enqueue(force=True)
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 3524a47..5030964 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -649,21 +649,25 @@
 
 			elif (
 				sle.voucher_type in ["Purchase Receipt", "Purchase Invoice"]
-				and sle.actual_qty > 0
+				and sle.voucher_detail_no
 				and frappe.get_cached_value(sle.voucher_type, sle.voucher_no, "is_internal_supplier")
 			):
-				sle_details = frappe.db.get_value(
-					"Stock Ledger Entry",
-					{
-						"voucher_type": sle.voucher_type,
-						"voucher_no": sle.voucher_no,
-						"dependant_sle_voucher_detail_no": sle.voucher_detail_no,
-					},
-					["stock_value_difference", "actual_qty"],
-					as_dict=1,
+				field = (
+					"delivery_note_item" if sle.voucher_type == "Purchase Receipt" else "sales_invoice_item"
+				)
+				doctype = (
+					"Delivery Note Item" if sle.voucher_type == "Purchase Receipt" else "Sales Invoice Item"
+				)
+				refernce_name = frappe.get_cached_value(
+					sle.voucher_type + " Item", sle.voucher_detail_no, field
 				)
 
-				rate = abs(sle_details.stock_value_difference / sle.actual_qty)
+				if refernce_name:
+					rate = frappe.get_cached_value(
+						doctype,
+						refernce_name,
+						"incoming_rate",
+					)
 			else:
 				if sle.voucher_type in ("Purchase Receipt", "Purchase Invoice"):
 					rate_field = "valuation_rate"
@@ -745,7 +749,12 @@
 	def update_rate_on_purchase_receipt(self, sle, outgoing_rate):
 		if frappe.db.exists(sle.voucher_type + " Item", sle.voucher_detail_no):
 			frappe.db.set_value(
-				sle.voucher_type + " Item", sle.voucher_detail_no, "base_net_rate", outgoing_rate
+				sle.voucher_type + " Item",
+				sle.voucher_detail_no,
+				{
+					"base_net_rate": outgoing_rate,
+					"valuation_rate": outgoing_rate,
+				},
 			)
 		else:
 			frappe.db.set_value(
diff --git a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js
index 065ef39..40963f8 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js
+++ b/erpnext/subcontracting/doctype/subcontracting_order/subcontracting_order.js
@@ -107,7 +107,7 @@
 	get_materials_from_supplier: function (frm) {
 		let sco_rm_details = [];
 
-		if (frm.doc.supplied_items && frm.doc.per_received > 0) {
+		if (frm.doc.status != "Closed" && frm.doc.supplied_items && frm.doc.per_received > 0) {
 			frm.doc.supplied_items.forEach(d => {
 				if (d.total_supplied_qty > 0 && d.total_supplied_qty != d.consumed_qty) {
 					sco_rm_details.push(d.name);
diff --git a/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py b/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py
index f4a943f..d054ce0 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py
+++ b/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py
@@ -502,6 +502,35 @@
 
 		set_backflush_based_on("BOM")
 
+	def test_get_materials_from_supplier(self):
+		# Create SCO
+		sco = get_subcontracting_order()
+
+		# Transfer RM
+		rm_items = get_rm_items(sco.supplied_items)
+		itemwise_details = make_stock_in_entry(rm_items=rm_items)
+		make_stock_transfer_entry(
+			sco_no=sco.name,
+			rm_items=rm_items,
+			itemwise_details=copy.deepcopy(itemwise_details),
+		)
+
+		# Create SCR (Partial)
+		scr = make_subcontracting_receipt(sco.name)
+		scr.items[0].qty -= 5
+		scr.save()
+		scr.submit()
+
+		# Get RM from Supplier
+		ste = get_materials_from_supplier(sco.name, [d.name for d in sco.supplied_items])
+		ste.save()
+		ste.submit()
+
+		sco.load_from_db()
+
+		self.assertEqual(sco.status, "Closed")
+		self.assertEqual(sco.supplied_items[0].returned_qty, 5)
+
 
 def create_subcontracting_order(**args):
 	args = frappe._dict(args)
@@ -510,7 +539,7 @@
 	for item in sco.items:
 		item.include_exploded_items = args.get("include_exploded_items", 1)
 
-	if args.get("warehouse"):
+	if args.warehouse:
 		for item in sco.items:
 			item.warehouse = args.warehouse
 	else:
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
index 1da7340..cd05b74 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
@@ -5,6 +5,8 @@
 from frappe import _
 from frappe.utils import cint, flt, getdate, nowdate
 
+import erpnext
+from erpnext.accounts.utils import get_account_currency
 from erpnext.controllers.subcontracting_controller import SubcontractingController
 
 
@@ -225,6 +227,137 @@
 		if status:
 			frappe.db.set_value("Subcontracting Receipt", self.name, "status", status, update_modified)
 
+	def get_gl_entries(self, warehouse_account=None):
+		from erpnext.accounts.general_ledger import process_gl_map
+
+		gl_entries = []
+		self.make_item_gl_entries(gl_entries, warehouse_account)
+
+		return process_gl_map(gl_entries)
+
+	def make_item_gl_entries(self, gl_entries, warehouse_account=None):
+		if erpnext.is_perpetual_inventory_enabled(self.company):
+			stock_rbnb = self.get_company_default("stock_received_but_not_billed")
+			expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
+
+		warehouse_with_no_account = []
+
+		for item in self.items:
+			if flt(item.rate) and flt(item.qty):
+				if warehouse_account.get(item.warehouse):
+					stock_value_diff = frappe.db.get_value(
+						"Stock Ledger Entry",
+						{
+							"voucher_type": "Subcontracting Receipt",
+							"voucher_no": self.name,
+							"voucher_detail_no": item.name,
+							"warehouse": item.warehouse,
+							"is_cancelled": 0,
+						},
+						"stock_value_difference",
+					)
+
+					warehouse_account_name = warehouse_account[item.warehouse]["account"]
+					warehouse_account_currency = warehouse_account[item.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")
+
+					# FG Warehouse Account (Debit)
+					self.add_gl_entry(
+						gl_entries=gl_entries,
+						account=warehouse_account_name,
+						cost_center=item.cost_center,
+						debit=stock_value_diff,
+						credit=0.0,
+						remarks=remarks,
+						against_account=stock_rbnb,
+						account_currency=warehouse_account_currency,
+						item=item,
+					)
+
+					# Supplier Warehouse Account (Credit)
+					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=warehouse_account_name,
+							account_currency=supplier_warehouse_account_currency,
+							item=item,
+						)
+
+					# Expense Account (Credit)
+					if flt(item.service_cost_per_qty):
+						self.add_gl_entry(
+							gl_entries=gl_entries,
+							account=item.expense_account,
+							cost_center=item.cost_center,
+							debit=0.0,
+							credit=flt(item.service_cost_per_qty) * flt(item.qty),
+							remarks=remarks,
+							against_account=warehouse_account_name,
+							account_currency=get_account_currency(item.expense_account),
+							item=item,
+						)
+
+					# Loss Account (Credit)
+					divisional_loss = flt(item.amount - stock_value_diff, item.precision("amount"))
+
+					if divisional_loss:
+						if self.is_return:
+							loss_account = expenses_included_in_valuation
+						else:
+							loss_account = item.expense_account
+
+						self.add_gl_entry(
+							gl_entries=gl_entries,
+							account=loss_account,
+							cost_center=item.cost_center,
+							debit=divisional_loss,
+							credit=0.0,
+							remarks=remarks,
+							against_account=warehouse_account_name,
+							account_currency=get_account_currency(loss_account),
+							project=item.project,
+							item=item,
+						)
+				elif (
+					item.warehouse not in warehouse_with_no_account
+					or item.rejected_warehouse not in warehouse_with_no_account
+				):
+					warehouse_with_no_account.append(item.warehouse)
+
+		# Additional Costs Expense Accounts (Credit)
+		for row in self.additional_costs:
+			credit_amount = (
+				flt(row.base_amount)
+				if (row.base_amount or row.account_currency != self.company_currency)
+				else flt(row.amount)
+			)
+
+			self.add_gl_entry(
+				gl_entries=gl_entries,
+				account=row.expense_account,
+				cost_center=self.cost_center or self.get_company_default("cost_center"),
+				debit=0.0,
+				credit=credit_amount,
+				remarks=remarks,
+				against_account=None,
+			)
+
+		if warehouse_with_no_account:
+			frappe.msgprint(
+				_("No accounting entries for the following warehouses")
+				+ ": \n"
+				+ "\n".join(warehouse_with_no_account)
+			)
+
 
 @frappe.whitelist()
 def make_subcontract_return(source_name, target_doc=None):
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py
index a47af52..090f145 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py
@@ -6,8 +6,10 @@
 
 import frappe
 from frappe.tests.utils import FrappeTestCase
-from frappe.utils import flt
+from frappe.utils import cint, flt
 
+import erpnext
+from erpnext.accounts.doctype.account.test_account import get_inventory_account
 from erpnext.controllers.sales_and_purchase_return import make_return_doc
 from erpnext.controllers.tests.test_subcontracting_controller import (
 	get_rm_items,
@@ -22,6 +24,7 @@
 	set_backflush_based_on,
 )
 from erpnext.stock.doctype.item.test_item import make_item
+from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import get_gl_entries
 from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
 from erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order import (
 	make_subcontracting_receipt,
@@ -366,6 +369,103 @@
 		args = frappe._dict(scr_name=scr1.name, qty=-15)
 		self.assertRaises(OverAllowanceError, make_return_subcontracting_receipt, **args)
 
+	def test_subcontracting_receipt_no_gl_entry(self):
+		sco = get_subcontracting_order()
+		rm_items = get_rm_items(sco.supplied_items)
+		itemwise_details = make_stock_in_entry(rm_items=rm_items)
+		make_stock_transfer_entry(
+			sco_no=sco.name,
+			rm_items=rm_items,
+			itemwise_details=copy.deepcopy(itemwise_details),
+		)
+
+		scr = make_subcontracting_receipt(sco.name)
+		scr.append(
+			"additional_costs",
+			{
+				"expense_account": "Expenses Included In Valuation - _TC",
+				"description": "Test Additional Costs",
+				"amount": 100,
+			},
+		)
+		scr.save()
+		scr.submit()
+
+		stock_value_difference = frappe.db.get_value(
+			"Stock Ledger Entry",
+			{
+				"voucher_type": "Subcontracting Receipt",
+				"voucher_no": scr.name,
+				"item_code": "Subcontracted Item SA7",
+				"warehouse": "_Test Warehouse - _TC",
+			},
+			"stock_value_difference",
+		)
+
+		# Service Cost(100 * 10) + Raw Materials Cost(50 * 10) + Additional Costs(100) = 1600
+		self.assertEqual(stock_value_difference, 1600)
+		self.assertFalse(get_gl_entries("Subcontracting Receipt", scr.name))
+
+	def test_subcontracting_receipt_gl_entry(self):
+		sco = get_subcontracting_order(
+			company="_Test Company with perpetual inventory",
+			warehouse="Stores - TCP1",
+			supplier_warehouse="Work In Progress - TCP1",
+		)
+		rm_items = get_rm_items(sco.supplied_items)
+		itemwise_details = make_stock_in_entry(rm_items=rm_items)
+		make_stock_transfer_entry(
+			sco_no=sco.name,
+			rm_items=rm_items,
+			itemwise_details=copy.deepcopy(itemwise_details),
+		)
+
+		scr = make_subcontracting_receipt(sco.name)
+		additional_costs_expense_account = "Expenses Included In Valuation - TCP1"
+		scr.append(
+			"additional_costs",
+			{
+				"expense_account": additional_costs_expense_account,
+				"description": "Test Additional Costs",
+				"amount": 100,
+				"base_amount": 100,
+			},
+		)
+		scr.save()
+		scr.submit()
+
+		self.assertEqual(cint(erpnext.is_perpetual_inventory_enabled(scr.company)), 1)
+
+		gl_entries = get_gl_entries("Subcontracting Receipt", scr.name)
+
+		self.assertTrue(gl_entries)
+
+		fg_warehouse_ac = get_inventory_account(scr.company, scr.items[0].warehouse)
+		supplier_warehouse_ac = get_inventory_account(scr.company, scr.supplier_warehouse)
+		expense_account = scr.items[0].expense_account
+
+		if fg_warehouse_ac == supplier_warehouse_ac:
+			expected_values = {
+				fg_warehouse_ac: [2100.0, 1000.0],  # FG Amount (D), RM Cost (C)
+				expense_account: [0.0, 1000.0],  # Service Cost (C)
+				additional_costs_expense_account: [0.0, 100.0],  # Additional Cost (C)
+			}
+		else:
+			expected_values = {
+				fg_warehouse_ac: [2100.0, 0.0],  # FG Amount (D)
+				supplier_warehouse_ac: [0.0, 1000.0],  # RM Cost (C)
+				expense_account: [0.0, 1000.0],  # Service Cost (C)
+				additional_costs_expense_account: [0.0, 100.0],  # Additional Cost (C)
+			}
+
+		for gle in gl_entries:
+			self.assertEqual(expected_values[gle.account][0], gle.debit)
+			self.assertEqual(expected_values[gle.account][1], gle.credit)
+
+		scr.reload()
+		scr.cancel()
+		self.assertTrue(get_gl_entries("Subcontracting Receipt", scr.name))
+
 
 def make_return_subcontracting_receipt(**args):
 	args = frappe._dict(args)