Coverage for apps/orders/serializers.py: 95%

154 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-10-27 13:26 -0600

1from django.db import transaction 

2from django.db.models import Sum 

3from rest_framework import serializers 

4 

5from api.serializers import ToRepresentationMixin 

6from apps.catalogues.serializers import WeekSerializer 

7from apps.products.serializers import BasicProductSerializer, ProductVariationSerializer 

8from apps.sales.serializers import BasicSalesPersonSerializer 

9from apps.suppliers.serializers import SupplierSerializer 

10from apps.users.serializers import UserSerializer 

11 

12from .models import Icon, Order, OrderComment, OrderIcon, OrderItem, OrderItemSize 

13 

14 

15class IconSerializer(serializers.ModelSerializer): 

16 """ 

17 Serializer for Icon 

18 """ 

19 

20 class Meta: 

21 model = Icon 

22 read_only_fields = ["random_slug"] 

23 fields = read_only_fields + ["name", "color", "iconify_icon"] 

24 

25 

26class OrderIconSerializer(serializers.ModelSerializer): 

27 """ 

28 Serializer for Order Icon 

29 """ 

30 

31 icon = IconSerializer() 

32 

33 class Meta: 

34 model = OrderIcon 

35 read_only_fields = ["random_slug", "icon"] 

36 fields = read_only_fields + ["is_active"] 

37 

38 

39class OrderItemSizeSerializer(serializers.ModelSerializer): 

40 """ 

41 Serializer for Order Item Size 

42 """ 

43 

44 class Meta: 

45 model = OrderItemSize 

46 read_only_fields = ["random_slug", "status", "delivered_amount", "pending_amount"] 

47 fields = read_only_fields + ["order_item", "amount", "size"] 

48 extra_kwargs = {"order_item": {"required": False}} 

49 

50 

51class OrderItemSerializer(ToRepresentationMixin): 

52 """ 

53 Serializer for Order Item 

54 """ 

55 

56 REPRESENTATION_FIELDS = [ 

57 ["product_variation", ProductVariationSerializer, False], 

58 ["sales_person", BasicSalesPersonSerializer, False], 

59 ] 

60 

61 sizes = OrderItemSizeSerializer(many=True) 

62 total_cost = serializers.SerializerMethodField() 

63 total_amount = serializers.SerializerMethodField() 

64 product_detail = serializers.SerializerMethodField() 

65 

66 class Meta: 

67 model = OrderItem 

68 read_only_fields = ["random_slug"] 

69 fields = read_only_fields + [ 

70 "order", 

71 "product_variation", 

72 "product_detail", 

73 "sales_person", 

74 "description", 

75 "cost", 

76 "total_cost", 

77 "total_amount", 

78 "status", 

79 "sizes", 

80 ] 

81 extra_kwargs = {"order": {"required": False}} 

82 

83 def get_total_cost(self, instance): 

84 return instance.sizes.aggregate(total_amount=Sum("amount")).get("total_amount") or 0 * instance.cost 

85 

86 def get_total_amount(self, instance): 

87 return instance.sizes.aggregate(total_amount=Sum("amount")).get("total_amount") or 0 

88 

89 def get_product_detail(self, instance): 

90 return BasicProductSerializer(instance.product_variation.product, context=self.context).data 

91 

92 def validate(self, attrs): 

93 product_variation = attrs.get("product_variation", None) 

94 sizes = attrs.get("sizes", []) 

95 for order_item_size in sizes: 

96 size = order_item_size.get("size") 

97 if product_variation: 97 ↛ 95line 97 didn't jump to line 95, because the condition on line 97 was never false

98 if size not in product_variation.sizes: 

99 raise serializers.ValidationError( 

100 { 

101 "sizes": f"El tamaño {size} no es un tamaño valido para {product_variation.product.name} [{product_variation.initial}, {product_variation.final}, {product_variation.step}]" 

102 } 

103 ) 

104 return attrs 

105 

106 def create(self, validated_data): 

107 sizes = validated_data.pop("sizes", []) 

108 

109 order_item = super().create(validated_data) 

110 

111 for size in sizes: 

112 size["order_item"] = order_item 

113 order_item_size_serializer = OrderItemSizeSerializer(size) 

114 order_item_size_serializer.create(size) 

115 

116 return order_item 

117 

118 def update(self, instance, validated_data): 

119 product_variation = validated_data.pop("product_variation", None) 

120 sizes = validated_data.pop("sizes", []) 

121 

122 order_item = super().update(instance, validated_data) 

123 

124 if product_variation: 124 ↛ 135line 124 didn't jump to line 135, because the condition on line 124 was never false

125 instance.product_variation = product_variation 

126 instance.save() 

127 

128 instance.sizes.all().delete() 

129 

130 for size in sizes: 

131 size["order_item"] = order_item 

132 order_item_size_serializer = OrderItemSizeSerializer(size) 

133 order_item_size_serializer.create(size) 

134 

135 return instance 

136 

137 

