Merge pull request #29609 from deepeshgarg007/gstr_3b_export_zero_rated

fix: Zero rated exports in GSTR-3B report
diff --git a/erpnext/accounts/report/balance_sheet/balance_sheet.py b/erpnext/accounts/report/balance_sheet/balance_sheet.py
index dc1f7aa..f10a5ea 100644
--- a/erpnext/accounts/report/balance_sheet/balance_sheet.py
+++ b/erpnext/accounts/report/balance_sheet/balance_sheet.py
@@ -120,11 +120,11 @@
 	opening_balance = 0
 	float_precision = cint(frappe.db.get_default("float_precision")) or 2
 	if asset:
-		opening_balance = flt(asset[0].get("opening_balance", 0), float_precision)
+		opening_balance = flt(asset[-1].get("opening_balance", 0), float_precision)
 	if liability:
-		opening_balance -= flt(liability[0].get("opening_balance", 0), float_precision)
+		opening_balance -= flt(liability[-1].get("opening_balance", 0), float_precision)
 	if equity:
-		opening_balance -= flt(equity[0].get("opening_balance", 0), float_precision)
+		opening_balance -= flt(equity[-1].get("opening_balance", 0), float_precision)
 
 	opening_balance = flt(opening_balance, float_precision)
 	if opening_balance:
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index 03ae0ae..db28cdf 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -282,7 +282,8 @@
 	total_row = {
 		"account_name": _("Total {0} ({1})").format(_(root_type), _(balance_must_be)),
 		"account": _("Total {0} ({1})").format(_(root_type), _(balance_must_be)),
-		"currency": company_currency
+		"currency": company_currency,
+		"opening_balance": 0.0
 	}
 
 	for row in out:
@@ -294,6 +295,7 @@
 
 			total_row.setdefault("total", 0.0)
 			total_row["total"] += flt(row["total"])
+			total_row["opening_balance"] += row["opening_balance"]
 			row["total"] = ""
 
 	if "total" in total_row:
diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py
index 76a7cda..affde4a 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -400,6 +400,16 @@
 			ref_doc = frappe.get_doc(ref_dt, ref_dn)
 
 			ref_doc.db_set("per_billed", per_billed)
+
+			# set billling status
+			if hasattr(ref_doc, 'billing_status'):
+				if ref_doc.per_billed < 0.001:
+					ref_doc.db_set("billing_status", "Not Billed")
+				elif ref_doc.per_billed > 99.999999:
+					ref_doc.db_set("billing_status", "Fully Billed")
+				else:
+					ref_doc.db_set("billing_status", "Partly Billed")
+
 			ref_doc.set_status(update=True)
 
 def get_allowance_for(item_code, item_allowance=None, global_qty_allowance=None, global_amount_allowance=None, qty_or_amount="qty"):
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index 42bc0b7..acf048e 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -1375,6 +1375,30 @@
 
 		automatically_fetch_payment_terms(enable=0)
 
+	def test_zero_amount_sales_order_billing_status(self):
+		from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+
+		so = make_sales_order(uom="Nos", do_not_save=1)
+		so.items[0].rate = 0
+		so.save()
+		so.submit()
+
+		self.assertEqual(so.net_total, 0)
+		self.assertEqual(so.billing_status, 'Not Billed')
+
+		si = create_sales_invoice(qty=10, do_not_save=1)
+		si.price_list = '_Test Price List'
+		si.items[0].rate = 0
+		si.items[0].price_list_rate = 0
+		si.items[0].sales_order = so.name
+		si.items[0].so_detail = so.items[0].name
+		si.save()
+		si.submit()
+
+		self.assertEqual(si.net_total, 0)
+		so.load_from_db()
+		self.assertEqual(so.billing_status, 'Fully Billed')
+
 def automatically_fetch_payment_terms(enable=1):
 	accounts_settings = frappe.get_doc("Accounts Settings")
 	accounts_settings.automatically_fetch_payment_terms = enable