winofy-backend/CHANGELOG.md
Ali Asadi 85fe57d1ca Allow checkout to target selected stores instead of the whole cart
POST /api/v1/checkout/ always converted the customer's entire
multi-store cart into orders. Add an optional store_uuids field to
CheckoutSerializer — when given, checkout() only processes those
stores' cart groups and only clears their items, leaving the rest of
the cart intact for a later checkout. Omitted, behavior is unchanged
(whole cart checks out).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-05 15:26:16 +03:30

3.3 KiB

Changelog

[Unreleased]

Fixed

  • GET /api/v1/stores/ — documented the category, neighborhood, search, lat, and lng query params for drf-spectacular so they render in swagger. The filtering itself already worked; only the OpenAPI schema was missing them (apps/stores/views.py).
  • GET /api/v1/products/ — same issue: documented the existing store, category, and search query params for swagger (apps/catalog/views.py).
  • Cart items: CartItemView was registered on both /api/v1/cart/items/ and /api/v1/cart/items/{item_uuid}/, so swagger showed POST/PATCH/DELETE on both paths — 3 of those 6 combinations crashed with a TypeError at runtime (item_uuid missing or unexpected). Split into CartItemView (POST only, list path) and CartItemDetailView (PATCH/DELETE only, detail path) so swagger only shows the combinations that actually work (apps/orders/views.py, apps/orders/urls.py).
  • Cancelling an order never restored the product stock that checkout() decremented, so cancelled orders' items stayed permanently out of stock. Added _restock_order_items(), run on the CANCELLED transition (apps/orders/services.py).
  • POST /api/v1/checkout/ always checked out the customer's entire cart, even when it held items from stores the customer didn't intend to order from yet. It now checks out only the requested stores when store_uuids is given (default: whole cart, unchanged), and only clears those stores' items — the rest of the cart is left intact for a later checkout (apps/orders/serializers.py, apps/orders/services.py).

Added

  • GET /api/v1/cities/?search= — search cities by name (apps/locations/views.py); previously no text search existed.
  • GET /api/v1/neighborhoods/?search= — search neighborhoods by neighborhood name or city name, alongside the existing city UUID filter (apps/locations/views.py).
  • GET /api/v1/stores/ now returns phone_number in the list (previously only on the single-store detail view) and a distance_km field, populated whenever lat/lng are passed (apps/stores/serializers.py).
  • Store latitude/longitude now come back on every store response — list, retrieve, and the seller's own store (GET/PATCH/POST /api/v1/seller/store/) — derived from Store.location via new Store.latitude/Store.longitude properties (apps/stores/models.py, apps/stores/serializers.py). Previously they were write-only on the seller serializer and absent everywhere else.
  • Test coverage for StoreViewSet list filtering (apps/stores/tests/test_store_list.py) — previously untested.
  • Test coverage for ProductViewSet list filtering (apps/catalog/tests/test_product_list.py) — previously untested.
  • Test coverage for CityViewSet/NeighborhoodViewSet list filtering (apps/locations/tests/test_location_list.py) — previously untested.

Changed

  • Replaced hand-rolled get_queryset filtering with django-filter FilterSet classes (apps/{stores,catalog,locations,reviews}/filters.py) and filterset_fields (apps/orders status). django-filter was already installed and set as DEFAULT_FILTER_BACKENDS but unused everywhere; params are now auto-documented in swagger by drf-spectacular's django-filter integration, so the manual OpenApiParameter declarations for those fields were removed (stores keeps lat/lng manual since geo-distance isn't a plain filter).