class PromoCode(TimestampedModel): objects = PromoCodeQuerySet.as_manager() name = models.CharField(_('Promo Code'), max_length=32, unique=True, db_index=True) discount_percent = models.IntegerField(_('Discount percent')) active = models.BooleanField(_('Active'), default=True) comment = models.TextField(_('Comment'), blank=True, null=True) courses = models.ManyToManyField( 'products.Course', help_text=_('Can not be used for courses not checked here'), blank=True) class Meta: verbose_name = _('Promo Code') verbose_name_plural = _('Promo Codes') def compatible_with(self, course: Course) -> bool: return self.courses.count() == 0 or course in self.courses.all() def apply(self, course: Course) -> Decimal: if not self.compatible_with(course): return course.price return Decimal(course.price * (100 - self.discount_percent) / 100)
class Question(TimestampedModel): slug = models.UUIDField(db_index=True, unique=True, default=uuid.uuid4) courses = models.ManyToManyField('products.Course') name = models.CharField(_('Name'), max_length=256) text = MarkdownxField() class Meta: verbose_name = _('Homework') verbose_name_plural = _('Homeworks') permissions = [ ('see_all_questions', _('May see questions for all homeworks')), ] def get_absolute_url(self): return urljoin(settings.FRONTEND_URL, f'homework/questions/{self.slug}/') def dispatch_crosscheck(self, *args, **kwargs): from homework.services import QuestionCrossCheckDispatcher dispatcher = QuestionCrossCheckDispatcher(question=self, *args, **kwargs) return dispatcher()
class Bundle(Shippable): records = models.ManyToManyField('products.Record') courses = models.ManyToManyField('products.Course') class Meta: ordering = ['-id'] verbose_name = _('Bundle') verbose_name_plural = _('Bundles') db_table = 'courses_bundle' def ship(self, *args, **kwargs): for record in self.records.iterator(): record.ship(*args, **kwargs) for course in self.courses.iterator(): course.ship(*args, **kwargs)
class Bundle(Shippable): records = models.ManyToManyField('courses.Record') courses = models.ManyToManyField('courses.Course') class Meta: ordering = ['-id'] verbose_name = _('Bundle') verbose_name_plural = _('Bundles') def get_absolute_url(self): return urljoin(settings.FRONTEND_URL, '/'.join(['bundles', self.slug, ''])) def ship(self, to): for record in self.records.iterator(): record.ship(to=to) for course in self.courses.iterator(): course.ship(to=to)
class Bundle(Shippable): records = models.ManyToManyField('products.Record') courses = models.ManyToManyField('products.Course') class Meta: ordering = ['-id'] verbose_name = _('Bundle') verbose_name_plural = _('Bundles') db_table = 'courses_bundle' def iterate_bundled_items(self) -> Generator[Shippable, None, None]: yield from self.records.iterator() yield from self.courses.iterator() def ship(self, *args, **kwargs): for item in self.iterate_bundled_items(): item.ship(*args, **kwargs) def unship(self, *args, **kwargs): for item in self.iterate_bundled_items(): item.unship(*args, **kwargs)
class Question(TimestampedModel): slug = models.UUIDField(db_index=True, unique=True, default=uuid.uuid4) courses = models.ManyToManyField('products.Course') name = models.CharField(_('Name'), max_length=256) text = MarkdownxField() class Meta: verbose_name = _('Homework') verbose_name_plural = _('Homeworks') def get_absolute_url(self): return urljoin(settings.FRONTEND_URL, f'/homework/questions/{self.slug}/')