示例#1
0
class Acknowledgement(models.Model):
    burn = models.ForeignKey('PrescribedBurn',
                             related_name='acknowledgements',
                             on_delete=models.PROTECT)
    user = models.ForeignKey(User,
                             help_text="User",
                             null=True,
                             blank=True,
                             on_delete=models.PROTECT)
    acknow_type = models.CharField(max_length=64, null=True, blank=True)
    acknow_date = models.DateTimeField(auto_now_add=True,
                                       null=True,
                                       blank=True)

    fmt = "%d/%m/%Y %H:%M"

    @property
    def record(self):
        username = '******'.format(self.user.first_name[0], self.user.last_name)
        return "{} {}".format(
            username,
            self.acknow_date.astimezone(tz.tzlocal()).strftime(self.fmt))

    def remove(self):
        self.delete()

    def __str__(self):
        return "{} - {} - {}".format(self.burn, self.acknow_type, self.record)
示例#2
0
class Token(models.Model):
    link = models.ForeignKey(ApplicationLink)
    user = models.ForeignKey(settings.AUTH_USER_MODEL,
                             related_name="%(app_label)s_%(class)s_user",
                             help_text="User token authenticates as")
    url = models.TextField(help_text="Suburl this token is restricted to, "
                           "relative e.g. (/my/single/service/entrypoint)",
                           default="/")
    secret = models.CharField(max_length=320,
                              help_text="Token Secret",
                              unique=True)
    modified = models.DateTimeField(default=timezone.now, editable=False)
    timeout = models.IntegerField(default=600,
                                  help_text="Timeout token in "
                                  "seconds, 0 means never times out")

    class Meta:
        app_label = 'swingers'

    def save(self, *args, **kwargs):
        try:
            revision.unregister(self.__class__)
        except:
            pass
        super(Token, self).save(*args, **kwargs)

    def natural_key(self):
        return (self.secret, )

    def get_by_natural_key(self, secret):
        return self.get(secret=secret)

    def __str__(self):
        return "{0} - {1}:{2}@{3}".format(self.pk, self.user, self.secret,
                                          self.link.client_name)[:320]
示例#3
0
class DocumentAbstract(Audit, ActiveModel):
    '''
    Generic class for supporting documents.
    '''
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')
    uploaded_file = models.FileField(
        # max_length is maximum full path and filename length:
        max_length=255,
        upload_to=content_filename)
    description = models.TextField(
        blank=True,
        null=True,
        help_text='Name and/or description of the supporting document.')

    class Meta:
        abstract = True

    def __unicode__(self):
        return unicode(self.pk)

    @property
    def uploaded_file_name(self):
        """
        Return the file name of the uploaded file, minus the server file path.
        """
        try:
            return self.uploaded_file.name.rsplit('/', 1)[-1]
        except:
            # If the file has been deleted/is missing, return a warning.
            return '<missing_file>'

    @property
    def uploaded_file_ext(self):
        '''
        Return the file extension of the uploaded file.
        '''
        try:
            ext = os.path.splitext(self.uploaded_file.name)[1]
            return ext.replace('.', '').upper()
        except:
            # If the file has been deleted/is missing, return an empty string.
            return ''

    @property
    def filesize_str(self):
        '''
        Return the filesize as a nicely human-readable string.
        '''
        try:
            num = self.uploaded_file.size
            for x in ['bytes', 'KB', 'MB', 'GB']:
                if num < 1024.0:
                    return '%3.1f%s' % (num, x)
                num /= 1024.0
        except:
            # If the file has been deleted/is missing, return an empty string.
            return ''
示例#4
0
class OperationalOverview(Audit):
    prescription = models.ForeignKey(Prescription, on_delete=models.PROTECT)
    overview = models.TextField(blank=True, null=True)

    def __str__(self):
        return self.overview

    class Meta:
        get_latest_by = 'id'
示例#5
0
文件: models.py 项目: ropable/pbs
class DocumentTag(models.Model):
    name = models.CharField(verbose_name="Document Tag", max_length=200)
    category = models.ForeignKey(DocumentCategory, on_delete=models.PROTECT)
    objects = CategoryManager()

    class Meta:
        ordering = ['name']

    def __str__(self):
        return self.name
示例#6
0
class BurnState(models.Model):
    prescription = models.ForeignKey(Prescription,
                                     related_name='burnstate',
                                     on_delete=models.PROTECT)
    user = models.ForeignKey(User, help_text="User", on_delete=models.PROTECT)
    review_type = models.CharField(max_length=64)
    review_date = models.DateTimeField(auto_now_add=True)

    fmt = "%d/%m/%Y %H:%M:%S"

    @property
    def record(self):
        username = '******'.format(self.user.first_name[0], self.user.last_name)
        return "{} {}".format(
            username,
            self.review_date.astimezone(tz.tzlocal()).strftime(self.fmt))

    def __str__(self):
        return "{} - {} - {}".format(self.prescription, self.review_type,
                                     self.record)
示例#7
0
文件: models.py 项目: ropable/pbs
class ExclusionArea(Audit):
    prescription = models.ForeignKey(
        Prescription, help_text="Prescription this exclusion area belongs to.", on_delete=models.PROTECT)
    description = models.TextField()
    location = models.TextField()
    detail = models.TextField(verbose_name="How will fire be excluded?")

    _required_fields = ('location', 'description',
                        'detail')

    def __str__(self):
        return "{0} - {1}".format(self.location, self.description)
示例#8
0
文件: models.py 项目: ropable/pbs
class ProposedAction(Audit):
    prescription = models.ForeignKey(Prescription, on_delete=models.PROTECT)
    observations = models.TextField(blank=True,
                                    verbose_name='Observations Identified')
    action = models.TextField(blank=True, verbose_name='Proposed Action')

    _required_fields = ('observations', 'action')

    def __str__(self):
        return self.action

    class Meta:
        verbose_name = 'Lesson Learned'
        verbose_name_plural = "Lessons Learned"
示例#9
0
文件: models.py 项目: ropable/pbs
class PostBurnChecklist(Audit):
    prescription = models.ForeignKey(Prescription,
                                     blank=True,
                                     null=True,
                                     on_delete=models.PROTECT)
    action = models.CharField(max_length=320)
    relevant = models.BooleanField(default=False)
    completed_on = models.DateField(default=timezone.now,
                                    blank=True,
                                    null=True)
    completed_by = models.TextField(verbose_name="Action completed by (name)",
                                    blank=True,
                                    null=True)

    _required_fields = ('completed_on', 'completed_by')

    def __str__(self):
        return self.action

    def clean_completed_on(self):
        if self.completed_on is not None:
            # The following line was causing validation failure before 0800.
            # Jira ref: PBS-1454
            #if self.completed_on > timezone.now().date():
            if self.completed_on > datetime.now().date():
                raise ValidationError("This action could not be completed "
                                      "in the future.")
            if (self.prescription.approval_status_modified is None
                    or self.completed_on <
                    self.prescription.approval_status_modified.date()):
                raise ValidationError("This action could not be completed "
                                      "before its prescription was approved.")

    def clean(self, *args, **kwargs):
        super(PostBurnChecklist, self).clean(*args, **kwargs)

        if self.completed_on is not None and not self.completed_by:
            raise ValidationError("Please specify who completed this action.")

        if self.completed_by and self.completed_on is None:
            raise ValidationError("Please specify when was this action "
                                  "completed.")

    class Meta:
        ordering = ["pk"]
        verbose_name = "post burn checklist item"
        verbose_name_plural = "post burn checklist"
