Parcourir la source

correction de la commande « services »

Élie Bouttier il y a 8 ans
Parent
commit
fe2efa6dc8
3 fichiers modifiés avec 49 ajouts et 42 suppressions
  1. 2 2
      adhesions/models.py
  2. 47 39
      services/management/commands/services.py
  3. 0 1
      services/models.py

+ 2 - 2
adhesions/models.py

@@ -50,9 +50,9 @@ class Adherent(models.Model):
 
     def __str__(self):
         if self.id:
-            return 'Adhérent #%d' % self.id
+            return 'ADT%d – %s' % (self.id, self.get_name())
         else:
-            return 'Adhérent #?'
+            return '?'
 
 
 class Corporation(models.Model):

+ 47 - 39
services/management/commands/services.py

@@ -2,11 +2,14 @@ from django.core.management.base import BaseCommand, CommandParser, CommandError
 from django.db.models import DecimalField, F, Sum, Func, Q
 from django.core.validators import validate_ipv4_address, validate_ipv6_address
 from django.core.exceptions import ValidationError
+from django.utils import timezone
 
 import argparse
 from decimal import Decimal
 
-from services.models import Service, ServiceType, IPResource
+from djadhere.utils import get_active_filter
+from adhesions.models import Adherent
+from services.models import Service, ServiceType, IPResource, ResourceAllocation
 
 
 class IPAction(argparse.Action):
@@ -59,21 +62,21 @@ class Command(BaseCommand):
             choices=ServiceType.objects.all().values_list('name', flat=True),
             help='Afficher uniquement les services d’un certain type')
         group = parser_list.add_mutually_exclusive_group()
