from django.db import models from django.contrib.auth import get_user_model from django.contrib.postgres.fields import ArrayField, JSONField from constance import config from paymentwall import Pingback from polymorphic.models import PolymorphicModel from apps.course.models import Course from apps.school.models import SchoolSchedule User = get_user_model() class AuthorBalance(models.Model): IN = 0 OUT = 1 TYPE_CHOICES = ( (IN, 'In'), (OUT, 'Out'), ) PENDING = 0 ACCEPTED = 1 DECLINED = 2 STATUS_CHOICES = ( (PENDING, 'Pending'), (ACCEPTED, 'Accepted'), (DECLINED, 'Declined'), ) author = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='Автор', null=True, blank=True, related_name='balances') type = models.PositiveSmallIntegerField('Тип', choices=TYPE_CHOICES, default=0) amount = models.DecimalField('Итого', max_digits=8, decimal_places=2, default=0) commission = models.DecimalField('Комиссия', max_digits=8, decimal_places=2, default=0) status = models.PositiveSmallIntegerField('Статус', choices=STATUS_CHOICES, default=0) payment = models.OneToOneField('Payment', on_delete=models.CASCADE, null=True, blank=True, verbose_name='Платёж') cause = models.TextField('Причина отказа', null=True, blank=True) class Meta: verbose_name = 'Баланс' verbose_name_plural = 'Балансы' class Payment(PolymorphicModel): PW_STATUS_CHOICES = ( (Pingback.PINGBACK_TYPE_REGULAR, 'regular',), (Pingback.PINGBACK_TYPE_GOODWILL, 'goodwill',), (Pingback.PINGBACK_TYPE_NEGATIVE, 'negative',), (Pingback.PINGBACK_TYPE_RISK_UNDER_REVIEW, 'risk under review',), (Pingback.PINGBACK_TYPE_RISK_REVIEWED_ACCEPTED, 'risk reviewed accepted',), (Pingback.PINGBACK_TYPE_RISK_REVIEWED_DECLINED, 'risk reviewed declined',), (Pingback.PINGBACK_TYPE_RISK_AUTHORIZATION_VOIDED, 'risk authorization voided',), (Pingback.PINGBACK_TYPE_SUBSCRIPTION_CANCELLATION, 'subscription cancelation',), (Pingback.PINGBACK_TYPE_SUBSCRIPTION_EXPIRED, 'subscription expired',), (Pingback.PINGBACK_TYPE_SUBSCRIPTION_PAYMENT_FAILED, 'subscription payment failed',), ) user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='Пользователь', related_name='payments') amount = models.DecimalField('Итого', max_digits=8, decimal_places=2, default=0, editable=False) status = models.PositiveSmallIntegerField('Статус платежа', choices=PW_STATUS_CHOICES, null=True, editable=False) data = JSONField('Данные платежа от провайдера', default={}, editable=False) class Meta: verbose_name = 'Платеж' verbose_name_plural = 'Платежи' def calc_commission(self): return self.amount * config.SERVICE_COMMISSION / 100 class CoursePayment(Payment): course = models.ForeignKey(Course, on_delete=models.CASCADE, verbose_name='Курс', related_name='payments') class Meta: verbose_name = 'Платеж за курс' verbose_name_plural = 'Платежи за курсы' def save(self, *args, **kwargs): self.amount = self.course.price 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, commission=self.calc_commission(), ) else: author_balance.amount = self.amount author_balance.commission = self.calc_commission() author_balance.save() class SchoolPayment(Payment): weekdays = ArrayField(models.IntegerField(), size=7, verbose_name='Дни недели') date_start = models.DateField('Дата начала подписки', null=True, blank=True) date_end = models.DateField('Дата окончания подписки', null=True, blank=True) class Meta: verbose_name = 'Платеж за школу' verbose_name_plural = 'Платежи за школу' def save(self, *args, **kwargs): aggregate = SchoolSchedule.objects.filter( weekday__in=self.weekdays, ).aggregate( models.Sum('month_price'), models.Sum('day_discount'), ) month_price_sum = aggregate.get('month_price__sum', 0) day_discount_sum = aggregate.get('day_discount__sum', 0) if len(self.weekdays) == 7 else 0 self.amount = month_price_sum - day_discount_sum super().save(*args, **kwargs)