Skip to content

Commit 4c5d9e7

Browse files
authored
Fix issues with course certificate generation (#3106)
1 parent f4ff864 commit 4c5d9e7

File tree

4 files changed

+36
-6
lines changed

4 files changed

+36
-6
lines changed

courses/api.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -845,9 +845,14 @@ def generate_course_run_certificates():
845845
0,
846846
)
847847
for edx_grade, user in edx_grade_user_iter:
848-
course_run_grade, created, updated = ensure_course_run_grade(
849-
user=user, course_run=run, edx_grade=edx_grade, should_update=True
850-
)
848+
try:
849+
course_run_grade, created, updated = ensure_course_run_grade(
850+
user=user, course_run=run, edx_grade=edx_grade, should_update=True
851+
)
852+
except ValidationError:
853+
msg = f"Can't save grade {edx_grade} for {user} in {run}, skipping certificate generation"
854+
log.exception(msg)
855+
continue
851856

852857
if created:
853858
created_grades_count += 1
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Generated by Django 4.2.25 on 2025-11-24 15:31
2+
3+
import django.core.validators
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
dependencies = [
9+
("courses", "0074_populate_issue_date"),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name="courserungrade",
15+
name="grade",
16+
field=models.FloatField(
17+
validators=[
18+
django.core.validators.MinValueValidator(0.0),
19+
django.core.validators.MaxValueValidator(2.0),
20+
]
21+
),
22+
),
23+
]

courses/models.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1710,7 +1710,7 @@ class CourseRunGrade(TimestampedModel, AuditableModel, ValidateOnSaveMixin):
17101710
user = models.ForeignKey(User, null=False, on_delete=models.CASCADE)
17111711
course_run = models.ForeignKey(CourseRun, null=False, on_delete=models.CASCADE)
17121712
grade = models.FloatField(
1713-
null=False, validators=[MinValueValidator(0.0), MaxValueValidator(1.0)]
1713+
null=False, validators=[MinValueValidator(0.0), MaxValueValidator(2.0)]
17141714
)
17151715
letter_grade = models.CharField(max_length=6, blank=True, null=True) # noqa: DJ001
17161716
passed = models.BooleanField(default=False)
@@ -1728,11 +1728,11 @@ def to_dict(self):
17281728

17291729
@property
17301730
def grade_percent(self) -> Decimal:
1731-
"""Returns the grade field value as a number out of 100 (or None if the value is None)"""
1731+
"""Returns the grade field value as a number out of 100 (or Decimal(0) if the value is None)"""
17321732
return (
17331733
Decimal(self.grade * 100).quantize(exp=Decimal(1), rounding=ROUND_HALF_EVEN)
17341734
if self.grade is not None
1735-
else None
1735+
else Decimal(0)
17361736
)
17371737

17381738
@property

courses/serializers/v1/base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ class Meta:
116116
class CourseRunGradeSerializer(serializers.ModelSerializer):
117117
"""CourseRunGrade serializer"""
118118

119+
grade = serializers.FloatField(min_value=0.0, max_value=1.0)
120+
119121
class Meta:
120122
model = models.CourseRunGrade
121123
fields = ["grade", "letter_grade", "passed", "set_by_admin", "grade_percent"]

0 commit comments

Comments
 (0)