Coverage for apps/payments/serializers.py: 50%

93 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2024-05-23 11:15 -0600

1from django.db import transaction 

2from djstripe.models import Price, Session 

3from rest_framework import serializers 

4from sentry_sdk import capture_exception 

5 

6from app.stripe.actions import Stripe 

7from apps.practitioners.models import Practitioner 

8 

9from apps.patients.serializers import PatientSerializer 

10 

11from .models import OrganizationPaymentMethod, Payment, PaymentAllocation, PaymentExport 

12 

13 

14 

15class SessionSerializer(serializers.ModelSerializer): 

16 """ 

17 Serializer for Session 

18 """ 

19 

20 practitioner = serializers.PrimaryKeyRelatedField(queryset=Practitioner.objects.all(), write_only=True) 

21 price = serializers.SlugRelatedField(slug_field="id", queryset=Price.objects.all(), write_only=True) 

22 url = serializers.SerializerMethodField() 

23 

24 class Meta: 

25 model = Session 

26 read_only_fields = ["id", "subscription", "url"] 

27 fields = read_only_fields + ["practitioner", "price", "success_url", "cancel_url"] 

28 

29 def validate_practitioner(self, practitioner): 

30 if practitioner.is_paid: 

31 raise serializers.ValidationError("Ya tiene suscripcion") 

32 return practitioner 

33 

34 def create(self, validated_data): 

35 practitioner = validated_data.get("practitioner") 

36 price = validated_data.get("price") 

37 success_url = validated_data.get("success_url") 

38 cancel_url = validated_data.get("cancel_url") 

39 

40 stripe = Stripe() 

41 session = stripe.create_checkout_session_for_subscription(practitioner, price, success_url, cancel_url) 

42 

43 return session 

44 

45 def get_url(self, instance): 

46 stripe = Stripe() 

47 return stripe.client.checkout.Session.retrieve(instance.id).url 

48 

49 

50class OrganizationPaymentMethodSerializer(serializers.ModelSerializer): 

51 """ 

52 Serializer for Payment Method on Oragnization used for Patient Payment 

53 """ 

54 

55 class Meta: 

56 model = OrganizationPaymentMethod 

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

58 fields = read_only_fields + ["organization", "name", "is_active", "sat_id"] 

59 

60 

61class PaymentAllocationSerializer(serializers.ModelSerializer): 

62 """ 

63 Serializer for Paymment Allocation on Appointment Charge 

64 """ 

65 

66 class Meta: 

67 model = PaymentAllocation 

68 read_only_fields = [ 

69 "random_slug", 

70 "created_at", 

71 ] 

72 fields = read_only_fields + ["payment", "appointment_charge", "amount", "is_invoiceable"] 

73 extra_kwargs = {"payment": {"required": False}} 

74 

75 def validate(self, attrs): 

76 amount = attrs.get("amount") 

77 appointment_charge = attrs.get("appointment_charge") 

78 

79 if amount > appointment_charge.total_price.amount: 

80 raise serializers.ValidationError({"amount": "El monto no puede ser mayor que el total del cargo"}) 

81 elif amount > appointment_charge.pending_amount.amount: 

82 raise serializers.ValidationError({"amount": "El monto no puede ser mayor que lo pendiente por pagar"}) 

83 

84 return attrs 

85 

86 

87class PaymentSerializer(serializers.ModelSerializer): 

88 """ 

89 Serializer for Payment by Patient 

90 """ 

91 

92 allocations = PaymentAllocationSerializer(many=True, required=False) 

93 patient = PatientSerializer(many=False, read_only=True) 

94 

95 class Meta: 

96 model = Payment 

97 read_only_fields = ["random_slug", "created_at", "created_by", "patient"] 

98 fields = read_only_fields + ["payment_method", "appointment", "date", "amount", "allocations", "is_invoiceable"] 

99 

100 

101 def create(self, validated_data): 

102 with transaction.atomic(): 

103 allocations = validated_data.pop("allocations", []) 

104 

105 payment = super().create(validated_data) 

106 

107 for allocation in allocations: 

108 allocation["payment"] = payment 

109 payment_allocation_serializer = PaymentAllocationSerializer(allocation) 

110 payment_allocation_serializer.create(allocation) 

111 

112 try: 

113 from app.facturapi import FacturapiOrganizationClient 

114 from apps.appointments.services import PatientCommunication 

115 from apps.practitioners.models import Practitioner 

116 

117 practitioners_pk = ( 

118 payment.allocations.order_by("appointment_charge__product__practitioner") 

119 .filter(appointment_charge__product__practitioner__invoice_configuration__isnull=False) 

120 .values_list("appointment_charge__product__practitioner", flat=True) 

121 .distinct() 

122 ) 

123 for practitioner_pk in practitioners_pk: 

124 practitioner = Practitioner.objects.get(pk=practitioner_pk) 

125 practitioner_invoice_configuration = getattr(practitioner, 'invoice_configuration', None) 

126 if practitioner_invoice_configuration: 

127 facturapi_client = FacturapiOrganizationClient( 

128 practitioner_invoice_configuration.facturapi_secret_key 

129 ) 

130 payment_allocations = payment.allocations.filter( 

131 appointment_charge__product__practitioner=practitioner, is_invoiceable=True 

132 ) 

133 items = [] 

134 for payment_allocation in payment_allocations: 

135 product_data = ( 

136 payment_allocation.appointment_charge.product.invoice_configuration.facturapi_data 

137 ) 

138 product_data["price"] = payment_allocation.invoiced_amount - payment_allocation.amount 

139 item = { 

140 "product": product_data, 

141 "quantity": payment_allocation.appointment_charge.quantity, 

142 } 

143 items.append(item) 

144 receipt = facturapi_client.Receipt.create(items=items, payment_form=payment.payment_method.sat_id) 

145 facturapi_client.Receipt.send_email(receipt.get("id"), payment.patient.email_set.first()) 

146 PatientCommunication(patient=payment.patient).send_invoices_link(receipt.get("self_invoice_url")) 

147 except Exception as e: 

148 capture_exception(e) 

149 

150 return payment 

151 

152 

153class PaymentExportSerializer(serializers.ModelSerializer): 

154 """ 

155 Serializer for PaymentExport 

156 """ 

157 

158 class Meta: 

159 model = PaymentExport 

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

161 fields = read_only_fields + ["organization", "practitioner", "from_date", "to_date"]