Разработка партнёрской программы (Affiliate Platform)

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.
Разработка и обслуживание любых видов сайтов:
Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Разработка партнёрской программы (Affiliate Platform)
Средняя
от 1 недели до 3 месяцев
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1214
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    852
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    823
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    815

Разработка партнёрской программы (Affiliate Platform)

Партнёрская программа позволяет владельцам трафика продвигать продукт за комиссию. Партнёр получает уникальную ссылку, приводит клиента, система фиксирует это и начисляет вознаграждение. Технически задача — надёжный трекинг, честный расчёт комиссий и удобный личный кабинет партнёра.

Схема данных

CREATE TABLE affiliates (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id         UUID UNIQUE NOT NULL REFERENCES users(id),
    ref_code        VARCHAR(20) UNIQUE NOT NULL,
    status          VARCHAR(20) NOT NULL DEFAULT 'pending'
                    CHECK (status IN ('pending','active','suspended','terminated')),
    commission_rate NUMERIC(5,2) NOT NULL DEFAULT 10,  -- % от суммы
    commission_type VARCHAR(20) NOT NULL DEFAULT 'percent'
                    CHECK (commission_type IN ('percent','fixed','hybrid')),
    fixed_amount    NUMERIC(12,2),           -- для fixed/hybrid типов
    cookie_days     INTEGER NOT NULL DEFAULT 30,
    payout_min      NUMERIC(12,2) NOT NULL DEFAULT 1000,
    approved_at     TIMESTAMPTZ,
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE affiliate_links (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    affiliate_id    UUID NOT NULL REFERENCES affiliates(id),
    campaign_name   VARCHAR(200),
    landing_url     VARCHAR(500) NOT NULL,
    params          JSONB DEFAULT '{}',  -- UTM и кастомные параметры
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE affiliate_clicks (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    affiliate_id    UUID NOT NULL REFERENCES affiliates(id),
    link_id         UUID REFERENCES affiliate_links(id),
    ip              INET,
    user_agent      TEXT,
    referrer        VARCHAR(500),
    fingerprint     VARCHAR(64),   -- device fingerprint для cross-device
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_affiliate_clicks_date ON affiliate_clicks(affiliate_id, created_at DESC);

CREATE TABLE affiliate_conversions (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    affiliate_id    UUID NOT NULL REFERENCES affiliates(id),
    click_id        UUID REFERENCES affiliate_clicks(id),
    customer_id     UUID REFERENCES users(id),
    order_id        UUID,
    order_amount    NUMERIC(15,2),
    commission      NUMERIC(15,2) NOT NULL,
    status          VARCHAR(20) NOT NULL DEFAULT 'pending'
                    CHECK (status IN ('pending','confirmed','rejected','paid')),
    rejection_reason VARCHAR(200),
    hold_days       INTEGER NOT NULL DEFAULT 30,
    available_at    DATE,
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

Трекинг кликов

import hashlib
from django.core.cache import cache


def track_affiliate_click(request, ref_code: str, landing_url: str) -> str | None:
    affiliate = Affiliate.objects.filter(
        ref_code=ref_code, status='active'
    ).first()

    if not affiliate:
        return None

    # Device fingerprint для кросс-девайс атрибуции
    fingerprint_raw = f'{request.META.get("HTTP_USER_AGENT")}:{request.META.get("ACCEPT_LANGUAGE")}'
    fingerprint = hashlib.sha256(fingerprint_raw.encode()).hexdigest()[:32]

    click = AffiliateClick.objects.create(
        affiliate=affiliate,
        ip=get_client_ip(request),
        user_agent=request.META.get('HTTP_USER_AGENT', ''),
        referrer=request.META.get('HTTP_REFERER', ''),
        fingerprint=fingerprint,
    )

    # Кука для атрибуции
    cookie_value = str(click.id)
    return cookie_value  # устанавливается в response


def set_affiliate_cookie(response, click_id: str, cookie_days: int):
    response.set_cookie(
        'aff_click',
        click_id,
        max_age=cookie_days * 86400,
        httponly=True,
        samesite='Lax',
    )

Атрибуция конверсии

def attribute_conversion(order, request):
    """Вызывается после успешной оплаты заказа"""
    click_id = request.COOKIES.get('aff_click')
    affiliate = None
    click = None

    if click_id:
        click = AffiliateClick.objects.filter(id=click_id).first()
        if click:
            # Проверяем, не истёк ли cookie window
            cutoff = timezone.now() - timedelta(days=click.affiliate.cookie_days)
            if click.created_at >= cutoff:
                affiliate = click.affiliate

    if not affiliate:
        # Fallback: ищем по fingerprint (кросс-девайс)
        fingerprint = compute_fingerprint(request)
        recent_click = AffiliateClick.objects.filter(
            fingerprint=fingerprint,
            created_at__gte=timezone.now() - timedelta(days=30)
        ).order_by('-created_at').first()
        if recent_click:
            affiliate = recent_click.affiliate
            click = recent_click

    if affiliate:
        commission = calculate_commission(affiliate, order.total_amount)
        AffiliateConversion.objects.create(
            affiliate=affiliate,
            click=click,
            customer=order.user,
            order=order,
            order_amount=order.total_amount,
            commission=commission,
            hold_days=affiliate.hold_days,
            available_at=date.today() + timedelta(days=affiliate.hold_days),
        )

        # Инвалидируем куку после конверсии
        return True

    return False


def calculate_commission(affiliate, order_amount: Decimal) -> Decimal:
    if affiliate.commission_type == 'percent':
        return (order_amount * affiliate.commission_rate / 100).quantize(Decimal('0.01'))
    elif affiliate.commission_type == 'fixed':
        return affiliate.fixed_amount
    else:  # hybrid
        percent_part = order_amount * affiliate.commission_rate / 100
        return (percent_part + affiliate.fixed_amount).quantize(Decimal('0.01'))

Многоуровневая партнёрская программа

class AffiliateRelation(models.Model):
    """Дерево партнёров для многоуровневой программы"""
    affiliate = models.OneToOneField(Affiliate, on_delete=models.CASCADE)
    parent = models.ForeignKey(
        'self', null=True, blank=True,
        on_delete=models.SET_NULL, related_name='children'
    )
    level = models.IntegerField(default=1)


REFERRAL_RATES = {
    1: Decimal('10'),   # прямой партнёр: 10%
    2: Decimal('3'),    # партнёр партнёра: 3%
    3: Decimal('1'),    # третий уровень: 1%
}


def distribute_multilevel_commission(conversion):
    """Начисляем комиссию по всей цепочке вверх"""
    relation = AffiliateRelation.objects.filter(
        affiliate=conversion.affiliate
    ).first()

    level = 1
    current = relation

    while current and level <= 3:
        rate = REFERRAL_RATES.get(level)
        if rate:
            commission = (conversion.order_amount * rate / 100).quantize(Decimal('0.01'))
            AffiliateConversion.objects.create(
                affiliate=current.affiliate,
                order=conversion.order,
                order_amount=conversion.order_amount,
                commission=commission,
                status='pending',
                hold_days=current.affiliate.hold_days,
                available_at=date.today() + timedelta(days=current.affiliate.hold_days),
            )
        current = current.parent
        level += 1

Выплаты партнёрам

@shared_task
def process_affiliate_payouts():
    """Ежедневно: выплачиваем партнёрам с доступным балансом"""
    affiliates_with_balance = (
        Affiliate.objects
        .annotate(
            available=Coalesce(
                Subquery(
                    AffiliateConversion.objects.filter(
                        affiliate=OuterRef('pk'),
                        status='confirmed',
                        available_at__lte=date.today()
                    ).values('affiliate').annotate(s=Sum('commission')).values('s')
                ),
                Decimal('0')
            )
        )
        .filter(available__gte=F('payout_min'), status='active')
    )

    for affiliate in affiliates_with_balance:
        initiate_payout(affiliate, affiliate.available)

Антифрод

def check_conversion_fraud(conversion) -> bool:
    """Базовые фрод-проверки"""
    # Самореферрал
    if conversion.customer == conversion.affiliate.user:
        conversion.status = 'rejected'
        conversion.rejection_reason = 'self_referral'
        conversion.save()
        return True

    # Слишком много конверсий с одного IP за час
    recent_from_ip = AffiliateConversion.objects.filter(
        click__ip=conversion.click.ip if conversion.click else None,
        created_at__gte=timezone.now() - timedelta(hours=1)
    ).count()

    if recent_from_ip > 10:
        flag_for_review(conversion, 'high_conversion_rate_from_ip')
        return True

    # Конверсия через несколько секунд после клика
    if conversion.click:
        time_to_convert = (conversion.created_at - conversion.click.created_at).total_seconds()
        if time_to_convert < 30:
            flag_for_review(conversion, 'instant_conversion')
            return True

    return False

Сроки

Базовая партнёрская программа (одноуровневая, percent-комиссия, личный кабинет, выплата на карту): 3–4 недели. С многоуровневой структурой, антифродом, детальной аналитикой по кампаниям и автоматическими выплатами: 6–8 недель.