from django.conf import settings from django.core.exceptions import ValidationError from django.core.urlresolvers import reverse from django.db import models from .validators import less_than_one class AbstractItem(models.Model): name = models.CharField(max_length=130) description = models.TextField(blank=True) def __str__(self): return self.name def get_use_class(self): raise NotImplemented def used(self, except_by=None): """ Return the used fraction of an item :type: Service :param except_by: exclude this service from the math :rtype: float """ sharing_costs = self.get_use_class().objects.filter(resource=self) if except_by: sharing_costs = sharing_costs.exclude(service=except_by) existing_uses_sum = sum( sharing_costs.values_list('share', flat=True)) return existing_uses_sum class Meta: abstract = True class Cost(AbstractItem): """ A monthtly cost we have to pay """ price = models.FloatField(help_text="Coût mensuel") def get_use_class(self): return CostUse class Meta: verbose_name = 'Coût' class Good(AbstractItem): """ A good, which replacement is provisioned """ price = models.FloatField() provisioning_duration = models.DurationField( choices=settings.PROVISIONING_DURATIONS) def get_use_class(self): return GoodUse def monthly_provision(self): return self.price/self.provisioning_duration.days*(365.25/12) class Meta: verbose_name = 'Bien' class AbstractUse(models.Model): share = models.FloatField(validators=[less_than_one]) service = models.ForeignKey('Service') class Meta: abstract = True def clean(self): if hasattr(self, 'resource'): if (self.resource.used(except_by=self.service) + self.share) > 1: raise ValidationError( "Cannot use more than 100% of {})".format(self.resource)) class CostUse(AbstractUse): resource = models.ForeignKey(Cost) def cost_share(self): return self.share*self.resource.price def unit_cost_share(self): subscriptions_count = self.service.subscriptions_count if subscriptions_count == 0: return 0 else: return self.cost_share()/self.service.subscriptions_count class GoodUse(AbstractUse): resource = models.ForeignKey(Good) def monthly_provision_share(self): return self.real_share()*self.resource.monthly_provision() def unit_monthly_provision_share(self): subscriptions_count = self.service.subscriptions_count monthly_share = self.monthly_provision_share() if subscriptions_count == 0: return 0 else: return monthly_share/subscriptions_count class Service(AbstractItem): """ A service we sell (considered monthly) """ costs = models.ManyToManyField( Cost, through=CostUse, related_name='using_services') goods = models.ManyToManyField( Good, through=GoodUse, related_name='using_services') # services = models.ManyToMany('Service') #TODO subscriptions_count = models.PositiveIntegerField(default=0) def get_absolute_url(self): return reverse('detail-service', kwargs={'pk': self.pk})