backend routes
This commit is contained in:
@@ -42,6 +42,7 @@ class RouteSerializer(serializers.ModelSerializer):
|
|||||||
formatted_arrival = serializers.SerializerMethodField()
|
formatted_arrival = serializers.SerializerMethodField()
|
||||||
formatted_cargo_type = serializers.SerializerMethodField()
|
formatted_cargo_type = serializers.SerializerMethodField()
|
||||||
formatted_transport = serializers.SerializerMethodField()
|
formatted_transport = serializers.SerializerMethodField()
|
||||||
|
is_highlighted = serializers.SerializerMethodField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Route
|
model = Route
|
||||||
@@ -102,6 +103,8 @@ class RouteSerializer(serializers.ModelSerializer):
|
|||||||
transport_types = dict(type_transport_choices)
|
transport_types = dict(type_transport_choices)
|
||||||
return transport_types.get(obj.type_transport, obj.type_transport)
|
return transport_types.get(obj.type_transport, obj.type_transport)
|
||||||
|
|
||||||
|
def get_is_highlighted(self, obj):
|
||||||
|
return obj.is_currently_highlighted
|
||||||
|
|
||||||
class CreateRouteSerializer(serializers.ModelSerializer):
|
class CreateRouteSerializer(serializers.ModelSerializer):
|
||||||
country_from = serializers.CharField(write_only=True)
|
country_from = serializers.CharField(write_only=True)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from django.core.validators import validate_email
|
|||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from .serializers import RouteSerializer, CreateRouteSerializer, CitySerializer, CountrySerializer, PlanChangeSerializer, PricingSerializer, LeadSerializer, LeadResponseSerializer
|
from .serializers import RouteSerializer, CreateRouteSerializer, CitySerializer, CountrySerializer, PlanChangeSerializer, PricingSerializer, LeadSerializer, LeadResponseSerializer
|
||||||
from api.auth.serializers import UserResponseSerializer
|
from api.auth.serializers import UserResponseSerializer
|
||||||
@@ -310,3 +311,26 @@ class LeadViewSet(ViewSet):
|
|||||||
LeadResponseSerializer(leads, many=True).data,
|
LeadResponseSerializer(leads, many=True).data,
|
||||||
status=status.HTTP_200_OK
|
status=status.HTTP_200_OK
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class PremiumMembershipActionsView(ViewSet):
|
||||||
|
"""Выделение объявления"""
|
||||||
|
|
||||||
|
@action(detail=False, methods=['patch'])
|
||||||
|
@handle_exceptions
|
||||||
|
def highlight_route(self, request):
|
||||||
|
"""Выделяем объявление"""
|
||||||
|
route_id = request.data.get('route_id')
|
||||||
|
route = get_object_or_404(Route, id=route_id)
|
||||||
|
route.is_highlighted = True
|
||||||
|
route.save()
|
||||||
|
return Response({"message": "Объявление выделено"}, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
|
@action(detail=False, methods=['patch'])
|
||||||
|
@handle_exceptions
|
||||||
|
def upper_route(self, request):
|
||||||
|
"""Поднимаем объявление"""
|
||||||
|
route_id = request.data.get('route_id')
|
||||||
|
route = get_object_or_404(Route, id=route_id)
|
||||||
|
route.rising_DT = datetime.now()
|
||||||
|
route.save()
|
||||||
|
return Response({"message": "Объявление поднято"}, status=status.HTTP_200_OK)
|
||||||
@@ -15,7 +15,8 @@ CityView,
|
|||||||
CountryView,
|
CountryView,
|
||||||
GetMembershipData,
|
GetMembershipData,
|
||||||
ChangeUserMembership,
|
ChangeUserMembership,
|
||||||
LeadViewSet)
|
LeadViewSet,
|
||||||
|
PremiumMembershipActionsView)
|
||||||
|
|
||||||
from api.search.views import SearchRouteListView
|
from api.search.views import SearchRouteListView
|
||||||
|
|
||||||
@@ -35,6 +36,8 @@ urlpatterns = [
|
|||||||
path("v1/account/change_main_data/", AccountActionsView.as_view({'patch':'change_data_main_tab'}), name='change_data_main_tab'),
|
path("v1/account/change_main_data/", AccountActionsView.as_view({'patch':'change_data_main_tab'}), name='change_data_main_tab'),
|
||||||
path("v1/account/routes/", AccountActionsView.as_view({'get':'user_routes'}), name='user_routes'),
|
path("v1/account/routes/", AccountActionsView.as_view({'get':'user_routes'}), name='user_routes'),
|
||||||
path("v1/account/create_route/", AccountActionsView.as_view({'post':'create_route'}), name='create_route'),
|
path("v1/account/create_route/", AccountActionsView.as_view({'post':'create_route'}), name='create_route'),
|
||||||
|
path("v1/account/highlight/", PremiumMembershipActionsView.as_view({'patch':'highlight_route'}), name='highlight_route'),
|
||||||
|
path("v1/account/upper/", PremiumMembershipActionsView.as_view({'patch':'upper_route'}), name='upper_route'),
|
||||||
|
|
||||||
path("v1/account/send_lead/", LeadViewSet.as_view({'post':'send_lead'}), name='send_lead'),
|
path("v1/account/send_lead/", LeadViewSet.as_view({'post':'send_lead'}), name='send_lead'),
|
||||||
path("v1/account/leads/", LeadViewSet.as_view({'get':'get_leads'}), name='get_leads'),
|
path("v1/account/leads/", LeadViewSet.as_view({'get':'get_leads'}), name='get_leads'),
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# Generated by Django 5.2.1 on 2025-05-29 09:21
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('routes', '0008_city_russian_name_alter_city_name'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='route',
|
||||||
|
name='highlight_end_DT',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='route',
|
||||||
|
name='is_highlighted',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='Выделено'),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
backend/routes/migrations/0010_route_highlight_end_dt.py
Normal file
18
backend/routes/migrations/0010_route_highlight_end_dt.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.2.1 on 2025-05-29 09:24
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('routes', '0009_remove_route_highlight_end_dt_route_is_highlighted'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='route',
|
||||||
|
name='highlight_end_DT',
|
||||||
|
field=models.DateTimeField(blank=True, null=True, verbose_name='Выделено до'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from routes.constants.routeChoices import owner_type_choices, type_transport_choices, cargo_type_choices
|
from routes.constants.routeChoices import owner_type_choices, type_transport_choices, cargo_type_choices
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
class Country(models.Model):
|
class Country(models.Model):
|
||||||
id = models.BigAutoField(primary_key=True)
|
id = models.BigAutoField(primary_key=True)
|
||||||
@@ -101,10 +102,11 @@ class Route(models.Model):
|
|||||||
verbose_name=('Дата и время последнего поднятия'),
|
verbose_name=('Дата и время последнего поднятия'),
|
||||||
blank=True, null=True
|
blank=True, null=True
|
||||||
)
|
)
|
||||||
|
is_highlighted = models.BooleanField(default=False, verbose_name=('Выделено'))
|
||||||
highlight_end_DT = models.DateTimeField(
|
highlight_end_DT = models.DateTimeField(
|
||||||
verbose_name=('Дата и время окончания выделения'),
|
verbose_name=('Выделено до'),
|
||||||
blank=True, null=True
|
null=True,
|
||||||
|
blank=True
|
||||||
)
|
)
|
||||||
|
|
||||||
status = models.CharField(
|
status = models.CharField(
|
||||||
@@ -123,6 +125,13 @@ class Route(models.Model):
|
|||||||
to_city_name = self.to_city.name if self.to_city else 'Не указан'
|
to_city_name = self.to_city.name if self.to_city else 'Не указан'
|
||||||
return f"Маршрут #{self.id}: {from_city_name} → {to_city_name}"
|
return f"Маршрут #{self.id}: {from_city_name} → {to_city_name}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_currently_highlighted(self):
|
||||||
|
"""Проверяем, выделено ли объявление на текущий момент"""
|
||||||
|
if not self.highlight_end_DT:
|
||||||
|
return False
|
||||||
|
return timezone.now() <= self.highlight_end_DT
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = (u'Маршрут')
|
verbose_name = (u'Маршрут')
|
||||||
verbose_name_plural = (u'Маршруты')
|
verbose_name_plural = (u'Маршруты')
|
||||||
|
|||||||
@@ -1,3 +1,31 @@
|
|||||||
from django.shortcuts import render
|
from django.utils import timezone
|
||||||
|
from datetime import timedelta
|
||||||
|
from rest_framework.decorators import api_view, permission_classes
|
||||||
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework import status
|
||||||
|
from .models import Route
|
||||||
|
|
||||||
# Create your views here.
|
@api_view(['PATCH'])
|
||||||
|
@permission_classes([IsAuthenticated])
|
||||||
|
def highlight_route(request):
|
||||||
|
try:
|
||||||
|
route_id = request.data.get('route_id')
|
||||||
|
route = Route.objects.get(id=route_id, owner=request.user)
|
||||||
|
|
||||||
|
# подсвечиваем объявление на 24 часа
|
||||||
|
route.highlight_end_DT = timezone.now() + timedelta(days=1)
|
||||||
|
route.is_highlighted = True
|
||||||
|
route.save()
|
||||||
|
|
||||||
|
return Response({'status': 'success'})
|
||||||
|
except Route.DoesNotExist:
|
||||||
|
return Response(
|
||||||
|
{'error': 'Маршрут не найден или у вас нет прав для его изменения'},
|
||||||
|
status=status.HTTP_404_NOT_FOUND
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
return Response(
|
||||||
|
{'error': str(e)},
|
||||||
|
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
||||||
|
)
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ export default function UserRoutes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const data = await response.json()
|
const data = await response.json()
|
||||||
|
console.log(data)
|
||||||
|
|
||||||
setRoutes(data || [])
|
setRoutes(data || [])
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching routes:', error)
|
console.error('Error fetching routes:', error)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export async function PATCH(req: NextRequest) {
|
|||||||
|
|
||||||
const { route_id } = await req.json()
|
const { route_id } = await req.json()
|
||||||
|
|
||||||
const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/account/route_highlight/`, {
|
const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/account/highlight/`, {
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export async function PATCH(req: NextRequest) {
|
|||||||
|
|
||||||
const { route_id } = await req.json()
|
const { route_id } = await req.json()
|
||||||
|
|
||||||
const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/account/route_up/`, {
|
const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/account/upper/`, {
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@@ -31,7 +31,7 @@ export async function PATCH(req: NextRequest) {
|
|||||||
const result = await response.json()
|
const result = await response.json()
|
||||||
return new Response(JSON.stringify(result), { status: 200 })
|
return new Response(JSON.stringify(result), { status: 200 })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('PATCH /api/account/route_up error:', error)
|
console.error('PATCH /api/account/upper error:', error)
|
||||||
return new Response(JSON.stringify({ error: 'Internal Server Error' }), {
|
return new Response(JSON.stringify({ error: 'Internal Server Error' }), {
|
||||||
status: 500,
|
status: 500,
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user