| from datetime import date |
| from decimal import Decimal |
| from pathlib import Path |
|
|
| import pytest |
| from openpyxl import load_workbook |
|
|
| from finreport_agent.generic import discover_fragments |
| from finreport_agent.extraction import extract_document |
| from finreport_agent.models import GenericDocumentReport |
| from finreport_agent.pipeline import _is_fund_portfolio, convert_report |
|
|
|
|
| KAP_PDF = Path("/home/ahmet/Downloads/KAP - 1636723.pdf") |
| AFT_PDF = Path("/home/ahmet/Downloads/AFT_2026.06.pdf") |
| DGF_PDF = Path("/home/ahmet/Downloads/DGF_2026.06.pdf") |
|
|
|
|
| @pytest.mark.skipif(not KAP_PDF.exists(), reason="Local KAP golden PDF is unavailable") |
| def test_rotated_kap_tables_are_discovered_and_stitched(): |
| fragments = discover_fragments(extract_document(KAP_PDF)) |
| financial = [item for item in fragments if item.table_id.startswith("table_")] |
|
|
| assert len(financial) == 6 |
| assert financial[0].source_pages == [5, 6, 7] |
| assert financial[1].source_pages == [8, 9, 10] |
| assert financial[2].source_pages == [11, 12] |
|
|
| assets_total = next( |
| row |
| for row in financial[0].rows |
| if row.label == "VARLIKLAR TOPLAMI" |
| ) |
| assert assets_total.values == [ |
| Decimal("82737"), |
| Decimal("133729"), |
| Decimal("216466"), |
| Decimal("76130"), |
| Decimal("128393"), |
| Decimal("204523"), |
| ] |
|
|
|
|
| @pytest.mark.skipif(not KAP_PDF.exists(), reason="Local KAP golden PDF is unavailable") |
| def test_kap_uses_generic_route_and_dynamic_workbook(tmp_path, monkeypatch): |
| monkeypatch.setenv("DISABLE_AGENT_PLANNER", "1") |
| output = tmp_path / "kap.xlsx" |
|
|
| result = convert_report(KAP_PDF, output) |
|
|
| assert isinstance(result.report, GenericDocumentReport) |
| assert result.report.document_type == "Banka Finansal Raporu" |
| assert [table.sheet_name for table in result.report.tables] == [ |
| "Belge Bilgileri", |
| "Bilanço", |
| "Nazım Hesaplar", |
| "Kâr veya Zarar", |
| "Kapsamlı Gelir", |
| "Nakit Akış", |
| "Özkaynak Değişim", |
| ] |
| workbook = load_workbook(output, data_only=True, read_only=True) |
| assert workbook.sheetnames == [ |
| "Özet", |
| "Belge Bilgileri", |
| "Bilanço", |
| "Nazım Hesaplar", |
| "Kâr veya Zarar", |
| "Kapsamlı Gelir", |
| "Nakit Akış", |
| "Özkaynak Değişim", |
| "Kontroller", |
| "Kaynak İzleri", |
| ] |
| assert "Hisse Senetleri" not in workbook.sheetnames |
|
|
|
|
| @pytest.mark.skipif(not AFT_PDF.exists(), reason="Local AFT golden PDF is unavailable") |
| def test_different_fund_layout_falls_back_to_generic_route(tmp_path, monkeypatch): |
| monkeypatch.setenv("DISABLE_AGENT_PLANNER", "1") |
| document = extract_document(AFT_PDF) |
|
|
| assert not _is_fund_portfolio(document) |
|
|
| output = tmp_path / "aft.xlsx" |
| result = convert_report(AFT_PDF, output) |
|
|
| assert isinstance(result.report, GenericDocumentReport) |
| assert result.report.planner_mode == "deterministic_fund_schema" |
| assert len(result.report.tables) >= 10 |
| portfolio = next( |
| table for table in result.report.tables |
| if table.sheet_name == "Portföy Değeri" |
| ) |
| apple = next(row for row in portfolio.rows if row.label.startswith("AAPL US")) |
| assert Decimal("885016484.17") in apple.values |
|
|
| workbook = load_workbook(output, data_only=True, read_only=True) |
| assert "Tanıtıcı Bilgiler" in workbook.sheetnames |
| assert "Performans" in workbook.sheetnames |
| assert "Portföy Değeri" in workbook.sheetnames |
| assert "Fon Toplam Değeri" in workbook.sheetnames |
| assert "Giderler" in workbook.sheetnames |
| assert "Dönem İşlemleri" in workbook.sheetnames |
| assert "Kontroller" in workbook.sheetnames |
| assert "Kaynak İzleri" in workbook.sheetnames |
|
|
|
|
| @pytest.mark.skipif(not DGF_PDF.exists(), reason="Local DGF golden PDF is unavailable") |
| def test_standard_fund_sections_do_not_mix_performance_and_portfolio( |
| tmp_path, |
| monkeypatch, |
| ): |
| monkeypatch.setenv("DISABLE_AGENT_PLANNER", "1") |
| output = tmp_path / "dgf.xlsx" |
|
|
| result = convert_report(DGF_PDF, output) |
|
|
| assert isinstance(result.report, GenericDocumentReport) |
| assert result.report.planner_mode == "deterministic_fund_schema" |
| by_sheet = {table.sheet_name: table for table in result.report.tables} |
| assert { |
| "Tanıtıcı Bilgiler", |
| "Performans", |
| "Portföy Değeri", |
| "Portföy Değeri 2", |
| "Fon Toplam Değeri", |
| "Giderler", |
| "Dönem İşlemleri", |
| }.issubset(by_sheet) |
|
|
| performance = by_sheet["Performans"] |
| assert all("TREGVYO" not in row.label for row in performance.rows) |
| assert any(row.label.startswith("A-)Ay Sonu Pay Fiyatı") for row in performance.rows) |
|
|
| portfolio = by_sheet["Portföy Değeri 2"] |
| glcvy = next(row for row in portfolio.rows if "GLCVY" in row.label) |
| assert Decimal("532993.50") in glcvy.values |
| assert "TREGVYO00011" in glcvy.values |
| assert date(2026, 6, 26) in glcvy.values |
|
|
| expenses = by_sheet["Giderler"] |
| management_fee = next( |
| row for row in expenses.rows if row.label == "Fon Yönetim Ücreti" |
| ) |
| assert management_fee.values[0] == Decimal("27476.04") |
|
|