|
|
|
@ -1,3 +1,4 @@ |
|
|
|
|
|
|
|
from decimal import Decimal |
|
|
|
import arrow |
|
|
|
import arrow |
|
|
|
from django.db.models import Func, F |
|
|
|
from django.db.models import Func, F |
|
|
|
|
|
|
|
|
|
|
|
@ -102,6 +103,7 @@ class Payment(PolymorphicModel): |
|
|
|
roistat_visit = models.PositiveIntegerField('Номер визита Roistat', null=True, editable=False) |
|
|
|
roistat_visit = models.PositiveIntegerField('Номер визита Roistat', null=True, editable=False) |
|
|
|
created_at = models.DateTimeField(auto_now_add=True) |
|
|
|
created_at = models.DateTimeField(auto_now_add=True) |
|
|
|
update_at = models.DateTimeField(auto_now=True) |
|
|
|
update_at = models.DateTimeField(auto_now=True) |
|
|
|
|
|
|
|
bonus = models.ForeignKey('payment.UserBonus', null=True, on_delete=models.SET_NULL, related_name='purchase_payments') |
|
|
|
|
|
|
|
|
|
|
|
objects = PaymentManger() |
|
|
|
objects = PaymentManger() |
|
|
|
|
|
|
|
|
|
|
|
@ -120,18 +122,23 @@ class Payment(PolymorphicModel): |
|
|
|
return result.datetime |
|
|
|
return result.datetime |
|
|
|
|
|
|
|
|
|
|
|
@classmethod |
|
|
|
@classmethod |
|
|
|
def calc_amount(cls, course_payment=None, school_payment=None, user=None, course=None, date_start=None, weekdays=None): |
|
|
|
def calc_amount(cls, payment=None, user=None, course=None, date_start=None, weekdays=None): |
|
|
|
date_start = date_start or now().date() |
|
|
|
date_start = date_start or now().date() |
|
|
|
date_end = Payment.add_months(date_start, 1) |
|
|
|
date_end = Payment.add_months(date_start, 1) |
|
|
|
if course_payment: |
|
|
|
if isinstance(payment, CoursePayment): |
|
|
|
course = course_payment.course |
|
|
|
course = payment.course |
|
|
|
user = course_payment.user |
|
|
|
user = payment.user |
|
|
|
if school_payment: |
|
|
|
if isinstance(payment, SchoolPayment): |
|
|
|
user = school_payment.user |
|
|
|
user = payment.user |
|
|
|
weekdays = school_payment.weekdays |
|
|
|
weekdays = payment.weekdays |
|
|
|
date_start = school_payment.date_start |
|
|
|
date_start = payment.date_start |
|
|
|
discount = 0 |
|
|
|
|
|
|
|
price = 0 |
|
|
|
price = 0 |
|
|
|
|
|
|
|
referral_bonus = 0 |
|
|
|
|
|
|
|
referrer_bonus = 0 |
|
|
|
|
|
|
|
if hasattr(user, 'referral') and not user.referral.payment: |
|
|
|
|
|
|
|
referral_bonus = user.referral.bonus |
|
|
|
|
|
|
|
referrer_bonus = user.referral.referrer_bonus |
|
|
|
|
|
|
|
discount = 0 |
|
|
|
if course: |
|
|
|
if course: |
|
|
|
price = course.price |
|
|
|
price = course.price |
|
|
|
else: |
|
|
|
else: |
|
|
|
@ -140,7 +147,6 @@ class Payment(PolymorphicModel): |
|
|
|
user=user, |
|
|
|
user=user, |
|
|
|
date_start__lte=date_start, |
|
|
|
date_start__lte=date_start, |
|
|
|
date_end__gte=date_start, |
|
|
|
date_end__gte=date_start, |
|
|
|
add_days=False, |
|
|
|
|
|
|
|
status__in=[ |
|
|
|
status__in=[ |
|
|
|
Pingback.PINGBACK_TYPE_REGULAR, |
|
|
|
Pingback.PINGBACK_TYPE_REGULAR, |
|
|
|
Pingback.PINGBACK_TYPE_GOODWILL, |
|
|
|
Pingback.PINGBACK_TYPE_GOODWILL, |
|
|
|
@ -150,8 +156,8 @@ class Payment(PolymorphicModel): |
|
|
|
school_schedules_purchased = school_payments.annotate( |
|
|
|
school_schedules_purchased = school_payments.annotate( |
|
|
|
joined_weekdays=Func(F('weekdays'), function='unnest', ) |
|
|
|
joined_weekdays=Func(F('weekdays'), function='unnest', ) |
|
|
|
).values_list('joined_weekdays', flat=True).distinct() |
|
|
|
).values_list('joined_weekdays', flat=True).distinct() |
|
|
|
weekdays = set(map(int, weekdays)) - set(school_schedules_purchased) |
|
|
|
weekdays = list(set(map(int, weekdays)) - set(school_schedules_purchased)) |
|
|
|
prev_school_payment = school_payments.last() |
|
|
|
prev_school_payment = school_payments.filter(add_days=False).last() |
|
|
|
add_days = bool(prev_school_payment) |
|
|
|
add_days = bool(prev_school_payment) |
|
|
|
else: |
|
|
|
else: |
|
|
|
add_days = False |
|
|
|
add_days = False |
|
|
|
@ -169,15 +175,20 @@ class Payment(PolymorphicModel): |
|
|
|
price = school_schedules.aggregate( |
|
|
|
price = school_schedules.aggregate( |
|
|
|
models.Sum('month_price'), |
|
|
|
models.Sum('month_price'), |
|
|
|
).get('month_price__sum', 0) |
|
|
|
).get('month_price__sum', 0) |
|
|
|
if not (school_payment and school_payment.id) and price >= config.SERVICE_DISCOUNT_MIN_AMOUNT: |
|
|
|
if not (payment and payment.id) and price >= config.SERVICE_DISCOUNT_MIN_AMOUNT: |
|
|
|
discount = config.SERVICE_DISCOUNT |
|
|
|
discount = config.SERVICE_DISCOUNT |
|
|
|
amount = price - discount |
|
|
|
amount = price - discount |
|
|
|
|
|
|
|
referral_bonus = round(amount * referral_bonus / 100) |
|
|
|
|
|
|
|
referrer_bonus = round(amount * referrer_bonus / 100) |
|
|
|
return { |
|
|
|
return { |
|
|
|
'price': price, |
|
|
|
'price': price, |
|
|
|
'amount': amount, |
|
|
|
'amount': amount, |
|
|
|
|
|
|
|
'referral_bonus': referral_bonus, |
|
|
|
|
|
|
|
'referrer_bonus': referrer_bonus, |
|
|
|
'discount': discount, |
|
|
|
'discount': discount, |
|
|
|
'date_start': date_start, |
|
|
|
'date_start': date_start, |
|
|
|
'date_end': date_end, |
|
|
|
'date_end': date_end, |
|
|
|
|
|
|
|
'weekdays': weekdays, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
def calc_commission(self): |
|
|
|
def calc_commission(self): |
|
|
|
@ -199,6 +210,36 @@ class Payment(PolymorphicModel): |
|
|
|
Pingback.PINGBACK_TYPE_RISK_REVIEWED_DECLINED, |
|
|
|
Pingback.PINGBACK_TYPE_RISK_REVIEWED_DECLINED, |
|
|
|
] |
|
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def save(self, *args, **kwargs): |
|
|
|
|
|
|
|
paid = self.status in [Pingback.PINGBACK_TYPE_REGULAR, Pingback.PINGBACK_TYPE_GOODWILL, |
|
|
|
|
|
|
|
Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED,] |
|
|
|
|
|
|
|
amount_data = Payment.calc_amount(payment=self) |
|
|
|
|
|
|
|
print('amount_data', amount_data) |
|
|
|
|
|
|
|
if self.status is None and not self.bonus: |
|
|
|
|
|
|
|
print(123) |
|
|
|
|
|
|
|
self.amount = amount_data.get('amount') |
|
|
|
|
|
|
|
if isinstance(self, SchoolPayment): |
|
|
|
|
|
|
|
self.weekdays = amount_data.get('weekdays') |
|
|
|
|
|
|
|
super().save(*args, **kwargs) |
|
|
|
|
|
|
|
if isinstance(self, CoursePayment) and paid: |
|
|
|
|
|
|
|
author_balance = getattr(self, 'authorbalance', None) |
|
|
|
|
|
|
|
if not author_balance : |
|
|
|
|
|
|
|
AuthorBalance.objects.create( |
|
|
|
|
|
|
|
author=self.course.author, |
|
|
|
|
|
|
|
amount=self.amount, |
|
|
|
|
|
|
|
payment=self, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
author_balance.amount = self.amount |
|
|
|
|
|
|
|
author_balance.save() |
|
|
|
|
|
|
|
# Если юзер реферал и нет платежа, где применялась скидка |
|
|
|
|
|
|
|
if hasattr(self.user, 'referral') and not self.user.referral.payment and paid: |
|
|
|
|
|
|
|
# Платеж - как сигнал, что скидка применилась |
|
|
|
|
|
|
|
self.user.referral.payment = self |
|
|
|
|
|
|
|
self.user.referral.save() |
|
|
|
|
|
|
|
# Отправляем кэшбэк |
|
|
|
|
|
|
|
self.user.referral.send_bonuses(amount_data.get('referral_bonus'), amount_data.get('referrer_bonus')) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CoursePayment(Payment): |
|
|
|
class CoursePayment(Payment): |
|
|
|
course = models.ForeignKey(Course, on_delete=models.CASCADE, verbose_name='Курс', related_name='payments') |
|
|
|
course = models.ForeignKey(Course, on_delete=models.CASCADE, verbose_name='Курс', related_name='payments') |
|
|
|
@ -207,22 +248,6 @@ class CoursePayment(Payment): |
|
|
|
verbose_name = 'Платеж за курс' |
|
|
|
verbose_name = 'Платеж за курс' |
|
|
|
verbose_name_plural = 'Платежи за курсы' |
|
|
|
verbose_name_plural = 'Платежи за курсы' |
|
|
|
|
|
|
|
|
|
|
|
def save(self, *args, **kwargs): |
|
|
|
|
|
|
|
if self.status is None: |
|
|
|
|
|
|
|
amount_data = Payment.calc_amount(course_payment=self) |
|
|
|
|
|
|
|
self.amount = amount_data.get('amount') |
|
|
|
|
|
|
|
super().save(*args, **kwargs) |
|
|
|
|
|
|
|
author_balance = getattr(self, 'authorbalance', None) |
|
|
|
|
|
|
|
if not author_balance: |
|
|
|
|
|
|
|
AuthorBalance.objects.create( |
|
|
|
|
|
|
|
author=self.course.author, |
|
|
|
|
|
|
|
amount=self.amount, |
|
|
|
|
|
|
|
payment=self, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
author_balance.amount = self.amount |
|
|
|
|
|
|
|
author_balance.save() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SchoolPayment(Payment): |
|
|
|
class SchoolPayment(Payment): |
|
|
|
weekdays = ArrayField(models.IntegerField(), size=7, verbose_name='Дни недели') |
|
|
|
weekdays = ArrayField(models.IntegerField(), size=7, verbose_name='Дни недели') |
|
|
|
@ -241,12 +266,17 @@ class SchoolPayment(Payment): |
|
|
|
]) |
|
|
|
]) |
|
|
|
return days |
|
|
|
return days |
|
|
|
|
|
|
|
|
|
|
|
def save(self, *args, **kwargs): |
|
|
|
|
|
|
|
if self.status is None: |
|
|
|
|
|
|
|
amount_data = Payment.calc_amount(school_payment=self) |
|
|
|
|
|
|
|
self.amount = amount_data.get('amount') |
|
|
|
|
|
|
|
super().save(*args, **kwargs) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@property |
|
|
|
@property |
|
|
|
def date_end_humanize(self): |
|
|
|
def date_end_humanize(self): |
|
|
|
return arrow.get(self.date_end, settings.TIME_ZONE).humanize(locale='ru') |
|
|
|
return arrow.get(self.date_end, settings.TIME_ZONE).humanize(locale='ru') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class UserBonus(models.Model): |
|
|
|
|
|
|
|
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='bonuses') |
|
|
|
|
|
|
|
amount = models.DecimalField(max_digits=8, decimal_places=2, default=0, editable=False) |
|
|
|
|
|
|
|
payment = models.ForeignKey(Payment, on_delete=models.SET_NULL, null=True) |
|
|
|
|
|
|
|
referral = models.ForeignKey('user.Referral', on_delete=models.SET_NULL, null=True) |
|
|
|
|
|
|
|
created_at = models.DateTimeField(auto_now_add=True) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Meta: |
|
|
|
|
|
|
|
ordering = ('created_at',) |
|
|
|
|