models.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  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 djadhere.utils import get_active_filter, is_overlapping
  10. from adhesions.models import Adhesion
  11. from banking.models import Payment
  12. class IPResource(models.Model):
  13. ip = models.GenericIPAddressField(verbose_name='IP')
  14. mask = models.PositiveIntegerField(validators=[MaxValueValidator(128)],
  15. default=0, verbose_name='Masque')
  16. @property
  17. def in_use(self):
  18. if self.allocations.filter(get_active_filter()).exists():
  19. return True
  20. else:
  21. return False
  22. @property
  23. def services(self):
  24. allocations = self.allocations.filter(get_active_filter()).all()
  25. if allocations:
  26. return ', '.join(allocations)
  27. else:
  28. return '–'
  29. class Meta:
  30. verbose_name = 'ressource IP'
  31. verbose_name_plural = 'ressources IP'
  32. def __str__(self):
  33. r = str(self.ip)
  34. if self.mask:
  35. r += '/%d' % self.mask
  36. return r
  37. class ServiceType(models.Model):
  38. name = models.CharField(max_length=64, verbose_name='Nom', unique=True)
  39. group = models.ForeignKey(Group, null=True, blank=True,
  40. verbose_name='Groupe de gestion',
  41. related_name='service_types')
  42. class Meta:
  43. verbose_name = 'type de service'
  44. verbose_name_plural = 'types de service'
  45. def __str__(self):
  46. return self.name
  47. class Service(models.Model):
  48. adhesion = models.ForeignKey(Adhesion, verbose_name='Adhérent', related_name='services')
  49. service_type = models.ForeignKey(ServiceType, related_name='services',
  50. verbose_name='Type de service')
  51. label = models.CharField(blank=True, default='', max_length=128)
  52. notes = models.TextField(blank=True, default='')
  53. active = models.BooleanField(default=True, verbose_name='actif')
  54. created = models.DateTimeField(auto_now_add=True)
  55. contributions = GenericRelation(Payment,
  56. content_type_field='reason_type',
  57. object_id_field='reason_id',
  58. related_query_name='service')
  59. @property
  60. def contribution(self):
  61. try:
  62. return self.contributions.get(get_active_filter())
  63. except Payment.DoesNotExist:
  64. return None
  65. # MultipleObjectsReturned non catché volontairement, cf remarque adhesions.Adhesion.contribution
  66. @property
  67. def active_allocations(self):
  68. return self.allocations.filter(get_active_filter())
  69. @property
  70. def inactive_allocations(self):
  71. return self.allocations.exclude(get_active_filter())
  72. def clean(self):
  73. super().clean()
  74. # Vérification de l’unicité par type de service du label
  75. if self.label != '' and Service.objects.exclude(pk=self.pk).filter(service_type=self.service_type, label=self.label):
  76. raise ValidationError("Un service du même type existe déjà avec ce label.")
  77. def get_absolute_url(self):
  78. return reverse('service-detail', kwargs={'pk': self.pk})
  79. def __str__(self):
  80. s = str(self.service_type)
  81. if self.label:
  82. s += ' ' + self.label
  83. return s
  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. start = models.DateTimeField(verbose_name='Début de la période d’allocation')
  88. end = models.DateTimeField(null=True, blank=True, verbose_name='Fin de la période d’allocation')
  89. def clean(self):
  90. super().clean()
  91. # Vérification de la cohérence des champs start et end
  92. if self.end and self.start > self.end:
  93. raise ValidationError("La date de début de l’allocation doit être antérieur "
  94. "à la date de fin de l’allocation.")
  95. # Vérification de l’abscence de chevauchement de la période d’allocation
  96. if self.resource_id:
  97. allocations = ResourceAllocation.objects.filter(resource__pk=self.resource.pk)
  98. if is_overlapping(self, allocations):
  99. raise ValidationError("La période d’allocation de cette ressource chevauche "
  100. "avec une période d’allocation précédente.")
  101. class Meta:
  102. verbose_name = 'allocation'
  103. verbose_name_plural = 'allocations'
  104. ordering = ['-start']
  105. def __str__(self):
  106. return str(self.resource)