loko/streetup/contracts/migrations/0001_initial.py

291 lines
21 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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'],
},
),
]