示例#10
0
文件: models.py 项目: ropable/pbs
class Way(Audit):
    prescription = models.ForeignKey(
        Prescription, help_text="Prescription this belongs to.", on_delete=models.PROTECT)
    name = models.CharField(max_length=300)
    signs_installed = models.DateField(
        verbose_name="Signs Installed", null=True, blank=True)
    signs_removed = models.DateField(
        verbose_name="Signs Removed", null=True, blank=True)

    def __str__(self):
        return self.name

    def clean_signs_removed(self):
        if ((self.signs_removed and self.signs_installed and
             self.signs_removed < self.signs_installed)):
            raise ValidationError('Signs cannot be removed earlier than the '
                                  'install date.')
示例#11
0
文件: models.py 项目: ropable/pbs
class SignInspection(Audit):
    way = models.ForeignKey(
        Way, verbose_name="Road/Track/Trail Name", on_delete=models.PROTECT)
    inspected = models.DateTimeField(
        default=timezone.now, verbose_name="Date Inspected")
    comments = models.TextField()
    inspector = models.TextField(verbose_name="Inspecting Officer")

    def __str__(self):
        return "%s (%s)" % (self.way.name, date(self.inspected))

    @property
    def prescription(self):
        return self.way.prescription

    class Meta:
        ordering = ['id']
        verbose_name = "Sign Inspection"
        verbose_name_plural = "Sign Inspections"
示例#12
0
文件: models.py 项目: ropable/pbs
class RoadSegment(Way):
    road_type = models.TextField(
        verbose_name="Road Type",
        blank=True)
    traffic_considerations = models.TextField(
        blank=True, verbose_name="Special Traffic Considerations")
    traffic_diagram = models.ForeignKey(
        TrafficControlDiagram, null=True, blank=True,
        verbose_name="Select Traffic Control Diagram", on_delete=models.PROTECT)

    _required_fields = ('name', 'road_type',)

    def __str__(self):
        return self.name

    class Meta:
        ordering = ['id']
        verbose_name = "Road"
        verbose_name_plural = "Roads"
示例#13
0
    def test_imports(self):
        from swingers import models

        # check all these are exposed via models.*
        models.Model
        models.ForeignKey(ActiveDuck)
        models.Manager()
        models.ActiveModel
        models.ActiveModelManager()
        models.Audit

        self.assertEqual(models.GIS_ENABLED,
                         getattr(settings, 'GIS_ENABLED', False))

        if models.GIS_ENABLED:
            self.assertTrue(issubclass(models.Manager, GeoManager))
            self.assertTrue(issubclass(models.ActiveModel,
                                       models.base.ActiveGeoModel))
            self.assertTrue(issubclass(models.ActiveModelManager,
                                       models.managers.ActiveGeoModelManager))
        else:
            self.assertTrue(issubclass(models.Manager, Manager))
            self.assertFalse(issubclass(models.ActiveModel,
                                        models.base.ActiveGeoModel))
            self.assertFalse(issubclass(models.ActiveModelManager,
                                        models.managers.ActiveGeoModelManager))

        # check the GEO stuff validates
        models.managers.ActiveGeoModelManager()
        models.managers.ActiveGeoQuerySet(ActiveDuck)
        models.base.ActiveGeoModel

        # check the normal stuff validates
        models.managers.ActiveModelManager()
        models.managers.ActiveQuerySet(ActiveDuck)
        models.base.ActiveModel
示例#14
0
文件: models.py 项目: ropable/pbs
class AreaAchievement(Audit):
    prescription = models.ForeignKey(Prescription, on_delete=models.PROTECT)
    #Jira issue PBS-1407
    ignition = models.DateField(verbose_name="Ignition Date", )
    # default=lambda: timezone.now().date())
    ignition_types = models.ManyToManyField(IgnitionType)
    area_treated = models.DecimalField(
        verbose_name="Area where treatment is complete (ha)",
        validators=[MinValueValidator(0)],
        default=0,
        decimal_places=1,
        max_digits=12)
    area_estimate = models.DecimalField(verbose_name="Area treated today (ha)",
                                        validators=[MinValueValidator(0)],
                                        default=0,
                                        decimal_places=1,
                                        max_digits=12)
    edging_length = models.DecimalField(
        verbose_name="Length of Successful Edging (kms)",
        validators=[MinValueValidator(0)],
        default=0,
        decimal_places=1,
        max_digits=12)
    edging_depth_estimate = models.DecimalField(
        verbose_name="Estimated Depth of Edging (m)",
        validators=[MinValueValidator(0)],
        default=0,
        decimal_places=1,
        max_digits=12)
    dpaw_fire_no = models.CharField(verbose_name="DPaW Fire Number",
                                    max_length=64,
                                    blank=True)
    dfes_fire_no = models.CharField(verbose_name="DFES Fire Number",
                                    max_length=64,
                                    blank=True)
    date_escaped = models.DateField(verbose_name="Date of Escape",
                                    null=True,
                                    blank=True)

    _required_fields = ('ignition', 'ignition_types', 'area_treated',
                        'area_estimate')

    class Meta:
        ordering = ['-ignition']
        get_latest_by = 'ignition'
        verbose_name = "Day of Burn Achievement"
        verbose_name_plural = "Day of Burn Achievements"

    def __str__(self):
        return "%s %d ha %d kms" % (self.ignition, self.area_estimate,
                                    self.edging_length)

    def clean_ignition(self):
        if self.ignition and self.ignition > timezone.now().date():
            raise ValidationError("Ignition date cannot be in the future.")

    def clean_date_escaped(self):
        if self.date_escaped:
            if self.date_escaped > timezone.now().date():
                raise ValidationError("Date of escape cannot be in the "
                                      "future.")
            if not self.dpaw_fire_no and not self.dfes_fire_no:
                raise ValidationError("If there is a date of escape, there "
                                      "must also be a DPaW or DFES fire no.")

    def save(self, **kwargs):
        super(AreaAchievement, self).save(**kwargs)
        self.prescription.save()

    def delete(self, **kwargs):
        super(AreaAchievement, self).delete(**kwargs)
        obj = self.prescription
        if obj.areaachievement_set.all().count() == 0:
            obj.ignition_completed_date = None
            obj.save()
示例#15
0
文件: models.py 项目: ropable/pbs
class Document(Audit):
    prescription = models.ForeignKey(
        Prescription, null=True,
        help_text="Prescription that this document belongs to", on_delete=models.PROTECT)
    category = models.ForeignKey(DocumentCategory, related_name="documents", on_delete=models.PROTECT)
    tag = ChainedForeignKey(
        DocumentTag, chained_field="category", chained_model_field="category",
        show_all=False, auto_choose=True, verbose_name="Descriptor", on_delete=models.PROTECT)
    custom_tag = models.CharField(
        max_length=64, blank=True, verbose_name="Custom Descriptor")
    document = ContentTypeRestrictedFileField(
        upload_to=content_file_name, max_length=200,
        content_types=['application/pdf', 'image/tiff', 'image/tif',
                       'image/jpeg', 'image/jpg', 'image/gif', 'image/png',
                       'application/zip', 'application/x-zip-compressed'],
        help_text='Acceptable file types: pdf, tiff, jpg, gif, png, zip')

    document_created = models.DateTimeField(
        verbose_name="Date Document Created", default=timezone.now, editable=True, null=True, blank=True)

    document_archived = models.BooleanField(default=False, verbose_name="Archived Document")

    objects = TagManager()

    def save(self, *args, **kwargs):
        super(Document, self).save(*args, **kwargs)
        # confirm that file is written to filesystem, if not remove the record
        if not self.exists:
            fname = self.document.name
            Document.objects.get(id=self.id).delete()
            raise Exception('ERROR: File not created on filesystem {}'.format(fname))
        return

    @property
    def descriptor(self):
        if self.custom_tag:
            return "Other ({0})".format(self.custom_tag)
        else:
            return self.tag.name

    @property
    def dimensions(self):
        return get_dimensions(self.document.path)

    @property
    def filename(self):
        try:
            return os.path.basename(self.document.path)
        except:
            return None

    @property
    def exists(self):
        """
        Check if file exists on the file system
        """
        try:
            return os.path.exists(self.document.file.name)
        except:
            return False


    @property
    def is_zipped(self):
        return self.filename.endswith('.zip')

    class Meta:
        ordering = ['tag', 'document']
        permissions = (
            ("archive_document", "Can archive documents")
        )

    def __str__(self):
        return "{0} - {1}".format(self.prescription, self.document.name)
