Merge pull request 'Return store latitude/longitude in every store response' (#7) from feature/lat-long into master
Reviewed-on: #7
This commit is contained in:
commit
dcf63952b5
5 changed files with 45 additions and 3 deletions
|
|
@ -11,6 +11,7 @@
|
||||||
- `GET /api/v1/cities/?search=` — search cities by name (`apps/locations/views.py`); previously no text search existed.
|
- `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/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`).
|
- `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 `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 `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.
|
- Test coverage for `CityViewSet`/`NeighborhoodViewSet` list filtering (`apps/locations/tests/test_location_list.py`) — previously untested.
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,14 @@ class Store(BaseModel):
|
||||||
from django.conf import settings as dj_settings
|
from django.conf import settings as dj_settings
|
||||||
return dj_settings.DEFAULT_COMMISSION_PERCENT
|
return dj_settings.DEFAULT_COMMISSION_PERCENT
|
||||||
|
|
||||||
|
@property
|
||||||
|
def latitude(self):
|
||||||
|
return self.location.y if self.location else None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def longitude(self):
|
||||||
|
return self.location.x if self.location else None
|
||||||
|
|
||||||
|
|
||||||
class StoreWorkingHours(BaseModel):
|
class StoreWorkingHours(BaseModel):
|
||||||
class Weekday(models.IntegerChoices):
|
class Weekday(models.IntegerChoices):
|
||||||
|
|
|
||||||
|
|
@ -32,13 +32,15 @@ class StoreListSerializer(serializers.ModelSerializer):
|
||||||
logo_url = serializers.SerializerMethodField()
|
logo_url = serializers.SerializerMethodField()
|
||||||
cover_image_url = serializers.SerializerMethodField()
|
cover_image_url = serializers.SerializerMethodField()
|
||||||
distance_km = serializers.SerializerMethodField()
|
distance_km = serializers.SerializerMethodField()
|
||||||
|
latitude = serializers.FloatField(read_only=True)
|
||||||
|
longitude = serializers.FloatField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Store
|
model = Store
|
||||||
fields = (
|
fields = (
|
||||||
'uuid', 'name', 'category', 'logo', 'logo_url', 'cover_image', 'cover_image_url',
|
'uuid', 'name', 'category', 'logo', 'logo_url', 'cover_image', 'cover_image_url',
|
||||||
'phone_number', 'rating_avg', 'rating_count', 'min_order_amount', 'delivery_fee',
|
'phone_number', 'rating_avg', 'rating_count', 'min_order_amount', 'delivery_fee',
|
||||||
'free_delivery_threshold', 'is_open', 'distance_km',
|
'free_delivery_threshold', 'is_open', 'distance_km', 'latitude', 'longitude',
|
||||||
)
|
)
|
||||||
|
|
||||||
@extend_schema_field(serializers.URLField(allow_null=True))
|
@extend_schema_field(serializers.URLField(allow_null=True))
|
||||||
|
|
@ -109,8 +111,8 @@ class SellerStoreSerializer(serializers.ModelSerializer):
|
||||||
source='service_neighborhoods', queryset=Neighborhood.objects.filter(is_active=True),
|
source='service_neighborhoods', queryset=Neighborhood.objects.filter(is_active=True),
|
||||||
write_only=True, many=True, required=False,
|
write_only=True, many=True, required=False,
|
||||||
)
|
)
|
||||||
latitude = serializers.FloatField(write_only=True, required=False)
|
latitude = serializers.FloatField(required=False)
|
||||||
longitude = serializers.FloatField(write_only=True, required=False)
|
longitude = serializers.FloatField(required=False)
|
||||||
bank_account = StoreBankAccountSerializer(read_only=True)
|
bank_account = StoreBankAccountSerializer(read_only=True)
|
||||||
logo_url = serializers.SerializerMethodField()
|
logo_url = serializers.SerializerMethodField()
|
||||||
cover_image_url = serializers.SerializerMethodField()
|
cover_image_url = serializers.SerializerMethodField()
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,13 @@ class SellerStoreTests(OrdersTestCase):
|
||||||
'category_uuid': str(self.category.uuid),
|
'category_uuid': str(self.category.uuid),
|
||||||
'city_uuid': str(self.city.uuid),
|
'city_uuid': str(self.city.uuid),
|
||||||
'address': 'خیابان ولیعصر',
|
'address': 'خیابان ولیعصر',
|
||||||
|
'latitude': 35.75,
|
||||||
|
'longitude': 51.4,
|
||||||
})
|
})
|
||||||
self.assertEqual(response.status_code, 201, response.data)
|
self.assertEqual(response.status_code, 201, response.data)
|
||||||
self.assertTrue(Store.objects.filter(owner=self.new_seller).exists())
|
self.assertTrue(Store.objects.filter(owner=self.new_seller).exists())
|
||||||
|
self.assertAlmostEqual(response.data['latitude'], 35.75)
|
||||||
|
self.assertAlmostEqual(response.data['longitude'], 51.4)
|
||||||
|
|
||||||
def test_seller_cannot_create_a_second_store(self):
|
def test_seller_cannot_create_a_second_store(self):
|
||||||
self.client.force_authenticate(user=self.seller1)
|
self.client.force_authenticate(user=self.seller1)
|
||||||
|
|
|
||||||
|
|
@ -48,3 +48,30 @@ class StoreListFilterTests(OrdersTestCase):
|
||||||
|
|
||||||
store = next(s for s in response.data['results'] if s['uuid'] == str(self.store1.uuid))
|
store = next(s for s in response.data['results'] if s['uuid'] == str(self.store1.uuid))
|
||||||
self.assertIsNone(store['distance_km'])
|
self.assertIsNone(store['distance_km'])
|
||||||
|
|
||||||
|
def test_latitude_longitude_included_in_list(self):
|
||||||
|
self.store1.location = Point(51.4, 35.75, srid=4326)
|
||||||
|
self.store1.save(update_fields=['location'])
|
||||||
|
|
||||||
|
response = self.client.get('/api/v1/stores/')
|
||||||
|
|
||||||
|
store = next(s for s in response.data['results'] if s['uuid'] == str(self.store1.uuid))
|
||||||
|
self.assertAlmostEqual(store['latitude'], 35.75)
|
||||||
|
self.assertAlmostEqual(store['longitude'], 51.4)
|
||||||
|
|
||||||
|
def test_latitude_longitude_null_without_location(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['latitude'])
|
||||||
|
self.assertIsNone(store['longitude'])
|
||||||
|
|
||||||
|
def test_latitude_longitude_included_in_retrieve(self):
|
||||||
|
self.store1.location = Point(51.4, 35.75, srid=4326)
|
||||||
|
self.store1.save(update_fields=['location'])
|
||||||
|
|
||||||
|
response = self.client.get(f'/api/v1/stores/{self.store1.uuid}/')
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertAlmostEqual(response.data['latitude'], 35.75)
|
||||||
|
self.assertAlmostEqual(response.data['longitude'], 51.4)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue