80 lines
2.4 KiB
Python
80 lines
2.4 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import date, timedelta
|
|
|
|
import pandas as pd
|
|
|
|
from app.services.analytics_service import AnalyticsService
|
|
|
|
|
|
class StubWarehouseClient:
|
|
def fetch_daily_sales(self) -> pd.DataFrame:
|
|
today = date.today()
|
|
rows = []
|
|
for i in range(120):
|
|
day = today - timedelta(days=120 - i)
|
|
rows.append(
|
|
{
|
|
"sale_date": day.isoformat(),
|
|
"revenue": 1000 + (i * 5),
|
|
"cost": 500 + (i * 2),
|
|
"quantity": 40 + i,
|
|
"orders": 5 + (i % 4),
|
|
"source": "stub",
|
|
}
|
|
)
|
|
return pd.DataFrame(rows)
|
|
|
|
def fetch_product_performance(self) -> pd.DataFrame:
|
|
return pd.DataFrame(
|
|
[
|
|
{
|
|
"product_id": "A1",
|
|
"product_name": "Alpha",
|
|
"category_name": "CatA",
|
|
"revenue": 12000,
|
|
"cost": 6000,
|
|
"quantity": 400,
|
|
"orders": 150,
|
|
"source": "stub",
|
|
},
|
|
{
|
|
"product_id": "B1",
|
|
"product_name": "Beta",
|
|
"category_name": "CatB",
|
|
"revenue": 9000,
|
|
"cost": 8500,
|
|
"quantity": 300,
|
|
"orders": 110,
|
|
"source": "stub",
|
|
},
|
|
]
|
|
)
|
|
|
|
def fetch_customer_performance(self) -> pd.DataFrame:
|
|
return pd.DataFrame(
|
|
[
|
|
{
|
|
"customer_id": "C1",
|
|
"customer_name": "Contoso",
|
|
"revenue": 15000,
|
|
"orders": 80,
|
|
"source": "stub",
|
|
}
|
|
]
|
|
)
|
|
|
|
|
|
def test_forecast_has_expected_horizon() -> None:
|
|
service = AnalyticsService(StubWarehouseClient()) # type: ignore[arg-type]
|
|
forecast = service.get_forecast(horizon_days=15)
|
|
assert len(forecast) == 15
|
|
assert "predicted_revenue" in forecast[0]
|
|
|
|
|
|
def test_rankings_are_sorted() -> None:
|
|
service = AnalyticsService(StubWarehouseClient()) # type: ignore[arg-type]
|
|
rankings = service.get_rankings(top_n=2)
|
|
assert len(rankings) == 2
|
|
assert rankings[0]["score"] >= rankings[1]["score"]
|