示例#16
0
class LightingSequence(Audit):
    prescription = models.ForeignKey(
        Prescription,
        help_text="Prescription this lighting sequence belongs to.",
        on_delete=models.PROTECT)
    seqno = models.PositiveSmallIntegerField(
        verbose_name="Lighting Sequence Number",
        choices=Prescription.INT_CHOICES)
    cellname = models.TextField(verbose_name="Cell Name")
    strategies = models.TextField(
        help_text="Textual description of strategies for this sequence")
    wind_min = models.PositiveIntegerField(
        verbose_name="Min Wind Speed (km/h)",
        validators=[MaxValueValidator(200)],
        blank=True)
    wind_max = models.PositiveIntegerField(
        verbose_name="Max Wind Speed (km/h)",
        validators=[MinValueValidator(0),
                    MaxValueValidator(200)],
        blank=True)
    wind_dir = models.TextField(verbose_name="Wind Direction")
    fuel_description = models.TextField(
        help_text="Textual description of the fuel for this sequence")
    fuel_age = models.PositiveSmallIntegerField(verbose_name="Fuel Age",
                                                help_text="Fuel Age in years",
                                                null=True,
                                                blank=True)
    fuel_age_unknown = models.BooleanField(verbose_name="Fuel Age Unknown?",
                                           default=False)
    ignition_types = models.ManyToManyField(
        IgnitionType, verbose_name="Planned Core Ignition Type")
    ffdi_min = models.PositiveIntegerField(verbose_name="FFDI Min", blank=True)
    ffdi_max = models.PositiveIntegerField(verbose_name="FFDI Max", blank=True)
    gfdi_min = models.PositiveIntegerField(verbose_name="GFDI Min", blank=True)
    gfdi_max = models.PositiveIntegerField(verbose_name="GFDI Max", blank=True)
    grassland_curing_min = models.PositiveIntegerField(
        verbose_name="Grassland Curing Min", blank=True)
    grassland_curing_max = models.PositiveIntegerField(
        verbose_name="Grassland Curing Max", blank=True)
    ros_min = models.PositiveIntegerField(verbose_name="ROS Min (m/h)",
                                          blank=True)
    ros_max = models.PositiveIntegerField(verbose_name="ROS Max (m/h)",
                                          blank=True)
    resources = models.TextField(verbose_name="Specialist Resources",
                                 blank=True)

    _required_fields = ('seqno', 'cellname', 'strategies', 'fuel_description',
                        'fuel_age', 'fuel_age_unknown', 'ignition_types',
                        'ffdi_min', 'ffdi_max', 'ros_min', 'ros_max',
                        'wind_min', 'wind_max', 'wind_dir')

    class Meta:
        verbose_name = "Lighting Sequence"
        verbose_name_plural = "Lighting Sequences"
        ordering = ['id']

    def wind_speed(self):
        return field_range(self.wind_min, self.wind_max)

    wind_speed.short_description = mark_safe(
        '<abbr title="Wind Speed">Wind Speed</abbr> Range')

    def ffdi(self):
        return field_range(self.ffdi_min, self.ffdi_max)

    ffdi.short_description = mark_safe(
        '<abbr title="Forecast Fire Danger Index">FFDI</abbr> Range')

    def gfdi(self):
        return field_range(self.gfdi_min, self.gfdi_max)

    gfdi.short_description = mark_safe(
        '<abbr title="Grassland Fire Danger Index">FFDI</abbr> Range')
    gfdi.admin_order_field = "gfdi_max"

    def grassland_curing(self):
        return field_range(self.grassland_curing_min,
                           self.grassland_curing_max)

    grassland_curing.short_description = mark_safe(
        '<abbr title="Grassland Curing Percent</abbr> Range')
    grassland_curing.admin_order_field = "grassland_curing_max"

    def ros(self):
        return field_range(self.ros_min, self.ros_max)

    ros.short_description = mark_safe(
        '<abbr title="Rate of Spread">ROS</abbr> Range')

    def clean_fuel_age(self):
        if self.fuel_age_unknown and self.fuel_age:
            raise ValidationError("You must either enter a fuel age or tick "
                                  "Fuel Age Unknown.")
        if not (self.fuel_age_unknown or self.fuel_age):
            raise ValidationError("You must enter a fuel age or tick Fuel Age "
                                  "Unknown.")

    def clean_ffdi_min(self):
        if self.ffdi_min is None:
            self.ffdi_min = 0

    def clean_ffdi_max(self):
        if self.ffdi_max is None:
            self.ffdi_max = 0

    def clean_gfdi_min(self):
        if self.gfdi_min is None:
            self.gfdi_min = 0

    def clean_gfdi_max(self):
        if self.gfdi_max is None:
            self.gfdi_max = 0

    def clean_grassland_curing_min(self):
        if self.grassland_curing_min is None:
            self.grassland_curing_min = 0

    def clean_grassland_curing_max(self):
        if self.grassland_curing_max is None:
            self.grassland_curing_max = 0

    def clean_ros_min(self):
        if self.ros_min is None:
            self.ros_min = 0

    def clean_ros_max(self):
        if self.ros_max is None:
            self.ros_max = 0

    def clean_wind_min(self):
        if self.wind_min is None:
            self.wind_min = 0

    def clean_wind_max(self):
        if self.wind_max is None:
            self.wind_max = 0

    def __str__(self):
        return "{0}. {1}".format(self.seqno, self.cellname)
