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
« 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
6from app.stripe.actions import Stripe
7from apps.practitioners.models import Practitioner
9from apps.patients.serializers import PatientSerializer
11from .models import OrganizationPaymentMethod, Payment, PaymentAllocation, PaymentExport
15class SessionSerializer(serializers.ModelSerializer):
16 """
17 Serializer for Session
18 """
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()
24 class Meta:
25 model = Session
26 read_only_fields = ["id", "subscription", "url"]
27 fields = read_only_fields + ["practitioner", "price", "success_url", "cancel_url"]
29 def validate_practitioner(self, practitioner):
30 if practitioner.is_paid:
31 raise serializers.ValidationError("Ya tiene suscripcion")
32 return practitioner
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")
40 stripe = Stripe()
41 session = stripe.create_checkout_session_for_subscription(practitioner, price, success_url, cancel_url)
43 return session
45 def get_url(self, instance):
46 stripe = Stripe()
47 return stripe.client.checkout.Session.retrieve(instance.id).url
50class OrganizationPaymentMethodSerializer(serializers.ModelSerializer):
51 """
52 Serializer for Payment Method on Oragnization used for Patient Payment
53 """
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"]
61class PaymentAllocationSerializer(serializers.ModelSerializer):
62 """
63 Serializer for Paymment Allocation on Appointment Charge
64 """
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}}
75 def validate(self, attrs):
76 amount = attrs.get("amount")
77 appointment_charge = attrs.get("appointment_charge")
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"})
84 return attrs
87class PaymentSerializer(serializers.ModelSerializer):
88 """
89 Serializer for Payment by Patient
90 """
92 allocations = PaymentAllocationSerializer(many=True, required=False)
93 patient = PatientSerializer(many=False, read_only=True)
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"]
101 def create(self, validated_data):
102 with transaction.atomic():
103 allocations = validated_data.pop("allocations", [])
105 payment = super().create(validated_data)
107 for allocation in allocations:
108 allocation["payment"] = payment
109 payment_allocation_serializer = PaymentAllocationSerializer(allocation)
110 payment_allocation_serializer.create(allocation)
112 try:
113 from app.facturapi import FacturapiOrganizationClient
114 from apps.appointments.services import PatientCommunication
115 from apps.practitioners.models import Practitioner
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)
150 return payment
153class PaymentExportSerializer(serializers.ModelSerializer):
154 """
155 Serializer for PaymentExport
156 """
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"]