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
20 changes: 17 additions & 3 deletions learning_resources/etl/loaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from django.db import transaction

from learning_resources.constants import (
AvailabilityType,
LearningResourceFormat,
LearningResourceRelationTypes,
LearningResourceType,
Expand Down Expand Up @@ -125,7 +126,11 @@ def load_next_start_date_and_prices(
next_upcoming_run
or resource.runs.filter(published=True).order_by("-start_date").first()
)
resource.prices = best_run.prices if best_run and best_run.prices else []
resource.prices = (
best_run.prices
if resource.certification and best_run and best_run.prices
else []
)
resource.save()
return resource.next_start_date, resource.prices

Expand Down Expand Up @@ -227,8 +232,17 @@ def load_run(
image_data = run_data.pop("image", None)
instructors_data = run_data.pop("instructors", [])

# Make sure any prices are unique and sorted in ascending order
run_data["prices"] = sorted(set(run_data.get("prices", [])), key=lambda x: float(x))
if (
run_data.get("availability") == AvailabilityType.archived.value
or learning_resource.certification is False
):
# Archived runs or runs of resources w/out certificates should not have prices
run_data["prices"] = []
else:
# Make sure any prices are unique and sorted in ascending order
run_data["prices"] = sorted(
set(run_data.get("prices", [])), key=lambda x: float(x)
)

with transaction.atomic():
(
Expand Down
51 changes: 44 additions & 7 deletions learning_resources/etl/loaders_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from django.utils import timezone

from learning_resources.constants import (
AvailabilityType,
LearningResourceFormat,
LearningResourceRelationTypes,
LearningResourceType,
Expand All @@ -31,6 +32,7 @@
load_courses,
load_image,
load_instructors,
load_next_start_date_and_prices,
load_offered_by,
load_playlist,
load_playlists,
Expand Down Expand Up @@ -391,7 +393,9 @@ def test_load_course( # noqa: PLR0913
)
assert result.next_start_date == expected_next_start_date
assert result.prices == (
[Decimal(0.00), Decimal(49.00)] if is_run_published else []
[Decimal(0.00), Decimal(49.00)]
if is_run_published and result.certification
else []
)

if course_exists and ((not is_published or not is_run_published) or blocklisted):
Expand Down Expand Up @@ -593,31 +597,48 @@ def test_load_course_dupe_urls(unique_url):


@pytest.mark.parametrize("run_exists", [True, False])
def test_load_run(run_exists):
@pytest.mark.parametrize(
"availability", [AvailabilityType.archived.value, AvailabilityType.current.value]
)
@pytest.mark.parametrize("certification", [True, False])
def test_load_run(run_exists, availability, certification):
"""Test that load_run loads the course run"""
course = CourseFactory.create(learning_resource__runs=[])
course = LearningResourceFactory.create(
is_course=True, runs=[], certification=certification
)
learning_resource_run = (
LearningResourceRunFactory.create(learning_resource=course.learning_resource)
LearningResourceRunFactory.create(learning_resource=course)
if run_exists
else LearningResourceRunFactory.build()
)
props = model_to_dict(
LearningResourceRunFactory.build(run_id=learning_resource_run.run_id)
LearningResourceRunFactory.build(
run_id=learning_resource_run.run_id,
availability=availability,
prices=["70.00", "20.00"],
)
)

del props["id"]
del props["learning_resource"]

assert LearningResourceRun.objects.count() == (1 if run_exists else 0)
assert course.certification == certification

result = load_run(course.learning_resource, props)
result = load_run(course, props)

assert LearningResourceRun.objects.count() == 1

assert result.learning_resource == course.learning_resource
assert result.learning_resource == course

assert isinstance(result, LearningResourceRun)

assert result.prices == (
[]
if (availability == AvailabilityType.archived.value or certification is False)
else sorted(props["prices"])
)
props.pop("prices")
for key, value in props.items():
assert getattr(result, key) == value, f"Property {key} should equal {value}"

Expand Down Expand Up @@ -1365,3 +1386,19 @@ def test_load_course_percolation(
mock_upsert_tasks.upsert_learning_resource_immutable_signature.assert_called_with(
result.id
)


@pytest.mark.parametrize("certification", [True, False])
def test_load_prices_by_certificate(certification):
"""Prices should be empty for a course without certificates, else equal to only published run"""
course = LearningResourceFactory.create(
is_course=True, certification=certification, runs=[]
)
run = LearningResourceRunFactory.create(
learning_resource=course,
published=True,
availability=AvailabilityType.current.value,
prices=[Decimal("0.00"), Decimal("20.00")],
)
load_next_start_date_and_prices(course)
assert course.prices == ([] if not certification else run.prices)