chore: Test and fixes

- Tests as per new design flow
- Fixed duplicate data bug in Warehouse Capacity Summary
- Set Amount currently on applying rule in client side
- Apply rules on server side before validate
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 31efb6a..5463448 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -2050,9 +2050,10 @@
 
 				let items =  result.message;
 				items.forEach((row) => {
-					delete row["name"];
+					delete row["name"]; // dont overwrite name from server side
 					let child = frm.add_child("items");
 					Object.assign(child, row);
+					frm.script_manager.trigger("qty", child.doctype, child.name);
 				});
 				frm.get_field("items").grid.refresh();
 			}
diff --git a/erpnext/stock/dashboard/item_dashboard.js b/erpnext/stock/dashboard/item_dashboard.js
index 070589b..20415bc 100644
--- a/erpnext/stock/dashboard/item_dashboard.js
+++ b/erpnext/stock/dashboard/item_dashboard.js
@@ -69,7 +69,7 @@
 
 		// more
 		this.content.find('.btn-more').on('click', function() {
-			me.start += this.page_length;
+			me.start += me.page_length;
 			me.refresh();
 		});
 
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 4372bdc..d36d515 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -83,7 +83,7 @@
 				}
 			])
 
-	def before_save(self):
+	def before_validate(self):
 		from erpnext.stock.doctype.putaway_rule.putaway_rule import apply_putaway_rule
 
 		if self.get("items") and self.apply_putaway_rule:
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 9b8eeed..7b3a830 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -979,6 +979,7 @@
 	pr.currency = args.currency or "INR"
 	pr.is_return = args.is_return
 	pr.return_against = args.return_against
+	pr.apply_putaway_rule = args.apply_putaway_rule
 	qty = args.qty or 5
 	received_qty = args.received_qty or qty
 	rejected_qty = args.rejected_qty or flt(received_qty) - flt(qty)
@@ -994,6 +995,7 @@
 		"rejected_warehouse": args.rejected_warehouse or "_Test Rejected Warehouse - _TC" if rejected_qty != 0 else "",
 		"rate": args.rate if args.rate != None else 50,
 		"conversion_factor": args.conversion_factor or 1.0,
+		"stock_qty": flt(qty) * (flt(args.conversion_factor) or 1.0),
 		"serial_no": args.serial_no,
 		"stock_uom": args.stock_uom or "_Test UOM",
 		"uom": uom,
diff --git a/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py b/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py
index 7b81784..17619e0 100644
--- a/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py
+++ b/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py
@@ -9,8 +9,8 @@
 from erpnext.stock.get_item_details import get_conversion_factor
 from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
 from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
-from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_receipt
 from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
+from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
 
 class TestPutawayRule(unittest.TestCase):
 	def setUp(self):
@@ -42,17 +42,15 @@
 		rule_2 = create_putaway_rule(item_code="_Rice", warehouse=warehouse_2, capacity=300,
 			uom="Kg", priority=2)
 
-		po = create_purchase_order(item_code="_Rice", qty=300)
-		self.assertEqual(len(po.items), 1)
-
-		pr = make_purchase_receipt(po.name)
+		pr = make_purchase_receipt(item_code="_Rice", qty=300, apply_putaway_rule=1,
+			do_not_submit=1)
 		self.assertEqual(len(pr.items), 2)
 		self.assertEqual(pr.items[0].qty, 200)
 		self.assertEqual(pr.items[0].warehouse, warehouse_1)
 		self.assertEqual(pr.items[1].qty, 100)
 		self.assertEqual(pr.items[1].warehouse, warehouse_2)
 
-		po.cancel()
+		pr.delete()
 		rule_1.delete()
 		rule_2.delete()
 
@@ -70,10 +68,8 @@
 		# out of 500 kg capacity, occupy 100 kg in warehouse_1
 		stock_receipt = make_stock_entry(item_code="_Rice", target=warehouse_1, qty=100, basic_rate=50)
 
-		po = create_purchase_order(item_code="_Rice", qty=700)
-		self.assertEqual(len(po.items), 1)
-
-		pr = make_purchase_receipt(po.name)
+		pr = make_purchase_receipt(item_code="_Rice", qty=700, apply_putaway_rule=1,
+			do_not_submit=1)
 		self.assertEqual(len(pr.items), 2)
 		self.assertEqual(pr.items[0].qty, 500)
 		# warehouse_2 has 500 kg free space, it is given priority
