Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ node_modules/

#IDE
.vscode/
.cursor/

#temporaire
/.tgitconfig
Expand Down
129 changes: 129 additions & 0 deletions conventions/management/commands/cleanup_ddt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
from django.core.management.base import BaseCommand

from instructeurs.models import Administration


class Command(BaseCommand):
help = "Foo"

def add_arguments(self, parser):
parser.add_argument(
"--verbose",
help="Verbose output",
action="store_true",
default=False,
)
parser.add_argument(
"--dry-run",
help="Dry run",
action="store_true",
default=False,
)

def handle(self, *args, **options):
verbose = options["verbose"]
dry_run = options["dry_run"]

ddt = Administration.objects.filter(code__startswith="DD").exclude(
code__startswith="DDI"
)
self.stdout.write(self.style.SUCCESS(f"## {ddt.count()} DDT"))
self.stdout.write(self.style.SUCCESS(""))
if verbose:
for d in ddt.order_by("code"):
self.stdout.write(self.style.SUCCESS(f"{d.code} - {d.nom}"))
self.stdout.write(self.style.SUCCESS(""))
ddi = Administration.objects.filter(code__startswith="DDI")
self.stdout.write(self.style.SUCCESS(f"\n## {ddi.count()} DDI\n"))
self.stdout.write(self.style.SUCCESS(""))
if verbose:
for d in ddi.order_by("code"):
self.stdout.write(self.style.SUCCESS(f"{d.code} - {d.nom}"))
ddi_codes = [d.code for d in ddi]
ddi_by_code = {d.code: d for d in ddi}
ddt_ddi = {}
for dd in ddt:
ddi_code = dd.code.replace("DD", "DDI")
if ddi_code in ddi_codes:
ddt_ddi[dd.code] = ddi_by_code[ddi_code]
else:
self.stdout.write(
self.style.WARNING(
f"{dd.code} - {dd.nom} doesn't have a DDI equivalence"
)
)
nb_conventions_total = 0
self.stdout.write(self.style.SUCCESS(""))
self.stdout.write(self.style.SUCCESS("## Détails par DDT"))
self.stdout.write(self.style.SUCCESS(""))
for d in ddt.order_by("code"):
nb_conventions_ddt = 0
conventions = []
self.stdout.write(self.style.SUCCESS(""))
self.stdout.write(self.style.SUCCESS(f"### {d.code} - {d.nom}"))
self.stdout.write(self.style.SUCCESS(""))
if nb_programme := d.programmes.all().count():
self.stdout.write(
self.style.SUCCESS(
f"{d.code} - {d.nom} : {nb_programme} programmes"
)
)
nb_users = len(list(set([r.user for r in d.roles.all()])))
if nb_users > 1:
self.stdout.write(
self.style.NOTICE(f"{d.code} - {d.nom} : {nb_users} users")
)
else:
self.stdout.write(
self.style.SUCCESS(f"{d.code} - {d.nom} : {nb_users} users")
)
for p in d.programmes.all():
for c in p.conventions.all():
nb_conventions_ddt += 1
conventions.append(c)
self.stdout.write(
self.style.SUCCESS(
f"{d.code} - {d.nom} : {nb_conventions_ddt} conventions"
)
)
if verbose:
self.stdout.write(self.style.SUCCESS(""))
self.stdout.write(self.style.SUCCESS("#### Conventions"))
self.stdout.write(self.style.SUCCESS(""))
for c in conventions:
self.stdout.write(self.style.SUCCESS(f"{c} ({c.uuid})"))
nb_conventions_total += nb_conventions_ddt
self.stdout.write(self.style.SUCCESS(f"{nb_conventions_total} conventions"))

self.stdout.write(self.style.WARNING(""))
self.stdout.write(self.style.WARNING("Début de ré-attribution"))
for d in ddt.order_by("code"):
self.stdout.write(self.style.WARNING(""))
self.stdout.write(
self.style.WARNING(
f"Début de ré-attribution pour la DDT {d.code} - {d.nom} vers"
f" {ddt_ddi[d.code].code} ({ddt_ddi[d.code].nom})"
)
)
self.stdout.write(self.style.WARNING(""))
for p in d.programmes.all():
if verbose:
self.stdout.write(
self.style.SUCCESS(
f"Ré-attribution de {p} de {d.code} vers {ddt_ddi[d.code].code}"
)
)
if not dry_run:
p.administration_id = ddt_ddi[d.code].id
p.save()
if d.programmes.all().count() != 0 and not dry_run:
raise Exception(
f"La DDT {d.code} - {d.nom} a plusieurs programmes après"
f" ré-attribution : {d.programmes.all()}"
)
self.stdout.write(self.style.SUCCESS(""))
self.stdout.write(
self.style.SUCCESS(f"Suppression de la DDT {d.code} - {d.nom}")
)
if not dry_run:
d.delete()
26 changes: 26 additions & 0 deletions programmes/migrations/0128_alter_programme_administration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Generated by Django 5.2.4 on 2025-08-12 06:08

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("instructeurs", "0001_initial_squashed_0017_auto_20230925_1209"),
("programmes", "0127_alter_typestationnement_typologie"),
]

operations = [
migrations.AlterField(
model_name="programme",
name="administration",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="programmes",
to="instructeurs.administration",
),
),
]
6 changes: 5 additions & 1 deletion programmes/models/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,11 @@ class Meta:
null=False,
)
administration = models.ForeignKey(
"instructeurs.Administration", on_delete=models.SET_NULL, null=True, blank=True
"instructeurs.Administration",
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="programmes",
)
adresse = models.TextField(blank=True)
code_postal = models.CharField(max_length=5, blank=True)
Expand Down
Loading