Coverage for apps/appointments/views.py: 35%
208 statements
« prev ^ index » next coverage.py v6.4.4, created at 2024-05-21 11:15 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2024-05-21 11:15 -0600
1from django.db.models import Count, Sum
2from django.utils import timezone
3from rest_framework import status
4from rest_framework.decorators import action
5from rest_framework.mixins import CreateModelMixin as Create
6from rest_framework.mixins import DestroyModelMixin as Delete
7from rest_framework.mixins import ListModelMixin as List
8from rest_framework.mixins import RetrieveModelMixin as Detail
9from rest_framework.mixins import UpdateModelMixin as Update
10from rest_framework.response import Response
11from rest_framework.viewsets import GenericViewSet
12from rest_framework.validators import ValidationError
14from apps.catalogues.models import PaymentMethod
15from apps.organizations.models import Organization
16from apps.practitioners.models import Practitioner
17from apps.products.models import (
18 ConsultationProduct,
19 HospitalizationProduct,
20 ProcedureProduct,
21 SellableProduct,
22 SurgicalProduct,
23)
24from apps.users.mixins import AdminMixin, UserMixin
25from apps.payments.models import OrganizationPaymentMethod, PaymentAllocation
26from services.pusher import PusherClient
28from .models import AppointmentCharge, AppointmentType
29from .serializers import (
30 AppointmentChargeExportSerializer,
31 AppointmentChargeSerializer,
32 AppointmentDateCountSerializer,
33 AppointmentExportSerializer,
34 AppointmentPractitionerSerializer,
35 AppointmentSerializer,
36 AppointmentTypeSerializer,
37 AppointmentSummarySerializer,
38)
41class AdminAppointmentViewSet(AdminMixin, GenericViewSet, Create, List, Detail, Update, Delete):
42 """
43 Model ViewSet for Appointments
44 """
46 serializer_class = AppointmentSerializer
49class AdminAppointmentChargeViewSet(AdminMixin, GenericViewSet, Create, List, Detail, Update, Delete):
50 """
51 Model ViewSet for Appointment Charges
52 """
54 serializer_class = AppointmentChargeSerializer
57class UserAppointmentViewSet(UserMixin, GenericViewSet, Create, List, Detail, Update, Delete):
58 """
59 Model ViewSet for Appointments
60 """
62 serializer_class = AppointmentSerializer
63 filterset_fields = {
64 "practitioners__practitioner": ["exact"],
65 "organization": ["exact"],
66 "date": ["lte", "gte", "exact"],
67 }
69 def _push_notification(self, channel: str, event: str = "appointment-status-update", data: dict = {}):
70 pusher = PusherClient()
71 pusher.trigger(channel, event, data)
73 def perform_update(self, serializer):
74 appointment = serializer.save()
75 try:
76 self._push_notification(
77 appointment.organization.random_slug,
78 "appointment-update",
79 {
80 "user": getattr(self.request.user, "pk", None),
81 },
82 )
83 except Exception as e:
84 print(e)
85 return appointment
87 def perform_create(self, serializer):
88 appointment = serializer.save()
89 try:
90 self._push_notification(
91 appointment.organization.random_slug,
92 "appointment-creation",
93 {
94 "user": getattr(self.request.user, "pk", None),
95 },
96 )
97 except Exception as e:
98 print(e)
99 return appointment
101 def perform_destroy(self, instance):
102 appointment = instance
103 instance.delete()
104 try:
105 self._push_notification(
106 appointment.organization.random_slug,
107 "appointment-deletion",
108 {
109 "user": getattr(self.request.user, "pk", None),
110 },
111 )
112 except Exception as e:
113 print(e)
114 return appointment
116 @action(methods=["GET"], detail=False, url_path="daycount")
117 def day_count(self, request, *args, **kwargs):
118 self.serializer = AppointmentDateCountSerializer
119 queryset = super().get_queryset().order_by("date").values("date").annotate(count=Count("pk"))
120 queryset = self.filter_queryset(queryset)
121 page = self.paginate_queryset(queryset)
122 if page is not None:
123 serializer = self.serializer(page, many=True)
124 return self.get_paginated_response(serializer.data)
125 serializer = self.serializer(queryset, many=True)
126 return Response(serializer.data)
128 @action(methods=["GET"], detail=False)
129 def today(self, request, *args, **kwargs):
130 queryset = self.filter_queryset(self.get_queryset().filter(date=timezone.now().astimezone().date()))
131 page = self.paginate_queryset(queryset)
132 if page is not None:
133 serializer = self.get_serializer(page, many=True)
134 return self.get_paginated_response(serializer.data)
135 serializer = self.get_serializer(queryset, many=True)
136 return Response(serializer.data)
138 @action(methods=["PATCH"], detail=True)
139 def cancel(self, request, *args, **kwargs):
140 appointment = self.get_object()
141 appointment.status = AppointmentSerializer.Meta.model.StatusChoices.CANCELED
142 appointment.patient_canceled()
143 appointment.save()
144 self._push_notification(
145 appointment.organization.random_slug,
146 "appointment-deletion",
147 {
148 "user": getattr(self.request.user, "pk", None),
149 },
150 )
151 return Response(self.serializer_class(appointment).data)
153 @action(methods=["PATCH"], detail=True)
154 def confirm(self, request, *args, **kwargs):
155 appointment = self.get_object()
156 appointment.is_confirmed = True
157 appointment.patient_confirmed()
158 appointment.save()
159 self._push_notification(
160 appointment.organization.random_slug,
161 "appointment-deletion",
162 {
163 "user": getattr(self.request.user, "pk", None),
164 },
165 )
166 return Response(self.serializer_class(appointment).data)
168 @action(methods=["PATCH"], detail=True)
169 def arrival(self, request, *args, **kwargs):
170 # TODO: Whatsapp to practitioner
171 appointment = self.get_object()
172 appointment.arrival_timestamp = timezone.datetime.now()
173 appointment.patient_arrived()
174 appointment.save()
175 self._push_notification(
176 appointment.organization.random_slug,
177 "appointment-deletion",
178 {
179 "user": getattr(self.request.user, "pk", None),
180 },
181 )
182 return Response(self.serializer_class(appointment).data)
184 @action(methods=["PATCH"], detail=True)
185 def start(self, request, *args, **kwargs):
186 appointment = self.get_object()
187 appointment.start_timestamp = timezone.datetime.now()
188 appointment.patient_entered()
189 appointment.save()
190 self._push_notification(
191 appointment.organization.random_slug,
192 "appointment-deletion",
193 {
194 "user": getattr(self.request.user, "pk", None),
195 },
196 )
197 return Response(self.serializer_class(appointment).data)
199 @action(methods=["PATCH"], detail=True)
200 def end(self, request, *args, **kwargs):
201 appointment = self.get_object()
202 appointment.end_timestamp = timezone.datetime.now()
203 appointment.patient_exited()
204 appointment.save()
205 self._push_notification(
206 appointment.organization.random_slug,
207 "appointment-deletion",
208 {
209 "user": getattr(self.request.user, "pk", None),
210 },
211 )
212 return Response(self.serializer_class(appointment).data)
214 @action(methods=["PATCH"], detail=True)
215 def departure(self, request, *args, **kwargs):
216 # TODO: Whatsapp to practitioner and patient
217 appointment = self.get_object()
218 appointment.departure_timestamp = timezone.datetime.now()
219 appointment.save()
220 appointment.patient_departed()
221 appointment.save()
222 self._push_notification(
223 appointment.organization.random_slug,
224 "appointment-deletion",
225 {
226 "user": getattr(self.request.user, "pk", None),
227 },
228 )
229 return Response(self.serializer_class(appointment).data)
231 @action(methods=["GET"], detail=False)
232 def summary(self, request, serializer_class=AppointmentSummarySerializer, *args, **kwargs):
233 if getattr(self.request.user, "practitioner", None):
234 practitioner = self.request.user.practitioner
235 else:
236 try:
237 practitioner = Practitioner.objects.get(pk=request.query_params.get("practitioner"))
238 except Practitioner.DoesNotExist:
239 practitioner = None
241 serializer_data = request.query_params.dict()
242 serializer_data.update({"practitioner": practitioner.pk if practitioner else practitioner})
244 serializer = serializer_class(data=serializer_data)
245 serializer.is_valid(raise_exception=True)
246 from_date = serializer.validated_data.get("from_date")
247 to_date = serializer.validated_data.get("to_date")
249 products = practitioner.products.all()
250 payment_methods = PaymentMethod.objects.all()
252 products_mapping = {
253 "Consultas": products.instance_of(ConsultationProduct),
254 "Procedimientos": products.instance_of(ProcedureProduct),
255 "Productos": products.instance_of(SellableProduct),
256 "Cirugias": products.instance_of(SurgicalProduct),
257 "Hospitalizaciones": products.instance_of(HospitalizationProduct),
258 }
260 final_response_data = []
262 appointment_charges = AppointmentCharge.objects.filter(date__gte=from_date, date__lte=to_date).filter(
263 product__in=products.values_list("pk", flat=True)
264 )
266 for type_of, products in products_mapping.items():
267 appointment_charges_by_product = appointment_charges.filter(
268 product__in=products.values_list("pk", flat=True)
269 )
270 product_mapping = {
271 "type_of": type_of,
272 "total": appointment_charges_by_product.aggregate(total=Sum("price")).get("total") or 0,
273 "by_payment_method": [],
274 }
275 payment_allocations = PaymentAllocation.objects.filter(
276 appointment_charge__in=appointment_charges_by_product.values_list("pk", flat=True)
277 )
278 for payment_method in payment_methods:
279 payment_allocations_by_method = payment_allocations.filter(
280 payment__payment_method__sat_id=payment_method.sat_id
281 )
282 product_mapping["by_payment_method"].append(
283 {
284 "name": payment_method.name,
285 "amount": payment_allocations_by_method.aggregate(total=Sum("amount")).get("total") or 0,
286 }
287 )
288 product_mapping["pending_amount"] = product_mapping["total"] - (
289 payment_allocations.aggregate(total=Sum("amount")).get("total") or 0
290 )
291 product_mapping["products"] = []
292 for product in products:
293 appointment_product_detail = appointment_charges_by_product.filter(product=product)
294 amount = int(appointment_product_detail.aggregate(amount=Sum("quantity")).get("amount") or 0)
295 product_mapping["products"].append(
296 {
297 "name": product.name,
298 "total": (appointment_product_detail.aggregate(total=Sum("price")).get("total") or 0),
299 "quantity": amount,
300 }
301 )
302 final_response_data.append(product_mapping)
304 return Response(final_response_data)
306 def get_queryset(self):
307 return super().get_queryset().filter(organization__in=self.user.affiliations.values_list("organization"))
309 def destroy(self, request, *args, **kwargs):
310 user = request.user
311 appointment = self.get_object()
312 owner_practitioners = getattr(user, "practitioner", None) in appointment.owner_practitioners()
313 ended_appointment = appointment.status in [
314 appointment.StatusChoices.FINISHED,
315 appointment.StatusChoices.OVERDUE,
316 appointment.StatusChoices.CLOSED,
317 ]
318 if not owner_practitioners and ended_appointment:
319 content = {"error": "you dont have permissions to delete this appointment"}
320 return Response(content, status=status.HTTP_403_FORBIDDEN)
321 return super().destroy(request, *args, **kwargs)
324class UserAppointmentPractitionerViewSet(UserMixin, GenericViewSet, Create, List, Update, Delete):
325 """
326 Model ViewSet for Appointment Practitioner
327 """
329 serializer_class = AppointmentPractitionerSerializer
332class UserAppointmentChargeViewSet(UserMixin, GenericViewSet, Create, List, Detail, Update, Delete):
333 """
334 Model ViewSet for Appointment Charges
335 """
337 serializer_class = AppointmentChargeSerializer
338 filterset_fields = {
339 "appointment": ["exact"],
340 "appointment__patient": ["exact"],
341 # "pending_amount": ["exact", "lte", "gte", "gt"],
342 }
344 def create(self, request, *args, **kwargs):
345 request.data["created_by"] = request.user.pk
346 return super().create(request, args, kwargs)
348 def get_queryset(self):
349 return (
350 super()
351 .get_queryset()
352 .filter(appointment__organization__in=self.user.affiliations.values_list("organization"))
353 )
355 @action(methods=["GET"], detail=False)
356 def summary(self, request, *args, **kwargs):
357 date = request.GET.get("date", timezone.now().date())
358 qs = self.get_queryset().filter(appointment__date=date)
361class UserAppointmentTypeViewSet(UserMixin, GenericViewSet, Create, List, Update):
362 """
363 Appointment Type ViewSet for User
364 """
366 serializer_class = AppointmentTypeSerializer
367 filterset_fields = {
368 "practitioner": ["exact"],
369 }
371 def get_queryset(self):
372 if hasattr(self.user, "practitioner"):
373 return super().get_queryset().filter(practitioner=self.user.practitioner, is_active=True)
375 # TODO: Refactor this
376 b = Organization.objects.filter(affiliation__user=self.user)
377 print(b)
378 objs = AppointmentType.objects.none()
379 for org in b:
380 for aff in org.affiliation_set.all():
381 if hasattr(aff.user, "practitioner"):
382 apptyp = AppointmentType.objects.filter(practitioner=aff.user.practitioner, is_active=True)
383 objs = objs | apptyp
384 return objs
387class UserAppointmentExportViewSet(UserMixin, GenericViewSet, Create):
388 """
389 ViewSet for AppointmentExport
390 """
392 serializer_class = AppointmentExportSerializer
394 def create(self, request, *args, **kwargs):
395 if hasattr(self.user, "practitioner") and getattr(request.data, "practitioner", False):
396 request.data["practitioner"] = self.user.practitioner.pk
397 return super().create(request, args, kwargs)
400class UserAppointmentChargeExportViewSet(UserMixin, GenericViewSet, Create):
401 """
402 ViewSet for AppointmentChargeExport
403 """
405 serializer_class = AppointmentChargeExportSerializer
407 def create(self, request, *args, **kwargs):
408 if hasattr(self.user, "practitioner") and getattr(request.data, "practitioner", False):
409 request.data["practitioner"] = self.user.practitioner.pk
410 return super().create(request, args, kwargs)