327 lines
28 KiB
Python
327 lines
28 KiB
Python
# Generated by Django 5.2.8 on 2026-05-21 13:51
|
|
|
|
import django.contrib.gis.db.models.fields
|
|
import django.contrib.postgres.fields
|
|
import django.core.validators
|
|
import django.db.models.deletion
|
|
from django.conf import settings
|
|
from django.db import migrations, models
|
|
|
|
|
|
class Migration(migrations.Migration):
|
|
|
|
initial = True
|
|
|
|
dependencies = [
|
|
('assets', '0001_initial'),
|
|
('contenttypes', '0002_remove_content_type_name'),
|
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
]
|
|
|
|
operations = [
|
|
migrations.CreateModel(
|
|
name='AppView',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('code', models.CharField(max_length=50, unique=True, verbose_name='Code')),
|
|
('name_fr', models.CharField(max_length=100, verbose_name='Nom')),
|
|
('name_nl', models.CharField(max_length=100, verbose_name='Naam')),
|
|
('icon', models.CharField(blank=True, max_length=50, null=True, verbose_name='Icône Bootstrap')),
|
|
('url_name', models.CharField(help_text="Ex: 'home:index' ou 'sign:index'", max_length=100, verbose_name="Nom de l'URL")),
|
|
('is_default', models.BooleanField(default=False, help_text='Vue affichée par défaut pour les nouveaux utilisateurs', verbose_name='Vue par défaut')),
|
|
('order', models.PositiveIntegerField(default=0, verbose_name="Ordre d'affichage")),
|
|
],
|
|
options={
|
|
'verbose_name': 'Vue applicative',
|
|
'verbose_name_plural': 'Vues applicatives',
|
|
'ordering': ['order', 'name_fr'],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='Municipality',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('fid', models.CharField(max_length=100)),
|
|
('name_fr', models.CharField(max_length=255, verbose_name='Name FR')),
|
|
('name_nl', models.CharField(max_length=255, verbose_name='Name NL')),
|
|
('niscode', models.CharField(blank=True, max_length=30, null=True, verbose_name='Postal code')),
|
|
('geom', django.contrib.gis.db.models.fields.MultiPolygonField(blank=True, null=True, srid=3812)),
|
|
],
|
|
),
|
|
migrations.CreateModel(
|
|
name='Role',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('name', models.CharField(max_length=50, unique=True)),
|
|
],
|
|
),
|
|
migrations.CreateModel(
|
|
name='Thematic',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('code', models.CharField(max_length=100, unique=True, verbose_name='Code')),
|
|
('name_fr', models.CharField(max_length=255, verbose_name='Nom')),
|
|
('name_nl', models.CharField(max_length=255, verbose_name='Naam')),
|
|
('description', models.TextField(blank=True, null=True, verbose_name='Description')),
|
|
('icon', models.CharField(blank=True, max_length=100, null=True, verbose_name='Icône Bootstrap')),
|
|
('color', models.CharField(default='#000000', max_length=7, verbose_name='Couleur associée')),
|
|
('uses_occupations', models.BooleanField(default=False, verbose_name='Utilise les occupations')),
|
|
('include_in_daily_report', models.BooleanField(default=False, help_text="Si coché, cette thématique apparaît toujours dans le rapport journalier, même si le nombre d'interventions est 0.", verbose_name='Inclure dans rapport journalier')),
|
|
('allow_planning_without_contract', models.BooleanField(default=False, help_text="Si coché, les interventions de cette thématique peuvent passer au statut 'À planifier' sans qu'un prestataire ou un contrat soit renseigné. Le prestataire et le contrat restent modifiables dans ce statut.", verbose_name='Planification sans contrat autorisée')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Thématique',
|
|
'verbose_name_plural': 'Thématiques',
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='UserContractAccess',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('can_view_posts', models.BooleanField(default=False)),
|
|
('can_view_prices', models.BooleanField(default=False)),
|
|
('can_view_interventions', models.BooleanField(default=True)),
|
|
('can_view_assets', models.BooleanField(default=True)),
|
|
('can_create_interventions', models.BooleanField(default=False, help_text='Permet au prestataire de créer des interventions pour ce contrat.', verbose_name='Peut créer des interventions')),
|
|
('can_check_interventions', models.BooleanField(default=False, help_text='Permet de vérifier les interventions pour ce contrat.', verbose_name='Peut vérifier les interventions')),
|
|
('can_approve', models.BooleanField(default=False, help_text="Permet de faire passer les interventions du statut 'à approuver' vers un autre statut pour ce contrat.", verbose_name='Peut approuver les interventions')),
|
|
],
|
|
),
|
|
migrations.CreateModel(
|
|
name='UserContractStatusPermission',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('status', models.CharField(choices=[('in_preparation', 'En préparation'), ('to_be_approved', 'À approuver'), ('to_be_planned', 'À planifier'), ('to_be_processed', 'À traiter'), ('assigned', 'Pris en charge'), ('in_progress', 'Démarré'), ('on_pause', 'En pause'), ('finished', 'Terminé'), ('processed', 'Traité'), ('to_be_corrected', 'À corriger'), ('corrected', 'Corrigé'), ('validated', 'Validé'), ('invoiced', 'Comptabilisé'), ('closed', 'Finalisé'), ('canceled', 'Annulé')], max_length=30, verbose_name='Statut')),
|
|
('can_view', models.BooleanField(default=False, help_text='Peut voir les interventions à ce statut.', verbose_name='Voir')),
|
|
('can_edit', models.BooleanField(default=False, help_text='Peut modifier les interventions à ce statut.', verbose_name='Modifier')),
|
|
('can_change_status_to', models.BooleanField(default=False, help_text='Peut déclencher une transition vers ce statut (selon le graphe global des transitions).', verbose_name='Changer vers')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Permission par statut (contrat)',
|
|
'verbose_name_plural': 'Permissions par statut (contrat)',
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='UserThematics',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('can_view_assets', models.BooleanField(default=True)),
|
|
('can_edit_assets', models.BooleanField(default=False)),
|
|
('can_view_interventions', models.BooleanField(default=True)),
|
|
('can_edit_interventions', models.BooleanField(default=False)),
|
|
('can_edit_locations', models.BooleanField(default=False)),
|
|
('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')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Thématique utilisateur',
|
|
'verbose_name_plural': 'Thématiques utilisateur',
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='UserThematicStatusPermission',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('status', models.CharField(choices=[('in_preparation', 'En préparation'), ('to_be_approved', 'À approuver'), ('to_be_planned', 'À planifier'), ('to_be_processed', 'À traiter'), ('assigned', 'Pris en charge'), ('in_progress', 'Démarré'), ('on_pause', 'En pause'), ('finished', 'Terminé'), ('processed', 'Traité'), ('to_be_corrected', 'À corriger'), ('corrected', 'Corrigé'), ('validated', 'Validé'), ('invoiced', 'Comptabilisé'), ('closed', 'Finalisé'), ('canceled', 'Annulé')], max_length=30, verbose_name='Statut')),
|
|
('can_view', models.BooleanField(default=False, help_text='Peut voir les interventions à ce statut.', verbose_name='Voir')),
|
|
('can_edit', models.BooleanField(default=False, help_text='Peut modifier les interventions à ce statut.', verbose_name='Modifier')),
|
|
('can_change_status_to', models.BooleanField(default=False, help_text='Peut déclencher une transition vers ce statut (selon le graphe global des transitions).', verbose_name='Changer vers')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Permission par statut (thématique)',
|
|
'verbose_name_plural': 'Permissions par statut (thématique)',
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='UserWarehouseAccess',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('can_view', models.BooleanField(default=True, verbose_name='Peut visualiser')),
|
|
('can_manage', models.BooleanField(default=False, verbose_name='Peut gérer')),
|
|
('can_administer', models.BooleanField(default=False, verbose_name='Peut administrer')),
|
|
('can_manage_preparation_orders', models.BooleanField(default=False, verbose_name='Peut gérer les bons de préparation')),
|
|
('can_manage_purchase_orders', models.BooleanField(default=False, verbose_name='Peut gérer les bons de commande')),
|
|
('can_validate_inventory', models.BooleanField(default=False, verbose_name='Peut valider les inventaires')),
|
|
('is_default', models.BooleanField(default=False, verbose_name='Entrepôt par défaut')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Accès Entrepôt',
|
|
'verbose_name_plural': 'Accès Entrepôts',
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='AssetTypePermissionConfig',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('requires_explicit_permissions', models.BooleanField(default=False, help_text="Si coché, les droits thématiques seuls ne suffisent pas. Chaque utilisateur doit avoir une entrée explicite dans « Accès assets spécifiques » pour ce type d'objet.", verbose_name='Droits explicites requis')),
|
|
('content_type', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='asset_permission_config', to='contenttypes.contenttype', verbose_name="Type d'asset")),
|
|
],
|
|
options={
|
|
'verbose_name': "Config permissions par type d'asset",
|
|
'verbose_name_plural': "Configs permissions par type d'asset",
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='AdrStreet',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('fid', models.CharField(max_length=100, unique=True)),
|
|
('name_fr', models.CharField(max_length=255, verbose_name='Nom')),
|
|
('name_nl', models.CharField(max_length=255, verbose_name='Naam')),
|
|
('full_street_fr', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Nom complet FR')),
|
|
('full_street_nl', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Nom complet NL')),
|
|
('centroid', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=3812)),
|
|
('lon', models.FloatField(blank=True, null=True)),
|
|
('lat', models.FloatField(blank=True, null=True)),
|
|
('geom', django.contrib.gis.db.models.fields.MultiPolygonField(blank=True, null=True, srid=3812)),
|
|
('municipality', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='street_names', to='common.municipality')),
|
|
],
|
|
),
|
|
migrations.CreateModel(
|
|
name='AdrPoint',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('fid', models.CharField(max_length=100, unique=True)),
|
|
('number', models.CharField(max_length=255, verbose_name='Numéro')),
|
|
('zipcode', models.CharField(blank=True, max_length=255, null=True, verbose_name='Code postal')),
|
|
('full_address_fr', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Adresse complète FR')),
|
|
('full_address_nl', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Adresse complète NL')),
|
|
('geom', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=3812)),
|
|
('lon', models.FloatField(blank=True, null=True)),
|
|
('lat', models.FloatField(blank=True, null=True)),
|
|
('street_name', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='addresses', to='common.adrstreet')),
|
|
('municipality', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='addresses', to='common.municipality')),
|
|
],
|
|
),
|
|
migrations.CreateModel(
|
|
name='RequestLog',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('timestamp', models.DateTimeField(auto_now_add=True, db_index=True, verbose_name='Date et heure')),
|
|
('level', models.CharField(choices=[('DEBUG', 'Debug'), ('INFO', 'Info'), ('WARNING', 'Warning'), ('ERROR', 'Error'), ('CRITICAL', 'Critical')], default='ERROR', max_length=10, verbose_name='Niveau')),
|
|
('username', models.CharField(blank=True, max_length=150, null=True, verbose_name="Nom d'utilisateur")),
|
|
('method', models.CharField(blank=True, max_length=10, null=True, verbose_name='Méthode HTTP')),
|
|
('path', models.CharField(max_length=2048, verbose_name='URL')),
|
|
('full_url', models.CharField(blank=True, max_length=4096, null=True, verbose_name='URL complète')),
|
|
('status_code', models.IntegerField(blank=True, null=True, verbose_name='Code HTTP')),
|
|
('ip_address', models.GenericIPAddressField(blank=True, null=True, verbose_name='Adresse IP')),
|
|
('user_agent', models.TextField(blank=True, null=True, verbose_name='User Agent')),
|
|
('referer', models.CharField(blank=True, max_length=2048, null=True, verbose_name='Referer')),
|
|
('exception_type', models.CharField(blank=True, max_length=255, null=True, verbose_name="Type d'exception")),
|
|
('exception_message', models.TextField(blank=True, null=True, verbose_name="Message d'erreur")),
|
|
('traceback', models.TextField(blank=True, null=True, verbose_name='Traceback')),
|
|
('request_data', models.TextField(blank=True, null=True, verbose_name='Données de la requête')),
|
|
('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='request_logs', to=settings.AUTH_USER_MODEL, verbose_name='Utilisateur')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Log de requête',
|
|
'verbose_name_plural': 'Logs de requêtes',
|
|
'ordering': ['-timestamp'],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='ScheduledCommand',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('name', models.CharField(help_text='Nom descriptif de la tâche planifiée', max_length=200, unique=True, verbose_name='Nom de la tâche')),
|
|
('command_name', models.CharField(help_text='Nom de la commande Django (ex: export_interventions_xlsx)', max_length=200, verbose_name='Nom de la commande')),
|
|
('command_args', models.JSONField(blank=True, default=dict, help_text='Arguments de la commande au format JSON (ex: {"output": "file.xlsx"})', verbose_name='Arguments de la commande')),
|
|
('frequency', models.CharField(choices=[('hourly', 'Toutes les heures'), ('daily', 'Quotidien'), ('weekly', 'Hebdomadaire'), ('monthly', 'Mensuel')], default='daily', max_length=20, verbose_name='Fréquence')),
|
|
('hour', models.IntegerField(default=0, help_text="Heure d'exécution (0-23)", validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(23)], verbose_name='Heure')),
|
|
('minute', models.IntegerField(default=0, help_text="Minute d'exécution (0-59)", validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(59)], verbose_name='Minute')),
|
|
('day_of_month', models.IntegerField(blank=True, help_text='Pour les tâches mensuelles : jour du mois (1-31)', null=True, validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(31)], verbose_name='Jour du mois')),
|
|
('day_of_week', models.IntegerField(blank=True, choices=[(0, 'Lundi'), (1, 'Mardi'), (2, 'Mercredi'), (3, 'Jeudi'), (4, 'Vendredi'), (5, 'Samedi'), (6, 'Dimanche')], help_text='Pour les tâches hebdomadaires : 0=Lundi, 6=Dimanche', null=True, verbose_name='Jour de la semaine')),
|
|
('is_active', models.BooleanField(default=True, help_text='Si décoché, la tâche ne sera pas exécutée', verbose_name='Active')),
|
|
('send_email', models.BooleanField(default=False, help_text="Envoyer un email après l'exécution", verbose_name='Envoyer un email')),
|
|
('email_recipients', models.TextField(blank=True, help_text='Adresses email séparées par des virgules', verbose_name='Destinataires')),
|
|
('email_subject', models.CharField(blank=True, max_length=200, verbose_name="Sujet de l'email")),
|
|
('last_run', models.DateTimeField(blank=True, null=True, verbose_name='Dernière exécution')),
|
|
('next_run', models.DateTimeField(blank=True, null=True, verbose_name='Prochaine exécution')),
|
|
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Créé le')),
|
|
('description', models.TextField(blank=True, verbose_name='Description')),
|
|
('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='created_scheduled_commands', to=settings.AUTH_USER_MODEL, verbose_name='Créé par')),
|
|
],
|
|
options={
|
|
'verbose_name': 'Commande planifiée',
|
|
'verbose_name_plural': 'Commandes planifiées',
|
|
'ordering': ['name'],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='CommandExecutionLog',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('started_at', models.DateTimeField(auto_now_add=True, verbose_name='Démarré à')),
|
|
('finished_at', models.DateTimeField(blank=True, null=True, verbose_name='Terminé à')),
|
|
('status', models.CharField(choices=[('running', 'En cours'), ('success', 'Succès'), ('error', 'Erreur')], default='running', max_length=20, verbose_name='Statut')),
|
|
('output', models.TextField(blank=True, verbose_name='Sortie')),
|
|
('error_message', models.TextField(blank=True, verbose_name="Message d'erreur")),
|
|
('duration_seconds', models.FloatField(blank=True, null=True, verbose_name='Durée (secondes)')),
|
|
('email_sent', models.BooleanField(default=False, verbose_name='Email envoyé')),
|
|
('scheduled_command', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='execution_logs', to='common.scheduledcommand', verbose_name='Commande planifiée')),
|
|
],
|
|
options={
|
|
'verbose_name': "Journal d'exécution",
|
|
'verbose_name_plural': "Journaux d'exécution",
|
|
'ordering': ['-started_at'],
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='UserAssetAccess',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('object_id', models.PositiveIntegerField(verbose_name="ID de l'objet")),
|
|
('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')),
|
|
('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={
|
|
'verbose_name': 'Accès asset spécifique',
|
|
'verbose_name_plural': 'Accès assets spécifiques',
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='UserAssetTypeAccess',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('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')),
|
|
('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={
|
|
'verbose_name': "Accès par type d'asset",
|
|
'verbose_name_plural': "Accès par type d'asset",
|
|
},
|
|
),
|
|
migrations.CreateModel(
|
|
name='UserConfig',
|
|
fields=[
|
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
('is_intern', models.BooleanField(default=False)),
|
|
('limit_assets_to_contracts', models.BooleanField(default=True)),
|
|
('limit_interventions_to_contracts', models.BooleanField(default=True)),
|
|
('limit_shortcuts_to_contracts', models.BooleanField(default=False, help_text="Limite les raccourcis et les compteurs de la page d'accueil aux contrats pour lesquels l'utilisateur dispose de permissions explicites.", verbose_name="Limiter la page d'accueil aux contrats")),
|
|
('generic_email', models.EmailField(blank=True, max_length=254, null=True)),
|
|
('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')),
|
|
('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')),
|
|
('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)')),
|
|
('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')),
|
|
('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')),
|
|
('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")),
|
|
],
|
|
),
|
|
]
|