service.py 5.21 KB
import json
import calendar
import pytz

from django.core.serializers.json import DjangoJSONEncoder
from datetime import datetime, timedelta, time

from .models import Evento, FechaEvento


class GenerarFechas:
    def __init__(self, evento: Evento, mes: int):
        self.fechas_generadas = {}
        self.evento = evento
        self.mes = mes

    def obtener_rango_del_mes(self):
        """Obtiene el rango de fechas para el mes específico."""
        year = datetime.now().year
        self.mes = int(self.mes)
        primer_dia, ultimo_dia = calendar.monthrange(year, self.mes)
        fecha_inicio_mes = datetime(year, self.mes, 1)
        fecha_fin_mes = datetime(year, self.mes, ultimo_dia)
        return fecha_inicio_mes, fecha_fin_mes

    def ajustar_fechas_a_rango_mes(self):
        """Ajusta las fechas del evento al rango del mes especificado."""
        zona_horaria = pytz.timezone('America/Argentina/Buenos_Aires')

        fecha_inicio_evento = self.combinar_fecha_hora(self.evento.fecha_inicio, self.evento.hora_inicio, zona_horaria)
        fecha_fin_evento = self.combinar_fecha_hora(self.evento.fecha_final, self.evento.hora_fin, zona_horaria)

        fecha_inicio_mes, fecha_fin_mes = self.obtener_rango_del_mes()
        fecha_inicio_evento = max(fecha_inicio_evento, zona_horaria.localize(fecha_inicio_mes))
        fecha_fin_evento = min(fecha_fin_evento, zona_horaria.localize(fecha_fin_mes))

        return fecha_inicio_evento, fecha_fin_evento

    @staticmethod
    def combinar_fecha_hora(fecha, hora, zona_horaria):
        """Combina la fecha y hora en un solo objeto datetime."""
        if fecha is None or hora is None:
            return None
        fecha_hora = datetime.combine(fecha, hora)
        return zona_horaria.localize(fecha_hora) if fecha_hora.tzinfo is None else fecha_hora

    def obtener_dias_del_evento(self):
        """Obtiene los días de la semana en los que se realiza el evento (en formato 1 a 7)."""
        dias_evento = []
        for fecha in self.evento.fechas.all():
            if fecha.duracion_evento is not None:  # Solo considerar fechas con duracion_evento definido
                dias_evento.append(int(fecha.duracion_evento))  # Convertir a entero y agregar a la lista
        return dias_evento

    def procesar_fechas_evento(self):
        """Genera las fechas del evento ajustadas al mes especificado."""
        fecha_inicio, fecha_fin = self.ajustar_fechas_a_rango_mes()
        dias_evento = self.obtener_dias_del_evento()
        fechas_null = self.evento.fechas.filter(dias__isnull=True)

        self.asignar_fechas_nulas(fechas_null, dias_evento, fecha_inicio)
        self.generar_fechas_para_dias_especificos(fecha_inicio, fecha_fin, dias_evento)

        return self.fechas_generadas

    def asignar_fechas_nulas(self, fechas_null, dias_evento, fecha_inicio):
        """Asigna fechas a las entradas que no tienen días especificados."""
        for fecha_obj in fechas_null:
            dia_semana = fecha_inicio.weekday() + 1  # Ajustar de 0-6 a 1-7
            if dia_semana in dias_evento:
                fecha_obj.dias = fecha_inicio.date()
                fecha_obj.save(update_fields=['dias'])
                self.fechas_generadas[fecha_inicio.strftime('%Y-%m-%d')] = fecha_obj.pk

    def generar_fechas_para_dias_especificos(self, fecha_inicio, fecha_fin, dias_evento):
        """Genera fechas adicionales dentro del rango si coinciden con los días seleccionados."""
        fecha_actual = fecha_inicio
        while fecha_actual <= fecha_fin:
            dia_semana = fecha_actual.weekday() + 1  # Ajustar de 0-6 a 1-7
            if dia_semana in dias_evento:
                self.agregar_fecha(fecha_actual, dia_semana)
            fecha_actual += timedelta(days=1)

    def agregar_fecha(self, fecha_actual, dia_semana):
        """Agrega una fecha al evento si no existe ya en el sistema."""
        if not FechaEvento.objects.filter(dias=fecha_actual, duracion_evento=str(dia_semana)).exists():
            nueva_fecha = FechaEvento.objects.create(dias=fecha_actual, duracion_evento=str(dia_semana))
            self.evento.fechas.add(nueva_fecha)
            self.fechas_generadas[fecha_actual.strftime('%Y-%m-%d')] = nueva_fecha.pk

    def obtener_datos_evento(self):
        """Devuelve los datos del evento en formato serializado."""
        return {
            'titulo': self.evento.titulo,
            'categoria': self.evento.categoria,
            'descripcion': self.evento.descripcion,
            'direccion': self.evento.direccion,
            'fecha_inicio': self.evento.fecha_inicio.isoformat() if self.evento.fecha_inicio else None,
            'hora_inicio': self.evento.hora_inicio.isoformat() if self.evento.hora_inicio else None,
            'fecha_final': self.evento.fecha_final.isoformat() if self.evento.fecha_final else None,
            'hora_fin': self.evento.hora_fin.isoformat() if self.evento.hora_fin else None,
            'url': self.evento.url,
            'imagen': self.evento.imagen.url if self.evento.imagen else None,
            'fechas': list(self.evento.fechas.values('id', 'duracion_evento', 'dias')),
            'organismo': list(self.evento.organismo.values('short_name')),
            'dependencia': list(self.evento.dependencia.values('short_name')),
        }