示例#17
0
class EdgingPlan(Audit):
    prescription = models.ForeignKey(
        Prescription,
        help_text="Prescription this edging plan belongs to.",
        on_delete=models.PROTECT)
    location = models.TextField(
        verbose_name="Edge Location",
        blank=True,
        null=True,
        help_text="Textual description of edge & its location")
    desirable_season = models.PositiveSmallIntegerField(
        verbose_name="Desirable Season",
        max_length=64,
        choices=Season.SEASON_CHOICES,
        blank=True,
        null=True)
    strategies = models.TextField(
        help_text="Textual description of strategies for this plan",
        blank=True,
        null=True)
    # NOTE: the fuel_type field will be deprecated in favour of a reference to
    # the VegetationType model in the prescription app.

    fuel_type = models.ForeignKey(FuelType,
                                  verbose_name="Fuel Type",
                                  blank=True,
                                  null=True,
                                  on_delete=models.PROTECT)
    ffdi_min = models.PositiveIntegerField(verbose_name="Min FFDI",
                                           blank=True,
                                           null=True)
    ffdi_max = models.PositiveIntegerField(verbose_name="Max FFDI",
                                           blank=True,
                                           null=True)
    gfdi_min = models.PositiveIntegerField(verbose_name="Min GFDI",
                                           blank=True,
                                           null=True)
    gfdi_max = models.PositiveIntegerField(verbose_name="Max GFDI",
                                           blank=True,
                                           null=True)
    sdi = models.TextField(verbose_name="SDI", blank=True, null=True)
    wind_min = models.PositiveIntegerField(
        verbose_name="Min Wind Speed (km/h)", blank=True, null=True)
    wind_max = models.PositiveIntegerField(
        verbose_name="Max Wind speed (km/h)", blank=True, null=True)
    wind_dir = models.TextField(verbose_name="Wind Direction",
                                blank=True,
                                null=True)
    ros_min = models.PositiveIntegerField(verbose_name="Min ROS (m/h)",
                                          blank=True,
                                          null=True)
    ros_max = models.PositiveIntegerField(verbose_name="Max ROS (m/h)",
                                          blank=True,
                                          null=True)
    grassland_curing_min = models.PositiveIntegerField(
        verbose_name="Grassland Curing % Min", blank=True, null=True)
    grassland_curing_max = models.PositiveIntegerField(
        verbose_name="Grassland Curing % Max", blank=True, null=True)

    def ffdi(self):
        return field_range(self.ffdi_min, self.ffdi_max)

    ffdi.short_description = mark_safe(
        '<abbr title="Forecast Fire Danger Index">FFDI</abbr> Range')
    ffdi.admin_order_field = 'ffdi_min'

    def gfdi(self):
        return field_range(self.gfdi_min, self.gfdi_max)

    gfdi.short_description = mark_safe(
        '<abbr title="Grassland Fire Danger Index">FFDI</abbr> Range')
    gfdi.admin_order_field = "gfdi_max"

    def wind(self):
        return "%d-%d" % (self.wind_min, self.wind_max)

    wind.short_description = "Wind Speed Range (km/h)"

    def grassland_curing(self):
        return field_range(self.grassland_curing_min,
                           self.grassland_curing_max)

    grassland_curing.short_description = mark_safe(
        '<abbr title="Grassland Curing Percent</abbr> Range')
    grassland_curing.admin_order_field = "grassland_curing_max"

    def ros(self):
        return field_range(self.ros_min, self.ros_max)

    ros.short_description = mark_safe(
        '<abbr title="Rate of Spread">ROS</abbr> Range')

    def clean_sdi(self):
        if self.sdi == '':
            self.sdi = "N/A"

    def __str__(self):
        return self.location

    class Meta:
        verbose_name = "Edging Plan"
        verbose_name_plural = "Edging Plans"
        ordering = ['created']
示例#18
0
class PrescribedBurn(Audit):
    BURN_ACTIVE = 1
    BURN_INACTIVE = 2
    BURN_MONITORED = 3
    BURN_CHOICES = (
        (BURN_ACTIVE, 'Yes'),
        (BURN_INACTIVE, 'No'),
        (BURN_MONITORED, 'Monitored'),
    )

    IGNITION_STATUS_REQUIRED = 1
    IGNITION_STATUS_COMPLETED = 2
    IGNITION_STATUS_CHOICES = (
        (IGNITION_STATUS_REQUIRED, 'Further ignitions required'),
        (IGNITION_STATUS_COMPLETED, 'Ignition now complete'),
    )

    APPROVAL_DRAFT = 'DRAFT'
    APPROVAL_SUBMITTED = 'USER'
    APPROVAL_ENDORSED = 'SRM'
    APPROVAL_APPROVED = 'SDO'
    APPROVAL_CHOICES = (
        (APPROVAL_DRAFT, 'Draft'),
        (APPROVAL_SUBMITTED, 'District Submitted'),
        (APPROVAL_ENDORSED, 'Region Endorsed'),
        (APPROVAL_APPROVED, 'State Approved'),
    )

    FORM_268A = 1
    FORM_268B = 2
    FORM_NAME_CHOICES = (
        (FORM_268A, 'Form 268a'),
        (FORM_268B, 'Form 268b'),
    )
    '''
    BUSHFIRE_DISTRICT_ALIASES can be used to override the District's original code from the model. Usage e.g.:
    BUSHFIRE_DISTRICT_ALIASES = {
        'PHS' : 'PH',
        'SWC' : 'SC',
    }
    '''
    BUSHFIRE_DISTRICT_ALIASES = {}

    fmt = "%Y-%m-%d %H:%M"

    prescription = models.ForeignKey(Prescription,
                                     verbose_name="Burn ID",
                                     related_name='prescribed_burn',
                                     null=True,
                                     blank=True,
                                     on_delete=models.PROTECT)
    #    prescription = ChainedForeignKey(
    #        Prescription, chained_field="region", chained_model_field="region",
    #        show_all=False, auto_choose=True, blank=True, null=True)

    # Required for Fire records
    fire_id = models.CharField(verbose_name="Fire Number",
                               max_length=15,
                               null=True,
                               blank=True)
    fire_name = models.TextField(verbose_name="Name", null=True, blank=True)
    region = models.PositiveSmallIntegerField(choices=[
        (r.id, r.name) for r in Region.objects.all()
    ],
                                              null=True,
                                              blank=True)
    district = ChainedForeignKey(District,
                                 chained_field="region",
                                 chained_model_field="region",
                                 show_all=False,
                                 auto_choose=True,
                                 blank=True,
                                 null=True,
                                 on_delete=models.PROTECT)
    fire_tenures = models.ManyToManyField(FireTenure,
                                          verbose_name="Tenures",
                                          blank=True)
    date = models.DateField(auto_now_add=False)
    form_name = models.PositiveSmallIntegerField(
        verbose_name="Form Name (268a / 268b)",
        choices=FORM_NAME_CHOICES,
        editable=True)
    status = models.PositiveSmallIntegerField(verbose_name="Active",
                                              choices=BURN_CHOICES,
                                              null=True,
                                              blank=True)
    ignition_status = models.PositiveSmallIntegerField(
        verbose_name="Ignition Status",
        choices=IGNITION_STATUS_CHOICES,
        null=True,
        blank=True)
    external_assist = models.ManyToManyField(
        ExternalAssist, verbose_name="Assistance received from", blank=True)

    planned_area = models.DecimalField(
        verbose_name="Today's treatment area (ha)",
        max_digits=12,
        decimal_places=1,
        validators=[MinValueValidator(0.0)],
        null=True,
        blank=True)
    area = models.DecimalField(verbose_name="Yesterday's treatment area (ha)",
                               max_digits=12,
                               decimal_places=1,
                               validators=[MinValueValidator(0.0)],
                               null=True,
                               blank=True)

    planned_distance = models.DecimalField(
        verbose_name="Today's treatment distance (km)",
        max_digits=12,
        decimal_places=1,
        validators=[MinValueValidator(0.0)],
        null=True,
        blank=True)
    distance = models.DecimalField(
        verbose_name="Yesterday's treatment distance (km)",
        max_digits=12,
        decimal_places=1,
        validators=[MinValueValidator(0.0)],
        null=True,
        blank=True)

    tenures = models.TextField(verbose_name="Tenure")
    location = models.TextField(verbose_name="Location", null=True, blank=True)
    est_start = models.TimeField('Estimated Start Time', null=True, blank=True)
    conditions = models.TextField(verbose_name='SDO Special Conditions',
                                  null=True,
                                  blank=True)
    rolled = models.BooleanField(verbose_name="Fire Rolled from yesterday",
                                 editable=False,
                                 default=False)
    latitude = models.FloatField(default=0.0)
    longitude = models.FloatField(default=0.0)

    #aircraft_burn = models.BooleanField(verbose_name="Aircraft Burn", default=False)

    def clean(self):
        if not self.form_name:
            if self.prescription and self.area == None and self.distance == None:
                self.form_name = 1
            else:
                self.form_name = 2

        if self.prescription and not (self.region and self.district):
            self.region = self.prescription.region.id
            self.district = self.prescription.district

    def clean_fire_id(self):
        # set the Lat/Long to Zero, since Bushfire is not assigning these required fields
        self.latitude = 0.0
        self.longitude = 0.0


