Skip to content

Fix 500 error on program checkout completion#3338

Merged
gumaerc merged 3 commits intomainfrom
copilot/fix-checkout-program-error
Feb 27, 2026
Merged

Fix 500 error on program checkout completion#3338
gumaerc merged 3 commits intomainfrom
copilot/fix-checkout-program-error

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 26, 2026

  • Fix post_checkout_redirect in ecommerce/views/legacy/__init__.py to use line.courseware instead of purchased_object.course.title (which fails for Programs)
  • Add test test_checkout_api_result_program_accept using the correct CheckoutCallbackView endpoint (checkout-result-callback) that sets the redirect cookie, not BackofficeCallbackView (checkout_result_api)
Original prompt

This section details on the original issue you should resolve

<issue_title>Completing checkout with a program that you have to pay for fails</issue_title>
<issue_description>Sentry Issue: MITXONLINE-6BY

AttributeError: 'Program' object has no attribute 'course'
(3 additional frame(s) were not displayed)
...
  File "ecommerce/views/legacy/__init__.py", line 814, in post
    return self.post_checkout_redirect(
  File "ecommerce/views/legacy/__init__.py", line 763, in post_checkout_redirect
    "run": order.lines.first().purchased_object.course.title,

This was encountered testing #3335 - I ran through the checkout process with a program product, and i got a 500 error at the end. I then did it with a 100% off coupon (which short-circuits the normal checkout process) and that worked OK. The code path for payment didn't get tested enough so this slipped through.

Expected Behavior

Paying for a program purchase should work.

Current Behavior

It doesn't.

Steps to Reproduce

  1. Create a program and a product for said program. The product should cost some amount of money <= $999.
  2. Attempt to buy the program. (I did this by using the APIs directly in Swagger to set up the cart, then went to the cart page and checked out from there.)
  3. Go through the CyberSource process.
  4. When completed, you should end up with a 500 error on MITx Online.

If you want to see what happens when it does work, create a 100% off or $0 fixed-price coupon and apply it, then check out. Since you won't go through the CyberSource process, it'll work and you should get a verified program enrollment and a record in the Paid Programs table.

Possible Solution

The system generates a redirect to the dashboard with some additional data; it was fixed up elsewhere to work with course runs or programs, but not in this particular spot. (This is why the short-circuiting works - that's where it's fixed.) So this part just needs to be fixed up in the same way, and the tests should be updated to cover this case so we don't miss it again.
</issue_description>

<agent_instructions>The format string that is used for the redirect on success expects a CourseRun, when it should work for either a CourseRun or a Program. This has been fixed elsewhere, in generate_checkout_payload when the order is zero value; the same fix should be applied.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

  • Fixes mitodl/hq#10347

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

…d_object.course.title

Co-authored-by: jkachel <945611+jkachel@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix checkout failure with program products Fix 500 error on program checkout completion Feb 26, 2026
Copilot AI requested a review from jkachel February 26, 2026 21:04
@github-actions
Copy link
Copy Markdown

OpenAPI Changes

Show/hide ## Changes for v0.yaml:
## Changes for v0.yaml:


## Changes for v1.yaml:


## Changes for v2.yaml:


Unexpected changes? Ensure your branch is up-to-date with main (consider rebasing).

Copy link
Copy Markdown
Contributor

@jkachel jkachel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty good; testing the wrong API for the cookie, though.

"transaction_id": "12345",
}

resp = api_client.post(reverse("checkout_result_api"), payload)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not the correct API to use for this purpose. This resolves to the BackofficeCallbackView, which is an out-of-band endpoint that doesn't set cookies or redirect the user, because it's consumed by a webhook from the payment processor. The CheckoutCallbackView endpoint is where the payment processor sends the user after they've completed checkout (and will set the cookie we're looking for).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in fa25be9 — changed to user_client.post(reverse("checkout-result-callback"), ...) (the CheckoutCallbackView) and updated the expected status code to 302 since it returns a redirect.

…llbackView

Co-authored-by: jkachel <945611+jkachel@users.noreply.github.com>
Copilot AI requested a review from jkachel February 26, 2026 22:51
@jkachel jkachel marked this pull request as ready for review February 26, 2026 23:40
Copy link
Copy Markdown
Contributor

@jkachel jkachel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

Copy link
Copy Markdown
Contributor

@gumaerc gumaerc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@gumaerc gumaerc merged commit df8362d into main Feb 27, 2026
10 checks passed
@gumaerc gumaerc deleted the copilot/fix-checkout-program-error branch February 27, 2026 17:02
This was referenced Mar 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants