From 851f2af2c13ecec3b4567f9a6e01f8c3dde1bc5e Mon Sep 17 00:00:00 2001 From: Antonio Gurgel Date: Mon, 16 Feb 2026 18:02:17 -0800 Subject: [PATCH 1/5] Create error type --- beancount_reds_plugins/effective_date/effective_date.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/beancount_reds_plugins/effective_date/effective_date.py b/beancount_reds_plugins/effective_date/effective_date.py index 8923db9..28821b4 100644 --- a/beancount_reds_plugins/effective_date/effective_date.py +++ b/beancount_reds_plugins/effective_date/effective_date.py @@ -7,6 +7,7 @@ import string import sys import time +from typing import NamedTuple from beancount.core import data from beancount_reds_plugins.common import common @@ -18,6 +19,10 @@ LINK_FORMAT = 'edate-{date}-{random}' +class EffectiveDateError(NamedTuple): + source: data.Meta + message: str + entry: data.Directive def has_valid_effective_date(posting): return posting.meta is not None and \ From 9f7e709a747c60834d2f65b29bee51124ef11903 Mon Sep 17 00:00:00 2001 From: Antonio Gurgel Date: Mon, 16 Feb 2026 18:02:25 -0800 Subject: [PATCH 2/5] Append error if invalid date encountered --- .../effective_date/effective_date.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/beancount_reds_plugins/effective_date/effective_date.py b/beancount_reds_plugins/effective_date/effective_date.py index 28821b4..73d1311 100644 --- a/beancount_reds_plugins/effective_date/effective_date.py +++ b/beancount_reds_plugins/effective_date/effective_date.py @@ -117,10 +117,19 @@ def effective_date(entries, options_map, config): if posting.account.startswith(acct): found_acct = acct - # find earlier or later (is this necessary?) - holding_account = holding_accts[found_acct]['earlier'] - if posting.meta['effective_date'] > entry.date: + # Find earlier or later + if posting.meta['effective_date'] < entry.date: + holding_account = holding_accts[found_acct]['earlier'] + elif posting.meta['effective_date'] > entry.date: holding_account = holding_accts[found_acct]['later'] + else: + errors.append( + EffectiveDateError( + entry.meta, + "Effective and actual dates are identical", + entry + ) + ) # Replace posting in original entry with holding account new_posting = posting._replace(account=posting.account.replace(found_acct, holding_account)) From fd215509262ed23b7b8449dbef997866115a8e1a Mon Sep 17 00:00:00 2001 From: Antonio Gurgel Date: Mon, 16 Feb 2026 18:14:19 -0800 Subject: [PATCH 3/5] Don't let `new_entries` get mangled by invalid output Shunt entries with meaningless e-dates to `filtered_entries`; this way, only valid entries go through the extensive computations in line 128 and thereafter. --- .../effective_date/effective_date.py | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/beancount_reds_plugins/effective_date/effective_date.py b/beancount_reds_plugins/effective_date/effective_date.py index 73d1311..2373af6 100644 --- a/beancount_reds_plugins/effective_date/effective_date.py +++ b/beancount_reds_plugins/effective_date/effective_date.py @@ -36,6 +36,13 @@ def has_posting_with_valid_effective_date(entry): return True return False +def has_posting_with_meaningless_effective_date(entry): + for posting in entry.postings: + if has_valid_effective_date(posting) \ + and posting.meta['effective_date'] == entry.date: + return True + return False + def create_new_effective_date_entry(entry, date, hold_posting, original_posting): def cleaned(p): @@ -85,7 +92,17 @@ def effective_date(entries, options_map, config): new_accounts = set() for entry in entries: if isinstance(entry, data.Transaction) and has_posting_with_valid_effective_date(entry): - interesting_entries.append(entry) + if not has_posting_with_meaningless_effective_date(entry): + interesting_entries.append(entry) + else: + errors.append( + EffectiveDateError( + entry.meta, + "Effective and actual dates are identical", + entry + ) + ) + filtered_entries.append(entry) else: filtered_entries.append(entry) @@ -122,14 +139,6 @@ def effective_date(entries, options_map, config): holding_account = holding_accts[found_acct]['earlier'] elif posting.meta['effective_date'] > entry.date: holding_account = holding_accts[found_acct]['later'] - else: - errors.append( - EffectiveDateError( - entry.meta, - "Effective and actual dates are identical", - entry - ) - ) # Replace posting in original entry with holding account new_posting = posting._replace(account=posting.account.replace(found_acct, holding_account)) From eaa73643918505cd90bbfe84c5070d9b99913f74 Mon Sep 17 00:00:00 2001 From: Antonio Gurgel Date: Mon, 16 Feb 2026 18:15:52 -0800 Subject: [PATCH 4/5] Add test case --- .../effective_date/test_effective_date.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/beancount_reds_plugins/effective_date/test_effective_date.py b/beancount_reds_plugins/effective_date/test_effective_date.py index 7e023bf..d61a76e 100644 --- a/beancount_reds_plugins/effective_date/test_effective_date.py +++ b/beancount_reds_plugins/effective_date/test_effective_date.py @@ -142,3 +142,18 @@ def test_expense_later_multiple(self, entries, _, options_map): new_entries, _ = effective_date(entries, options_map, None) self.assertEqual(7, len(new_entries)) + + @loader.load_doc() + def test_meaningless_effective_dates(self, entries, _, options_map): + """ + 2014-01-01 open Liabilities:Mastercard + 2014-01-01 open Expenses:Taxes:Federal + + 2014-02-01 * "Estimated taxes for 2013" + Liabilities:Mastercard -2000 USD + Expenses:Taxes:Federal 2000 USD + effective_date: 2014-02-01 + """ + new_entries, errors = effective_date(entries, options_map, None) + self.assertEqual(1, len(errors)) + self.assertEqual(new_entries, entries) From 42b1b95b31f6023f7fd6a174ed955f426c1f97e2 Mon Sep 17 00:00:00 2001 From: Antonio Gurgel Date: Mon, 16 Feb 2026 18:25:50 -0800 Subject: [PATCH 5/5] Fix leftover hunk from 9f7e709 --- beancount_reds_plugins/effective_date/effective_date.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/beancount_reds_plugins/effective_date/effective_date.py b/beancount_reds_plugins/effective_date/effective_date.py index 2373af6..93c40de 100644 --- a/beancount_reds_plugins/effective_date/effective_date.py +++ b/beancount_reds_plugins/effective_date/effective_date.py @@ -134,10 +134,9 @@ def effective_date(entries, options_map, config): if posting.account.startswith(acct): found_acct = acct - # Find earlier or later - if posting.meta['effective_date'] < entry.date: - holding_account = holding_accts[found_acct]['earlier'] - elif posting.meta['effective_date'] > entry.date: + # find earlier or later (is this necessary?) + holding_account = holding_accts[found_acct]['earlier'] + if posting.meta['effective_date'] > entry.date: holding_account = holding_accts[found_acct]['later'] # Replace posting in original entry with holding account