Merge pull request #30950 from marination/actual-qty-total-js-reactive

fix: Set actual qty and basic rate in SE on warehouse triggers (`get_warehouse_details`)
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index 5860c4c..9189f18 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -637,6 +637,8 @@
 						}
 					}
 					stock_entry.add_to_stock_entry_detail(items_dict)
+
+		stock_entry.set_missing_values()
 		return stock_entry.as_dict()
 	else:
 		frappe.throw(_("No Items selected for transfer"))
@@ -724,7 +726,7 @@
 			add_items_in_ste(ste_doc, value, value.qty, po_details)
 
 	ste_doc.set_stock_entry_type()
-	ste_doc.calculate_rate_and_amount()
+	ste_doc.set_missing_values()
 
 	return ste_doc
 
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py
index bf4f82f..a98fc94 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/job_card.py
@@ -764,8 +764,6 @@
 		pending_fg_qty = flt(source.get("for_quantity", 0)) - flt(source.get("transferred_qty", 0))
 		target.fg_completed_qty = pending_fg_qty if pending_fg_qty > 0 else 0
 
-		target.set_transfer_qty()
-		target.calculate_rate_and_amount()
 		target.set_missing_values()
 		target.set_stock_entry_type()
 
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 767221e..c3812f3 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -1384,12 +1384,15 @@
 		var me = this;
 		var args = this._get_args(item);
 		if (!(args.items && args.items.length)) {
-			if(calculate_taxes_and_totals) me.calculate_taxes_and_totals();
+			if (calculate_taxes_and_totals) me.calculate_taxes_and_totals();
 			return;
 		}
 
 		// Target doc created from a mapped doc
 		if (this.frm.doc.__onload && this.frm.doc.__onload.ignore_price_list) {
+			// Calculate totals even though pricing rule is not applied.
+			// `apply_pricing_rule` is triggered due to change in data which most likely contributes to Total.
+			if (calculate_taxes_and_totals) me.calculate_taxes_and_totals();
 			return;
 		}
 
diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py
index a70ff17..c998629 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -597,7 +597,7 @@
 		if source.material_request_type == "Customer Provided":
 			target.purpose = "Material Receipt"
 
-		target.run_method("calculate_rate_and_amount")
+		target.set_missing_values()
 		target.set_stock_entry_type()
 		target.set_job_card_data()
 
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 6b0e928..7dc3ba0 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -679,8 +679,7 @@
 	else:
 		stock_entry = update_stock_entry_items_with_no_reference(pick_list, stock_entry)
 
-	stock_entry.set_actual_qty()
-	stock_entry.calculate_rate_and_amount()
+	stock_entry.set_missing_values()
 
 	return stock_entry.as_dict()
 
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index ec0e809..fcf0cd1 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -1036,6 +1036,7 @@
 	def set_missing_values(source, target):
 		target.stock_entry_type = "Material Transfer"
 		target.purpose = "Material Transfer"
+		target.set_missing_values()
 
 	doclist = get_mapped_doc(
 		"Purchase Receipt",
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index 1df56ef..540ad18 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -470,7 +470,9 @@
 				},
 				callback: function(r) {
 					if (!r.exc) {
-						$.extend(child, r.message);
+						["actual_qty", "basic_rate"].forEach((field) => {
+							frappe.model.set_value(cdt, cdn, field, (r.message[field] || 0.0));
+						});
 						frm.events.calculate_basic_amount(frm, child);
 					}
 				}
@@ -1057,8 +1059,8 @@
 
 function check_should_not_attach_bom_items(bom_no) {
   return (
-    bom_no === undefined ||
-    (erpnext.stock.bom && erpnext.stock.bom.name === bom_no)
+	bom_no === undefined ||
+	(erpnext.stock.bom && erpnext.stock.bom.name === bom_no)
   );
 }
 
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 27a6eaf..2a7354d 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -2197,6 +2197,12 @@
 
 		return sorted(list(set(get_serial_nos(self.pro_doc.serial_no)) - set(used_serial_nos)))
 
+	def set_missing_values(self):
+		"Updates rate and availability of all the items of mapped doc."
+		self.set_transfer_qty()
+		self.set_actual_qty()
+		self.calculate_rate_and_amount()
+
 
 @frappe.whitelist()
 def move_sample_to_retention_warehouse(company, items):
@@ -2246,6 +2252,7 @@
 def make_stock_in_entry(source_name, target_doc=None):
 	def set_missing_values(source, target):
 		target.set_stock_entry_type()
+		target.set_missing_values()
 
 	def update_item(source_doc, target_doc, source_parent):
 		target_doc.t_warehouse = ""
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry_utils.py b/erpnext/stock/doctype/stock_entry/stock_entry_utils.py
index b3df728..c5c0cef 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry_utils.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry_utils.py
@@ -132,6 +132,7 @@
 	)
 
 	s.set_stock_entry_type()
+
 	if not args.do_not_save:
 		s.insert()
 		if not args.do_not_submit:
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index b9c57c1..71baf9f 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -1424,6 +1424,25 @@
 
 		self.assertRaises(frappe.ValidationError, se.save)
 
+	def test_mapped_stock_entry(self):
+		"Check if rate and stock details are populated in mapped SE given warehouse."
+		from erpnext.stock.doctype.purchase_receipt.purchase_receipt import make_stock_entry
+		from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
+
+		item_code = "_TestMappedItem"
+		create_item(item_code, is_stock_item=True)
+
+		pr = make_purchase_receipt(
+			item_code=item_code, qty=2, rate=100, company="_Test Company", warehouse="Stores - _TC"
+		)
+
+		mapped_se = make_stock_entry(pr.name)
+
+		self.assertEqual(mapped_se.items[0].s_warehouse, "Stores - _TC")
+		self.assertEqual(mapped_se.items[0].actual_qty, 2)
+		self.assertEqual(mapped_se.items[0].basic_rate, 100)
+		self.assertEqual(mapped_se.items[0].basic_amount, 200)
+
 
 def make_serialized_item(**args):
 	args = frappe._dict(args)