#    def clean_date(self):
#        today = date.today()
#        tomorrow = today + timedelta(days=1)
#        if not self.pk and (self.date < today or self.date > tomorrow):
#            raise ValidationError("You must enter burn plans for today or tommorow's date only.")

    def clean_planned_distance(self):
        if self.planned_area == None and self.planned_distance == None:
            raise ValidationError(
                "Must input at least one of Area or Distance")

    def clean_distance(self):
        if self.area == None and self.distance == None:
            raise ValidationError(
                "Must input at least one of Area or Distance")

    @property
    def is_acknowledged(self):
        if all(x in [i.acknow_type for i in self.acknowledgements.all()]
               for x in ['SDO_A', 'SDO_B']):
            return True
        else:
            return False

    @property
    def user_a_record(self):
        ack = self.acknowledgements.filter(acknow_type='USER_A')
        return ack[0].record if ack else None

    @property
    def srm_a_record(self):
        ack = self.acknowledgements.filter(acknow_type='SRM_A')
        return ack[0].record if ack else None

    @property
    def sdo_a_record(self):
        ack = self.acknowledgements.filter(acknow_type='SDO_A')
        return ack[0].record if ack else None

    @property
    def user_b_record(self):
        ack = self.acknowledgements.filter(acknow_type='USER_B')
        return ack[0].record if ack else None

    @property
    def srm_b_record(self):
        ack = self.acknowledgements.filter(acknow_type='SRM_B')
        return ack[0].record if ack else None

    @property
    def sdo_b_record(self):
        ack = self.acknowledgements.filter(acknow_type='SDO_B')
        return ack[0].record if ack else None

    @property
    def formA_isDraft(self):
        return not any(
            x in [i.acknow_type for i in self.acknowledgements.all()]
            for x in ['USER_A', 'SRM_A', 'SDO_A'])

    @property
    def formB_isDraft(self):
        return not any(
            x in [i.acknow_type for i in self.acknowledgements.all()]
            for x in ['USER_B', 'SRM_B', 'SDO_B'])

    @property
    def formA_user_acknowledged(self):
        return True if self.user_a_record else False

    @property
    def formA_srm_acknowledged(self):
        return True if self.srm_a_record else False

    @property
    def formA_sdo_acknowledged(self):
        return True if self.sdo_a_record else False

    @property
    def formB_user_acknowledged(self):
        return True if self.user_b_record else False

    @property
    def formB_srm_acknowledged(self):
        return True if self.srm_b_record else False

    @property
    def formB_sdo_acknowledged(self):
        return True if self.sdo_b_record else False

    @property
    def fire_type(self):
        return "Burn" if self.prescription else "Fire"

    @property
    def fire_idd(self):
        if self.prescription:
            return self.prescription.burn_id
        else:
            return self.fire_id

    @property
    def further_ignitions_req(self):
        if self.ignition_status == self.IGNITION_STATUS_REQUIRED:
            return True
        elif self.ignition_status == self.IGNITION_STATUS_COMPLETED:
            return False
        return None

    @property
    def active(self):
        # if self.status==self.BURN_ACTIVE:
        if self.status == self.BURN_ACTIVE or self.status == self.BURN_MONITORED:
            return True
        elif self.status == self.BURN_INACTIVE:
            return False
        return None

    @property
    def has_conditions(self):
        if self.conditions:
            return True
        return False

    @property
    def planned_area_str(self):
        _str = ''
        if self.planned_area:
            _str += str(self.planned_area) + " ha {} ".format(
                '-' if self.planned_distance else '')

        if self.planned_distance:
            _str += str(self.planned_distance) + " km"

        return _str

    @property
    def area_str(self):
        _str = ''
        if self.area >= 0:
            _str += str(
                self.area) + " ha {} ".format('-' if self.distance else '')

        if self.distance >= 0:
            _str += str(self.distance) + " km"

        return _str

    @property
    def tenures_str(self):
        if self.prescription:
            return self.tenures  #', '.join([t.name for t in self.tenures.all()])
        else:
            return ', '.join([i.name for i in self.fire_tenures.all()])

    @property
    def had_external_assist(self):
        if self.external_assist.all().count() > 0:
            return True
        return False

    @property
    def external_assist_str(self):
        return ', '.join([i.name for i in self.external_assist.all()])

    @property
    def name(self):
        if self.prescription:
            return self.prescription.name
        else:
            return self.fire_name

    @property
    def get_region(self):
        return self.prescription.region if self.prescription else self.region

    @property
    def get_district(self):
        return self.prescription.district if self.prescription else self.district

    @property
    def can_endorse(self):
        return (self.status == self.APPROVAL_SUBMITTED)

    @property
    def can_approve(self):
        return (self.status == self.APPROVAL_ENDORSED)

    @property
    def last_ignition(self):
        if self.prescription:
            area_achievements = self.prescription.areaachievement_set.all()
            if area_achievements:
                return max([i.ignition for i in area_achievements])
        return None

    def short_str(self):
        return self.prescription.burn_id if self.prescription else self.fire_id

    def copy_ongoing_records(self, dt):
        """
        Copy today's 'active' records to tomorrow

        268b - (Automatically) copy all records from yesterday that were Active when 268a Region Endorsement occurs,
        except for Active and Area Burnt Yesterday

        dt = from date, copied to dt+1
        """

        tomorrow = dt + timedelta(days=1)  # relative to dt
        #objects = [obj for obj in PrescribedBurn.objects.filter(date=dt, status=PrescribedBurn.BURN_ACTIVE)]
        objects = [self]
        now = timezone.now()
        admin = User.objects.get(username='******')
        count = 0
        for obj in objects:
            if obj.fire_id and PrescribedBurn.objects.filter(
                    fire_id=obj.fire_id,
                    date=tomorrow,
                    form_name=PrescribedBurn.FORM_268B):
                # don't copy if already exists - since record is unique on Prescription (not fire_id)
                logger.info(
                    'Ongoing Record Already Exists (Fire) - not copied (268b today to 268b tomorrow). Record {}, today {}, tomorrow {}'
                    .format(obj.fire_idd, dt, tomorrow))
                continue
            if obj.prescription and PrescribedBurn.objects.filter(
                    prescription__burn_id=obj.prescription.burn_id,
                    date=tomorrow,
                    form_name=PrescribedBurn.FORM_268B,
                    location=obj.location):
                # don't copy if already exists - since record is unique on Prescription (not fire_id)
                logger.info(
                    'Ongoing Record Already Exists (Burn) - not copied (268b today to 268b tomorrow). Record {}, today {}, tomorrow {}'
                    .format(obj.fire_idd, dt, tomorrow))
                continue
            try:
                obj.pk = None
                obj.date = tomorrow
                obj.area = None
                obj.status = None
                obj.approval_268a_status = PrescribedBurn.APPROVAL_DRAFT
                obj.approval_268a_status_modified = now
                obj.approval_268b_status = PrescribedBurn.APPROVAL_DRAFT
                obj.approval_268b_status_modified = now
                obj.acknowledgements.all().delete()
                obj.rolled = True
                obj.save()
                count += 1
                logger.info(
                    'Ongoing Record copied (268b today to 268b tomorrow). Record {}, today {}, tomorrow {}'
                    .format(obj.fire_idd, dt, tomorrow))
            except:
                # records already exist - pk (pres, date) will not allow overwrite, so ignore the exception
                logger.warn(
                    'Ongoing Record not copied. Record {} already exists on day {}'
                    .format(obj.fire_idd, tomorrow))

    def copy_planned_approved_records_adhoc(self, dt):
        """
        Copy today's 'planned' records (268a), that have been SDO approved. to tomorrow ongoing (268b)

        set Active and Area Burnt fields to None

        dt = from date, copied to dt+1
        """

        tomorrow = dt + timedelta(days=1)  # relative to dt
        if not self.formA_sdo_acknowledged:
            logger.info(
                'Only SDO Acknowledged record can be copied from dt {} to tomorrow {}'
                .format(dt, tomorrow))
            return

        #objects = PrescribedBurn.objects.filter(date=dt, acknowledgements__acknow_type__in=['SDO_A'], form_name=PrescribedBurn.FORM_268A)
        objects = [self]
        now = timezone.now()
        count = 0
        for obj in objects:
            if obj.fire_id and PrescribedBurn.objects.filter(
                    fire_id=obj.fire_id,
                    date=tomorrow,
                    form_name=PrescribedBurn.FORM_268B):
                # don't copy if already exists - since record is unique on Prescription (not fire_id)
                logger.info(
                    'Planned Approved Record Already Exists (Fire) - not copied (268a today to 268b tomorrow). Record {}, today {}, tomorrow {}'
                    .format(obj.fire_idd, dt, tomorrow))
                continue
            if obj.prescription and PrescribedBurn.objects.filter(
                    prescription__burn_id=obj.prescription.burn_id,
                    date=tomorrow,
                    form_name=PrescribedBurn.FORM_268B,
                    location=obj.location):
                # don't copy if already exists - since record is unique on Prescription (not fire_id)
                logger.info(
                    'Planned Approved Record Already Exists (Burn) - not copied (268a today to 268b tomorrow). Record {}, today {}, tomorrow {}'
                    .format(obj.fire_idd, dt, tomorrow))
                continue
            try:
                obj.pk = None
                obj.date = tomorrow
                obj.area = None
                obj.distance = None
                obj.status = None
                obj.approval_268a_status = PrescribedBurn.APPROVAL_DRAFT
                obj.approval_268a_status_modified = now
                obj.approval_268b_status = PrescribedBurn.APPROVAL_DRAFT
                obj.approval_268b_status_modified = now
                #obj.acknowledgements.all().delete()
                obj.form_name = PrescribedBurn.FORM_268B
                obj.rolled = True
                obj.save()
                count += 1
                logger.info(
                    'Planned Approved Record copied (268a today to 268b tomorrow). Record {}, today {}, tomorrow {}'
                    .format(obj.fire_idd, dt, tomorrow))
            except:
                # records already exist - pk (pres, date) will not allow overwrite, so ignore the exception
                logger.warn(
                    'Planned Approved Record not copied. Record {} already exists on day {}'
                    .format(obj.fire_idd, tomorrow))

    def __str__(self):
        return self.prescription.burn_id + ' (Burn)' if self.prescription else self.fire_id + ' (Fire)'

    class Meta:
        unique_together = ('prescription', 'date', 'form_name', 'location')
        verbose_name = 'Prescribed Burn or Bushfire'
        verbose_name_plural = 'Prescribed Burns and Bushfires'
        permissions = (
            ("can_endorse", "Can endorse burns"),
            ("can_approve", "Can approve burns"),
        )
