Coverage for payments/serializers.py: 74%

124 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1from rest_framework import serializers 

2from rest_polymorphic.serializers import PolymorphicSerializer 

3from app.stripe.actions import Stripe 

4from accounting.models import ProductCharge 

5from memberships.models import Membership 

6from memberships.serializers import BasicMembershipSerializer 

7from .models import Payment, PaymentIntent, ManualPayment, PaymentAllocation, PaymentAllocationExport 

8 

9 

10class PaymentSerializer(serializers.ModelSerializer): 

11 class Meta: 

12 model = Payment 

13 read_only_fields = ["random_slug", "created_at"] 

14 fields = read_only_fields + ["membership", "amount", "concept"] 

15 

16 def to_representation(self, instance): 

17 representation = super(PaymentSerializer, self).to_representation(instance) 

18 membership_slug = representation.get("membership") 

19 membership = Membership.objects.get(random_slug=membership_slug) 

20 serializer = BasicMembershipSerializer(instance=membership) 

21 representation["membership"] = serializer.data 

22 return representation 

23 

24 

25class PaymentAllocationSerializer(serializers.ModelSerializer): 

26 class Meta: 

27 model = PaymentAllocation 

28 read_only_fields = ["random_slug", "created_at"] 

29 fields = read_only_fields + ["product_charge", "amount"] 

30 

31 

32class PaymentIntentSerializer(serializers.ModelSerializer): 

33 payment_allocations = PaymentAllocationSerializer(many=True, required=False) 

34 

35 class Meta: 

36 model = PaymentIntent 

37 read_only_fields = ["random_slug", "stripe_pi_id", "created_at", "stripe_pi_id"] 

38 fields = read_only_fields + ["membership", "payment_method", "amount", "concept", "payment_allocations"] 

39 

40 def _make_stripe_payment_intent(self, membership, amount, payment_method): 

41 try: 

42 pi_id = Stripe(membership=membership).create_payment_intent( 

43 amount=int(amount * 100), payment_method=payment_method 

44 ) 

45 except Exception as e: 

46 raise serializers.ValidationError(e) 

47 

48 return pi_id 

49 

50 def create(self, validated_data): 

51 membership = validated_data.pop("membership") 

52 payment_method = validated_data.pop("payment_method") 

53 amount = validated_data.pop("amount") 

54 payment_allocations = validated_data.get("payment_allocations", None) 

55 

56 for allocation in payment_allocations: 

57 product_charge = allocation.get("product_charge") 

58 if (product_charge.paid_amount + allocation.get("amount")) > product_charge.amount: 58 ↛ 59line 58 didn't jump to line 59, because the condition on line 58 was never true

59 raise serializers.ValidationError({"detail": "No se puede pagar un monto mayor al pendiente"}) 

60 

61 pi_id = self._make_stripe_payment_intent(membership, amount, payment_method) 

62 

63 payment_intent = PaymentIntent.objects.create( 

64 organization=membership.organization, 

65 membership=membership, 

66 amount=amount, 

67 stripe_pi_id=pi_id, 

68 payment_method=payment_method, 

69 ) 

70 

71 for allocation in payment_allocations: 

72 PaymentAllocation.objects.create( 

73 payment=payment_intent, product_charge=allocation.get("product_charge"), amount=allocation.get("amount") 

74 ) 

75 

76 return payment_intent 

77 

78 def to_representation(self, instance): 

79 representation = super(PaymentIntentSerializer, self).to_representation(instance) 

80 membership_slug = representation.get("membership") 

81 membership = Membership.objects.get(random_slug=membership_slug) 

82 serializer = BasicMembershipSerializer(instance=membership) 

83 representation["membership"] = serializer.data 

84 return representation 

85 

86 

87class MemberPaymentIntentSerializer(PaymentIntentSerializer): 

88 product_charges = serializers.PrimaryKeyRelatedField( 

89 many=True, write_only=True, queryset=ProductCharge.objects.all() 

90 ) 

91 

92 class Meta(PaymentIntentSerializer.Meta): 

93 read_only_fields = ["random_slug", "stripe_pi_id", "created_at", "stripe_pi_id"] 

94 fields = read_only_fields + [ 

95 "membership", 

96 "payment_method", 

97 "concept", 

98 "payment_allocations", 

99 "product_charges", 

100 ] 

101 extra_kwargs = {"product_charges": {"write_only": True}} 

102 

103 def create(self, validated_data): 

104 membership = validated_data.pop("membership") 

105 payment_method = validated_data.pop("payment_method") 

106 product_charges = validated_data.pop("product_charges") 

107 

108 total_amount = sum(product_charge.amount - product_charge.paid_amount for product_charge in product_charges) 

109 

110 if total_amount == 0: 

111 raise serializers.ValidationError({"detail": "El monto a pagar no puede ser 0"}) 

112 

