test: Internal tranfer precision loss test
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index ce44ae3..b63b9ed 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -32,10 +32,20 @@
 	get_qty_after_transaction,
 	make_stock_entry,
 )
-from erpnext.stock.utils import get_incoming_rate
+from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import (
+	create_stock_reconciliation,
+)
+from erpnext.stock.utils import get_incoming_rate, get_stock_balance
 
 
 class TestSalesInvoice(unittest.TestCase):
+	def setUp(self):
+		from erpnext.stock.doctype.stock_ledger_entry.test_stock_ledger_entry import create_items
+
+		create_items(["_Test Internal Transfer Item"], uoms=[{"uom": "Box", "conversion_factor": 10}])
+		create_internal_parties()
+		setup_accounts()
+
 	def make(self):
 		w = frappe.copy_doc(test_records[0])
 		w.is_pos = 0
@@ -1705,7 +1715,7 @@
 		si.save()
 		self.assertEqual(si.get("items")[0].rate, flt((price_list_rate * 25) / 100 + price_list_rate))
 
-	def test_outstanding_amount_after_advance_jv_cancelation(self):
+	def test_outstanding_amount_after_advance_jv_cancellation(self):
 		from erpnext.accounts.doctype.journal_entry.test_journal_entry import (
 			test_records as jv_test_records,
 		)
@@ -1749,7 +1759,7 @@
 			flt(si.rounded_total + si.total_advance, si.precision("outstanding_amount")),
 		)
 