示例#19
0
class BurningPrescription(Audit):
    prescription = models.ForeignKey(
        Prescription,
        help_text="Prescription this fuel schedule belongs to.",
        on_delete=models.PROTECT)
    # NOTE: the fuel_type field will be deprecated in favour of a reference to
    # the VegetationType model in the prescription app.

    fuel_type = models.ForeignKey(FuelType,
                                  verbose_name="Fuel Type",
                                  blank=True,
                                  null=True,
                                  on_delete=models.PROTECT)
    scorch = models.PositiveIntegerField(
        help_text="Maximum Scorch Height (m)",
        verbose_name="Scorch Height",
        validators=[MinValueValidator(1),
                    MaxValueValidator(30)],
        blank=True,
        null=True)
    min_area = models.PositiveIntegerField(
        verbose_name="Min Area to be Burnt (%)",
        validators=[MinValueValidator(1),
                    MaxValueValidator(100)],
        blank=True,
        null=True)
    max_area = models.PositiveIntegerField(
        verbose_name="Max Area to be Burnt (%)",
        validators=[MinValueValidator(1),
                    MaxValueValidator(100)],
        blank=True,
        null=True)
    ros_min = models.PositiveIntegerField(
        verbose_name="Min ROS (m/h)",
        validators=[MinValueValidator(0),
                    MaxValueValidator(10000)],
        blank=True,
        null=True)
    ros_max = models.PositiveIntegerField(
        verbose_name="Max ROS (m/h)",
        validators=[MinValueValidator(0),
                    MaxValueValidator(10000)],
        blank=True,
        null=True)
    ffdi_min = models.PositiveIntegerField(
        verbose_name="Min FFDI",
        validators=[MinValueValidator(0),
                    MaxValueValidator(100)],
        blank=True,
        null=True)
    ffdi_max = models.PositiveIntegerField(
        verbose_name="Max FFDI",
        validators=[MinValueValidator(0),
                    MaxValueValidator(100)],
        blank=True,
        null=True)
    gfdi_min = models.PositiveIntegerField(
        verbose_name="Min GFDI",
        validators=[MinValueValidator(0),
                    MaxValueValidator(100)],
        blank=True,
        null=True)
    gfdi_max = models.PositiveIntegerField(
        verbose_name="Max GFDI",
        validators=[MinValueValidator(0),
                    MaxValueValidator(100)],
        blank=True,
        null=True)
    temp_min = models.PositiveIntegerField(
        verbose_name="Min Temp (degrees C)",
        validators=[MinValueValidator(0),
                    MaxValueValidator(60)],
        blank=True,
        null=True)
    temp_max = models.PositiveIntegerField(
        verbose_name="Max Temp (degress C)",
        validators=[MinValueValidator(0),
                    MaxValueValidator(60)],
        blank=True,
        null=True)
    rh_min = models.PositiveIntegerField(
        verbose_name="Min Relative Humidity (%)",
        validators=[MinValueValidator(0),
                    MaxValueValidator(100)],
        blank=True,
        null=True)
    rh_max = models.PositiveIntegerField(
        verbose_name="Max Relative Humidity (%)",
        validators=[MinValueValidator(0),
                    MaxValueValidator(100)],
        blank=True,
        null=True)
    sdi = models.TextField(verbose_name="SDI", blank=True, null=True)
    smc_min = models.PositiveIntegerField(
        verbose_name="Min Surface Moisture Content (%)",
        validators=[MinValueValidator(0),
                    MaxValueValidator(100)],
        blank=True,
        null=True)
    smc_max = models.PositiveIntegerField(
        verbose_name="Max Surface Moisture Content (%)",
        validators=[MinValueValidator(0),
                    MaxValueValidator(100)],
        blank=True,
        null=True)
    pmc_min = models.PositiveIntegerField(
        verbose_name="Min Profile Moisture Content (%)",
        validators=[MinValueValidator(0),
                    MaxValueValidator(100)],
        blank=True,
        null=True)
    pmc_max = models.PositiveIntegerField(
        verbose_name="Max Profile Moisture Content (%)",
        validators=[MinValueValidator(0),
                    MaxValueValidator(100)],
        blank=True,
        null=True)
    wind_min = models.PositiveIntegerField(
        verbose_name="Min Wind Speed (km/h)",
        blank=True,
        null=True,
        validators=[MinValueValidator(0),
                    MaxValueValidator(200)])
    wind_max = models.PositiveIntegerField(
        verbose_name="Max Wind Speed (km/h)",
        validators=[MinValueValidator(0),
                    MaxValueValidator(200)],
        blank=True,
        null=True)
    wind_dir = models.TextField(verbose_name="Wind Direction",
                                blank=True,
                                null=True)
    grassland_curing_min = models.PositiveIntegerField(
        verbose_name="Grassland Curing % Min",
        validators=[MinValueValidator(0),
                    MaxValueValidator(200)],
        blank=True,
        null=True)
    grassland_curing_max = models.PositiveIntegerField(
        verbose_name="Grassland Curing % Max",
        validators=[MinValueValidator(0),
                    MaxValueValidator(200)],
        blank=True,
        null=True)

    def area(self):
        return field_range(self.min_area, self.max_area, True)

    area.short_description = "Area to be Burnt (%)"
    area.admin_order_field = "area_max"

    def ros(self):
        return field_range(self.ros_min, self.ros_max)

    ros.short_description = mark_safe(
        '<abbr title="Rate of Spread">ROS</abbr> Range')
    ros.admin_order_field = "ros_max"

    def ffdi(self):
        return field_range(self.ffdi_min, self.ffdi_max)

    ffdi.short_description = mark_safe(
        '<abbr title="Forecast Fire Danger Index">FFDI</abbr> Range')
    ffdi.admin_order_field = "ffdi_max"

    def gfdi(self):
        return field_range(self.gfdi_min, self.gfdi_max)

    gfdi.short_description = mark_safe(
        '<abbr title="Global Fire Danger Index">GFDI</abbr> Range')
    gfdi.admin_order_field = "gfdi_max"

    def temp(self):
        return field_range(self.temp_min, self.temp_max)

    temp.short_description = "Temperature Range"
    temp.admin_order_field = "temp_max"

    def rh(self):
        return field_range(self.rh_min, self.rh_max, True)

    rh.short_description = mark_safe(
        '<abbr title="Relative Humidity">RH</abbr> Range (%)')
    temp.admin_order_field = "temp_max"

    sdi.short_description = mark_safe(
        '<abbr title="Soil Dryness Index">SDI</abbr> Range')

    def smc(self):
        return field_range(self.smc_min, self.smc_max)

    smc.short_description = mark_safe(
        '<abbr title="Surface Moisture Content">SMC</abbr> Range')
    smc.admin_order_field = "smc_max"

    def pmc(self):
        return field_range(self.pmc_min, self.pmc_max)

    pmc.short_description = mark_safe(
        '<abbr title="Profile Moisture Content">PMC</abbr> Range')
    pmc.admin_order_field = "pmc_max"

    def wind(self):
        return field_range(self.wind_min, self.wind_max)

    wind.short_description = "Wind Speed Range (km/h)"
    wind.admin_order_field = "wind_max"

    def grassland_curing(self):
        return field_range(self.grassland_curing_min,
                           self.grassland_curing_max)

    grassland_curing.short_description = mark_safe(
        '<abbr title="Grassland Curing Percent">GLC</abbr> Range')
    grassland_curing.admin_order_field = "grassland_curing_max"

    def clean_sdi(self):
        if self.sdi == '':
            self.sdi = "N/A"

    def __str__(self):
        return self.fuel_type.name

    class Meta:
        verbose_name = "Burning Prescription"
        verbose_name_plural = "Burning Prescriptions"
