test: add coverage for Share Balance report

This commit is contained in:
Nabin Hait
2026-07-01 21:13:02 +05:30
parent 0f65004626
commit 02460b4684

View File

@@ -0,0 +1,153 @@
# Copyright (c) 2026, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import frappe
from erpnext.accounts.report.share_balance.share_balance import execute
from erpnext.tests.utils import ERPNextTestSuite
COMPANY = "_Test Company"
class TestShareBalanceReport(ERPNextTestSuite):
def setUp(self):
self.share_type = create_share_type("_Test Share Balance Equity")
self.shareholder = create_shareholder("_Test Share Balance Holder", COMPANY)
def test_date_filter_is_mandatory(self):
self.assertRaises(frappe.ValidationError, execute, frappe._dict({"shareholder": self.shareholder}))
def test_no_shareholder_returns_empty_data(self):
# `shareholder` is optional; without it the report yields no rows.
columns, data = execute(frappe._dict({"date": "2026-06-01", "company": COMPANY}))
self.assertEqual(data, [])
self.assertEqual(len(columns), 5)
def test_balance_after_issue(self):
create_share_transfer(
transfer_type="Issue",
to_shareholder=self.shareholder,
share_type=self.share_type,
from_no=1,
to_no=100,
no_of_shares=100,
rate=10,
date="2026-06-01",
)
row = self.get_row(date="2026-06-05")
self.assertEqual(row[0], self.shareholder)
self.assertEqual(row[1], self.share_type)
self.assertEqual(row[2], 100) # no_of_shares
self.assertEqual(row[3], 10) # average rate
self.assertEqual(row[4], 1000) # amount = 100 * 10
def test_balance_increases_on_second_issue(self):
create_share_transfer(
transfer_type="Issue",
to_shareholder=self.shareholder,
share_type=self.share_type,
from_no=1,
to_no=100,
no_of_shares=100,
rate=10,
date="2026-06-01",
)
create_share_transfer(
transfer_type="Issue",
to_shareholder=self.shareholder,
share_type=self.share_type,
from_no=101,
to_no=200,
no_of_shares=100,
rate=20,
date="2026-06-10",
)
# The report groups by share type, summing shares and amount and
# recomputing the average rate: (1000 + 2000) / 200 = 15.
row = self.get_row(date="2026-06-15")
self.assertEqual(row[2], 200)
self.assertEqual(row[3], 15)
self.assertEqual(row[4], 3000)
def test_balance_reduces_after_transfer_out(self):
other_holder = create_shareholder("_Test Share Balance Holder 2", COMPANY)
create_share_transfer(
transfer_type="Issue",
to_shareholder=self.shareholder,
share_type=self.share_type,
from_no=1,
to_no=100,
no_of_shares=100,
rate=10,
date="2026-06-01",
)
create_share_transfer(
transfer_type="Transfer",
from_shareholder=self.shareholder,
to_shareholder=other_holder,
share_type=self.share_type,
from_no=1,
to_no=40,
no_of_shares=40,
rate=10,
date="2026-06-10",
)
row = self.get_row(date="2026-06-15")
self.assertEqual(row[2], 60) # 100 issued - 40 transferred out
self.assertEqual(row[4], 600)
other_row = self.get_row(date="2026-06-15", shareholder=other_holder)
self.assertEqual(other_row[2], 40)
self.assertEqual(other_row[4], 400)
def test_report_reflects_current_balance_regardless_of_date(self):
# NOTE: the report reads the Shareholder's current `share_balance` table
# and does NOT actually filter by the `date` value (it is required but
# unused in the computation). So an as-on date before the issue still
# shows the current holding rather than 0. This asserts the real
# behavior and flags the missing date-based filtering.
create_share_transfer(
transfer_type="Issue",
to_shareholder=self.shareholder,
share_type=self.share_type,
from_no=1,
to_no=100,
no_of_shares=100,
rate=10,
date="2026-06-01",
)
row = self.get_row(date="2020-01-01") # long before the issue
self.assertEqual(row[2], 100)
def get_row(self, date, shareholder=None):
filters = frappe._dict(
{"date": date, "company": COMPANY, "shareholder": shareholder or self.shareholder}
)
data = execute(filters)[1]
holdings = [r for r in data if r[1] == self.share_type]
self.assertEqual(len(holdings), 1, f"Expected one row for share type, got: {data}")
return holdings[0]
def create_share_type(title):
if not frappe.db.exists("Share Type", title):
frappe.get_doc({"doctype": "Share Type", "title": title}).insert()
return title
def create_shareholder(title, company):
shareholder = frappe.get_doc({"doctype": "Shareholder", "title": title, "company": company}).insert()
return shareholder.name
def create_share_transfer(**kwargs):
kwargs.setdefault("company", COMPANY)
kwargs.setdefault("asset_account", "Cash - _TC")
kwargs.setdefault("equity_or_liability_account", "Creditors - _TC")
transfer = frappe.get_doc({"doctype": "Share Transfer", **kwargs})
transfer.submit()
return transfer