|
@@ -1,12 +1,114 @@
|
|
|
from django.db import models
|
|
from django.db import models
|
|
|
-from .validators import json_email_array, json_not_empty_string_array
|
|
|
|
|
|
|
+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 Preport(models.Model):
|
|
|
|
|
|
|
+class ProgrammedReport(models.Model):
|
|
|
|
|
+ REPORT_FORMATS = [
|
|
|
|
|
+ ("excel", "Excel"),
|
|
|
|
|
+ ("csv", "CSV")
|
|
|
|
|
+ ]
|
|
|
|
|
+
|
|
|
|
|
+ name = models.CharField(max_length=100)
|
|
|
user_id = models.CharField(max_length=2048)
|
|
user_id = models.CharField(max_length=2048)
|
|
|
- report_type = models.CharField(max_length=50)
|
|
|
|
|
- modules = models.JSONField(
|
|
|
|
|
- validators=[json_not_empty_string_array])
|
|
|
|
|
|
|
+ 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(
|
|
notified_emails = models.JSONField(
|
|
|
validators=[json_not_empty_string_array, json_email_array])
|
|
validators=[json_not_empty_string_array, json_email_array])
|
|
|
- last_report_date = models.DateField(blank=True, null=True, default=None)
|
|
|
|
|
|
|
+
|
|
|
|
|
+ # 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
|