From 05f38d157e7908503004e641e6a0b8ee9eb2480e Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 12 Apr 2020 11:35:37 +0200 Subject: [PATCH] add a discounter function to the product model --- .../uncloud/uncloud_pay/models.py | 75 ++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/uncloud_django_based/uncloud/uncloud_pay/models.py b/uncloud_django_based/uncloud/uncloud_pay/models.py index f7aee62..7a87ffa 100644 --- a/uncloud_django_based/uncloud/uncloud_pay/models.py +++ b/uncloud_django_based/uncloud/uncloud_pay/models.py @@ -28,9 +28,9 @@ class RecurringPeriod(models.TextChoices): ONE_TIME = 'ONCE', _('Onetime') PER_YEAR = 'YEAR', _('Per Year') PER_MONTH = 'MONTH', _('Per Month') - PER_MINUTE = 'MINUTE', _('Per Minute') PER_DAY = 'DAY', _('Per Day') PER_HOUR = 'HOUR', _('Per Hour') + PER_MINUTE = 'MINUTE', _('Per Minute') PER_SECOND = 'SECOND', _('Per Second') @@ -456,6 +456,10 @@ class Product(UncloudModel): editable=False, null=True) + # Default period for all products + default_recurring_period = RecurringPeriod.PER_MONTH + + @property def recurring_price(self, recurring_period=RecurringPeriod.PER_MONTH): pass # To be implemented in child. @@ -474,3 +478,72 @@ class Product(UncloudModel): class Meta: 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")