diff --git a/requirements/base.txt b/requirements/base.txt index dccd382..bb9f731 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -1,11 +1,11 @@ asgiref==3.11.0 certifi==2025.11.12 charset-normalizer==3.4.4 -crispy-bootstrap5==2025.6 -Django==5.2.8 -djangorestframework==3.16.1 +crispy-bootstrap5==2026.3 +Django==6.0.7 +djangorestframework==3.17.1 djangorestframework-simplejwt==5.5.1 -django-crispy-forms==2.5 +django-crispy-forms==2.6 et_xmlfile==2.0.0 geopandas==1.1.1 idna==3.11 diff --git a/streetup/analytics/migrations/0001_initial.py b/streetup/analytics/migrations/0001_initial.py index 22d2f4e..7103686 100644 --- a/streetup/analytics/migrations/0001_initial.py +++ b/streetup/analytics/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import django.db.models.deletion from django.conf import settings diff --git a/streetup/api/migrations/0001_initial.py b/streetup/api/migrations/0001_initial.py index eb37a4e..088d9c1 100644 --- a/streetup/api/migrations/0001_initial.py +++ b/streetup/api/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import django.db.models.deletion from django.conf import settings diff --git a/streetup/assets/migrations/0001_initial.py b/streetup/assets/migrations/0001_initial.py index 851742e..7f2473c 100644 --- a/streetup/assets/migrations/0001_initial.py +++ b/streetup/assets/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import assets.models.controlcenters import assets.models.its @@ -26,7 +26,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('code', models.CharField(max_length=50)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -78,7 +78,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('code', models.CharField(max_length=50)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -183,7 +183,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -246,7 +246,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -490,7 +490,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -598,7 +598,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -702,7 +702,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -737,7 +737,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -764,7 +764,7 @@ class Migration(migrations.Migration): ('buffer', models.FloatField(blank=True, null=True)), ('width', models.FloatField(blank=True, null=True)), ('length', models.FloatField(blank=True, null=True)), - ('bulb_types', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(choices=[('tulipes', 'Tulipes'), ('jacynthes', 'Jacynthes'), ('jonquilles', 'Jonquilles'), ('narcisses', 'Narcisses'), ('crocus', 'Crocus'), ('perce_neige', 'Perce-neige'), ('autres', 'Autres')], max_length=50), blank=True, default=list, size=None, verbose_name='Types de bulbes')), + ('bulb_types', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(choices=[('tulipes', 'Tulipes'), ('jacynthes', 'Jacynthes'), ('jonquilles', 'Jonquilles'), ('narcisses', 'Narcisses'), ('crocus', 'Crocus'), ('perce_neige', 'Perce-neige'), ('autres', 'Autres')], max_length=50), blank=True, default=list, verbose_name='Types de bulbes')), ], options={ 'abstract': False, @@ -785,43 +785,6 @@ class Migration(migrations.Migration): 'abstract': False, }, ), - migrations.CreateModel( - name='NatureHollowGreenSpace', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('code', models.CharField(max_length=50)), - ('name_fr', models.CharField(blank=True, max_length=200, null=True)), - ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), - ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), - ('installation_date', models.DateTimeField(blank=True, null=True)), - ('uninstallation_date', models.DateTimeField(blank=True, null=True)), - ('serial_number', models.CharField(blank=True, max_length=200, null=True)), - ('warranty_duration', models.IntegerField(blank=True, null=True, verbose_name='Duration of the warranty (months)')), - ('last_inspection_date', models.DateTimeField(blank=True, null=True)), - ('last_preventive_date', models.DateTimeField(blank=True, null=True)), - ('last_corrective_date', models.DateTimeField(blank=True, null=True)), - ('last_survey_date', models.DateTimeField(blank=True, null=True)), - ('brand', models.CharField(blank=True, max_length=500, null=True)), - ('marked_as_removed_date', models.DateTimeField(blank=True, null=True, verbose_name='Date de marquage comme retiré')), - ('note', models.TextField(blank=True, null=True, verbose_name='Note')), - ('validation_status', models.CharField(blank=True, choices=[('to_be_validated', 'À valider'), ('validated', 'Validé'), ('to_be_completed', 'À compléter'), ('rejected', 'Rejeté')], max_length=50, null=True, verbose_name='Statut de validation')), - ('updated_at', models.DateTimeField(auto_now=True)), - ('lon', models.FloatField(blank=True, null=True)), - ('lat', models.FloatField(blank=True, null=True)), - ('geojson', models.TextField(blank=True, null=True)), - ('geom', django.contrib.gis.db.models.fields.MultiPolygonField(blank=True, null=True, srid=3812)), - ('surface_area', models.FloatField(blank=True, null=True)), - ('width', models.FloatField(blank=True, null=True)), - ('length', models.FloatField(blank=True, null=True)), - ('hgs_type', models.CharField(blank=True, choices=[('rain_garden', 'Jardin de pluie'), ('swale', 'Noue'), ('ditch', 'Fossé'), ('dry_basin', "Bassin sec/d'infiltration"), ('wet_basin', 'Bassin en eau')], max_length=50, null=True, verbose_name="Type d'EVC")), - ('coat_type', models.CharField(blank=True, choices=[('earth_stone_mixture', 'Mélange terre-pierre'), ('vegetal', 'Végétal'), ('grassed_structure', 'Structure enherbée'), ('non_aggregated_material', 'Matériau non agrégé'), ('mineral_filled_structure', 'Structure à remplissage minéral'), ('elevated_coating', 'Revêtement surélevé'), ('modular_porous', 'Modulaire poreux'), ('continuous_porous', 'Continu poreux'), ('impermeable', 'Impermeable')], max_length=50, null=True, verbose_name='Type de revêtement')), - ], - options={ - 'verbose_name': 'Espace vert creux', - 'verbose_name_plural': 'Espaces verts creux', - }, - ), migrations.CreateModel( name='NatureLocation', fields=[ @@ -842,6 +805,72 @@ class Migration(migrations.Migration): 'abstract': False, }, ), + migrations.CreateModel( + name='NatureRWIAsset', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('code', models.CharField(max_length=50)), + ('name_fr', models.CharField(blank=True, max_length=200, null=True)), + ('name_nl', models.CharField(blank=True, max_length=200, null=True)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), + ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), + ('installation_date', models.DateTimeField(blank=True, null=True)), + ('uninstallation_date', models.DateTimeField(blank=True, null=True)), + ('serial_number', models.CharField(blank=True, max_length=200, null=True)), + ('warranty_duration', models.IntegerField(blank=True, null=True, verbose_name='Duration of the warranty (months)')), + ('last_inspection_date', models.DateTimeField(blank=True, null=True)), + ('last_preventive_date', models.DateTimeField(blank=True, null=True)), + ('last_corrective_date', models.DateTimeField(blank=True, null=True)), + ('last_survey_date', models.DateTimeField(blank=True, null=True)), + ('brand', models.CharField(blank=True, max_length=500, null=True)), + ('marked_as_removed_date', models.DateTimeField(blank=True, null=True, verbose_name='Date de marquage comme retiré')), + ('note', models.TextField(blank=True, null=True, verbose_name='Note')), + ('validation_status', models.CharField(blank=True, choices=[('to_be_validated', 'À valider'), ('validated', 'Validé'), ('to_be_completed', 'À compléter'), ('rejected', 'Rejeté')], max_length=50, null=True, verbose_name='Statut de validation')), + ('updated_at', models.DateTimeField(auto_now=True)), + ('lon', models.FloatField(blank=True, null=True)), + ('lat', models.FloatField(blank=True, null=True)), + ('geojson', models.TextField(blank=True, null=True)), + ('geom', django.contrib.gis.db.models.fields.GeometryField(blank=True, null=True, srid=3812)), + ('external_id', models.IntegerField(blank=True, null=True, verbose_name='External ID')), + ('code_name', models.CharField(blank=True, choices=[('AV', 'Stormwater inlet (Avaloir)'), ('BS', 'Sequenced border (Bordure séquencée)'), ('BI', "Injection port (Bouche d'injection)"), ('CA', 'Non-return valve (Clapet anti-retour)'), ('ES', 'Sedimentation (Empierrement sédimentation)'), ('KC', 'Kerb cell'), ('PI', "Infiltration well (Puits d'infiltration)"), ('SU', 'Overflow (Surverse)'), ('VI', "Isolation valve (Vanne d'isolation)"), ('VR', 'Control valve (Vanne de régulation)'), ('GT', 'Sidewalk gargoyle (Gargouille de trottoir)'), ('FE', "Trickle of water (Filet d'eau)"), ('AR', 'Rail drain (Avaloir de rail)'), ('BA', 'Leveled edge (Bordure arasée)'), ('CI', 'Infiltration channel (Caniveau infiltrant)'), ('D', 'Drain'), ('TP', 'Overflowing (Trop plein)'), ('RES', 'Separate sewer system (Réseau égout séparatif)'), ('EVC', 'Hollow green space (Espace vert creux)'), ('OED', 'Decentralized underground structure (Ouvrage enterré décentralisé)'), ('OSI', 'Work on an impermeable surface (Ouvrage sur surface imperméable)'), ('TA', 'Alternative technique (Technique alternative)'), ('OA', 'Supplementary work (Ouvrage annexe)')], max_length=50, null=True, verbose_name='Code name')), + ('structure_type', models.CharField(blank=True, choices=[('avaloir', 'Stormwater inlet (Avaloir)'), ('bordure sequencee', 'Sequenced border (Bordure séquencée)'), ('bouche injection', "Injection port (Bouche d'injection)"), ('clapet anti-retour', 'Non-return valve (Clapet anti-retour)'), ('empierrement sedimentation', 'Sedimentation (Empierrement sédimentation)'), ('kerb cell', 'Kerb cell'), ('puits infiltration', "Infiltration well (Puits d'infiltration)"), ('surverse', 'Overflow (Surverse)'), ('vanne isolation', "Isolation valve (Vanne d'isolation)"), ('vanne regulation', 'Control valve (Vanne de régulation)'), ('gargouille de trottoir', 'Sidewalk gargoyle (Gargouille de trottoir)'), ('filet eau', "Trickle of water (Filet d'eau)"), ('avaloir de rail', 'Rail drain (Avaloir de rail)'), ('bordure arasee', 'Leveled edge (Bordure arasée)'), ('caniveau infiltrant', 'Infiltration channel (Caniveau infiltrant)'), ('drain', 'Drain'), ('trop plein', 'Overflowing (Trop plein)'), ('reseau egout separatif', 'Separate sewer system (Réseau égout séparatif)'), ('bassin sec/infiltration', 'Dry/infiltration basin (Bassin sec/infiltration)'), ('bassin en eau', 'Wet basin (Bassin en eau)'), ('fosse', 'Ditch (Fossé)'), ('jardin de pluie', 'Rain garden (Jardin de pluie)'), ('noue', 'Swale (Noue)'), ('massif drainant', 'Draining structure (Massif drainant)'), ('tranchee drainante', 'Draining trench (Tranchée drainante)'), ('toiture stockante', 'Retention roof (Toiture stockante)'), ('toiture verte', 'Green roof (Toiture verte)'), ('bassin orage', "Stormwater basin (Bassin d'orage)"), ('SAUL-vide', 'SAUL-empty (SAUL-vide)'), ('SAUL-terre', 'SAUL-earth (SAUL-terre)'), ('citerne', 'Cistern (Citerne)'), ('espace vert sur dalle', 'Green space on slab (Espace vert sur dalle)'), ('bande filtrante', 'Filter strip (Bande filtrante)'), ('collecteur en beton poreux', 'Porous concrete collector (Collecteur en béton poreux)')], max_length=100, null=True, verbose_name='Structure type')), + ('geometry_type', models.CharField(blank=True, choices=[('point', 'Point'), ('line', 'Line'), ('polygon', 'Polygon')], max_length=50, null=True, verbose_name='Geometry type')), + ('project_manager', models.CharField(blank=True, choices=[('DPV', 'DPV'), ('DITP', 'DITP'), ('DEN', 'DEN'), ('DPO', 'DPO'), ('Beliris', 'Beliris'), ('Commune', 'Commune')], max_length=50, null=True, verbose_name='Project manager')), + ('construction_status', models.CharField(blank=True, choices=[('etude', 'Design (Étude)'), ('travaux', 'Construction (Travaux)'), ('reception provisoire', 'Provisional acceptance (Réception provisoire)'), ('reception definitive', 'Final acceptance (Réception définitive)')], max_length=100, null=True, verbose_name='Construction status')), + ('commissioning_date', models.DateField(blank=True, null=True, verbose_name='Commissioning date')), + ('condition', models.CharField(blank=True, choices=[('bon', 'Good (Bon)'), ('examen a programmer', 'Inspection to schedule (Examen à programmer)'), ('intervention curative necessaire', 'Curative action needed (Intervention curative nécessaire)'), ('refection totale necessaire', 'Total rehabilitation needed (Réfection totale nécessaire)'), ('travaux entretien a realiser', 'Maintenance works to perform (Travaux entretien à réaliser)'), ('travaux maintenance', 'Maintenance works (Travaux maintenance)'), ('travaux maintenance a programmer', 'Maintenance works to schedule (Travaux maintenance à programmer)')], max_length=100, null=True, verbose_name='Condition')), + ('administrator', models.CharField(blank=True, max_length=500, null=True, verbose_name='Administrator')), + ('monitoring', models.CharField(blank=True, max_length=500, null=True, verbose_name='Monitoring')), + ('comment', models.TextField(blank=True, null=True, verbose_name='Comment')), + ('has_filter', models.BooleanField(blank=True, null=True, verbose_name='Has filter')), + ('sewer_connection', models.CharField(blank=True, choices=[('connecte', 'Connected (Connecté)'), ('non connecte', 'Not connected (Non connecté)')], max_length=50, null=True, verbose_name='Sewer connection')), + ('separate_network_connection', models.CharField(blank=True, choices=[('connecte', 'Connected (Connecté)'), ('non connecte', 'Not connected (Non connecté)')], max_length=50, null=True, verbose_name='Separate network connection')), + ('hydro_network_connection', models.CharField(blank=True, choices=[('connecte', 'Connected (Connecté)'), ('non connecte', 'Not connected (Non connecté)')], max_length=50, null=True, verbose_name='Hydro network connection')), + ('surface_area', models.FloatField(blank=True, null=True, verbose_name='Surface area (m²)')), + ('length', models.FloatField(blank=True, null=True, verbose_name='Length (m)')), + ('coating_category', models.CharField(blank=True, choices=[('Vegetal', 'Vegetal (Végétal)'), ('Structure enherbee', 'Grassed structure (Structure enherbée)'), ('Materiau non agrege', 'Unbound material (Matériau non agrégé)'), ('Structure a remplissage mineral', 'Mineral-filled structure (Structure à remplissage minéral)'), ('Revetement sureleve', 'Raised coating (Revêtement surélevé)'), ('Modulaire poreux', 'Porous modular (Modulaire poreux)'), ('Continu poreux', 'Porous continuous (Continu poreux)'), ('Impermeable', 'Impermeable (Imperméable)')], max_length=100, null=True, verbose_name='Coating category')), + ('coating_type', models.CharField(blank=True, choices=[('Pleine terre', 'Open soil (Pleine terre)'), ('Melange terre-pierre', 'Soil-stone mixture (Mélange terre-pierre)'), ('Paves a joints larges enherbes', 'Grassed wide-joint pavers (Pavés à joints larges enherbés)'), ('Dalles gazon en beton', 'Concrete grass grids (Dalles gazon en béton)'), ('Dalles alveolaires vegetalisees', 'Vegetated cellular tiles (Dalles alvéolaires végétalisées)'), ('Mulch vegetal', 'Woodchips/mulch (Mulch végétal)'), ('Graviers calcaires', 'Limestone gravel (Graviers calcaires)'), ('Graviers non calcaires', 'Non-limestone gravel (Graviers non calcaires)'), ('Terre battue', 'Dirt ground (Terre battue)'), ('Paves a joints larges engravillonnes', 'Gravel wide-joint pavers (Pavés à joints larges engravillonnés)'), ('Dalles alveolaires en gravier', 'Gravel cellular tiles (Dalles alvéolaires en gravier)'), ('Dalles en PEHD remplies de pave', 'HDPE tiles filled with pavers (Dalles en PEHD remplies de pavé)'), ('Grilles', 'Grates (Grilles)'), ('Platelages bois', 'Wooden decking (Platelages bois)'), ('Pave en beton poreux', 'Porous concrete pavers (Pavé en béton poreux)'), ('Dalle en beton poreux', 'Porous concrete slab (Dalle en béton poreux)'), ('Enrobes bitumineux poreux', 'Porous asphalt (Enrobés bitumineux poreux)'), ('Betons poreux', 'Porous concrete (Bétons poreux)'), ('Graviers lies a la resine', 'Resin-bound gravel (Graviers liés à la résine)'), ('Graviers concasses lies aux polymeres', 'Polymer-bound crushed gravel (Graviers concassés liés aux polymères)'), ('Revetements EPDM et ESBR', 'EPDM and SBR rubber coatings (Revêtements EPDM et ESBR)'), ('Revetements en beton de ciment non permeables', 'Non-porous cement concrete coatings (Revêtements en béton de ciment non perméables)'), ('Revetements bitumineux non permeables', 'Non-porous asphalt coatings (Revêtements bitumineux non perméables)'), ('Dallages non permeables', 'Non-porous tiling (Dallages non perméables)'), ('Pavages non permeables', 'Non-porous paving (Pavages non perméables)'), ('Autres revetements non permeables', 'Other non-porous coatings (Autres revêtements non perméables)')], max_length=100, null=True, verbose_name='Coating type')), + ], + options={ + 'verbose_name': 'RWI Asset', + 'verbose_name_plural': 'RWI Assets', + }, + ), + migrations.CreateModel( + name='NatureRWIAssetDocument', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('description', models.TextField(blank=True, null=True, verbose_name='Description du document')), + ('upload_date', models.DateTimeField(auto_now=True, verbose_name='Date de téléversement')), + ('status', models.CharField(choices=[('active', 'Actif'), ('archived', 'Archivé')], default='active')), + ('file', models.FileField(max_length=255, storage=common.storages.PrivateMediaStorage(), upload_to='assets_documents/nature/rwi/', verbose_name='File')), + ('thumbnail', models.ImageField(blank=True, max_length=255, null=True, storage=common.storages.PrivateMediaStorage(), upload_to='assets_documents/nature/rwi/')), + ], + options={ + 'verbose_name': 'RWI Asset Document', + 'verbose_name_plural': 'RWI Asset Documents', + }, + ), migrations.CreateModel( name='NatureRWIZ', fields=[ @@ -867,7 +896,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -902,7 +931,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -936,7 +965,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -986,7 +1015,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -1033,7 +1062,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -1053,6 +1082,10 @@ class Migration(migrations.Migration): ('geom', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=3812)), ('geojson', models.TextField(blank=True, null=True)), ], + options={ + 'verbose_name': 'Public lighting pole', + 'verbose_name_plural': 'Public lighting poles', + }, ), migrations.CreateModel( name='PublicLightingPoleModel', @@ -1112,7 +1145,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -1133,7 +1166,7 @@ class Migration(migrations.Migration): ('geojson', models.TextField(blank=True, null=True)), ('address', models.CharField(blank=True, max_length=2048, null=True)), ('main_function', models.CharField(blank=True, choices=[('protection', 'Protection Asset'), ('antiterrorist', 'Antiterroriste'), ('parking_neutralization', 'Neutralisation stationnement'), ('road_safety', 'Sécurité routière'), ('public_space', 'Espace public'), ('construction', 'Chantier'), ('unidentified', 'Non identifié')], max_length=200, null=True)), - ('secondary_functions', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(choices=[('protection', 'Protection Asset'), ('antiterrorist', 'Antiterroriste'), ('parking_neutralization', 'Neutralisation stationnement'), ('road_safety', 'Sécurité routière'), ('public_space', 'Espace public'), ('construction', 'Chantier'), ('unidentified', 'Non identifié')], max_length=200), blank=True, null=True, size=None)), + ('secondary_functions', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(choices=[('protection', 'Protection Asset'), ('antiterrorist', 'Antiterroriste'), ('parking_neutralization', 'Neutralisation stationnement'), ('road_safety', 'Sécurité routière'), ('public_space', 'Espace public'), ('construction', 'Chantier'), ('unidentified', 'Non identifié')], max_length=200), blank=True, null=True)), ('number_of_blocks', models.IntegerField(blank=True, null=True)), ('length', models.FloatField(blank=True, null=True)), ('recommended_action', models.CharField(blank=True, choices=[('keep', 'Maintenir'), ('remove', 'Enlever'), ('replace', 'Remplacer')], max_length=2048, null=True)), @@ -1151,7 +1184,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -1177,7 +1210,7 @@ class Migration(migrations.Migration): ('nearby_vegetation', models.BooleanField(blank=True, null=True)), ('possible_rooting', models.BooleanField(blank=True, null=True)), ('is_defect', models.BooleanField(blank=True, null=True)), - ('defect_types', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(choices=[('obstructed', 'Obstrué'), ('smell_cut_missing', 'Coupe-odeur manquant'), ('grate_broken', 'Grille cassée'), ('grate_missing', 'Grille manquante'), ('poor_water_flow', 'Mauvais écoulement'), ('other', 'Autre')], max_length=200), blank=True, null=True, size=None)), + ('defect_types', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(choices=[('obstructed', 'Obstrué'), ('smell_cut_missing', 'Coupe-odeur manquant'), ('grate_broken', 'Grille cassée'), ('grate_missing', 'Grille manquante'), ('poor_water_flow', 'Mauvais écoulement'), ('other', 'Autre')], max_length=200), blank=True, null=True)), ('defect_note', models.TextField(blank=True, null=True)), ('related_image_type', models.CharField(blank=True, max_length=1000, null=True)), ('altitude', models.FloatField(blank=True, null=True)), @@ -1208,7 +1241,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -1259,7 +1292,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -1345,7 +1378,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -1410,7 +1443,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -1471,6 +1504,9 @@ class Migration(migrations.Migration): ('name_nl', models.CharField(max_length=200)), ('description', models.TextField(blank=True, null=True)), ('sgv_picture', models.ImageField(blank=True, null=True, upload_to='sign/signpanels_types/')), + ('default_width', models.FloatField(blank=True, null=True, verbose_name='Largeur par défaut (cm)')), + ('default_height', models.FloatField(blank=True, null=True, verbose_name='Hauteur par défaut (cm)')), + ('default_diameter', models.FloatField(blank=True, null=True, verbose_name='Diamètre par défaut (cm)')), ], ), migrations.CreateModel( @@ -1480,7 +1516,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -1515,7 +1551,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -1659,7 +1695,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -1707,7 +1743,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -1754,7 +1790,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -1813,7 +1849,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -1852,7 +1888,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -1913,7 +1949,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -1934,7 +1970,7 @@ class Migration(migrations.Migration): ('geojson', models.TextField(blank=True, null=True)), ('name', models.CharField(blank=True, max_length=255, null=True, verbose_name='Nom du détecteur')), ('hardware', models.CharField(blank=True, max_length=255, null=True, verbose_name='Hardware')), - ('phases', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=50), blank=True, null=True, size=None, verbose_name='Phases associées')), + ('phases', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=50), blank=True, null=True, verbose_name='Phases associées')), ('mentionned_on_plan', models.BooleanField(default=False, verbose_name='Mentionné sur le plan')), ], options={ @@ -1963,7 +1999,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -2011,7 +2047,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -2087,6 +2123,7 @@ class Migration(migrations.Migration): ('status', models.CharField(choices=[('active', 'Actif'), ('in_preparation', 'En préparation'), ('under_repair', 'En cours de réparation'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('inactive', 'Désactivé'), ('archived', 'Archivé')], default='active')), ('begin_time', models.DateTimeField(blank=True, null=True)), ('current_index', models.CharField(blank=True, max_length=100, null=True)), + ('is_radar', models.BooleanField(default=False, verbose_name='Est un radar ?')), ], options={ 'ordering': ['code'], @@ -2116,7 +2153,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -2160,7 +2197,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -2195,7 +2232,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -2220,8 +2257,8 @@ class Migration(migrations.Migration): ('ral', models.CharField(blank=True, max_length=200, null=True, verbose_name='RAL')), ], options={ - 'verbose_name': 'Poteau', - 'verbose_name_plural': 'Poteaux', + 'verbose_name': 'Traffic light pole', + 'verbose_name_plural': 'Traffic light poles', }, ), migrations.CreateModel( @@ -2248,7 +2285,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -2273,6 +2310,101 @@ class Migration(migrations.Migration): 'ordering': ['-commissioning_date'], }, ), + migrations.CreateModel( + name='TrafficLightRadar', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('code', models.CharField(max_length=50)), + ('name_fr', models.CharField(blank=True, max_length=200, null=True)), + ('name_nl', models.CharField(blank=True, max_length=200, null=True)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), + ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), + ('installation_date', models.DateTimeField(blank=True, null=True)), + ('uninstallation_date', models.DateTimeField(blank=True, null=True)), + ('serial_number', models.CharField(blank=True, max_length=200, null=True)), + ('warranty_duration', models.IntegerField(blank=True, null=True, verbose_name='Duration of the warranty (months)')), + ('last_inspection_date', models.DateTimeField(blank=True, null=True)), + ('last_preventive_date', models.DateTimeField(blank=True, null=True)), + ('last_corrective_date', models.DateTimeField(blank=True, null=True)), + ('last_survey_date', models.DateTimeField(blank=True, null=True)), + ('brand', models.CharField(blank=True, max_length=500, null=True)), + ('marked_as_removed_date', models.DateTimeField(blank=True, null=True, verbose_name='Date de marquage comme retiré')), + ('note', models.TextField(blank=True, null=True, verbose_name='Note')), + ('validation_status', models.CharField(blank=True, choices=[('to_be_validated', 'À valider'), ('validated', 'Validé'), ('to_be_completed', 'À compléter'), ('rejected', 'Rejeté')], max_length=50, null=True, verbose_name='Statut de validation')), + ('updated_at', models.DateTimeField(auto_now=True)), + ('lon', models.FloatField(blank=True, null=True)), + ('lat', models.FloatField(blank=True, null=True)), + ('geom', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=3812)), + ('geojson', models.TextField(blank=True, null=True)), + ], + options={ + 'verbose_name': 'Radar', + 'verbose_name_plural': 'Radars', + }, + ), + migrations.CreateModel( + name='TrafficLightRadarModel', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('code', models.CharField(max_length=50)), + ('name_fr', models.CharField(blank=True, max_length=200, null=True)), + ('name_nl', models.CharField(blank=True, max_length=200, null=True)), + ('description', models.TextField(blank=True, null=True)), + ('brand', models.CharField(blank=True, max_length=500, null=True)), + ], + options={ + 'verbose_name': 'Traffic Light Radar Model', + 'verbose_name_plural': 'Traffic Light Radar Models', + }, + ), + migrations.CreateModel( + name='TrafficLightRadarPole', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('code', models.CharField(max_length=50)), + ('name_fr', models.CharField(blank=True, max_length=200, null=True)), + ('name_nl', models.CharField(blank=True, max_length=200, null=True)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), + ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), + ('installation_date', models.DateTimeField(blank=True, null=True)), + ('uninstallation_date', models.DateTimeField(blank=True, null=True)), + ('serial_number', models.CharField(blank=True, max_length=200, null=True)), + ('warranty_duration', models.IntegerField(blank=True, null=True, verbose_name='Duration of the warranty (months)')), + ('last_inspection_date', models.DateTimeField(blank=True, null=True)), + ('last_preventive_date', models.DateTimeField(blank=True, null=True)), + ('last_corrective_date', models.DateTimeField(blank=True, null=True)), + ('last_survey_date', models.DateTimeField(blank=True, null=True)), + ('brand', models.CharField(blank=True, max_length=500, null=True)), + ('marked_as_removed_date', models.DateTimeField(blank=True, null=True, verbose_name='Date de marquage comme retiré')), + ('note', models.TextField(blank=True, null=True, verbose_name='Note')), + ('validation_status', models.CharField(blank=True, choices=[('to_be_validated', 'À valider'), ('validated', 'Validé'), ('to_be_completed', 'À compléter'), ('rejected', 'Rejeté')], max_length=50, null=True, verbose_name='Statut de validation')), + ('updated_at', models.DateTimeField(auto_now=True)), + ('lon', models.FloatField(blank=True, null=True)), + ('lat', models.FloatField(blank=True, null=True)), + ('geom', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=3812)), + ('geojson', models.TextField(blank=True, null=True)), + ('colour', models.CharField(blank=True, max_length=200, null=True, verbose_name='Couleur')), + ('ral', models.CharField(blank=True, max_length=200, null=True, verbose_name='RAL')), + ], + options={ + 'verbose_name': 'Radar Pole', + 'verbose_name_plural': 'Radar Poles', + }, + ), + migrations.CreateModel( + name='TrafficLightRadarPoleModel', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('code', models.CharField(max_length=50)), + ('name_fr', models.CharField(blank=True, max_length=200, null=True)), + ('name_nl', models.CharField(blank=True, max_length=200, null=True)), + ('description', models.TextField(blank=True, null=True)), + ('brand', models.CharField(blank=True, max_length=500, null=True)), + ], + options={ + 'abstract': False, + }, + ), migrations.CreateModel( name='TrafficLightVoltageHardware', fields=[ @@ -2280,7 +2412,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), diff --git a/streetup/assets/migrations/0002_initial.py b/streetup/assets/migrations/0002_initial.py index b473481..4029b72 100644 --- a/streetup/assets/migrations/0002_initial.py +++ b/streetup/assets/migrations/0002_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import django.db.models.deletion from django.conf import settings diff --git a/streetup/assets/migrations/0003_initial.py b/streetup/assets/migrations/0003_initial.py index 4d2f897..c90878e 100644 --- a/streetup/assets/migrations/0003_initial.py +++ b/streetup/assets/migrations/0003_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import django.db.models.deletion from django.conf import settings @@ -79,6 +79,11 @@ class Migration(migrations.Migration): name='street', field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='fountains', to='assets.artworkstreet'), ), + migrations.AddField( + model_name='assetcategory', + name='allowed_models', + field=models.ManyToManyField(blank=True, help_text="Les types de modèles d'assets (Django) autorisés pour cette catégorie.", related_name='asset_categories', to='contenttypes.contenttype', verbose_name='Modèles Django autorisés'), + ), migrations.AddField( model_name='assetcategory', name='parent', @@ -489,26 +494,6 @@ class Migration(migrations.Migration): name='uploaded_by', field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Ajouté par'), ), - migrations.AddField( - model_name='naturehollowgreenspace', - name='category', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.assetcategory'), - ), - migrations.AddField( - model_name='naturehollowgreenspace', - name='marked_as_removed_by', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_marked_as_removed', to=settings.AUTH_USER_MODEL, verbose_name='Marqué comme retiré par'), - ), - migrations.AddField( - model_name='naturehollowgreenspace', - name='replaced_by', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='replaces', to='assets.naturehollowgreenspace', verbose_name='Remplacé par'), - ), - migrations.AddField( - model_name='naturehollowgreenspace', - name='updated_by', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Mis à jour par'), - ), migrations.AddField( model_name='naturelocation', name='category', @@ -539,16 +524,46 @@ class Migration(migrations.Migration): name='location', field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='nature_benches', to='assets.naturelocation'), ), + migrations.AddField( + model_name='naturerwiasset', + name='category', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.assetcategory'), + ), + migrations.AddField( + model_name='naturerwiasset', + name='marked_as_removed_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_marked_as_removed', to=settings.AUTH_USER_MODEL, verbose_name='Marqué comme retiré par'), + ), + migrations.AddField( + model_name='naturerwiasset', + name='replaced_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='replaces', to='assets.naturerwiasset', verbose_name='Remplacé par'), + ), + migrations.AddField( + model_name='naturerwiasset', + name='updated_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Mis à jour par'), + ), + migrations.AddField( + model_name='naturerwiassetdocument', + name='managed_document', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_sources', to='documents.manageddocument'), + ), + migrations.AddField( + model_name='naturerwiassetdocument', + name='rwi_asset', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='documents', to='assets.naturerwiasset', verbose_name='RWI Asset'), + ), + migrations.AddField( + model_name='naturerwiassetdocument', + name='uploaded_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Ajouté par'), + ), migrations.AddField( model_name='naturerwiz', name='updated_by', field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_location_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Mis à jour par'), ), - migrations.AddField( - model_name='naturehollowgreenspace', - name='location', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='hollow_green_spaces', to='assets.naturerwiz'), - ), migrations.AddField( model_name='natureshrub', name='category', diff --git a/streetup/assets/migrations/0004_initial.py b/streetup/assets/migrations/0004_initial.py index a37de5d..d077678 100644 --- a/streetup/assets/migrations/0004_initial.py +++ b/streetup/assets/migrations/0004_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import django.db.models.deletion from django.conf import settings @@ -11,7 +11,7 @@ class Migration(migrations.Migration): dependencies = [ ('assets', '0003_initial'), - ('common', '0003_initial'), + ('common', '0004_initial'), ('contracts', '0001_initial'), ('documents', '0001_initial'), ('observations', '0001_initial'), @@ -889,6 +889,101 @@ class Migration(migrations.Migration): name='programming', field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='documents', to='assets.trafficlightprogramming', verbose_name='Programmation associée'), ), + migrations.AddField( + model_name='trafficlightradar', + name='category', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.assetcategory'), + ), + migrations.AddField( + model_name='trafficlightradar', + name='intersection', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='radars', to='assets.trafficlightintersection'), + ), + migrations.AddField( + model_name='trafficlightradar', + name='marked_as_removed_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_marked_as_removed', to=settings.AUTH_USER_MODEL, verbose_name='Marqué comme retiré par'), + ), + migrations.AddField( + model_name='trafficlightradar', + name='power_publiclighting_pole', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='powered_radars', to='assets.publiclightingpole', verbose_name='Public Lighting Pole (Power)'), + ), + migrations.AddField( + model_name='trafficlightradar', + name='power_trafficlights_pole', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='powered_radars', to='assets.trafficlightpole', verbose_name='Traffic Light Pole (Power)'), + ), + migrations.AddField( + model_name='trafficlightradar', + name='publiclighting_pole', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='radars', to='assets.publiclightingpole', verbose_name='Public Lighting Pole (Support)'), + ), + migrations.AddField( + model_name='trafficlightradar', + name='replaced_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='replaces', to='assets.trafficlightradar', verbose_name='Remplacé par'), + ), + migrations.AddField( + model_name='trafficlightradar', + name='trafficlights_pole', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='radars', to='assets.trafficlightpole', verbose_name='Traffic Light Pole (Support)'), + ), + migrations.AddField( + model_name='trafficlightradar', + name='updated_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Mis à jour par'), + ), + migrations.AddField( + model_name='trafficlightradarmodel', + name='category', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.assetcategory'), + ), + migrations.AddField( + model_name='trafficlightradar', + name='model', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='assets.trafficlightradarmodel'), + ), + migrations.AddField( + model_name='trafficlightradarpole', + name='category', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.assetcategory'), + ), + migrations.AddField( + model_name='trafficlightradarpole', + name='intersection', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='radar_poles', to='assets.trafficlightintersection'), + ), + migrations.AddField( + model_name='trafficlightradarpole', + name='marked_as_removed_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_marked_as_removed', to=settings.AUTH_USER_MODEL, verbose_name='Marqué comme retiré par'), + ), + migrations.AddField( + model_name='trafficlightradarpole', + name='replaced_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='replaces', to='assets.trafficlightradarpole', verbose_name='Remplacé par'), + ), + migrations.AddField( + model_name='trafficlightradarpole', + name='updated_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Mis à jour par'), + ), + migrations.AddField( + model_name='trafficlightradar', + name='pole', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='radars', to='assets.trafficlightradarpole', verbose_name='Radar Pole (Support)'), + ), + migrations.AddField( + model_name='trafficlightradarpolemodel', + name='category', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.assetcategory'), + ), + migrations.AddField( + model_name='trafficlightradarpole', + name='model', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.trafficlightradarpolemodel'), + ), migrations.AddField( model_name='trafficlightvoltagehardware', name='category', diff --git a/streetup/assets/migrations/0005_alter_artworkfountain_status_and_more.py b/streetup/assets/migrations/0005_alter_artworkfountain_status_and_more.py deleted file mode 100644 index 363e460..0000000 --- a/streetup/assets/migrations/0005_alter_artworkfountain_status_and_more.py +++ /dev/null @@ -1,188 +0,0 @@ -# Generated by Django 5.2.8 on 2026-05-23 05:45 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('assets', '0004_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='artworkfountain', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='artworkmonument', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='cleanglasscontainer', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='cleanlitterbin', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='controlcentergeoasset', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='itsgeoasset', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='naturebench', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='naturegreensurface', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='naturehollowgreenspace', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='natureshrub', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='naturetree', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='publiclightingelectricalcabinet', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='publiclightinglightfixture', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='publiclightingpole', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='roadconcreteblockset', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='roaddrain', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='roadfurniture', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='roadsidewalk', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='roadway', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='signpanel', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='signparkingspot', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='signpole', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='structuregeoasset', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='trafficlightaccessory', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='trafficlightcable', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='trafficlightcontroller', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='trafficlightcontrollerhardware', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='trafficlightdetector', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='trafficlightelectricalcabinet', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='trafficlightelectricalcabinetcontent', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='trafficlightlantern', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='trafficlightnetworkhardware', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='trafficlightpole', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='trafficlightprogramming', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='trafficlightvoltagehardware', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - ] diff --git a/streetup/assets/migrations/0006_naturegiepasset_naturegiepassetdocument.py b/streetup/assets/migrations/0006_naturegiepasset_naturegiepassetdocument.py deleted file mode 100644 index b12456f..0000000 --- a/streetup/assets/migrations/0006_naturegiepasset_naturegiepassetdocument.py +++ /dev/null @@ -1,92 +0,0 @@ -# Generated by Django 5.2.8 on 2026-05-27 09:44 - -import common.storages -import django.contrib.gis.db.models.fields -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('assets', '0005_alter_artworkfountain_status_and_more'), - ('documents', '0001_initial'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='NatureGIEPAsset', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('code', models.CharField(max_length=50)), - ('name_fr', models.CharField(blank=True, max_length=200, null=True)), - ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), - ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), - ('installation_date', models.DateTimeField(blank=True, null=True)), - ('uninstallation_date', models.DateTimeField(blank=True, null=True)), - ('serial_number', models.CharField(blank=True, max_length=200, null=True)), - ('warranty_duration', models.IntegerField(blank=True, null=True, verbose_name='Duration of the warranty (months)')), - ('last_inspection_date', models.DateTimeField(blank=True, null=True)), - ('last_preventive_date', models.DateTimeField(blank=True, null=True)), - ('last_corrective_date', models.DateTimeField(blank=True, null=True)), - ('last_survey_date', models.DateTimeField(blank=True, null=True)), - ('brand', models.CharField(blank=True, max_length=500, null=True)), - ('marked_as_removed_date', models.DateTimeField(blank=True, null=True, verbose_name='Date de marquage comme retiré')), - ('note', models.TextField(blank=True, null=True, verbose_name='Note')), - ('validation_status', models.CharField(blank=True, choices=[('to_be_validated', 'À valider'), ('validated', 'Validé'), ('to_be_completed', 'À compléter'), ('rejected', 'Rejeté')], max_length=50, null=True, verbose_name='Statut de validation')), - ('updated_at', models.DateTimeField(auto_now=True)), - ('lon', models.FloatField(blank=True, null=True)), - ('lat', models.FloatField(blank=True, null=True)), - ('geojson', models.TextField(blank=True, null=True)), - ('geom', django.contrib.gis.db.models.fields.GeometryField(blank=True, null=True, srid=3812)), - ('external_id', models.IntegerField(blank=True, null=True, verbose_name='External ID')), - ('code_name', models.CharField(blank=True, choices=[('AV', 'Stormwater inlet (Avaloir)'), ('BS', 'Sequenced border (Bordure séquencée)'), ('BI', "Injection port (Bouche d'injection)"), ('CA', 'Non-return valve (Clapet anti-retour)'), ('ES', 'Sedimentation (Empierrement sédimentation)'), ('KC', 'Kerb cell'), ('PI', "Infiltration well (Puits d'infiltration)"), ('SU', 'Overflow (Surverse)'), ('VI', "Isolation valve (Vanne d'isolation)"), ('VR', 'Control valve (Vanne de régulation)'), ('GT', 'Sidewalk gargoyle (Gargouille de trottoir)'), ('FE', "Trickle of water (Filet d'eau)"), ('AR', 'Rail drain (Avaloir de rail)'), ('BA', 'Leveled edge (Bordure arasée)'), ('CI', 'Infiltration channel (Caniveau infiltrant)'), ('D', 'Drain'), ('TP', 'Overflowing (Trop plein)'), ('RES', 'Separate sewer system (Réseau égout séparatif)'), ('EVC', 'Hollow green space (Espace vert creux)'), ('OED', 'Decentralized underground structure (Ouvrage enterré décentralisé)'), ('OSI', 'Work on an impermeable surface (Ouvrage sur surface imperméable)'), ('TA', 'Alternative technique (Technique alternative)'), ('OA', 'Supplementary work (Ouvrage annexe)')], max_length=50, null=True, verbose_name='Code name')), - ('structure_type', models.CharField(blank=True, choices=[('avaloir', 'Stormwater inlet (Avaloir)'), ('bordure sequencee', 'Sequenced border (Bordure séquencée)'), ('bouche injection', "Injection port (Bouche d'injection)"), ('clapet anti-retour', 'Non-return valve (Clapet anti-retour)'), ('empierrement sedimentation', 'Sedimentation (Empierrement sédimentation)'), ('kerb cell', 'Kerb cell'), ('puits infiltration', "Infiltration well (Puits d'infiltration)"), ('surverse', 'Overflow (Surverse)'), ('vanne isolation', "Isolation valve (Vanne d'isolation)"), ('vanne regulation', 'Control valve (Vanne de régulation)'), ('gargouille de trottoir', 'Sidewalk gargoyle (Gargouille de trottoir)'), ('filet eau', "Trickle of water (Filet d'eau)"), ('avaloir de rail', 'Rail drain (Avaloir de rail)'), ('bordure arasee', 'Leveled edge (Bordure arasée)'), ('caniveau infiltrant', 'Infiltration channel (Caniveau infiltrant)'), ('drain', 'Drain'), ('trop plein', 'Overflowing (Trop plein)'), ('reseau egout separatif', 'Separate sewer system (Réseau égout séparatif)'), ('bassin sec/infiltration', 'Dry/infiltration basin (Bassin sec/infiltration)'), ('bassin en eau', 'Wet basin (Bassin en eau)'), ('fosse', 'Ditch (Fossé)'), ('jardin de pluie', 'Rain garden (Jardin de pluie)'), ('noue', 'Swale (Noue)'), ('massif drainant', 'Draining structure (Massif drainant)'), ('tranchee drainante', 'Draining trench (Tranchée drainante)'), ('toiture stockante', 'Retention roof (Toiture stockante)'), ('toiture verte', 'Green roof (Toiture verte)'), ('bassin orage', "Stormwater basin (Bassin d'orage)"), ('SAUL-vide', 'SAUL-empty (SAUL-vide)'), ('SAUL-terre', 'SAUL-earth (SAUL-terre)'), ('citerne', 'Cistern (Citerne)'), ('espace vert sur dalle', 'Green space on slab (Espace vert sur dalle)'), ('bande filtrante', 'Filter strip (Bande filtrante)'), ('collecteur en beton poreux', 'Porous concrete collector (Collecteur en béton poreux)')], max_length=100, null=True, verbose_name='Structure type')), - ('project_manager', models.CharField(blank=True, choices=[('DPV', 'DPV'), ('DITP', 'DITP'), ('DEN', 'DEN'), ('DPO', 'DPO'), ('Beliris', 'Beliris'), ('Commune', 'Commune')], max_length=50, null=True, verbose_name='Project manager')), - ('location_precision', models.CharField(blank=True, choices=[('precise', 'Precise (Précise)'), ('supposee', 'Assumed (Supposée)')], max_length=50, null=True, verbose_name='Location precision')), - ('construction_status', models.CharField(blank=True, choices=[('etude', 'Design (Étude)'), ('travaux', 'Construction (Travaux)'), ('reception provisoire', 'Provisional acceptance (Réception provisoire)'), ('reception definitive', 'Final acceptance (Réception définitive)')], max_length=100, null=True, verbose_name='Construction status')), - ('commissioning_date', models.DateField(blank=True, null=True, verbose_name='Commissioning date')), - ('condition', models.CharField(blank=True, choices=[('bon', 'Good (Bon)'), ('examen a programmer', 'Inspection to schedule (Examen à programmer)'), ('intervention curative necessaire', 'Curative action needed (Intervention curative nécessaire)'), ('refection totale necessaire', 'Total rehabilitation needed (Réfection totale nécessaire)'), ('travaux entretien a realiser', 'Maintenance works to perform (Travaux entretien à réaliser)'), ('travaux maintenance', 'Maintenance works (Travaux maintenance)'), ('travaux maintenance a programmer', 'Maintenance works to schedule (Travaux maintenance à programmer)')], max_length=100, null=True, verbose_name='Condition')), - ('administrator', models.CharField(blank=True, max_length=500, null=True, verbose_name='Administrator')), - ('monitoring', models.CharField(blank=True, max_length=500, null=True, verbose_name='Monitoring')), - ('comment', models.TextField(blank=True, null=True, verbose_name='Comment')), - ('has_filter', models.BooleanField(blank=True, null=True, verbose_name='Has filter')), - ('sewer_connection', models.CharField(blank=True, choices=[('connecte', 'Connected (Connecté)'), ('non connecte', 'Not connected (Non connecté)')], max_length=50, null=True, verbose_name='Sewer connection')), - ('separate_network_connection', models.CharField(blank=True, choices=[('connecte', 'Connected (Connecté)'), ('non connecte', 'Not connected (Non connecté)')], max_length=50, null=True, verbose_name='Separate network connection')), - ('hydro_network_connection', models.CharField(blank=True, choices=[('connecte', 'Connected (Connecté)'), ('non connecte', 'Not connected (Non connecté)')], max_length=50, null=True, verbose_name='Hydro network connection')), - ('surface_area', models.FloatField(blank=True, null=True, verbose_name='Surface area (m²)')), - ('length', models.FloatField(blank=True, null=True, verbose_name='Length (m)')), - ('coating_category', models.CharField(blank=True, choices=[('Vegetal', 'Vegetal (Végétal)'), ('Structure enherbee', 'Grassed structure (Structure enherbée)'), ('Materiau non agrege', 'Unbound material (Matériau non agrégé)'), ('Structure a remplissage mineral', 'Mineral-filled structure (Structure à remplissage minéral)'), ('Revetement sureleve', 'Raised coating (Revêtement surélevé)'), ('Modulaire poreux', 'Porous modular (Modulaire poreux)'), ('Continu poreux', 'Porous continuous (Continu poreux)'), ('Impermeable', 'Impermeable (Imperméable)')], max_length=100, null=True, verbose_name='Coating category')), - ('coating_type', models.CharField(blank=True, choices=[('Pleine terre', 'Open soil (Pleine terre)'), ('Melange terre-pierre', 'Soil-stone mixture (Mélange terre-pierre)'), ('Paves a joints larges enherbes', 'Grassed wide-joint pavers (Pavés à joints larges enherbés)'), ('Dalles gazon en beton', 'Concrete grass grids (Dalles gazon en béton)'), ('Dalles alveolaires vegetalisees', 'Vegetated cellular tiles (Dalles alvéolaires végétalisées)'), ('Mulch vegetal', 'Woodchips/mulch (Mulch végétal)'), ('Graviers calcaires', 'Limestone gravel (Graviers calcaires)'), ('Graviers non calcaires', 'Non-limestone gravel (Graviers non calcaires)'), ('Terre battue', 'Dirt ground (Terre battue)'), ('Paves a joints larges engravillonnes', 'Gravel wide-joint pavers (Pavés à joints larges engravillonnés)'), ('Dalles alveolaires en gravier', 'Gravel cellular tiles (Dalles alvéolaires en gravier)'), ('Dalles en PEHD remplies de pave', 'HDPE tiles filled with pavers (Dalles en PEHD remplies de pavé)'), ('Grilles', 'Grates (Grilles)'), ('Platelages bois', 'Wooden decking (Platelages bois)'), ('Pave en beton poreux', 'Porous concrete pavers (Pavé en béton poreux)'), ('Dalle en beton poreux', 'Porous concrete slab (Dalle en béton poreux)'), ('Enrobes bitumineux poreux', 'Porous asphalt (Enrobés bitumineux poreux)'), ('Betons poreux', 'Porous concrete (Bétons poreux)'), ('Graviers lies a la resine', 'Resin-bound gravel (Graviers liés à la résine)'), ('Graviers concasses lies aux polymeres', 'Polymer-bound crushed gravel (Graviers concassés liés aux polymères)'), ('Revetements EPDM et ESBR', 'EPDM and SBR rubber coatings (Revêtements EPDM et ESBR)'), ('Revetements en beton de ciment non permeables', 'Non-porous cement concrete coatings (Revêtements en béton de ciment non perméables)'), ('Revetements bitumineux non permeables', 'Non-porous asphalt coatings (Revêtements bitumineux non perméables)'), ('Dallages non permeables', 'Non-porous tiling (Dallages non perméables)'), ('Pavages non permeables', 'Non-porous paving (Pavages non perméables)'), ('Autres revetements non permeables', 'Other non-porous coatings (Autres revêtements non perméables)')], max_length=100, null=True, verbose_name='Coating type')), - ('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.assetcategory')), - ('marked_as_removed_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_marked_as_removed', to=settings.AUTH_USER_MODEL, verbose_name='Marqué comme retiré par')), - ('replaced_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='replaces', to='assets.naturegiepasset', verbose_name='Remplacé par')), - ('updated_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Mis à jour par')), - ], - options={ - 'verbose_name': 'GIEP Asset', - 'verbose_name_plural': 'GIEP Assets', - }, - ), - migrations.CreateModel( - name='NatureGIEPAssetDocument', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('description', models.TextField(blank=True, null=True, verbose_name='Description du document')), - ('upload_date', models.DateTimeField(auto_now=True, verbose_name='Date de téléversement')), - ('status', models.CharField(choices=[('active', 'Actif'), ('archived', 'Archivé')], default='active')), - ('file', models.FileField(max_length=255, storage=common.storages.PrivateMediaStorage(), upload_to='assets_documents/nature/giep/', verbose_name='File')), - ('thumbnail', models.ImageField(blank=True, max_length=255, null=True, storage=common.storages.PrivateMediaStorage(), upload_to='assets_documents/nature/giep/')), - ('giep_asset', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='documents', to='assets.naturegiepasset', verbose_name='GIEP Asset')), - ('managed_document', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_sources', to='documents.manageddocument')), - ('uploaded_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Ajouté par')), - ], - options={ - 'verbose_name': 'GIEP Asset Document', - 'verbose_name_plural': 'GIEP Asset Documents', - }, - ), - ] diff --git a/streetup/assets/migrations/0007_remove_naturegiepassetdocument_giep_asset_and_more.py b/streetup/assets/migrations/0007_remove_naturegiepassetdocument_giep_asset_and_more.py deleted file mode 100644 index b59f290..0000000 --- a/streetup/assets/migrations/0007_remove_naturegiepassetdocument_giep_asset_and_more.py +++ /dev/null @@ -1,111 +0,0 @@ -# Generated by Django 5.2.8 on 2026-05-27 09:50 - -import common.storages -import django.contrib.gis.db.models.fields -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('assets', '0006_naturegiepasset_naturegiepassetdocument'), - ('documents', '0001_initial'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.RemoveField( - model_name='naturegiepassetdocument', - name='giep_asset', - ), - migrations.RemoveField( - model_name='naturegiepassetdocument', - name='managed_document', - ), - migrations.RemoveField( - model_name='naturegiepassetdocument', - name='uploaded_by', - ), - migrations.CreateModel( - name='NatureRWIAsset', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('code', models.CharField(max_length=50)), - ('name_fr', models.CharField(blank=True, max_length=200, null=True)), - ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), - ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), - ('installation_date', models.DateTimeField(blank=True, null=True)), - ('uninstallation_date', models.DateTimeField(blank=True, null=True)), - ('serial_number', models.CharField(blank=True, max_length=200, null=True)), - ('warranty_duration', models.IntegerField(blank=True, null=True, verbose_name='Duration of the warranty (months)')), - ('last_inspection_date', models.DateTimeField(blank=True, null=True)), - ('last_preventive_date', models.DateTimeField(blank=True, null=True)), - ('last_corrective_date', models.DateTimeField(blank=True, null=True)), - ('last_survey_date', models.DateTimeField(blank=True, null=True)), - ('brand', models.CharField(blank=True, max_length=500, null=True)), - ('marked_as_removed_date', models.DateTimeField(blank=True, null=True, verbose_name='Date de marquage comme retiré')), - ('note', models.TextField(blank=True, null=True, verbose_name='Note')), - ('validation_status', models.CharField(blank=True, choices=[('to_be_validated', 'À valider'), ('validated', 'Validé'), ('to_be_completed', 'À compléter'), ('rejected', 'Rejeté')], max_length=50, null=True, verbose_name='Statut de validation')), - ('updated_at', models.DateTimeField(auto_now=True)), - ('lon', models.FloatField(blank=True, null=True)), - ('lat', models.FloatField(blank=True, null=True)), - ('geojson', models.TextField(blank=True, null=True)), - ('geom', django.contrib.gis.db.models.fields.GeometryField(blank=True, null=True, srid=3812)), - ('external_id', models.IntegerField(blank=True, null=True, verbose_name='External ID')), - ('code_name', models.CharField(blank=True, choices=[('AV', 'Stormwater inlet (Avaloir)'), ('BS', 'Sequenced border (Bordure séquencée)'), ('BI', "Injection port (Bouche d'injection)"), ('CA', 'Non-return valve (Clapet anti-retour)'), ('ES', 'Sedimentation (Empierrement sédimentation)'), ('KC', 'Kerb cell'), ('PI', "Infiltration well (Puits d'infiltration)"), ('SU', 'Overflow (Surverse)'), ('VI', "Isolation valve (Vanne d'isolation)"), ('VR', 'Control valve (Vanne de régulation)'), ('GT', 'Sidewalk gargoyle (Gargouille de trottoir)'), ('FE', "Trickle of water (Filet d'eau)"), ('AR', 'Rail drain (Avaloir de rail)'), ('BA', 'Leveled edge (Bordure arasée)'), ('CI', 'Infiltration channel (Caniveau infiltrant)'), ('D', 'Drain'), ('TP', 'Overflowing (Trop plein)'), ('RES', 'Separate sewer system (Réseau égout séparatif)'), ('EVC', 'Hollow green space (Espace vert creux)'), ('OED', 'Decentralized underground structure (Ouvrage enterré décentralisé)'), ('OSI', 'Work on an impermeable surface (Ouvrage sur surface imperméable)'), ('TA', 'Alternative technique (Technique alternative)'), ('OA', 'Supplementary work (Ouvrage annexe)')], max_length=50, null=True, verbose_name='Code name')), - ('structure_type', models.CharField(blank=True, choices=[('avaloir', 'Stormwater inlet (Avaloir)'), ('bordure sequencee', 'Sequenced border (Bordure séquencée)'), ('bouche injection', "Injection port (Bouche d'injection)"), ('clapet anti-retour', 'Non-return valve (Clapet anti-retour)'), ('empierrement sedimentation', 'Sedimentation (Empierrement sédimentation)'), ('kerb cell', 'Kerb cell'), ('puits infiltration', "Infiltration well (Puits d'infiltration)"), ('surverse', 'Overflow (Surverse)'), ('vanne isolation', "Isolation valve (Vanne d'isolation)"), ('vanne regulation', 'Control valve (Vanne de régulation)'), ('gargouille de trottoir', 'Sidewalk gargoyle (Gargouille de trottoir)'), ('filet eau', "Trickle of water (Filet d'eau)"), ('avaloir de rail', 'Rail drain (Avaloir de rail)'), ('bordure arasee', 'Leveled edge (Bordure arasée)'), ('caniveau infiltrant', 'Infiltration channel (Caniveau infiltrant)'), ('drain', 'Drain'), ('trop plein', 'Overflowing (Trop plein)'), ('reseau egout separatif', 'Separate sewer system (Réseau égout séparatif)'), ('bassin sec/infiltration', 'Dry/infiltration basin (Bassin sec/infiltration)'), ('bassin en eau', 'Wet basin (Bassin en eau)'), ('fosse', 'Ditch (Fossé)'), ('jardin de pluie', 'Rain garden (Jardin de pluie)'), ('noue', 'Swale (Noue)'), ('massif drainant', 'Draining structure (Massif drainant)'), ('tranchee drainante', 'Draining trench (Tranchée drainante)'), ('toiture stockante', 'Retention roof (Toiture stockante)'), ('toiture verte', 'Green roof (Toiture verte)'), ('bassin orage', "Stormwater basin (Bassin d'orage)"), ('SAUL-vide', 'SAUL-empty (SAUL-vide)'), ('SAUL-terre', 'SAUL-earth (SAUL-terre)'), ('citerne', 'Cistern (Citerne)'), ('espace vert sur dalle', 'Green space on slab (Espace vert sur dalle)'), ('bande filtrante', 'Filter strip (Bande filtrante)'), ('collecteur en beton poreux', 'Porous concrete collector (Collecteur en béton poreux)')], max_length=100, null=True, verbose_name='Structure type')), - ('geometry_type', models.CharField(blank=True, choices=[('point', 'Point'), ('line', 'Line'), ('polygon', 'Polygon')], max_length=50, null=True, verbose_name='Geometry type')), - ('project_manager', models.CharField(blank=True, choices=[('DPV', 'DPV'), ('DITP', 'DITP'), ('DEN', 'DEN'), ('DPO', 'DPO'), ('Beliris', 'Beliris'), ('Commune', 'Commune')], max_length=50, null=True, verbose_name='Project manager')), - ('location_precision', models.CharField(blank=True, choices=[('precise', 'Precise (Précise)'), ('supposee', 'Assumed (Supposée)')], max_length=50, null=True, verbose_name='Location precision')), - ('construction_status', models.CharField(blank=True, choices=[('etude', 'Design (Étude)'), ('travaux', 'Construction (Travaux)'), ('reception provisoire', 'Provisional acceptance (Réception provisoire)'), ('reception definitive', 'Final acceptance (Réception définitive)')], max_length=100, null=True, verbose_name='Construction status')), - ('commissioning_date', models.DateField(blank=True, null=True, verbose_name='Commissioning date')), - ('condition', models.CharField(blank=True, choices=[('bon', 'Good (Bon)'), ('examen a programmer', 'Inspection to schedule (Examen à programmer)'), ('intervention curative necessaire', 'Curative action needed (Intervention curative nécessaire)'), ('refection totale necessaire', 'Total rehabilitation needed (Réfection totale nécessaire)'), ('travaux entretien a realiser', 'Maintenance works to perform (Travaux entretien à réaliser)'), ('travaux maintenance', 'Maintenance works (Travaux maintenance)'), ('travaux maintenance a programmer', 'Maintenance works to schedule (Travaux maintenance à programmer)')], max_length=100, null=True, verbose_name='Condition')), - ('administrator', models.CharField(blank=True, max_length=500, null=True, verbose_name='Administrator')), - ('monitoring', models.CharField(blank=True, max_length=500, null=True, verbose_name='Monitoring')), - ('comment', models.TextField(blank=True, null=True, verbose_name='Comment')), - ('has_filter', models.BooleanField(blank=True, null=True, verbose_name='Has filter')), - ('sewer_connection', models.CharField(blank=True, choices=[('connecte', 'Connected (Connecté)'), ('non connecte', 'Not connected (Non connecté)')], max_length=50, null=True, verbose_name='Sewer connection')), - ('separate_network_connection', models.CharField(blank=True, choices=[('connecte', 'Connected (Connecté)'), ('non connecte', 'Not connected (Non connecté)')], max_length=50, null=True, verbose_name='Separate network connection')), - ('hydro_network_connection', models.CharField(blank=True, choices=[('connecte', 'Connected (Connecté)'), ('non connecte', 'Not connected (Non connecté)')], max_length=50, null=True, verbose_name='Hydro network connection')), - ('surface_area', models.FloatField(blank=True, null=True, verbose_name='Surface area (m²)')), - ('length', models.FloatField(blank=True, null=True, verbose_name='Length (m)')), - ('coating_category', models.CharField(blank=True, choices=[('Vegetal', 'Vegetal (Végétal)'), ('Structure enherbee', 'Grassed structure (Structure enherbée)'), ('Materiau non agrege', 'Unbound material (Matériau non agrégé)'), ('Structure a remplissage mineral', 'Mineral-filled structure (Structure à remplissage minéral)'), ('Revetement sureleve', 'Raised coating (Revêtement surélevé)'), ('Modulaire poreux', 'Porous modular (Modulaire poreux)'), ('Continu poreux', 'Porous continuous (Continu poreux)'), ('Impermeable', 'Impermeable (Imperméable)')], max_length=100, null=True, verbose_name='Coating category')), - ('coating_type', models.CharField(blank=True, choices=[('Pleine terre', 'Open soil (Pleine terre)'), ('Melange terre-pierre', 'Soil-stone mixture (Mélange terre-pierre)'), ('Paves a joints larges enherbes', 'Grassed wide-joint pavers (Pavés à joints larges enherbés)'), ('Dalles gazon en beton', 'Concrete grass grids (Dalles gazon en béton)'), ('Dalles alveolaires vegetalisees', 'Vegetated cellular tiles (Dalles alvéolaires végétalisées)'), ('Mulch vegetal', 'Woodchips/mulch (Mulch végétal)'), ('Graviers calcaires', 'Limestone gravel (Graviers calcaires)'), ('Graviers non calcaires', 'Non-limestone gravel (Graviers non calcaires)'), ('Terre battue', 'Dirt ground (Terre battue)'), ('Paves a joints larges engravillonnes', 'Gravel wide-joint pavers (Pavés à joints larges engravillonnés)'), ('Dalles alveolaires en gravier', 'Gravel cellular tiles (Dalles alvéolaires en gravier)'), ('Dalles en PEHD remplies de pave', 'HDPE tiles filled with pavers (Dalles en PEHD remplies de pavé)'), ('Grilles', 'Grates (Grilles)'), ('Platelages bois', 'Wooden decking (Platelages bois)'), ('Pave en beton poreux', 'Porous concrete pavers (Pavé en béton poreux)'), ('Dalle en beton poreux', 'Porous concrete slab (Dalle en béton poreux)'), ('Enrobes bitumineux poreux', 'Porous asphalt (Enrobés bitumineux poreux)'), ('Betons poreux', 'Porous concrete (Bétons poreux)'), ('Graviers lies a la resine', 'Resin-bound gravel (Graviers liés à la résine)'), ('Graviers concasses lies aux polymeres', 'Polymer-bound crushed gravel (Graviers concassés liés aux polymères)'), ('Revetements EPDM et ESBR', 'EPDM and SBR rubber coatings (Revêtements EPDM et ESBR)'), ('Revetements en beton de ciment non permeables', 'Non-porous cement concrete coatings (Revêtements en béton de ciment non perméables)'), ('Revetements bitumineux non permeables', 'Non-porous asphalt coatings (Revêtements bitumineux non perméables)'), ('Dallages non permeables', 'Non-porous tiling (Dallages non perméables)'), ('Pavages non permeables', 'Non-porous paving (Pavages non perméables)'), ('Autres revetements non permeables', 'Other non-porous coatings (Autres revêtements non perméables)')], max_length=100, null=True, verbose_name='Coating type')), - ('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.assetcategory')), - ('marked_as_removed_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_marked_as_removed', to=settings.AUTH_USER_MODEL, verbose_name='Marqué comme retiré par')), - ('replaced_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='replaces', to='assets.naturerwiasset', verbose_name='Remplacé par')), - ('updated_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Mis à jour par')), - ], - options={ - 'verbose_name': 'RWI Asset', - 'verbose_name_plural': 'RWI Assets', - }, - ), - migrations.CreateModel( - name='NatureRWIAssetDocument', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('description', models.TextField(blank=True, null=True, verbose_name='Description du document')), - ('upload_date', models.DateTimeField(auto_now=True, verbose_name='Date de téléversement')), - ('status', models.CharField(choices=[('active', 'Actif'), ('archived', 'Archivé')], default='active')), - ('file', models.FileField(max_length=255, storage=common.storages.PrivateMediaStorage(), upload_to='assets_documents/nature/rwi/', verbose_name='File')), - ('thumbnail', models.ImageField(blank=True, max_length=255, null=True, storage=common.storages.PrivateMediaStorage(), upload_to='assets_documents/nature/rwi/')), - ('managed_document', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_sources', to='documents.manageddocument')), - ('rwi_asset', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='documents', to='assets.naturerwiasset', verbose_name='RWI Asset')), - ('uploaded_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='Ajouté par')), - ], - options={ - 'verbose_name': 'RWI Asset Document', - 'verbose_name_plural': 'RWI Asset Documents', - }, - ), - migrations.DeleteModel( - name='NatureGIEPAsset', - ), - migrations.DeleteModel( - name='NatureGIEPAssetDocument', - ), - ] diff --git a/streetup/assets/migrations/0008_delete_naturehollowgreenspace.py b/streetup/assets/migrations/0008_delete_naturehollowgreenspace.py deleted file mode 100644 index 49c35d4..0000000 --- a/streetup/assets/migrations/0008_delete_naturehollowgreenspace.py +++ /dev/null @@ -1,16 +0,0 @@ -# Generated by Django 5.2.8 on 2026-05-27 12:12 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('assets', '0007_remove_naturegiepassetdocument_giep_asset_and_more'), - ] - - operations = [ - migrations.DeleteModel( - name='NatureHollowGreenSpace', - ), - ] diff --git a/streetup/assets/migrations/0009_signpaneltype_default_diameter_and_more.py b/streetup/assets/migrations/0009_signpaneltype_default_diameter_and_more.py deleted file mode 100644 index 6435f8c..0000000 --- a/streetup/assets/migrations/0009_signpaneltype_default_diameter_and_more.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 5.2.8 on 2026-05-30 13:30 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('assets', '0008_delete_naturehollowgreenspace'), - ] - - operations = [ - migrations.AddField( - model_name='signpaneltype', - name='default_diameter', - field=models.FloatField(blank=True, null=True, verbose_name='Diamètre par défaut (cm)'), - ), - migrations.AddField( - model_name='signpaneltype', - name='default_height', - field=models.FloatField(blank=True, null=True, verbose_name='Hauteur par défaut (cm)'), - ), - migrations.AddField( - model_name='signpaneltype', - name='default_width', - field=models.FloatField(blank=True, null=True, verbose_name='Largeur par défaut (cm)'), - ), - ] diff --git a/streetup/assets/migrations/0010_trafficlightradarmodel_trafficlightradar.py b/streetup/assets/migrations/0010_trafficlightradarmodel_trafficlightradar.py deleted file mode 100644 index 236e146..0000000 --- a/streetup/assets/migrations/0010_trafficlightradarmodel_trafficlightradar.py +++ /dev/null @@ -1,71 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-22 08:31 - -import django.contrib.gis.db.models.fields -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('assets', '0009_signpaneltype_default_diameter_and_more'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='TrafficLightRadarModel', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('code', models.CharField(max_length=50)), - ('name_fr', models.CharField(blank=True, max_length=200, null=True)), - ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('description', models.TextField(blank=True, null=True)), - ('brand', models.CharField(blank=True, max_length=500, null=True)), - ('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.assetcategory')), - ], - options={ - 'verbose_name': 'Traffic Light Radar Model', - 'verbose_name_plural': 'Traffic Light Radar Models', - }, - ), - migrations.CreateModel( - name='TrafficLightRadar', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('code', models.CharField(max_length=50)), - ('name_fr', models.CharField(blank=True, max_length=200, null=True)), - ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), - ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), - ('installation_date', models.DateTimeField(blank=True, null=True)), - ('uninstallation_date', models.DateTimeField(blank=True, null=True)), - ('serial_number', models.CharField(blank=True, max_length=200, null=True)), - ('warranty_duration', models.IntegerField(blank=True, null=True, verbose_name='Duration of the warranty (months)')), - ('last_inspection_date', models.DateTimeField(blank=True, null=True)), - ('last_preventive_date', models.DateTimeField(blank=True, null=True)), - ('last_corrective_date', models.DateTimeField(blank=True, null=True)), - ('last_survey_date', models.DateTimeField(blank=True, null=True)), - ('brand', models.CharField(blank=True, max_length=500, null=True)), - ('marked_as_removed_date', models.DateTimeField(blank=True, null=True, verbose_name='Date de marquage comme retiré')), - ('note', models.TextField(blank=True, null=True, verbose_name='Note')), - ('validation_status', models.CharField(blank=True, choices=[('to_be_validated', 'À valider'), ('validated', 'Validé'), ('to_be_completed', 'À compléter'), ('rejected', 'Rejeté')], max_length=50, null=True, verbose_name='Statut de validation')), - ('updated_at', models.DateTimeField(auto_now=True)), - ('lon', models.FloatField(blank=True, null=True)), - ('lat', models.FloatField(blank=True, null=True)), - ('geom', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=3812)), - ('geojson', models.TextField(blank=True, null=True)), - ('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.assetcategory')), - ('intersection', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='radars', to='assets.trafficlightintersection')), - ('marked_as_removed_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_marked_as_removed', to=settings.AUTH_USER_MODEL, verbose_name='Marqué comme retiré par')), - ('replaced_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='replaces', to='assets.trafficlightradar', verbose_name='Remplacé par')), - ('updated_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Mis à jour par')), - ('model', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='assets.trafficlightradarmodel')), - ], - options={ - 'verbose_name': 'Radar', - 'verbose_name_plural': 'Radars', - }, - ), - ] diff --git a/streetup/assets/migrations/0011_create_radar_preventif_category.py b/streetup/assets/migrations/0011_create_radar_preventif_category.py deleted file mode 100644 index cd776a5..0000000 --- a/streetup/assets/migrations/0011_create_radar_preventif_category.py +++ /dev/null @@ -1,44 +0,0 @@ -from django.db import migrations - -def create_radar_preventif_category(apps, schema_editor): - Thematic = apps.get_model('common', 'Thematic') - AssetCategory = apps.get_model('assets', 'AssetCategory') - - # Get trafficlights thematic - try: - tl_thematic = Thematic.objects.get(code='trafficlights') - except Thematic.DoesNotExist: - tl_thematic = Thematic.objects.create( - code='trafficlights', - name_fr='Feux de signalisation', - name_nl='Verkeerslichten' - ) - - # Get or create radar_preventif category - category, created = AssetCategory.objects.get_or_create( - code='TL_RADAR_PREVENTIF', - defaults={ - 'name_fr': 'Radar Préventif', - 'name_nl': 'Preventieve radar', - 'thematic': tl_thematic - } - ) - if not created and category.thematic != tl_thematic: - category.thematic = tl_thematic - category.save() - -def reverse_radar_preventif_category(apps, schema_editor): - AssetCategory = apps.get_model('assets', 'AssetCategory') - AssetCategory.objects.filter(code='TL_RADAR_PREVENTIF').delete() - - -class Migration(migrations.Migration): - - dependencies = [ - ('assets', '0010_trafficlightradarmodel_trafficlightradar'), - ('common', '0001_initial'), - ] - - operations = [ - migrations.RunPython(create_radar_preventif_category, reverse_radar_preventif_category), - ] diff --git a/streetup/assets/migrations/0012_trafficlightintersection_is_radar.py b/streetup/assets/migrations/0012_trafficlightintersection_is_radar.py deleted file mode 100644 index 269e1f7..0000000 --- a/streetup/assets/migrations/0012_trafficlightintersection_is_radar.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-22 12:43 - -from django.db import migrations, models - - -def populate_is_radar(apps, schema_editor): - TrafficLightIntersection = apps.get_model('assets', 'TrafficLightIntersection') - TrafficLightRadar = apps.get_model('assets', 'TrafficLightRadar') - - # Intersections linked to at least one radar are radar intersections - radar_intersection_ids = TrafficLightRadar.objects.filter(intersection__isnull=False).values_list('intersection_id', flat=True).distinct() - TrafficLightIntersection.objects.filter(id__in=radar_intersection_ids).update(is_radar=True) - - -class Migration(migrations.Migration): - - dependencies = [ - ('assets', '0011_create_radar_preventif_category'), - ] - - operations = [ - migrations.AddField( - model_name='trafficlightintersection', - name='is_radar', - field=models.BooleanField(default=False, verbose_name='Est un radar ?'), - ), - migrations.RunPython(populate_is_radar, migrations.RunPython.noop), - ] diff --git a/streetup/assets/migrations/0013_update_rwi_assets_codification.py b/streetup/assets/migrations/0013_update_rwi_assets_codification.py deleted file mode 100644 index 55ac786..0000000 --- a/streetup/assets/migrations/0013_update_rwi_assets_codification.py +++ /dev/null @@ -1,169 +0,0 @@ -from django.db import migrations - -def update_rwi_codes(apps, schema_editor): - NatureRWIAsset = apps.get_model('assets', 'NatureRWIAsset') - - # We try-catch the GuidedOperationData import because it's in another app, - # and we want to ensure robust execution. - try: - GuidedOperationData = apps.get_model('interventions', 'GuidedOperationData') - except LookupError: - GuidedOperationData = None - - # Mappings from structure type to acronym - mappings = { - 'avaloir': 'AV', - 'bordure sequencee': 'BS', - 'bouche injection': 'BI', - 'clapet anti-retour': 'CA', - 'empierrement sedimentation': 'ES', - 'kerb cell': 'KC', - 'puits infiltration': 'PI', - 'surverse': 'SU', - 'vanne isolation': 'VI', - 'vanne regulation': 'VR', - 'gargouille de trottoir': 'GT', - 'filet eau': 'FE', - 'avaloir de rail': 'AR', - 'bordure arasee': 'BA', - 'caniveau infiltrant': 'CI', - 'drain': 'D', - 'trop plein': 'TP', - 'reseau egout separatif': 'RES', - 'bassin sec/infiltration': 'OED', - 'bassin en eau': 'OED', - 'fosse': 'EVC', - 'jardin de pluie': 'EVC', - 'noue': 'EVC', - 'massif drainant': 'OED', - 'tranchee drainante': 'OED', - 'toiture stockante': 'OSI', - 'toiture verte': 'OSI', - 'bassin orage': 'OED', - 'SAUL-vide': 'OED', - 'SAUL-terre': 'TA', - 'citerne': 'OED', - 'espace vert sur dalle': 'EVC', - 'bande filtrante': 'EVC', - 'collecteur en beton poreux': 'OED', - 'chambre de visite': 'CV', - } - - code_updates = {} - - for asset in NatureRWIAsset.objects.all(): - old_code = asset.code - - # Calculate acronym - struct_type_lower = asset.structure_type.strip().lower() if asset.structure_type else None - - acronym = None - if asset.code_name: - acronym = asset.code_name.strip().upper() - elif struct_type_lower in mappings: - acronym = mappings[struct_type_lower] - elif asset.geometry_type: - acronym = asset.geometry_type.upper() - else: - acronym = 'UNK' - - fid = asset.external_id or asset.id - new_code = f"RWI_{acronym}_{fid:03d}" - - if old_code != new_code: - asset.code = new_code - if asset.name_fr == old_code: - asset.name_fr = new_code - if asset.name_nl == old_code: - asset.name_nl = new_code - asset.save(update_fields=['code', 'name_fr', 'name_nl']) - code_updates[old_code] = new_code - - # Update GuidedOperationData JSON references - if GuidedOperationData and code_updates: - for gd in GuidedOperationData.objects.all(): - modified = False - data = gd.data - if not isinstance(data, dict): - continue - - def replace_codes(obj): - nonlocal modified - if isinstance(obj, dict): - for k, v in list(obj.items()): - if k == 'rwi_asset_code' and v in code_updates: - obj[k] = code_updates[v] - modified = True - else: - replace_codes(v) - elif isinstance(obj, list): - for item in obj: - replace_codes(item) - - replace_codes(data) - if modified: - gd.data = data - gd.save(update_fields=['data']) - -def reverse_rwi_codes(apps, schema_editor): - NatureRWIAsset = apps.get_model('assets', 'NatureRWIAsset') - try: - GuidedOperationData = apps.get_model('interventions', 'GuidedOperationData') - except LookupError: - GuidedOperationData = None - - code_updates_reverse = {} - - for asset in NatureRWIAsset.objects.all(): - old_code = asset.code - - # Calculate old format: RWI_{geometry_type.upper()}_{external_id:03d} - geom_type_upper = asset.geometry_type.upper() if asset.geometry_type else 'POLYGON' - fid = asset.external_id or asset.id - original_code = f"RWI_{geom_type_upper}_{fid:03d}" - - if old_code != original_code: - asset.code = original_code - if asset.name_fr == old_code: - asset.name_fr = original_code - if asset.name_nl == old_code: - asset.name_nl = original_code - asset.save(update_fields=['code', 'name_fr', 'name_nl']) - code_updates_reverse[old_code] = original_code - - # Revert GuidedOperationData JSON references - if GuidedOperationData and code_updates_reverse: - for gd in GuidedOperationData.objects.all(): - modified = False - data = gd.data - if not isinstance(data, dict): - continue - - def replace_codes(obj): - nonlocal modified - if isinstance(obj, dict): - for k, v in list(obj.items()): - if k == 'rwi_asset_code' and v in code_updates_reverse: - obj[k] = code_updates_reverse[v] - modified = True - else: - replace_codes(v) - elif isinstance(obj, list): - for item in obj: - replace_codes(item) - - replace_codes(data) - if modified: - gd.data = data - gd.save(update_fields=['data']) - - -class Migration(migrations.Migration): - - dependencies = [ - ('assets', '0012_trafficlightintersection_is_radar'), - ] - - operations = [ - migrations.RunPython(update_rwi_codes, reverse_rwi_codes), - ] diff --git a/streetup/assets/migrations/0014_remove_nature_rwi_asset_location_precision.py b/streetup/assets/migrations/0014_remove_nature_rwi_asset_location_precision.py deleted file mode 100644 index f4eed05..0000000 --- a/streetup/assets/migrations/0014_remove_nature_rwi_asset_location_precision.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-25 12:13 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('assets', '0013_update_rwi_assets_codification'), - ] - - operations = [ - migrations.RemoveField( - model_name='naturerwiasset', - name='location_precision', - ), - ] diff --git a/streetup/assets/migrations/0015_trafficlightradar_pole.py b/streetup/assets/migrations/0015_trafficlightradar_pole.py deleted file mode 100644 index 00b85ad..0000000 --- a/streetup/assets/migrations/0015_trafficlightradar_pole.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-26 12:23 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('assets', '0014_remove_nature_rwi_asset_location_precision'), - ] - - operations = [ - migrations.AddField( - model_name='trafficlightradar', - name='pole', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='radars', to='assets.publiclightingpole'), - ), - ] diff --git a/streetup/assets/migrations/0016_trafficlightradar_publiclighting_pole_and_more.py b/streetup/assets/migrations/0016_trafficlightradar_publiclighting_pole_and_more.py deleted file mode 100644 index f058390..0000000 --- a/streetup/assets/migrations/0016_trafficlightradar_publiclighting_pole_and_more.py +++ /dev/null @@ -1,91 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-26 12:41 - -import django.contrib.gis.db.models.fields -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('assets', '0015_trafficlightradar_pole'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.AddField( - model_name='trafficlightradar', - name='publiclighting_pole', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='radars', to='assets.publiclightingpole'), - ), - migrations.AddField( - model_name='trafficlightradar', - name='trafficlights_pole', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='radars', to='assets.trafficlightpole'), - ), - migrations.CreateModel( - name='TrafficLightRadarPole', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('code', models.CharField(max_length=50)), - ('name_fr', models.CharField(blank=True, max_length=200, null=True)), - ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), - ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), - ('installation_date', models.DateTimeField(blank=True, null=True)), - ('uninstallation_date', models.DateTimeField(blank=True, null=True)), - ('serial_number', models.CharField(blank=True, max_length=200, null=True)), - ('warranty_duration', models.IntegerField(blank=True, null=True, verbose_name='Duration of the warranty (months)')), - ('last_inspection_date', models.DateTimeField(blank=True, null=True)), - ('last_preventive_date', models.DateTimeField(blank=True, null=True)), - ('last_corrective_date', models.DateTimeField(blank=True, null=True)), - ('last_survey_date', models.DateTimeField(blank=True, null=True)), - ('brand', models.CharField(blank=True, max_length=500, null=True)), - ('marked_as_removed_date', models.DateTimeField(blank=True, null=True, verbose_name='Date de marquage comme retiré')), - ('note', models.TextField(blank=True, null=True, verbose_name='Note')), - ('validation_status', models.CharField(blank=True, choices=[('to_be_validated', 'À valider'), ('validated', 'Validé'), ('to_be_completed', 'À compléter'), ('rejected', 'Rejeté')], max_length=50, null=True, verbose_name='Statut de validation')), - ('updated_at', models.DateTimeField(auto_now=True)), - ('lon', models.FloatField(blank=True, null=True)), - ('lat', models.FloatField(blank=True, null=True)), - ('geom', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=3812)), - ('geojson', models.TextField(blank=True, null=True)), - ('colour', models.CharField(blank=True, max_length=200, null=True, verbose_name='Couleur')), - ('ral', models.CharField(blank=True, max_length=200, null=True, verbose_name='RAL')), - ('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.assetcategory')), - ('intersection', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='radar_poles', to='assets.trafficlightintersection')), - ('marked_as_removed_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_marked_as_removed', to=settings.AUTH_USER_MODEL, verbose_name='Marqué comme retiré par')), - ('replaced_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='replaces', to='assets.trafficlightradarpole', verbose_name='Remplacé par')), - ('updated_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Mis à jour par')), - ], - options={ - 'verbose_name': 'Radar Pole', - 'verbose_name_plural': 'Radar Poles', - }, - ), - migrations.AlterField( - model_name='trafficlightradar', - name='pole', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='radars', to='assets.trafficlightradarpole'), - ), - migrations.CreateModel( - name='TrafficLightRadarPoleModel', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('code', models.CharField(max_length=50)), - ('name_fr', models.CharField(blank=True, max_length=200, null=True)), - ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('description', models.TextField(blank=True, null=True)), - ('brand', models.CharField(blank=True, max_length=500, null=True)), - ('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.assetcategory')), - ], - options={ - 'abstract': False, - }, - ), - migrations.AddField( - model_name='trafficlightradarpole', - name='model', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='assets.trafficlightradarpolemodel'), - ), - ] diff --git a/streetup/assets/migrations/0017_create_radar_pole_category.py b/streetup/assets/migrations/0017_create_radar_pole_category.py deleted file mode 100644 index c6328c2..0000000 --- a/streetup/assets/migrations/0017_create_radar_pole_category.py +++ /dev/null @@ -1,44 +0,0 @@ -from django.db import migrations - -def create_radar_pole_category(apps, schema_editor): - Thematic = apps.get_model('common', 'Thematic') - AssetCategory = apps.get_model('assets', 'AssetCategory') - - # Get trafficlights thematic - try: - tl_thematic = Thematic.objects.get(code='trafficlights') - except Thematic.DoesNotExist: - tl_thematic = Thematic.objects.create( - code='trafficlights', - name_fr='Feux de signalisation', - name_nl='Verkeerslichten' - ) - - # Get or create radar_pole category - category, created = AssetCategory.objects.get_or_create( - code='TL_RADAR_POLE', - defaults={ - 'name_fr': 'Poteau radar', - 'name_nl': 'Radarpaal', - 'thematic': tl_thematic - } - ) - if not created and category.thematic != tl_thematic: - category.thematic = tl_thematic - category.save() - -def reverse_radar_pole_category(apps, schema_editor): - AssetCategory = apps.get_model('assets', 'AssetCategory') - AssetCategory.objects.filter(code='TL_RADAR_POLE').delete() - - -class Migration(migrations.Migration): - - dependencies = [ - ('assets', '0016_trafficlightradar_publiclighting_pole_and_more'), - ('common', '0001_initial'), - ] - - operations = [ - migrations.RunPython(create_radar_pole_category, reverse_radar_pole_category), - ] diff --git a/streetup/assets/migrations/0018_alter_publiclightingpole_options_and_more.py b/streetup/assets/migrations/0018_alter_publiclightingpole_options_and_more.py deleted file mode 100644 index a01e226..0000000 --- a/streetup/assets/migrations/0018_alter_publiclightingpole_options_and_more.py +++ /dev/null @@ -1,27 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-26 16:22 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('assets', '0017_create_radar_pole_category'), - ('contenttypes', '0002_remove_content_type_name'), - ] - - operations = [ - migrations.AlterModelOptions( - name='publiclightingpole', - options={'verbose_name': 'Public lighting pole', 'verbose_name_plural': 'Public lighting poles'}, - ), - migrations.AlterModelOptions( - name='trafficlightpole', - options={'verbose_name': 'Traffic light pole', 'verbose_name_plural': 'Traffic light poles'}, - ), - migrations.AddField( - model_name='assetcategory', - name='allowed_models', - field=models.ManyToManyField(blank=True, help_text="Les types de modèles d'assets (Django) autorisés pour cette catégorie.", related_name='asset_categories', to='contenttypes.contenttype', verbose_name='Modèles Django autorisés'), - ), - ] diff --git a/streetup/assets/migrations/0019_populate_assetcategory_allowed_models.py b/streetup/assets/migrations/0019_populate_assetcategory_allowed_models.py deleted file mode 100644 index 73014a4..0000000 --- a/streetup/assets/migrations/0019_populate_assetcategory_allowed_models.py +++ /dev/null @@ -1,70 +0,0 @@ -from django.db import migrations - -def populate_allowed_models(apps, schema_editor): - AssetCategory = apps.get_model('assets', 'AssetCategory') - ContentType = apps.get_model('contenttypes', 'ContentType') - - # Mapping of category codes to Django model name strings (lowercase) - mapping = { - # Traffic lights - 'TL_POTEAU': ['trafficlightpole'], - 'TL_CABLE': ['trafficlightcable'], - 'TL_LANTERNE': ['trafficlightlantern'], - 'TL_REGELAAR': ['trafficlightcontroller'], - 'TL_ARMOIRE': ['trafficlightelectricalcabinet'], - 'TL_DETEC_BP': ['trafficlightdetector'], - 'TL_DETEC_RADAR': ['trafficlightdetector'], - 'TL_DETEC_VIDEO': ['trafficlightdetector'], - 'TL_DETEC_OTHER': ['trafficlightdetector'], - 'TL_BORNIER': ['trafficlightaccessory'], - 'TL_DIVERS': ['trafficlightaccessory'], - 'TL_RADAR_PREVENTIF': ['trafficlightradar'], - 'TL_RADAR_POLE': ['trafficlightradarpole'], - - # Public lighting - 'LI_poles': ['publiclightingpole'], - 'LI_lightfixtures': ['publiclightinglightfixture'], - 'LI_electrical_cabinets': ['publiclightingelectricalcabinet'], - - # Cleanliness - 'CL_BASKET': ['cleanlitterbin'], - 'CL_BUBBLE': ['cleanglasscontainer'], - - # Nature - 'NAT_GREEN_AREAS': ['naturegreensurface'], - 'NAT_TREES': ['naturetree'], - 'NAT_RWI': ['naturerwiasset'], - 'NAT_FURNITURES': ['naturebench', 'natureshrub'], - - # Artworks - 'ART_MONUMENT': ['artworkmonument'], - 'ART_FONTAIN': ['artworkfountain'], - } - - for category_code, model_names in mapping.items(): - try: - category = AssetCategory.objects.get(code=category_code) - for model_name in model_names: - try: - ct = ContentType.objects.get(app_label='assets', model=model_name) - category.allowed_models.add(ct) - except ContentType.DoesNotExist: - print(f"ContentType assets.{model_name} not found.") - except AssetCategory.DoesNotExist: - pass - -def clear_allowed_models(apps, schema_editor): - AssetCategory = apps.get_model('assets', 'AssetCategory') - for category in AssetCategory.objects.all(): - category.allowed_models.clear() - - -class Migration(migrations.Migration): - - dependencies = [ - ('assets', '0018_alter_publiclightingpole_options_and_more'), - ] - - operations = [ - migrations.RunPython(populate_allowed_models, clear_allowed_models), - ] diff --git a/streetup/assets/migrations/0020_alter_trafficlightradarpole_model.py b/streetup/assets/migrations/0020_alter_trafficlightradarpole_model.py deleted file mode 100644 index c77ae52..0000000 --- a/streetup/assets/migrations/0020_alter_trafficlightradarpole_model.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-27 07:05 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('assets', '0019_populate_assetcategory_allowed_models'), - ] - - operations = [ - migrations.AlterField( - model_name='trafficlightradarpole', - name='model', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.trafficlightradarpolemodel'), - ), - ] diff --git a/streetup/assets/migrations/0021_set_default_validation_status_for_active.py b/streetup/assets/migrations/0021_set_default_validation_status_for_active.py deleted file mode 100644 index ce2054e..0000000 --- a/streetup/assets/migrations/0021_set_default_validation_status_for_active.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 5.2.8 on 2026-07-03 09:16 - -from django.db import migrations - - -def set_default_validation_status(apps, schema_editor): - model_names = [ - 'trafficlightpole', 'trafficlightcable', 'trafficlightlantern', 'trafficlightcontroller', - 'trafficlightcontrollerhardware', 'trafficlightdetector', 'trafficlightnetworkhardware', - 'trafficlightvoltagehardware', 'trafficlightelectricalcabinet', 'trafficlightelectricalcabinetcontent', - 'trafficlightaccessory', 'trafficlightprogramming', 'trafficlightradarpole', 'trafficlightradar', - 'publiclightingpole', 'publiclightinglightfixture', 'publiclightingelectricalcabinet', 'artworkmonument', - 'artworkfountain', 'naturegreensurface', 'naturetree', 'natureshrub', 'naturebench', - 'naturerwiasset', 'structuregeoasset', 'controlcentergeoasset', 'signpole', 'signpanel', - 'signparkingspot', 'roadway', 'roadsidewalk', 'roadfurniture', 'roadconcreteblockset', - 'roaddrain', 'itsgeoasset', 'cleanlitterbin', 'cleanglasscontainer' - ] - for model_name in model_names: - try: - Model = apps.get_model('assets', model_name) - # Update all active assets with no validation status to 'validated' - Model.objects.filter(status='active', validation_status__isnull=True).update(validation_status='validated') - Model.objects.filter(status='active', validation_status='').update(validation_status='validated') - except LookupError: - pass - -def reverse_default_validation_status(apps, schema_editor): - pass - - -class Migration(migrations.Migration): - - dependencies = [ - ('assets', '0020_alter_trafficlightradarpole_model'), - ] - - operations = [ - migrations.RunPython(set_default_validation_status, reverse_default_validation_status), - ] diff --git a/streetup/assets/migrations/0022_sync_trafficlights_documents.py b/streetup/assets/migrations/0022_sync_trafficlights_documents.py deleted file mode 100644 index 54d4fee..0000000 --- a/streetup/assets/migrations/0022_sync_trafficlights_documents.py +++ /dev/null @@ -1,48 +0,0 @@ -# Generated by hand - -from django.db import migrations - -def sync_trafficlights_documents(apps, schema_editor): - from assets.models import TrafficLightIntersection as ActiveIntersection, TrafficLightIntersectionDocument as ActiveIntersectionDoc - from assets.views.trafficlights import ensure_intersection_document_folder, generate_dxf_overlay_managed_document - from documents.models import ensure_document_for_legacy - - for intersection in ActiveIntersection.objects.all(): - try: - ensure_intersection_document_folder(intersection) - except Exception as e: - print(f"Error ensuring document folder for intersection {intersection.id}: {e}") - - for doc in ActiveIntersectionDoc.objects.all(): - try: - import os - if not doc.file or not doc.file.name: - continue - - # If the file does not exist on disk, we skip it gracefully - if not os.path.exists(doc.file.path): - print(f"Migration: File not found on disk, skipping sync for {doc.file.name}") - continue - - # Sync it to the ManagedDocument system - ensure_document_for_legacy(doc) - - # If it's a DXF, generate the overlay - if doc.file.name.lower().endswith('.dxf') and doc.managed_document: - generate_dxf_overlay_managed_document(doc.managed_document, user=doc.uploaded_by) - except Exception as e: - print(f"Error syncing document during migration for {doc.file.name if doc.file else 'None'}: {e}") - -def reverse_sync_trafficlights_documents(apps, schema_editor): - pass - -class Migration(migrations.Migration): - - dependencies = [ - ('assets', '0021_set_default_validation_status_for_active'), - ('documents', '0003_manageddocument_georeference_coords_and_more'), - ] - - operations = [ - migrations.RunPython(sync_trafficlights_documents, reverse_sync_trafficlights_documents), - ] diff --git a/streetup/assets/migrations/0023_trafficlightradar_power_publiclighting_pole_and_more.py b/streetup/assets/migrations/0023_trafficlightradar_power_publiclighting_pole_and_more.py deleted file mode 100644 index d602a0e..0000000 --- a/streetup/assets/migrations/0023_trafficlightradar_power_publiclighting_pole_and_more.py +++ /dev/null @@ -1,39 +0,0 @@ -# Generated by Django 5.2.8 on 2026-07-10 09:13 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('assets', '0022_sync_trafficlights_documents'), - ] - - operations = [ - migrations.AddField( - model_name='trafficlightradar', - name='power_publiclighting_pole', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='powered_radars', to='assets.publiclightingpole', verbose_name='Public Lighting Pole (Power)'), - ), - migrations.AddField( - model_name='trafficlightradar', - name='power_trafficlights_pole', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='powered_radars', to='assets.trafficlightpole', verbose_name='Traffic Light Pole (Power)'), - ), - migrations.AlterField( - model_name='trafficlightradar', - name='pole', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='radars', to='assets.trafficlightradarpole', verbose_name='Radar Pole (Support)'), - ), - migrations.AlterField( - model_name='trafficlightradar', - name='publiclighting_pole', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='radars', to='assets.publiclightingpole', verbose_name='Public Lighting Pole (Support)'), - ), - migrations.AlterField( - model_name='trafficlightradar', - name='trafficlights_pole', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='radars', to='assets.trafficlightpole', verbose_name='Traffic Light Pole (Support)'), - ), - ] diff --git a/streetup/authorizations/migrations/0001_initial.py b/streetup/authorizations/migrations/0001_initial.py index 6f9efd4..f784b99 100644 --- a/streetup/authorizations/migrations/0001_initial.py +++ b/streetup/authorizations/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import authorizations.models import django.contrib.gis.db.models.fields diff --git a/streetup/authorizations/migrations/0002_create_authorizations_view.py b/streetup/authorizations/migrations/0002_create_authorizations_view.py deleted file mode 100644 index c36fd30..0000000 --- a/streetup/authorizations/migrations/0002_create_authorizations_view.py +++ /dev/null @@ -1,30 +0,0 @@ -from django.db import migrations - -def create_authorizations_view(apps, schema_editor): - AppView = apps.get_model('common', 'AppView') - AppView.objects.get_or_create( - code='authorizations', - defaults={ - 'name_fr': 'Autorisations', - 'name_nl': 'Autorisaties', - 'icon': 'bi-file-earmark-text', - 'url_name': 'authorizations:authorization_list', - 'is_default': False, - 'order': 40, - } - ) - -def remove_authorizations_view(apps, schema_editor): - AppView = apps.get_model('common', 'AppView') - AppView.objects.filter(code='authorizations').delete() - -class Migration(migrations.Migration): - - dependencies = [ - ('authorizations', '0001_initial'), - ('common', '0011_userwarehouselocationaccess_and_more'), - ] - - operations = [ - migrations.RunPython(create_authorizations_view, remove_authorizations_view), - ] diff --git a/streetup/common/migrations/0001_initial.py b/streetup/common/migrations/0001_initial.py index 81a14a3..82781a0 100644 --- a/streetup/common/migrations/0001_initial.py +++ b/streetup/common/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import django.contrib.gis.db.models.fields import django.contrib.postgres.fields @@ -113,6 +113,7 @@ class Migration(migrations.Migration): ('can_process_observations', models.BooleanField(default=False, verbose_name='Peut traiter les observations')), ('can_view_projects', models.BooleanField(default=False, verbose_name='Peut voir les projets')), ('can_edit_projects', models.BooleanField(default=False, verbose_name='Peut éditer les projets')), + ('can_validate_assets', models.BooleanField(default=False, verbose_name='Peut valider les assets')), ], options={ 'verbose_name': 'Thématique utilisateur', @@ -150,6 +151,18 @@ class Migration(migrations.Migration): 'verbose_name_plural': 'Accès Entrepôts', }, ), + migrations.CreateModel( + name='UserWarehouseLocationAccess', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('can_perform_inventory', models.BooleanField(default=False, verbose_name="Peut faire l'inventaire")), + ('can_validate_inventory', models.BooleanField(default=False, verbose_name="Peut valider l'inventaire")), + ], + options={ + 'verbose_name': 'Accès Emplacement', + 'verbose_name_plural': 'Accès Emplacements', + }, + ), migrations.CreateModel( name='AssetTypePermissionConfig', fields=[ @@ -275,8 +288,8 @@ class Migration(migrations.Migration): ('can_view', models.BooleanField(default=False, verbose_name='Peut visualiser')), ('can_edit', models.BooleanField(default=False, verbose_name='Peut modifier')), ('can_delete', models.BooleanField(default=False, verbose_name='Peut supprimer')), - ('editable_fields', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=200), blank=True, help_text='Liste des noms de champs que cet utilisateur peut modifier sur cet objet. Si renseignée (non vide), remplace complètement les champs autorisés par le rôle.', null=True, size=None, verbose_name='Champs modifiables')), - ('visible_fields', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=200), blank=True, help_text='Liste des noms de champs que cet utilisateur peut voir sur cet objet. Si renseignée (non vide), remplace complètement les champs affichés par défaut.', null=True, size=None, verbose_name='Champs visibles')), + ('editable_fields', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=200), blank=True, help_text='Liste des noms de champs que cet utilisateur peut modifier sur cet objet. Si renseignée (non vide), remplace complètement les champs autorisés par le rôle.', null=True, verbose_name='Champs modifiables')), + ('visible_fields', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=200), blank=True, help_text='Liste des noms de champs que cet utilisateur peut voir sur cet objet. Si renseignée (non vide), remplace complètement les champs affichés par défaut.', null=True, verbose_name='Champs visibles')), ('content_type', models.ForeignKey(help_text="Le modèle Django de l'asset ou de la location concernée.", on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype', verbose_name="Type d'objet")), ], options={ @@ -291,8 +304,8 @@ class Migration(migrations.Migration): ('can_view', models.BooleanField(default=False, verbose_name='Peut visualiser')), ('can_edit', models.BooleanField(default=False, verbose_name='Peut modifier')), ('can_delete', models.BooleanField(default=False, verbose_name='Peut supprimer')), - ('editable_fields', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=200), blank=True, help_text='Liste des noms de champs modifiables pour tous les objets de ce type. Si renseignée (non vide), remplace les champs autorisés par le rôle. Peut être écrasée objet par objet via UserAssetAccess.', null=True, size=None, verbose_name='Champs modifiables')), - ('visible_fields', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=200), blank=True, help_text='Liste des noms de champs visibles pour tous les objets de ce type. Si renseignée (non vide), remplace les champs affichés par défaut. Peut être écrasée objet par objet via UserAssetAccess.', null=True, size=None, verbose_name='Champs visibles')), + ('editable_fields', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=200), blank=True, help_text='Liste des noms de champs modifiables pour tous les objets de ce type. Si renseignée (non vide), remplace les champs autorisés par le rôle. Peut être écrasée objet par objet via UserAssetAccess.', null=True, verbose_name='Champs modifiables')), + ('visible_fields', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=200), blank=True, help_text='Liste des noms de champs visibles pour tous les objets de ce type. Si renseignée (non vide), remplace les champs affichés par défaut. Peut être écrasée objet par objet via UserAssetAccess.', null=True, verbose_name='Champs visibles')), ('content_type', models.ForeignKey(help_text="Le modèle Django concerné (s'applique à toutes ses instances).", on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype', verbose_name="Type d'asset")), ], options={ @@ -312,14 +325,23 @@ class Migration(migrations.Migration): ('hide_intervention_map_by_default', models.BooleanField(default=False, help_text="Affiche un bouton permettant d'afficher la carte au besoin.", verbose_name='Masquer la carte des interventions par défaut')), ('intervention_list_layout', models.CharField(choices=[('both', 'Tableau et carte'), ('table_only', 'Tableau seul'), ('map_only', 'Carte seule')], default='both', help_text='Préférence de disposition pour la vue liste des interventions.', max_length=20, verbose_name='Disposition de la liste des interventions')), ('intervention_list_filters', models.JSONField(blank=True, default=dict, help_text='Préférences de filtrage pour la vue liste des interventions.', verbose_name='Filtres de la liste des interventions')), + ('mobile_intervention_list_filters', models.JSONField(blank=True, default=dict, help_text='Préférences de filtrage pour la vue mobile de la liste des interventions.', verbose_name='Filtres de la liste des interventions mobile')), ('intervention_list_sort', models.JSONField(blank=True, default=dict, help_text='Préférences de tri pour la vue liste des interventions.', verbose_name='Tri de la liste des interventions')), ('intervention_list_columns', models.JSONField(blank=True, default=None, help_text='Liste des champs masqués dans le tableau de la vue liste des interventions.', null=True, verbose_name='Colonnes masquées de la liste des interventions')), ('observation_list_filters', models.JSONField(blank=True, default=dict, help_text='Préférences de filtrage pour la vue liste des observations.', verbose_name='Filtres de la liste des observations')), ('observation_list_sort', models.JSONField(blank=True, default=dict, help_text='Préférences de tri pour la vue liste des observations.', verbose_name='Tri de la liste des observations')), + ('project_list_filters', models.JSONField(blank=True, default=dict, help_text='Préférences de filtrage pour la vue liste des projets.', verbose_name='Filtres de la liste des projets')), + ('project_list_sort', models.JSONField(blank=True, default=dict, help_text='Préférences de tri pour la vue liste des projets.', verbose_name='Tri de la liste des projets')), ('assets_list_layout', models.CharField(choices=[('both', 'Tableau et carte'), ('table_only', 'Tableau seul'), ('map_only', 'Carte seule')], default='both', help_text='Préférence de disposition pour la vue liste des assets.', max_length=20, verbose_name='Disposition de la liste des assets')), ('auto_logout_hours', models.PositiveIntegerField(blank=True, help_text="Nombre d'heures après la connexion avant déconnexion automatique. Laisser vide pour désactiver.", null=True, verbose_name='Déconnexion automatique (heures)')), + ('panoramax_can_upload', models.BooleanField(default=False, help_text="Permet à l'utilisateur d'uploader de nouvelles photos ou vidéos 360 pour Panoramax.", verbose_name='Peut uploader des photos 360')), ('can_add_unique_tag_documents', models.BooleanField(default=False, help_text="Permet aux utilisateurs externes d'ajouter/modifier des documents avec des tags uniques (CME, PIS, As-Built, etc.).", verbose_name='Peut ajouter des documents avec tags uniques')), + ('esign_can_edit', models.BooleanField(default=False, help_text='Permission pour éditer les panneaux et les poteaux.', verbose_name='eSign : Peut éditer')), + ('esign_can_manage_rcp', models.BooleanField(default=False, help_text='Permission pour créer, modifier et supprimer les RCP.', verbose_name='eSign : Peut gérer les RCP')), + ('esign_can_validate_rcp', models.BooleanField(default=False, help_text='Permission pour valider les RCP.', verbose_name='eSign : Peut valider les RCP')), ('reporting_preferences', models.JSONField(blank=True, default=dict, help_text='Préférences de filtrage pour les différentes pages du reporting.', verbose_name='Préférences du reporting')), + ('assets_index_preferences', models.JSONField(blank=True, default=dict, help_text='Préférences de la page assets (thématiques actives, catégories, filtres, position carte).', verbose_name='Préférences de la page index unifiée')), + ('calendar_preferences', models.JSONField(blank=True, default=dict, help_text="Préférences de la page calendrier (mode d'affichage, zoom, filtres actifs, état d'expansion du backlog).", null=True, verbose_name='Préférences du calendrier')), ('accessible_views', models.ManyToManyField(blank=True, help_text="Les vues/applications auxquelles l'utilisateur a accès.", related_name='user_configs', to='common.appview', verbose_name='Vues accessibles')), ('approval_categories', models.ManyToManyField(blank=True, help_text="Catégories d'assets pour lesquelles l'utilisateur approuve des interventions. Si vide, aucun filtre de catégorie n'est appliqué.", related_name='approver_user_configs', to='assets.assetcategory', verbose_name="Catégories d'approbation")), ], diff --git a/streetup/common/migrations/0002_initial.py b/streetup/common/migrations/0002_initial.py index 3a6a245..782a17a 100644 --- a/streetup/common/migrations/0002_initial.py +++ b/streetup/common/migrations/0002_initial.py @@ -1,7 +1,6 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import django.db.models.deletion -from django.conf import settings from django.db import migrations, models @@ -12,7 +11,6 @@ class Migration(migrations.Migration): dependencies = [ ('common', '0001_initial'), ('contracts', '0001_initial'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ @@ -26,88 +24,4 @@ class Migration(migrations.Migration): name='default_thematic', field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='default_user_accesses', to='common.thematic'), ), - migrations.AddField( - model_name='userconfig', - name='linked_configs', - field=models.ManyToManyField(blank=True, to='common.userconfig', verbose_name='Comptes liés'), - ), - migrations.AddField( - model_name='userconfig', - name='roles', - field=models.ManyToManyField(blank=True, to='common.role'), - ), - migrations.AddField( - model_name='userconfig', - name='user', - field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='config', to=settings.AUTH_USER_MODEL), - ), - migrations.AddField( - model_name='userassettypeaccess', - name='user_config', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='asset_type_accesses', to='common.userconfig', verbose_name='Configuration utilisateur'), - ), - migrations.AddField( - model_name='userassetaccess', - name='user_config', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='asset_accesses', to='common.userconfig', verbose_name='Configuration utilisateur'), - ), - migrations.CreateModel( - name='UserApprovalConfig', - fields=[ - ], - options={ - 'verbose_name': 'Configuration approbateur', - 'verbose_name_plural': 'Configurations approbateurs', - 'ordering': ['user__username'], - 'proxy': True, - 'indexes': [], - 'constraints': [], - }, - bases=('common.userconfig',), - ), - migrations.AddField( - model_name='usercontractaccess', - name='contract', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contracts.contract'), - ), - migrations.AddField( - model_name='usercontractaccess', - name='user_config', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='common.userconfig'), - ), - migrations.AddField( - model_name='userconfig', - name='contracts', - field=models.ManyToManyField(related_name='user_accesses', through='common.UserContractAccess', to='contracts.contract'), - ), - migrations.AddField( - model_name='usercontractstatuspermission', - name='user_contract', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='status_permissions', to='common.usercontractaccess'), - ), - migrations.AddField( - model_name='userthematics', - name='thematic', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='common.thematic'), - ), - migrations.AddField( - model_name='userthematics', - name='user_config', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='userthematics', to='common.userconfig'), - ), - migrations.AddField( - model_name='userconfig', - name='thematics', - field=models.ManyToManyField(related_name='user_accesses', through='common.UserThematics', to='common.thematic'), - ), - migrations.AddField( - model_name='userthematicstatuspermission', - name='user_thematic', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='status_permissions', to='common.userthematics'), - ), - migrations.AddField( - model_name='userwarehouseaccess', - name='user_config', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='userwarehouses', to='common.userconfig'), - ), ] diff --git a/streetup/common/migrations/0003_initial.py b/streetup/common/migrations/0003_initial.py index 000c9dd..782d396 100644 --- a/streetup/common/migrations/0003_initial.py +++ b/streetup/common/migrations/0003_initial.py @@ -1,6 +1,7 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import django.db.models.deletion +from django.conf import settings from django.db import migrations, models @@ -10,74 +11,99 @@ class Migration(migrations.Migration): dependencies = [ ('common', '0002_initial'), - ('stock', '0001_initial'), + ('contracts', '0001_initial'), + ('sign', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.AddField( - model_name='userwarehouseaccess', - name='warehouse', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='stock.warehouse'), + model_name='userconfig', + name='esign_organizations', + field=models.ManyToManyField(blank=True, help_text="Les gestionnaires (communes, Bruxelles Mobilité) pour lesquels l'utilisateur a des permissions.", related_name='user_configs', to='sign.organization', verbose_name='eSign : Gestionnaires'), ), migrations.AddField( model_name='userconfig', - name='warehouses', - field=models.ManyToManyField(blank=True, related_name='user_accesses', through='common.UserWarehouseAccess', to='stock.warehouse'), + name='linked_configs', + field=models.ManyToManyField(blank=True, to='common.userconfig', verbose_name='Comptes liés'), ), - migrations.AddIndex( - model_name='requestlog', - index=models.Index(fields=['level'], name='common_requ_level_55ef16_idx'), + migrations.AddField( + model_name='userconfig', + name='roles', + field=models.ManyToManyField(blank=True, to='common.role'), ), - migrations.AddIndex( - model_name='requestlog', - index=models.Index(fields=['user'], name='common_requ_user_id_3781cb_idx'), + migrations.AddField( + model_name='userconfig', + name='user', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='config', to=settings.AUTH_USER_MODEL), ), - migrations.AddIndex( - model_name='requestlog', - index=models.Index(fields=['status_code'], name='common_requ_status__b046e1_idx'), + migrations.AddField( + model_name='userassettypeaccess', + name='user_config', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='asset_type_accesses', to='common.userconfig', verbose_name='Configuration utilisateur'), ), - migrations.AddIndex( - model_name='requestlog', - index=models.Index(fields=['timestamp', 'level'], name='common_requ_timesta_264745_idx'), - ), - migrations.AlterUniqueTogether( - name='userassettypeaccess', - unique_together={('user_config', 'content_type')}, - ), - migrations.AddIndex( + migrations.AddField( model_name='userassetaccess', - index=models.Index(fields=['content_type', 'object_id'], name='common_user_content_e5ef8d_idx'), + name='user_config', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='asset_accesses', to='common.userconfig', verbose_name='Configuration utilisateur'), ), - migrations.AlterUniqueTogether( - name='userassetaccess', - unique_together={('user_config', 'content_type', 'object_id')}, + migrations.CreateModel( + name='UserApprovalConfig', + fields=[ + ], + options={ + 'verbose_name': 'Configuration approbateur', + 'verbose_name_plural': 'Configurations approbateurs', + 'ordering': ['user__username'], + 'proxy': True, + 'indexes': [], + 'constraints': [], + }, + bases=('common.userconfig',), ), - migrations.AlterUniqueTogether( - name='usercontractaccess', - unique_together={('user_config', 'contract')}, + migrations.AddField( + model_name='usercontractaccess', + name='contract', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contracts.contract'), ), - migrations.AddIndex( + migrations.AddField( + model_name='usercontractaccess', + name='user_config', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='common.userconfig'), + ), + migrations.AddField( + model_name='userconfig', + name='contracts', + field=models.ManyToManyField(related_name='user_accesses', through='common.UserContractAccess', to='contracts.contract'), + ), + migrations.AddField( model_name='usercontractstatuspermission', - index=models.Index(fields=['user_contract', 'status', 'can_view'], name='ucsp_status_canview_idx'), + name='user_contract', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='status_permissions', to='common.usercontractaccess'), ), - migrations.AlterUniqueTogether( - name='usercontractstatuspermission', - unique_together={('user_contract', 'status')}, + migrations.AddField( + model_name='userthematics', + name='thematic', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='common.thematic'), ), - migrations.AlterUniqueTogether( - name='userthematics', - unique_together={('user_config', 'thematic')}, + migrations.AddField( + model_name='userthematics', + name='user_config', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='userthematics', to='common.userconfig'), ), - migrations.AddIndex( + migrations.AddField( + model_name='userconfig', + name='thematics', + field=models.ManyToManyField(related_name='user_accesses', through='common.UserThematics', to='common.thematic'), + ), + migrations.AddField( model_name='userthematicstatuspermission', - index=models.Index(fields=['user_thematic', 'status', 'can_view'], name='utsp_status_canview_idx'), + name='user_thematic', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='status_permissions', to='common.userthematics'), ), - migrations.AlterUniqueTogether( - name='userthematicstatuspermission', - unique_together={('user_thematic', 'status')}, - ), - migrations.AlterUniqueTogether( - name='userwarehouseaccess', - unique_together={('user_config', 'warehouse')}, + migrations.AddField( + model_name='userwarehouseaccess', + name='user_config', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='userwarehouses', to='common.userconfig'), ), ] diff --git a/streetup/common/migrations/0004_initial.py b/streetup/common/migrations/0004_initial.py new file mode 100644 index 0000000..759ce13 --- /dev/null +++ b/streetup/common/migrations/0004_initial.py @@ -0,0 +1,102 @@ +# Generated by Django 6.0.7 on 2026-07-22 13:42 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('common', '0003_initial'), + ('stock', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='userwarehouseaccess', + name='warehouse', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='stock.warehouse'), + ), + migrations.AddField( + model_name='userconfig', + name='warehouses', + field=models.ManyToManyField(blank=True, related_name='user_accesses', through='common.UserWarehouseAccess', to='stock.warehouse'), + ), + migrations.AddField( + model_name='userwarehouselocationaccess', + name='user_config', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='userlocations', to='common.userconfig'), + ), + migrations.AddField( + model_name='userwarehouselocationaccess', + name='warehouse_location', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_accesses', to='stock.warehouselocation', verbose_name='Emplacement'), + ), + migrations.AddField( + model_name='userconfig', + name='warehouse_locations', + field=models.ManyToManyField(blank=True, related_name='user_configs', through='common.UserWarehouseLocationAccess', to='stock.warehouselocation'), + ), + migrations.AddIndex( + model_name='requestlog', + index=models.Index(fields=['level'], name='common_requ_level_55ef16_idx'), + ), + migrations.AddIndex( + model_name='requestlog', + index=models.Index(fields=['user'], name='common_requ_user_id_3781cb_idx'), + ), + migrations.AddIndex( + model_name='requestlog', + index=models.Index(fields=['status_code'], name='common_requ_status__b046e1_idx'), + ), + migrations.AddIndex( + model_name='requestlog', + index=models.Index(fields=['timestamp', 'level'], name='common_requ_timesta_264745_idx'), + ), + migrations.AlterUniqueTogether( + name='userassettypeaccess', + unique_together={('user_config', 'content_type')}, + ), + migrations.AddIndex( + model_name='userassetaccess', + index=models.Index(fields=['content_type', 'object_id'], name='common_user_content_e5ef8d_idx'), + ), + migrations.AlterUniqueTogether( + name='userassetaccess', + unique_together={('user_config', 'content_type', 'object_id')}, + ), + migrations.AlterUniqueTogether( + name='usercontractaccess', + unique_together={('user_config', 'contract')}, + ), + migrations.AddIndex( + model_name='usercontractstatuspermission', + index=models.Index(fields=['user_contract', 'status', 'can_view'], name='ucsp_status_canview_idx'), + ), + migrations.AlterUniqueTogether( + name='usercontractstatuspermission', + unique_together={('user_contract', 'status')}, + ), + migrations.AlterUniqueTogether( + name='userthematics', + unique_together={('user_config', 'thematic')}, + ), + migrations.AddIndex( + model_name='userthematicstatuspermission', + index=models.Index(fields=['user_thematic', 'status', 'can_view'], name='utsp_status_canview_idx'), + ), + migrations.AlterUniqueTogether( + name='userthematicstatuspermission', + unique_together={('user_thematic', 'status')}, + ), + migrations.AlterUniqueTogether( + name='userwarehouseaccess', + unique_together={('user_config', 'warehouse')}, + ), + migrations.AlterUniqueTogether( + name='userwarehouselocationaccess', + unique_together={('user_config', 'warehouse_location')}, + ), + ] diff --git a/streetup/common/migrations/0004_userconfig_assets_index_preferences.py b/streetup/common/migrations/0004_userconfig_assets_index_preferences.py deleted file mode 100644 index f04026d..0000000 --- a/streetup/common/migrations/0004_userconfig_assets_index_preferences.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.8 on 2026-05-23 05:45 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('common', '0003_initial'), - ] - - operations = [ - migrations.AddField( - model_name='userconfig', - name='assets_index_preferences', - field=models.JSONField(blank=True, default=dict, help_text='Préférences de la page assets (thématiques actives, catégories, filtres, position carte).', verbose_name='Préférences de la page index unifiée'), - ), - ] diff --git a/streetup/common/migrations/0005_userconfig_calendar_preferences.py b/streetup/common/migrations/0005_userconfig_calendar_preferences.py deleted file mode 100644 index 393aa27..0000000 --- a/streetup/common/migrations/0005_userconfig_calendar_preferences.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.8 on 2026-05-24 09:30 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('common', '0004_userconfig_assets_index_preferences'), - ] - - operations = [ - migrations.AddField( - model_name='userconfig', - name='calendar_preferences', - field=models.JSONField(blank=True, default=dict, help_text="Préférences de la page calendrier (mode d'affichage, zoom, filtres actifs, état d'expansion du backlog).", null=True, verbose_name='Préférences du calendrier'), - ), - ] diff --git a/streetup/common/migrations/0006_userconfig_esign_can_edit_and_more.py b/streetup/common/migrations/0006_userconfig_esign_can_edit_and_more.py deleted file mode 100644 index eb82698..0000000 --- a/streetup/common/migrations/0006_userconfig_esign_can_edit_and_more.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 5.2.8 on 2026-05-30 08:35 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('common', '0005_userconfig_calendar_preferences'), - ] - - operations = [ - migrations.AddField( - model_name='userconfig', - name='esign_can_edit', - field=models.BooleanField(default=False, help_text='Permission pour éditer les panneaux et les poteaux.', verbose_name='eSign : Peut éditer'), - ), - migrations.AddField( - model_name='userconfig', - name='esign_can_manage_rcp', - field=models.BooleanField(default=False, help_text='Permission pour créer, modifier et supprimer les RCP.', verbose_name='eSign : Peut gérer les RCP'), - ), - migrations.AddField( - model_name='userconfig', - name='esign_can_validate_rcp', - field=models.BooleanField(default=False, help_text='Permission pour valider les RCP.', verbose_name='eSign : Peut valider les RCP'), - ), - ] diff --git a/streetup/common/migrations/0007_userconfig_esign_organizations.py b/streetup/common/migrations/0007_userconfig_esign_organizations.py deleted file mode 100644 index 51a553f..0000000 --- a/streetup/common/migrations/0007_userconfig_esign_organizations.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 5.2.8 on 2026-05-30 10:14 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('common', '0006_userconfig_esign_can_edit_and_more'), - ('sign', '0003_alter_signpanel_street_alter_signpole_street'), - ] - - operations = [ - migrations.AddField( - model_name='userconfig', - name='esign_organizations', - field=models.ManyToManyField(blank=True, help_text="Les gestionnaires (communes, Bruxelles Mobilité) pour lesquels l'utilisateur a des permissions.", related_name='user_configs', to='sign.organization', verbose_name='eSign : Gestionnaires'), - ), - ] diff --git a/streetup/common/migrations/0008_create_agents_regie.py b/streetup/common/migrations/0008_create_agents_regie.py deleted file mode 100644 index b79d5c7..0000000 --- a/streetup/common/migrations/0008_create_agents_regie.py +++ /dev/null @@ -1,156 +0,0 @@ -# Generated by Django on 2026-06-10 - -from django.db import migrations -from django.contrib.auth.hashers import make_password -from django.conf import settings -import zipfile -import xml.etree.ElementTree as ET -import unicodedata -import random -import string -import os - -def normalize_text(text): - nfkd_form = unicodedata.normalize('NFKD', text) - only_ascii = "".join([c for c in nfkd_form if not unicodedata.combining(c)]) - cleaned = "".join([c.lower() for c in only_ascii if c.isalnum()]) - return cleaned - -def generate_password(): - first_char = random.choice(string.ascii_uppercase) - rest_chars = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(11)) - return first_char + rest_chars - -def create_agents_regie(apps, schema_editor): - User = apps.get_model('auth', 'User') - Role = apps.get_model('common', 'Role') - UserConfig = apps.get_model('common', 'UserConfig') - Company = apps.get_model('contracts', 'Company') - CompanyMember = apps.get_model('contracts', 'CompanyMember') - - # Find the ODS file path - ods_path = os.path.join(settings.BASE_DIR, '..', 'external_files', 'agents_regie.ods') - if not os.path.exists(ods_path): - ods_path = os.path.join(settings.BASE_DIR, 'external_files', 'agents_regie.ods') - - if not os.path.exists(ods_path): - print(f"\n[WARNING] agents_regie.ods not found at {ods_path}. Skipping user creation.") - return - - # Parse ODS file - namespaces = { - 'table': 'urn:oasis:names:tc:opendocument:xmlns:table:1.0', - 'text': 'urn:oasis:names:tc:opendocument:xmlns:text:1.0', - 'office': 'urn:oasis:names:tc:opendocument:xmlns:office:1.0' - } - - agents = [] - with zipfile.ZipFile(ods_path, 'r') as z: - content_xml = z.read('content.xml') - root = ET.fromstring(content_xml) - tables = root.findall('.//table:table', namespaces) - for table in tables: - rows = table.findall('.//table:table-row', namespaces) - for idx, row in enumerate(rows): - cells = [] - for cell in row.findall('.//table:table-cell', namespaces): - repeated = cell.get('{' + namespaces['table'] + '}number-columns-repeated') - rep_count = int(repeated) if repeated else 1 - text_elems = cell.findall('.//text:p', namespaces) - cell_text = "".join([t.text if t.text else "" for t in text_elems]) - for _ in range(rep_count): - cells.append(cell_text) - - if any(cells): - while cells and cells[-1] == "": - cells.pop() - if idx == 0: - continue - if len(cells) >= 2: - name = cells[0].strip() - firstname = cells[1].strip() - if name and firstname: - agents.append((name, firstname)) - - if not agents: - print("\n[WARNING] No agents found in agents_regie.ods. Skipping.") - return - - role_tech, _ = Role.objects.get_or_create(name='technician') - company_regie, _ = Company.objects.get_or_create(name='BM - Régie') - - created_users = [] - passwords_file_lines = [ - "=== BM - Régie : Nouveaux Techniciens ===", - f"Généré le : {os.getenv('CURRENT_TIME', '2026-06-10')}", - "-" * 50 - ] - - for name, firstname in agents: - last_name_formatted = name.capitalize() - first_name_formatted = firstname - - first_letter = normalize_text(first_name_formatted)[:1] - last_name_normalized = normalize_text(last_name_formatted) - username = f"{first_letter}{last_name_normalized}" - - if User.objects.filter(username=username).exists(): - continue - - password = generate_password() - - # Create user - user = User.objects.create( - username=username, - first_name=first_name_formatted, - last_name=last_name_formatted, - password=make_password(password) - ) - - # Create UserConfig - config = UserConfig.objects.create( - user=user, - company=company_regie - ) - config.roles.add(role_tech) - - # Create CompanyMember - CompanyMember.objects.create( - user=user, - name=first_name_formatted - ) - - created_users.append((username, password)) - passwords_file_lines.append(f"Login: {username:<15} | Password: {password}") - - if created_users: - print("\n" + "="*80) - print("BM - RÉGIE : UTILISATEURS CRÉÉS") - print("="*80) - for username, password in created_users: - print(f" Login: {username:<15} | Mot de passe: {password}") - print("="*80) - - # Write to generated_passwords.txt on production server - passwords_file_path = os.path.join(settings.BASE_DIR, 'generated_passwords.txt') - try: - with open(passwords_file_path, 'w', encoding='utf-8') as f: - f.write("\n".join(passwords_file_lines) + "\n") - print(f"Mots de passe sauvegardés dans : {passwords_file_path}") - except Exception as e: - print(f"[ERROR] Impossible d'écrire les mots de passe dans un fichier: {e}") - print("="*80 + "\n") - -def delete_agents_regie(apps, schema_editor): - pass - -class Migration(migrations.Migration): - - dependencies = [ - ('common', '0007_userconfig_esign_organizations'), - ('contracts', '0006_companymember_teams_m2m'), - ] - - operations = [ - migrations.RunPython(create_agents_regie, reverse_code=delete_agents_regie), - ] diff --git a/streetup/common/migrations/0008_userconfig_mobile_intervention_list_filters.py b/streetup/common/migrations/0008_userconfig_mobile_intervention_list_filters.py deleted file mode 100644 index 6b6a86a..0000000 --- a/streetup/common/migrations/0008_userconfig_mobile_intervention_list_filters.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-11 11:48 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('common', '0007_userconfig_esign_organizations'), - ] - - operations = [ - migrations.AddField( - model_name='userconfig', - name='mobile_intervention_list_filters', - field=models.JSONField(blank=True, default=dict, help_text='Préférences de filtrage pour la vue mobile de la liste des interventions.', verbose_name='Filtres de la liste des interventions mobile'), - ), - ] diff --git a/streetup/common/migrations/0009_merge_20260611_1539.py b/streetup/common/migrations/0009_merge_20260611_1539.py deleted file mode 100644 index 86b7ed5..0000000 --- a/streetup/common/migrations/0009_merge_20260611_1539.py +++ /dev/null @@ -1,14 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-11 13:39 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('common', '0008_create_agents_regie'), - ('common', '0008_userconfig_mobile_intervention_list_filters'), - ] - - operations = [ - ] diff --git a/streetup/common/migrations/0010_userconfig_project_list_filters_and_more.py b/streetup/common/migrations/0010_userconfig_project_list_filters_and_more.py deleted file mode 100644 index 0a99008..0000000 --- a/streetup/common/migrations/0010_userconfig_project_list_filters_and_more.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-16 10:51 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('common', '0009_merge_20260611_1539'), - ] - - operations = [ - migrations.AddField( - model_name='userconfig', - name='project_list_filters', - field=models.JSONField(blank=True, default=dict, help_text='Préférences de filtrage pour la vue liste des projets.', verbose_name='Filtres de la liste des projets'), - ), - migrations.AddField( - model_name='userconfig', - name='project_list_sort', - field=models.JSONField(blank=True, default=dict, help_text='Préférences de tri pour la vue liste des projets.', verbose_name='Tri de la liste des projets'), - ), - ] diff --git a/streetup/common/migrations/0011_userwarehouselocationaccess_and_more.py b/streetup/common/migrations/0011_userwarehouselocationaccess_and_more.py deleted file mode 100644 index 80723b0..0000000 --- a/streetup/common/migrations/0011_userwarehouselocationaccess_and_more.py +++ /dev/null @@ -1,35 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-17 07:46 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('common', '0010_userconfig_project_list_filters_and_more'), - ('stock', '0007_add_comment_by_to_inventoryitem'), - ] - - operations = [ - migrations.CreateModel( - name='UserWarehouseLocationAccess', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('can_perform_inventory', models.BooleanField(default=False, verbose_name="Peut faire l'inventaire")), - ('can_validate_inventory', models.BooleanField(default=False, verbose_name="Peut valider l'inventaire")), - ('user_config', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='userlocations', to='common.userconfig')), - ('warehouse_location', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user_accesses', to='stock.warehouselocation', verbose_name='Emplacement')), - ], - options={ - 'verbose_name': 'Accès Emplacement', - 'verbose_name_plural': 'Accès Emplacements', - 'unique_together': {('user_config', 'warehouse_location')}, - }, - ), - migrations.AddField( - model_name='userconfig', - name='warehouse_locations', - field=models.ManyToManyField(blank=True, related_name='user_configs', through='common.UserWarehouseLocationAccess', to='stock.warehouselocation'), - ), - ] diff --git a/streetup/common/migrations/0012_create_water_thematic_and_transfer_data.py b/streetup/common/migrations/0012_create_water_thematic_and_transfer_data.py deleted file mode 100644 index fe71809..0000000 --- a/streetup/common/migrations/0012_create_water_thematic_and_transfer_data.py +++ /dev/null @@ -1,112 +0,0 @@ -from django.db import migrations, models - -def create_water_thematic_and_transfer_data(apps, schema_editor): - Thematic = apps.get_model('common', 'Thematic') - UserThematics = apps.get_model('common', 'UserThematics') - AssetCategory = apps.get_model('assets', 'AssetCategory') - Symptom = apps.get_model('interventions', 'Symptom') - InspectionConfiguration = apps.get_model('interventions', 'InspectionConfiguration') - Intervention = apps.get_model('interventions', 'Intervention') - - # 1. Create or get water thematic - water_thematic, created = Thematic.objects.get_or_create( - code='water', - defaults={ - 'name_fr': 'Eau', - 'name_nl': 'Water', - 'icon': 'bi-droplet', - 'color': '#0d6efd', - } - ) - - # 2. Replicate UserThematics permissions for 'water' from 'nature' - nature_permissions = UserThematics.objects.filter(thematic__code='nature') - for np in nature_permissions: - UserThematics.objects.get_or_create( - user_config=np.user_config, - thematic=water_thematic, - defaults={ - 'can_view_assets': np.can_view_assets, - 'can_edit_assets': np.can_edit_assets, - 'can_view_interventions': np.can_view_interventions, - 'can_edit_interventions': np.can_edit_interventions, - 'can_edit_locations': np.can_edit_locations, - 'can_process_observations': np.can_process_observations, - 'can_view_projects': np.can_view_projects, - 'can_edit_projects': np.can_edit_projects, - } - ) - - # 3. Transfer AssetCategory NAT_RWI - try: - giep_cat = AssetCategory.objects.get(code='NAT_RWI') - giep_cat.thematic = water_thematic - giep_cat.save() - - # Transfer any subcategories recursively (in case any exist) - def transfer_children(parent_cat): - for child in AssetCategory.objects.filter(parent=parent_cat): - child.thematic = water_thematic - child.save() - transfer_children(child) - transfer_children(giep_cat) - except AssetCategory.DoesNotExist: - pass - - # 4. Transfer Symptom instances linked to NAT_RWI - giep_cats = AssetCategory.objects.filter(thematic=water_thematic) - symptoms_to_transfer = Symptom.objects.filter( - models.Q(thematic__code='nature') & - (models.Q(asset_categories__in=giep_cats) | models.Q(name_fr__icontains='giep') | models.Q(name_nl__icontains='giep')) - ).distinct() - for symp in symptoms_to_transfer: - symp.thematic = water_thematic - symp.save() - - # 5. Transfer InspectionConfiguration - configs_to_transfer = InspectionConfiguration.objects.filter( - models.Q(thematic__code='nature') & - (models.Q(name_fr__icontains='giep') | models.Q(name_nl__icontains='giep') | models.Q(default_category__thematic=water_thematic)) - ).distinct() - for config in configs_to_transfer: - config.thematic = water_thematic - config.save() - - # 6. Transfer Interventions - ContentType = apps.get_model('contenttypes', 'ContentType') - try: - rwiz_ct = ContentType.objects.get(app_label='assets', model='naturerwiz') - rwiasset_ct = ContentType.objects.get(app_label='assets', model='naturerwiasset') - - # Interventions with category in water thematic - itvs_by_cat = Intervention.objects.filter(thematic__code='nature', asset_category__thematic=water_thematic) - - # Interventions with location in NatureRWIZ - InterventionLocation = apps.get_model('interventions', 'InterventionLocation') - itv_ids_by_loc = InterventionLocation.objects.filter(content_type=rwiz_ct).values_list('intervention_id', flat=True) - itvs_by_loc = Intervention.objects.filter(thematic__code='nature', id__in=itv_ids_by_loc) - - # Interventions with asset in NatureRWIAsset - InterventionAsset = apps.get_model('interventions', 'InterventionAsset') - itv_ids_by_asset = InterventionAsset.objects.filter(content_type=rwiasset_ct).values_list('intervention_id', flat=True) - itvs_by_asset = Intervention.objects.filter(thematic__code='nature', id__in=itv_ids_by_asset) - - all_giep_itvs = (itvs_by_cat | itvs_by_loc | itvs_by_asset).distinct() - for itv in all_giep_itvs: - itv.thematic = water_thematic - itv.save() - except ContentType.DoesNotExist: - pass - - -class Migration(migrations.Migration): - - dependencies = [ - ('common', '0011_userwarehouselocationaccess_and_more'), - ('assets', '0020_alter_trafficlightradarpole_model'), - ('interventions', '0016_inspectionconfiguration_show_equipment'), - ] - - operations = [ - migrations.RunPython(create_water_thematic_and_transfer_data, reverse_code=migrations.RunPython.noop), - ] diff --git a/streetup/common/migrations/0013_userthematics_can_validate_assets.py b/streetup/common/migrations/0013_userthematics_can_validate_assets.py deleted file mode 100644 index 878f49e..0000000 --- a/streetup/common/migrations/0013_userthematics_can_validate_assets.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.8 on 2026-07-03 09:11 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('common', '0012_create_water_thematic_and_transfer_data'), - ] - - operations = [ - migrations.AddField( - model_name='userthematics', - name='can_validate_assets', - field=models.BooleanField(default=False, verbose_name='Peut valider les assets'), - ), - ] diff --git a/streetup/common/migrations/0014_userconfig_panoramax_can_upload.py b/streetup/common/migrations/0014_userconfig_panoramax_can_upload.py deleted file mode 100644 index f301237..0000000 --- a/streetup/common/migrations/0014_userconfig_panoramax_can_upload.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.8 on 2026-07-19 05:35 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('common', '0013_userthematics_can_validate_assets'), - ] - - operations = [ - migrations.AddField( - model_name='userconfig', - name='panoramax_can_upload', - field=models.BooleanField(default=False, help_text="Permet à l'utilisateur d'uploader de nouvelles photos ou vidéos 360 pour Panoramax.", verbose_name='Peut uploader des photos 360'), - ), - ] diff --git a/streetup/contracts/migrations/0001_initial.py b/streetup/contracts/migrations/0001_initial.py index 16775f5..286a0e7 100644 --- a/streetup/contracts/migrations/0001_initial.py +++ b/streetup/contracts/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import common.storages import contracts.models @@ -202,6 +202,9 @@ class Migration(migrations.Migration): ('is_provider', models.BooleanField(default=False, help_text='Indique si cette équipe est un prestataire extérieur.', verbose_name='Prestataire')), ('can_generate_daily_report', models.BooleanField(default=False, help_text='Indique si les membres de cette équipe peuvent générer un rapport quotidien des interventions.', verbose_name='Peut générer le rapport journalier')), ('photos_required', models.BooleanField(default=False, help_text="Si activé, au moins une photo doit être ajoutée à l'intervention avant de pouvoir la terminer.", verbose_name='Photos obligatoires')), + ('restrict_today_interventions_visibility', models.BooleanField(default=False, help_text="Si activé, les interventions ne sont visibles qu'à partir d'une certaine heure, et uniquement pour le jour même.", verbose_name='Restreindre la visibilité aux interventions du jour')), + ('visibility_start_hour', models.TimeField(blank=True, help_text='Heure locale à partir de laquelle les interventions du jour deviennent visibles (ex: 06:00:00).', null=True, verbose_name='Heure de début de visibilité')), + ('restrict_to_assigned_interventions', models.BooleanField(default=False, help_text="Si activé, les membres de cette équipe ne voient que les interventions assignées à l'équipe ou directement à un membre.", verbose_name='Restreindre aux interventions assignées')), ('asset_categories', models.ManyToManyField(blank=True, help_text="Catégories d'assets dont cette équipe est responsable.", related_name='managing_teams', to='assets.assetcategory', verbose_name="Catégories d'assets gérées")), ('company', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='teams', to='contracts.company')), ('thematics', models.ManyToManyField(blank=True, related_name='company_teams', to='common.thematic')), @@ -230,8 +233,8 @@ class Migration(migrations.Migration): ), migrations.AddField( model_name='companymember', - name='team', - field=models.ForeignKey(blank=True, help_text='Laisser vide pour un membre non assigné à une équipe.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='members', to='contracts.companyteam', verbose_name='Équipe'), + name='teams', + field=models.ManyToManyField(blank=True, help_text='Équipes auxquelles ce membre appartient.', related_name='members', to='contracts.companyteam', verbose_name='Équipes'), ), migrations.CreateModel( name='Contract', @@ -253,6 +256,7 @@ class Migration(migrations.Migration): ('needs_approval', models.BooleanField(default=False, help_text="Indique si les interventions liées à ce contrat nécessitent une approbation avant d'être transmises pour traitement.", verbose_name='Nécessite une approbation')), ('needs_checking', models.BooleanField(default=False, help_text="Indique si les interventions liées à ce contrat nécessitent une vérification avant d'être transmises pour traitement.", verbose_name='Nécessite une vérification')), ('uses_occupations', models.BooleanField(default=False, help_text='Indique si les interventions liées à ce contrat utilisent la gestion des occupations (temps passé par membre).', verbose_name='Utilise les occupations')), + ('uses_intervention_manager', models.BooleanField(default=False, help_text="Indique si les interventions liées à ce contrat utilisent un gestionnaire d'intervention.", verbose_name="Utilise les gestionnaires d'intervention")), ('occupations_required', models.BooleanField(default=False, help_text='Si activé, au moins une occupation doit être enregistrée avant de terminer une intervention corrective liée à ce contrat.', verbose_name='Occupations obligatoires')), ('warn_if_no_prestation_on_processed', models.BooleanField(default=False, help_text="Si activé, un avertissement est affiché lorsque l'utilisateur tente de passer une intervention au statut 'Traité' sans avoir encodé de prestation.", verbose_name="Avertir si aucune prestation au passage à 'Traité'")), ('send_daily_summary', models.BooleanField(default=False, help_text="Si activé, les fiches d'intervention du jour sont regroupées dans un seul email envoyé en fin de journée, plutôt qu'un email par intervention.", verbose_name='Envoi groupé journalier')), diff --git a/streetup/contracts/migrations/0002_initial.py b/streetup/contracts/migrations/0002_initial.py index 8575287..7de19f2 100644 --- a/streetup/contracts/migrations/0002_initial.py +++ b/streetup/contracts/migrations/0002_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import django.db.models.deletion from django.conf import settings @@ -10,7 +10,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('common', '0003_initial'), + ('common', '0004_initial'), ('contracts', '0001_initial'), ('projects', '0001_initial'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), diff --git a/streetup/contracts/migrations/0003_contract_uses_intervention_manager.py b/streetup/contracts/migrations/0003_contract_uses_intervention_manager.py deleted file mode 100644 index e2ec6a6..0000000 --- a/streetup/contracts/migrations/0003_contract_uses_intervention_manager.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-03 15:20 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('contracts', '0002_initial'), - ] - - operations = [ - migrations.AddField( - model_name='contract', - name='uses_intervention_manager', - field=models.BooleanField(default=False, help_text="Indique si les interventions liées à ce contrat utilisent un gestionnaire d'intervention.", verbose_name="Utilise les gestionnaires d'intervention"), - ), - ] diff --git a/streetup/contracts/migrations/0004_contract_auto_close_delay_days_and_more.py b/streetup/contracts/migrations/0004_contract_auto_close_delay_days_and_more.py deleted file mode 100644 index fcef582..0000000 --- a/streetup/contracts/migrations/0004_contract_auto_close_delay_days_and_more.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-07 09:14 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('contracts', '0003_contract_uses_intervention_manager'), - ] - - operations = [ - migrations.AddField( - model_name='contract', - name='auto_close_delay_days', - field=models.PositiveIntegerField(default=30, help_text='Délai en jours après lequel une intervention est clôturée automatiquement.', verbose_name='Délai de clôture automatique (jours)'), - ), - migrations.AddField( - model_name='contract', - name='auto_close_interventions', - field=models.BooleanField(default=False, help_text='Indique si les interventions liées à ce contrat doivent être automatiquement clôturées après un certain délai.', verbose_name='Clôture automatique des interventions'), - ), - ] diff --git a/streetup/contracts/migrations/0005_remove_contract_auto_close.py b/streetup/contracts/migrations/0005_remove_contract_auto_close.py deleted file mode 100644 index 0d2a85d..0000000 --- a/streetup/contracts/migrations/0005_remove_contract_auto_close.py +++ /dev/null @@ -1,19 +0,0 @@ -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('contracts', '0004_contract_auto_close_delay_days_and_more'), - ] - - operations = [ - migrations.RemoveField( - model_name='contract', - name='auto_close_delay_days', - ), - migrations.RemoveField( - model_name='contract', - name='auto_close_interventions', - ), - ] diff --git a/streetup/contracts/migrations/0006_companymember_teams_m2m.py b/streetup/contracts/migrations/0006_companymember_teams_m2m.py deleted file mode 100644 index 30460fd..0000000 --- a/streetup/contracts/migrations/0006_companymember_teams_m2m.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-10 08:31 - -from django.db import migrations, models - -def copy_team_to_teams(apps, schema_editor): - CompanyMember = apps.get_model('contracts', 'CompanyMember') - for member in CompanyMember.objects.all(): - # access the raw DB field team_id to avoid django loading issues if team FK field is already removed or modified - team_id = getattr(member, 'team_id', None) - if team_id is not None: - member.teams.add(team_id) - -def copy_teams_to_team(apps, schema_editor): - CompanyMember = apps.get_model('contracts', 'CompanyMember') - for member in CompanyMember.objects.all(): - first_team = member.teams.first() - if first_team: - member.team = first_team - member.save(update_fields=['team']) - -class Migration(migrations.Migration): - - dependencies = [ - ('contracts', '0005_remove_contract_auto_close'), - ] - - operations = [ - migrations.AddField( - model_name='companymember', - name='teams', - field=models.ManyToManyField(blank=True, help_text='Équipes auxquelles ce membre appartient.', related_name='members', to='contracts.companyteam', verbose_name='Équipes'), - ), - migrations.RunPython(copy_team_to_teams, reverse_code=copy_teams_to_team), - migrations.RemoveField( - model_name='companymember', - name='team', - ), - ] diff --git a/streetup/contracts/migrations/0007_companyteam_restrict_today_interventions_visibility_and_more.py b/streetup/contracts/migrations/0007_companyteam_restrict_today_interventions_visibility_and_more.py deleted file mode 100644 index ae01219..0000000 --- a/streetup/contracts/migrations/0007_companyteam_restrict_today_interventions_visibility_and_more.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-17 14:18 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('contracts', '0006_companymember_teams_m2m'), - ] - - operations = [ - migrations.AddField( - model_name='companyteam', - name='restrict_today_interventions_visibility', - field=models.BooleanField(default=False, help_text="Si activé, les interventions ne sont visibles qu'à partir d'une certaine heure, et uniquement pour le jour même.", verbose_name='Restreindre la visibilité aux interventions du jour'), - ), - migrations.AddField( - model_name='companyteam', - name='visibility_start_hour', - field=models.TimeField(blank=True, help_text='Heure locale à partir de laquelle les interventions du jour deviennent visibles (ex: 06:00:00).', null=True, verbose_name='Heure de début de visibilité'), - ), - ] diff --git a/streetup/contracts/migrations/0008_companyteam_restrict_to_assigned_interventions.py b/streetup/contracts/migrations/0008_companyteam_restrict_to_assigned_interventions.py deleted file mode 100644 index 6ba2185..0000000 --- a/streetup/contracts/migrations/0008_companyteam_restrict_to_assigned_interventions.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-22 09:59 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('contracts', '0007_companyteam_restrict_today_interventions_visibility_and_more'), - ] - - operations = [ - migrations.AddField( - model_name='companyteam', - name='restrict_to_assigned_interventions', - field=models.BooleanField(default=False, help_text="Si activé, les membres de cette équipe ne voient que les interventions assignées à l'équipe ou directement à un membre.", verbose_name='Restreindre aux interventions assignées'), - ), - ] diff --git a/streetup/controls/migrations/0001_initial.py b/streetup/controls/migrations/0001_initial.py index 31c43bc..659e37a 100644 --- a/streetup/controls/migrations/0001_initial.py +++ b/streetup/controls/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import common.storages import django.contrib.gis.db.models.fields @@ -105,6 +105,18 @@ class Migration(migrations.Migration): 'ordering': ['control', 'remark_number'], }, ), + migrations.CreateModel( + name='RemarkHistory', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('description', models.TextField(blank=True, null=True)), + ('status', models.CharField(choices=[('information', 'Info'), ('to_be_processed', 'NOK'), ('processed', 'Traité'), ('validated', 'OK'), ('canceled', 'Annulé')], default='to_be_processed')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ], + options={ + 'ordering': ['created_at'], + }, + ), migrations.CreateModel( name='RemarkImage', fields=[ diff --git a/streetup/controls/migrations/0002_initial.py b/streetup/controls/migrations/0002_initial.py index 57558a7..d13975c 100644 --- a/streetup/controls/migrations/0002_initial.py +++ b/streetup/controls/migrations/0002_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 from django.db import migrations, models diff --git a/streetup/controls/migrations/0003_initial.py b/streetup/controls/migrations/0003_initial.py index e0c9969..4eb70dc 100644 --- a/streetup/controls/migrations/0003_initial.py +++ b/streetup/controls/migrations/0003_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import django.db.models.deletion from django.conf import settings @@ -10,7 +10,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('common', '0003_initial'), + ('common', '0004_initial'), ('contracts', '0002_initial'), ('controls', '0002_initial'), ('documents', '0001_initial'), @@ -109,6 +109,21 @@ class Migration(migrations.Migration): name='remark', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quantities', to='controls.remark'), ), + migrations.AddField( + model_name='remarkhistory', + name='created_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='remarkhistory', + name='remark', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='history', to='controls.remark'), + ), + migrations.AddField( + model_name='remarkimage', + name='history_entry', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='images', to='controls.remarkhistory'), + ), migrations.AddField( model_name='remarkimage', name='managed_document', diff --git a/streetup/controls/migrations/0004_remarkhistory_remarkimage_history_entry.py b/streetup/controls/migrations/0004_remarkhistory_remarkimage_history_entry.py deleted file mode 100644 index 5a28344..0000000 --- a/streetup/controls/migrations/0004_remarkhistory_remarkimage_history_entry.py +++ /dev/null @@ -1,35 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-23 13:10 - -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('controls', '0003_initial'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='RemarkHistory', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('description', models.TextField(blank=True, null=True)), - ('status', models.CharField(choices=[('information', 'Info'), ('to_be_processed', 'NOK'), ('processed', 'Traité'), ('validated', 'OK'), ('canceled', 'Annulé')], default='to_be_processed')), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), - ('remark', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='history', to='controls.remark')), - ], - options={ - 'ordering': ['created_at'], - }, - ), - migrations.AddField( - model_name='remarkimage', - name='history_entry', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='images', to='controls.remarkhistory'), - ), - ] diff --git a/streetup/documents/migrations/0001_initial.py b/streetup/documents/migrations/0001_initial.py index 6c96578..da7e128 100644 --- a/streetup/documents/migrations/0001_initial.py +++ b/streetup/documents/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import common.storages import django.db.models.deletion @@ -122,6 +122,8 @@ class Migration(migrations.Migration): ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')), ('is_archived', models.BooleanField(default=False, verbose_name='Archived')), ('unique_params', models.JSONField(blank=True, default=dict, help_text="Additional parameters to determine uniqueness for documents with unique tags (e.g., {'format': 'pdf', 'cables': 'C1,C2'})", verbose_name='Unique parameters')), + ('georeference_coords', models.JSONField(blank=True, help_text='Coordinates of the 4 corners: [[lng, lat], [lng, lat], [lng, lat], [lng, lat]]', null=True, verbose_name='Georeference Coordinates')), + ('georeference_page', models.IntegerField(default=1, help_text='Specific page of the PDF that has been georeferenced', verbose_name='Georeference Page')), ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='created_documents', to=settings.AUTH_USER_MODEL, verbose_name='Created by')), ('current_version', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='current_for_documents', to='documents.documentversion', verbose_name='Current version')), ('folders', models.ManyToManyField(blank=True, related_name='documents', to='documents.documentfolder', verbose_name='Folders')), diff --git a/streetup/documents/migrations/0002_create_giep_folders.py b/streetup/documents/migrations/0002_create_giep_folders.py deleted file mode 100644 index ad9245e..0000000 --- a/streetup/documents/migrations/0002_create_giep_folders.py +++ /dev/null @@ -1,100 +0,0 @@ -# Generated by hand - -from django.db import migrations -from django.utils.text import slugify - - -def create_giep_folders(apps, schema_editor): - DocumentFolder = apps.get_model('documents', 'DocumentFolder') - DocumentFolderAttachment = apps.get_model('documents', 'DocumentFolderAttachment') - NatureRWIZ = apps.get_model('assets', 'NatureRWIZ') - Thematic = apps.get_model('common', 'Thematic') - ContentType = apps.get_model('contenttypes', 'ContentType') - - # 1. Get or create 'assets' folder - assets_folder, _ = DocumentFolder.objects.get_or_create( - slug='assets', - defaults={'name': 'Assets', 'is_predefined': True} - ) - - # 2. Get water thematic - water_thematic = Thematic.objects.filter(code='water').first() - - # Create 'other' document tag - DocumentTag = apps.get_model('documents', 'DocumentTag') - other_tag, _ = DocumentTag.objects.get_or_create( - slug='other', - defaults={ - 'name_fr': 'Autre', - 'name_nl': 'Andere', - 'show_in_asset_detail': True - } - ) - if water_thematic: - other_tag.thematics.add(water_thematic) - - # 3. Create 'water' folder as child of 'assets' - water_folder, _ = DocumentFolder.objects.get_or_create( - slug='water', - defaults={ - 'name': 'Water', - 'is_predefined': True, - } - ) - if water_thematic: - water_folder.thematics.add(water_thematic) - water_folder.parent_folders.add(assets_folder) - - # 4. Create subfolder for each GIEP zone (NatureRWIZ) - nature_rwiz_content_type = ContentType.objects.get_for_model(NatureRWIZ) - - for zone in NatureRWIZ.objects.all(): - # Avoid creating duplicate folders for the same GIEP zone - exists = DocumentFolderAttachment.objects.filter( - content_type=nature_rwiz_content_type, - object_id=zone.id, - is_default=True - ).exists() - if exists: - continue - - folder_name = zone.code - base_slug = slugify(folder_name) or f"giep-{zone.id}" - slug = base_slug - counter = 1 - while DocumentFolder.objects.filter(slug=slug).exists(): - slug = f"{base_slug}-{counter}" - counter += 1 - - zone_folder = DocumentFolder.objects.create( - name=folder_name, - slug=slug, - is_predefined=True - ) - if water_thematic: - zone_folder.thematics.add(water_thematic) - zone_folder.parent_folders.add(water_folder) - - # Attach folder to NatureRWIZ - DocumentFolderAttachment.objects.create( - folder=zone_folder, - content_type=nature_rwiz_content_type, - object_id=zone.id, - is_default=True - ) - - -def remove_giep_folders(apps, schema_editor): - pass - - -class Migration(migrations.Migration): - - dependencies = [ - ('documents', '0001_initial'), - ('assets', '0020_alter_trafficlightradarpole_model'), - ] - - operations = [ - migrations.RunPython(create_giep_folders, remove_giep_folders), - ] diff --git a/streetup/documents/migrations/0003_manageddocument_georeference_coords_and_more.py b/streetup/documents/migrations/0003_manageddocument_georeference_coords_and_more.py deleted file mode 100644 index 1eddcc8..0000000 --- a/streetup/documents/migrations/0003_manageddocument_georeference_coords_and_more.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.2.8 on 2026-07-04 06:15 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('documents', '0002_create_giep_folders'), - ] - - operations = [ - migrations.AddField( - model_name='manageddocument', - name='georeference_coords', - field=models.JSONField(blank=True, help_text='Coordinates of the 4 corners: [[lng, lat], [lng, lat], [lng, lat], [lng, lat]]', null=True, verbose_name='Georeference Coordinates'), - ), - migrations.AddField( - model_name='manageddocument', - name='georeference_page', - field=models.IntegerField(default=1, help_text='Specific page of the PDF that has been georeferenced', verbose_name='Georeference Page'), - ), - ] diff --git a/streetup/home/migrations/0001_initial.py b/streetup/home/migrations/0001_initial.py index ec3c671..311afd0 100644 --- a/streetup/home/migrations/0001_initial.py +++ b/streetup/home/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import django.db.models.deletion from django.db import migrations, models @@ -18,7 +18,7 @@ class Migration(migrations.Migration): name='HomeWidget', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('widget_code', models.CharField(choices=[('intervention_stats', 'Statistiques interventions'), ('contracts_summary', 'Résumé contrats'), ('map_today', 'Carte du jour'), ('operator_shortcuts', 'Raccourcis opérateur'), ('assets_links', 'Liens assets'), ('stock_summary', 'Résumé stock'), ('observer_shortcuts', 'Raccourcis observateur'), ('incident_counter', 'Compteur incidents à traiter'), ('intervention_to_verify', 'Compteur interventions à vérifier'), ('intervention_to_plan', 'Compteur interventions à planifier'), ('intervention_to_approve', 'Compteur interventions à approuver'), ('intervention_checked_to_approve', 'Compteur interventions vérifiées à approuver'), ('stock_actions', 'Actions stock')], max_length=50, unique=True, verbose_name='Code du widget')), + ('widget_code', models.CharField(choices=[('intervention_stats', 'Statistiques interventions'), ('contracts_summary', 'Résumé contrats'), ('map_today', 'Carte du jour'), ('operator_shortcuts', 'Raccourcis opérateur'), ('assets_links', 'Liens assets'), ('stock_summary', 'Résumé stock'), ('observer_shortcuts', 'Raccourcis observateur'), ('incident_counter', 'Compteur incidents à traiter'), ('intervention_to_verify', 'Compteur interventions à vérifier'), ('intervention_to_plan', 'Compteur interventions à planifier'), ('intervention_to_approve', 'Compteur interventions à approuver'), ('intervention_checked_to_approve', 'Compteur interventions vérifiées à approuver'), ('intervention_finished', 'Compteur interventions terminées'), ('stock_actions', 'Actions stock')], max_length=50, unique=True, verbose_name='Code du widget')), ('default_template_override', models.CharField(blank=True, help_text='Chemin du template optionnel (sinon home/widgets/.html)', max_length=255, null=True, verbose_name='Template par défaut (surcharge)')), ('is_active', models.BooleanField(default=True, verbose_name='Actif')), ], @@ -28,6 +28,22 @@ class Migration(migrations.Migration): 'ordering': ['widget_code'], }, ), + migrations.CreateModel( + name='TeambuildingVote', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('voter_name', models.CharField(blank=True, max_length=100, null=True, verbose_name='Nom (optionnel)')), + ('vote_gael', models.IntegerField(default=0, verbose_name="La journée 'Gaël Non Di Dju'")), + ('vote_charly', models.IntegerField(default=0, verbose_name="La journée 'La cité de Charly'")), + ('vote_tequila', models.IntegerField(default=0, verbose_name="La journée 'Tequila Cadena'")), + ('vote_vivien', models.IntegerField(default=0, verbose_name="La journée 'Vivien de La Grande Propreté'")), + ('created_at', models.DateTimeField(auto_now_add=True)), + ], + options={ + 'verbose_name': 'Vote Teambuilding', + 'verbose_name_plural': 'Votes Teambuilding', + }, + ), migrations.CreateModel( name='HomeWidgetConditionGroup', fields=[ @@ -53,6 +69,7 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('condition_type', models.CharField(choices=[('role', 'Rôle'), ('team', 'Équipe'), ('contract', 'Contrat'), ('thematic', 'Thématique'), ('is_intern', 'Statut interne')], max_length=20, verbose_name='Type de condition')), ('is_intern', models.BooleanField(blank=True, help_text="Utilisé si type = 'is_intern'", null=True, verbose_name='Statut interne')), + ('is_negated', models.BooleanField(default=False, help_text='Inverser le sens de la condition (ex: NOT role=Admin)', verbose_name='NOT')), ('is_active', models.BooleanField(default=True, verbose_name='Actif')), ('contract', models.ForeignKey(blank=True, help_text="Utilisé si type = 'contract'", null=True, on_delete=django.db.models.deletion.CASCADE, to='contracts.contract', verbose_name='Contrat')), ('role', models.ForeignKey(blank=True, help_text="Utilisé si type = 'role'", null=True, on_delete=django.db.models.deletion.CASCADE, to='common.role', verbose_name='Rôle')), diff --git a/streetup/home/migrations/0002_alter_homewidget_widget_code.py b/streetup/home/migrations/0002_alter_homewidget_widget_code.py deleted file mode 100644 index 81a05d0..0000000 --- a/streetup/home/migrations/0002_alter_homewidget_widget_code.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-03 09:03 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('home', '0001_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='homewidget', - name='widget_code', - field=models.CharField(choices=[('intervention_stats', 'Statistiques interventions'), ('contracts_summary', 'Résumé contrats'), ('map_today', 'Carte du jour'), ('operator_shortcuts', 'Raccourcis opérateur'), ('assets_links', 'Liens assets'), ('stock_summary', 'Résumé stock'), ('observer_shortcuts', 'Raccourcis observateur'), ('incident_counter', 'Compteur incidents à traiter'), ('intervention_to_verify', 'Compteur interventions à vérifier'), ('intervention_to_plan', 'Compteur interventions à planifier'), ('intervention_to_approve', 'Compteur interventions à approuver'), ('intervention_checked_to_approve', 'Compteur interventions vérifiées à approuver'), ('intervention_finished', 'Compteur interventions terminées'), ('stock_actions', 'Actions stock')], max_length=50, unique=True, verbose_name='Code du widget'), - ), - ] diff --git a/streetup/home/migrations/0003_homewidgetcondition_is_negated.py b/streetup/home/migrations/0003_homewidgetcondition_is_negated.py deleted file mode 100644 index a4755c1..0000000 --- a/streetup/home/migrations/0003_homewidgetcondition_is_negated.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-03 09:23 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('home', '0002_alter_homewidget_widget_code'), - ] - - operations = [ - migrations.AddField( - model_name='homewidgetcondition', - name='is_negated', - field=models.BooleanField(default=False, help_text='Inverser le sens de la condition (ex: NOT role=Admin)', verbose_name='NOT'), - ), - ] diff --git a/streetup/home/migrations/0004_teambuildingvote.py b/streetup/home/migrations/0004_teambuildingvote.py deleted file mode 100644 index b00dc7d..0000000 --- a/streetup/home/migrations/0004_teambuildingvote.py +++ /dev/null @@ -1,29 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-18 08:48 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('home', '0003_homewidgetcondition_is_negated'), - ] - - operations = [ - migrations.CreateModel( - name='TeambuildingVote', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('voter_name', models.CharField(blank=True, max_length=100, null=True, verbose_name='Nom (optionnel)')), - ('vote_gael', models.IntegerField(default=0, verbose_name="La journée 'Gaël Non Di Dju'")), - ('vote_charly', models.IntegerField(default=0, verbose_name="La journée 'La cité de Charly'")), - ('vote_tequila', models.IntegerField(default=0, verbose_name="La journée 'Tequila Cadena'")), - ('vote_vivien', models.IntegerField(default=0, verbose_name="La journée 'Vivien de La Grande Propreté'")), - ('created_at', models.DateTimeField(auto_now_add=True)), - ], - options={ - 'verbose_name': 'Vote Teambuilding', - 'verbose_name_plural': 'Votes Teambuilding', - }, - ), - ] diff --git a/streetup/interventions/migrations/0001_initial.py b/streetup/interventions/migrations/0001_initial.py index 6e11682..0423e03 100644 --- a/streetup/interventions/migrations/0001_initial.py +++ b/streetup/interventions/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import common.storages import django.contrib.gis.db.models.fields @@ -14,7 +14,7 @@ class Migration(migrations.Migration): dependencies = [ ('assets', '0003_initial'), - ('common', '0002_initial'), + ('common', '0003_initial'), ('contenttypes', '0002_remove_content_type_name'), ('contracts', '0001_initial'), ('documents', '0001_initial'), @@ -153,13 +153,13 @@ class Migration(migrations.Migration): ('location_code', models.CharField(blank=True, max_length=500, null=True)), ('status', models.CharField(choices=[('in_preparation', 'En préparation'), ('to_be_approved', 'A approuver'), ('to_be_planned', 'A planifier'), ('to_be_processed', 'A traiter'), ('assigned', 'Pris en charge'), ('in_progress', 'Démarré'), ('on_pause', 'En pause'), ('finished', 'Terminé'), ('processed', 'Traité'), ('to_be_corrected', 'A corriger'), ('corrected', 'Corrigé'), ('validated', 'Validé'), ('invoiced', 'Comptabilisé'), ('closed', 'Finalisé'), ('canceled', 'Annulé')], default='in_preparation')), ('status_order', models.IntegerField(default=1)), - ('pause_reason', models.CharField(blank=True, choices=[('reschedule', 'Intervention à replanifier'), ('order_material', 'Matériel à commander'), ('treated_in_next_maintenance', 'Traité dans le prochain entretien'), ('other', 'Autre')], max_length=50, null=True)), + ('pause_reason', models.CharField(blank=True, choices=[('reschedule', 'Intervention à replanifier'), ('order_material', 'Matériel à commander'), ('treated_in_next_maintenance', 'Traité dans le prochain entretien'), ('waiting_for_material_delivery', 'En attente livraison de matériel'), ('waiting_for_supplier', 'En attente sous-traitant'), ('offer_by_provider', 'Offre à faire par le prestataire'), ('waiting_for_validation', 'En attente de validation'), ('under_framework_contract', 'Sous garantie marché transversal'), ('other', 'Autre')], max_length=50, null=True)), ('pause_reason_other', models.CharField(blank=True, max_length=255, null=True)), ('cancellation_type', models.CharField(blank=True, choices=[('duplicate', 'Doublon'), ('to_redirect', 'A rediriger'), ('not_our_assets', 'Pas sous notre gestion'), ('non_relevant', 'Non-relevant'), ('other', 'Autre')], max_length=50, null=True)), ('priority', models.CharField(choices=[('1', 'Urgent'), ('2', 'Elevé'), ('3', 'Normal'), ('4', 'Bas')], default='3')), ('description', models.TextField(blank=True, null=True)), ('maintain_type', models.CharField(choices=[('corrective', 'Maintenance corrective'), ('preventive', 'Maintenance préventive'), ('ameliorative', 'Maintenance améliorative')], default='corrective')), - ('type', models.CharField(blank=True, choices=[('fixing', 'Dépannage'), ('repair', 'Réparation'), ('repair_post_preventive', 'Réparation post préventif'), ('replace', 'Remplacement'), ('care', 'Entretien'), ('control', 'Contrôle'), ('inspection', 'Inspection'), ('build', 'Construction')], null=True)), + ('type', models.CharField(blank=True, choices=[('fixing', 'Dépannage'), ('repair', 'Réparation'), ('repair_post_preventive', 'Réparation post préventif'), ('replace', 'Remplacement'), ('care', 'Entretien'), ('control', 'Contrôle'), ('inspection', 'Inspection'), ('build', 'Construction'), ('collection', 'Ramassage')], null=True)), ('origin_type', models.CharField(choices=[('damage', 'Avarie'), ('defect', 'Défaut/Panne'), ('demand', 'Demande')], default='damage')), ('begin_time', models.DateTimeField(blank=True, null=True)), ('end_time', models.DateTimeField(blank=True, null=True)), @@ -198,6 +198,7 @@ class Migration(migrations.Migration): ('contract', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='interventions', to='contracts.contract')), ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='created_interventions', to=settings.AUTH_USER_MODEL)), ('guided_operation_template', models.ForeignKey(blank=True, help_text="Assigné automatiquement lors du choix d'un template d'opérations avec un template guidé associé.", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='interventions', to='interventions.guidedoperationtemplate', verbose_name="Template d'opérations guidées")), + ('intervention_manager', models.ForeignKey(blank=True, help_text='Utilisateur qui approuve cette intervention (spécifique aux contrats concernés).', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='managed_interventions', to=settings.AUTH_USER_MODEL, verbose_name="Gestionnaire d'intervention")), ('last_modified_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='modified_interventions', to=settings.AUTH_USER_MODEL)), ('order', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='interventions', to='contracts.contractorder')), ('thematic', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='common.thematic')), @@ -413,6 +414,28 @@ class Migration(migrations.Migration): name='equipment_operation_templates', field=models.ManyToManyField(blank=True, related_name='interventions_equipment', to='interventions.operationtemplate'), ), + migrations.CreateModel( + name='InspectionConfiguration', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name_fr', models.CharField(max_length=255, verbose_name='Nom (FR)')), + ('name_nl', models.CharField(blank=True, max_length=255, verbose_name='Nom (NL)')), + ('description', models.TextField(blank=True, verbose_name='Description')), + ('maintain_type', models.CharField(choices=[('corrective', 'Maintenance corrective'), ('preventive', 'Maintenance préventive'), ('ameliorative', 'Maintenance améliorative')], default='preventive', max_length=50, verbose_name='Type de maintenance')), + ('show_equipment', models.BooleanField(default=True, help_text="Si décoché, le champ équipement sera masqué lors de l'encodage de cette inspection.", verbose_name='Afficher le champ équipement')), + ('concerned_categories', models.ManyToManyField(blank=True, help_text='Filtre les localisations et équipements affichés sur la carte par catégorie. Si vide, tous sont affichés.', related_name='inspection_configs', to='assets.assetcategory', verbose_name='Catégories concernées')), + ('default_category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.assetcategory', verbose_name='Catégorie par défaut')), + ('displayed_asset_types', models.ManyToManyField(blank=True, limit_choices_to=models.Q(('app_label', 'assets')), related_name='inspection_configs_as_asset', to='contenttypes.contenttype', verbose_name="Types d'équipements à afficher sur la carte")), + ('displayed_location_types', models.ManyToManyField(blank=True, limit_choices_to=models.Q(('app_label', 'assets')), related_name='inspection_configs_as_location', to='contenttypes.contenttype', verbose_name='Types de localisations à afficher sur la carte')), + ('thematic', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='common.thematic', verbose_name='Thématique')), + ('operation_templates', models.ManyToManyField(blank=True, to='interventions.operationtemplate', verbose_name="Templates d'opérations")), + ], + options={ + 'verbose_name': "Configuration d'inspection", + 'verbose_name_plural': "Configurations d'inspections", + 'ordering': ['name_fr'], + }, + ), migrations.CreateModel( name='OperationTemplateItem', fields=[ @@ -448,9 +471,12 @@ class Migration(migrations.Migration): ('check_priority', models.BooleanField(default=False, help_text='Indique si la priorité doit être vérifiée.')), ('origin_type', models.CharField(blank=True, choices=[('damage', 'Avarie'), ('defect', 'Défaut/Panne'), ('demand', 'Demande')], default='damage', null=True)), ('maintenance_type', models.CharField(blank=True, choices=[('infra', 'TL - Infrastructure'), ('controller', 'TL - Contrôleur de traffic'), ('electromeca', 'TU - Electromécanique'), ('civil_engineering', 'TU - Génie civil'), ('equipments', 'ITS - Équipement'), ('clean', 'Clean - Nettoyage'), ('collection', 'Clean - Ramassage'), ('other', 'Autre')], help_text="Type de maintenance concerné (ex: 'controller' pour les contrôleurs de traffic).", max_length=50, null=True)), + ('require_equipment_selection', models.BooleanField(default=False, help_text='Si coché, une intervention avec ce symptôme doit obligatoirement être liée à un équipement.', verbose_name='Équipement obligatoire')), ('order_number', models.IntegerField(blank=True, null=True)), ('is_active', models.BooleanField(default=True)), ('recommended_next_status', models.CharField(blank=True, choices=[('in_preparation', 'En préparation'), ('to_be_approved', 'A approuver'), ('to_be_planned', 'A planifier'), ('to_be_processed', 'A traiter'), ('assigned', 'Pris en charge'), ('in_progress', 'Démarré'), ('on_pause', 'En pause'), ('finished', 'Terminé'), ('processed', 'Traité'), ('to_be_corrected', 'A corriger'), ('corrected', 'Corrigé'), ('validated', 'Validé'), ('invoiced', 'Comptabilisé'), ('closed', 'Finalisé'), ('canceled', 'Annulé')], default='to_be_processed', max_length=50, null=True)), + ('auto_create_intervention', models.BooleanField(default=False, help_text="Si coché, une intervention est automatiquement créée lorsque l'observation passe au statut 'À traiter'.", verbose_name="Création automatique d'interventions")), + ('auto_create_intervention_status', models.CharField(blank=True, choices=[('in_preparation', 'En préparation'), ('to_be_approved', 'A approuver'), ('to_be_planned', 'A planifier'), ('to_be_processed', 'A traiter'), ('assigned', 'Pris en charge'), ('in_progress', 'Démarré'), ('on_pause', 'En pause'), ('finished', 'Terminé'), ('processed', 'Traité'), ('to_be_corrected', 'A corriger'), ('corrected', 'Corrigé'), ('validated', 'Validé'), ('invoiced', 'Comptabilisé'), ('closed', 'Finalisé'), ('canceled', 'Annulé')], default='to_be_processed', help_text="Statut dans lequel l'intervention automatique doit être créée.", max_length=50, null=True, verbose_name="Statut de l'intervention auto-créée")), ('internal_notification_emails', models.CharField(blank=True, help_text="Liste d'emails pour les notifications internes.", max_length=1000, null=True)), ('asset_categories', models.ManyToManyField(blank=True, related_name='symptoms', to='assets.assetcategory')), ('contract', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='contracts.contract')), @@ -487,6 +513,34 @@ class Migration(migrations.Migration): name='symptom', field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='interventions.symptom'), ), + migrations.CreateModel( + name='DirectContractRouting', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('thematic', models.CharField(choices=[('structures', 'Structures'), ('trafficlights', 'Traffic Lights'), ('clean', 'Clean'), ('its', 'ITS'), ('nature', 'Nature'), ('roads', 'Roads'), ('publiclighting', 'Public Lighting')], max_length=50, verbose_name='Thématique')), + ('asset_code', models.CharField(help_text="Le code de l'ouvrage d'art ou de l'équipement concerné.", max_length=100, verbose_name="Code de l'asset (ex: OA054)")), + ('contract', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contracts.contract', verbose_name='Contrat à forcer')), + ('symptom', models.ForeignKey(blank=True, help_text="Si renseigné, cette règle s'applique uniquement à ce symptôme. Sinon, elle s'applique par défaut.", null=True, on_delete=django.db.models.deletion.CASCADE, to='interventions.symptom', verbose_name='Symptôme spécifique')), + ], + options={ + 'verbose_name': 'Routage direct de contrat', + 'verbose_name_plural': 'Routages directs de contrats', + }, + ), + migrations.CreateModel( + name='SymptomContractAutoClose', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('delay_days', models.PositiveIntegerField(default=30, help_text="Délai en jours après lequel l'intervention est clôturée automatiquement.", verbose_name='Délai (jours)')), + ('contract', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='auto_close_rules', to='contracts.contract', verbose_name='Contrat')), + ('symptom', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='auto_close_rules', to='interventions.symptom', verbose_name='Symptôme')), + ], + options={ + 'verbose_name': 'Règle de clôture automatique (symptôme × contrat)', + 'verbose_name_plural': 'Règles de clôture automatique (symptôme × contrat)', + 'ordering': ['symptom', 'contract'], + }, + ), migrations.CreateModel( name='SymptomRecommendation', fields=[ @@ -507,7 +561,7 @@ class Migration(migrations.Migration): name='ContractPauseReasonAssignment', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('pause_reason', models.CharField(choices=[('reschedule', 'Intervention à replanifier'), ('order_material', 'Matériel à commander'), ('treated_in_next_maintenance', 'Traité dans le prochain entretien'), ('other', 'Autre')], max_length=50, verbose_name='Motif de pause')), + ('pause_reason', models.CharField(choices=[('reschedule', 'Intervention à replanifier'), ('order_material', 'Matériel à commander'), ('treated_in_next_maintenance', 'Traité dans le prochain entretien'), ('waiting_for_material_delivery', 'En attente livraison de matériel'), ('waiting_for_supplier', 'En attente sous-traitant'), ('offer_by_provider', 'Offre à faire par le prestataire'), ('waiting_for_validation', 'En attente de validation'), ('under_framework_contract', 'Sous garantie marché transversal'), ('other', 'Autre')], max_length=50, verbose_name='Motif de pause')), ('assigned_member', models.ForeignKey(blank=True, help_text="Membre à qui réassigner automatiquement l'intervention lors d'une mise en pause avec ce motif. Laisser vide pour désassigner.", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='pause_reason_assignments', to='contracts.companymember', verbose_name='Membre assigné')), ('contract', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='pause_reason_assignments', to='contracts.contract', verbose_name='Contrat')), ], @@ -517,6 +571,38 @@ class Migration(migrations.Migration): 'unique_together': {('contract', 'pause_reason')}, }, ), + migrations.CreateModel( + name='InspectionConfigurationContract', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('contract', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='inspection_configuration_contracts', to='contracts.contract', verbose_name='Contrat')), + ('inspection_configuration', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='contracts_providers', to='interventions.inspectionconfiguration', verbose_name="Configuration d'inspection")), + ('provider', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='inspection_configuration_contracts', to='contracts.company', verbose_name='Prestataire')), + ], + options={ + 'verbose_name': "Prestataire et Contrat d'inspection", + 'verbose_name_plural': "Prestataires et Contrats d'inspections", + 'unique_together': {('inspection_configuration', 'provider', 'contract')}, + }, + ), + migrations.CreateModel( + name='InterventionAssignment', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('status', models.CharField(blank=True, choices=[('in_preparation', 'En préparation'), ('to_be_approved', 'A approuver'), ('to_be_planned', 'A planifier'), ('to_be_processed', 'A traiter'), ('assigned', 'Pris en charge'), ('in_progress', 'Démarré'), ('on_pause', 'En pause'), ('finished', 'Terminé'), ('processed', 'Traité'), ('to_be_corrected', 'A corriger'), ('corrected', 'Corrigé'), ('validated', 'Validé'), ('invoiced', 'Comptabilisé'), ('closed', 'Finalisé'), ('canceled', 'Annulé')], max_length=50, null=True, verbose_name='Statut')), + ('date', models.DateField(verbose_name="Date d'assignation")), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('intervention', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='daily_assignments', to='interventions.intervention', verbose_name='Intervention')), + ('member', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='daily_assignments', to='contracts.companymember', verbose_name='Membre')), + ('team', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='daily_assignments', to='contracts.companyteam', verbose_name='Équipe')), + ], + options={ + 'verbose_name': "Assignation quotidienne d'intervention", + 'verbose_name_plural': "Assignations quotidiennes d'interventions", + 'ordering': ['date', 'team'], + 'unique_together': {('intervention', 'date')}, + }, + ), migrations.CreateModel( name='InterventionLink', fields=[ @@ -561,6 +647,20 @@ class Migration(migrations.Migration): 'unique_together': {('intervention', 'contract_post', 'period_number')}, }, ), + migrations.CreateModel( + name='InterventionSubscription', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Abonné le')), + ('intervention', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='subscriptions', to='interventions.intervention', verbose_name='Intervention')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='intervention_subscriptions', to=settings.AUTH_USER_MODEL, verbose_name='Utilisateur')), + ], + options={ + 'verbose_name': 'Abonnement à une intervention', + 'verbose_name_plural': 'Abonnements aux interventions', + 'unique_together': {('user', 'intervention')}, + }, + ), migrations.AlterUniqueTogether( name='operationstatus', unique_together={('status_set', 'value')}, @@ -603,4 +703,12 @@ class Migration(migrations.Migration): model_name='intervention', index=models.Index(fields=['begin_time', 'planned_begin_time', 'expected_begin_time', 'maintain_type'], name='intv_chart_begin_maintain_idx'), ), + migrations.AlterUniqueTogether( + name='directcontractrouting', + unique_together={('thematic', 'asset_code', 'symptom')}, + ), + migrations.AlterUniqueTogether( + name='symptomcontractautoclose', + unique_together={('symptom', 'contract')}, + ), ] diff --git a/streetup/interventions/migrations/0002_alter_intervention_type.py b/streetup/interventions/migrations/0002_alter_intervention_type.py deleted file mode 100644 index ad7059d..0000000 --- a/streetup/interventions/migrations/0002_alter_intervention_type.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.8 on 2026-05-24 08:47 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('interventions', '0001_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='intervention', - name='type', - field=models.CharField(blank=True, choices=[('fixing', 'Dépannage'), ('repair', 'Réparation'), ('repair_post_preventive', 'Réparation post préventif'), ('replace', 'Remplacement'), ('care', 'Entretien'), ('control', 'Contrôle'), ('inspection', 'Inspection'), ('build', 'Construction'), ('collection', 'Ramassage')], null=True), - ), - ] diff --git a/streetup/interventions/migrations/0003_inspectionconfiguration.py b/streetup/interventions/migrations/0003_inspectionconfiguration.py deleted file mode 100644 index 547a8be..0000000 --- a/streetup/interventions/migrations/0003_inspectionconfiguration.py +++ /dev/null @@ -1,35 +0,0 @@ -# Generated by Django 5.2.8 on 2026-05-28 12:44 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('common', '0005_userconfig_calendar_preferences'), - ('contracts', '0002_initial'), - ('interventions', '0002_alter_intervention_type'), - ] - - operations = [ - migrations.CreateModel( - name='InspectionConfiguration', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name_fr', models.CharField(max_length=255, verbose_name='Nom (FR)')), - ('name_nl', models.CharField(blank=True, max_length=255, verbose_name='Nom (NL)')), - ('description', models.TextField(blank=True, verbose_name='Description')), - ('maintain_type', models.CharField(choices=[('corrective', 'Maintenance corrective'), ('preventive', 'Maintenance préventive'), ('ameliorative', 'Maintenance améliorative')], default='preventive', max_length=50, verbose_name='Type de maintenance')), - ('assigned_provider', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='inspection_configs', to='contracts.company', verbose_name='Prestataire')), - ('contract', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='inspection_configs', to='contracts.contract', verbose_name='Contrat')), - ('operation_templates', models.ManyToManyField(blank=True, to='interventions.operationtemplate', verbose_name="Templates d'opérations")), - ('thematic', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='common.thematic', verbose_name='Thématique')), - ], - options={ - 'verbose_name': "Configuration d'inspection", - 'verbose_name_plural': "Configurations d'inspections", - 'ordering': ['name_fr'], - }, - ), - ] diff --git a/streetup/interventions/migrations/0004_inspectionconfigurationcontract.py b/streetup/interventions/migrations/0004_inspectionconfigurationcontract.py deleted file mode 100644 index af11112..0000000 --- a/streetup/interventions/migrations/0004_inspectionconfigurationcontract.py +++ /dev/null @@ -1,43 +0,0 @@ -# Generated by Django 5.2.8 on 2026-05-28 14:19 - -import django.db.models.deletion -from django.db import migrations, models - - -def migrate_existing_inspection_configs(apps, schema_editor): - InspectionConfiguration = apps.get_model('interventions', 'InspectionConfiguration') - InspectionConfigurationContract = apps.get_model('interventions', 'InspectionConfigurationContract') - - for config in InspectionConfiguration.objects.all(): - if config.contract_id and config.assigned_provider_id: - InspectionConfigurationContract.objects.get_or_create( - inspection_configuration=config, - contract_id=config.contract_id, - provider_id=config.assigned_provider_id - ) - - -class Migration(migrations.Migration): - - dependencies = [ - ('contracts', '0002_initial'), - ('interventions', '0003_inspectionconfiguration'), - ] - - operations = [ - migrations.CreateModel( - name='InspectionConfigurationContract', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('contract', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='inspection_configuration_contracts', to='contracts.contract', verbose_name='Contrat')), - ('inspection_configuration', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='contracts_providers', to='interventions.inspectionconfiguration', verbose_name="Configuration d'inspection")), - ('provider', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='inspection_configuration_contracts', to='contracts.company', verbose_name='Prestataire')), - ], - options={ - 'verbose_name': "Prestataire et Contrat d'inspection", - 'verbose_name_plural': "Prestataires et Contrats d'inspections", - 'unique_together': {('inspection_configuration', 'provider', 'contract')}, - }, - ), - migrations.RunPython(migrate_existing_inspection_configs, reverse_code=migrations.RunPython.noop), - ] diff --git a/streetup/interventions/migrations/0005_remove_inspectionconfiguration_assigned_provider_and_more.py b/streetup/interventions/migrations/0005_remove_inspectionconfiguration_assigned_provider_and_more.py deleted file mode 100644 index 2986377..0000000 --- a/streetup/interventions/migrations/0005_remove_inspectionconfiguration_assigned_provider_and_more.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 5.2.8 on 2026-05-28 14:20 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('interventions', '0004_inspectionconfigurationcontract'), - ] - - operations = [ - migrations.RemoveField( - model_name='inspectionconfiguration', - name='assigned_provider', - ), - migrations.RemoveField( - model_name='inspectionconfiguration', - name='contract', - ), - ] diff --git a/streetup/interventions/migrations/0006_inspectionconfiguration_default_category.py b/streetup/interventions/migrations/0006_inspectionconfiguration_default_category.py deleted file mode 100644 index e7ee63a..0000000 --- a/streetup/interventions/migrations/0006_inspectionconfiguration_default_category.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 5.2.8 on 2026-05-28 14:43 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('assets', '0008_delete_naturehollowgreenspace'), - ('interventions', '0005_remove_inspectionconfiguration_assigned_provider_and_more'), - ] - - operations = [ - migrations.AddField( - model_name='inspectionconfiguration', - name='default_category', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='assets.assetcategory', verbose_name='Catégorie par défaut'), - ), - ] diff --git a/streetup/interventions/migrations/0007_inspectionconfigurationasset_and_more.py b/streetup/interventions/migrations/0007_inspectionconfigurationasset_and_more.py deleted file mode 100644 index 3aa976c..0000000 --- a/streetup/interventions/migrations/0007_inspectionconfigurationasset_and_more.py +++ /dev/null @@ -1,43 +0,0 @@ -# Generated by Django 5.2.8 on 2026-05-29 07:44 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('contenttypes', '0002_remove_content_type_name'), - ('interventions', '0006_inspectionconfiguration_default_category'), - ] - - operations = [ - migrations.CreateModel( - name='InspectionConfigurationAsset', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('object_id', models.PositiveIntegerField(verbose_name="ID d'équipement")), - ('content_type', models.ForeignKey(limit_choices_to=models.Q(('app_label', 'assets')), on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype', verbose_name="Type d'équipement")), - ('inspection_configuration', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='assets', to='interventions.inspectionconfiguration', verbose_name="Configuration d'inspection")), - ], - options={ - 'verbose_name': 'Équipement à afficher sur la carte', - 'verbose_name_plural': 'Équipements à afficher sur la carte', - 'unique_together': {('inspection_configuration', 'content_type', 'object_id')}, - }, - ), - migrations.CreateModel( - name='InspectionConfigurationLocation', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('object_id', models.PositiveIntegerField(verbose_name='ID de localisation')), - ('content_type', models.ForeignKey(limit_choices_to=models.Q(('app_label', 'assets')), on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype', verbose_name='Type de localisation')), - ('inspection_configuration', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='locations', to='interventions.inspectionconfiguration', verbose_name="Configuration d'inspection")), - ], - options={ - 'verbose_name': 'Localisation à afficher sur la carte', - 'verbose_name_plural': 'Localisations à afficher sur la carte', - 'unique_together': {('inspection_configuration', 'content_type', 'object_id')}, - }, - ), - ] diff --git a/streetup/interventions/migrations/0008_alter_inspectionconfigurationlocation_unique_together_and_more.py b/streetup/interventions/migrations/0008_alter_inspectionconfigurationlocation_unique_together_and_more.py deleted file mode 100644 index e585d62..0000000 --- a/streetup/interventions/migrations/0008_alter_inspectionconfigurationlocation_unique_together_and_more.py +++ /dev/null @@ -1,42 +0,0 @@ -# Generated by Django 5.2.8 on 2026-05-29 07:54 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('contenttypes', '0002_remove_content_type_name'), - ('interventions', '0007_inspectionconfigurationasset_and_more'), - ] - - operations = [ - migrations.AlterUniqueTogether( - name='inspectionconfigurationlocation', - unique_together=None, - ), - migrations.RemoveField( - model_name='inspectionconfigurationlocation', - name='content_type', - ), - migrations.RemoveField( - model_name='inspectionconfigurationlocation', - name='inspection_configuration', - ), - migrations.AddField( - model_name='inspectionconfiguration', - name='displayed_asset_types', - field=models.ManyToManyField(blank=True, limit_choices_to=models.Q(('app_label', 'assets')), related_name='inspection_configs_as_asset', to='contenttypes.contenttype', verbose_name="Types d'équipements à afficher sur la carte"), - ), - migrations.AddField( - model_name='inspectionconfiguration', - name='displayed_location_types', - field=models.ManyToManyField(blank=True, limit_choices_to=models.Q(('app_label', 'assets')), related_name='inspection_configs_as_location', to='contenttypes.contenttype', verbose_name='Types de localisations à afficher sur la carte'), - ), - migrations.DeleteModel( - name='InspectionConfigurationAsset', - ), - migrations.DeleteModel( - name='InspectionConfigurationLocation', - ), - ] diff --git a/streetup/interventions/migrations/0009_inspectionconfiguration_concerned_categories.py b/streetup/interventions/migrations/0009_inspectionconfiguration_concerned_categories.py deleted file mode 100644 index 68f735f..0000000 --- a/streetup/interventions/migrations/0009_inspectionconfiguration_concerned_categories.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated manually - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('assets', '0008_delete_naturehollowgreenspace'), - ('interventions', '0008_alter_inspectionconfigurationlocation_unique_together_and_more'), - ] - - operations = [ - migrations.AddField( - model_name='inspectionconfiguration', - name='concerned_categories', - field=models.ManyToManyField( - blank=True, - help_text="Filtre les localisations et équipements affichés sur la carte par catégorie. Si vide, tous sont affichés.", - related_name='inspection_configs', - to='assets.assetcategory', - verbose_name='Catégories concernées', - ), - ), - ] diff --git a/streetup/interventions/migrations/0010_intervention_intervention_manager.py b/streetup/interventions/migrations/0010_intervention_intervention_manager.py deleted file mode 100644 index d6eb8d6..0000000 --- a/streetup/interventions/migrations/0010_intervention_intervention_manager.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-03 15:20 - -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('interventions', '0009_inspectionconfiguration_concerned_categories'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.AddField( - model_name='intervention', - name='intervention_manager', - field=models.ForeignKey(blank=True, help_text='Utilisateur qui approuve cette intervention (spécifique aux contrats concernés).', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='managed_interventions', to=settings.AUTH_USER_MODEL, verbose_name="Gestionnaire d'intervention"), - ), - ] diff --git a/streetup/interventions/migrations/0011_symptom_auto_close_delay_days_and_more.py b/streetup/interventions/migrations/0011_symptom_auto_close_delay_days_and_more.py deleted file mode 100644 index de9843a..0000000 --- a/streetup/interventions/migrations/0011_symptom_auto_close_delay_days_and_more.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-07 09:39 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('interventions', '0010_intervention_intervention_manager'), - ] - - operations = [ - migrations.AddField( - model_name='symptom', - name='auto_close_delay_days', - field=models.PositiveIntegerField(default=30, help_text='Délai en jours après lequel une intervention est clôturée automatiquement pour ce symptôme.', verbose_name='Délai de clôture automatique (jours)'), - ), - migrations.AddField( - model_name='symptom', - name='auto_close_interventions', - field=models.BooleanField(default=False, help_text='Indique si les interventions liées à ce symptôme doivent être automatiquement clôturées après un certain délai.', verbose_name='Clôture automatique des interventions'), - ), - ] diff --git a/streetup/interventions/migrations/0012_symptomcontractautoclose_remove_symptom_auto_close.py b/streetup/interventions/migrations/0012_symptomcontractautoclose_remove_symptom_auto_close.py deleted file mode 100644 index 7f3608f..0000000 --- a/streetup/interventions/migrations/0012_symptomcontractautoclose_remove_symptom_auto_close.py +++ /dev/null @@ -1,36 +0,0 @@ -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('contracts', '0004_contract_auto_close_delay_days_and_more'), - ('interventions', '0011_symptom_auto_close_delay_days_and_more'), - ] - - operations = [ - migrations.CreateModel( - name='SymptomContractAutoClose', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('delay_days', models.PositiveIntegerField(default=30, help_text="Délai en jours après lequel l'intervention est clôturée automatiquement.", verbose_name='Délai (jours)')), - ('contract', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='auto_close_rules', to='contracts.contract', verbose_name='Contrat')), - ('symptom', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='auto_close_rules', to='interventions.symptom', verbose_name='Symptôme')), - ], - options={ - 'verbose_name': 'Règle de clôture automatique (symptôme × contrat)', - 'verbose_name_plural': 'Règles de clôture automatique (symptôme × contrat)', - 'ordering': ['symptom', 'contract'], - 'unique_together': {('symptom', 'contract')}, - }, - ), - migrations.RemoveField( - model_name='symptom', - name='auto_close_delay_days', - ), - migrations.RemoveField( - model_name='symptom', - name='auto_close_interventions', - ), - ] diff --git a/streetup/interventions/migrations/0013_symptom_require_equipment_selection.py b/streetup/interventions/migrations/0013_symptom_require_equipment_selection.py deleted file mode 100644 index 7c2eedc..0000000 --- a/streetup/interventions/migrations/0013_symptom_require_equipment_selection.py +++ /dev/null @@ -1,20 +0,0 @@ -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('interventions', '0012_symptomcontractautoclose_remove_symptom_auto_close'), - ] - - operations = [ - migrations.AddField( - model_name='symptom', - name='require_equipment_selection', - field=models.BooleanField( - default=False, - help_text="Si coché, une intervention avec ce symptôme doit obligatoirement être liée à un équipement.", - verbose_name='Équipement obligatoire', - ), - ), - ] diff --git a/streetup/interventions/migrations/0014_interventionassignment.py b/streetup/interventions/migrations/0014_interventionassignment.py deleted file mode 100644 index 4560f9c..0000000 --- a/streetup/interventions/migrations/0014_interventionassignment.py +++ /dev/null @@ -1,61 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-11 13:40 - -import django.db.models.deletion -from django.db import migrations, models - -def create_initial_assignments(apps, schema_editor): - Intervention = apps.get_model('interventions', 'Intervention') - InterventionAssignment = apps.get_model('interventions', 'InterventionAssignment') - from datetime import timedelta - - for itv in Intervention.objects.filter(assigned_team__isnull=False): - start_dt = itv.planned_begin_time or itv.begin_time or itv.expected_begin_time or itv.creation_time - end_dt = itv.planned_end_time or itv.end_time or itv.expected_end_time or start_dt - if start_dt: - start_date = start_dt.date() - end_date = end_dt.date() - curr = start_date - while curr <= end_date: - InterventionAssignment.objects.get_or_create( - intervention=itv, - date=curr, - defaults={ - 'team': itv.assigned_team, - 'member': itv.assigned_member, - 'status': itv.status, - } - ) - curr += timedelta(days=1) - - -class Migration(migrations.Migration): - - dependencies = [ - ('contracts', '0006_companymember_teams_m2m'), - ('interventions', '0013_symptom_require_equipment_selection'), - ] - - operations = [ - migrations.CreateModel( - name='InterventionAssignment', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('status', models.CharField(blank=True, choices=[('in_preparation', 'En préparation'), ('to_be_approved', 'A approuver'), ('to_be_planned', 'A planifier'), ('to_be_processed', 'A traiter'), ('assigned', 'Pris en charge'), ('in_progress', 'Démarré'), ('on_pause', 'En pause'), ('finished', 'Terminé'), ('processed', 'Traité'), ('to_be_corrected', 'A corriger'), ('corrected', 'Corrigé'), ('validated', 'Validé'), ('invoiced', 'Comptabilisé'), ('closed', 'Finalisé'), ('canceled', 'Annulé')], max_length=50, null=True, verbose_name='Statut')), - ('date', models.DateField(verbose_name="Date d'assignation")), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('intervention', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='daily_assignments', to='interventions.intervention', verbose_name='Intervention')), - ('member', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='daily_assignments', to='contracts.companymember', verbose_name='Membre')), - ('team', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='daily_assignments', to='contracts.companyteam', verbose_name='Équipe')), - ], - options={ - 'verbose_name': "Assignation quotidienne d'intervention", - 'verbose_name_plural': "Assignations quotidiennes d'interventions", - 'ordering': ['date', 'team'], - 'unique_together': {('intervention', 'date')}, - }, - ), - migrations.RunPython( - create_initial_assignments, - reverse_code=migrations.RunPython.noop - ), - ] diff --git a/streetup/interventions/migrations/0015_symptom_auto_create_intervention_and_more.py b/streetup/interventions/migrations/0015_symptom_auto_create_intervention_and_more.py deleted file mode 100644 index 37ecb55..0000000 --- a/streetup/interventions/migrations/0015_symptom_auto_create_intervention_and_more.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-16 17:38 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('interventions', '0014_interventionassignment'), - ] - - operations = [ - migrations.AddField( - model_name='symptom', - name='auto_create_intervention', - field=models.BooleanField(default=False, help_text="Si coché, une intervention est automatiquement créée lorsque l'observation passe au statut 'À traiter'.", verbose_name="Création automatique d'interventions"), - ), - migrations.AddField( - model_name='symptom', - name='auto_create_intervention_status', - field=models.CharField(blank=True, choices=[('in_preparation', 'En préparation'), ('to_be_approved', 'A approuver'), ('to_be_planned', 'A planifier'), ('to_be_processed', 'A traiter'), ('assigned', 'Pris en charge'), ('in_progress', 'Démarré'), ('on_pause', 'En pause'), ('finished', 'Terminé'), ('processed', 'Traité'), ('to_be_corrected', 'A corriger'), ('corrected', 'Corrigé'), ('validated', 'Validé'), ('invoiced', 'Comptabilisé'), ('closed', 'Finalisé'), ('canceled', 'Annulé')], default='to_be_processed', help_text="Statut dans lequel l'intervention automatique doit être créée.", max_length=50, null=True, verbose_name="Statut de l'intervention auto-créée"), - ), - ] diff --git a/streetup/interventions/migrations/0016_inspectionconfiguration_show_equipment.py b/streetup/interventions/migrations/0016_inspectionconfiguration_show_equipment.py deleted file mode 100644 index 126d44a..0000000 --- a/streetup/interventions/migrations/0016_inspectionconfiguration_show_equipment.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-25 13:14 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('interventions', '0015_symptom_auto_create_intervention_and_more'), - ] - - operations = [ - migrations.AddField( - model_name='inspectionconfiguration', - name='show_equipment', - field=models.BooleanField(default=True, help_text="Si décoché, le champ équipement sera masqué lors de l'encodage de cette inspection.", verbose_name='Afficher le champ équipement'), - ), - ] diff --git a/streetup/interventions/migrations/0017_interventionsubscription.py b/streetup/interventions/migrations/0017_interventionsubscription.py deleted file mode 100644 index 7b5d092..0000000 --- a/streetup/interventions/migrations/0017_interventionsubscription.py +++ /dev/null @@ -1,30 +0,0 @@ -# Generated by Django 5.2.8 on 2026-07-06 08:33 - -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('interventions', '0016_inspectionconfiguration_show_equipment'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='InterventionSubscription', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Abonné le')), - ('intervention', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='subscriptions', to='interventions.intervention', verbose_name='Intervention')), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='intervention_subscriptions', to=settings.AUTH_USER_MODEL, verbose_name='Utilisateur')), - ], - options={ - 'verbose_name': 'Abonnement à une intervention', - 'verbose_name_plural': 'Abonnements aux interventions', - 'unique_together': {('user', 'intervention')}, - }, - ), - ] diff --git a/streetup/interventions/migrations/0018_alter_contractpausereasonassignment_pause_reason_and_more.py b/streetup/interventions/migrations/0018_alter_contractpausereasonassignment_pause_reason_and_more.py deleted file mode 100644 index 4c110ef..0000000 --- a/streetup/interventions/migrations/0018_alter_contractpausereasonassignment_pause_reason_and_more.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.2.8 on 2026-07-09 09:11 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('interventions', '0017_interventionsubscription'), - ] - - operations = [ - migrations.AlterField( - model_name='contractpausereasonassignment', - name='pause_reason', - field=models.CharField(choices=[('reschedule', 'Intervention à replanifier'), ('order_material', 'Matériel à commander'), ('treated_in_next_maintenance', 'Traité dans le prochain entretien'), ('waiting_for_material_delivery', 'En attente livraison de matériel'), ('waiting_for_supplier', 'En attente sous-traitant'), ('offer_by_provider', 'Offre à faire par le prestataire'), ('waiting_for_validation', 'En attente de validation'), ('under_framework_contract', 'Sous garantie marché transversal'), ('other', 'Autre')], max_length=50, verbose_name='Motif de pause'), - ), - migrations.AlterField( - model_name='intervention', - name='pause_reason', - field=models.CharField(blank=True, choices=[('reschedule', 'Intervention à replanifier'), ('order_material', 'Matériel à commander'), ('treated_in_next_maintenance', 'Traité dans le prochain entretien'), ('waiting_for_material_delivery', 'En attente livraison de matériel'), ('waiting_for_supplier', 'En attente sous-traitant'), ('offer_by_provider', 'Offre à faire par le prestataire'), ('waiting_for_validation', 'En attente de validation'), ('under_framework_contract', 'Sous garantie marché transversal'), ('other', 'Autre')], max_length=50, null=True), - ), - ] diff --git a/streetup/interventions/migrations/0019_directcontractrouting.py b/streetup/interventions/migrations/0019_directcontractrouting.py deleted file mode 100644 index e67ce7d..0000000 --- a/streetup/interventions/migrations/0019_directcontractrouting.py +++ /dev/null @@ -1,30 +0,0 @@ -# Generated by Django 5.2.8 on 2026-07-22 09:11 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('contracts', '0008_companyteam_restrict_to_assigned_interventions'), - ('interventions', '0018_alter_contractpausereasonassignment_pause_reason_and_more'), - ] - - operations = [ - migrations.CreateModel( - name='DirectContractRouting', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('thematic', models.CharField(choices=[('structures', 'Structures'), ('trafficlights', 'Traffic Lights'), ('clean', 'Clean'), ('its', 'ITS'), ('nature', 'Nature'), ('roads', 'Roads'), ('publiclighting', 'Public Lighting')], max_length=50, verbose_name='Thématique')), - ('asset_code', models.CharField(help_text="Le code de l'ouvrage d'art ou de l'équipement concerné.", max_length=100, verbose_name="Code de l'asset (ex: OA054)")), - ('contract', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contracts.contract', verbose_name='Contrat à forcer')), - ('symptom', models.ForeignKey(blank=True, help_text="Si renseigné, cette règle s'applique uniquement à ce symptôme. Sinon, elle s'applique par défaut.", null=True, on_delete=django.db.models.deletion.CASCADE, to='interventions.symptom', verbose_name='Symptôme spécifique')), - ], - options={ - 'verbose_name': 'Routage direct de contrat', - 'verbose_name_plural': 'Routages directs de contrats', - 'unique_together': {('thematic', 'asset_code', 'symptom')}, - }, - ), - ] diff --git a/streetup/interventions/migrations/0020_auto_20260722_1142.py b/streetup/interventions/migrations/0020_auto_20260722_1142.py deleted file mode 100644 index cc55e08..0000000 --- a/streetup/interventions/migrations/0020_auto_20260722_1142.py +++ /dev/null @@ -1,49 +0,0 @@ -# Generated by Django 5.2.8 on 2026-07-22 09:42 - -from django.db import migrations - - -def inject_oa054_routing(apps, schema_editor): - DirectContractRouting = apps.get_model('interventions', 'DirectContractRouting') - Contract = apps.get_model('contracts', 'Contract') - Symptom = apps.get_model('interventions', 'Symptom') - - # Find the contracts - contract_x005 = Contract.objects.filter(contract_number='X00.005').first() - contract_x006 = Contract.objects.filter(contract_number='X00.006').first() - symptom_clean = Symptom.objects.filter(code='TU_CLEAN_ROADWAY').first() - - # If X00.005 and TU_CLEAN_ROADWAY symptom exist, create the routing rule - if contract_x005 and symptom_clean: - DirectContractRouting.objects.get_or_create( - thematic='structures', - asset_code='OA054', - symptom=symptom_clean, - defaults={'contract': contract_x005} - ) - - # If X00.006 exists, create the default routing rule for OA054 - if contract_x006: - DirectContractRouting.objects.get_or_create( - thematic='structures', - asset_code='OA054', - symptom=None, - defaults={'contract': contract_x006} - ) - - -def reverse_oa054_routing(apps, schema_editor): - DirectContractRouting = apps.get_model('interventions', 'DirectContractRouting') - DirectContractRouting.objects.filter(thematic='structures', asset_code='OA054').delete() - - -class Migration(migrations.Migration): - - dependencies = [ - ('interventions', '0019_directcontractrouting'), - ('contracts', '__first__'), - ] - - operations = [ - migrations.RunPython(inject_oa054_routing, reverse_code=reverse_oa054_routing), - ] diff --git a/streetup/interventions/models.py b/streetup/interventions/models.py index c6bf913..58cd002 100644 --- a/streetup/interventions/models.py +++ b/streetup/interventions/models.py @@ -712,7 +712,7 @@ class InterventionLink(models.Model): name="uniq_intervention_link", ), models.CheckConstraint( - check=~Q(first=F("second")), + condition=~Q(first=F("second")), name="prevent_self_link", ), ] diff --git a/streetup/maps/migrations/0001_initial.py b/streetup/maps/migrations/0001_initial.py index 6090f8b..1a3290f 100644 --- a/streetup/maps/migrations/0001_initial.py +++ b/streetup/maps/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 from django.conf import settings from django.db import migrations, models diff --git a/streetup/notifications/migrations/0001_initial.py b/streetup/notifications/migrations/0001_initial.py index 274e556..f70ff5e 100644 --- a/streetup/notifications/migrations/0001_initial.py +++ b/streetup/notifications/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import django.db.models.deletion import notifications.models diff --git a/streetup/observations/migrations/0001_initial.py b/streetup/observations/migrations/0001_initial.py index c5f3713..2eca25e 100644 --- a/streetup/observations/migrations/0001_initial.py +++ b/streetup/observations/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import common.storages import django.contrib.gis.db.models.fields @@ -143,7 +143,7 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True)), ('observation_type', models.CharField(choices=[('incident', 'Incident'), ('inventory', 'Inventaire'), ('remark', 'Remarque')], default='incident', max_length=20)), ('geom', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=3812)), - ('status', models.CharField(choices=[('in_preparation', 'En préparation'), ('to_process', 'À traiter'), ('in_progress', 'En cours'), ('processed', 'Traité'), ('not_relevant', 'Non relevant'), ('to_redirect', 'À rediriger'), ('duplicate', 'Doublon'), ('archived', 'Archivé')], default='in_preparation', max_length=20)), + ('status', models.CharField(choices=[('in_preparation', 'En préparation'), ('to_process', 'À traiter'), ('in_progress', 'En cours'), ('processed', 'Traité'), ('not_relevant', 'Non relevant'), ('to_redirect', 'À rediriger'), ('duplicate', 'Doublon'), ('closed', 'Clôturé'), ('archived', 'Archivé')], default='in_preparation', max_length=20)), ('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='observations', to='assets.assetcategory')), ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='observations', to=settings.AUTH_USER_MODEL)), ('intervention', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='observations', to='interventions.intervention')), diff --git a/streetup/observations/migrations/0002_initial.py b/streetup/observations/migrations/0002_initial.py index ab40123..cc9b404 100644 --- a/streetup/observations/migrations/0002_initial.py +++ b/streetup/observations/migrations/0002_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import django.db.models.deletion from django.conf import settings @@ -10,7 +10,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('common', '0003_initial'), + ('common', '0004_initial'), ('interventions', '0001_initial'), ('observations', '0001_initial'), ('projects', '0001_initial'), diff --git a/streetup/observations/migrations/0003_alter_observation_status.py b/streetup/observations/migrations/0003_alter_observation_status.py deleted file mode 100644 index bb121f9..0000000 --- a/streetup/observations/migrations/0003_alter_observation_status.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-07 09:14 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('observations', '0002_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='observation', - name='status', - field=models.CharField(choices=[('in_preparation', 'En préparation'), ('to_process', 'À traiter'), ('in_progress', 'En cours'), ('processed', 'Traité'), ('not_relevant', 'Non relevant'), ('to_redirect', 'À rediriger'), ('duplicate', 'Doublon'), ('closed', 'Clôturé'), ('archived', 'Archivé')], default='in_preparation', max_length=20), - ), - ] diff --git a/streetup/panoramax/migrations/0001_initial.py b/streetup/panoramax/migrations/0001_initial.py index 2c78203..e660e1a 100644 --- a/streetup/panoramax/migrations/0001_initial.py +++ b/streetup/panoramax/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-07-19 05:35 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import django.db.models.deletion from django.conf import settings @@ -26,6 +26,8 @@ class Migration(migrations.Migration): ('progress', models.IntegerField(default=0, verbose_name='Progression (%)')), ('error_message', models.TextField(blank=True, null=True, verbose_name="Message d'erreur")), ('upload_set_id', models.CharField(blank=True, max_length=100, null=True, verbose_name='ID de session Panoramax')), + ('associated_collections', models.JSONField(blank=True, default=list, verbose_name='Collections associées')), + ('camera_offset', models.IntegerField(default=0, verbose_name="Offset d'orientation caméra (degrés)")), ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Date de création')), ('updated_at', models.DateTimeField(auto_now=True, verbose_name='Date de mise à jour')), ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Utilisateur')), diff --git a/streetup/panoramax/migrations/0002_panoramaxupload_associated_collections.py b/streetup/panoramax/migrations/0002_panoramaxupload_associated_collections.py deleted file mode 100644 index 93647cd..0000000 --- a/streetup/panoramax/migrations/0002_panoramaxupload_associated_collections.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.8 on 2026-07-19 13:03 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('panoramax', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='panoramaxupload', - name='associated_collections', - field=models.JSONField(blank=True, default=list, verbose_name='Collections associées'), - ), - ] diff --git a/streetup/panoramax/migrations/0003_panoramaxupload_camera_offset.py b/streetup/panoramax/migrations/0003_panoramaxupload_camera_offset.py deleted file mode 100644 index 82fb222..0000000 --- a/streetup/panoramax/migrations/0003_panoramaxupload_camera_offset.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.8 on 2026-07-19 13:42 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('panoramax', '0002_panoramaxupload_associated_collections'), - ] - - operations = [ - migrations.AddField( - model_name='panoramaxupload', - name='camera_offset', - field=models.IntegerField(default=0, verbose_name="Offset d'orientation caméra (degrés)"), - ), - ] diff --git a/streetup/projects/migrations/0001_initial.py b/streetup/projects/migrations/0001_initial.py index e72f485..01ce1d2 100644 --- a/streetup/projects/migrations/0001_initial.py +++ b/streetup/projects/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import common.storages import django.contrib.gis.db.models.fields @@ -13,7 +13,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('common', '0003_initial'), + ('common', '0004_initial'), ('contenttypes', '0002_remove_content_type_name'), ('contracts', '0001_initial'), ('documents', '0001_initial'), diff --git a/streetup/reporting/migrations/0001_initial.py b/streetup/reporting/migrations/0001_initial.py index 59cd974..050b730 100644 --- a/streetup/reporting/migrations/0001_initial.py +++ b/streetup/reporting/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import django.db.models.deletion from django.db import migrations, models diff --git a/streetup/road_detection/migrations/0001_initial.py b/streetup/road_detection/migrations/0001_initial.py index 62aa890..e81e5a7 100644 --- a/streetup/road_detection/migrations/0001_initial.py +++ b/streetup/road_detection/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import django.db.models.deletion from django.conf import settings diff --git a/streetup/schools/migrations/0001_initial.py b/streetup/schools/migrations/0001_initial.py index cf578c1..4175c18 100644 --- a/streetup/schools/migrations/0001_initial.py +++ b/streetup/schools/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import common.storages import django.db.models.deletion diff --git a/streetup/schools/migrations/0002_trigram_extension.py b/streetup/schools/migrations/0002_trigram_extension.py deleted file mode 100644 index 2cc3a5a..0000000 --- a/streetup/schools/migrations/0002_trigram_extension.py +++ /dev/null @@ -1,12 +0,0 @@ -from django.contrib.postgres.operations import TrigramExtension -from django.db import migrations - -class Migration(migrations.Migration): - - dependencies = [ - ('schools', '0001_initial'), - ] - - operations = [ - TrigramExtension(), - ] diff --git a/streetup/sign/migrations/0001_initial.py b/streetup/sign/migrations/0001_initial.py index b2d39db..b37bfae 100644 --- a/streetup/sign/migrations/0001_initial.py +++ b/streetup/sign/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import common.storages import django.contrib.gis.db.models.fields @@ -49,6 +49,9 @@ class Migration(migrations.Migration): ('name_nl', models.CharField(max_length=200)), ('description', models.TextField(blank=True, null=True)), ('sgv_picture', models.ImageField(blank=True, null=True, upload_to='sign/signpanels_types/')), + ('default_width', models.FloatField(blank=True, null=True, verbose_name='Largeur par défaut (cm)')), + ('default_height', models.FloatField(blank=True, null=True, verbose_name='Hauteur par défaut (cm)')), + ('default_diameter', models.FloatField(blank=True, null=True, verbose_name='Diamètre par défaut (cm)')), ], ), migrations.CreateModel( @@ -131,7 +134,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -162,6 +165,7 @@ class Migration(migrations.Migration): ('marked_as_removed_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_marked_as_removed', to=settings.AUTH_USER_MODEL, verbose_name='Marqué comme retiré par')), ('organization', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='sign_app_panels', to='sign.organization')), ('replaced_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='replaces', to='sign.signpanel', verbose_name='Remplacé par')), + ('street', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sign_app_panels', to='common.adrstreet')), ('updated_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Mis à jour par')), ], ), @@ -246,7 +250,7 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=50)), ('name_fr', models.CharField(blank=True, max_length=200, null=True)), ('name_nl', models.CharField(blank=True, max_length=200, null=True)), - ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé')], default='active', max_length=50)), + ('status', models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50)), ('obsolescence', models.CharField(blank=True, choices=[('good', 'Bon état'), ('medium', 'Moyen'), ('bad', 'Dégradé'), ('critical', 'Critique'), ('unknown', 'Inconnu')], default='unknown', null=True)), ('installation_date', models.DateTimeField(blank=True, null=True)), ('uninstallation_date', models.DateTimeField(blank=True, null=True)), @@ -270,6 +274,7 @@ class Migration(migrations.Migration): ('marked_as_removed_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_marked_as_removed', to=settings.AUTH_USER_MODEL, verbose_name='Marqué comme retiré par')), ('organization', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='sign_app_poles', to='sign.organization')), ('replaced_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='replaces', to='sign.signpole', verbose_name='Remplacé par')), + ('street', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sign_app_poles', to='common.adrstreet')), ('updated_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(app_label)s_%(class)s_updated_by', to=settings.AUTH_USER_MODEL, verbose_name='Mis à jour par')), ], ), @@ -328,16 +333,6 @@ class Migration(migrations.Migration): 'abstract': False, }, ), - migrations.AddField( - model_name='signpole', - name='street', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='sign_app_poles', to='sign.signstreet'), - ), - migrations.AddField( - model_name='signpanel', - name='street', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sign_app_panels', to='sign.signstreet'), - ), migrations.CreateModel( name='SignStreetDocument', fields=[ @@ -370,12 +365,12 @@ class Migration(migrations.Migration): name='signpaneltypearticle', unique_together={('panel_type', 'article')}, ), - migrations.AddIndex( - model_name='signpole', - index=models.Index(fields=['code'], name='sign_signpo_code_16a79b_idx'), - ), migrations.AddIndex( model_name='signpanel', index=models.Index(fields=['code'], name='sign_signpa_code_65ed88_idx'), ), + migrations.AddIndex( + model_name='signpole', + index=models.Index(fields=['code'], name='sign_signpo_code_16a79b_idx'), + ), ] diff --git a/streetup/sign/migrations/0002_alter_signpanel_status_alter_signpole_status.py b/streetup/sign/migrations/0002_alter_signpanel_status_alter_signpole_status.py deleted file mode 100644 index 5549e1e..0000000 --- a/streetup/sign/migrations/0002_alter_signpanel_status_alter_signpole_status.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.2.8 on 2026-05-23 05:45 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('sign', '0001_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='signpanel', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - migrations.AlterField( - model_name='signpole', - name='status', - field=models.CharField(choices=[('to_be_approved', 'À approuver'), ('planned', 'Planifié'), ('active', 'Actif'), ('damaged', 'Endommagé'), ('to_replace', 'A remplacer'), ('voluntarily_out_of_service', 'Mis hors service volontairement'), ('removed', 'Enlevé'), ('archived', 'Archivé')], default='active', max_length=50), - ), - ] diff --git a/streetup/sign/migrations/0003_alter_signpanel_street_alter_signpole_street.py b/streetup/sign/migrations/0003_alter_signpanel_street_alter_signpole_street.py deleted file mode 100644 index 1c41f77..0000000 --- a/streetup/sign/migrations/0003_alter_signpanel_street_alter_signpole_street.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 5.2.8 on 2026-05-24 16:32 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('common', '0005_userconfig_calendar_preferences'), - ('sign', '0002_alter_signpanel_status_alter_signpole_status'), - ] - - operations = [ - migrations.AlterField( - model_name='signpanel', - name='street', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sign_app_panels', to='common.adrstreet'), - ), - migrations.AlterField( - model_name='signpole', - name='street', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sign_app_poles', to='common.adrstreet'), - ), - ] diff --git a/streetup/sign/migrations/0004_signpaneltype_default_diameter_and_more.py b/streetup/sign/migrations/0004_signpaneltype_default_diameter_and_more.py deleted file mode 100644 index 51788c4..0000000 --- a/streetup/sign/migrations/0004_signpaneltype_default_diameter_and_more.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 5.2.8 on 2026-05-30 13:30 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('sign', '0003_alter_signpanel_street_alter_signpole_street'), - ] - - operations = [ - migrations.AddField( - model_name='signpaneltype', - name='default_diameter', - field=models.FloatField(blank=True, null=True, verbose_name='Diamètre par défaut (cm)'), - ), - migrations.AddField( - model_name='signpaneltype', - name='default_height', - field=models.FloatField(blank=True, null=True, verbose_name='Hauteur par défaut (cm)'), - ), - migrations.AddField( - model_name='signpaneltype', - name='default_width', - field=models.FloatField(blank=True, null=True, verbose_name='Largeur par défaut (cm)'), - ), - ] diff --git a/streetup/stock/migrations/0001_initial.py b/streetup/stock/migrations/0001_initial.py index e728c0e..472d1c6 100644 --- a/streetup/stock/migrations/0001_initial.py +++ b/streetup/stock/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.8 on 2026-05-21 13:51 +# Generated by Django 6.0.7 on 2026-07-22 13:42 import common.storages import django.contrib.gis.db.models.fields @@ -37,6 +37,7 @@ class Migration(migrations.Migration): ('reserved_quantity', models.IntegerField(default=0)), ('qr_code', models.ImageField(blank=True, null=True, upload_to='stock/qrcodes/products/', verbose_name='QR Code')), ('is_serialized', models.BooleanField(default=False, help_text='Si activé, chaque article de ce produit devra avoir un numéro de série unique.', verbose_name='Articles tracés (numéro de série)')), + ('is_active', models.BooleanField(default=True, help_text='Si désactivé, le produit ne sera plus disponible pour les opérations (nouvelles entrées, sorties, transferts, interventions).', verbose_name='Actif')), ], ), migrations.CreateModel( @@ -107,7 +108,11 @@ class Migration(migrations.Migration): ('order_number', models.CharField(max_length=100, unique=True)), ('date', models.DateTimeField(auto_now_add=True)), ('status', models.CharField(choices=[('to_process', 'A traiter'), ('pending', 'En attente'), ('processed', 'Traité'), ('cancelled', 'Annulé')], default='to_process', max_length=50)), + ('priority', models.CharField(choices=[('1', 'Urgent'), ('2', 'Elevé'), ('3', 'Normal'), ('4', 'Bas')], default='3', max_length=50, verbose_name='Priorité')), ('requester', models.CharField(blank=True, help_text="Personne ou service à l'origine de la demande", max_length=255, null=True, verbose_name='Demandeur')), + ('is_loan', models.BooleanField(default=False, verbose_name='Prêt de matériel')), + ('estimated_return_date', models.DateField(blank=True, null=True, verbose_name='Date de retour attendue')), + ('loan_returned', models.BooleanField(default=False, verbose_name='Prêt retourné')), ('qr_code', models.ImageField(blank=True, null=True, upload_to='stock/qrcodes/preparation_orders/', verbose_name='QR Code')), ('intervention', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='preparation_orders', to='interventions.intervention', verbose_name='Intervention')), ], @@ -200,6 +205,41 @@ class Migration(migrations.Migration): ('purchase_order', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='documents', to='stock.purchaseorder', verbose_name='Commande fournisseur')), ], ), + migrations.CreateModel( + name='RequestForQuote', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('code', models.CharField(blank=True, max_length=50, unique=True)), + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False)), + ('date_created', models.DateField(auto_now_add=True)), + ('status', models.CharField(choices=[('draft', 'Brouillon'), ('sent', 'Envoyée'), ('completed', 'Convertie en commande'), ('cancelled', 'Annulée')], default='draft', max_length=50, verbose_name='Statut')), + ('notes', models.TextField(blank=True, null=True, verbose_name='Notes')), + ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='created_request_for_quotes', to=settings.AUTH_USER_MODEL, verbose_name='Créé par')), + ('suppliers', models.ManyToManyField(blank=True, related_name='request_for_quotes', to='stock.supplier', verbose_name='Fournisseurs sollicités')), + ('warehouse', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='request_for_quotes', to='stock.warehouse', verbose_name='Entrepôt')), + ], + options={ + 'verbose_name': "Demande d'offre", + 'verbose_name_plural': "Demandes d'offres", + 'ordering': ('-date_created', '-id'), + }, + ), + migrations.AddField( + model_name='purchaseorder', + name='request_for_quote', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='purchase_orders', to='stock.requestforquote', verbose_name="Demande d'offre d'origine"), + ), + migrations.CreateModel( + name='RequestForQuoteItem', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('quantity', models.IntegerField(help_text='Quantité totale souhaitée', verbose_name='Quantité totale')), + ('num_articles', models.PositiveIntegerField(blank=True, null=True, verbose_name="Nombre d'articles")), + ('quantity_per_article', models.DecimalField(blank=True, decimal_places=3, max_digits=10, null=True, verbose_name='Quantité par article')), + ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='stock.product', verbose_name='Produit')), + ('request_for_quote', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='stock.requestforquote')), + ], + ), migrations.CreateModel( name='SerializedItem', fields=[ @@ -209,6 +249,7 @@ class Migration(migrations.Migration): ('notes', models.TextField(blank=True, default='', verbose_name='Notes')), ('qr_code', models.ImageField(blank=True, null=True, upload_to='stock/qrcodes/serialized_items/', verbose_name='QR Code')), ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Créé le')), + ('is_active', models.BooleanField(default=True, verbose_name='Actif')), ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='created_serialized_items', to=settings.AUTH_USER_MODEL, verbose_name='Créé par')), ('current_holder', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='held_serialized_items', to='contracts.companymember', verbose_name='Détenteur actuel')), ('product', models.ForeignKey(limit_choices_to={'is_serialized': True}, on_delete=django.db.models.deletion.CASCADE, related_name='serialized_items', to='stock.product', verbose_name='Produit')), @@ -229,7 +270,11 @@ class Migration(migrations.Migration): ('reason', models.TextField(blank=True, null=True, verbose_name='Raison')), ('requester', models.CharField(blank=True, help_text="Personne ou service à l'origine de la demande", max_length=255, null=True, verbose_name='Demandeur')), ('signature', models.ImageField(blank=True, help_text='Signature du réceptionnaire (image depuis tablette)', null=True, upload_to='stock_movements/signatures/', verbose_name='Signature')), - ('company', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='stock_batches', to='contracts.company', verbose_name='Entreprise')), + ('signature_name', models.CharField(blank=True, max_length=255, null=True, verbose_name='Nom du signataire')), + ('is_loan', models.BooleanField(default=False, verbose_name='Prêt de matériel')), + ('estimated_return_date', models.DateField(blank=True, null=True, verbose_name='Date de retour attendue')), + ('loan_returned', models.BooleanField(default=False, verbose_name='Prêt retourné')), + ('company', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='stock_batches', to='contracts.company', verbose_name='Entreprise / Organisation')), ('contract', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='stock_batches', to='contracts.contract', verbose_name='Contrat')), ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='created_stock_batches', to=settings.AUTH_USER_MODEL, verbose_name='Créé par')), ('person', models.ForeignKey(blank=True, help_text='Personne à qui le matériel est attribué ou qui le restitue', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='stock_batches', to='contracts.companymember', verbose_name='Personne')), @@ -248,6 +293,7 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('image', models.ImageField(upload_to=stock.models.stock_batch_signature_upload_path, verbose_name='Image de signature')), ('signed_at', models.DateTimeField(auto_now_add=True, verbose_name='Signé le')), + ('signature_name', models.CharField(blank=True, max_length=255, null=True, verbose_name='Nom du signataire')), ('signed_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='batch_signatures', to=settings.AUTH_USER_MODEL, verbose_name='Signé par')), ('batch', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='signatures', to='stock.stockmovementbatch', verbose_name='Lot')), ], @@ -339,6 +385,8 @@ class Migration(migrations.Migration): ('num_articles', models.PositiveIntegerField(blank=True, help_text="Nombre d'articles commandés (ex: nombre de sacs)", null=True, verbose_name="Nombre d'articles")), ('quantity_per_article', models.DecimalField(blank=True, decimal_places=3, help_text="Quantité dans l'unité du produit par article (ex: 10 kg par sac)", max_digits=10, null=True, verbose_name='Quantité par article')), ('received_quantity', models.IntegerField(default=0, help_text='Quantité déjà réceptionnée pour cet article', verbose_name='Quantité reçue')), + ('unit_price', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='Prix unitaire (HTVA)')), + ('vat_rate', models.DecimalField(decimal_places=2, default=21.0, max_digits=5, verbose_name='Taux de TVA (%)')), ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='stock.product')), ('purchase_order', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='stock.purchaseorder')), ('location', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='stock.warehouselocation')), @@ -349,6 +397,11 @@ class Migration(migrations.Migration): name='output_location', field=models.ForeignKey(blank=True, help_text="Emplacement où le produit fini sera ajouté au stock. Si vide, utilise l'emplacement par défaut de la conception.", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='conception_orders_output', to='stock.warehouselocation', verbose_name='Emplacement de stockage du produit fini'), ), + migrations.AddField( + model_name='product', + name='authorized_locations', + field=models.ManyToManyField(blank=True, help_text='Emplacements dans lesquels ce produit est autorisé à être stocké (vide = tous autorisés).', related_name='authorized_products', to='stock.warehouselocation', verbose_name='Emplacements autorisés'), + ), migrations.CreateModel( name='Inventory', fields=[ @@ -358,6 +411,7 @@ class Migration(migrations.Migration): ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('validated_at', models.DateTimeField(blank=True, null=True)), + ('validator_comment', models.TextField(blank=True, default='', verbose_name='Commentaire du validateur')), ('qr_code', models.ImageField(blank=True, null=True, upload_to='stock/qrcodes/inventories/', verbose_name='QR Code')), ('validated_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='validated_inventories', to=settings.AUTH_USER_MODEL, verbose_name='Validé par')), ('warehouse_location', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='inventories', to='stock.warehouselocation')), @@ -375,8 +429,11 @@ class Migration(migrations.Migration): ('is_validated', models.BooleanField(default=False, verbose_name='Validé')), ('validated_at', models.DateTimeField(blank=True, null=True, verbose_name='Validé le')), ('comment', models.TextField(blank=True, default='', verbose_name='Commentaire')), + ('validator_comment', models.TextField(blank=True, default='', verbose_name='Commentaire du validateur')), + ('comment_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='inventory_item_comments', to=settings.AUTH_USER_MODEL, verbose_name='Commentaire par')), ('inventory', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='stock.inventory')), ('validated_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='validated_inventory_items', to=settings.AUTH_USER_MODEL, verbose_name='Validé par')), + ('validator_comment_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='inventory_item_validator_comments', to=settings.AUTH_USER_MODEL, verbose_name='Commentaire validateur par')), ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='stock.product')), ], options={ diff --git a/streetup/stock/migrations/0002_stockbatchsignature_signature_name_and_more.py b/streetup/stock/migrations/0002_stockbatchsignature_signature_name_and_more.py deleted file mode 100644 index 0ce36fc..0000000 --- a/streetup/stock/migrations/0002_stockbatchsignature_signature_name_and_more.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.2.8 on 2026-05-24 11:20 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('stock', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='stockbatchsignature', - name='signature_name', - field=models.CharField(blank=True, max_length=255, null=True, verbose_name='Nom du signataire'), - ), - migrations.AddField( - model_name='stockmovementbatch', - name='signature_name', - field=models.CharField(blank=True, max_length=255, null=True, verbose_name='Nom du signataire'), - ), - ] diff --git a/streetup/stock/migrations/0003_preparationorder_priority.py b/streetup/stock/migrations/0003_preparationorder_priority.py deleted file mode 100644 index fd3a0c4..0000000 --- a/streetup/stock/migrations/0003_preparationorder_priority.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.8 on 2026-05-24 11:50 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('stock', '0002_stockbatchsignature_signature_name_and_more'), - ] - - operations = [ - migrations.AddField( - model_name='preparationorder', - name='priority', - field=models.CharField(choices=[('1', 'Urgent'), ('2', 'Elevé'), ('3', 'Normal'), ('4', 'Bas')], default='3', max_length=50, verbose_name='Priorité'), - ), - ] diff --git a/streetup/stock/migrations/0004_product_is_active_serializeditem_is_active.py b/streetup/stock/migrations/0004_product_is_active_serializeditem_is_active.py deleted file mode 100644 index af59528..0000000 --- a/streetup/stock/migrations/0004_product_is_active_serializeditem_is_active.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.2.8 on 2026-05-27 07:10 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('stock', '0003_preparationorder_priority'), - ] - - operations = [ - migrations.AddField( - model_name='product', - name='is_active', - field=models.BooleanField(default=True, help_text='Si désactivé, le produit ne sera plus disponible pour les opérations (nouvelles entrées, sorties, transferts, interventions).', verbose_name='Actif'), - ), - migrations.AddField( - model_name='serializeditem', - name='is_active', - field=models.BooleanField(default=True, verbose_name='Actif'), - ), - ] diff --git a/streetup/stock/migrations/0005_product_authorized_locations.py b/streetup/stock/migrations/0005_product_authorized_locations.py deleted file mode 100644 index aa20c13..0000000 --- a/streetup/stock/migrations/0005_product_authorized_locations.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-01 16:41 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('stock', '0004_product_is_active_serializeditem_is_active'), - ] - - operations = [ - migrations.AddField( - model_name='product', - name='authorized_locations', - field=models.ManyToManyField(blank=True, help_text='Emplacements dans lesquels ce produit est autorisé à être stocké (vide = tous autorisés).', related_name='authorized_products', to='stock.warehouselocation', verbose_name='Emplacements autorisés'), - ), - ] diff --git a/streetup/stock/migrations/0006_inventory_validator_comment_and_more.py b/streetup/stock/migrations/0006_inventory_validator_comment_and_more.py deleted file mode 100644 index 6f43332..0000000 --- a/streetup/stock/migrations/0006_inventory_validator_comment_and_more.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-05 08:47 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('stock', '0005_product_authorized_locations'), - ] - - operations = [ - migrations.AddField( - model_name='inventory', - name='validator_comment', - field=models.TextField(blank=True, default='', verbose_name='Commentaire du validateur'), - ), - migrations.AddField( - model_name='inventoryitem', - name='validator_comment', - field=models.TextField(blank=True, default='', verbose_name='Commentaire du validateur'), - ), - ] diff --git a/streetup/stock/migrations/0007_add_comment_by_to_inventoryitem.py b/streetup/stock/migrations/0007_add_comment_by_to_inventoryitem.py deleted file mode 100644 index 30684dd..0000000 --- a/streetup/stock/migrations/0007_add_comment_by_to_inventoryitem.py +++ /dev/null @@ -1,26 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-05 10:17 - -import django.db.models.deletion -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('stock', '0006_inventory_validator_comment_and_more'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.AddField( - model_name='inventoryitem', - name='comment_by', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='inventory_item_comments', to=settings.AUTH_USER_MODEL, verbose_name='Commentaire par'), - ), - migrations.AddField( - model_name='inventoryitem', - name='validator_comment_by', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='inventory_item_validator_comments', to=settings.AUTH_USER_MODEL, verbose_name='Commentaire validateur par'), - ), - ] diff --git a/streetup/stock/migrations/0008_purchaseorderitem_unit_price_and_more.py b/streetup/stock/migrations/0008_purchaseorderitem_unit_price_and_more.py deleted file mode 100644 index 31b7e8d..0000000 --- a/streetup/stock/migrations/0008_purchaseorderitem_unit_price_and_more.py +++ /dev/null @@ -1,62 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-17 08:29 - -import django.db.models.deletion -import uuid -from django.conf import settings -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('stock', '0007_add_comment_by_to_inventoryitem'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.AddField( - model_name='purchaseorderitem', - name='unit_price', - field=models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='Prix unitaire (HTVA)'), - ), - migrations.AddField( - model_name='purchaseorderitem', - name='vat_rate', - field=models.DecimalField(decimal_places=2, default=21.0, max_digits=5, verbose_name='Taux de TVA (%)'), - ), - migrations.CreateModel( - name='RequestForQuote', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('code', models.CharField(blank=True, max_length=50, unique=True)), - ('uuid', models.UUIDField(default=uuid.uuid4, editable=False)), - ('date_created', models.DateField(auto_now_add=True)), - ('status', models.CharField(choices=[('draft', 'Brouillon'), ('sent', 'Envoyée'), ('completed', 'Convertie en commande'), ('cancelled', 'Annulée')], default='draft', max_length=50, verbose_name='Statut')), - ('notes', models.TextField(blank=True, null=True, verbose_name='Notes')), - ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='created_request_for_quotes', to=settings.AUTH_USER_MODEL, verbose_name='Créé par')), - ('suppliers', models.ManyToManyField(blank=True, related_name='request_for_quotes', to='stock.supplier', verbose_name='Fournisseurs sollicités')), - ('warehouse', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='request_for_quotes', to='stock.warehouse', verbose_name='Entrepôt')), - ], - options={ - 'verbose_name': "Demande d'offre", - 'verbose_name_plural': "Demandes d'offres", - 'ordering': ('-date_created', '-id'), - }, - ), - migrations.AddField( - model_name='purchaseorder', - name='request_for_quote', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='purchase_orders', to='stock.requestforquote', verbose_name="Demande d'offre d'origine"), - ), - migrations.CreateModel( - name='RequestForQuoteItem', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('quantity', models.IntegerField(help_text='Quantité totale souhaitée', verbose_name='Quantité totale')), - ('num_articles', models.PositiveIntegerField(blank=True, null=True, verbose_name="Nombre d'articles")), - ('quantity_per_article', models.DecimalField(blank=True, decimal_places=3, max_digits=10, null=True, verbose_name='Quantité par article')), - ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='stock.product', verbose_name='Produit')), - ('request_for_quote', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='items', to='stock.requestforquote')), - ], - ), - ] diff --git a/streetup/stock/migrations/0009_alter_stockmovementbatch_company.py b/streetup/stock/migrations/0009_alter_stockmovementbatch_company.py deleted file mode 100644 index 7cdb66c..0000000 --- a/streetup/stock/migrations/0009_alter_stockmovementbatch_company.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-17 14:51 - -import django.db.models.deletion -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('contracts', '0007_companyteam_restrict_today_interventions_visibility_and_more'), - ('stock', '0008_purchaseorderitem_unit_price_and_more'), - ] - - operations = [ - migrations.AlterField( - model_name='stockmovementbatch', - name='company', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='stock_batches', to='contracts.company', verbose_name='Entreprise / Organisation'), - ), - ] diff --git a/streetup/stock/migrations/0010_preparationorder_estimated_return_date_and_more.py b/streetup/stock/migrations/0010_preparationorder_estimated_return_date_and_more.py deleted file mode 100644 index 8ae453a..0000000 --- a/streetup/stock/migrations/0010_preparationorder_estimated_return_date_and_more.py +++ /dev/null @@ -1,43 +0,0 @@ -# Generated by Django 5.2.8 on 2026-06-17 15:13 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('stock', '0009_alter_stockmovementbatch_company'), - ] - - operations = [ - migrations.AddField( - model_name='preparationorder', - name='estimated_return_date', - field=models.DateField(blank=True, null=True, verbose_name='Date de retour attendue'), - ), - migrations.AddField( - model_name='preparationorder', - name='is_loan', - field=models.BooleanField(default=False, verbose_name='Prêt de matériel'), - ), - migrations.AddField( - model_name='preparationorder', - name='loan_returned', - field=models.BooleanField(default=False, verbose_name='Prêt retourné'), - ), - migrations.AddField( - model_name='stockmovementbatch', - name='estimated_return_date', - field=models.DateField(blank=True, null=True, verbose_name='Date de retour attendue'), - ), - migrations.AddField( - model_name='stockmovementbatch', - name='is_loan', - field=models.BooleanField(default=False, verbose_name='Prêt de matériel'), - ), - migrations.AddField( - model_name='stockmovementbatch', - name='loan_returned', - field=models.BooleanField(default=False, verbose_name='Prêt retourné'), - ), - ] diff --git a/streetup/streetup/settings.py b/streetup/streetup/settings.py index efec875..bbf6115 100644 --- a/streetup/streetup/settings.py +++ b/streetup/streetup/settings.py @@ -73,6 +73,7 @@ INSTALLED_APPS = [ 'django.contrib.messages', 'django.contrib.staticfiles', "django.contrib.gis", + "django.contrib.postgres", "crispy_forms", "crispy_bootstrap5", "rest_framework",