示例#20
0
class GrandParentDuck(Audit):
    """A parent duck."""
    name = models.CharField(max_length=20)
    duck = models.ForeignKey(ParentDuck)
    objects = Manager()
示例#21
0
class BurnProgramLink(models.Model):
    prescription = models.ForeignKey(Prescription, unique=True)
    wkb_geometry = models.MultiPolygonField(srid=4326)
    area_ha = models.FloatField()
    longitude = models.FloatField()
    latitude = models.FloatField()
    perim_km = models.FloatField()
    trtd_area = models.FloatField()

    @classmethod
    def populate(cls):
        # Links prescriptions to burn program records imported using ogr2ogr
        import subprocess
        subprocess.check_call([
            'ogr2ogr', '-overwrite', '-f', 'PostgreSQL',
            "PG:dbname='{NAME}' host='{HOST}' port='{PORT}' user='******' password={PASSWORD}"
            .format(**settings.DATABASES["default"]),
            settings.ANNUAL_INDIC_PROGRAM_PATH, settings.SHP_LAYER, '-nln',
            'review_annualindicativeburnprogram', '-nlt', 'PROMOTE_TO_MULTI',
            '-t_srs', 'EPSG:4326', '-lco', 'GEOMETRY_NAME=wkb_geometry'
        ])
        for p in AnnualIndicativeBurnProgram.objects.all():
            try:
                for prescription in Prescription.objects.filter(
                        burn_id=p.burnid,
                        financial_year=p.fin_yr.replace("/", "/20")):
                    if cls.objects.filter(prescription=prescription).exists():
                        obj = cls.objects.get(prescription=prescription)
                    else:
                        obj = cls(prescription=prescription)
                    obj.wkb_geometry = p.wkb_geometry
                    obj.area_ha = p.area_ha
                    obj.longitude = p.longitude
                    obj.latitude = p.latitude
                    obj.perim_km = p.perim_km
                    obj.trtd_area = p.trtd_area if p.trtd_area and isinstance(
                        p.trtd_area, float) else 0.0
                    obj.save()
            except:
                logger.error(
                    'ERROR: Assigning AnnulaIndicativeBurnProgram \n{}'.format(
                        sys.exc_info()))

        from django.db import connection
        cursor = connection.cursor()
        cursor.execute('''
            create or replace view review_v_dailyburns as
			select
			  p.burn_id,
			  to_char(pb.date, 'FMDay, DD Mon YYYY') as burn_target_date,
			  pb.date as burn_target_date_raw,
			  case
				when string_agg(pb.form_name::text, ', ') = '1, 2' or string_agg(pb.form_name::text, ', ') = '2, 1' then
					'Active - Planned Ignitions Today'
				when string_agg(pb.form_name::text, ', ') = '2' then
					'Active - No Planned Ignitions Today'
				when string_agg(pb.form_name::text, ', ') = '1' then
					'Planned - No Prior Ignitions'
				else
					'Error'
			  end as burn_stat,
			  case
				when pb.location like '%|%' then
					case
						when p.forest_blocks not like '' then
							split_part(pb.location, '|', 1) || ', ' || split_part(pb.location, '|', 2) || 'km ' ||
								split_part(pb.location, '|', 3) || ' of '|| split_part(pb.location, '|', 4) ||
								' (' || p.forest_blocks || ')'
						else
							split_part(pb.location, '|', 1) || ', ' || split_part(pb.location, '|', 2) || 'km ' ||
								split_part(pb.location, '|', 3) || ' of '|| split_part(pb.location, '|', 4)
						end
				else
					case
						when p.forest_blocks not like '' then
							pb.location || ' (' || p.forest_blocks || ')'
						else
							pb.location
						end
			  end as location,
			  p.forest_blocks,
			  link.area_ha AS indicative_area,
			  coalesce(
				(select rpb.est_start
					 from review_prescribedburn rpb
					 where
						  rpb.date = pb.date and
						  rpb.prescription_id::text = pb.prescription_id::text and
						  rpb.form_name = 1 and
						  rpb.location = pb.location)::text,
				'') AS burn_est_start, -- use time from 268a
			  coalesce(
				(select rpb.longitude
				 from review_prescribedburn rpb
				 where
						rpb.date = pb.date and
						rpb.prescription_id::text = pb.prescription_id::text and
						rpb.form_name = 1 and
						rpb.location = pb.location),
				pb.longitude) AS burn_target_long, -- use longitude from 268a, else 268b
			  coalesce(
				(select rpb.latitude
				 from review_prescribedburn rpb
				 where
					rpb.date = pb.date and
					rpb.prescription_id::text = pb.prescription_id::text and
					rpb.form_name = 1 and
					rpb.location = pb.location),
				pb.latitude) AS burn_target_lat, -- use latitude from 268a, else 268b
			  coalesce(
				cast((select rpb.planned_area
				 from review_prescribedburn rpb
				 where
					rpb.date = pb.date and
					rpb.prescription_id::text = pb.prescription_id::text and
					rpb.form_name = 1 and
					rpb.location = pb.location) as text),
				'') AS burn_planned_area_today, -- use planned_area from 268a
			  coalesce(
				cast((select rpb.planned_distance
				 from review_prescribedburn rpb
				 where
					rpb.date = pb.date and
					rpb.prescription_id::text = pb.prescription_id::text and
					rpb.form_name = 1 and
					rpb.location = pb.location) as text),
				'') AS burn_planned_distance_today, -- use planned_distance from 268a
			  link.wkb_geometry,
                          coalesce((SELECT array_to_string(array_agg(pp.name),' , ')
                                    FROM prescription_prescription_purposes ppps JOIN prescription_purpose pp ON ppps.purpose_id = pp.id
                                    WHERE ppps.prescription_id = p.id)
                           ,'') AS burn_purpose
			from
			  (((prescription_prescription p
				 LEFT JOIN review_prescribedburn  pb ON ((p.id = pb.prescription_id)))
				 LEFT JOIN review_acknowledgement ack ON ((pb.id = ack.burn_id)))
				 LEFT JOIN review_burnprogramlink link ON ((p.id = link.prescription_id)))
			WHERE (
				(((ack.acknow_type)::text = 'SDO_A'::text) AND (pb.form_name = 1)) OR -- approved 268a
				((((ack.acknow_type)::text = 'SDO_B'::text) AND (pb.form_name = 2)) AND (pb.status = 1))) -- approved active 268b
			group by
				p.id,p.burn_id, pb.location, p.forest_blocks, burn_target_date, indicative_area,
				burn_target_long, burn_target_lat, burn_est_start, link.wkb_geometry,
				burn_planned_area_today, burn_planned_distance_today, burn_target_date_raw
			ORDER BY p.burn_id, burn_target_date_raw;
			create or replace view review_v_todaysburns as select * from review_v_dailyburns where burn_target_date_raw = current_date;
			create or replace view review_v_yesterdaysburns as select * from review_v_dailyburns where burn_target_date_raw = current_date - interval '1 day';
                        CREATE  OR REPLACE  FUNCTION review_f_lastdaysburns() RETURNS setof review_v_dailyburns AS $$
                        DECLARE
                            last_date review_v_dailyburns.burn_target_date_raw%TYPE;
                        BEGIN
                            SELECT max(pb.date) INTO last_date
                            FROM
                                review_prescribedburn  pb LEFT JOIN review_acknowledgement ack ON pb.id = ack.burn_id
                            WHERE (
                                    (((ack.acknow_type)::text = 'SDO_A'::text) AND (pb.form_name = 1))
                                    OR
                                    ((((ack.acknow_type)::text = 'SDO_B'::text) AND (pb.form_name = 2)) AND (pb.status = 1))
                                   )
                                   AND (pb.date < current_date);
                        
                            IF last_date IS NULL THEN
                                RETURN QUERY SELECT * FROM review_v_dailyburns WHERE false;
                            ELSE
                                RETURN QUERY SELECT * FROM review_v_dailyburns WHERE burn_target_date_raw = last_date;
                            END IF;
                        END;
                        $$ LANGUAGE plpgsql;
			create or replace view review_v_lastdaysburns as select * from review_f_lastdaysburns();

                        ''')
