Skip to content

Commit

Permalink
✨(backend) add offer and price fields to courseRun
Browse files Browse the repository at this point in the history
Add offer and price fields to courseRun displayed at admin view

related to #2445
  • Loading branch information
JoaoGarcao committed Aug 6, 2024
1 parent 7a0bf9f commit 8ee54a1
Show file tree
Hide file tree
Showing 12 changed files with 141 additions and 1 deletion.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ Versioning](https://semver.org/spec/v2.0.0.html).

## [Unrealeased]

### Added

- Add offer and price fields to courseRun displayed at admin
view.

## [2.28.1]

### Fixed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,13 @@ class Base(StyleguideMixin, DRFMixin, RichieCoursesConfigurationMixin, Configura
environ_prefix=None,
)

# Course run price currency value that would be shown on course detail page
RICHIE_DEFAULT_COURSE_RUN_PRICE_CURRENCY = values.Value(
"EUR",
environ_name="RICHIE_DEFAULT_COURSE_RUN_PRICE_CURRENCY",
environ_prefix=None,
)

# Internationalization
TIME_ZONE = "Europe/Paris"
USE_I18N = True
Expand Down
7 changes: 7 additions & 0 deletions sandbox/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,13 @@ class Base(StyleguideMixin, DRFMixin, RichieCoursesConfigurationMixin, Configura
environ_prefix=None,
)

# Course run price currency value that would be shown on course detail page
RICHIE_DEFAULT_COURSE_RUN_PRICE_CURRENCY = values.Value(
"EUR",
environ_name="RICHIE_DEFAULT_COURSE_RUN_PRICE_CURRENCY",
environ_prefix=None,
)

@classmethod
def _get_environment(cls):
"""Environment in which the application is launched."""
Expand Down
4 changes: 4 additions & 0 deletions src/richie/apps/courses/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ class Meta:
"languages",
"enrollment_count",
"catalog_visibility",
"offer",
"price",
"sync_mode",
"display_mode",
]
Expand Down Expand Up @@ -150,6 +152,8 @@ class CourseRunAdmin(FrontendEditableAdminMixin, TranslatableAdmin):
"languages",
"enrollment_count",
"catalog_visibility",
"offer",
"price",
"sync_mode",
)
list_display = ["id"]
Expand Down
17 changes: 17 additions & 0 deletions src/richie/apps/courses/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import factory
from cms.api import add_plugin

from richie.apps.courses.models.course import CourseRunOffer
from richie.plugins.nesteditem.defaults import ACCORDION

