Return phone_number and distance_km on store list
phone_number was only exposed on the store detail serializer; add it to the list too. Also surface the distance annotation (already computed when lat/lng are passed) as distance_km on both, instead of using it only for ordering. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
fa9a69fff3
commit
755d74a9ff
3 changed files with 38 additions and 3 deletions
|
|
@ -9,6 +9,7 @@
|
|||
### 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`).
|
||||
- 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.
|
||||
|
|
|
|||
|
|
@ -31,13 +31,14 @@ class StoreListSerializer(serializers.ModelSerializer):
|
|||
category = StoreCategorySerializer(read_only=True)
|
||||
logo_url = serializers.SerializerMethodField()
|
||||
cover_image_url = serializers.SerializerMethodField()
|
||||
distance_km = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = Store
|
||||
fields = (
|
||||
'uuid', 'name', 'category', 'logo', 'logo_url', 'cover_image', 'cover_image_url',
|
||||
'rating_avg', 'rating_count', 'min_order_amount', 'delivery_fee',
|
||||
'free_delivery_threshold', 'is_open',
|
||||
'phone_number', 'rating_avg', 'rating_count', 'min_order_amount', 'delivery_fee',
|
||||
'free_delivery_threshold', 'is_open', 'distance_km',
|
||||
)
|
||||
|
||||
@extend_schema_field(serializers.URLField(allow_null=True))
|
||||
|
|
@ -48,13 +49,19 @@ class StoreListSerializer(serializers.ModelSerializer):
|
|||
def get_cover_image_url(self, obj):
|
||||
return presigned_media_url(obj.cover_image)
|
||||
|
||||
@extend_schema_field(serializers.FloatField(allow_null=True))
|
||||
def get_distance_km(self, obj):
|
||||
"""Only present when the request passed `lat`/`lng` (see StoreViewSet.get_queryset)."""
|
||||
distance = getattr(obj, 'distance', None)
|
||||
return round(distance.km, 2) if distance is not None else None
|
||||
|
||||
|
||||
class StoreDetailSerializer(StoreListSerializer):
|
||||
working_hours = StoreWorkingHoursSerializer(many=True, read_only=True)
|
||||
|
||||
class Meta(StoreListSerializer.Meta):
|
||||
fields = StoreListSerializer.Meta.fields + (
|
||||
'description', 'address', 'phone_number',
|
||||
'description', 'address',
|
||||
'accepts_wallet', 'accepts_online', 'accepts_cash_on_delivery', 'working_hours',
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
from django.contrib.gis.geos import Point
|
||||
|
||||
from apps.stores.models import StoreCategory
|
||||
|
||||
from apps.orders.tests.base import OrdersTestCase
|
||||
|
|
@ -21,3 +23,28 @@ class StoreListFilterTests(OrdersTestCase):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
uuids = {store['uuid'] for store in response.data['results']}
|
||||
self.assertEqual(uuids, {str(self.store1.uuid), str(self.store2.uuid)})
|
||||
|
||||
def test_phone_number_included_in_list(self):
|
||||
self.store1.phone_number = '02112345678'
|
||||
self.store1.save(update_fields=['phone_number'])
|
||||
|
||||
response = self.client.get('/api/v1/stores/')
|
||||
|
||||
store = next(s for s in response.data['results'] if s['uuid'] == str(self.store1.uuid))
|
||||
self.assertEqual(store['phone_number'], '02112345678')
|
||||
|
||||
def test_distance_km_present_when_lat_lng_given(self):
|
||||
self.store1.location = Point(51.4, 35.75, srid=4326)
|
||||
self.store1.save(update_fields=['location'])
|
||||
|
||||
response = self.client.get('/api/v1/stores/', {'lat': '35.75', 'lng': '51.4'})
|
||||
|
||||
store = next(s for s in response.data['results'] if s['uuid'] == str(self.store1.uuid))
|
||||
self.assertIsNotNone(store['distance_km'])
|
||||
self.assertAlmostEqual(store['distance_km'], 0, delta=0.1)
|
||||
|
||||
def test_distance_km_absent_without_lat_lng(self):
|
||||
response = self.client.get('/api/v1/stores/')
|
||||
|
||||
store = next(s for s in response.data['results'] if s['uuid'] == str(self.store1.uuid))
|
||||
self.assertIsNone(store['distance_km'])
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue