arbret/backend/services/pricing.py
counterweight 4d0dad8e2b
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
2025-12-26 20:13:24 +01:00

106 lines
4 KiB
Python

"""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,
)