Coverage for api\serializers\travel_serializer.py: 97.7%
103 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-08-30 20:58 +0200
« prev ^ index » next coverage.py v7.15.2, created at 2026-08-30 20:58 +0200
1from rest_framework import serializers
2from travels.models import *
3from django.db import transaction
4from django.contrib.gis.geos import Point
5from api.errors import ErrorCodes
6from api.exceptions import CustomAPIException
7from api.serializers.base import AuditFieldsMixin
8from api.serializers.user_serializer import PublicUserSerializer, VehicleSerializer
9from django.utils.dateparse import parse_datetime
10from chats.models import Chat
12# Serializer para el modelo Travel
13class TravelSerializer(AuditFieldsMixin, serializers.ModelSerializer):
15 # Atributos para crear los puntos
16 origin_lat = serializers.FloatField(write_only=True)
17 origin_lng = serializers.FloatField(write_only=True)
18 destination_lat = serializers.FloatField(write_only=True)
19 destination_lng = serializers.FloatField(write_only=True)
21 vehicle_id = serializers.PrimaryKeyRelatedField(
22 queryset=Vehicles.objects.all(),
23 source='vehicle',
24 write_only=True
25 )
27 pick_up_points = serializers.ListField(child=serializers.DictField(), write_only=True, required=False)
28 deny_roles = serializers.ListField(child=serializers.CharField(), write_only=True, required=False)
29 creation_user = PublicUserSerializer(read_only=True)
30 vehicle = VehicleSerializer(read_only=True)
32 class Meta:
33 model = Travel
34 fields = "__all__"
36 def validate_vehicle_id(self, value):
37 request = self.context.get('request')
39 # Sin peticion en el contexto no hay contra quien comprobar, pasa al usar el serializer fuera de una vista (pruebas, scripts), y ahi no aplica
40 if request is None or not request.user.is_authenticated: 40 ↛ 41line 40 didn't jump to line 41 because the condition on line 40 was never true
41 return value
43 # Se debe validar que el vehiculo no este borrado y que realmente pertenezca al usuario que hace la peticion
44 if value.id_user_id != request.user.pk or value.is_deleted:
45 raise CustomAPIException(
46 code=ErrorCodes.VEHICLE_DONT_EXIST,
47 message="El vehículo no existe o no es tuyo",
48 status_code=404
49 )
50 return value
52 @transaction.atomic
53 def create(self, validated_data):
54 # Coordenadas de los puntos de origen y destino
55 o_lat = validated_data.pop('origin_lat')
56 o_lng = validated_data.pop('origin_lng')
57 d_lat = validated_data.pop('destination_lat')
58 d_lng = validated_data.pop('destination_lng')
59 pick_up_points_data = validated_data.pop('pick_up_points', [])
60 deny_roles_data = validated_data.pop('deny_roles', [])
62 validated_data['origin_point'] = Point(float(o_lng), float(o_lat), srid=4326)
63 validated_data['destination_point'] = Point(float(d_lng), float(d_lat), srid=4326)
64 validated_data['creation_user'] = self.context['request'].user
65 validated_data['remaining_seats'] = validated_data['num_seats']
67 travel = Travel.objects.create(**validated_data)
68 # El trigger create_periodic_travels() crea los viajes hijos con los datos del padre, pero solo el viaje, no puntos de recogida ni usuarios denegados
70 pickup_points = []
71 denied_users = []
73 # Se crean los puntos de recogida del padre
74 if pick_up_points_data:
75 pickup_points = [
76 PickUpPoints(
77 id_travel=travel,
78 direction=pick_up_point['direction'],
79 date=pick_up_point.get('date'), # Se le asigna la hora de paso por la parada
80 order_in_travel=pick_up_point['order_in_travel'],
81 point=Point(float(pick_up_point['lng']), float(pick_up_point['lat']), srid=4326)
82 ) for pick_up_point in pick_up_points_data
83 ]
84 PickUpPoints.objects.bulk_create(pickup_points)
86 # Se crean los roles denegados del padre
87 if deny_roles_data:
88 user_types = UserType.objects.filter(code__in=deny_roles_data)
89 denied_users = [
90 UsersDenied(
91 id_travel=travel,
92 user_type=ut
93 ) for ut in user_types
94 ]
95 UsersDenied.objects.bulk_create(denied_users)
97 # Se buscan los hijos y se les copia las relaciones
98 if pickup_points or denied_users:
99 child_travels = Travel.objects.filter(id_origin_travel=travel)
101 if child_travels.exists():
102 child_pickup_points = []
103 child_denied_users = []
105 for child in child_travels:
106 # Se calcula la diferencia de tiempo entre el viaje padre y los hijos
107 time_diff = child.travel_date - travel.travel_date
109 for pp in pickup_points:
110 # Se parsea la fecha
111 original_date = pp.date
112 if isinstance(original_date, str): 112 ↛ 116line 112 didn't jump to line 116 because the condition on line 112 was always true
113 original_date = parse_datetime(original_date)
115 # Se le suma el perido entre viajes para poner la fecha correcta
116 new_date = original_date + time_diff if original_date else None
118 child_pickup_points.append(
119 PickUpPoints(
120 id_travel=child,
121 direction=pp.direction,
122 date=new_date,
123 order_in_travel=pp.order_in_travel,
124 point=pp.point
125 )
126 )
128 # Se copian los usuarios denegados
129 for du in denied_users:
130 child_denied_users.append(
131 UsersDenied(
132 id_travel=child,
133 user_type=du.user_type
134 )
135 )
137 # Se crean los puntos intermedios y los usuarios denegados
138 if child_pickup_points:
139 PickUpPoints.objects.bulk_create(child_pickup_points)
140 if child_denied_users:
141 UsersDenied.objects.bulk_create(child_denied_users)
143 # Se crea el chat del viaje y el de los hijos
144 Chat.get_or_create_for_travel(travel)
145 for child in Travel.objects.filter(id_origin_travel=travel):
146 Chat.get_or_create_for_travel(child)
148 return travel
150#Serializer para el modelo TravelStates
151class TravelStatesSerializer(AuditFieldsMixin, serializers.ModelSerializer):
152 class Meta:
153 model = TravelStates
154 fields = "__all__"
156# Serializer para el modelo RequestTravels
157class RequestTravelsSerializer(AuditFieldsMixin, serializers.ModelSerializer):
158 id_travel = TravelSerializer(read_only=True)
159 user = PublicUserSerializer(read_only=True)
160 validation_code = serializers.SerializerMethodField()
162 class Meta:
163 model = RequestTravels
164 fields = "__all__"
166 def get_validation_code(self, obj):
167 request = self.context.get('request')
168 if request is not None and obj.user_id == request.user.pk:
169 return obj.validation_code
170 return None
172# Serializer para el modelo RequestStates
173class RequestStatesSerializer(AuditFieldsMixin, serializers.ModelSerializer):
174 class Meta:
175 model = RequestStates
176 fields = "__all__"
178# Serializer para el modelo PickUpPoints
179class PickUpPointSerializer(AuditFieldsMixin, serializers.ModelSerializer):
180 class Meta:
181 model = PickUpPoints
182 fields = "__all__"
184# Serializer para el modelo UsersDenied
185class UsersDeniedSerializer(AuditFieldsMixin, serializers.ModelSerializer):
186 class Meta:
187 model = UsersDenied
188 fields = "__all__"