113 pi_id = self._make_stripe_payment_intent(membership, total_amount, payment_method) 

114 

115 payment_intent = PaymentIntent.objects.create( 

116 organization=membership.organization, 

117 membership=membership, 

118 amount=total_amount, 

119 stripe_pi_id=pi_id, 

120 payment_method=payment_method, 

121 ) 

122 

123 for product_charge in product_charges: 

124 PaymentAllocation.objects.create( 

125 payment=payment_intent, 

126 product_charge=product_charge, 

127 amount=product_charge.amount - product_charge.paid_amount, 

128 ) 

129 

130 return payment_intent 

131 

132 

133class ManualPaymentSerializer(serializers.ModelSerializer): 

134 payment_allocations = PaymentAllocationSerializer(many=True, required=False) 

135 

136 class Meta: 

137 model = ManualPayment 

138 read_only_fields = ["random_slug", "created_at"] 

139 fields = read_only_fields + [ 

140 "membership", 

141 "payment_method_type", 

142 "date", 

143 "amount", 

144 "concept", 

145 "reference", 

146 "payment_allocations", 

147 ] 

148 

149 def create(self, validated_data): 

150 membership = validated_data.get("membership") 

151 payment_allocations = validated_data.pop("payment_allocations", None) 

152 

153 for allocation in payment_allocations: 

154 product_charge = allocation.get("product_charge") 

155 if (product_charge.paid_amount + allocation.get("amount")) > product_charge.amount: 155 ↛ 156line 155 didn't jump to line 156, because the condition on line 155 was never true

156 raise serializers.ValidationError({"detail": "No se puede pagar un monto mayor al pendiente"}) 

157 

158 validated_data["organization"] = membership.organization 

159 

160 manual_payment = ManualPayment.objects.create(**validated_data) 

161 

162 for allocation in payment_allocations: 

163 PaymentAllocation.objects.create( 

164 payment=manual_payment, product_charge=allocation.get("product_charge"), amount=allocation.get("amount") 

165 ) 

166 

167 return manual_payment 

168 

169 def to_representation(self, instance): 

170 representation = super(ManualPaymentSerializer, self).to_representation(instance) 

171 membership_slug = representation.get("membership") 

172 membership = Membership.objects.get(random_slug=membership_slug) 

173 serializer = BasicMembershipSerializer(instance=membership) 

174 representation["membership"] = serializer.data 

175 return representation 

176 

177 

178class PaymentPolymorphicSerializer(PolymorphicSerializer): 

179 """ 

180 Polymorphic serializer for Payment objects 

181 """ 

182 

183 model_serializer_mapping = { 

184 PaymentIntent: PaymentIntentSerializer, 

185 ManualPayment: ManualPaymentSerializer, 

186 } 

187 

188 

189class PaymentAllocationExportSerializer(serializers.ModelSerializer): 

190 """ 

191 Serializer for PaymentAllocationExport 

192 """ 

193 

194 class Meta: 

195 model = PaymentAllocationExport 

196 read_only_fields = ["random_slug", "created_at", "export_file"] 

197 fields = read_only_fields + ["from_date", "to_date"] 

198 

199 

200class PublicPaymentIntentSerializer(PaymentIntentSerializer): 

201 product_charges = serializers.PrimaryKeyRelatedField( 

202 many=True, write_only=True, queryset=ProductCharge.objects.all() 

203 ) 

204 cs_url = serializers.URLField() 

205 

206 class Meta(PaymentIntentSerializer.Meta): 

207 read_only_fields = ["random_slug", "created_at", "stripe_cs_id", "cs_url"] 

208 fields = read_only_fields + [ 

209 "success_url", 

210 "cancel_url", 

211 "concept", 

212 "payment_allocations", 

213 "product_charges", 

214 ] 

215 extra_kwargs = {"product_charges": {"write_only": True}} 

216 

217 def create(self, validated_data): 

218 payment_method = validated_data.pop("payment_method") 

219 product_charges = validated_data.pop("product_charges") 

220 

221 total_amount = sum(product_charge.amount - product_charge.paid_amount for product_charge in product_charges) 

222 

223 if total_amount == 0: 

224 raise serializers.ValidationError({"detail": "El monto a pagar no puede ser 0"}) 

225 

226 # pi_id = self._make_stripe_payment_intent(membership, total_amount, payment_method) 

227 

228 payment_intent = PaymentIntent.objects.create( 

229 organization=product_charges.first().organization, 

230 amount=total_amount, 

231 # stripe_pi_id=pi_id, 

232 payment_method=payment_method, 

233 ) 

234 

235 for product_charge in product_charges: 

236 PaymentAllocation.objects.create( 

237 payment=payment_intent, 

238 product_charge=product_charge, 

239 amount=product_charge.amount - product_charge.paid_amount, 

240 ) 

241 

242 return payment_intent