Reapply "Redesign finance dashboard with period summaries"

This reverts commit da14ec5740.
This commit is contained in:
SmartUp Developer
2026-07-03 23:25:47 +08:00
parent da14ec5740
commit 4dd4448970
6 changed files with 1207 additions and 801 deletions
+150
View File
@@ -861,6 +861,156 @@ def test_save_summary_if_absent_skips_existing(monkeypatch):
db.close()
def _insert_finance_summary_row(db, stat_date, summary):
from app.models.finance_daily_summary import FinanceDailySummary
row = FinanceDailySummary(
stat_date=stat_date,
summary_json=json.dumps(summary, ensure_ascii=False),
success=summary.get("success", False),
)
db.add(row)
db.commit()
return row
def test_week_summary_aggregates_stored_snapshots_only(monkeypatch):
"""Week aggregation reads existing DB snapshots without computing missing days."""
from app.services.finance_service import get_finance_summary
db = _make_inmemory_db()
_insert_finance_summary_row(db, date(2026, 6, 30), {
"date": "2026-06-30",
"total_revenue": 100.0,
"total_cost": 30.0,
"net_income": 70.0,
"margin_percent": 70.0,
"website_items": [
{"id": 1, "name": "Site A", "upstream_type": "sub2api", "amount": 100.0, "status": "success", "error": None},
],
"upstream_items": [
{"id": 10, "name": "Up A", "upstream_type": "new_api", "amount": 30.0, "status": "success", "error": None},
],
"failed_count": 0,
"success": True,
})
_insert_finance_summary_row(db, date(2026, 7, 2), {
"date": "2026-07-02",
"total_revenue": 50.0,
"total_cost": 0.0,
"net_income": 50.0,
"margin_percent": 100.0,
"website_items": [
{"id": 1, "name": "Site A", "upstream_type": "sub2api", "amount": 50.0, "status": "success", "error": None},
],
"upstream_items": [
{"id": 10, "name": "Up A", "upstream_type": "new_api", "amount": 0.0, "status": "failed", "error": "timeout"},
],
"failed_count": 1,
"success": False,
})
def _should_not_compute(*_args, **_kwargs):
raise AssertionError("week/month summary must not compute daily summaries")
monkeypatch.setattr("app.services.finance_service.compute_daily_summary", _should_not_compute)
result = get_finance_summary(db, "week", date(2026, 7, 2))
assert result["start_date"] == "2026-06-26"
assert result["end_date"] == "2026-07-02"
assert result["included_days"] == 2
assert result["partial"] is True
assert len(result["missing_dates"]) == 5
assert result["total_revenue"] == 150.0
assert result["total_cost"] == 30.0
assert result["net_income"] == 120.0
assert result["chart"]["labels"] == [
"2026-06-26", "2026-06-27", "2026-06-28", "2026-06-29",
"2026-06-30", "2026-07-01", "2026-07-02",
]
assert result["chart"]["revenue"] == [0.0, 0.0, 0.0, 0.0, 100.0, 0.0, 50.0]
assert result["website_items"][0]["amount"] == 150.0
assert result["upstream_items"][0]["status"] == "failed"
assert result["upstream_items"][0]["amount"] == 30.0
assert result["upstream_items"][0]["error"] == "2026-07-02: timeout"
db.close()
def test_month_summary_uses_natural_month_and_reports_missing_dates():
"""Month aggregation spans the selected date's calendar month."""
from app.services.finance_service import get_finance_summary
db = _make_inmemory_db()
_insert_finance_summary_row(db, date(2026, 6, 1), {
"date": "2026-06-01",
"total_revenue": 10.0,
"total_cost": 4.0,
"net_income": 6.0,
"margin_percent": 60.0,
"website_items": [],
"upstream_items": [],
"failed_count": 0,
"success": True,
})
_insert_finance_summary_row(db, date(2026, 6, 15), {
"date": "2026-06-15",
"total_revenue": 20.0,
"total_cost": 7.0,
"net_income": 13.0,
"margin_percent": 65.0,
"website_items": [],
"upstream_items": [],
"failed_count": 0,
"success": True,
})
result = get_finance_summary(db, "month", date(2026, 6, 15))
assert result["start_date"] == "2026-06-01"
assert result["end_date"] == "2026-06-30"
assert result["included_days"] == 2
assert result["partial"] is True
assert len(result["missing_dates"]) == 28
assert result["total_revenue"] == 30.0
assert result["total_cost"] == 11.0
assert result["net_income"] == 19.0
assert len(result["chart"]["labels"]) == 30
db.close()
def test_day_summary_adds_seven_day_snapshot_chart(monkeypatch):
"""Day summary keeps existing compute-on-miss behavior and adds daily trend data."""
from app.services.finance_service import get_finance_summary
db = _make_inmemory_db()
_add_minimal_test_data(db)
_insert_finance_summary_row(db, date(2026, 6, 30), {
"date": "2026-06-30",
"total_revenue": 80.0,
"total_cost": 20.0,
"net_income": 60.0,
"margin_percent": 75.0,
"website_items": [],
"upstream_items": [],
"failed_count": 0,
"success": True,
})
monkeypatch.setattr("app.services.finance_service.fetch_website_revenue", lambda *_: (100.0, None))
monkeypatch.setattr("app.services.finance_service.fetch_upstream_cost_sub2api", lambda *_: (40.0, None))
result = get_finance_summary(db, "day", date(2026, 7, 2))
assert result["total_revenue"] == 100.0
assert result["included_days"] == 1
assert result["partial"] is False
assert result["chart"]["labels"] == [
"2026-06-26", "2026-06-27", "2026-06-28", "2026-06-29",
"2026-06-30", "2026-07-01", "2026-07-02",
]
assert result["chart"]["revenue"] == [0.0, 0.0, 0.0, 0.0, 80.0, 0.0, 100.0]
db.close()
def _make_test_summary(website_items, upstream_items=None):
"""Return a summary dict with deep-copied items to prevent cross-contamination."""
return {