Implement FIN-WP-0006-T01 settlement statement join; mark FIN-WP-0004/0005 blocked
Add SettlementStatement schema and a dedicated settlement_statements store (ingest_settlement_statement, current_settlement_statements) so resource-control internal transfer settlements join as a referenced projection without ever entering the booked-cost ledger. exchange_health now surfaces a current statement with payment_recognition=unknown as a settlement_awaiting_payment_join residual instead of booked cost. Adds CLI commands finhub ledger ingest-settlement / settlements. FIN-WP-0006-T01 is done; the workplan is finished. Reviewed all other open workplans for closeable work: FIN-WP-0004's only remaining task (T05) waits on an external provider fact from resource-control, and every FIN-WP-0005 task waits on operator/Steuerbüro confirmation or a non-production DATEV tenant. Neither has actionable in-repo work right now, so both move to status: blocked. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: sonnet Assistant-Process: 242919@bnt-lap001 Assistant-Session: 286d235a-1654-40ff-b8fd-eee4e2ff9ea6
This commit is contained in:
parent
4ef6fec8ff
commit
91d62f6430
8 changed files with 377 additions and 8 deletions
28
tests/fixtures/settlement-statement-2026-08.json
vendored
Normal file
28
tests/fixtures/settlement-statement-2026-08.json
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"schema_version": "0.1",
|
||||
"record_type": "settlement_statement",
|
||||
"terms_version": "V0.1",
|
||||
"financial_entity_id": "entity:frontier",
|
||||
"procuring_entity_id": "entity:railiance",
|
||||
"period": "2026-08",
|
||||
"statement_date": "2026-09-01",
|
||||
"due_date": "2026-09-15",
|
||||
"currency": "EUR",
|
||||
"line_items": [
|
||||
{"resource_id": "resource:platform:audit-storage", "delivered_cost_eur": "42.10", "markup_eur": "6.32"}
|
||||
],
|
||||
"known_delivered_cost_eur": "42.10",
|
||||
"known_transfer_price_eur": "48.42",
|
||||
"unknown_cost_remainder": false,
|
||||
"prior_outstanding_eur": "0.00",
|
||||
"recognized_payments_eur": null,
|
||||
"payment_recognition": "unknown",
|
||||
"interest_eur": "0.00",
|
||||
"new_transfer_charges_eur": "48.42",
|
||||
"outstanding_eur": "48.42",
|
||||
"credit_limit_eur": "500.00",
|
||||
"credit_headroom_eur": "451.58",
|
||||
"consumption_mode": "open",
|
||||
"next_month_allowance_eur": null,
|
||||
"payment_instruction": null
|
||||
}
|
||||
|
|
@ -12,13 +12,16 @@ from fin_hub.schemas.exchange import (
|
|||
BookedCostEvidence,
|
||||
ForecastEvidence,
|
||||
)
|
||||
from fin_hub.schemas.exchange import SettlementStatement
|
||||
from fin_hub.services.exchange import (
|
||||
booked_cost_projection,
|
||||
current_settlement_statements,
|
||||
exchange_health,
|
||||
financial_constraint_projection,
|
||||
ingest_planning_evidence,
|
||||
ingest_resource_forecast,
|
||||
ingest_resource_usage,
|
||||
ingest_settlement_statement,
|
||||
reconcile_resource_period,
|
||||
)
|
||||
from fin_hub.services.ledger import import_csv
|
||||
|
|
@ -413,3 +416,86 @@ def test_audit_storage_usage_omits_nulls_and_does_not_invent_zero_spend(tmp_path
|
|||
assert august.invented_zero is False
|
||||
health = exchange_health(ledger_path=ledger)
|
||||
assert "usage_without_booked_fact" in {issue.code for issue in health.issues}
|
||||
|
||||
|
||||
def _settlement_payload() -> dict:
|
||||
return json.loads((FIXTURES / "settlement-statement-2026-08.json").read_text())
|
||||
|
||||
|
||||
def test_settlement_statement_joins_as_referenced_projection_not_booked_cost(
|
||||
tmp_path: Path,
|
||||
):
|
||||
ledger = tmp_path / "ledger.db"
|
||||
payload = _settlement_payload()
|
||||
|
||||
statement = ingest_settlement_statement(
|
||||
payload,
|
||||
source_evidence_ref="resource-control:data/settlements/2026-08.json",
|
||||
ledger_path=ledger,
|
||||
)
|
||||
|
||||
assert isinstance(statement, SettlementStatement)
|
||||
assert statement.financial_entity_id == "entity:frontier"
|
||||
assert statement.outstanding_eur == Decimal("48.42")
|
||||
assert statement.payment_recognition == "unknown"
|
||||
|
||||
current = current_settlement_statements(ledger_path=ledger)
|
||||
assert len(current) == 1
|
||||
assert current[0].statement_id() == statement.statement_id()
|
||||
|
||||
# No booked cost is created by joining a settlement statement.
|
||||
assert booked_cost_projection(ledger_path=ledger) == []
|
||||
|
||||
|
||||
def test_settlement_statement_is_idempotent_and_supersedes_prior_period_statement(
|
||||
tmp_path: Path,
|
||||
):
|
||||
ledger = tmp_path / "ledger.db"
|
||||
payload = _settlement_payload()
|
||||
|
||||
ingest_settlement_statement(
|
||||
payload, source_evidence_ref="resource-control:data/settlements/2026-08.json",
|
||||
ledger_path=ledger,
|
||||
)
|
||||
ingest_settlement_statement(
|
||||
payload, source_evidence_ref="resource-control:data/settlements/2026-08.json",
|
||||
ledger_path=ledger,
|
||||
)
|
||||
assert len(current_settlement_statements(ledger_path=ledger)) == 1
|
||||
|
||||
corrected = {**payload, "statement_date": "2026-09-05", "outstanding_eur": "10.00",
|
||||
"new_transfer_charges_eur": "10.00", "known_transfer_price_eur": "10.00"}
|
||||
ingest_settlement_statement(
|
||||
corrected, source_evidence_ref="resource-control:data/settlements/2026-08-corrected.json",
|
||||
ledger_path=ledger,
|
||||
)
|
||||
|
||||
current = current_settlement_statements(ledger_path=ledger)
|
||||
assert len(current) == 1
|
||||
assert current[0].outstanding_eur == Decimal("10.00")
|
||||
|
||||
|
||||
def test_settlement_statement_rejects_provider_invoice_shaped_payload(tmp_path: Path):
|
||||
ledger = tmp_path / "ledger.db"
|
||||
with pytest.raises(ValueError, match="record_type=settlement_statement"):
|
||||
ingest_settlement_statement(
|
||||
{"record_type": "booked_cost"},
|
||||
source_evidence_ref="resource-control:x",
|
||||
ledger_path=ledger,
|
||||
)
|
||||
|
||||
|
||||
def test_exchange_health_surfaces_settlement_without_payment_join_as_residual(
|
||||
tmp_path: Path,
|
||||
):
|
||||
ledger = tmp_path / "ledger.db"
|
||||
ingest_settlement_statement(
|
||||
_settlement_payload(),
|
||||
source_evidence_ref="resource-control:data/settlements/2026-08.json",
|
||||
ledger_path=ledger,
|
||||
)
|
||||
|
||||
health = exchange_health(ledger_path=ledger)
|
||||
|
||||
assert "settlement_awaiting_payment_join" in {issue.code for issue in health.issues}
|
||||
assert health.booked_fact_count == 0
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue