Step 3: Add admin API endpoints for pricing configuration
- Add PricingConfigResponse and PricingConfigUpdate schemas - Create PricingService with validation logic - Add GET and PUT endpoints in routes/pricing.py - Add MANAGE_PRICING permission to admin role - Register pricing router in main.py - Add comprehensive API tests for permissions and validation
This commit is contained in:
parent
74b934135a
commit
4d0dad8e2b
8 changed files with 534 additions and 0 deletions
|
|
@ -16,6 +16,7 @@ from routes import availability as availability_routes
|
|||
from routes import exchange as exchange_routes
|
||||
from routes import invites as invites_routes
|
||||
from routes import meta as meta_routes
|
||||
from routes import pricing as pricing_routes
|
||||
from routes import profile as profile_routes
|
||||
from routes import test as test_routes
|
||||
from shared_constants import PRICE_REFRESH_SECONDS
|
||||
|
|
@ -91,6 +92,7 @@ app.include_router(auth_routes.router)
|
|||
app.include_router(audit_routes.router)
|
||||
app.include_router(profile_routes.router)
|
||||
app.include_router(availability_routes.router)
|
||||
app.include_router(pricing_routes.router)
|
||||
app.include_router(meta_routes.router)
|
||||
app.include_router(test_routes.router)
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ class Permission(str, PyEnum):
|
|||
|
||||
# Availability/Exchange permissions (admin)
|
||||
MANAGE_AVAILABILITY = "manage_availability"
|
||||
MANAGE_PRICING = "manage_pricing"
|
||||
VIEW_ALL_EXCHANGES = "view_all_exchanges"
|
||||
CANCEL_ANY_EXCHANGE = "cancel_any_exchange"
|
||||
COMPLETE_EXCHANGE = "complete_exchange"
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ ROLE_DEFINITIONS: dict[str, RoleConfig] = {
|
|||
Permission.FETCH_PRICE,
|
||||
Permission.MANAGE_INVITES,
|
||||
Permission.MANAGE_AVAILABILITY,
|
||||
Permission.MANAGE_PRICING,
|
||||
Permission.VIEW_ALL_EXCHANGES,
|
||||
Permission.CANCEL_ANY_EXCHANGE,
|
||||
Permission.COMPLETE_EXCHANGE,
|
||||
|
|
|
|||
33
backend/routes/pricing.py
Normal file
33
backend/routes/pricing.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
"""Pricing routes for admin to manage pricing configuration."""
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from auth import require_permission
|
||||
from database import get_db
|
||||
from models import Permission, User
|
||||
from schemas import PricingConfigResponse, PricingConfigUpdate
|
||||
from services.pricing import PricingService
|
||||
|
||||
router = APIRouter(prefix="/api/admin/pricing", tags=["pricing"])
|
||||
|
||||
|
||||
@router.get("", response_model=PricingConfigResponse)
|
||||
async def get_pricing_config(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
_current_user: User = Depends(require_permission(Permission.MANAGE_PRICING)),
|
||||
) -> PricingConfigResponse:
|
||||
"""Get current pricing configuration."""
|
||||
service = PricingService(db)
|
||||
return await service.get_config()
|
||||
|
||||
|
||||
@router.put("", response_model=PricingConfigResponse)
|
||||
async def update_pricing_config(
|
||||
request: PricingConfigUpdate,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
_current_user: User = Depends(require_permission(Permission.MANAGE_PRICING)),
|
||||
) -> PricingConfigResponse:
|
||||
"""Update pricing configuration."""
|
||||
service = PricingService(db)
|
||||
return await service.update_config(request)
|
||||
|
|
@ -44,6 +44,9 @@ from .price import (
|
|||
PriceResponse,
|
||||
)
|
||||
|
||||
# Export pricing schemas
|
||||
from .pricing import PricingConfigResponse, PricingConfigUpdate
|
||||
|
||||
# Export profile schemas
|
||||
from .profile import ProfileResponse, ProfileUpdate
|
||||
|
||||
|
|
@ -73,6 +76,8 @@ __all__ = [
|
|||
"PaginatedResponse",
|
||||
"PriceHistoryResponse",
|
||||
"PriceResponse",
|
||||
"PricingConfigResponse",
|
||||
"PricingConfigUpdate",
|
||||
"ProfileResponse",
|
||||
"ProfileUpdate",
|
||||
"RecordT",
|
||||
|
|
|
|||
27
backend/schemas/pricing.py
Normal file
27
backend/schemas/pricing.py
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class PricingConfigResponse(BaseModel):
|
||||
"""Response model for pricing configuration."""
|
||||
|
||||
premium_buy: int
|
||||
premium_sell: int
|
||||
small_trade_threshold_eur: int
|
||||
small_trade_extra_premium: int
|
||||
eur_min_buy: int
|
||||
eur_max_buy: int
|
||||
eur_min_sell: int
|
||||
eur_max_sell: int
|
||||
|
||||
|
||||
class PricingConfigUpdate(BaseModel):
|
||||
"""Request model for updating pricing configuration."""
|
||||
|
||||
premium_buy: int
|
||||
premium_sell: int
|
||||
small_trade_threshold_eur: int
|
||||
small_trade_extra_premium: int
|
||||
eur_min_buy: int
|
||||
eur_max_buy: int
|
||||
eur_min_sell: int
|
||||
eur_max_sell: int
|
||||
106
backend/services/pricing.py
Normal file
106
backend/services/pricing.py
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
"""Pricing service for managing pricing configuration."""
|
||||
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from exceptions import BadRequestError, NotFoundError
|
||||
from repositories.pricing import PricingRepository
|
||||
from schemas import PricingConfigResponse, PricingConfigUpdate
|
||||
|
||||
|
||||
class PricingService:
|
||||
"""Service for pricing configuration business logic."""
|
||||
|
||||
def __init__(self, db: AsyncSession):
|
||||
self.db = db
|
||||
self.repo = PricingRepository(db)
|
||||
|
||||
async def get_config(self) -> PricingConfigResponse:
|
||||
"""Get current pricing configuration.
|
||||
|
||||
Returns:
|
||||
PricingConfigResponse with current config
|
||||
|
||||
Raises:
|
||||
NotFoundError: If no config exists
|
||||
"""
|
||||
config = await self.repo.get_current()
|
||||
if config is None:
|
||||
raise NotFoundError("Pricing configuration not found")
|
||||
|
||||
return PricingConfigResponse(
|
||||
premium_buy=config.premium_buy,
|
||||
premium_sell=config.premium_sell,
|
||||
small_trade_threshold_eur=config.small_trade_threshold_eur,
|
||||
small_trade_extra_premium=config.small_trade_extra_premium,
|
||||
eur_min_buy=config.eur_min_buy,
|
||||
eur_max_buy=config.eur_max_buy,
|
||||
eur_min_sell=config.eur_min_sell,
|
||||
eur_max_sell=config.eur_max_sell,
|
||||
)
|
||||
|
||||
async def update_config(self, data: PricingConfigUpdate) -> PricingConfigResponse:
|
||||
"""Update pricing configuration with validation.
|
||||
|
||||
Args:
|
||||
data: Pricing configuration update data
|
||||
|
||||
Returns:
|
||||
PricingConfigResponse with updated config
|
||||
|
||||
Raises:
|
||||
BadRequestError: If validation fails
|
||||
"""
|
||||
# Validate premium values (-100 to 100)
|
||||
if not (-100 <= data.premium_buy <= 100):
|
||||
raise BadRequestError("premium_buy must be between -100 and 100")
|
||||
if not (-100 <= data.premium_sell <= 100):
|
||||
raise BadRequestError("premium_sell must be between -100 and 100")
|
||||
if not (-100 <= data.small_trade_extra_premium <= 100):
|
||||
raise BadRequestError(
|
||||
"small_trade_extra_premium must be between -100 and 100"
|
||||
)
|
||||
|
||||
# Validate min amounts (positive integers)
|
||||
if data.eur_min_buy <= 0:
|
||||
raise BadRequestError("eur_min_buy must be positive")
|
||||
if data.eur_min_sell <= 0:
|
||||
raise BadRequestError("eur_min_sell must be positive")
|
||||
|
||||
# Validate max amounts (positive integers)
|
||||
if data.eur_max_buy <= 0:
|
||||
raise BadRequestError("eur_max_buy must be positive")
|
||||
if data.eur_max_sell <= 0:
|
||||
raise BadRequestError("eur_max_sell must be positive")
|
||||
|
||||
# Validate min < max for both directions
|
||||
if data.eur_min_buy >= data.eur_max_buy:
|
||||
raise BadRequestError("eur_min_buy must be less than eur_max_buy")
|
||||
if data.eur_min_sell >= data.eur_max_sell:
|
||||
raise BadRequestError("eur_min_sell must be less than eur_max_sell")
|
||||
|
||||
# Validate threshold (positive integer)
|
||||
if data.small_trade_threshold_eur <= 0:
|
||||
raise BadRequestError("small_trade_threshold_eur must be positive")
|
||||
|
||||
# Update config
|
||||
config = await self.repo.create_or_update(
|
||||
premium_buy=data.premium_buy,
|
||||
premium_sell=data.premium_sell,
|
||||
small_trade_threshold_eur=data.small_trade_threshold_eur,
|
||||
small_trade_extra_premium=data.small_trade_extra_premium,
|
||||
eur_min_buy=data.eur_min_buy,
|
||||
eur_max_buy=data.eur_max_buy,
|
||||
eur_min_sell=data.eur_min_sell,
|
||||
eur_max_sell=data.eur_max_sell,
|
||||
)
|
||||
|
||||
return PricingConfigResponse(
|
||||
premium_buy=config.premium_buy,
|
||||
premium_sell=config.premium_sell,
|
||||
small_trade_threshold_eur=config.small_trade_threshold_eur,
|
||||
small_trade_extra_premium=config.small_trade_extra_premium,
|
||||
eur_min_buy=config.eur_min_buy,
|
||||
eur_max_buy=config.eur_max_buy,
|
||||
eur_min_sell=config.eur_min_sell,
|
||||
eur_max_sell=config.eur_max_sell,
|
||||
)
|
||||
359
backend/tests/test_pricing_api.py
Normal file
359
backend/tests/test_pricing_api.py
Normal file
|
|
@ -0,0 +1,359 @@
|
|||
"""
|
||||
Pricing API Tests
|
||||
|
||||
Tests for the admin pricing configuration endpoints.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from repositories.pricing import PricingRepository
|
||||
|
||||
|
||||
class TestPricingPermissions:
|
||||
"""Test that only admins can access pricing endpoints."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_admin_can_get_pricing(self, client_factory, admin_user):
|
||||
"""Admin can access GET pricing endpoint."""
|
||||
# Seed pricing config first
|
||||
async with client_factory.get_db_session() as db:
|
||||
repo = PricingRepository(db)
|
||||
await repo.create_or_update(
|
||||
premium_buy=5,
|
||||
premium_sell=5,
|
||||
small_trade_threshold_eur=20000,
|
||||
small_trade_extra_premium=2,
|
||||
eur_min_buy=10000,
|
||||
eur_max_buy=300000,
|
||||
eur_min_sell=10000,
|
||||
eur_max_sell=300000,
|
||||
)
|
||||
|
||||
async with client_factory.create(cookies=admin_user["cookies"]) as client:
|
||||
response = await client.get("/api/admin/pricing")
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert "premium_buy" in data
|
||||
assert "premium_sell" in data
|
||||
assert data["premium_buy"] == 5
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_regular_user_cannot_get_pricing(self, client_factory, regular_user):
|
||||
"""Regular user cannot access GET pricing endpoint."""
|
||||
async with client_factory.create(cookies=regular_user["cookies"]) as client:
|
||||
response = await client.get("/api/admin/pricing")
|
||||
|
||||
assert response.status_code == 403
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_unauthenticated_cannot_get_pricing(self, client):
|
||||
"""Unauthenticated user cannot access GET pricing endpoint."""
|
||||
response = await client.get("/api/admin/pricing")
|
||||
assert response.status_code == 401
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_admin_can_update_pricing(self, client_factory, admin_user):
|
||||
"""Admin can access PUT pricing endpoint."""
|
||||
# Seed pricing config first
|
||||
async with client_factory.get_db_session() as db:
|
||||
repo = PricingRepository(db)
|
||||
await repo.create_or_update(
|
||||
premium_buy=5,
|
||||
premium_sell=5,
|
||||
small_trade_threshold_eur=20000,
|
||||
small_trade_extra_premium=2,
|
||||
eur_min_buy=10000,
|
||||
eur_max_buy=300000,
|
||||
eur_min_sell=10000,
|
||||
eur_max_sell=300000,
|
||||
)
|
||||
|
||||
async with client_factory.create(cookies=admin_user["cookies"]) as client:
|
||||
response = await client.put(
|
||||
"/api/admin/pricing",
|
||||
json={
|
||||
"premium_buy": 7,
|
||||
"premium_sell": 6,
|
||||
"small_trade_threshold_eur": 25000,
|
||||
"small_trade_extra_premium": 3,
|
||||
"eur_min_buy": 15000,
|
||||
"eur_max_buy": 350000,
|
||||
"eur_min_sell": 12000,
|
||||
"eur_max_sell": 320000,
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["premium_buy"] == 7
|
||||
assert data["premium_sell"] == 6
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_regular_user_cannot_update_pricing(
|
||||
self, client_factory, regular_user
|
||||
):
|
||||
"""Regular user cannot access PUT pricing endpoint."""
|
||||
async with client_factory.create(cookies=regular_user["cookies"]) as client:
|
||||
response = await client.put(
|
||||
"/api/admin/pricing",
|
||||
json={
|
||||
"premium_buy": 7,
|
||||
"premium_sell": 6,
|
||||
"small_trade_threshold_eur": 25000,
|
||||
"small_trade_extra_premium": 3,
|
||||
"eur_min_buy": 15000,
|
||||
"eur_max_buy": 350000,
|
||||
"eur_min_sell": 12000,
|
||||
"eur_max_sell": 320000,
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 403
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_unauthenticated_cannot_update_pricing(self, client):
|
||||
"""Unauthenticated user cannot access PUT pricing endpoint."""
|
||||
response = await client.put(
|
||||
"/api/admin/pricing",
|
||||
json={
|
||||
"premium_buy": 7,
|
||||
"premium_sell": 6,
|
||||
"small_trade_threshold_eur": 25000,
|
||||
"small_trade_extra_premium": 3,
|
||||
"eur_min_buy": 15000,
|
||||
"eur_max_buy": 350000,
|
||||
"eur_min_sell": 12000,
|
||||
"eur_max_sell": 320000,
|
||||
},
|
||||
)
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
class TestPricingValidation:
|
||||
"""Test validation of pricing configuration updates."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_update_with_valid_data(self, client_factory, admin_user):
|
||||
"""Update with valid data succeeds."""
|
||||
# Seed pricing config first
|
||||
async with client_factory.get_db_session() as db:
|
||||
repo = PricingRepository(db)
|
||||
await repo.create_or_update(
|
||||
premium_buy=5,
|
||||
premium_sell=5,
|
||||
small_trade_threshold_eur=20000,
|
||||
small_trade_extra_premium=2,
|
||||
eur_min_buy=10000,
|
||||
eur_max_buy=300000,
|
||||
eur_min_sell=10000,
|
||||
eur_max_sell=300000,
|
||||
)
|
||||
|
||||
async with client_factory.create(cookies=admin_user["cookies"]) as client:
|
||||
response = await client.put(
|
||||
"/api/admin/pricing",
|
||||
json={
|
||||
"premium_buy": 10,
|
||||
"premium_sell": 8,
|
||||
"small_trade_threshold_eur": 30000,
|
||||
"small_trade_extra_premium": 5,
|
||||
"eur_min_buy": 20000,
|
||||
"eur_max_buy": 400000,
|
||||
"eur_min_sell": 15000,
|
||||
"eur_max_sell": 350000,
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["premium_buy"] == 10
|
||||
assert data["premium_sell"] == 8
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_premium_out_of_range_rejected(self, client_factory, admin_user):
|
||||
"""Premium values outside -100 to 100 are rejected."""
|
||||
# Seed pricing config first
|
||||
async with client_factory.get_db_session() as db:
|
||||
repo = PricingRepository(db)
|
||||
await repo.create_or_update(
|
||||
premium_buy=5,
|
||||
premium_sell=5,
|
||||
small_trade_threshold_eur=20000,
|
||||
small_trade_extra_premium=2,
|
||||
eur_min_buy=10000,
|
||||
eur_max_buy=300000,
|
||||
eur_min_sell=10000,
|
||||
eur_max_sell=300000,
|
||||
)
|
||||
|
||||
async with client_factory.create(cookies=admin_user["cookies"]) as client:
|
||||
# Test premium_buy > 100
|
||||
response = await client.put(
|
||||
"/api/admin/pricing",
|
||||
json={
|
||||
"premium_buy": 101,
|
||||
"premium_sell": 5,
|
||||
"small_trade_threshold_eur": 20000,
|
||||
"small_trade_extra_premium": 2,
|
||||
"eur_min_buy": 10000,
|
||||
"eur_max_buy": 300000,
|
||||
"eur_min_sell": 10000,
|
||||
"eur_max_sell": 300000,
|
||||
},
|
||||
)
|
||||
assert response.status_code == 400
|
||||
|
||||
# Test premium_buy < -100
|
||||
response = await client.put(
|
||||
"/api/admin/pricing",
|
||||
json={
|
||||
"premium_buy": -101,
|
||||
"premium_sell": 5,
|
||||
"small_trade_threshold_eur": 20000,
|
||||
"small_trade_extra_premium": 2,
|
||||
"eur_min_buy": 10000,
|
||||
"eur_max_buy": 300000,
|
||||
"eur_min_sell": 10000,
|
||||
"eur_max_sell": 300000,
|
||||
},
|
||||
)
|
||||
assert response.status_code == 400
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_min_greater_than_max_rejected(self, client_factory, admin_user):
|
||||
"""Min >= Max is rejected."""
|
||||
# Seed pricing config first
|
||||
async with client_factory.get_db_session() as db:
|
||||
repo = PricingRepository(db)
|
||||
await repo.create_or_update(
|
||||
premium_buy=5,
|
||||
premium_sell=5,
|
||||
small_trade_threshold_eur=20000,
|
||||
small_trade_extra_premium=2,
|
||||
eur_min_buy=10000,
|
||||
eur_max_buy=300000,
|
||||
eur_min_sell=10000,
|
||||
eur_max_sell=300000,
|
||||
)
|
||||
|
||||
async with client_factory.create(cookies=admin_user["cookies"]) as client:
|
||||
# Test eur_min_buy >= eur_max_buy
|
||||
response = await client.put(
|
||||
"/api/admin/pricing",
|
||||
json={
|
||||
"premium_buy": 5,
|
||||
"premium_sell": 5,
|
||||
"small_trade_threshold_eur": 20000,
|
||||
"small_trade_extra_premium": 2,
|
||||
"eur_min_buy": 300000,
|
||||
"eur_max_buy": 300000,
|
||||
"eur_min_sell": 10000,
|
||||
"eur_max_sell": 300000,
|
||||
},
|
||||
)
|
||||
assert response.status_code == 400
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_negative_amounts_rejected(self, client_factory, admin_user):
|
||||
"""Negative amounts are rejected."""
|
||||
# Seed pricing config first
|
||||
async with client_factory.get_db_session() as db:
|
||||
repo = PricingRepository(db)
|
||||
await repo.create_or_update(
|
||||
premium_buy=5,
|
||||
premium_sell=5,
|
||||
small_trade_threshold_eur=20000,
|
||||
small_trade_extra_premium=2,
|
||||
eur_min_buy=10000,
|
||||
eur_max_buy=300000,
|
||||
eur_min_sell=10000,
|
||||
eur_max_sell=300000,
|
||||
)
|
||||
|
||||
async with client_factory.create(cookies=admin_user["cookies"]) as client:
|
||||
# Test negative eur_min_buy
|
||||
response = await client.put(
|
||||
"/api/admin/pricing",
|
||||
json={
|
||||
"premium_buy": 5,
|
||||
"premium_sell": 5,
|
||||
"small_trade_threshold_eur": 20000,
|
||||
"small_trade_extra_premium": 2,
|
||||
"eur_min_buy": -1000,
|
||||
"eur_max_buy": 300000,
|
||||
"eur_min_sell": 10000,
|
||||
"eur_max_sell": 300000,
|
||||
},
|
||||
)
|
||||
assert response.status_code == 400
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_zero_amounts_rejected(self, client_factory, admin_user):
|
||||
"""Zero amounts are rejected."""
|
||||
# Seed pricing config first
|
||||
async with client_factory.get_db_session() as db:
|
||||
repo = PricingRepository(db)
|
||||
await repo.create_or_update(
|
||||
premium_buy=5,
|
||||
premium_sell=5,
|
||||
small_trade_threshold_eur=20000,
|
||||
small_trade_extra_premium=2,
|
||||
eur_min_buy=10000,
|
||||
eur_max_buy=300000,
|
||||
eur_min_sell=10000,
|
||||
eur_max_sell=300000,
|
||||
)
|
||||
|
||||
async with client_factory.create(cookies=admin_user["cookies"]) as client:
|
||||
# Test zero eur_min_buy
|
||||
response = await client.put(
|
||||
"/api/admin/pricing",
|
||||
json={
|
||||
"premium_buy": 5,
|
||||
"premium_sell": 5,
|
||||
"small_trade_threshold_eur": 20000,
|
||||
"small_trade_extra_premium": 2,
|
||||
"eur_min_buy": 0,
|
||||
"eur_max_buy": 300000,
|
||||
"eur_min_sell": 10000,
|
||||
"eur_max_sell": 300000,
|
||||
},
|
||||
)
|
||||
assert response.status_code == 400
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_when_no_config_returns_404(self, client_factory, admin_user):
|
||||
"""GET returns 404 when no config exists."""
|
||||
async with client_factory.create(cookies=admin_user["cookies"]) as client:
|
||||
response = await client.get("/api/admin/pricing")
|
||||
|
||||
assert response.status_code == 404
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_update_creates_config_if_none_exists(
|
||||
self, client_factory, admin_user
|
||||
):
|
||||
"""PUT creates config if none exists."""
|
||||
async with client_factory.create(cookies=admin_user["cookies"]) as client:
|
||||
response = await client.put(
|
||||
"/api/admin/pricing",
|
||||
json={
|
||||
"premium_buy": 5,
|
||||
"premium_sell": 5,
|
||||
"small_trade_threshold_eur": 20000,
|
||||
"small_trade_extra_premium": 2,
|
||||
"eur_min_buy": 10000,
|
||||
"eur_max_buy": 300000,
|
||||
"eur_min_sell": 10000,
|
||||
"eur_max_sell": 300000,
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["premium_buy"] == 5
|
||||
|
||||
# Verify it was created
|
||||
response = await client.get("/api/admin/pricing")
|
||||
assert response.status_code == 200
|
||||
Loading…
Add table
Add a link
Reference in a new issue