feat: add tackle catalog and recommendation analytics
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.database import Base
|
||||
from app.models import CatchReport, CatchTackleComponent, Fish, ModerationStatus, SourceType, Spot, Waterbody
|
||||
from app.routers.analytics import tackle_combinations
|
||||
|
||||
|
||||
def test_tackle_recommendation_requires_samples_and_independent_players() -> None:
|
||||
now = datetime.now(timezone.utc)
|
||||
engine = create_engine("sqlite://")
|
||||
Base.metadata.create_all(engine)
|
||||
with Session(engine) as db:
|
||||
waterbody = Waterbody(slug="lake", name_ru="Озеро", unlock_level=1)
|
||||
fish = Fish(slug="pike", name_ru="Щука", trophy_weight_g=10_000)
|
||||
spot = Spot(waterbody=waterbody, x=10, y=20)
|
||||
db.add_all([waterbody, fish, spot])
|
||||
db.flush()
|
||||
for index, player in enumerate(("One", "One", "Two")):
|
||||
report = CatchReport(
|
||||
fish=fish, waterbody=waterbody, spot=spot, weight_g=1000,
|
||||
caught_at=now - timedelta(hours=1), reported_at=now - timedelta(hours=1),
|
||||
player_name=player, source_type=SourceType.user, source_confidence=80,
|
||||
moderation_status=ModerationStatus.approved,
|
||||
)
|
||||
report.tackle_components.append(CatchTackleComponent(role="lure", position=0, raw_value="Spinner #1"))
|
||||
db.add(report)
|
||||
db.commit()
|
||||
|
||||
rows = tackle_combinations(db, waterbody="lake", fish="pike", method=None, hours=72, min_samples=3, min_players=2)
|
||||
assert len(rows) == 1
|
||||
assert (rows[0].status, rows[0].catches, rows[0].unique_players) == ("recommendation", 3, 2)
|
||||
|
||||
rows = tackle_combinations(db, waterbody="lake", fish="pike", method=None, hours=72, min_samples=3, min_players=3)
|
||||
assert rows[0].status == "insufficient_data"
|
||||
|
||||
engine.dispose()
|
||||
@@ -0,0 +1,32 @@
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.database import Base
|
||||
from app.models import Rig, RigComponent, TackleItem
|
||||
from app.routers.catalog import rig_detail, tackle_item, tackle_items
|
||||
|
||||
|
||||
def test_tackle_catalog_filters_details_and_missing_fields() -> None:
|
||||
engine = create_engine("sqlite://")
|
||||
Base.metadata.create_all(engine)
|
||||
with Session(engine) as db:
|
||||
item = TackleItem(
|
||||
name="API тестовая блесна", normalized_name="api тестовая блесна",
|
||||
category="lure", subcategory="spinner", brand="RF4", family=None,
|
||||
unlock_level=0, source_system="fixture", source_external_id="api-lure-1",
|
||||
source_url="https://example.test/lure/api-lure-1",
|
||||
)
|
||||
rig = Rig(name="API тестовый монтаж", normalized_name="api тестовый монтаж", source_system="fixture")
|
||||
rig.components.append(RigComponent(role="lure", position=0, tackle_item=item, raw_value=item.name))
|
||||
db.add(rig)
|
||||
db.commit()
|
||||
|
||||
page = tackle_items(db, category="lure", brand="RF4", family=None, unlock_level=None, limit=10, offset=0)
|
||||
assert page.total == 1
|
||||
assert page.items[0].missing_fields == ["family", "source_checked_at"]
|
||||
assert tackle_item(item.id, db).name == item.name
|
||||
details = rig_detail(rig.id, db)
|
||||
assert details.components[0].raw_value == item.name
|
||||
assert details.missing_fields == ["source_url", "source_checked_at"]
|
||||
|
||||
engine.dispose()
|
||||
Reference in New Issue
Block a user