@@ -82,8 +78,8 @@
 		# warehouse_1 has 400 kg free space, it is given less priority
 		self.assertEqual(pr.items[1].warehouse, warehouse_1)
 
-		po.cancel()
 		stock_receipt.cancel()
+		pr.delete()
 		rule_1.delete()
 		rule_2.delete()
 
@@ -97,21 +93,14 @@
 		rule_2 = create_putaway_rule(item_code="_Rice", warehouse=warehouse_2, capacity=200,
 			uom="Kg")
 
-		po = create_purchase_order(item_code="_Rice", qty=350)
-		self.assertEqual(len(po.items), 1)
-
-		pr = make_purchase_receipt(po.name)
-
-		self.assertEqual(len(pr.items), 3)
+		pr = make_purchase_receipt(item_code="_Rice", qty=350, apply_putaway_rule=1,
+			do_not_submit=1)
+		self.assertEqual(len(pr.items), 2)
 		self.assertEqual(pr.items[0].qty, 200)
 		self.assertEqual(pr.items[0].warehouse, warehouse_2)
 		self.assertEqual(pr.items[1].qty, 100)
 		self.assertEqual(pr.items[1].warehouse, warehouse_1)
-		# extra qty has no warehouse assigned
-		self.assertEqual(pr.items[2].qty, 50)
-		self.assertEqual(pr.items[2].warehouse, '')
-
-		po.cancel()
+		pr.delete()
 		rule_1.delete()
 		rule_2.delete()
 
@@ -135,24 +124,19 @@
 			uom="Bag")
 		self.assertEqual(rule_2.stock_capacity, 4000)
 
+		# populate 'Rack 1' with 1 Bag, making the free space 2 Bags
 		stock_receipt = make_stock_entry(item_code="_Rice", target=warehouse_1, qty=1000, basic_rate=50)
 
-		po = create_purchase_order(item_code="_Rice", qty=6, do_not_save=True)
-		po.items[0].uom = "Bag"
-		po.save()
-		po.submit()
-
-		self.assertEqual(po.items[0].stock_qty, 6000)
-
-		pr = make_purchase_receipt(po.name)
+		pr = make_purchase_receipt(item_code="_Rice", qty=6, uom="Bag", stock_uom="Kg",
+			conversion_factor=1000, apply_putaway_rule=1, do_not_submit=1)
 		self.assertEqual(len(pr.items), 2)
 		self.assertEqual(pr.items[0].qty, 4)
 		self.assertEqual(pr.items[0].warehouse, warehouse_2)
 		self.assertEqual(pr.items[1].qty, 2)
 		self.assertEqual(pr.items[1].warehouse, warehouse_1)
 
-		po.cancel()
 		stock_receipt.cancel()
+		pr.delete()
 		rule_1.delete()
 		rule_2.delete()
 
@@ -180,24 +164,15 @@
 		self.assertEqual(rule_2.stock_capacity, 500)
 		# total capacity is 1500 Kg
 
-		po = create_purchase_order(item_code="_Rice", qty=2, do_not_save=True)
-		# PO for 2 Bags (2000 Kg)
-		po.items[0].uom = "Bag"
-		po.save()
-		po.submit()
-
-		self.assertEqual(po.items[0].stock_qty, 2000)
-
-		pr = make_purchase_receipt(po.name)
-		self.assertEqual(len(pr.items), 2)
+		pr = make_purchase_receipt(item_code="_Rice", qty=2, uom="Bag", stock_uom="Kg",
+			conversion_factor=1000, apply_putaway_rule=1, do_not_submit=1)
+		self.assertEqual(len(pr.items), 1)
 		self.assertEqual(pr.items[0].qty, 1)
 		self.assertEqual(pr.items[0].warehouse, warehouse_1)
 		# leftover space was for 500 kg (0.5 Bag)
 		# Since Bag is a whole UOM, 1(out of 2) Bag will be unassigned
-		self.assertEqual(pr.items[1].qty, 1)
-		self.assertEqual(pr.items[1].warehouse, '')
 
-		po.cancel()
+		pr.delete()
 		rule_1.delete()
 		rule_2.delete()
 