-	def test_outstanding_amount_after_advance_payment_entry_cancelation(self):
+	def test_outstanding_amount_after_advance_payment_entry_cancellation(self):
 		pe = frappe.get_doc(
 			{
 				"doctype": "Payment Entry",
@@ -2367,29 +2377,6 @@
 		acc_settings.save()
 
 	def test_inter_company_transaction(self):
-		from erpnext.selling.doctype.customer.test_customer import create_internal_customer
-
-		create_internal_customer(
-			customer_name="_Test Internal Customer",
-			represents_company="_Test Company 1",
-			allowed_to_interact_with="Wind Power LLC",
-		)
-
-		if not frappe.db.exists("Supplier", "_Test Internal Supplier"):
-			supplier = frappe.get_doc(
-				{
-					"supplier_group": "_Test Supplier Group",
-					"supplier_name": "_Test Internal Supplier",
-					"doctype": "Supplier",
-					"is_internal_supplier": 1,
-					"represents_company": "Wind Power LLC",
-				}
-			)
-
-			supplier.append("companies", {"company": "_Test Company 1"})
-
-			supplier.insert()
-
 		si = create_sales_invoice(
 			company="Wind Power LLC",
 			customer="_Test Internal Customer",
@@ -2440,38 +2427,6 @@
 			"Expenses Included In Valuation - _TC1",
 		)
 
-		if not frappe.db.exists("Customer", "_Test Internal Customer"):
-			customer = frappe.get_doc(
-				{
-					"customer_group": "_Test Customer Group",
-					"customer_name": "_Test Internal Customer",
-					"customer_type": "Individual",
-					"doctype": "Customer",
-					"territory": "_Test Territory",
-					"is_internal_customer": 1,
-					"represents_company": "_Test Company 1",
-				}
-			)
-
-			customer.append("companies", {"company": "Wind Power LLC"})
-
-			customer.insert()
-
-		if not frappe.db.exists("Supplier", "_Test Internal Supplier"):
-			supplier = frappe.get_doc(
-				{
-					"supplier_group": "_Test Supplier Group",
-					"supplier_name": "_Test Internal Supplier",
-					"doctype": "Supplier",
-					"is_internal_supplier": 1,
-					"represents_company": "Wind Power LLC",
-				}
-			)
-
-			supplier.append("companies", {"company": "_Test Company 1"})
-
-			supplier.insert()
-
 		# begin test
 		si = create_sales_invoice(
 			company="Wind Power LLC",
@@ -2541,34 +2496,9 @@
 		se.cancel()
 
 	def test_internal_transfer_gl_entry(self):
-		## Create internal transfer account
-		from erpnext.selling.doctype.customer.test_customer import create_internal_customer
-
-		account = create_account(
-			account_name="Unrealized Profit",
-			parent_account="Current Liabilities - TCP1",
-			company="_Test Company with perpetual inventory",
-		)
-
-		frappe.db.set_value(
-			"Company", "_Test Company with perpetual inventory", "unrealized_profit_loss_account", account
-		)
-
-		customer = create_internal_customer(
-			"_Test Internal Customer 2",
-			"_Test Company with perpetual inventory",
-			"_Test Company with perpetual inventory",
-		)
-
-		create_internal_supplier(
-			"_Test Internal Supplier 2",
-			"_Test Company with perpetual inventory",
-			"_Test Company with perpetual inventory",
-		)
-
 		si = create_sales_invoice(
 			company="_Test Company with perpetual inventory",
-			customer=customer,
+			customer="_Test Internal Customer 2",
 			debit_to="Debtors - TCP1",
 			warehouse="Stores - TCP1",
 			income_account="Sales - TCP1",
@@ -2582,7 +2512,7 @@
 		si.update_stock = 1
 		si.items[0].target_warehouse = "Work In Progress - TCP1"
 
-		# Add stock to stores for succesful stock transfer
+		# Add stock to stores for successful stock transfer
 		make_stock_entry(
 			target="Stores - TCP1", company="_Test Company with perpetual inventory", qty=1, basic_rate=100
 		)
@@ -2638,6 +2568,77 @@
 
 		check_gl_entries(self, target_doc.name, pi_gl_entries, add_days(nowdate(), -1))
 
+	def test_internal_transfer_gl_precision_issues(self):
+		# Make a stock queue of an item with two valuations
+
+		# Remove all existing stock for this
+		if get_stock_balance("_Test Internal Transfer Item", "Stores - TCP1", "2022-04-10"):
+			create_stock_reconciliation(
+				item_code="_Test Internal Transfer Item",
+				warehouse="Stores - TCP1",
+				qty=0,
+				rate=0,
+				company="_Test Company with perpetual inventory",
+				expense_account="Stock Adjustment - TCP1"
+				if frappe.get_all("Stock Ledger Entry")
+				else "Temporary Opening - TCP1",
+				posting_date="2020-04-10",
+				posting_time="14:00",
+			)
+
+		make_stock_entry(
+			item_code="_Test Internal Transfer Item",
+			target="Stores - TCP1",
+			qty=9000000,
+			basic_rate=52.0,
+			posting_date="2020-04-10",
+			posting_time="14:00",
+		)
+		make_stock_entry(
+			item_code="_Test Internal Transfer Item",
+			target="Stores - TCP1",
+			qty=60000000,
+			basic_rate=52.349777,
+			posting_date="2020-04-10",
+			posting_time="14:00",
+		)
+
+		# Make an internal transfer Sales Invoice Stock in non stock uom to check
+		# for rounding errors while converting to stock uom
+		si = create_sales_invoice(
+			company="_Test Company with perpetual inventory",
+			customer="_Test Internal Customer 2",
+			item_code="_Test Internal Transfer Item",
+			qty=5000000,
+			uom="Box",
+			debit_to="Debtors - TCP1",
+			warehouse="Stores - TCP1",
+			income_account="Sales - TCP1",
+			expense_account="Cost of Goods Sold - TCP1",
+			cost_center="Main - TCP1",
+			currency="INR",
+			do_not_save=1,
+		)
+
+		# Check GL Entries with precision
+		si.update_stock = 1
+		si.items[0].target_warehouse = "Work In Progress - TCP1"
+		si.items[0].conversion_factor = 10
+		si.save()
+		si.submit()
+
+		# Check if adjustment entry is created
+		self.assertTrue(
+			frappe.db.exists(
+				"GL Entry",
+				{
+					"voucher_type": "Sales Invoice",
+					"voucher_no": si.name,
+					"remarks": "Rounding gain/loss Entry for Stock Transfer",
+				},
+			)
+		)
+
 	def test_item_tax_net_range(self):
 		item = create_item("T Shirt")
 
@@ -3077,7 +3078,7 @@
 			[deferred_account, 2022.47, 0.0, "2019-03-15"],
 		]
 
-		gl_entries = gl_entries = frappe.db.sql(
+		gl_entries = frappe.db.sql(
 			"""select account, debit, credit, posting_date
 			from `tabGL Entry`
 			where voucher_type='Journal Entry' and voucher_detail_no=%s and posting_date <= %s
@@ -3431,6 +3432,34 @@
 	]
 
 
+def create_internal_parties():
+	from erpnext.selling.doctype.customer.test_customer import create_internal_customer
+
+	create_internal_customer(
+		customer_name="_Test Internal Customer",
+		represents_company="_Test Company 1",
+		allowed_to_interact_with="Wind Power LLC",
+	)
+
+	create_internal_customer(
+		customer_name="_Test Internal Customer 2",
+		represents_company="_Test Company with perpetual inventory",
+		allowed_to_interact_with="_Test Company with perpetual inventory",
+	)
+
+	create_internal_supplier(
+		supplier_name="_Test Internal Supplier",
+		represents_company="Wind Power LLC",
+		allowed_to_interact_with="_Test Company 1",
+	)
+
+	create_internal_supplier(
+		supplier_name="_Test Internal Supplier 2",
+		represents_company="_Test Company with perpetual inventory",
+		allowed_to_interact_with="_Test Company with perpetual inventory",
+	)
+
+
 def create_internal_supplier(supplier_name, represents_company, allowed_to_interact_with):
 	if not frappe.db.exists("Supplier", supplier_name):
 		supplier = frappe.get_doc(
@@ -3453,6 +3482,19 @@
 	return supplier_name
 
 
+def setup_accounts():
+	## Create internal transfer account
+	account = create_account(
+		account_name="Unrealized Profit",
+		parent_account="Current Liabilities - TCP1",
+		company="_Test Company with perpetual inventory",
+	)
+
+	frappe.db.set_value(
+		"Company", "_Test Company with perpetual inventory", "unrealized_profit_loss_account", account
+	)
+
+
 def add_taxes(doc):
 	doc.append(
 		"taxes",
diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py
index e35c8bf..31c9919 100644
--- a/erpnext/stock/doctype/item/test_item.py
+++ b/erpnext/stock/doctype/item/test_item.py
@@ -32,7 +32,7 @@
 test_dependencies = ["Warehouse", "Item Group", "Item Tax Template", "Brand", "Item Attribute"]
 
 
-def make_item(item_code=None, properties=None):
+def make_item(item_code=None, properties=None, uoms=None):
 	if not item_code:
 		item_code = frappe.generate_hash(length=16)
 
@@ -56,6 +56,11 @@
 		for item_default in [doc for doc in item.get("item_defaults") if not doc.default_warehouse]:
 			item_default.default_warehouse = "_Test Warehouse - _TC"
 			item_default.company = "_Test Company"
+
+	if uoms:
+		for uom in uoms:
+			item.append("uoms", uom)
+
 	item.insert()
 
 	return item
diff --git a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
index 1410da5..6c341d9 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/test_stock_ledger_entry.py
@@ -1323,13 +1323,15 @@
 		item.save()
 
 
-def create_items():
-	items = [
-		"_Test Item for Reposting",
-		"_Test Finished Item for Reposting",
-		"_Test Subcontracted Item for Reposting",
-		"_Test Bundled Item for Reposting",
-	]
+def create_items(items=None, uoms=None):
+	if not items:
+		items = [
+			"_Test Item for Reposting",
+			"_Test Finished Item for Reposting",
+			"_Test Subcontracted Item for Reposting",
+			"_Test Bundled Item for Reposting",
+		]
+
 	for d in items:
 		properties = {"valuation_method": "FIFO"}
 		if d == "_Test Bundled Item for Reposting":
@@ -1337,7 +1339,7 @@
 		elif d == "_Test Subcontracted Item for Reposting":
 			properties.update({"is_sub_contracted_item": 1})
 
-		make_item(d, properties=properties)
+		make_item(d, properties=properties, uoms=uoms)
 
 	return items
 
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index 23e0f1e..d92d0f1 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -132,7 +132,9 @@
 					key.append(row.get(field))
 
 			if key in item_warehouse_combinations:
-				self.validation_messages.append(_get_msg(row_num, _("Duplicate entry")))
+				self.validation_messages.append(
+					_get_msg(row_num, _("Same item and warehouse combination already entered."))
+				)
 			else:
 				item_warehouse_combinations.append(key)