示例#22
0
class AircraftBurn(Audit):
    APPROVAL_DRAFT = 'DRAFT'
    APPROVAL_SUBMITTED = 'USER'
    APPROVAL_ENDORSED = 'SRM'
    APPROVAL_APPROVED = 'SDO'
    APPROVAL_CHOICES = (
        (APPROVAL_DRAFT, 'Draft'),
        (APPROVAL_SUBMITTED, 'District Submitted'),
        (APPROVAL_ENDORSED, 'Region Endorsed'),
        (APPROVAL_APPROVED, 'State Approved'),
    )

    fmt = "%Y-%m-%d %H:%M"

    prescription = models.ForeignKey(Prescription,
                                     verbose_name="Burn ID",
                                     related_name='aircraft_burns',
                                     null=True,
                                     blank=True,
                                     on_delete=models.PROTECT)
    #prescribed_burn = models.ForeignKey(PrescribedBurn, verbose_name="Daily Burn ID", related_name='aircraft_burn', null=True, blank=True)

    date = models.DateField(auto_now_add=False)
    area = models.DecimalField(verbose_name="Area (ha)",
                               max_digits=12,
                               decimal_places=1,
                               validators=[MinValueValidator(0.0)],
                               null=True,
                               blank=True)
    est_start = models.TimeField('Estimated Start Time', null=True, blank=True)
    bombing_duration = models.DecimalField(
        verbose_name="Bombing Duration (hrs)",
        max_digits=5,
        decimal_places=1,
        validators=[MinValueValidator(0.0)],
        null=True,
        blank=True)
    min_smc = models.DecimalField(verbose_name="Min SMC",
                                  max_digits=5,
                                  decimal_places=1,
                                  validators=[MinValueValidator(0.0)],
                                  null=True,
                                  blank=True)
    max_fdi = models.DecimalField(verbose_name="Max FDI",
                                  max_digits=5,
                                  decimal_places=1,
                                  validators=[MinValueValidator(0.0)],
                                  null=True,
                                  blank=True)
    sdi_per_day = models.DecimalField(verbose_name="SDI Each Day",
                                      max_digits=5,
                                      decimal_places=1,
                                      validators=[MinValueValidator(0.0)],
                                      null=True,
                                      blank=True)
    flight_seq = models.TextField(verbose_name="Flight Sequence",
                                  null=True,
                                  blank=True)
    aircraft_rego = models.TextField(verbose_name="Aircraft Rego",
                                     null=True,
                                     blank=True)
    arrival_time = models.TimeField(verbose_name="Arrival Time Over Burn",
                                    null=True,
                                    blank=True)
    program = models.TextField(verbose_name="Program", null=True, blank=True)
    aircrew = models.TextField(verbose_name="Aircrew", null=True, blank=True)

    rolled = models.BooleanField(verbose_name="Fire Rolled from yesterday",
                                 editable=False,
                                 default=False)
    #location= models.TextField(verbose_name="Location", null=True, blank=True)

    @property
    def regional_approval(self):
        return True

    @property
    def state_duty_approval(self):
        return True

    @property
    def state_aviation_approval(self):
        return True

    def __str__(self):
        return self.prescription.burn_id

    class Meta:
        unique_together = ('prescription', 'date')
        verbose_name = 'Aircraft Burn'
        verbose_name_plural = 'Aircraft Burns'
        permissions = (
            ("can_endorse", "Can endorse burns"),
            ("can_approve", "Can approve burns"),
        )