[optimize]: bin updates (#15108)

diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py
index efa6c14..f86a77d 100644
--- a/erpnext/stock/doctype/bin/bin.py
+++ b/erpnext/stock/doctype/bin/bin.py
@@ -8,19 +8,11 @@
 from frappe.model.document import Document
 
 class Bin(Document):
-	def validate(self):
+	def before_save(self):
 		if self.get("__islocal") or not self.stock_uom:
-			self.stock_uom = frappe.db.get_value('Item', self.item_code, 'stock_uom')
-
-		self.validate_mandatory()
+			self.stock_uom = frappe.get_cached_value('Item', self.item_code, 'stock_uom')
 		self.set_projected_qty()
 
-	def validate_mandatory(self):
-		qf = ['actual_qty', 'reserved_qty', 'ordered_qty', 'indented_qty']
-		for f in qf:
-			if (not getattr(self, f, None)) or (not self.get(f)):
-				self.set(f, 0.0)
-
 	def update_stock(self, args, allow_negative_stock=False, via_landed_cost_voucher=False):
 		'''Called from erpnext.stock.utils.update_bin'''
 		self.update_qty(args)
diff --git a/erpnext/stock/stock_balance.py b/erpnext/stock/stock_balance.py
index 90c82c4..09d4e43 100644
--- a/erpnext/stock/stock_balance.py
+++ b/erpnext/stock/stock_balance.py
@@ -148,11 +148,9 @@
 			mismatch = True
 
 	if mismatch:
-		bin.projected_qty = (flt(bin.actual_qty) + flt(bin.ordered_qty) +
-			flt(bin.indented_qty) + flt(bin.planned_qty) - flt(bin.reserved_qty)
-			- flt(bin.reserved_qty_for_production)) - flt(bin.reserved_qty_for_sub_contract)
-
-		bin.save()
+		bin.set_projected_qty()
+		bin.db_update()
+		bin.clear_cache()
 
 def set_stock_balance_as_per_serial_no(item_code=None, posting_date=None, posting_time=None,
 	 	fiscal_year=None):