models.py 4.58 KB
Newer Older
1 2 3
"""
Add and create new modes for running courses on this particular LMS
"""
4
import pytz
5
from datetime import datetime
6

7 8 9
from django.db import models
from collections import namedtuple
from django.utils.translation import ugettext as _
10
from django.db.models import Q
11

12 13
from xmodule_django.models import CourseKeyField

14
Mode = namedtuple('Mode', ['slug', 'name', 'min_price', 'suggested_prices', 'currency', 'expiration_datetime'])
15 16 17 18 19 20 21

class CourseMode(models.Model):
    """
    We would like to offer a course in a variety of modes.

    """
    # the course that this mode is attached to
22
    course_id = CourseKeyField(max_length=255, db_index=True)
23 24 25 26 27 28 29 30 31 32 33 34 35 36

    # the reference to this mode that can be used by Enrollments to generate
    # similar behavior for the same slug across courses
    mode_slug = models.CharField(max_length=100)

    # The 'pretty' name that can be translated and displayed
    mode_display_name = models.CharField(max_length=255)

    # minimum price in USD that we would like to charge for this mode of the course
    min_price = models.IntegerField(default=0)

    # the suggested prices for this mode
    suggested_prices = models.CommaSeparatedIntegerField(max_length=255, blank=True, default='')

37 38 39
    # the currency these prices are in, using lower case ISO currency codes
    currency = models.CharField(default="usd", max_length=8)

40
    # turn this mode off after the given expiration date
41
    expiration_date = models.DateField(default=None, null=True, blank=True)
42

43 44
    expiration_datetime = models.DateTimeField(default=None, null=True, blank=True)

45
    DEFAULT_MODE = Mode('honor', _('Honor Code Certificate'), 0, '', 'usd', None)
46
    DEFAULT_MODE_SLUG = 'honor'
47

48 49 50 51
    class Meta:
        """ meta attributes of this model """
        unique_together = ('course_id', 'mode_slug', 'currency')

52 53 54
    @classmethod
    def modes_for_course(cls, course_id):
        """
55
        Returns a list of the non-expired modes for a given course id
56 57 58

        If no modes have been set in the table, returns the default mode
        """
59 60
        now = datetime.now(pytz.UTC)
        found_course_modes = cls.objects.filter(Q(course_id=course_id) &
61 62
                                                (Q(expiration_datetime__isnull=True) |
                                                Q(expiration_datetime__gte=now)))
63 64 65 66 67 68
        modes = ([Mode(
            mode.mode_slug,
            mode.mode_display_name,
            mode.min_price,
            mode.suggested_prices,
            mode.currency,
69
            mode.expiration_datetime
70
        ) for mode in found_course_modes])
71 72 73
        if not modes:
            modes = [cls.DEFAULT_MODE]
        return modes
74

75 76
    @classmethod
    def modes_for_course_dict(cls, course_id):
77
        """
78 79
        Returns the non-expired modes for a particular course as a
        dictionary with the mode slug as the key
80 81
        """
        return {mode.slug: mode for mode in cls.modes_for_course(course_id)}
82

83
    @classmethod
84 85 86 87
    def mode_for_course(cls, course_id, mode_slug):
        """
        Returns the mode for the course corresponding to mode_slug.

88 89
        Returns only non-expired modes.

90 91 92 93
        If this particular mode is not set for the course, returns None
        """
        modes = cls.modes_for_course(course_id)

94
        matched = [m for m in modes if m.slug == mode_slug]
95 96 97 98
        if matched:
            return matched[0]
        else:
            return None
99

100
    @classmethod
Julia Hansbrough committed
101
    def min_course_price_for_verified_for_currency(cls, course_id, currency):
Julia Hansbrough committed
102 103 104 105 106 107 108 109 110
        """
        Returns the minimum price of the course int he appropriate currency over all the
        course's *verified*, non-expired modes.

        Assuming all verified courses have a minimum price of >0, this value should always
        be >0.

        If no verified mode is found, 0 is returned.
        """
Julia Hansbrough committed
111 112 113 114 115 116 117
        modes = cls.modes_for_course(course_id)
        for mode in modes:
            if (mode.currency == currency) and (mode.slug == 'verified'):
                return mode.min_price
        return 0

    @classmethod
118 119
    def min_course_price_for_currency(cls, course_id, currency):
        """
120 121
        Returns the minimum price of the course in the appropriate currency over all the course's
        non-expired modes.
122 123 124 125 126
        If there is no mode found, will return the price of DEFAULT_MODE, which is 0
        """
        modes = cls.modes_for_course(course_id)
        return min(mode.min_price for mode in modes if mode.currency == currency)

127 128
    def __unicode__(self):
        return u"{} : {}, min={}, prices={}".format(
129
            self.course_id.to_deprecated_string(), self.mode_slug, self.min_price, self.suggested_prices
130
        )