|
@@ -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()
|