Files
tripwithbonus/backend/api/account/client/serializers.py
2025-05-24 14:55:27 +03:00

287 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from rest_framework import serializers
from routes.models import Route, City, Country, Leads
from django.conf import settings
from routes.constants.routeChoices import cargo_type_choices, type_transport_choices, owner_type_choices
from routes.constants.account_types import account_types
from api.models import UserProfile
from sitemanagement.models import Pricing
from django.shortcuts import get_object_or_404
import pytz
from django.utils import timezone
from django.contrib.auth.models import User
class CountrySerializer(serializers.ModelSerializer):
value = serializers.CharField(source='international_name') # для совместимости с селектом на фронте
label = serializers.SerializerMethodField() # для отображения в селекте
class Meta:
model = Country
fields = ['id', 'value', 'label', 'flag_img_url']
def get_label(self, obj):
return obj.international_name or obj.official_name
class CitySerializer(serializers.ModelSerializer):
value = serializers.CharField(source='name') # для совместимости с селектом
label = serializers.CharField(source='name') # для отображения в селекте
country_name = serializers.CharField(source='country.international_name')
class Meta:
model = City
fields = ['id', 'value', 'label', 'country_name']
class RouteSerializer(serializers.ModelSerializer):
from_city_name = serializers.SerializerMethodField()
to_city_name = serializers.SerializerMethodField()
from_country_name = serializers.SerializerMethodField()
to_country_name = serializers.SerializerMethodField()
formatted_departure = serializers.SerializerMethodField()
formatted_arrival = serializers.SerializerMethodField()
formatted_cargo_type = serializers.SerializerMethodField()
formatted_transport = serializers.SerializerMethodField()
class Meta:
model = Route
fields = '__all__'
def get_from_city_name(self, obj):
try:
city = City.objects.get(id=obj.from_city_id)
return city.name
except City.DoesNotExist:
return None
def get_to_city_name(self, obj):
try:
city = City.objects.get(id=obj.to_city_id)
return city.name
except City.DoesNotExist:
return None
def get_from_country_name(self, obj):
try:
city = City.objects.get(id=obj.from_city_id)
return city.country.international_name or city.country.official_name
except (City.DoesNotExist, AttributeError):
return None
def get_to_country_name(self, obj):
try:
city = City.objects.get(id=obj.to_city_id)
return city.country.international_name or city.country.official_name
except (City.DoesNotExist, AttributeError):
return None
def _convert_to_local_time(self, dt):
if dt is None:
return None
# проверяем что у datetime есть временная зона (если нет, считаем UTC)
if dt.tzinfo is None:
dt = pytz.UTC.localize(dt)
# конвертируем в локальную временную зону
local_tz = pytz.timezone(settings.TIME_ZONE)
local_dt = dt.astimezone(local_tz)
return local_dt
def get_formatted_departure(self, obj):
local_dt = self._convert_to_local_time(obj.departure_DT)
return local_dt.strftime("%d.%m.%Y, %H:%M") if local_dt else None
def get_formatted_arrival(self, obj):
local_dt = self._convert_to_local_time(obj.arrival_DT)
return local_dt.strftime("%d.%m.%Y, %H:%M") if local_dt else None
def get_formatted_cargo_type(self, obj):
cargo_types = dict(cargo_type_choices)
return cargo_types.get(obj.cargo_type, obj.cargo_type)
def get_formatted_transport(self, obj):
transport_types = dict(type_transport_choices)
return transport_types.get(obj.type_transport, obj.type_transport)
class CreateRouteSerializer(serializers.ModelSerializer):
country_from = serializers.CharField(write_only=True)
city_from = serializers.CharField(write_only=True)
country_to = serializers.CharField(write_only=True)
city_to = serializers.CharField(write_only=True)
departure = serializers.DateTimeField(source='departure_DT')
arrival = serializers.DateTimeField(source='arrival_DT')
transport = serializers.ChoiceField(choices=type_transport_choices, source='type_transport')
email_notification = serializers.BooleanField(source='receive_msg_by_email')
phone_number = serializers.CharField(write_only=True)
owner_type = serializers.ChoiceField(choices=owner_type_choices)
class Meta:
model = Route
fields = [
'transport',
'country_from',
'city_from',
'country_to',
'city_to',
'cargo_type',
'departure',
'arrival',
'phone_number',
'comment',
'email_notification',
'owner_type',
]
def validate_phone_number(self, value):
if len(value) < 13: # +375XXXXXXXXX
raise serializers.ValidationError("Номер телефона слишком короткий")
if len(value) > 18:
raise serializers.ValidationError("Номер телефона слишком длинный")
return value
def validate(self, data):
# проверяем что дата прибытия позже даты отправления
if data['departure_DT'] >= data['arrival_DT']:
raise serializers.ValidationError(
"Дата прибытия должна быть позже даты отправления"
)
# проверяем существование стран
try:
country_from = Country.objects.get(international_name=data['country_from'])
except Country.DoesNotExist:
raise serializers.ValidationError({
"country_from": f"Страна '{data['country_from']}' не найдена в базе данных"
})
try:
country_to = Country.objects.get(international_name=data['country_to'])
except Country.DoesNotExist:
raise serializers.ValidationError({
"country_to": f"Страна '{data['country_to']}' не найдена в базе данных"
})
# проверяем существование городов в указанных странах
try:
city_from = City.objects.get(name=data['city_from'], country=country_from)
except City.DoesNotExist:
raise serializers.ValidationError({
"city_from": f"Город '{data['city_from']}' не найден в стране {country_from}"
})
try:
city_to = City.objects.get(name=data['city_to'], country=country_to)
except City.DoesNotExist:
raise serializers.ValidationError({
"city_to": f"Город '{data['city_to']}' не найден в стране {country_to}"
})
return data
def create(self, validated_data):
try:
# получаем города и страны
country_from = Country.objects.get(international_name=validated_data.pop('country_from'))
country_to = Country.objects.get(international_name=validated_data.pop('country_to'))
from_city = City.objects.get(name=validated_data.pop('city_from'), country=country_from)
to_city = City.objects.get(name=validated_data.pop('city_to'), country=country_to)
# обновляем номер телефона в профиле пользователя
phone_number = validated_data.pop('phone_number') # Удаляем из validated_data
user_profile = get_object_or_404(UserProfile, user=self.context['request'].user)
# проверяем, не используется ли этот номер другим пользователем
if UserProfile.objects.filter(phone_number=phone_number).exclude(user=self.context['request'].user).exists():
raise serializers.ValidationError({
"phone_number": "Этот номер телефона уже используется другим пользователем"
})
user_profile.phone_number = phone_number
user_profile.save()
# создаем маршрут
route = Route.objects.create(
from_city=from_city,
to_city=to_city,
owner=self.context['request'].user,
**validated_data
)
return route
except Exception as e:
raise
class PricingSerializer(serializers.ModelSerializer):
isPopular = serializers.BooleanField(source='is_popular')
plan = serializers.CharField()
features = serializers.SerializerMethodField()
class Meta:
model = Pricing
fields = ['plan', 'price', 'features', 'isPopular']
def get_features(self, obj):
return list(obj.membershipfeatures_set.values_list('feature', flat=True))
def to_representation(self, instance):
# преобразуем данные перед отправкой на фронтенд
data = super().to_representation(instance)
data['plan'] = data['plan'].lower() # приводим к нижнему регистру
return data
class PlanChangeSerializer(serializers.Serializer):
account_type = serializers.CharField()
def validate_account_type(self, value):
"""
Проверяем, что тип тарифа соответствует допустимым значениям
"""
valid_types = [t[0] for t in account_types]
if value not in valid_types:
raise serializers.ValidationError(
f"Недопустимый тип тарифа. Допустимые значения: {', '.join(valid_types)}"
)
return value
def validate(self, data):
"""
Проверка возможности перехода с одного тарифа на другой
"""
if not self.instance:
raise serializers.ValidationError("Пользователь не найден")
current_type = getattr(self.instance, 'account_type', None)
if not current_type:
raise serializers.ValidationError("У пользователя не установлен текущий тариф")
new_type = data['account_type']
if current_type == new_type:
raise serializers.ValidationError("Этот тариф уже активен")
return data
def update(self, instance, validated_data):
"""
Обновляем тип тарифа пользователя
"""
instance.account_type = validated_data['account_type']
instance.save()
return instance
class LeadSerializer(serializers.ModelSerializer):
route = serializers.PrimaryKeyRelatedField(queryset=Route.objects.all())
moving_user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
class Meta:
model = Leads
fields = ['route', 'moving_user', 'moving_price', 'moving_date', 'comment']
def validate_moving_date(self, value):
if value < timezone.now().date():
raise serializers.ValidationError("Дата перевозки не может быть в прошлом")
return value
def validate_moving_price(self, value):
if value <= 0:
raise serializers.ValidationError("Цена должна быть больше нуля")
return value