fix: remove opt-out from jersey ordering options (#263) #265

Merged
forgejo_admin merged 1 commit from 263-remove-opt-out into main 2026-03-31 00:24:46 +00:00

Summary

Opt-out is no longer available for jersey ordering. All players must now order a jersey. This removes opt-out from the API response and rejects it at both checkout endpoints, while preserving existing DB records.

Changes

  • src/basketball_api/routes/jersey.py -- Removed opt_out entry from JERSEY_OPTIONS list, added explicit 422 rejection for opt_out in POST /jersey/checkout, simplified validation guards that previously had opt_out carve-outs, removed the opt-out handling block (no-Stripe path)
  • src/basketball_api/routes/checkout.py -- Added 422 rejection for opt_out jersey-category products in POST /checkout/create-session, added ProductCategory import
  • tests/test_jersey.py -- Updated options count from 3 to 2, converted 4 opt-out success tests to rejection tests verifying 422 status
  • tests/test_checkout.py -- Converted opt-out success tests to rejection tests, switched duplicate-order tests from opt-out product to reversible product with Stripe mocking

Test Plan

  • All 689 tests pass (python -m pytest tests/ -x -q)
  • ruff check and format clean
  • Verify GET /jersey/options returns only 2 options in production
  • Verify POST /jersey/checkout rejects opt_out with 422
  • Verify POST /checkout/create-session rejects opt_out jersey products with 422
  • Verify existing opt-out records (e.g. player id=113) are untouched

Review Checklist

  • No unrelated changes
  • Tests updated to match new behavior
  • Existing DB records preserved (JerseyOption.opt_out enum NOT removed from models.py)
  • Both checkout endpoints reject opt_out
  • Linting clean
  • Affected player: Zion Odejinmi (id=113) -- existing opt-out record preserved, not deleted

Closes #263

## Summary Opt-out is no longer available for jersey ordering. All players must now order a jersey. This removes opt-out from the API response and rejects it at both checkout endpoints, while preserving existing DB records. ## Changes - `src/basketball_api/routes/jersey.py` -- Removed opt_out entry from JERSEY_OPTIONS list, added explicit 422 rejection for opt_out in POST /jersey/checkout, simplified validation guards that previously had opt_out carve-outs, removed the opt-out handling block (no-Stripe path) - `src/basketball_api/routes/checkout.py` -- Added 422 rejection for opt_out jersey-category products in POST /checkout/create-session, added ProductCategory import - `tests/test_jersey.py` -- Updated options count from 3 to 2, converted 4 opt-out success tests to rejection tests verifying 422 status - `tests/test_checkout.py` -- Converted opt-out success tests to rejection tests, switched duplicate-order tests from opt-out product to reversible product with Stripe mocking ## Test Plan - [x] All 689 tests pass (`python -m pytest tests/ -x -q`) - [x] ruff check and format clean - [ ] Verify GET /jersey/options returns only 2 options in production - [ ] Verify POST /jersey/checkout rejects opt_out with 422 - [ ] Verify POST /checkout/create-session rejects opt_out jersey products with 422 - [ ] Verify existing opt-out records (e.g. player id=113) are untouched ## Review Checklist - [x] No unrelated changes - [x] Tests updated to match new behavior - [x] Existing DB records preserved (JerseyOption.opt_out enum NOT removed from models.py) - [x] Both checkout endpoints reject opt_out - [x] Linting clean ## Related Notes - Affected player: Zion Odejinmi (id=113) -- existing opt-out record preserved, not deleted ## Related Closes #263
fix: remove opt-out from jersey ordering options (#263)
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
bfb728f86c
Opt-out is no longer available -- all players must order a jersey.
Removes opt_out from JERSEY_OPTIONS list, rejects opt_out in both
POST /jersey/checkout and POST /checkout/create-session for jersey
products. Existing DB records preserved (enum not removed from models).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author
Owner

QA Review -- PR #265

Scope Check

  • 4 files changed, 93 additions, 101 deletions -- net reduction, clean removal
  • All changes scoped to the opt-out removal per issue #263
  • No unrelated changes detected

Correctness

  1. GET /jersey/options -- opt_out entry removed from JERSEY_OPTIONS list. Response will return 2 items. Correct.
  2. POST /jersey/checkout -- opt_out rejected with 422 after enum parsing. Error message for unknown options filters opt_out from the displayed valid list so users don't see a "valid but rejected" option. Correct.
  3. POST /checkout/create-session -- opt_out rejection scoped to ProductType.opt_out AND ProductCategory.jersey, so future non-jersey opt-out products are unaffected. Correct.
  4. Data preservation -- JerseyOption.opt_out and ProductType.opt_out left in models.py. Existing DB records (e.g. player id=113) remain intact. Correct per acceptance criteria.
  5. Dead code removal -- opt-out Stripe-skip block, opt-out size/number guard carve-outs, and opt-out direct-write path all removed cleanly. No orphaned code paths.

Test Coverage

  • Options count assertion updated from 3 to 2
  • 4 opt-out success tests converted to rejection tests (422 + "no longer available")
  • 1 opt-out number validation test converted to rejection test
  • Duplicate order prevention tests switched from opt-out product to reversible product with proper Stripe mocking added
  • All 689 tests reported passing

Nits

None.


VERDICT: APPROVED

## QA Review -- PR #265 ### Scope Check - 4 files changed, 93 additions, 101 deletions -- net reduction, clean removal - All changes scoped to the opt-out removal per issue #263 - No unrelated changes detected ### Correctness 1. **GET /jersey/options** -- opt_out entry removed from `JERSEY_OPTIONS` list. Response will return 2 items. Correct. 2. **POST /jersey/checkout** -- opt_out rejected with 422 after enum parsing. Error message for unknown options filters opt_out from the displayed valid list so users don't see a "valid but rejected" option. Correct. 3. **POST /checkout/create-session** -- opt_out rejection scoped to `ProductType.opt_out AND ProductCategory.jersey`, so future non-jersey opt-out products are unaffected. Correct. 4. **Data preservation** -- `JerseyOption.opt_out` and `ProductType.opt_out` left in models.py. Existing DB records (e.g. player id=113) remain intact. Correct per acceptance criteria. 5. **Dead code removal** -- opt-out Stripe-skip block, opt-out size/number guard carve-outs, and opt-out direct-write path all removed cleanly. No orphaned code paths. ### Test Coverage - Options count assertion updated from 3 to 2 - 4 opt-out success tests converted to rejection tests (422 + "no longer available") - 1 opt-out number validation test converted to rejection test - Duplicate order prevention tests switched from opt-out product to reversible product with proper Stripe mocking added - All 689 tests reported passing ### Nits None. --- **VERDICT: APPROVED**
forgejo_admin force-pushed 263-remove-opt-out from bfb728f86c
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
to b3f3a0da7a
Some checks failed
ci/woodpecker/pr/woodpecker Pipeline failed
2026-03-31 00:22:33 +00:00
Compare
forgejo_admin deleted branch 263-remove-opt-out 2026-03-31 00:24:46 +00:00
Sign in to join this conversation.
No description provided.