data: Add Account.is_open_on_date() method.
This commit is contained in:
parent
a0372d4b73
commit
4483d76999
2 changed files with 62 additions and 2 deletions
|
@ -250,6 +250,22 @@ class Account(str):
|
|||
def is_credit_card(self) -> bool:
|
||||
return self.is_under('Liabilities:CreditCard') is not None
|
||||
|
||||
def is_open_on_date(self, date: datetime.date) -> Optional[bool]:
|
||||
"""Return true if this account is open on the given date.
|
||||
|
||||
This method considers the dates on the account's open and close
|
||||
directives. If there is no close directive, it just checks the date is
|
||||
on or after the opening date. If neither exists, returns None.
|
||||
"""
|
||||
try:
|
||||
meta = self.meta
|
||||
except KeyError:
|
||||
return None
|
||||
close_date = meta.close_date
|
||||
if close_date is None:
|
||||
close_date = date + datetime.timedelta(days=1)
|
||||
return meta.open_date <= date < close_date
|
||||
|
||||
def is_opening_equity(self) -> bool:
|
||||
return self.is_under('Equity:Funds', 'Equity:OpeningBalance') is not None
|
||||
|
||||
|
|
|
@ -14,17 +14,17 @@
|
|||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import datetime
|
||||
import pytest
|
||||
|
||||
from . import testutil
|
||||
|
||||
from datetime import date as Date
|
||||
|
||||
from beancount.core.data import Open, Close, Booking
|
||||
from beancount.parser import options as bc_options
|
||||
|
||||
from conservancy_beancount import data
|
||||
|
||||
Date = datetime.date
|
||||
clean_account_meta = pytest.fixture()(testutil.clean_account_meta)
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -160,6 +160,50 @@ def test_is_credit_card(acct_name, expected):
|
|||
def test_is_opening_equity(acct_name, expected):
|
||||
assert data.Account(acct_name).is_opening_equity() == expected
|
||||
|
||||
@pytest.mark.parametrize('date', [
|
||||
testutil.PAST_DATE,
|
||||
testutil.FY_START_DATE,
|
||||
testutil.FY_MID_DATE,
|
||||
testutil.FUTURE_DATE,
|
||||
])
|
||||
def test_is_open_on_date_without_opening(date):
|
||||
account = data.Account('Assets:Cash')
|
||||
assert account.is_open_on_date(date) is None
|
||||
|
||||
@pytest.mark.parametrize('days_diff', range(-2, 3))
|
||||
def test_is_open_on_date_without_closing(clean_account_meta, days_diff):
|
||||
open_date = testutil.FY_START_DATE
|
||||
acct_name = 'Assets:Checking'
|
||||
data.Account.load_opening(Open({}, open_date, acct_name, None, None))
|
||||
account = data.Account(acct_name)
|
||||
check_date = open_date + datetime.timedelta(days=days_diff)
|
||||
assert account.is_open_on_date(check_date) == (days_diff >= 0)
|
||||
|
||||
@pytest.mark.parametrize('close_diff,check_diff', [
|
||||
(30, -30),
|
||||
(30, -1),
|
||||
(30, 0),
|
||||
(30, 1),
|
||||
(30, 29),
|
||||
(30, 30),
|
||||
(30, 60),
|
||||
(60, 30),
|
||||
(60, 59),
|
||||
(60, 60),
|
||||
(60, 90),
|
||||
(60, -60),
|
||||
])
|
||||
def test_is_open_on_date_with_closing(clean_account_meta, close_diff, check_diff):
|
||||
open_date = testutil.FY_START_DATE
|
||||
acct_name = 'Assets:Savings'
|
||||
data.Account.load_opening(Open({}, open_date, acct_name, None, None))
|
||||
close_date = open_date + datetime.timedelta(days=close_diff)
|
||||
data.Account.load_closing(Close({}, close_date, acct_name))
|
||||
account = data.Account(acct_name)
|
||||
check_date = open_date + datetime.timedelta(days=check_diff)
|
||||
expected = (0 <= check_diff < close_diff)
|
||||
assert account.is_open_on_date(check_date) == expected
|
||||
|
||||
@pytest.mark.parametrize('acct_name', [
|
||||
'Assets:Cash',
|
||||
'Assets:Prepaid:Expenses',
|
||||
|
|
Loading…
Reference in a new issue