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

#  Copyright (c) 2025 Ferrosoft GmbH. All rights reserved.
"""Cross-model lifecycle hooks for emiflow.

Two concerns are wired up here:

* Whenever a treatment-operation output line is inserted or removed, the
  parent operation's allocation is recomputed (no-op under manual
  allocation).
* Whenever an entity that owns an :class:`EmissionIntensity` (transport
  operation, treatment operation, or emitter) is deleted, the matching
  intensity row is removed. The intensity table uses a weak
  ``(owner_type, owner_id)`` reference rather than a real foreign key, so
  this cascade must be driven explicitly from signals.

The module is loaded via the wildcard import in
:mod:`ferrosoft.apps.emiflow.models.__init__`, which is what registers
these receivers at app startup.
"""
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver

from ferrosoft.apps.emiflow.models.transport import TransportOperation
from ferrosoft.apps.emiflow.models.catalog import Emitter
from ferrosoft.apps.emiflow.models.intensity import (
    EmissionIntensity,
    IntensityCapableEntity,
)
from ferrosoft.apps.emiflow.models.treatment import (
    TreatmentOperationOutputLine,
    TreatmentOperation,
)


[docs] @receiver(post_save, sender=TreatmentOperationOutputLine) def allocate_treatment_emissions_after_insertion( instance: TreatmentOperationOutputLine, **kwargs ): """Recompute parent operation's allocation after an output line is saved.""" instance.operation.trigger_allocation()
[docs] @receiver(post_delete, sender=TreatmentOperationOutputLine) def allocate_treatment_emissions_after_deletion( instance: TreatmentOperationOutputLine, **kwargs ): """Recompute parent operation's allocation after an output line is deleted.""" instance.operation.trigger_allocation()
[docs] @receiver(post_delete, sender=TransportOperation) def delete_transport_operation_emission_intensity( instance: TransportOperation, **kwargs ): """Remove the :class:`EmissionIntensity` owned by a deleted transport operation.""" EmissionIntensity.objects.delete_of_owner( IntensityCapableEntity.TRANSPORT_OPERATION, instance.pk )
[docs] @receiver(post_delete, sender=TreatmentOperation) def delete_treatment_operation_emission_intensity( instance: TreatmentOperation, **kwargs ): """Remove the :class:`EmissionIntensity` owned by a deleted treatment operation.""" EmissionIntensity.objects.delete_of_owner( IntensityCapableEntity.TREATMENT_OPERATION, instance.pk )
[docs] @receiver(post_delete, sender=Emitter) def delete_emitter_emission_intensity(instance: Emitter, **kwargs): """Remove the :class:`EmissionIntensity` owned by a deleted emitter.""" EmissionIntensity.objects.delete_of_owner( IntensityCapableEntity.EMITTER, instance.pk )