# -*- coding: utf-8 -*- from __future__ import unicode_literals import datetime from django.conf import settings from django.db import models from django.db.models import Q from django.core.validators import MinValueValidator class Offer(models.Model): """Description of an offer available to subscribers. Implementation notes: configuration_type store the model name of the configuration backend (ex VPNConfiguration). The choices list is dynamically generated at start in the __init__ """ name = models.CharField(max_length=255, blank=False, null=False, verbose_name="nom de l'offre") reference = models.CharField(max_length=255, blank=True, verbose_name="référence de l'offre", help_text="Identifiant a utiliser par exemple comme identifiant de virement") configuration_type = models.CharField(max_length=50, blank=True, verbose_name='type de configuration', help_text="Type de configuration à utiliser avec cette offre") billing_period = models.IntegerField(blank=False, null=False, default=1, verbose_name='période de facturation', help_text='en mois', validators=[MinValueValidator(1)]) period_fees = models.DecimalField(max_digits=5, decimal_places=2, blank=False, null=False, verbose_name='montant par période de ' 'facturation', help_text='en €') initial_fees = models.DecimalField(max_digits=5, decimal_places=2, blank=False, null=False, verbose_name='frais de mise en service', help_text='en €') non_billable = models.BooleanField(default=False, verbose_name='n\'est pas facturable', help_text='L\'offre ne sera pas facturée par la commande charge_members') def get_configuration_type_display(self): """ Renvoi le nom affichable du type de configuration """ from coin.configuration.models import Configuration for item in Configuration.get_configurations_choices_list(): if item and self.configuration_type in item: return item[1] return self.configuration_type get_configuration_type_display.short_description = 'type de configuration' def display_price(self): """Displays the price of an offer in a human-readable manner (for instance "30€ / month") """ if int(self.period_fees) == self.period_fees: fee = int(self.period_fees) else: fee = self.period_fees if self.billing_period == 1: period = "" else: period = self.billing_period return "{period_fee}€ / {billing_period} mois".format( period_fee=fee, billing_period=period) def __unicode__(self): return '{name} - {price}'.format(name=self.name, price=self.display_price()) class Meta: verbose_name = 'offre' class OfferSubscription(models.Model): """Only contains administrative details about a subscription, not technical. Nothing here should end up into the LDAP backend. Implementation notes: the Configuration model (which actually implementing the backend (technical configuration for the technology)) relate to this class with a OneToOneField """ subscription_date = models.DateField( null=False, blank=False, default=datetime.date.today, verbose_name="date de souscription à l'offre") # TODO: for data retention, prevent deletion of a subscription object # while the resign date is recent enough (e.g. one year in France). resign_date = models.DateField( null=True, blank=True, verbose_name='date de résiliation') # TODO: move this to offers? commitment = models.IntegerField(blank=False, null=False, verbose_name="période d'engagement", help_text='en mois', validators=[MinValueValidator(0)], default=0) member = models.ForeignKey('members.Member', verbose_name='membre') offer = models.ForeignKey('Offer', verbose_name='offre') def get_subscription_reference(self): return settings.SUBSCRIPTION_REFERENCE.format(subscription=self) get_subscription_reference.short_description = 'Référence' def __unicode__(self): return '%s - %s - %s' % (self.member, self.offer.name, self.subscription_date) class Meta: verbose_name = 'abonnement' def count_active_subscriptions(): today = datetime.date.today() query = Q(subscription_date__lte=today) & (Q(resign_date__isnull=True) | Q(resign_date__gte=today)) return OfferSubscription.objects.filter(query).count()