models.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. import datetime
  4. from django.db import models
  5. from django.db.models import Q
  6. from django.core.validators import MinValueValidator
  7. class Offer(models.Model):
  8. """Description of an offer available to subscribers.
  9. Implementation notes:
  10. configuration_type store the model name of the configuration backend
  11. (ex VPNConfiguration).
  12. The choices list is dynamically generated at start in the __init__
  13. """
  14. name = models.CharField(max_length=255, blank=False, null=False,
  15. verbose_name="nom de l'offre")
  16. configuration_type = models.CharField(max_length=50,
  17. blank=True,
  18. verbose_name='type de configuration',
  19. help_text="Type de configuration à utiliser avec cette offre")
  20. billing_period = models.IntegerField(blank=False, null=False, default=1,
  21. verbose_name='période de facturation',
  22. help_text='en mois',
  23. validators=[MinValueValidator(1)])
  24. period_fees = models.DecimalField(max_digits=5, decimal_places=2,
  25. blank=False, null=False,
  26. verbose_name='montant par période de '
  27. 'facturation',
  28. help_text='en €')
  29. initial_fees = models.DecimalField(max_digits=5, decimal_places=2,
  30. blank=False, null=False,
  31. verbose_name='frais de mise en service',
  32. help_text='en €')
  33. non_billable = models.BooleanField(default=False,
  34. verbose_name='n\'est pas facturable',
  35. help_text='L\'offre ne sera pas facturée par la commande charge_members')
  36. def get_configuration_type_display(self):
  37. """
  38. Renvoi le nom affichable du type de configuration
  39. """
  40. from coin.configuration.models import Configuration
  41. for item in Configuration.get_configurations_choices_list():
  42. if item and self.configuration_type in item:
  43. return item[1]
  44. return self.configuration_type
  45. get_configuration_type_display.short_description = 'type de configuration'
  46. def display_price(self):
  47. """Displays the price of an offer in a human-readable manner
  48. (for instance "30€ / month")
  49. """
  50. if int(self.period_fees) == self.period_fees:
  51. fee = int(self.period_fees)
  52. else:
  53. fee = self.period_fees
  54. if self.billing_period == 1:
  55. period = ""
  56. else:
  57. period = self.billing_period
  58. return "{period_fee}€ / {billing_period} mois".format(
  59. period_fee=fee,
  60. billing_period=period)
  61. def __unicode__(self):
  62. return '{name} - {price}'.format(name=self.name,
  63. price=self.display_price())
  64. class Meta:
  65. verbose_name = 'offre'
  66. class OfferSubscription(models.Model):
  67. """Only contains administrative details about a subscription, not
  68. technical. Nothing here should end up into the LDAP backend.
  69. Implementation notes: the Configuration model (which actually implementing the backend
  70. (technical configuration for the technology)) relate to this class
  71. with a OneToOneField
  72. """
  73. subscription_date = models.DateField(
  74. null=False,
  75. blank=False,
  76. default=datetime.date.today,
  77. verbose_name="date de souscription à l'offre")
  78. # TODO: for data retention, prevent deletion of a subscription object
  79. # while the resign date is recent enough (e.g. one year in France).
  80. resign_date = models.DateField(
  81. null=True,
  82. blank=True,
  83. verbose_name='date de résiliation')
  84. # TODO: move this to offers?
  85. commitment = models.IntegerField(blank=False, null=False,
  86. verbose_name="période d'engagement",
  87. help_text='en mois',
  88. validators=[MinValueValidator(0)],
  89. default=0)
  90. member = models.ForeignKey('members.Member', verbose_name='membre')
  91. offer = models.ForeignKey('Offer', verbose_name='offre')
  92. def __unicode__(self):
  93. return '%s - %s - %s' % (self.member, self.offer.name,
  94. self.subscription_date)
  95. class Meta:
  96. verbose_name = 'abonnement'
  97. def count_active_subscriptions():
  98. today = datetime.date.today()
  99. query = Q(subscription_date__lte=today) & (Q(resign_date__isnull=True) | Q(resign_date__gte=today))
  100. return OfferSubscription.objects.filter(query).count()