add a discounter function to the product model

This commit is contained in:
Nico Schottelius 2020-04-12 11:35:37 +02:00
parent 9431f11284
commit 05f38d157e

View file

@ -28,9 +28,9 @@ class RecurringPeriod(models.TextChoices):
ONE_TIME = 'ONCE', _('Onetime') ONE_TIME = 'ONCE', _('Onetime')
PER_YEAR = 'YEAR', _('Per Year') PER_YEAR = 'YEAR', _('Per Year')
PER_MONTH = 'MONTH', _('Per Month') PER_MONTH = 'MONTH', _('Per Month')
PER_MINUTE = 'MINUTE', _('Per Minute')
PER_DAY = 'DAY', _('Per Day') PER_DAY = 'DAY', _('Per Day')
PER_HOUR = 'HOUR', _('Per Hour') PER_HOUR = 'HOUR', _('Per Hour')
PER_MINUTE = 'MINUTE', _('Per Minute')
PER_SECOND = 'SECOND', _('Per Second') PER_SECOND = 'SECOND', _('Per Second')
@ -456,6 +456,10 @@ class Product(UncloudModel):
editable=False, editable=False,
null=True) null=True)
# Default period for all products
default_recurring_period = RecurringPeriod.PER_MONTH
@property @property
def recurring_price(self, recurring_period=RecurringPeriod.PER_MONTH): def recurring_price(self, recurring_period=RecurringPeriod.PER_MONTH):
pass # To be implemented in child. pass # To be implemented in child.
@ -474,3 +478,72 @@ class Product(UncloudModel):
class Meta: class Meta:
abstract = True abstract = True
def discounted_price_by_period(self, requested_period):
"""
Each product has a standard recurring period for which
we define a pricing. I.e. VPN is usually year, VM is usually monthly.
The user can opt-in to use a different period, which influences the price:
The longer a user commits, the higher the discount.
Products can also be limited in the available periods. For instance
a VPN only makes sense to be bought for at least one day.
Rules are as follows:
given a standard recurring period of ..., changing to ... modifies price ...
# One month for free if buying / year, compared to a month: about 8.33% discount
per_year -> per_month -> /11
per_month -> per_year -> *11
# Month has 30.42 days on average. About 7.9% discount to go monthly
per_month -> per_day -> /28
per_day -> per_month -> *28
# Day has 24h, give one for free
per_day -> per_hour -> /23
per_hour -> per_day -> /23
Examples
VPN @ 120CHF/y becomes
- 10.91 CHF/month (130.91 CHF/year)
- 0.39 CHF/day (142.21 CHF/year)
VM @ 15 CHF/month becomes
- 165 CHF/month (13.75 CHF/month)
- 0.54 CHF/day (16.30 CHF/month)
"""
if self.default_recurring_period == RecurringPeriod.PER_YEAR:
if requested_period == RecurringPeriod.PER_YEAR:
return self.recurring_price
if requested_period == RecurringPeriod.PER_MONTH:
return self.recurring_price/11.
if requested_period == RecurringPeriod.PER_DAY:
return self.recurring_price/11./28.
elif self.default_recurring_period == RecurringPeriod.PER_MONTH:
if requested_period == RecurringPeriod.PER_YEAR:
return self.recurring_price*11
if requested_period == RecurringPeriod.PER_MONTH:
return self.recurring_price
if requested_period == RecurringPeriod.PER_DAY:
return self.recurring_price/28.
elif self.default_recurring_period == RecurringPeriod.PER_DAY:
if requested_period == RecurringPeriod.PER_YEAR:
return self.recurring_price*11*28
if requested_period == RecurringPeriod.PER_MONTH:
return self.recurring_price*28
if requested_period == RecurringPeriod.PER_DAY:
return self.recurring_price
else:
# FIXME: use the right type of exception here!
raise Exception("Did not implement the discounter for this case")