fix(sync): dashboard sync covers current year plus Nov-Dec of previous
/sync-bank now uses one shared default window in both implementations: 1 November of the previous year to 31 December of the current year. Payments dated around New Year are picked up in January; duplicates are still filtered by Sync ID. Python used a hardcoded 2026 window and would have stopped syncing on 2027-01-01; Go used the current calendar year only. Adds make sync-year [YEAR=N] with the same window. The CLI default without flags (last 30 days) is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+6
-5
@@ -30,7 +30,7 @@ from views import (
|
||||
adapt_junior_members,
|
||||
)
|
||||
from cache_utils import get_sheet_modified_time, read_cache, write_cache, _LAST_CHECKED, flush_cache
|
||||
from sync_fio_to_sheets import sync_to_sheets
|
||||
from sync_fio_to_sheets import sync_to_sheets, default_sync_window
|
||||
from infer_payments import infer_payments
|
||||
|
||||
def get_cached_data(cache_key, sheet_id, fetch_func, *args, serialize=None, deserialize=None, **kwargs):
|
||||
@@ -128,13 +128,14 @@ def sync_bank():
|
||||
success = True
|
||||
try:
|
||||
with contextlib.redirect_stdout(output), contextlib.redirect_stderr(output):
|
||||
# sync_to_sheets: equivalent of make sync-2026
|
||||
output.write("=== Syncing Fio transactions (2026) ===\n")
|
||||
# sync_to_sheets: equivalent of make sync-year (same default window as Go)
|
||||
date_from, date_to = default_sync_window()
|
||||
output.write(f"=== Syncing Fio transactions ({date_from} to {date_to}) ===\n")
|
||||
sync_to_sheets(
|
||||
spreadsheet_id=PAYMENTS_SHEET_ID,
|
||||
credentials_path=CREDENTIALS_PATH,
|
||||
date_from_str="2026-01-01",
|
||||
date_to_str="2026-12-31",
|
||||
date_from_str=date_from,
|
||||
date_to_str=date_to,
|
||||
sort_by_date=True,
|
||||
)
|
||||
output.write("\n=== Inferring payment details ===\n")
|
||||
|
||||
@@ -59,6 +59,18 @@ def get_sheets_service(credentials_path: str):
|
||||
return _SHEETS_SERVICE
|
||||
|
||||
|
||||
def default_sync_window(today=None) -> tuple[str, str]:
|
||||
"""Window used by the dashboard sync, as (from, to) in YYYY-MM-DD.
|
||||
|
||||
The whole current calendar year plus the last two months of the previous
|
||||
one, so payments dated around New Year are still picked up in January.
|
||||
Re-fetching is safe because rows are deduplicated by Sync ID.
|
||||
Mirrors DefaultWindow in go/internal/services/banksync/sync.go.
|
||||
"""
|
||||
year = (today or datetime.now()).year
|
||||
return f"{year - 1}-11-01", f"{year}-12-31"
|
||||
|
||||
|
||||
def as_text_cell(value) -> str:
|
||||
"""Mark a value to be stored as text when written with USER_ENTERED.
|
||||
|
||||
|
||||
@@ -23,6 +23,20 @@ class TestWebApp(unittest.TestCase):
|
||||
app.config['TESTING'] = True
|
||||
self.client = app.test_client()
|
||||
|
||||
@patch('app.flush_cache', return_value=0)
|
||||
@patch('app.infer_payments')
|
||||
@patch('app.sync_to_sheets')
|
||||
def test_sync_bank_uses_default_window(self, mock_sync, mock_infer, mock_flush):
|
||||
"""/sync-bank syncs the current year plus Nov-Dec of the previous one, not a hardcoded year."""
|
||||
from datetime import datetime
|
||||
year = datetime.now().year
|
||||
response = self.client.get('/sync-bank')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
kwargs = mock_sync.call_args.kwargs
|
||||
self.assertEqual(kwargs['date_from_str'], f"{year - 1}-11-01")
|
||||
self.assertEqual(kwargs['date_to_str'], f"{year}-12-31")
|
||||
mock_infer.assert_called_once()
|
||||
|
||||
def test_index_page(self):
|
||||
"""Test that / returns the refresh meta tag"""
|
||||
response = self.client.get('/')
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
import contextlib
|
||||
import io
|
||||
import unittest
|
||||
from datetime import datetime
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from scripts.sync_fio_to_sheets import COLUMN_LABELS, as_text_cell, sync_to_sheets
|
||||
from scripts.sync_fio_to_sheets import COLUMN_LABELS, as_text_cell, default_sync_window, sync_to_sheets
|
||||
|
||||
|
||||
class TestDefaultSyncWindow(unittest.TestCase):
|
||||
def test_current_year_plus_last_two_months_of_previous(self):
|
||||
self.assertEqual(default_sync_window(datetime(2026, 10, 8)), ("2025-11-01", "2026-12-31"))
|
||||
self.assertEqual(default_sync_window(datetime(2027, 1, 1)), ("2026-11-01", "2027-12-31"))
|
||||
self.assertEqual(default_sync_window(datetime(2027, 12, 31)), ("2026-11-01", "2027-12-31"))
|
||||
|
||||
|
||||
class TestAsTextCell(unittest.TestCase):
|
||||
|
||||
Reference in New Issue
Block a user