feat: Change override date to datetime

When first building the Certificate Date Override feature, I set up the
CertificateDateOverride model to store the override dates as Dates
instead of DateTimes.

Turns out this is not how edX typically handles dates, and it’s causing
some minor headaches around needing to convert values. Also, using just
Dates causes timezone issues.

MICROBA-1488
This commit is contained in:
oliviaruizknott
2021-09-10 08:11:50 -06:00
parent 48ad7effb1
commit 59fefa10eb
5 changed files with 32 additions and 10 deletions

View File

@@ -0,0 +1,23 @@
# Generated by Django 2.2.24 on 2021-09-09 22:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('certificates', '0031_certificatedateoverride_historicalcertificatedateoverride'),
]
operations = [
migrations.AlterField(
model_name='certificatedateoverride',
name='date',
field=models.DateTimeField(help_text="The date to display on the certificate. Set 'Time' to midnight (00:00:00)."),
),
migrations.AlterField(
model_name='historicalcertificatedateoverride',
name='date',
field=models.DateTimeField(help_text="The date to display on the certificate. Set 'Time' to midnight (00:00:00)."),
),
]

View File

@@ -1214,8 +1214,8 @@ class CertificateDateOverride(TimeStampedModel):
related_name='date_override',
help_text="The id of the Generated Certificate to override",
)
date = models.DateField(
help_text="The date to display on the certificate",
date = models.DateTimeField(
help_text="The date to display on the certificate. Set 'Time' to midnight (00:00:00).",
)
reason = models.TextField(
help_text="The reason why you are overriding the certificate date (Update this when you add OR edit the date.)",

View File

@@ -115,5 +115,5 @@ class CertificateDateOverrideFactory(DjangoModelFactory):
class Meta:
model = CertificateDateOverride
date = datetime.datetime(2021, 5, 11)
date = datetime.datetime(2021, 5, 11, 0, 0, tzinfo=datetime.timezone.utc)
reason = "Learner really wanted this on their birthday"

View File

@@ -33,8 +33,7 @@ MAX_RETRIES = 11
PROGRAM_CERTIFICATE = 'program'
COURSE_CERTIFICATE = 'course-run'
VISIBLE_DATE_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
DATE_OVERRIDE_FORMAT = '%Y-%m-%d'
DATE_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
def get_completed_programs(site, student):
@@ -120,7 +119,7 @@ def award_program_certificate(client, user, program_uuid, visible_date):
'attributes': [
{
'name': 'visible_date',
'value': visible_date.strftime(VISIBLE_DATE_FORMAT)
'value': visible_date.strftime(DATE_FORMAT)
}
]
})
@@ -310,11 +309,11 @@ def post_course_certificate(client, username, certificate, visible_date, date_ov
'mode': certificate.mode,
'type': COURSE_CERTIFICATE,
},
'date_override': {'date': date_override.strftime(DATE_OVERRIDE_FORMAT)} if date_override else None,
'date_override': {'date': date_override.strftime(DATE_FORMAT)} if date_override else None,
'attributes': [
{
'name': 'visible_date',
'value': visible_date.strftime(VISIBLE_DATE_FORMAT)
'value': visible_date.strftime(DATE_FORMAT)
}
]
})
@@ -450,7 +449,7 @@ def award_course_certificate(self, username, course_run_key, certificate_availab
# Date is being passed via JSON and is encoded in the EMCA date time string format. The rest of the code
# expects a datetime.
if certificate_available_date:
certificate_available_date = datetime.strptime(certificate_available_date, VISIBLE_DATE_FORMAT)
certificate_available_date = datetime.strptime(certificate_available_date, DATE_FORMAT)
# Even in the cases where this task is called with a certificate_available_date, we still need to retrieve
# the course overview because it's required to determine if we should use the certificate_available_date or

View File

@@ -587,7 +587,7 @@ class AwardCourseCertificatesTestCase(CredentialsApiConfigMixin, TestCase):
assert call_args[1] == self.student.username
assert call_args[2] == self.certificate
assert call_args[3] == self.certificate.modified_date
assert call_args[4] == self.certificate.date_override.date.date()
assert call_args[4] == self.certificate.date_override.date
def test_award_course_cert_not_called_if_disabled(self, mock_post_course_certificate):
"""