# Generated by Django 6.0.7 on 2026-07-22 13:42 import common.storages import contracts.models import django.db.models.deletion from decimal import Decimal from django.conf import settings from django.db import migrations, models class Migration(migrations.Migration): initial = True dependencies = [ ('assets', '0001_initial'), ('common', '0001_initial'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ migrations.CreateModel( name='Company', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=255, unique=True)), ('address', models.TextField(blank=True, null=True)), ('contact_email', models.EmailField(blank=True, max_length=254, null=True)), ('phone_number', models.CharField(blank=True, max_length=20, null=True)), ('logo', models.ImageField(blank=True, null=True, upload_to='company_logos/')), ], options={ 'verbose_name': 'Société/Organisme', 'verbose_name_plural': 'Sociétés/Organismes', 'ordering': ['name'], }, ), migrations.CreateModel( name='ContractOrderAttachment', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('file', models.FileField(max_length=255, storage=common.storages.PrivateMediaStorage(), upload_to=contracts.models.order_attachment_upload_path, verbose_name='Fichier')), ('thumbnail', models.ImageField(blank=True, max_length=255, null=True, storage=common.storages.PrivateMediaStorage(), upload_to=contracts.models.order_attachment_upload_path, verbose_name='Vignette')), ('upload_date', models.DateTimeField(auto_now_add=True, verbose_name="Date d'ajout")), ], options={ 'verbose_name': 'Pièce jointe de commande', 'verbose_name_plural': 'Pièces jointes de commande', 'ordering': ['upload_date'], }, ), migrations.CreateModel( name='ContractOrderDocument', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('title', models.CharField(max_length=255)), ('document', models.FileField(storage=common.storages.PrivateMediaStorage(), upload_to=contracts.models.order_document_upload_path)), ('document_type', models.CharField(choices=[('invoice', 'Facture'), ('claim_declaration', 'Déclaration de créance'), ('state_of_works', 'État de travaux'), ('posts_detail', 'Détail des postes'), ('other', 'Autre')], default='other', max_length=50)), ('uploaded_at', models.DateTimeField(auto_now_add=True)), ], ), migrations.CreateModel( name='ContractOrderProgressState', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('index', models.PositiveIntegerField(blank=True, help_text="Numéro d'ordre de l'état d'avancement pour cette commande", null=True)), ('created_at', models.DateTimeField(auto_now_add=True)), ], options={ 'verbose_name': "État d'avancement", }, ), migrations.CreateModel( name='ContractOrderProgressStateItem', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('quantity', models.DecimalField(decimal_places=2, default=0, help_text='Quantité consommée à cette date', max_digits=10)), ], options={ 'verbose_name': "Item d'état d'avancement", 'verbose_name_plural': "Items d'états d'avancement", 'ordering': ['contract_post__order_number'], }, ), migrations.CreateModel( name='ContractOrderQuote', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('is_finalized', models.BooleanField(default=False)), ('finalized_at', models.DateTimeField(blank=True, null=True)), ], ), migrations.CreateModel( name='ContractOrderQuoteItem', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('quantity', models.DecimalField(decimal_places=2, max_digits=10)), ], options={ 'ordering': ['contract_post__order_number'], }, ), migrations.CreateModel( name='ContractPost', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('code', models.CharField(max_length=255)), ('description_fr', models.TextField()), ('description_nl', models.TextField()), ('order_number', models.PositiveIntegerField()), ('unit', models.CharField(max_length=255)), ('unit_price', models.DecimalField(decimal_places=2, max_digits=10)), ('total_quantity_used', models.DecimalField(decimal_places=2, default=0, max_digits=10)), ('post_type', models.CharField(blank=True, max_length=100, null=True)), ('is_coefficient_multipliable', models.BooleanField(default=False)), ('is_amount_to_be_justified', models.BooleanField(default=False)), ('coeff_amount_to_be_justified', models.DecimalField(blank=True, decimal_places=2, default=1, max_digits=10, null=True)), ], options={ 'ordering': ['order_number'], }, ), migrations.CreateModel( name='DirectOrderPost', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('quantity', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='Quantité')), ('comment', models.TextField(blank=True, null=True, verbose_name='Commentaire')), ('control_status', models.CharField(choices=[('pending', 'En attente de validation'), ('validated', 'Approuvé'), ('refused', 'Refusé'), ('invoiced', 'Facturé')], default='pending', max_length=20, verbose_name='Statut de validation')), ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Date de création')), ('validated_at', models.DateTimeField(blank=True, null=True, verbose_name='Date de validation')), ('invoiced_quantity', models.DecimalField(decimal_places=2, default=Decimal('0'), help_text='Quantité cumulée sur les déclarations de créance précédentes.', max_digits=10, verbose_name='Quantité déjà facturée')), ], options={ 'verbose_name': 'Commande directe – poste', 'verbose_name_plural': 'Commandes directes – postes', 'ordering': ['contract_post__order_number'], }, ), migrations.CreateModel( name='MaintainType', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('code', models.CharField(help_text='Code du type de maintenance (corrective, preventive, ameliorative)', max_length=50, unique=True)), ('name_fr', models.CharField(max_length=100, verbose_name='Nom (FR)')), ('name_nl', models.CharField(max_length=100, verbose_name='Nom (NL)')), ], options={ 'verbose_name': 'Type de maintenance', 'verbose_name_plural': 'Types de maintenance', 'ordering': ['code'], }, ), migrations.CreateModel( name='UserCompanyTeamAccess', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('can_view', models.BooleanField(default=False, help_text="L'utilisateur peut voir cette équipe et ses membres.", verbose_name='Peut consulter')), ('can_edit', models.BooleanField(default=False, help_text="L'utilisateur peut créer/supprimer des équipes et des membres, et déplacer des membres entre équipes.", verbose_name='Peut éditer')), ], options={ 'verbose_name': 'Accès utilisateur à une équipe', 'verbose_name_plural': 'Accès utilisateurs aux équipes', }, ), migrations.CreateModel( name='ClaimDeclarationAttachment', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('title', models.CharField(help_text='Titre ou description du justificatif', max_length=255, verbose_name='Titre')), ('document', models.FileField(storage=common.storages.PrivateMediaStorage(), upload_to=contracts.models.claim_attachment_upload_path, verbose_name='Fichier')), ('uploaded_at', models.DateTimeField(auto_now_add=True, verbose_name="Date d'ajout")), ('uploaded_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='uploaded_claim_attachments', to=settings.AUTH_USER_MODEL, verbose_name='Ajouté par')), ], options={ 'verbose_name': 'Pièce jointe de déclaration de créance', 'verbose_name_plural': 'Pièces jointes de déclarations de créance', 'ordering': ['uploaded_at'], }, ), migrations.CreateModel( name='CompanyMember', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=255)), ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], options={ 'verbose_name': 'Membre de société/organisme', 'verbose_name_plural': 'Membres de sociétés/organismes', 'ordering': ['name'], }, ), migrations.CreateModel( name='CompanyTeam', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=255, unique=True)), ('is_assets_manager', models.BooleanField(default=False, help_text="Indique si cette équipe est gestionnaire des catégories d'assets associées.", verbose_name="Gestionnaire d'assets")), ('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')), ], options={ 'verbose_name': 'Équipe de société/organisme', 'verbose_name_plural': 'Équipes de sociétés/organismes', 'ordering': ['name'], }, ), migrations.CreateModel( name='CompanyMemberHistory', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('join_date', models.DateField(verbose_name="Date d'entrée")), ('leave_date', models.DateField(blank=True, null=True, verbose_name='Date de sortie')), ('changed_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='member_team_changes', to=settings.AUTH_USER_MODEL, verbose_name='Modifié par')), ('member', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='team_history', to='contracts.companymember', verbose_name='Membre')), ('team', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='member_history', to='contracts.companyteam', verbose_name='Équipe')), ], options={ 'verbose_name': "Historique d'équipe d'un membre", 'verbose_name_plural': "Historiques d'équipe des membres", 'ordering': ['member', '-join_date'], }, ), 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.CreateModel( name='Contract', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('contract_number', models.CharField(max_length=100, unique=True)), ('start_date', models.DateField()), ('end_date', models.DateField()), ('description', models.TextField(blank=True, null=True)), ('committed_amount', models.DecimalField(blank=True, decimal_places=2, default=0, max_digits=10, null=True)), ('internal_link', models.URLField(blank=True, help_text='Lien vers le dossier interne', null=True)), ('notification_emails', models.CharField(blank=True, max_length=1000, null=True)), ('cc_notification_emails', models.CharField(blank=True, help_text='Adresses email à ajouter en copie des notifications (séparées par des virgules ou points-virgules)', max_length=1000, null=True, verbose_name='Emails en copie (CC)')), ('send_email_notifications', models.BooleanField(default=True, help_text='Envoyer des notifications liées aux interventions par email.')), ('signatory_name', models.CharField(blank=True, help_text='Nom de la personne qui signe les documents côté prestataire.', max_length=255, null=True, verbose_name='Nom du signataire (prestataire)')), ('signatory_role', models.CharField(blank=True, help_text='Rôle/fonction de la personne qui signe les documents côté prestataire.', max_length=255, null=True, verbose_name='Rôle du signataire (prestataire)')), ('contact_phone', models.CharField(blank=True, help_text='Numéro de téléphone du technicien de garde ou contact principal pour les urgences.', max_length=50, null=True, verbose_name='Téléphone de contact')), ('is_active', models.BooleanField(default=True, help_text='Indique si le contrat est actif.', verbose_name='Actif')), ('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')), ('daily_summary_hour', models.PositiveSmallIntegerField(default=18, help_text='Heure (0-23) à laquelle le résumé journalier des interventions est envoyé (heure locale).', verbose_name="Heure d'envoi du résumé journalier")), ('email_only_if_urgent', models.BooleanField(default=False, help_text="Si activé, les notifications email ne sont envoyées que pour les interventions de priorité 'Urgent'.", verbose_name='Emails uniquement si priorité urgente')), ('company', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='contracts', to='contracts.company')), ('executive_officer', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='executive_officer_contracts', to=settings.AUTH_USER_MODEL)), ('thematics', models.ManyToManyField(blank=True, help_text='Thématiques associées à ce contrat.', related_name='contracts', to='common.thematic', verbose_name='Thématiques')), ], options={ 'ordering': ['contract_number'], }, ), migrations.CreateModel( name='ContractOrder', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('order_code', models.CharField(max_length=100)), ('description', models.TextField(blank=True, null=True)), ('order_date', models.DateField()), ('delivery_date', models.DateField()), ('total_amount', models.DecimalField(blank=True, decimal_places=2, default=0, max_digits=10, null=True)), ('order_status', models.CharField(choices=[('pending', 'En préparation'), ('sent', 'Envoyé'), ('completed', 'Terminé'), ('invoiced', 'Comptabilisé'), ('paid', 'Payé'), ('cancelled', 'Annulé')], default='pending', max_length=50)), ('order_file', models.FileField(blank=True, null=True, upload_to=contracts.models.contract_order_upload_path)), ('contract', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='orders', to='contracts.contract')), ('ordered_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='contract_orders', to=settings.AUTH_USER_MODEL)), ], options={ 'ordering': ['-order_date'], }, ), ]