feat: replace enterprise_customer_for_request with CourseModePriceRequested filter#365
feat: replace enterprise_customer_for_request with CourseModePriceRequested filter#365kiram15 wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR replaces a direct dependency on enterprise_support in the course modes “choose your track” view with an Open edX filter hook (CourseModeCheckoutStarted), allowing enterprise checkout context (e.g., enterprise customer) to be provided via the filters framework and used to compute discounted pricing.
Changes:
- Replaced
enterprise_customer_for_request(request)withCourseModeCheckoutStarted.run_filter(...)to obtainenterprise_customer. - Updated unit tests to patch the filter call instead of patching the removed enterprise-support API.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| common/djangoapps/course_modes/views.py | Swaps enterprise-support lookup for CourseModeCheckoutStarted filter call in checkout/price calculation path. |
| common/djangoapps/course_modes/tests/test_views.py | Updates mocks/patching to align tests with the new filter-based integration point. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
329be4c to
c441b93
Compare
|
|
||
| mock_enterprise_customer_for_request.return_value = {'name': 'dummy'} if is_enterprise_enabled else {} | ||
| enterprise_customer = {'name': 'dummy', 'uuid': 'test-uuid'} if is_enterprise_enabled else None | ||
| mock_run_filter.return_value = {'enterprise_customer': enterprise_customer} |
| if enterprise_customer and verified_mode.sku: | ||
| course_price = get_course_final_price(request.user, verified_mode.sku, price_before_discount) |
There was a problem hiding this comment.
❌ These two lines are the main thing which needs to be replaced, yet they are still here. Remember, you can always check your work by searching for "enterprise" references after your changes. Unfortunately, I think the the proposed filter needs to be reconsidered.
Here are some facts I've gleaned:
- The goal of this branch is to show the enterprise-negotiated discounted price on the track-selection page for enterprise-linked learners only.
- The surrounding business logic seems designed to accommodate a "full" price (price_before_discount) and a "discounted" price (get_course_final_price).
- The helper function get_course_final_price() is only used by this enterprise-specific branch. It's what actually calculates the "enterprise-negotiated" discount, and that discount is established by enterprise customers in practice, but technically the discount could be established for non-enterprise reasons. Hence the entire code stack including get_course_final_price() and all code/APIs that it calls are not enterprise-specific.
Given all of those facts, I think the best approach is the following:
- A filter called
CourseModePriceRequestedthat takes auser,course_mode, andpriceand returns the same, with a possibly discounted price. - A pipeline step called
CalculateEnterpriseDiscountedPricewhich calls theget_course_final_pricefunction. This step importsget_course_final_pricefrom the platform and calls it. - The newly orphaned
get_course_final_pricefunction docstring should be updated to help protect it against deletion.
7554ae2 to
60a9010
Compare
|
|
||
| @httpretty.activate | ||
| @patch('common.djangoapps.course_modes.views.enterprise_customer_for_request') | ||
| @patch('common.djangoapps.course_modes.views.CourseModeCheckoutStarted.run_filter') |
| enterprise_customer = {'name': 'dummy', 'uuid': 'test-uuid'} if is_enterprise_enabled else None | ||
| mock_run_filter.return_value = {'enterprise_customer': enterprise_customer} | ||
| mock_get_course_final_price.return_value = discounted_price |
| # this filter applies discounts (e.g. enterprise-negotiated pricing) to the price | ||
| _, _, course_price = CourseModePriceRequested.run_filter( | ||
| user=request.user, | ||
| course_mode_data=verified_mode, | ||
| price=price_before_discount, | ||
| ) |
60a9010 to
9468ecc
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (4)
common/djangoapps/course_modes/tests/test_views.py:187
- The view imports and calls
CourseModePriceRequested.run_filter, but this test patchesCourseModeCheckoutStarted.run_filter(which doesn’t appear to exist in this module). This patch target should match the filter actually invoked by the view so the test can control the displayed price deterministically.
@patch('common.djangoapps.course_modes.views.CourseModeCheckoutStarted.run_filter')
common/djangoapps/course_modes/tests/test_views.py:212
CourseModePriceRequested.run_filteris unpacked as a 3-tuple in the view (_, _, course_price = ...). Returning a dict here will raise at runtime and won’t simulate the filter behavior. Mock this as(user, course_mode_data, price)(and you can drop the unused enterprise_customer dict).
enterprise_customer = {'name': 'dummy', 'uuid': 'test-uuid'} if is_enterprise_enabled else None
mock_run_filter.return_value = {'enterprise_customer': enterprise_customer}
mock_get_course_final_price.return_value = discounted_price
common/djangoapps/course_modes/views.py:31
get_course_final_priceis no longer used in this view after switching to theCourseModePriceRequestedfilter. Keeping the import is misleading and may fail linting as an unused import.
from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.course_modes.helpers import get_course_final_price, get_verified_track_links
from common.djangoapps.edxmako.shortcuts import render_to_response
common/djangoapps/course_modes/views.py:193
- The PR title/description mention wiring
CourseModeCheckoutStarted, but the code (and inline filter metadata) usesCourseModePriceRequested(org.openedx.learning.course_mode.price.requested.v1). Please align the PR description/title and the implementation (or switch the implementation to the intended filter) to avoid confusion for future maintainers.
# this filter applies discounts (e.g. enterprise-negotiated pricing) to the price
# .. filter_implemented_name: CourseModePriceRequested
# .. filter_type: org.openedx.learning.course_mode.price.requested.v1
_, _, course_price = CourseModePriceRequested.run_filter(
Description
Remove direct enterprise_support import from course_modes/views.py and replace with a call to the CourseModePriceRequested openedx-filter.
https://2u-internal.atlassian.net/browse/ENT-11573
openedx-filters #338 — CourseModePriceRequested filter definition
edx-enterprise #2556 — CalculateEnterpriseDiscountedPrice pipeline step
edx-platform #365 — view wired to invoke the filter
Testing instructions
E2E testing instructions detailed in the edx-enterprise PR