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

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 

11 

12# Serializer para el modelo Travel 

13class TravelSerializer(AuditFieldsMixin, serializers.ModelSerializer): 

14 

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) 

20 

21 vehicle_id = serializers.PrimaryKeyRelatedField( 

22 queryset=Vehicles.objects.all(), 

23 source='vehicle', 

24 write_only=True 

25 ) 

26 

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) 

31 

32 class Meta: 

33 model = Travel 

34 fields = "__all__" 

35 

36 def validate_vehicle_id(self, value): 

37 request = self.context.get('request') 

38 

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 

42 

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 

51 

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', []) 

61 

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'] 

66 

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 

69 

70 pickup_points = [] 

71 denied_users = [] 

72 

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) 

85 

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) 

96 

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) 

100 

101 if child_travels.exists(): 

102 child_pickup_points = [] 

103 child_denied_users = [] 

104 

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 

108 

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) 

114 

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 

117 

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 ) 

127 

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 ) 

136 

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) 

142 

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) 

147 

148 return travel 

149 

150#Serializer para el modelo TravelStates 

151class TravelStatesSerializer(AuditFieldsMixin, serializers.ModelSerializer): 

152 class Meta: 

153 model = TravelStates 

154 fields = "__all__" 

155 

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() 

161 

162 class Meta: 

163 model = RequestTravels 

164 fields = "__all__" 

165 

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 

171 

172# Serializer para el modelo RequestStates 

173class RequestStatesSerializer(AuditFieldsMixin, serializers.ModelSerializer): 

174 class Meta: 

175 model = RequestStates 

176 fields = "__all__" 

177 

178# Serializer para el modelo PickUpPoints 

179class PickUpPointSerializer(AuditFieldsMixin, serializers.ModelSerializer): 

180 class Meta: 

181 model = PickUpPoints 

182 fields = "__all__" 

183 

184# Serializer para el modelo UsersDenied 

185class UsersDeniedSerializer(AuditFieldsMixin, serializers.ModelSerializer): 

186 class Meta: 

187 model = UsersDenied 

188 fields = "__all__"