138class OrderSerializer(ToRepresentationMixin): 

139 """ 

140 Serializers for Order 

141 """ 

142 

143 REPRESENTATION_FIELDS = [["supplier", SupplierSerializer, False], ["week", WeekSerializer, False]] 

144 

145 items = OrderItemSerializer(many=True) 

146 icons = OrderIconSerializer(source="ordericon_set", many=True, read_only=True) 

147 

148 class Meta: 

149 model = Order 

150 read_only_fields = ["random_slug", "created_at", "icons"] 

151 fields = read_only_fields + [ 

152 "supplier", 

153 "week", 

154 "delivery_date", 

155 "cancellation_date", 

156 "description", 

157 "order_id", 

158 "status", 

159 "items", 

160 "original_order", 

161 ] 

162 

163 def create(self, validated_data): 

164 with transaction.atomic(): 

165 items = validated_data.pop("items", []) 

166 

167 order = super().create(validated_data) 

168 

169 for item in items: 

170 item["order"] = order 

171 order_item_serializer = OrderItemSerializer(item) 

172 order_item_serializer.create(item) 

173 

174 return order 

175 

176 

177class BasicOrderSerializer(serializers.ModelSerializer): 

178 """ 

179 Serializer for Order with minimum data 

180 """ 

181 

182 class Meta: 

183 model = Order 

184 read_only_fields = ["random_slug", "order_id", "created_at", "delivery_date", "cancellation_date", "status"] 

185 fields = read_only_fields + [] 

186 

187 

188class OrderItemSizeSplitSerializer(serializers.Serializer): 

189 """ 

190 Serializer for OrderItemSize split 

191 """ 

192 

193 order_item_size = serializers.PrimaryKeyRelatedField( 

194 queryset=OrderItemSize.objects.exclude(status=OrderItemSize.Status.DELIVERED) 

195 ) 

196 amount = serializers.IntegerField() 

197 

198 class Meta: 

199 fields = ["order_item_size", "amount"] 

200 

201 def validate(self, attrs): 

202 amount = attrs.get("amount") 

203 order_item_size = attrs.get("order_item_size") 

204 

205 if amount > order_item_size.pending_amount: 205 ↛ 206line 205 didn't jump to line 206, because the condition on line 205 was never true

206 raise serializers.ValidationError( 

207 {"amount": f"Solo hay {order_item_size.pending_amount} elementos para separar."} 

208 ) 

209 

210 return attrs 

211 

212 

213class OrderItemSplitSerializer(serializers.Serializer): 

214 """ 

215 Serializer for OrderItem split 

216 """ 

217 

218 order_item = serializers.PrimaryKeyRelatedField( 

219 queryset=OrderItem.objects.exclude(status=OrderItem.Status.DELIVERED) 

220 ) 

221 sizes = OrderItemSizeSplitSerializer(many=True) 

222 

223 class Meta: 

224 fields = ["order_item", "sizes"] 

225 

226 

227class OrderSplitSerializer(serializers.Serializer): 

228 """ 

229 Serializer for Order split 

230 """ 

231 

232 order = serializers.PrimaryKeyRelatedField(queryset=Order.objects.exclude(status=Order.Status.DELIVERED)) 

233 items = OrderItemSplitSerializer(many=True) 

234 

235 class Meta: 

236 fields = ["order", "items"] 

237 

238 def create(self, validated_data): 

239 with transaction.atomic(): 

240 order = validated_data.get("order") 

241 order.original_order = order 

242 order.random_slug = None 

243 order.status = Order.Status.PENDING 

244 order.save() 

245 

246 items = validated_data.get("items") 

247 

248 for item in items: 

249 order_item = item.get("order_item") 

250 order_item.random_slug = None 

251 order_item.order = order 

252 order_item.save() 

253 

254 sizes = item.get("sizes") 

255 

256 for size in sizes: 

257 order_item_size = size.get("order_item_size") 

258 amount = size.get("amount") 

259 order_item_size.amount -= amount 

260 order_item_size.save() 

261 order_item_size.random_slug = None 

262 order_item_size.order_item = order_item 

263 order_item_size.amount = amount 

264 order_item_size.save() 

265 

266 return order 

267 

268 

269class OrderCommentSerializer(serializers.ModelSerializer): 

270 """ 

271 Serializer for OrderComment 

272 """ 

273 

274 author = UserSerializer(read_only=True) 

275 children_comments = serializers.SerializerMethodField() 

276 

277 class Meta: 

278 model = OrderComment 

279 read_only_fields = ["random_slug", "created_at", "author", "children_comments"] 

280 fields = read_only_fields + ["order", "parent_comment", "comment"] 

281 

282 def get_children_comments(self, instance): 

283 return OrderCommentSerializer(instance.children_comments.all(), many=True).data 

284 

285 def validate_parent_comment(self, value): 

286 if value.parent_comment is not None: 

287 raise serializers.ValidationError("No puede haber comentarios de mas de un nivel.") 

288 return value