@@ -208,38 +183,58 @@
 
 		rule_1 = create_putaway_rule(item_code="_Rice", warehouse=warehouse_1, capacity=200,
 			uom="Kg")
-		rule_2 = create_putaway_rule(item_code="_Rice", warehouse=warehouse_2, capacity=100,
-			uom="Kg", priority=2)
-		# total capacity is 300 Kg
+		# total capacity is 200 Kg
 
-		po = create_purchase_order(item_code="_Rice", qty=200, rate=100, do_not_save=True)
-		po.append("items", {
-			"item_code":"_Rice",
+		pr = make_purchase_receipt(item_code="_Rice", qty=100, apply_putaway_rule=1,
+			do_not_submit=1)
+		pr.append("items", {
+			"item_code": "_Rice",
 			"warehouse": "_Test Warehouse - _TC",
-			"qty": 300,
-			"rate": 120,
-			"schedule_date": add_days(nowdate(), 1),
-		})
-		po.save()
-		po.submit()
-		# PO for 500 Kg (two rows of same item, different rates)
-		self.assertEqual(len(po.items), 2)
-
-		pr = make_purchase_receipt(po.name)
-		self.assertEqual(len(pr.items), 3)
-		self.assertEqual(pr.items[0].qty, 200)
+			"qty": 200,
+			"uom": "Kg",
+			"stock_uom": "Kg",
+			"stock_qty": 200,
+			"received_qty": 200,
+			"rate": 100,
+			"conversion_factor": 1.0,
+		}) # same item entered again in PR but with different rate
+		pr.save()
+		self.assertEqual(len(pr.items), 2)
+		self.assertEqual(pr.items[0].qty, 100)
 		self.assertEqual(pr.items[0].warehouse, warehouse_1)
-		# same rules applied to second item row
+		self.assertEqual(pr.items[0].putaway_rule, rule_1.name)
+		# same rule applied to second item row
 		# with previous assignment considered
-		self.assertEqual(pr.items[1].qty, 100)
-		self.assertEqual(pr.items[1].warehouse, warehouse_2)
-		# unassigned 200 Kg
-		self.assertEqual(pr.items[2].qty, 200)
-		self.assertEqual(pr.items[2].warehouse, '')
+		self.assertEqual(pr.items[1].qty, 100) # 100 unassigned in second row from 200
+		self.assertEqual(pr.items[1].warehouse, warehouse_1)
+		self.assertEqual(pr.items[1].putaway_rule, rule_1.name)
 
-		po.cancel()
+		pr.delete()
 		rule_1.delete()
-		rule_2.delete()
+
+	def test_validate_over_receipt_in_warehouse(self):
+		"""Test if overreceipt is blocked in the presence of putaway rules."""
+		warehouse_1 = frappe.db.get_value("Warehouse", {"warehouse_name": "Rack 1"})
+		warehouse_2 = frappe.db.get_value("Warehouse", {"warehouse_name": "Rack 2"})
+
+		rule_1 = create_putaway_rule(item_code="_Rice", warehouse=warehouse_1, capacity=200,
+			uom="Kg")
+
+		pr = make_purchase_receipt(item_code="_Rice", qty=300, apply_putaway_rule=1,
+			do_not_submit=1)
+		self.assertEqual(len(pr.items), 1)
+		self.assertEqual(pr.items[0].qty, 200) # 100 is unassigned fro 300 Kg
+		self.assertEqual(pr.items[0].warehouse, warehouse_1)
+		self.assertEqual(pr.items[0].putaway_rule, rule_1.name)
+
+		# force overreceipt and disable apply putaway rule in PR
+		pr.items[0].qty = 300
+		pr.items[0].stock_qty = 300
+		pr.apply_putaway_rule = 0
+		self.assertRaises(frappe.ValidationError, pr.save)
+
+		pr.delete()
+		rule_1.delete()
 
 def create_putaway_rule(**args):
 	args = frappe._dict(args)
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index f07039f..aed69e1 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -42,7 +42,7 @@
 		for item in self.get("items"):
 			item.update(get_bin_details(item.item_code, item.s_warehouse))
 
-	def before_save(self):
+	def before_validate(self):
 		from erpnext.stock.doctype.putaway_rule.putaway_rule import apply_putaway_rule
 		apply_rule = self.apply_putaway_rule and (self.purpose in ["Material Transfer", "Material Receipt"])