""" Seed data for Yield affiliate partners. Run via: python -m app.seeds.yield_partners Or: from app.seeds.yield_partners import seed_partners; await seed_partners(db) """ import asyncio import logging from decimal import Decimal from typing import Any from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.database import AsyncSessionLocal from app.models.yield_domain import AffiliatePartner logger = logging.getLogger(__name__) # Partner configurations grouped by category PARTNER_SEED_DATA: list[dict[str, Any]] = [ # ========================================================================= # MEDICAL / HEALTH # ========================================================================= { "name": "Comparis Dental", "slug": "comparis_dental", "network": "direct", "intent_categories": "medical_dental", "geo_countries": "CH", "payout_type": "cpl", "payout_amount": Decimal("25.00"), "payout_currency": "CHF", "description": "Dental treatment comparison platform. High conversion for Swiss dental searches.", "priority": 100, }, { "name": "Swisssmile", "slug": "swisssmile", "network": "awin", "intent_categories": "medical_dental", "geo_countries": "CH,DE,AT", "payout_type": "cpl", "payout_amount": Decimal("30.00"), "payout_currency": "CHF", "description": "Premium dental clinics network.", "priority": 90, }, { "name": "Comparis Health", "slug": "comparis_health", "network": "direct", "intent_categories": "medical_general", "geo_countries": "CH", "payout_type": "cpl", "payout_amount": Decimal("20.00"), "payout_currency": "CHF", "description": "Health insurance comparison.", "priority": 100, }, { "name": "Sanitas", "slug": "sanitas", "network": "awin", "intent_categories": "medical_general", "geo_countries": "CH", "payout_type": "cpl", "payout_amount": Decimal("35.00"), "payout_currency": "CHF", "description": "Swiss health insurance provider.", "priority": 80, }, { "name": "Swiss Esthetic", "slug": "swissesthetic", "network": "direct", "intent_categories": "medical_beauty", "geo_countries": "CH", "payout_type": "cpl", "payout_amount": Decimal("40.00"), "payout_currency": "CHF", "description": "Aesthetic treatments and beauty clinics.", "priority": 90, }, # ========================================================================= # FINANCE / INSURANCE # ========================================================================= { "name": "Comparis Insurance", "slug": "comparis_insurance", "network": "direct", "intent_categories": "finance_insurance", "geo_countries": "CH", "payout_type": "cpl", "payout_amount": Decimal("30.00"), "payout_currency": "CHF", "description": "All-in-one insurance comparison.", "priority": 100, }, { "name": "Bonus.ch", "slug": "bonus_ch", "network": "awin", "intent_categories": "finance_insurance", "geo_countries": "CH", "payout_type": "cpl", "payout_amount": Decimal("25.00"), "payout_currency": "CHF", "description": "Swiss insurance comparison portal.", "priority": 80, }, { "name": "Comparis Hypo", "slug": "comparis_hypo", "network": "direct", "intent_categories": "finance_mortgage", "geo_countries": "CH", "payout_type": "cpl", "payout_amount": Decimal("100.00"), "payout_currency": "CHF", "description": "Mortgage comparison - high value leads.", "priority": 100, }, { "name": "MoneyPark", "slug": "moneypark", "network": "awin", "intent_categories": "finance_mortgage", "geo_countries": "CH", "payout_type": "cpl", "payout_amount": Decimal("120.00"), "payout_currency": "CHF", "description": "Independent mortgage broker.", "priority": 90, }, { "name": "Neon Bank", "slug": "neon_bank", "network": "partnerstack", "intent_categories": "finance_banking", "geo_countries": "CH", "payout_type": "cps", "payout_amount": Decimal("50.00"), "payout_currency": "CHF", "description": "Swiss mobile banking app.", "priority": 80, }, # ========================================================================= # LEGAL # ========================================================================= { "name": "Legal CH", "slug": "legal_ch", "network": "direct", "intent_categories": "legal_general", "geo_countries": "CH", "payout_type": "cpl", "payout_amount": Decimal("50.00"), "payout_currency": "CHF", "description": "Lawyer matching service.", "priority": 100, }, { "name": "Anwalt24", "slug": "anwalt24", "network": "awin", "intent_categories": "legal_general", "geo_countries": "DE,AT", "payout_type": "cpl", "payout_amount": Decimal("35.00"), "payout_currency": "EUR", "description": "German lawyer directory.", "priority": 80, }, # ========================================================================= # REAL ESTATE # ========================================================================= { "name": "Homegate", "slug": "homegate", "network": "awin", "intent_categories": "realestate_buy,realestate_rent", "geo_countries": "CH", "payout_type": "cpc", "payout_amount": Decimal("0.50"), "payout_currency": "CHF", "description": "Switzerland's #1 real estate platform.", "priority": 100, }, { "name": "ImmoScout24", "slug": "immoscout", "network": "awin", "intent_categories": "realestate_buy,realestate_rent", "geo_countries": "CH,DE", "payout_type": "cpc", "payout_amount": Decimal("0.40"), "payout_currency": "CHF", "description": "Real estate marketplace.", "priority": 90, }, { "name": "Comparis Immo", "slug": "comparis_immo", "network": "direct", "intent_categories": "realestate_buy,realestate_rent", "geo_countries": "CH", "payout_type": "cpl", "payout_amount": Decimal("15.00"), "payout_currency": "CHF", "description": "Property valuation and search.", "priority": 85, }, # ========================================================================= # TRAVEL # ========================================================================= { "name": "Skyscanner", "slug": "skyscanner", "network": "awin", "intent_categories": "travel_flights", "geo_countries": "CH,DE,AT", "payout_type": "cpc", "payout_amount": Decimal("0.30"), "payout_currency": "CHF", "description": "Flight comparison engine.", "priority": 90, }, { "name": "Booking.com", "slug": "booking_com", "network": "awin", "intent_categories": "travel_hotels", "geo_countries": "CH,DE,AT", "payout_type": "cps", "payout_amount": Decimal("4.00"), # 4% commission "payout_currency": "CHF", "description": "World's leading accommodation site.", "priority": 100, }, # ========================================================================= # AUTOMOTIVE # ========================================================================= { "name": "AutoScout24", "slug": "autoscout", "network": "awin", "intent_categories": "auto_buy", "geo_countries": "CH,DE", "payout_type": "cpc", "payout_amount": Decimal("0.60"), "payout_currency": "CHF", "description": "Auto marketplace.", "priority": 100, }, { "name": "Comparis Auto", "slug": "comparis_auto", "network": "direct", "intent_categories": "auto_buy,auto_service", "geo_countries": "CH", "payout_type": "cpl", "payout_amount": Decimal("25.00"), "payout_currency": "CHF", "description": "Car insurance & leasing comparison.", "priority": 90, }, # ========================================================================= # JOBS # ========================================================================= { "name": "Jobs.ch", "slug": "jobs_ch", "network": "awin", "intent_categories": "jobs", "geo_countries": "CH", "payout_type": "cpc", "payout_amount": Decimal("0.40"), "payout_currency": "CHF", "description": "Swiss job board.", "priority": 100, }, { "name": "Indeed", "slug": "indeed", "network": "awin", "intent_categories": "jobs", "geo_countries": "CH,DE,AT", "payout_type": "cpc", "payout_amount": Decimal("0.25"), "payout_currency": "CHF", "description": "Global job search engine.", "priority": 80, }, # ========================================================================= # EDUCATION # ========================================================================= { "name": "Udemy", "slug": "udemy", "network": "awin", "intent_categories": "education", "geo_countries": "CH,DE,AT", "payout_type": "cps", "payout_amount": Decimal("10.00"), # Per sale "payout_currency": "USD", "description": "Online courses platform.", "priority": 80, }, # ========================================================================= # TECHNOLOGY / HOSTING # ========================================================================= { "name": "Hostpoint", "slug": "hostpoint", "network": "partnerstack", "intent_categories": "tech_hosting", "geo_countries": "CH", "payout_type": "cps", "payout_amount": Decimal("30.00"), "payout_currency": "CHF", "description": "Swiss web hosting leader.", "priority": 100, }, { "name": "Infomaniak", "slug": "infomaniak", "network": "direct", "intent_categories": "tech_hosting", "geo_countries": "CH", "payout_type": "cps", "payout_amount": Decimal("25.00"), "payout_currency": "CHF", "description": "Eco-friendly Swiss hosting.", "priority": 90, }, # ========================================================================= # SHOPPING # ========================================================================= { "name": "Galaxus", "slug": "galaxus", "network": "awin", "intent_categories": "shopping_general", "geo_countries": "CH", "payout_type": "cps", "payout_amount": Decimal("2.00"), # 2% commission "payout_currency": "CHF", "description": "Switzerland's largest online shop.", "priority": 100, }, { "name": "Zalando", "slug": "zalando", "network": "awin", "intent_categories": "shopping_fashion", "geo_countries": "CH,DE,AT", "payout_type": "cps", "payout_amount": Decimal("8.00"), # 8% commission "payout_currency": "CHF", "description": "Fashion & lifestyle.", "priority": 100, }, # ========================================================================= # FOOD / DELIVERY # ========================================================================= { "name": "Uber Eats", "slug": "uber_eats", "network": "awin", "intent_categories": "food_restaurant,food_delivery", "geo_countries": "CH,DE", "payout_type": "cps", "payout_amount": Decimal("5.00"), "payout_currency": "CHF", "description": "Food delivery service.", "priority": 90, }, # ========================================================================= # GENERIC FALLBACK # ========================================================================= { "name": "Generic Affiliate", "slug": "generic_affiliate", "network": "internal", "intent_categories": "generic", "geo_countries": "CH,DE,AT", "payout_type": "cpc", "payout_amount": Decimal("0.10"), "payout_currency": "CHF", "description": "Fallback for unclassified domains - shows Pounce marketplace.", "priority": 1, }, ] async def seed_partners(db: AsyncSession) -> int: """ Seed affiliate partners into database. Idempotent: updates existing partners by slug, creates new ones. Returns: Number of partners created/updated. """ count = 0 for data in PARTNER_SEED_DATA: slug = data["slug"] # Check if partner exists result = await db.execute( select(AffiliatePartner).where(AffiliatePartner.slug == slug) ) existing = result.scalar_one_or_none() if existing: # Update existing partner for key, value in data.items(): setattr(existing, key, value) logger.info(f"Updated partner: {slug}") else: # Create new partner partner = AffiliatePartner(**data) db.add(partner) logger.info(f"Created partner: {slug}") count += 1 await db.commit() logger.info(f"Seeded {count} affiliate partners") return count async def main(): """Run seed script standalone.""" logging.basicConfig(level=logging.INFO) async with AsyncSessionLocal() as db: count = await seed_partners(db) print(f"✅ Seeded {count} affiliate partners") if __name__ == "__main__": asyncio.run(main())