Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lms/djangoapps/learner_home/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ class CourseRunSerializer(serializers.Serializer):
isStarted = serializers.SerializerMethodField()
isArchived = serializers.SerializerMethodField()
courseId = serializers.CharField(source="course_id")
courseUuid = serializers.UUIDField(source="course_overview.variant_id", allow_null=True)
minPassingGrade = serializers.DecimalField(
max_digits=5, decimal_places=2, source="course_overview.lowest_passing_grade"
)
Expand Down
15 changes: 15 additions & 0 deletions lms/djangoapps/learner_home/test_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ def create_test_enrollment(self, course_mode=CourseMode.AUDIT):
test_enrollment.course_overview.marketing_url = random_url()
test_enrollment.course_overview.end = random_date()
test_enrollment.course_overview.certificate_available_date = random_date()
test_enrollment.course_overview.variant_id = uuid4()

return test_enrollment

Expand Down Expand Up @@ -213,6 +214,20 @@ def test_with_data(self):
for key in output_data:
assert output_data[key] is not None

def test_missing_course_uuid(self):
# Given a course run
input_data = self.create_test_enrollment()
input_context = self.create_test_context(input_data.course.id)

# ... where the catalog had nothing for this course
input_data.course_overview.variant_id = None

# When I serialize
output_data = CourseRunSerializer(input_data, context=input_context).data

# Then courseUuid is None, which is allowed
self.assertIsNone(output_data["courseUuid"])

def test_missing_resume_url(self):
# Given a course run
input_data = self.create_test_enrollment()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class Command(BaseCommand):
CourseRunField(catalog_name='marketing_url', course_overview_name='marketing_url'),
CourseRunField(catalog_name='eligible_for_financial_aid', course_overview_name='eligible_for_financial_aid'),
CourseRunField(catalog_name='content_language', course_overview_name='language'),
CourseRunField(catalog_name='variant_id', course_overview_name='variant_id'),
)

def handle(self, *args, **options):
Expand All @@ -51,7 +52,8 @@ def handle(self, *args, **options):
is_course_metadata_updated = False
for field in self.course_run_fields:
catalog_value = course_run.get(field.catalog_name)
if getattr(course_overview, field.course_overview_name) != catalog_value:
current_value = getattr(course_overview, field.course_overview_name)
if str(current_value) != str(catalog_value):
setattr(course_overview, field.course_overview_name, catalog_value)
is_course_metadata_updated = True

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ def test_course_run_sync(self, mock_catalog_course_runs):
previous_course_overview_value = getattr(self.course_overview, course_overview_field_name)
updated_course_overview_value = getattr(updated_course_overview, course_overview_field_name)

# course overview value matches catalog value
assert updated_course_overview_value == self.catalog_course_run.get(catalog_field_name) # pylint: disable=no-member, line-too-long
# course overview value matches catalog value (compared as strings, since e.g.
# variant_id round-trips as a uuid.UUID, not the raw string the catalog returned)
assert str(updated_course_overview_value) == str(self.catalog_course_run.get(catalog_field_name)) # pylint: disable=no-member, line-too-long
# new value doesn't match old value
assert updated_course_overview_value != previous_course_overview_value

Expand Down
1 change: 1 addition & 0 deletions openedx/core/djangoapps/catalog/tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ class CourseRunFactory(DictFactoryBase):
content_language = 'en'
max_effort = 4
weeks_to_complete = 10
variant_id = factory.Faker('uuid4')


class CourseFactory(DictFactoryBase):
Expand Down
Comment thread
jono-booth marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 4.2.28 on 2026-09-08 14:25

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('course_overviews', '0029_alter_historicalcourseoverview_options'),
]

operations = [
migrations.AddField(
model_name='courseoverview',
name='variant_id',
field=models.UUIDField(blank=True, null=True),
),
migrations.AddField(
model_name='historicalcourseoverview',
name='variant_id',
field=models.UUIDField(blank=True, null=True),
),
]
6 changes: 5 additions & 1 deletion openedx/core/djangoapps/content/course_overviews/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class Meta:
app_label = 'course_overviews'

# IMPORTANT: Bump this whenever you modify this model and/or add a migration.
VERSION = 19
VERSION = 20

# Cache entry versioning.
version = models.IntegerField()
Expand Down Expand Up @@ -132,6 +132,10 @@ class Meta:
marketing_url = models.TextField(null=True)
eligible_for_financial_aid = models.BooleanField(default=True)

# Identifier linking this course run to a product variant in an external LOB system
# (i.e. ExecEd & Bootcamps, e.g. GetSmarter/Titan). Synced from discovery's CourseRun.variant_id.
variant_id = models.UUIDField(null=True, blank=True)

# Course highlight info, used to guide course update emails
has_highlights = models.BooleanField(null=True, default=None) # if None, you have to look up the answer yourself

Expand Down
Loading