from ..core.defaults import ALL_LANGUAGES
Expand Down Expand Up @@ -529,6 +530,22 @@ def enrollment_count(self):
"""
return random.randint(0, 10000) # nosec

@factory.lazy_attribute
def price(self):
"""
The price of a course run is a random float between 1 and 100.
"""
return random.randint(100, 10000) / 100 # nosec

@factory.lazy_attribute
def offer(self):
"""
The offer of a course run is read from Django settings.
"""
return (
CourseRunOffer.FREE if self.price == 0.0 else CourseRunOffer.PAID
) # nosec


class CategoryFactory(BLDPageExtensionDjangoModelFactory):
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Generated by Django 4.2.13 on 2024-07-09 10:56

from django.db import migrations, models

import richie.apps.core.fields.multiselect


class Migration(migrations.Migration):
dependencies = [
("courses", "0034_auto_20230817_1736"),
]

operations = [
migrations.AddField(
model_name="courserun",
name="offer",
field=models.CharField(
choices=[
(
"free",
"free - The entire course can be completed without cost",
),
(
"partially_free",
"partially_free - More than half of the course is for free",
),
(
"subscription",
"subscription - The user must be a subscriber or paid member in order to complete the entire course",
),
(
"paid",
"paid - The user must pay to complete the course",
),
],
default="free",
max_length=20,
verbose_name="offer",
),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Generated by Django 4.2.13 on 2024-07-09 14:37

from django.db import migrations, models

import richie.apps.core.fields.multiselect


class Migration(migrations.Migration):
dependencies = [
("courses", "0035_courserun_offer_and_more"),
]

operations = [
migrations.AddField(
model_name="courserun",
name="price",
field=models.FloatField(
default=0.0, help_text="The cost of the course", verbose_name="price"
),
),
]
27 changes: 27 additions & 0 deletions src/richie/apps/courses/models/course.py
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,19 @@ class CourseRunCatalogVisibility(models.TextChoices):
HIDDEN = "hidden", _("hidden - hide on the course page and from search results")


class CourseRunOffer(models.TextChoices):
"""Course run offer choices."""

FREE = "free", _("free - The entire course can be completed without cost")
PARTIALLY_FREE = "partially_free", _(
"partially_free - More than half of the course is for free"
)
SUBSCRIPTION = "subscription", _(
"subscription - The user must be a subscriber or paid member to complete the entire course"
)
PAID = "paid", _("paid - The user must pay to complete the course")


class CourseRunDisplayMode(models.TextChoices):
"""Course run catalog display modes."""

Expand Down Expand Up @@ -771,6 +784,19 @@ class CourseRun(TranslatableModel):
blank=False,
max_length=20,
)
offer = models.CharField(
_("offer"),
choices=lazy(lambda: CourseRunOffer.choices, tuple)(),
default=CourseRunOffer.FREE,
blank=False,
max_length=20,
)
price = models.FloatField(
_("price"),
default=0.0,
blank=True,
help_text=_("The cost of the course"),
)
display_mode = models.CharField(
choices=CourseRunDisplayMode.choices,
default=CourseRunDisplayMode.DETAILED,
Expand Down Expand Up @@ -856,6 +882,7 @@ def mark_course_dirty(self):
def save(self, *args, **kwargs):
"""Enforce validation each time an instance is saved."""
self.full_clean()
self.price = float(self.price)
super().save(*args, **kwargs)

# pylint: disable=signature-differs
Expand Down
2 changes: 2 additions & 0 deletions src/richie/apps/courses/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ class Meta:
"state",
"enrollment_count",
"catalog_visibility",
"offer",
"price",
]


Expand Down
4 changes: 4 additions & 0 deletions tests/apps/courses/test_admin_course_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,8 @@ def _prepare_add_view_post(self, course, status_code):
"enrollment_end_0": "2015-01-23",
"enrollment_end_1": "09:07:11",
"catalog_visibility": "course_and_search",
"offer": "free",
"price": 0.0,
"sync_mode": "manual",
"display_mode": "detailed",
}
Expand Down Expand Up @@ -450,6 +452,8 @@ def _prepare_change_view_post(self, course_run, course, status_code, check_metho
"enrollment_end_1": "09:07:11",
"enrollment_count": "5",
"catalog_visibility": "course_and_search",
"offer": "free",
"price": 0.0,
"sync_mode": "manual",
"display_mode": "detailed",
}
Expand Down
3 changes: 3 additions & 0 deletions tests/apps/courses/test_admin_form_course_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ def _get_admin_form(course, user):
"enrollment_end_0": "2015-01-23",
"enrollment_end_1": "09:07:11",
"catalog_visibility": "course_and_search",
"offer": "free",
"price": 0.0,
"sync_mode": "manual",
"display_mode": "detailed",
}
Expand Down Expand Up @@ -117,6 +119,7 @@ def test_admin_form_course_run_superuser_empty_form(self):
"display_mode": ["This field is required."],
"languages": ["This field is required."],
"catalog_visibility": ["This field is required."],
"offer": ["This field is required."],
"sync_mode": ["This field is required."],
},
)
Expand Down
4 changes: 3 additions & 1 deletion tests/apps/courses/test_models_course_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from richie.apps.core.helpers import create_i18n_page
from richie.apps.courses.factories import CourseFactory, CourseRunFactory
from richie.apps.courses.models import CourseRun, CourseRunTranslation
from richie.apps.courses.models.course import CourseRunCatalogVisibility
from richie.apps.courses.models.course import CourseRunCatalogVisibility, CourseRunOffer


# pylint: disable=too-many-public-methods
Expand Down Expand Up @@ -623,6 +623,8 @@ def test_models_course_run_mark_dirty_any_field(self):
stub = CourseRunFactory(
sync_mode="manual",
catalog_visibility=CourseRunCatalogVisibility.COURSE_ONLY,
offer=CourseRunOffer.SUBSCRIPTION,
price=3.0,
display_mode="compact",
) # New random values to update our course run

Expand Down

0 comments on commit 8ee54a1

Please sign in to comment.