# ---------------------- # ITS Models # ---------------------- from django.contrib.gis.db import models from django.urls import reverse from django.utils.text import slugify from django.utils.translation import get_language import os from assets.models import AbstractLocation, AbstractAsset, AbstractGeoAsset, AbstractAssetModel from common.models import Municipality, Document from common.storages import PrivateMediaStorage private_storage = PrivateMediaStorage() # ITS locations class ITSLocation(AbstractLocation): geom = models.MultiPolygonField(srid=3812, null=True,blank=True) parent_location = models.ForeignKey('self', on_delete=models.SET_NULL, null=True, blank=True, related_name="child_locations") is_main_location = models.BooleanField(default=False, verbose_name="Main Location") def get_active_assets(self): def collect_assets(location): assets = list(location.assets.filter(status='active')) for child in location.child_locations.all(): assets += collect_assets(child) return assets return collect_assets(self) def get_all_assets(self): def collect_assets(location): assets = list(location.assets.all()) for child in location.child_locations.all(): assets += collect_assets(child) return assets return collect_assets(self) def get_direct_child_assets(self): return self.assets.all() def get_absolute_url(self): return reverse( 'assets:its_locations_detail', kwargs={ 'location_id': self.id } ) class Meta: verbose_name = "ITS Location" verbose_name_plural = "ITS Locations" ordering = ["code"] def upload_to_its_location(instance, filename): location = instance.location code = slugify(location.code or "unknown") # Fallback si code est None return os.path.join("assets_documents", "its_locations", code, filename) ITS_LOC_DOCUMENT_TYPE_CHOICES = ( ('as_built', 'As Built'), ('schema', "Schéma"), ('other', 'Autre'), ) # ITS Location Document class ITSLocationDocument(Document): location = models.ForeignKey(ITSLocation, on_delete=models.CASCADE, related_name="documents", verbose_name="Associated ITS Location") file = models.FileField(upload_to=upload_to_its_location, storage=private_storage, verbose_name="Fichier", max_length=255) thumbnail = models.ImageField(upload_to=upload_to_its_location, storage=private_storage, null=True, blank=True, max_length=255) document_type = models.CharField(max_length=50, choices=ITS_LOC_DOCUMENT_TYPE_CHOICES, default='other', verbose_name="Type de document") class ITSAssetModel(AbstractAssetModel): class Meta: verbose_name = "ITS Asset Model" verbose_name_plural = "ITS Asset Models" class ITSGeoAsset(AbstractGeoAsset): model = models.ForeignKey(ITSAssetModel, on_delete=models.PROTECT) location = models.ForeignKey(ITSLocation, related_name="assets", on_delete=models.SET_NULL, null=True, blank=True) trafficlights_pole = models.ForeignKey("assets.TrafficLightPole", on_delete=models.SET_NULL, null=True, blank=True, related_name="its_assets", verbose_name="Traffic Light Pole") lighting_pole = models.ForeignKey("assets.PublicLightingPole", on_delete=models.SET_NULL, null=True, blank=True, related_name="its_assets", verbose_name="Lighting Pole") class Meta: indexes = [ models.Index(fields=["code"]), ] def get_absolute_url(self): return reverse('assets:its_assets_detail', kwargs={'asset_model': 'itsgeoasset', 'asset_id':self.id}) class ITSLocationContract(models.Model): location = models.ForeignKey(ITSLocation, on_delete=models.CASCADE, related_name="its_locations_contracts") contract = models.ForeignKey("contracts.Contract", on_delete=models.CASCADE, related_name="its_locations_contracts") status = models.CharField(max_length=50, choices=[('active', 'Actif'), ('inactive', 'Inactif'), ('archived', 'Archivé')], default='active') maintenance_type = models.CharField(max_length=50, choices=[('equipments', 'Equipements'), ('office', 'Bureautique'), ('system', 'Système'), ('other', 'Autre')], default='other') def __str__(self): return f"{self.location.code} - {self.contract.contract_number}" class Meta: verbose_name = "ITS Location Contract" verbose_name_plural = "ITS Location Contracts" unique_together = ('location', 'contract') class ITSGeoAssetContract(models.Model): asset = models.ForeignKey(ITSGeoAsset, on_delete=models.CASCADE, related_name="its_assets_contracts") contract = models.ForeignKey("contracts.Contract", on_delete=models.CASCADE, related_name="its_assets_contracts") status = models.CharField(max_length=50, choices=[('active', 'Actif'), ('inactive', 'Inactif'), ('archived', 'Archivé')], default='active') maintenance_type = models.CharField(max_length=50, choices=[('equipments', 'Equipements'), ('office', 'Bureautique'), ('system', 'Système'), ('other', 'Autre')], default='other') def __str__(self): return f"{self.asset.code} - {self.contract.contract_number}" class Meta: verbose_name = "ITS Asset Contract" verbose_name_plural = "ITS Asset Contracts" unique_together = ('asset', 'contract')