Files
Ten31-Portal/backend/tests/test_pending_reimport.py
Jonathan Kirkwood 34842cd994 Add startup re-import queue to apply importer fixes to signed rounds
The loan-aware NAV fix (0.2.47) only affects new imports; an already-signed
quarter keeps its old holdings until re-imported. Add a boot-time queue: an
operator stages an eNAV plus a small JSON descriptor under
data/pending_reimports and the app re-imports it on startup via the same code
path as the admin Import screen, then removes the processed files. Guarded so a
queue problem never blocks boot. Bumps the package to 0.2.48.

Used to refresh SATS Credit Fund LP Q4 2025 to its full NAV including the
Fold Holdings loan.
2026-09-02 09:35:54 -05:00

52 lines
1.9 KiB
Python

"""The startup re-import queue: a staged eNAV is imported on boot, then deleted.
This is how an importer fix (e.g. loan-schedule parsing) gets applied to an
already-signed round without a manual admin re-upload.
"""
import json
from sqlmodel import select
import ten31portal.database as db
from ten31portal import config
from ten31portal.models import Entity, EntityType, UserRole, Valuation, ValuationRound
from ten31portal.pending_reimports import process_pending_reimports
from tests.conftest import make_user
from tests.test_loan_import import _enav_with_loan
def test_pending_reimport_drains_and_applies(session, monkeypatch, tmp_path):
monkeypatch.setattr(config, "DB_PATH", str(tmp_path / "portal.db"))
monkeypatch.setattr(db, "engine", session.get_bind())
make_user(session, username="approver", role=UserRole.approver)
fund = Entity(name="SATS Credit Fund LP", type=EntityType.fund)
session.add(fund)
session.commit()
session.refresh(fund)
queue = tmp_path / "pending_reimports"
queue.mkdir()
(queue / "sats.xlsx").write_bytes(_enav_with_loan())
(queue / "sats.json").write_text(json.dumps({"entity_id": fund.id}))
process_pending_reimports()
# The round now includes the loan valuation; NAV = securities + loan (principal + accrued).
rnd = session.exec(select(ValuationRound).where(ValuationRound.entity_id == fund.id)).one()
nav = sum(
v.value_cents
for v in session.exec(select(Valuation).where(Valuation.round_id == rnd.id)).all()
)
assert nav == 1_639_942_63 + 0 + 46_494_185_46
# Processed files are removed so the import runs exactly once (the JSON carries a password).
assert not (queue / "sats.xlsx").exists()
assert not (queue / "sats.json").exists()
def test_no_queue_dir_is_a_noop(monkeypatch, tmp_path):
monkeypatch.setattr(config, "DB_PATH", str(tmp_path / "portal.db"))
process_pending_reimports() # must not raise when the queue dir is absent