Merge pull request #40595 from rohitwaghchaure/fixed-rate-not-fetch-from-item-price

fix: rate not fetching from the item price
diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py
index 7162aef..25958692 100644
--- a/erpnext/accounts/report/gross_profit/gross_profit.py
+++ b/erpnext/accounts/report/gross_profit/gross_profit.py
@@ -669,20 +669,20 @@
 			elif row.sales_order and row.so_detail:
 				incoming_amount = self.get_buying_amount_from_so_dn(row.sales_order, row.so_detail, item_code)
 				if incoming_amount:
-					return incoming_amount
+					return flt(row.qty) * incoming_amount
 			else:
 				return flt(row.qty) * self.get_average_buying_rate(row, item_code)
 
 		return flt(row.qty) * self.get_average_buying_rate(row, item_code)
 
 	def get_buying_amount_from_so_dn(self, sales_order, so_detail, item_code):
-		from frappe.query_builder.functions import Sum
+		from frappe.query_builder.functions import Avg
 
 		delivery_note_item = frappe.qb.DocType("Delivery Note Item")
 
 		query = (
 			frappe.qb.from_(delivery_note_item)
-			.select(Sum(delivery_note_item.incoming_rate * delivery_note_item.stock_qty))
+			.select(Avg(delivery_note_item.incoming_rate))
 			.where(delivery_note_item.docstatus == 1)
 			.where(delivery_note_item.item_code == item_code)
 			.where(delivery_note_item.against_sales_order == sales_order)
diff --git a/erpnext/accounts/report/gross_profit/test_gross_profit.py b/erpnext/accounts/report/gross_profit/test_gross_profit.py
index 82fe1a0..aa820aa 100644
--- a/erpnext/accounts/report/gross_profit/test_gross_profit.py
+++ b/erpnext/accounts/report/gross_profit/test_gross_profit.py
@@ -460,3 +460,95 @@
 		}
 		gp_entry = [x for x in data if x.parent_invoice == sinv.name]
 		self.assertDictContainsSubset(expected_entry, gp_entry[0])
+
+	def test_different_rates_in_si_and_dn(self):
+		from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
+
+		"""
+			Test gp calculation when invoice and delivery note differ in qty and aren't connected
+			SO -- INV
+			|
+			DN
+		"""
+		se = make_stock_entry(
+			company=self.company,
+			item_code=self.item,
+			target=self.warehouse,
+			qty=3,
+			basic_rate=700,
+			do_not_submit=True,
+		)
+		item = se.items[0]
+		se.append(
+			"items",
+			{
+				"item_code": item.item_code,
+				"s_warehouse": item.s_warehouse,
+				"t_warehouse": item.t_warehouse,
+				"qty": 10,
+				"basic_rate": 700,
+				"conversion_factor": item.conversion_factor or 1.0,
+				"transfer_qty": flt(item.qty) * (flt(item.conversion_factor) or 1.0),
+				"serial_no": item.serial_no,
+				"batch_no": item.batch_no,
+				"cost_center": item.cost_center,
+				"expense_account": item.expense_account,
+			},
+		)
+		se = se.save().submit()
+
+		so = make_sales_order(
+			customer=self.customer,
+			company=self.company,
+			warehouse=self.warehouse,
+			item=self.item,
+			rate=800,
+			qty=10,
+			do_not_save=False,
+			do_not_submit=False,
+		)
+
+		from erpnext.selling.doctype.sales_order.sales_order import (
+			make_delivery_note,
+			make_sales_invoice,
+		)
+
+		dn1 = make_delivery_note(so.name)
+		dn1.items[0].qty = 4
+		dn1.items[0].rate = 800
+		dn1.save().submit()
+
+		dn2 = make_delivery_note(so.name)
+		dn2.items[0].qty = 6
+		dn2.items[0].rate = 800
+		dn2.save().submit()
+
+		sinv = make_sales_invoice(so.name)
+		sinv.items[0].qty = 4
+		sinv.items[0].rate = 800
+		sinv.save().submit()
+
+		filters = frappe._dict(
+			company=self.company, from_date=nowdate(), to_date=nowdate(), group_by="Invoice"
+		)
+
+		columns, data = execute(filters=filters)
+		expected_entry = {
+			"parent_invoice": sinv.name,
+			"currency": "INR",
+			"sales_invoice": self.item,
+			"customer": self.customer,
+			"posting_date": frappe.utils.datetime.date.fromisoformat(nowdate()),
+			"item_code": self.item,
+			"item_name": self.item,
+			"warehouse": "Stores - _GP",
+			"qty": 4.0,
+			"avg._selling_rate": 800.0,
+			"valuation_rate": 700.0,
+			"selling_amount": 3200.0,
+			"buying_amount": 2800.0,
+			"gross_profit": 400.0,
+			"gross_profit_%": 12.5,
+		}
+		gp_entry = [x for x in data if x.parent_invoice == sinv.name]
+		self.assertDictContainsSubset(expected_entry, gp_entry[0])
diff --git a/erpnext/stock/doctype/item_price/item_price.py b/erpnext/stock/doctype/item_price/item_price.py
index de2add6..25a28b4 100644
--- a/erpnext/stock/doctype/item_price/item_price.py
+++ b/erpnext/stock/doctype/item_price/item_price.py
@@ -7,7 +7,6 @@
 from frappe.model.document import Document
 from frappe.query_builder import Criterion
 from frappe.query_builder.functions import Cast_
-from frappe.utils import getdate
 
 
 class ItemPriceDuplicateItem(frappe.ValidationError):
@@ -46,7 +45,7 @@
 
 	def validate(self):
 		self.validate_item()
-		self.validate_dates()
+		self.validate_from_to_dates("valid_from", "valid_upto")
 		self.update_price_list_details()
 		self.update_item_details()
 		self.check_duplicates()
@@ -56,11 +55,6 @@
 		if not frappe.db.exists("Item", self.item_code):
 			frappe.throw(_("Item {0} not found.").format(self.item_code))
 
-	def validate_dates(self):
-		if self.valid_from and self.valid_upto:
-			if getdate(self.valid_from) > getdate(self.valid_upto):
-				frappe.throw(_("Valid From Date must be lesser than Valid Up To Date."))
-
 	def update_price_list_details(self):
 		if self.price_list:
 			price_list_details = frappe.db.get_value(