from django.db import models from .validators import json_email_array, json_not_empty_string_array, valid_frequency_format from django.utils import timezone from django.conf import settings from django.utils.timezone import timedelta as delta from dateutil.relativedelta import relativedelta as reldelta from pytz import timezone as tz import requests import logging logger = logging.getLogger('django') class ProgrammedReport(models.Model): REPORT_FORMATS = [ ("excel", "Excel"), ("csv", "CSV") ] name = models.CharField(max_length=100) user_id = models.CharField(max_length=2048) frequency = models.CharField(max_length=20, default="monthly", validators=[valid_frequency_format]) start_report_date = models.DateTimeField( default=timezone.now) due_date = models.DateTimeField(blank=True, null=True, default=None) # Valores que configuran al reporte: format = models.CharField( max_length=5, choices=REPORT_FORMATS) option = models.CharField(max_length=50, default="all") stations = models.JSONField(validators=[json_not_empty_string_array]) modules = models.JSONField(validators=[json_not_empty_string_array]) notified_emails = models.JSONField( validators=[json_not_empty_string_array, json_email_array]) # Calculamos el rango del reporte y lo guardamos en UTC en la base de datos. def save(self, *args, **kwargs): range = self.get_report_range() self.start_report_date = range[0].astimezone(tz('UTC')) self.due_date = range[1].astimezone(tz('UTC')) super().save(*args, **kwargs) def get_report_range(self): # Por defecto frequencia Diaria: start_date = self.start_report_date.astimezone(tz('America/Argentina/Cordoba')).replace(hour=0, minute=0, second=0, microsecond=0) end_date = self.start_report_date.astimezone(tz('America/Argentina/Cordoba')).replace(hour=23, minute=59, second=59, microsecond=0) if self.frequency == "weekly": start_date -= delta(days=start_date.weekday()) end_date += delta(days=(6 - end_date.weekday())) # Lunes de la siguiente semana elif self.frequency == "monthly": start_date = start_date.replace(day=1) end_date = (end_date.replace(day=1) + reldelta(months=1)).replace(day=1) - delta(days=1) elif self.frequency == "yearly": start_date = start_date.replace(day=1, month=1) end_date = (end_date.replace(day=1, month=1) + reldelta(years=1)) - delta(days=1) elif self.frequency != 'daily': return None return start_date, end_date # Metodo que envía la petición a Clima para enviar el reporte. def send_report(self): # Calculamos el formato en el que Clima requiere recibir los rangos. start_date = self.start_report_date.astimezone(tz('America/Argentina/Cordoba')).strftime("%d/%m/%Y %H:%M") end_date = self.due_date.astimezone(tz('America/Argentina/Cordoba')).strftime("%d/%m/%Y %H:%M") # Enviamos la request: response = requests.post(settings.CLIMA_URL + "/async_report_handler", { "id": self.id, "name": self.name, "user_id": self.user_id, "format": self.format, "stations": self.stations, "modules": self.modules, "option": self.option, "start_date": start_date, "end_date": end_date, "notified_emails": self.notified_emails }, headers={"AUTHORIZATION": settings.PROGRAMMED_REPORTS_SERVICE_AUTH_TOKEN}) if response.status_code != 200: logger.critical( "No se pudo enviar el reporte asincrono: %s\n Reason: %s", self, response.reason) # TODO! Seria ideal enviar un email al administrador para ver que paso. return False self.start_report_date = self.due_date + delta(seconds=1) # Pass to next cycle self.save() return True def send_report_now(self): # Calculamos el formato en el que Clima requiere recibir los rangos. start_date = self.start_report_date.astimezone(tz('America/Argentina/Cordoba')).strftime("%d/%m/%Y %H:%M") end_date = timezone.datetime.now().strftime("%d/%m/%Y %H:%M") # Enviamos la request: response = requests.post(settings.CLIMA_URL + "/async_report_handler", { "id": self.id, "name": self.name, "user_id": self.user_id, "format": self.format, "stations": self.stations, "modules": self.modules, "option": self.option, "start_date": start_date, "end_date": end_date, "notified_emails": self.notified_emails }, headers={"AUTHORIZATION": settings.PROGRAMMED_REPORTS_SERVICE_AUTH_TOKEN}) if response.status_code != 200: logger.critical( "No se pudo enviar el reporte asincrono: %s\n Reason: %s", self, response.reason) # TODO! Seria ideal enviar un email al administrador para ver que paso. return False return True