import arrow from datetime import datetime, timedelta, date from django.conf import settings from django.db import models from django.urls import reverse_lazy from django.utils.functional import cached_property from django.utils.timezone import now from project.mixins import BaseModel, DeactivatedMixin from apps.content.models import ImageObject from apps.payment import models as payment_models class SchoolSchedule(models.Model): WEEKDAY_SHORT_NAMES = ('пн', 'вт', 'ср', 'чт', 'пт', 'сб', 'вс') WEEKDAY_CHOICES = ( (1, 'понедельник'), (2, 'вторник'), (3, 'среда'), (4, 'четверг'), (5, 'пятница'), (6, 'суббота'), (7, 'воскресенье'), ) weekday = models.PositiveSmallIntegerField( 'День недели', choices=WEEKDAY_CHOICES, ) title = models.CharField('Заголовок', default='', max_length=100, db_index=True) short_description = models.CharField( 'Короткое описание', default='', max_length=100, db_index=True ) description = models.TextField('Описание') materials = models.TextField('Материалы') age = models.PositiveSmallIntegerField('Возраст', default=0) month_price = models.DecimalField('Цена', max_digits=8, decimal_places=2, default=0) day_discount = models.DecimalField( 'Скидка, в валюте', max_digits=8, decimal_places=2, default=0 ) start_at = models.TimeField('Начало урока', null=True) cover = models.ForeignKey( ImageObject, related_name='schoolschedule_cover', verbose_name='Обложка дня', on_delete=models.SET_NULL, null=True, blank=True, ) trial_lesson = models.URLField(default='', blank=True) is_camp = models.BooleanField(default=False) class Meta: ordering = ('weekday',) verbose_name = 'Расписание' verbose_name_plural = 'Расписания' unique_together = (('weekday', 'is_camp'),) def __str__(self): return dict(self.WEEKDAY_CHOICES).get(self.weekday, '') def is_online(self): end_at = datetime.combine(now().today(), self.start_at) + timedelta(hours=1) return self.start_at <= now().time() and end_at.time() >= now().time() and self.weekday == now().isoweekday() @cached_property def current_live_lesson(self): september2018 = date(2018, 9, 1) date_start = max(september2018, now().date()) live_lesson = LiveLesson.objects.filter( date__week_day=self.weekday % 7 + 1, date__range=[date_start, date_start + timedelta(days=6)], deactivated_at__isnull=True, is_camp=False, ).first() return live_lesson @cached_property def previous_live_lesson(self): now_time = now() live_lesson = LiveLesson.objects.filter( date__week_day=self.weekday % 7 + 1, date__range=[(now_time - timedelta(days=8)).date(), (now_time - timedelta(days=1)).date()], deactivated_at__isnull=True, is_camp=False, ).first() return live_lesson @cached_property def current_camp_lesson(self): date_start = now().date() live_lesson = LiveLesson.objects.filter( date__week_day=self.weekday % 7 + 1, date__range=[date_start, date_start + timedelta(days=6)], deactivated_at__isnull=True, is_camp=True, ).first() return live_lesson @cached_property def previous_camp_lesson(self): now_time = now() live_lesson = LiveLesson.objects.filter( date__week_day=self.weekday % 7 + 1, date__range=[(now_time - timedelta(days=8)).date(), (now_time - timedelta(days=1)).date()], deactivated_at__isnull=True, is_camp=True, ).first() return live_lesson @property def start_at_humanize(self): return arrow.get(datetime.combine(datetime.today(), self.start_at), settings.TIME_ZONE).humanize(locale='ru') if self.start_at else None class SchoolScheduleImage(models.Model): schoolschedule = models.ForeignKey( SchoolSchedule, on_delete=models.CASCADE, verbose_name='День занятия', related_name='schoolschedule_images', ) img = models.ForeignKey( ImageObject, related_name='schoolschedule_images', verbose_name='Объект изображения', on_delete=models.SET_NULL, null=True, blank=True, ) created_at = models.DateTimeField(auto_now_add=True) update_at = models.DateTimeField(auto_now=True) class Meta: verbose_name = 'Изображение работ' verbose_name_plural = 'Изображения работ' ordering = ('-created_at',) class LiveLesson(BaseModel, DeactivatedMixin): title = models.CharField('Название урока', max_length=100, default='', blank=True) short_description = models.TextField('Краткое описание урока', default='', blank=True) stream = models.URLField('Ссылка на VIMEO', default='', blank=True) date = models.DateField(default=now, unique=True) materials = models.TextField('Материалы', blank=True, default='') cover = models.ForeignKey( ImageObject, related_name='livelesson_covers', verbose_name='Обложка урока школы', on_delete=models.SET_NULL, null=True, blank=True, ) is_camp = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) update_at = models.DateTimeField(auto_now=True) class Meta: verbose_name = 'Урок онлайн школы' verbose_name_plural = 'Уроки онлайн школы' ordering = ('-date', 'title',) def __str__(self): return self.title def save(self, *args, **kwargs): if not self.id and LiveLesson.objects.filter(date=self.date).exists(): self.date = (datetime.combine(self.date, now().time()) + timedelta(days=1)).date() super().save(*args, **kwargs) @property def url(self): return self.get_absolute_url() def get_absolute_url(self): return (reverse_lazy('school:camp-lesson-detail', kwargs={'lesson_date': self.date.strftime('%d-%m-%y')}) if self.is_camp else reverse_lazy('school:lesson-detail', kwargs={'lesson_date': self.date.strftime('%d-%m-%y')})) def stream_index(self): return self.stream.split('/')[-1] @cached_property def school_schedule(self): try: return SchoolSchedule.objects.get(weekday=self.date.isoweekday(), is_camp=self.is_camp) except SchoolSchedule.DoesNotExist: return None @property def is_online(self): # если урок открыт, он сегодняшний и прошло не больше часа с момента старта - значит онлайн if self.is_opened and self.school_schedule: today = now().date() end_at = datetime.combine(today, self.school_schedule.start_at) + timedelta(hours=1) return self.date == today and end_at.time() >= now().time() return False @property def is_opened(self): # если есть заголовок и дата меньше сегодняшней (прошлый урок) или сегодняшняя и время показа урока уже пришло # тогда урок считается открытым к просмотру today = now().date() return self.title and (self.date < today or (self.date == today and self.school_schedule and self.school_schedule.start_at <= now().time()))