-        group.add_argument('--ongoing', action='store_true',
+        group.add_argument('--active', action='store_true',
             help='Afficher uniquement les services actifs')
-        group.add_argument('--forthcoming', action='store_true',
-            help='Afficher uniquement les services à venir (non configuré ou à date de début dans le futur)')
-        group.add_argument('--finished', action='store_true',
-            help='Afficher uniquement les services terminés')
+        group.add_argument('--inactive', action='store_true',
+            help='Afficher uniquement les services inactifs')
 
         parser_show = subparsers.add_parser('show', help='Afficher les informations concernant un service')
         parser_show.add_argument('id', type=int)
 
         parser_add = subparsers.add_parser('add', help='Ajouter un nouveau service')
+        parser_add.add_argument('--adherent', type=int, help='Numéro d’adhérent', required=True)
         parser_add.add_argument('--type', required=True,
             choices=ServiceType.objects.all().values_list('name', flat=True),
             help='Afficher uniquement les services d’un certain type')
         parser_add.add_argument('--ip', action=IPAction, default=[], help='Assigner une IP au service')
+        parser_add.add_argument('--label', default='')
 
         parser_delete = subparsers.add_parser('delete', help='Supprimer un service existant')
         parser_delete.add_argument('id', type=int)
@@ -88,20 +91,20 @@ class Command(BaseCommand):
         total_income = Decimal(0.0)
         lines = []
         for service_type in ServiceType.objects.all():
-            services = service_type.services.filter(Service.get_ongoing_filter())
+            services = service_type.services.filter(active=True)
             ntotal = services.count()
             services = services.exclude(adherent=None)
             nadh = services.count()
             ninf = ntotal - nadh
             services = services.exclude(
-                Q(contribution__isnull=True)
-                | Q(contribution__amount=0)
-                | Q(contribution__period=0)
+                Q(contributions__isnull=True)
+                | Q(contributions__amount=0)
+                | Q(contributions__period=0)
             )
             npay = services.count()
             ngra = nadh - npay
-            amount = Func(F('contribution__amount'), function='CAST', template=as_float_template)
-            period = F('contribution__period')
+            amount = Func(F('contributions__amount'), function='CAST', template=as_float_template)
+            period = F('contributions__period')
             output_field = DecimalField(max_digits=9, decimal_places=2)
             income = services.aggregate(income=Sum(amount / period,
                                                    output_field=output_field))['income'] or Decimal(0.0)
@@ -120,20 +123,18 @@ class Command(BaseCommand):
         if options['type']:
             st = ServiceType.objects.get(name=options['type'])
             services = services.filter(service_type=st)
-        if options['ongoing']:
-            services = services.filter(Service.get_ongoing_filter())
-        if options['forthcoming']:
-            services = services.filter(Service.get_forthcoming_filter())
-        if options['finished']:
-            services = services.filter(Service.get_finished_filter())
+        if options['active']:
+            services = services.filter(get_active_filter())
+        if options['inactive']:
+            services = services.exclude(get_active_filter())
 
         fmt = '{:<8}{:<20}{:<20}{:<10}{:<40}'
-        print(fmt.format('ID', 'Type', 'Adhérent', 'En cours', 'IPs'))
+        print(fmt.format('ID', 'Type', 'Adhérent', 'Actif', 'IPs'))
         for service in services:
-            adh = str(service.adherent) if service.adherent else '-'
-            ips = ', '.join(map(str, service.ip_resources.all())) or '-'
-            ongoing = '✔' if service.is_ongoing else '✘'
-            print(fmt.format(service.pk, str(service.service_type), adh, ongoing, ips))
+            adh = service.adherent.get_name()
+            ips = ', '.join(map(lambda a: str(a.resource), service.active_allocations.all())) or '-'
+            active = '✔' if service.active else '✘'
+            print(fmt.format(service.pk, str(service.service_type), adh, active, ips))
 
     def handle_show(self, *args, **options):
         try:
@@ -142,26 +143,32 @@ class Command(BaseCommand):
             raise CommandError('Le service n°%d n’existe pas' % options['id'])
         self.stdout.write('Service n°%d' % service.pk)
         self.stdout.write('\tType de service : %s' % service.service_type)
-        self.stdout.write('\tAdhérent : %s' % (service.adherent or 'aucun'))
-        self.stdout.write('\tDébut du service : %s' % (service.start or '-'))
-        self.stdout.write('\tFin du service : %s' % (service.end or '-'))
-        self.stdout.write('\tService en cours : %s' % ('oui' if service.is_ongoing else 'non'))
+        self.stdout.write('\tAdhérent : ADT%d - %s' % (service.adherent.pk, service.adherent.get_name()))
+        self.stdout.write('\tActif : %s' % ('oui' if service.active else 'non'))
+        if service.active_allocations.exists():
+            self.stdout.write('\tIP :')
+            for a in service.active_allocations.all():
+                self.stdout.write('\t\t%s' % a.resource)
+        else:
+            self.stdout.write('\tIP : aucune')
 
     def handle_add(self, *args, **options):
         for ip in options['ip']:
-            services = Service.objects.filter(ip_resources=ip).exclude(Service.get_finished_filter())
-            if services.exists():
-                self.stdout.write(self.style.WARNING('Note : la ressource IP "%s" est également affecté aux '
-                                                     'services suivants :' % ip))
-                for service in services:
-                    self.stdout.write(self.style.WARNING('\t%d (%s)' % (service.pk, service.service_type)))
-                value = input('Continuer ? [y/N] ')
-                if value.lower() != 'y':
-                    raise CommandError('Opération annulée')
+            try:
+                allocation = ResourceAllocation.objects.filter(resource=ip).get(get_active_filter())
+                raise CommandError("La ressource %s est déjà utilisé : %s (%s)" % (ip, allocation.service, allocation.service.adherent))
+            except ResourceAllocation.DoesNotExist:
+                pass
         st = ServiceType.objects.get(name=options['type'])
-        service = Service.objects.create(service_type=st)
-        service.ip_resources = options['ip']
-        service.save()
+        try:
+            adherent = Adherent.objects.get(pk=options['adherent'])
+        except Adherent.DoesNotExist:
+            raise CommandError("L’adhérent %d n’existe pas." % options['adherent'])
+        if Service.objects.filter(service_type=st, label=options['label']).exists():
+            raise CommandError("Un service du même type et portant le même label existe déjà.")
+        service = Service.objects.create(service_type=st, adherent=adherent, label=options['label'])
+        for ip in options['ip']:
+            ResourceAllocation.objects.create(service=service, resource=ip, start=timezone.now())
         self.stdout.write(self.style.SUCCESS('Service n°%d créé avec succès' % service.pk))
 
     def handle_delete(self, *args, **options):
@@ -169,6 +176,7 @@ class Command(BaseCommand):
             service = Service.objects.get(pk=options['id'])
         except Service.DoesNotExist:
             raise CommandError('Le service n°%d n’existe pas' % options['id'])
+        self.stdout.write('%s – %s' % (service, service.adherent))
         value = input('Êtes vous sûr de vouloir supprimer ce service ? [y/N] ')
         if value.lower() == 'y':
             service.delete()

+ 0 - 1
services/models.py

@@ -87,7 +87,6 @@ class Service(models.Model):
         s = str(self.service_type)
         if self.label:
             s += ' ' + self.label
-        s += ' (' + str(self.adherent) + ')'
         return s