Source code for ferrosoft.apps.emiflow.models.operation

#  Copyright (c) 2025 Ferrosoft GmbH. All rights reserved.
"""Transport-operation model and its operation-type enum.

A :class:`TransportOperation` is the activity definition (emitter +
energy carrier + activity type) that is reused across one or more
transport-chain elements. It owns an :class:`EmissionIntensity` once
calculated.
"""
from django.db import models
from django.urls import reverse
from django.utils.translation import gettext_lazy as _

from ferrosoft.apps.emiflow.models.catalog import Emitter, EnergyCarrier
from ferrosoft.apps.emiflow.models.intensity import EmissionIntensity
from ferrosoft.apps.ferrobase.models import (
    UUIDModel,
    IntegerChoicesMixin,
    ReadOnlyMixin,
)


[docs] class OperationEpitype(IntegerChoicesMixin, models.IntegerChoices): """The standard defines two kinds of operations, transport and hub operation. For our data model it is useful to combine them into one data type (OperationCategory) and differentiate between transport and hub operation by the "epitype". This is an overarching type, because transport operations are further characterized by their own type. """ TRANSPORT = 1, _("Transport Operation") HUB = 2, _("Hub Operation")
[docs] class TransportOperationManager(models.Manager): """Default manager that eagerly joins the emitter, energy carrier, and intensity."""
[docs] def get_queryset(self): return ( super() .get_queryset() .select_related( "emitter", "energy_carrier", "emission_intensity", "emission_intensity__unit", ) )
[docs] class TransportOperation(ReadOnlyMixin, UUIDModel): """A reusable transport-or-hub activity definition. Combines an :class:`Emitter` and an :class:`EnergyCarrier` with an activity type (transport vs. hub) and an optional cached :class:`EmissionIntensity`. The :attr:`~ReadOnlyMixin.read_only` flag is ``True`` for operations derived from imported catalog data (which must be copied before modification) and ``False`` for user-defined operations, which remain editable in place. """ class Meta: verbose_name = _("Transport Operation") verbose_name_plural = _("Transport Operations") indexes = [ models.Index(fields=["name"]), models.Index(fields=["activity_type"]), models.Index(fields=["emitter"]), models.Index(fields=["energy_carrier"]), ] constraints = [ models.UniqueConstraint( name="uniq_transport_operation", fields=["reference"], ) ] objects = TransportOperationManager() reference = models.CharField( verbose_name=_("Reference"), ) name = models.CharField( verbose_name=_("Name"), ) activity_type = models.IntegerField( choices=OperationEpitype.choices, default=OperationEpitype.TRANSPORT, verbose_name=_("Activity Type"), ) emitter = models.ForeignKey( Emitter, on_delete=models.RESTRICT, related_name="+", verbose_name=_("Emitter"), ) energy_carrier = models.ForeignKey( EnergyCarrier, on_delete=models.RESTRICT, related_name="+", verbose_name=_("Energy Carrier"), help_text=_("Leave blank to copy from selected emitter"), ) emission_intensity = models.ForeignKey( EmissionIntensity, null=True, on_delete=models.SET_NULL, related_name="+", verbose_name=_("Emission Intensity"), ) def __str__(self): if self.name == "": return self.reference return "%s - %s" % (self.reference, self.name)
[docs] def get_absolute_url(self): return reverse("emiflow:transportoperation_update", args=(self.pk,))