Step 2: Add seeding logic for pricing config

- Add seed_pricing_config() function to seed.py
- Seed initial values from shared/constants.json
- Add seeding to seed_e2e.py for E2E tests
- Add tests for seeding functionality
This commit is contained in:
counterweight 2025-12-26 20:11:00 +01:00
parent 32ce27180d
commit 74b934135a
Signed by: counterweight
GPG key ID: 883EDBAA726BD96C
3 changed files with 178 additions and 0 deletions

View file

@ -1,7 +1,9 @@
"""Seed the database with roles, permissions, and dev users."""
import asyncio
import json
import os
from pathlib import Path
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
@ -16,6 +18,7 @@ from models import (
Role,
User,
)
from repositories.pricing import PricingRepository
DEV_USER_EMAIL = os.environ["DEV_USER_EMAIL"]
DEV_USER_PASSWORD = os.environ["DEV_USER_PASSWORD"]
@ -78,6 +81,49 @@ async def upsert_user(
return user
async def seed_pricing_config(db: AsyncSession) -> None:
"""Seed initial pricing configuration from shared/constants.json."""
# Load constants from shared/constants.json
constants_path = Path(__file__).parent.parent / "shared" / "constants.json"
with constants_path.open() as f:
constants = json.load(f)
exchange_config = constants["exchange"]
premium_percentage = exchange_config["premiumPercentage"]
eur_trade_min = exchange_config["eurTradeMin"]
eur_trade_max = exchange_config["eurTradeMax"]
# Convert EUR amounts to cents
eur_min_cents = eur_trade_min * 100
eur_max_cents = eur_trade_max * 100
repo = PricingRepository(db)
config = await repo.create_or_update(
premium_buy=premium_percentage,
premium_sell=premium_percentage,
small_trade_threshold_eur=0, # Default: no small trade extra (admin will set)
small_trade_extra_premium=0, # Default: no extra premium
eur_min_buy=eur_min_cents,
eur_max_buy=eur_max_cents,
eur_min_sell=eur_min_cents,
eur_max_sell=eur_max_cents,
)
if config.id: # If config already existed (was updated)
print("Updated pricing config")
else:
print("Created pricing config")
print(f" Premium BUY: {config.premium_buy}%, Premium SELL: {config.premium_sell}%")
print(
f" Trade limits BUY: €{config.eur_min_buy / 100:.0f} - "
f"{config.eur_max_buy / 100:.0f}"
)
print(
f" Trade limits SELL: €{config.eur_min_sell / 100:.0f} - "
f"{config.eur_max_sell / 100:.0f}"
)
async def seed() -> None:
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
@ -99,6 +145,9 @@ async def seed() -> None:
# Create admin dev user
await upsert_user(db, DEV_ADMIN_EMAIL, DEV_ADMIN_PASSWORD, [ROLE_ADMIN])
print("\n=== Seeding Pricing Config ===")
await seed_pricing_config(db)
await db.commit()
print("\n=== Seeding Complete ===\n")

View file

@ -1,6 +1,8 @@
"""Fast re-seeding function for e2e tests - only seeds essential data."""
import json
import os
from pathlib import Path
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
@ -13,6 +15,7 @@ from models import (
Role,
User,
)
from repositories.pricing import PricingRepository
async def seed_base_data(db: AsyncSession) -> None:
@ -95,4 +98,30 @@ async def seed_base_data(db: AsyncSession) -> None:
admin_user.signal = None
admin_user.nostr_npub = None
# Seed pricing config
constants_path = Path(__file__).parent.parent / "shared" / "constants.json"
with constants_path.open() as f:
constants = json.load(f)
exchange_config = constants["exchange"]
premium_percentage = exchange_config["premiumPercentage"]
eur_trade_min = exchange_config["eurTradeMin"]
eur_trade_max = exchange_config["eurTradeMax"]
# Convert EUR amounts to cents
eur_min_cents = eur_trade_min * 100
eur_max_cents = eur_trade_max * 100
repo = PricingRepository(db)
await repo.create_or_update(
premium_buy=premium_percentage,
premium_sell=premium_percentage,
small_trade_threshold_eur=0,
small_trade_extra_premium=0,
eur_min_buy=eur_min_cents,
eur_max_buy=eur_max_cents,
eur_min_sell=eur_min_cents,
eur_max_sell=eur_max_cents,
)
await db.commit()

View file

@ -158,3 +158,103 @@ class TestPricingRepository:
result = await db.execute(select(PricingConfig))
all_configs = list(result.scalars().all())
assert len(all_configs) == 1
class TestPricingSeeding:
"""Test pricing configuration seeding."""
@pytest.mark.asyncio
async def test_seeding_creates_config_with_defaults(self, client_factory):
"""Seeding creates config with values from constants.json."""
import json
from pathlib import Path
# Load expected values from constants.json
constants_path = (
Path(__file__).parent.parent.parent / "shared" / "constants.json"
)
with constants_path.open() as f:
constants = json.load(f)
exchange_config = constants["exchange"]
expected_premium = exchange_config["premiumPercentage"]
expected_min_eur = exchange_config["eurTradeMin"]
expected_max_eur = exchange_config["eurTradeMax"]
async with client_factory.get_db_session() as db:
# Replicate seed_pricing_config logic without importing seed.py
repo = PricingRepository(db)
config = await repo.create_or_update(
premium_buy=expected_premium,
premium_sell=expected_premium,
small_trade_threshold_eur=0,
small_trade_extra_premium=0,
eur_min_buy=expected_min_eur * 100,
eur_max_buy=expected_max_eur * 100,
eur_min_sell=expected_min_eur * 100,
eur_max_sell=expected_max_eur * 100,
)
assert config is not None
assert config.premium_buy == expected_premium
assert config.premium_sell == expected_premium
assert config.eur_min_buy == expected_min_eur * 100
assert config.eur_max_buy == expected_max_eur * 100
assert config.eur_min_sell == expected_min_eur * 100
assert config.eur_max_sell == expected_max_eur * 100
assert config.small_trade_threshold_eur == 0
assert config.small_trade_extra_premium == 0
@pytest.mark.asyncio
async def test_re_running_seed_updates_existing_config(self, client_factory):
"""Re-running seed updates existing config instead of creating duplicate."""
import json
from pathlib import Path
constants_path = (
Path(__file__).parent.parent.parent / "shared" / "constants.json"
)
with constants_path.open() as f:
constants = json.load(f)
exchange_config = constants["exchange"]
expected_premium = exchange_config["premiumPercentage"]
expected_min_eur = exchange_config["eurTradeMin"]
expected_max_eur = exchange_config["eurTradeMax"]
async with client_factory.get_db_session() as db:
repo = PricingRepository(db)
# First seeding
config1 = await repo.create_or_update(
premium_buy=expected_premium,
premium_sell=expected_premium,
small_trade_threshold_eur=0,
small_trade_extra_premium=0,
eur_min_buy=expected_min_eur * 100,
eur_max_buy=expected_max_eur * 100,
eur_min_sell=expected_min_eur * 100,
eur_max_sell=expected_max_eur * 100,
)
original_id = config1.id
# Modify config manually
config1.premium_buy = 99
await db.commit()
# Re-run seed (update existing)
config2 = await repo.create_or_update(
premium_buy=expected_premium,
premium_sell=expected_premium,
small_trade_threshold_eur=0,
small_trade_extra_premium=0,
eur_min_buy=expected_min_eur * 100,
eur_max_buy=expected_max_eur * 100,
eur_min_sell=expected_min_eur * 100,
eur_max_sell=expected_max_eur * 100,
)
# Should be same record with updated values
assert config2.id == original_id
assert config2.premium_buy == expected_premium # Should be reset
assert config2.premium_buy != 99