Initial commit - clean project structure
This commit is contained in:
56
discount/services.py
Normal file
56
discount/services.py
Normal file
@@ -0,0 +1,56 @@
|
||||
"""
|
||||
منطق آفرهای رایگان (Offer/UserOffer)، جدا از منطق موجود DiscountCode
|
||||
(تخفیف روی مبلغ سفارش). اینجا محل تنها جاییه که تصمیم میگیره «اعمال یک
|
||||
آفر» دقیقاً یعنی چی (الان: فعالسازی اشتراک رایگان/محدود) — طبق درخواست
|
||||
سینیور برای signal-based و قابلتغییر بودنِ این منطق، تغییر دادنِ رفتار
|
||||
آفرها (مثلاً بجای اشتراک، دسترسی به یک اپ خاص) فقط همین فایل رو لمس میکنه،
|
||||
نه apps.py/receivers.py و نه هیچ اپ دیگهای.
|
||||
"""
|
||||
from django.db import IntegrityError
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
from .models import Offer, UserOffer
|
||||
|
||||
|
||||
def apply_offer(*, user_id: int, offer: Offer, source: str) -> UserOffer | None:
|
||||
"""
|
||||
یک آفر رو به یک کاربر اختصاص میده و اثرش رو اعمال میکنه (فعلاً: اشتراک
|
||||
رایگان/محدود). اگه کاربر قبلاً همین آفر رو گرفته باشه (unique constraint)
|
||||
None برمیگردونه، نه خطا — چون auto-assign هنگام ثبتنام نباید کرش کنه.
|
||||
"""
|
||||
if not offer.is_active:
|
||||
return None
|
||||
|
||||
try:
|
||||
user_offer = UserOffer.objects.create(
|
||||
user_id=user_id, offer=offer, source=source,
|
||||
expires_at=None, # پایینتر بعد از فعالسازی اشتراک ست میشه
|
||||
)
|
||||
except IntegrityError:
|
||||
return None
|
||||
|
||||
from subscription.services import grant_free_subscription
|
||||
|
||||
duration_days = offer.duration_days if offer.kind == 'trial' else None
|
||||
subscription = grant_free_subscription(
|
||||
user_id, duration_days=duration_days, event=f'offer_{offer.kind}',
|
||||
)
|
||||
|
||||
user_offer.expires_at = subscription.expires_at
|
||||
user_offer.save(update_fields=['expires_at'])
|
||||
return user_offer
|
||||
|
||||
|
||||
def redeem_offer_code(*, user_id: int, code: str) -> UserOffer:
|
||||
"""POST /api/discount/offers/redeem — اعمال آفر با کد، هر زمان بعد از ثبتنام."""
|
||||
offer = Offer.objects.filter(code=code, is_active=True).first()
|
||||
if offer is None:
|
||||
raise ValidationError({'code': 'این کد آفر معتبر نیست.'})
|
||||
|
||||
if UserOffer.objects.filter(offer=offer, user_id=user_id).exists():
|
||||
raise ValidationError({'code': 'شما قبلاً این آفر را دریافت کردهاید.'})
|
||||
|
||||
user_offer = apply_offer(user_id=user_id, offer=offer, source='code')
|
||||
if user_offer is None:
|
||||
raise ValidationError({'code': 'این کد آفر معتبر نیست یا غیرفعال شده است.'})
|
||||
return user_offer
|
||||
Reference in New Issue
Block a user