models.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. from django.db import models
  2. from django.db.models import Q
  3. from django.core.validators import MaxValueValidator
  4. from django.utils import timezone
  5. from django.contrib.auth.models import Group
  6. from django.contrib.contenttypes.fields import GenericRelation
  7. from django.core.exceptions import ValidationError
  8. from django.urls import reverse
  9. from django.utils import timezone
  10. from django.core.exceptions import PermissionDenied
  11. from djadhere.utils import get_active_filter, is_overlapping
  12. from adhesions.models import Adhesion
  13. from banking.models import Payment
  14. class IPPrefix(models.Model):
  15. prefix = models.CharField(max_length=128)
  16. def __str__(self):
  17. return self.prefix
  18. class IPResource(models.Model):
  19. ip = models.GenericIPAddressField(verbose_name='IP', primary_key=True)
  20. prefixes = models.ManyToManyField(IPPrefix, verbose_name='préfixes')
  21. reserved = models.BooleanField(default=False, verbose_name='réservée')
  22. @property
  23. def in_use(self):
  24. return self.allocation is not None
  25. @property
  26. def allocation(self):
  27. try:
  28. return self.allocations.get(get_active_filter())
  29. except ResourceAllocation.DoesNotExist:
  30. return None
  31. class Meta:
  32. ordering = ['ip']
  33. verbose_name = 'IP'
  34. verbose_name_plural = 'IP'
  35. def __str__(self):
  36. return str(self.ip)
  37. class ServiceType(models.Model):
  38. name = models.CharField(max_length=64, verbose_name='Nom', unique=True)
  39. class Meta:
  40. ordering = ['name']
  41. verbose_name = 'type de service'
  42. verbose_name_plural = 'types de service'
  43. def __str__(self):
  44. return self.name
  45. class Service(models.Model):
  46. adhesion = models.ForeignKey(Adhesion, verbose_name='Adhérent', related_name='services')
  47. service_type = models.ForeignKey(ServiceType, related_name='services',
  48. verbose_name='Type de service')
  49. label = models.CharField(blank=True, default='', max_length=128)
  50. notes = models.TextField(blank=True, default='')
  51. active = models.BooleanField(default=True, verbose_name='actif')
  52. created = models.DateTimeField(auto_now_add=True)
  53. contributions = GenericRelation(Payment,
  54. content_type_field='reason_type',
  55. object_id_field='reason_id',
  56. related_query_name='service')
  57. @property
  58. def contribution(self):
  59. try:
  60. return self.contributions.exclude(period=0).get(get_active_filter())
  61. except Payment.DoesNotExist:
  62. return None
  63. # MultipleObjectsReturned non catché volontairement, cf remarque adhesions.Adhesion.contribution
  64. @property
  65. def active_allocations(self):
  66. return self.allocations.filter(get_active_filter())
  67. @property
  68. def inactive_allocations(self):
  69. return self.allocations.exclude(get_active_filter())
  70. def clean(self):
  71. super().clean()
  72. # Vérification de l’unicité par type de service du label
  73. if self.label != '' and Service.objects.exclude(pk=self.pk).filter(service_type=self.service_type, label=self.label):
  74. raise ValidationError("Un service du même type existe déjà avec ce label.")
  75. def __str__(self):
  76. s = str(self.service_type)
  77. if self.label:
  78. s += ' ' + self.label
  79. return s
  80. class Route(models.Model):
  81. name = models.CharField(max_length=64)
  82. def __str__(self):
  83. return self.name
  84. class ResourceAllocation(models.Model):
  85. resource = models.ForeignKey(IPResource, verbose_name='Ressource', related_name='allocations', related_query_name='allocation')
  86. service = models.ForeignKey(Service, related_name='allocations', related_query_name='allocation')
  87. route = models.ForeignKey(Route, verbose_name='Route', related_name='allocations', related_query_name='allocation')
  88. start = models.DateTimeField(verbose_name='Début de la période d’allocation', default=timezone.now)
  89. end = models.DateTimeField(null=True, blank=True, verbose_name='Fin de la période d’allocation')
  90. notes = models.TextField(blank=True, default='')
  91. @property
  92. def active(self):
  93. return ResourceAllocation.objects.filter(pk=self.pk).filter(get_active_filter()).exists()
  94. def clean(self):
  95. super().clean()
  96. # Vérification de la cohérence des champs start et end
  97. if self.end and self.start > self.end:
  98. raise ValidationError("La date de début de l’allocation doit être antérieur "
  99. "à la date de fin de l’allocation.")
  100. # Vérification de l’abscence de chevauchement de la période d’allocation
  101. if self.resource_id:
  102. allocations = ResourceAllocation.objects.filter(resource__pk=self.resource.pk)
  103. if is_overlapping(self, allocations):
  104. raise ValidationError("La période d’allocation de cette ressource chevauche "
  105. "avec une période d’allocation précédente.")
  106. # Penser à appeler la méthode save !
  107. def deallocate(self):
  108. if not self.active:
  109. raise PermissionDenied
  110. self.end = timezone.now()
  111. class Meta:
  112. verbose_name = 'allocation'
  113. verbose_name_plural = 'allocations'
  114. ordering = ['-start']
  115. def __str__(self):
  116. return str(self.resource)