Add improvements
This commit is contained in:
127
services/tenant/app/jobs/startup_seeder.py
Normal file
127
services/tenant/app/jobs/startup_seeder.py
Normal file
@@ -0,0 +1,127 @@
|
||||
"""
|
||||
Startup seeder for tenant service.
|
||||
Seeds initial data (like pilot coupons) on service startup.
|
||||
All operations are idempotent - safe to run multiple times.
|
||||
"""
|
||||
|
||||
import os
|
||||
import uuid
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from typing import Optional
|
||||
|
||||
import structlog
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.models.coupon import CouponModel
|
||||
|
||||
logger = structlog.get_logger()
|
||||
|
||||
|
||||
async def ensure_pilot_coupon(session: AsyncSession) -> Optional[CouponModel]:
|
||||
"""
|
||||
Ensure the PILOT2025 coupon exists in the database.
|
||||
|
||||
This coupon provides 3 months (90 days) free trial extension
|
||||
for the first 20 pilot customers.
|
||||
|
||||
This function is idempotent - it will not create duplicates.
|
||||
|
||||
Args:
|
||||
session: Database session
|
||||
|
||||
Returns:
|
||||
The coupon model (existing or newly created), or None if disabled
|
||||
"""
|
||||
# Check if pilot mode is enabled via environment variable
|
||||
pilot_mode_enabled = os.getenv("VITE_PILOT_MODE_ENABLED", "true").lower() == "true"
|
||||
|
||||
if not pilot_mode_enabled:
|
||||
logger.info("Pilot mode is disabled, skipping coupon seeding")
|
||||
return None
|
||||
|
||||
coupon_code = os.getenv("VITE_PILOT_COUPON_CODE", "PILOT2025")
|
||||
trial_months = int(os.getenv("VITE_PILOT_TRIAL_MONTHS", "3"))
|
||||
max_redemptions = int(os.getenv("PILOT_MAX_REDEMPTIONS", "20"))
|
||||
|
||||
# Check if coupon already exists
|
||||
result = await session.execute(
|
||||
select(CouponModel).where(CouponModel.code == coupon_code)
|
||||
)
|
||||
existing_coupon = result.scalars().first()
|
||||
|
||||
if existing_coupon:
|
||||
logger.info(
|
||||
"Pilot coupon already exists",
|
||||
code=coupon_code,
|
||||
current_redemptions=existing_coupon.current_redemptions,
|
||||
max_redemptions=existing_coupon.max_redemptions,
|
||||
active=existing_coupon.active
|
||||
)
|
||||
return existing_coupon
|
||||
|
||||
# Create new coupon
|
||||
now = datetime.now(timezone.utc)
|
||||
valid_until = now + timedelta(days=180) # Valid for 6 months
|
||||
trial_days = trial_months * 30 # Approximate days
|
||||
|
||||
coupon = CouponModel(
|
||||
id=uuid.uuid4(),
|
||||
code=coupon_code,
|
||||
discount_type="trial_extension",
|
||||
discount_value=trial_days,
|
||||
max_redemptions=max_redemptions,
|
||||
current_redemptions=0,
|
||||
valid_from=now,
|
||||
valid_until=valid_until,
|
||||
active=True,
|
||||
created_at=now,
|
||||
extra_data={
|
||||
"program": "pilot_launch_2025",
|
||||
"description": f"Programa piloto - {trial_months} meses gratis para los primeros {max_redemptions} clientes",
|
||||
"terms": "Válido para nuevos registros únicamente. Un cupón por cliente."
|
||||
}
|
||||
)
|
||||
|
||||
session.add(coupon)
|
||||
await session.commit()
|
||||
await session.refresh(coupon)
|
||||
|
||||
logger.info(
|
||||
"Pilot coupon created successfully",
|
||||
code=coupon_code,
|
||||
type="Trial Extension",
|
||||
value=f"{trial_days} days ({trial_months} months)",
|
||||
max_redemptions=max_redemptions,
|
||||
valid_until=valid_until.isoformat(),
|
||||
id=str(coupon.id)
|
||||
)
|
||||
|
||||
return coupon
|
||||
|
||||
|
||||
async def run_startup_seeders(database_manager) -> None:
|
||||
"""
|
||||
Run all startup seeders.
|
||||
|
||||
This function is called during service startup to ensure
|
||||
required seed data exists in the database.
|
||||
|
||||
Args:
|
||||
database_manager: The database manager instance
|
||||
"""
|
||||
logger.info("Running startup seeders...")
|
||||
|
||||
try:
|
||||
async with database_manager.get_session() as session:
|
||||
# Seed pilot coupon
|
||||
await ensure_pilot_coupon(session)
|
||||
|
||||
logger.info("Startup seeders completed successfully")
|
||||
|
||||
except Exception as e:
|
||||
# Log but don't fail startup - seed data is not critical
|
||||
logger.warning(
|
||||
"Startup seeder encountered an error (non-fatal)",
|
||||
error=str(e)
|
||||
)
|
||||
Reference in New Issue
Block a user