from django.db import models from django.utils.translation import gettext_lazy as _ from lib.models.base import MetaDataModel from apps.employee.models import Employee from jsonfield import JSONField import collections # Create your models here. class Schedule(MetaDataModel): """ A model that holds the schedule information. Here we store the form data and let the Peregrine cluster make the calculations. It will inherit the attributes :attr:`~lib.models.base.MetaDataModel.created_at` and :attr:`~lib.models.base.MetaDataModel.updated_at` from the Abstract model :class:`~lib.models.base.MetaDataModel` Attributes ---------- employee : Employee The employee that is the owner of this schedule. name : str The name of the schedule. Max length is 100 characters. email : str The email address where the results should be sent to. Max length is 100 characters. status : ScheduleStatus The status of the schedule. planning_source : JSON The complete schedule stored in JSON data object. """ class Meta: verbose_name = _('schedule') verbose_name_plural = _('schedules') class ScheduleStatus(models.TextChoices): """This is a sub class of Schedule which holds all the possible schedule statuses .. data:: DRAFT The schedule is just created but not finished. Schedules in this state can be updated later on. .. data:: NEW The schedule is just created and waiting to be picked up by the Peregrine scripts. .. data:: ACCEPTED The Peregrine scripts have accepted the new schedule job. And the input is valid. .. data:: PROCESSING The Peregrine job is submitted to the job queue and should be starting soon. .. data:: PROCESSED The Peregrine job is finished, and the results will be futher processed in order to create a new report with the outcome. .. data:: DONE The schedule rapport is created and uploaded to the database. The Peregrine process is done. .. data:: INVALID The entered data is invalid. Either directly by the posting of the form. Or when the Peregrine script could not read the input. .. data:: FAILURE Something when wrong on Peregrine. Look at the logging output of the Peregrine job """ DRAFT = 'draft', _('Draft') NEW = 'new', _('New') ACCEPTED = 'accepted', _('Accepted') PROCESSING = 'processing', _('Processing') PROCESSED = 'processed', _('Processed') DONE = 'done', _('Done') INVALID = 'invalid', _('Invalid') FAILURE = 'failure', _('Failure') employee = models.ForeignKey(Employee, verbose_name=Employee._meta.verbose_name, on_delete=models.CASCADE, help_text=_('Select the employee that is responsible for this schedule request')) name = models.CharField(_('Name'), max_length=100, help_text=_('Name of the schedule')) email = models.CharField(_('Email address'), max_length=100, help_text=_('Email address where the results will be sent to.')) status = models.CharField(_('Status'), max_length=10, choices=ScheduleStatus.choices, default=ScheduleStatus.NEW, help_text=_('The status of this schedule.'), db_index=True, ) planning_source = JSONField(_('Schedule input'), blank=True, null=True, load_kwargs={'object_pairs_hook': collections.OrderedDict}, help_text=_('The schedule input in JSON format based on the form data')) peregrine_result = JSONField(_('Peregrine JSON output'), blank=True, null=True, load_kwargs={'object_pairs_hook': collections.OrderedDict}, help_text=_('The results from the Peregrine job in JSON')) output_peregrine = models.BinaryField(_('Peregrine binary output'), blank=True, null=True, help_text=_('This is the output in binary format from the Peregrine cluster')) report_sent = models.DateTimeField(_('Report is send to user'), blank=True, null=True, help_text=_('The date and time when the report has sended to the user.')) peregrine_output_log = models.TextField(_('Peregrine logging'), blank=True, help_text=_('Here you can see the logging of the Peregrine job.')) @property def done(self): """ Checks if the processing of this schedule is done on the Peregrine cluster. This can be either with the status: 1. :attr:`~ScheduleStatus.DONE` 2. :attr:`~ScheduleStatus.INVALID` 3. :attr:`~ScheduleStatus.FAILURE` Returns: boolean -- True when status is one of the above value. """ return self.status in [self.ScheduleStatus.DONE,self.ScheduleStatus.INVALID,self.ScheduleStatus.FAILURE] def __str__(self): """str: Returns a readable name for the schedule. Format is [schedule_name] (employee_name).""" return '{} ({})'.format(self.name, self.employee)