models.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. # -*- coding: utf-8 -*-
  2. import datetime
  3. from django.db import models
  4. class Offer(models.Model):
  5. """Description of an offer available to subscribers.
  6. Implementation notes: achieving genericity is difficult, especially
  7. because different technologies may have very different configuration
  8. parameters.
  9. Technology-specific configuration (e.g. for VPN) is implemented as a
  10. model having a OneToOne relation to OfferSubscription. In order to
  11. reach the technology-specific configuration model from an
  12. OfferSubscription, the OneToOne relation MUST have a related_name
  13. equal to one of the backends in OFFER_BACKEND_CHOICES (for instance
  14. "openvpn_ldap").
  15. """
  16. OFFER_BACKEND_CHOICES = (
  17. ('openvpn_ldap', 'OpenVPN (LDAP)'),
  18. # Use this if you don't actually want to implement a backend, for
  19. # instance if you resell somebody else's offers and don't manage
  20. # technical information yourself.
  21. ('none', 'None'),
  22. )
  23. name = models.CharField(max_length=255, blank=False, null=False,
  24. verbose_name='Nom de l\'offre')
  25. type = models.CharField(max_length=50,
  26. verbose_name="Type of offer, for instance technology used (informative only)")
  27. billing_period = models.IntegerField(blank=False, null=False, default=1,
  28. verbose_name='Période de facturation',
  29. help_text='en mois')
  30. period_fees = models.DecimalField(max_digits=5, decimal_places=2,
  31. blank=False, null=False,
  32. verbose_name='Montant par période de '
  33. 'facturation',
  34. help_text='en €')
  35. initial_fees = models.DecimalField(max_digits=5, decimal_places=2,
  36. blank=False, null=False,
  37. verbose_name='Frais de mise en service',
  38. help_text='en €')
  39. # TODO: really ensure that this field does not change (as it would
  40. # seriously break subscriptions)
  41. backend = models.CharField(max_length=50, choices=OFFER_BACKEND_CHOICES)
  42. def __unicode__(self):
  43. return u'%s - %d€ / %im [%s]' % (self.name, self.period_fees,
  44. self.billing_period, self.type)
  45. class Meta:
  46. verbose_name = 'offre'
  47. class OfferSubscription(models.Model):
  48. """Only contains administrative details about a subscription, not
  49. technical. Nothing here should end up into the LDAP backend.
  50. Implementation notes: the model actually implementing the backend
  51. (technical configuration for the technology) MUST relate to this class
  52. with a OneToOneField whose related name is a member of
  53. OFFER_BACKEND_CHOICES, for instance:
  54. models.OneToOneField('offers.OfferSubscription', related_name="openvpn_ldap")
  55. """
  56. subscription_date = models.DateField(
  57. null=False,
  58. blank=False,
  59. default=datetime.date.today,
  60. verbose_name='Date de souscription à l\'offre')
  61. # TODO: for data retention, prevent deletion of a subscription object
  62. # while the resign date is recent enough (e.g. one year in France).
  63. resign_date = models.DateField(
  64. null=True,
  65. blank=True,
  66. verbose_name='Date de résiliation')
  67. # TODO: move this to offers?
  68. commitment = models.IntegerField(blank=False, null=False,
  69. verbose_name='Période d\'engagement',
  70. help_text = 'en mois',
  71. default=0)
  72. member = models.ForeignKey('members.Member', verbose_name='Membre')
  73. offer = models.ForeignKey('Offer', verbose_name='Offre')
  74. @property
  75. def configuration(self):
  76. """Returns the configuration object associated to this subscription,
  77. according to the backend type specified in the offer. Yes, this
  78. is hand-made genericity. If you can think of a better way, feel
  79. free to propose something.
  80. """
  81. if self.offer.backend == 'none' or not hasattr(self, self.offer.backend):
  82. return
  83. return getattr(self, self.offer.backend)
  84. def __unicode__(self):
  85. return u'%s - %s - %s - %s' % (self.member, self.offer.name,
  86. self.subscription_date,
  87. self.configuration)
  88. class Meta:
  89. verbose_name = 'abonnement'