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: 0 additions & 1 deletion mesads/app/admin/ads.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,6 @@ def ads_users(self, ads):
<tr>
<td>{ads_user.status}</td>
<td>{ads_user.name}</td>
<td>{ads_user.siret}</td>
<td>{ads_user.license_number}</td>
</tr>
"""
Expand Down
1 change: 1 addition & 0 deletions mesads/app/admin/ads_manager_administrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def get_queryset(self, request):

fields = (
"prefecture",
"notify_verification_enabled",
"expected_ads_count",
"ads_managers_link",
"display_ads_count",
Expand Down
22 changes: 22 additions & 0 deletions mesads/app/crons.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from contextlib import redirect_stderr, redirect_stdout

from django.core.management import call_command
from django.utils import timezone
from django_cron import CronJobBase, Schedule
from sentry_sdk import capture_exception

Expand Down Expand Up @@ -67,3 +68,24 @@ def do(self):
with redirect_stdout(buf), redirect_stderr(buf):
call_command("liste_attente_mail_delai_depasse")
return buf.getvalue()


class NotificationVerification(CronJobBase):
# Run every day
schedule = Schedule(run_every_mins=60 * 24)

code = "notify_verifications" # unique code to represent this cron job

@sentry_exceptions
def do(self):
# Redirect stdout and stderr to a buffer to capture the output of the
# command. By returning it, django-cron will log it in the database.

today = timezone.localdate()
if today.day != 15:
return "Skipped - Notifications envoyées uniquement le 15 de chaque mois."

buf = io.StringIO()
with redirect_stdout(buf), redirect_stderr(buf):
call_command("notify_prefectures_gestionnaires")
return buf.getvalue()
8 changes: 6 additions & 2 deletions mesads/app/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ class Meta:
"owner_phone",
"owner_mobile",
"owner_email",
"location",
"locataire_nom",
"locataire_siret",
"locataire_date",
"locataire_email",
"locataire_phone",
"notes",
# It is important to leave "deleted_at" in the fields, otherwise
# django.db.models.constraints.CheckConstraint.validate() will silently skip
Expand Down Expand Up @@ -204,9 +210,7 @@ def _should_delete_form(self, form):
fields=(
"status",
"name",
"siret",
"license_number",
"date_location_gerance",
"deleted_at",
),
can_delete=True,
Expand Down
2 changes: 0 additions & 2 deletions mesads/app/management/commands/ads_donnees_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,6 @@ def process_batch(ids):
ads_id=ads["id"],
status=status,
name=f"{f.last_name()} {f.first_name()}",
siret="",
license_number="123456",
)
)
Expand All @@ -139,7 +138,6 @@ def process_batch(ids):
ads_id=ads["id"],
status="titulaire_exploitant",
name="", # vide comme dans ta version
siret="",
license_number="123456",
)
)
Expand Down
53 changes: 53 additions & 0 deletions mesads/app/management/commands/create_previous_update_logs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from django.core.management.base import BaseCommand
from django.db.models import Count
from reversion.models import Version

from mesads.app.models import ADS, ADSManagerAdministrator, ADSUpdateLog


class Command(BaseCommand):
help = "Import ADS from excel file"

def add_arguments(self, parser):
parser.add_argument(
"--departement", required=True, help="Numéro du département"
)

def create_for_ads_retrospectively(self, ads):
latest_version = Version.objects.get_for_object(ads).first()
if latest_version is None:
return False

user = latest_version.revision.user
last_update = ads.last_update
if not last_update or not user:
return False
update_log = ADSUpdateLog.create_for_ads(ads, user)
ADSUpdateLog.objects.filter(pk=update_log.pk).update(update_at=last_update)
return True

def handle(self, departement, **opts):
administrator = ADSManagerAdministrator.objects.filter(
prefecture__numero=departement
).first()
if not administrator:
return

nb_update_log_crees = 0
nb_update_logs_non_cree = 0

ads_without_update_logs = (
ADS.objects.filter(ads_manager__administrator=administrator)
.annotate(nb_update_logs=Count("ads_update_logs"))
.filter(nb_update_logs=0)
)
self.stdout.write(f"Nb ADS sans update logs: {ads_without_update_logs.count()}")
for ads in ads_without_update_logs:
result = self.create_for_ads_retrospectively(ads)
if result:
nb_update_log_crees += 1
else:
nb_update_logs_non_cree += 1

self.stdout.write(f"Nb update log créés {nb_update_log_crees}")
self.stdout.write(f"Nb update log non créés {nb_update_logs_non_cree}")
15 changes: 15 additions & 0 deletions mesads/app/management/commands/notify_prefectures_gestionnaires.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from django.core.management.base import BaseCommand

from mesads.app.services.notifications import notify_prefectures_gestionnaires


class Command(BaseCommand):
help = (
"Notifie les gestionnaires des prefectures en "
"cas d'ADS pas complètes et vérifiées"
)

def handle(self, *args, **options):
notify_prefectures_gestionnaires(
progress=self.stdout.write,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Generated by Django 5.2.10 on 2026-06-08 08:55

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('app', '0117_auto_20260527_1719'),
]

operations = [
migrations.AddField(
model_name='ads',
name='locataire_date',
field=models.DateField(blank=True, null=True, verbose_name='Date du contract de location'),
),
migrations.AddField(
model_name='ads',
name='locataire_email',
field=models.CharField(blank=True, default='', max_length=128, verbose_name="Email du locataire de l'ADS"),
),
migrations.AddField(
model_name='ads',
name='locataire_nom',
field=models.CharField(blank=True, default='', max_length=512, verbose_name="Nom du locataire de l'ADS (personne physique ou morale)"),
),
migrations.AddField(
model_name='ads',
name='locataire_phone',
field=models.CharField(blank=True, default='', max_length=128, verbose_name="Téléphone fixe du locataire de l'ADS"),
),
migrations.AddField(
model_name='ads',
name='locataire_siret',
field=models.CharField(blank=True, default='', help_text="Nous validons ce numéro en consultant les données officielles de l'INSEE. Indiquez le numéro de SIRET (14 chiffres) sans espace. ", max_length=128, verbose_name="SIRET du locataire de l'ADS"),
),
migrations.AddField(
model_name='ads',
name='location',
field=models.BooleanField(blank=True, default=False, verbose_name="L'ADS est elle en location?"),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.2.10 on 2026-06-10 09:47

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('app', '0118_ads_locataire_date_ads_locataire_email_and_more'),
]

operations = [
migrations.AddField(
model_name='adsmanageradministrator',
name='notify_verification_enabled',
field=models.BooleanField(blank=True, default=False, help_text="Si cette case est cochée, un mail sera envoyé mensuellement aux gestionnaires attachés à cette préfecture pour les notifier si au moins une de leur ADS n'est pas complète et à jour", verbose_name='Activer les notifications pour la vérification'),
),
]
31 changes: 31 additions & 0 deletions mesads/app/migrations/0120_auto_20260608_1200.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Generated by Django 5.2.10 on 2026-06-08 09:02

from django.db import migrations


def migrate_data_locataire(app, schema_editor):
ADS = app.get_model("app", "ADS")
LOCATAIRE_GERANT = "locataire_gerant"
ads_with_locataire = ADS.objects.filter(adsuser__status=LOCATAIRE_GERANT)

for ads in ads_with_locataire:
users = ads.adsuser_set.filter(status=LOCATAIRE_GERANT)
ads.location = True
for u in users:
if u.name and not ads.locataire_nom:
ads.locataire_nom = u.name
if u.siret and not ads.locataire_siret:
ads.locataire_siret = u.siret
if u.date_location_gerance and not ads.locataire_date:
ads.locataire_date = u.date_location_gerance
ads.save()

class Migration(migrations.Migration):

dependencies = [
('app', '0119_adsmanageradministrator_notify_verification_enabled'),
]

operations = [
migrations.RunPython(migrate_data_locataire)
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Generated by Django 5.2.10 on 2026-06-10 14:45

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('app', '0120_auto_20260608_1200'),
]

operations = [
migrations.RemoveConstraint(
model_name='adsuser',
name='siret_empty_for_titulaire_exploitant',
),
migrations.RemoveConstraint(
model_name='adsuser',
name='siret_empty_for_legal_representative',
),
migrations.RemoveConstraint(
model_name='adsuser',
name='siret_empty_for_salarie',
),
migrations.RemoveConstraint(
model_name='adsuser',
name='ads_location_gerance_set_only_for_locataire_gerant',
),
migrations.RemoveField(
model_name='adsuser',
name='date_location_gerance',
),
migrations.AlterField(
model_name='ads',
name='locataire_date',
field=models.DateField(blank=True, null=True, verbose_name='Date du contrat de location'),
),
migrations.AlterField(
model_name='adsuser',
name='siret',
field=models.CharField(blank=True, default='', help_text="Nous validons ce numéro en consultant les données officielles de l'INSEE. Indiquez le numéro de SIRET (14 chiffres) sans espace. ", max_length=128, verbose_name="SIRET de l'exploitant de l'ADS"),
),
]
Loading
Loading