Browse Source

fix: order reconciliation statuses by recency

master
Codex 2 months ago
parent
commit
8a36652bc8
  1. 16
      finance/reconciliation.py
  2. 59
      tests/finance/test_reconciliation.py

16
finance/reconciliation.py

@ -5,8 +5,8 @@ from datetime import date
from decimal import Decimal
from uuid import UUID
from django.db.models import DecimalField, Sum, Value
from django.db.models.functions import Coalesce
from django.db.models import DecimalField, F, Sum, Value, Window
from django.db.models.functions import Coalesce, RowNumber
from finance.models import ReconciliationCheckpoint, Transaction
@ -82,7 +82,13 @@ def latest_checkpoint_statuses(currency: str) -> list[CheckpointStatus]:
checkpoints = ReconciliationCheckpoint.objects.filter(
account__archived=False,
account__currency=currency,
).select_related("account").order_by(
"account_id", "-as_of_date", "-created_at", "-id"
).distinct("account_id")
).annotate(
account_rank=Window(
expression=RowNumber(),
partition_by=[F("account_id")],
order_by=["-as_of_date", "-created_at", "-id"],
)
).filter(account_rank=1).select_related("account").order_by(
"-as_of_date", "-created_at", "-id"
)
return [checkpoint_status(checkpoint) for checkpoint in checkpoints]

59
tests/finance/test_reconciliation.py

@ -1,11 +1,13 @@
"""Synthetic checks for immutable, audited reconciliation checkpoints."""
from datetime import date
from datetime import date, datetime
from decimal import Decimal
from uuid import UUID
import pytest
from django.utils import timezone
from finance.models import AuditEvent, ReconciliationCheckpoint
from finance.models import Account, AuditEvent, ReconciliationCheckpoint
from finance.reconciliation import (
checkpoint_history,
latest_checkpoint_statuses,
@ -254,3 +256,56 @@ def test_latest_checkpoint_statuses_select_by_as_of_date_then_creation_for_activ
by_date.pk: newer_as_of_date.pk,
by_creation.pk: correction.pk,
}
def test_latest_checkpoint_statuses_order_selected_accounts_by_checkpoint_recency():
oldest_account = Account.objects.create(
id=UUID("00000000-0000-0000-0000-000000000001"),
name="Synthetic oldest account",
kind="BANK",
)
older_same_date_account = Account.objects.create(
id=UUID("00000000-0000-0000-0000-000000000002"),
name="Synthetic older same-date account",
kind="BANK",
)
newest_account = Account.objects.create(
id=UUID("00000000-0000-0000-0000-000000000003"),
name="Synthetic newest account",
kind="BANK",
)
oldest = create_reconciliation_checkpoint(
account_id=oldest_account.pk,
as_of_date=AS_OF_DATE,
institution_balance=Decimal("0.00"),
actor=ACTOR,
)
older_same_date = create_reconciliation_checkpoint(
account_id=older_same_date_account.pk,
as_of_date=date(2026, 9, 2),
institution_balance=Decimal("0.00"),
actor=ACTOR,
)
newest = create_reconciliation_checkpoint(
account_id=newest_account.pk,
as_of_date=date(2026, 9, 2),
institution_balance=Decimal("0.00"),
actor=ACTOR,
)
ReconciliationCheckpoint.objects.filter(pk=oldest.pk).update(
created_at=timezone.make_aware(datetime(2026, 9, 1, 9, 0))
)
ReconciliationCheckpoint.objects.filter(pk=older_same_date.pk).update(
created_at=timezone.make_aware(datetime(2026, 9, 1, 10, 0))
)
ReconciliationCheckpoint.objects.filter(pk=newest.pk).update(
created_at=timezone.make_aware(datetime(2026, 9, 1, 11, 0))
)
statuses = latest_checkpoint_statuses("BRL")
assert [status.checkpoint_id for status in statuses] == [
newest.pk,
older_same_date.pk,
oldest.pk,
]

Loading…
Cancel
Save