# -*- coding: utf-8 -*-
from django.db import models
from django.utils.translation import gettext_lazy as _
from model_utils.models import TimeStampedModel, SoftDeletableModel
import swapper
[docs]class BasePlan(TimeStampedModel, SoftDeletableModel):
"""
Abstract BasePlan
-----------------
BasePlan is TimeStamped, which means it holds a reference to dates of creation and modification.
BasePlan is SoftDeletable, which means it becomes deactivated and not removed entirely (to keep a reference to
subscribed plans which become soft-deleted and thus no more available).
BasePlan also can be visible and available. Plan is displayed on the list of currently available plans
for user if it is visible. User cannot change plan to a plan that is not visible. Available means
that user can buy a plan. If plan is not visible but still available it means that user which
is using this plan already will be able to extend this plan again. If plan is not visible and not
available, he will be forced then to change plan next time he extends an account.
BasePlan is defined by its Features, which can be quotas, permissions on objects and features
"""
name = models.CharField(_('name'), max_length=255, unique=True)
description = models.TextField(_('description'), blank=True)
default = models.NullBooleanField(
help_text=_('Both "Unknown" and "No" means that the plan is not default'),
default=None,
db_index=True,
unique=True,
)
available = models.BooleanField(
_('available'), default=False, db_index=True,
help_text=_('Is still available for purchase')
)
visible = models.BooleanField(
_('visible'), default=True, db_index=True,
help_text=_('Is visible in current offer')
)
features = models.ManyToManyField(swapper.get_model_name('flexible_plans', 'Feature'), through='PlanFeatures')
[docs] @staticmethod
def get_provider_choices():
"""
Scans settings to look for configured payment providers and serve them as choice list
:return: [PaymentProvider]
"""
from django.conf import settings
choices = []
if getattr(settings, 'PAYMENT_PROVIDERS', None):
choices = list(settings.PAYMENT_PROVIDERS)
return choices
[docs] @staticmethod
def get_default_plan(cls):
"""
Shortcut to retrieve the default plan to be assigned if no plan is selected
:param cls:
:return: default Plan instance
"""
try:
default_plan = cls.objects.get(default=True)
except cls.DoesNotExists():
default_plan = None
return default_plan
[docs] def get_features_dict(self):
"""
Retrieve a Dict of all the plan's feature to pass through validators
:return: {feat.codename: feat.value}
"""
feat_dict = {}
for plan_feature in PlanFeature.objects.filter(plan=self).select_related('feature'):
feat_dict[plan_feature.feature.codename] = plan_feature.value
return feat_dict
class Meta:
abstract = True
[docs]class Plan(BasePlan):
"""
Single plan defined in the system. A plan can be customized (for specific users), which means
that only those users can purchase this plan and have it selected.
"""
provider = models.CharField(max_length=100, choices=BasePlan.get_provider_choices())
def __str__(self):
return self.name
class Meta:
# Setting model as swappable
swappable = swapper.swappable_setting('flexible_plans', 'Plan')
[docs]class PlanFeature(models.Model):
plan = models.ForeignKey('Plan')
feature = models.ForeignKey(swapper.get_model_name('flexible_plans', 'Feature'))