begin to change to day based differences
Signed-off-by: Nico Schottelius <nico@nico-notebook.schottelius.org>
This commit is contained in:
parent
18b862c2e1
commit
15535433e8
4 changed files with 67 additions and 70 deletions
|
@ -173,7 +173,7 @@ class VPNNetwork(Product):
|
|||
|
||||
wireguard_public_key = models.CharField(max_length=48)
|
||||
|
||||
default_recurring_period = RecurringPeriod.PER_YEAR
|
||||
default_recurring_period = RecurringPeriod.PER_365D
|
||||
|
||||
@property
|
||||
def recurring_price(self):
|
||||
|
|
|
@ -30,19 +30,15 @@ BILL_PAYMENT_DELAY=timedelta(days=10)
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
# See https://docs.djangoproject.com/en/dev/ref/models/fields/#field-choices-enum-types
|
||||
class RecurringPeriod(models.TextChoices):
|
||||
PER_YEAR = 'YEAR', _('Per Year') # this is broken - we can make it 365 days - REMOVE ME
|
||||
PER_MONTH = 'MONTH', _('Per Month') # this is broken - varying times - REMOVE ME
|
||||
|
||||
ONE_TIME = 'ONCE', _('Onetime') # this is ok
|
||||
PER_365D = '365D', _('Per 365 days') # this is ok
|
||||
PER_30D = '30D', _('Per 30 days') # this is ok
|
||||
PER_WEEK = 'WEEK', _('Per Week') # this is ok
|
||||
PER_DAY = 'DAY', _('Per Day') # this is ok
|
||||
PER_HOUR = 'HOUR', _('Per Hour') # this is ok
|
||||
PER_MINUTE = 'MINUTE', _('Per Minute') # this is ok
|
||||
PER_SECOND = 'SECOND', _('Per Second') # this is ok
|
||||
|
||||
class RecurringPeriod(models.IntegerChoices):
|
||||
PER_365D = 365*24*3600, _('Per 365 days')
|
||||
PER_30D = 30*24*3600, _('Per 30 days')
|
||||
PER_WEEK = 7*24*3600, _('Per Week')
|
||||
PER_DAY = 24*3600, _('Per Day')
|
||||
PER_HOUR = 3600, _('Per Hour')
|
||||
PER_MINUTE = 60, _('Per Minute')
|
||||
PER_SECOND = 1, _('Per Second')
|
||||
ONE_TIME = 0, _('Onetime')
|
||||
|
||||
|
||||
class CountryField(models.CharField):
|
||||
|
@ -292,6 +288,9 @@ class BillNico(models.Model):
|
|||
Can we do this even for recurring / all of them
|
||||
|
||||
"""
|
||||
|
||||
# FIXME: add something to check whether the order should be billed at all - i.e. a marker that
|
||||
# disables searching -> optimization for later
|
||||
for order in Order.objects.filter(Q(starting_date__gte=self.starting_date),
|
||||
Q(starting_date__lte=self.ending_date),
|
||||
owner=owner):
|
||||
|
@ -427,28 +426,28 @@ class Bill(models.Model):
|
|||
previous_bill = None
|
||||
|
||||
# FIXME: control flow is confusing in this block.
|
||||
if order.recurring_period == RecurringPeriod.PER_YEAR:
|
||||
# We ignore anything smaller than a day in here.
|
||||
next_yearly_bill_start_on = None
|
||||
if previous_bill == None:
|
||||
next_yearly_bill_start_on = order.starting_date
|
||||
elif previous_bill.ending_date <= ending_date:
|
||||
next_yearly_bill_start_on = (previous_bill.ending_date + timedelta(days=1))
|
||||
# if order.recurring_period == RecurringPeriod.PER_YEAR:
|
||||
# # We ignore anything smaller than a day in here.
|
||||
# next_yearly_bill_start_on = None
|
||||
# if previous_bill == None:
|
||||
# next_yearly_bill_start_on = order.starting_date
|
||||
# elif previous_bill.ending_date <= ending_date:
|
||||
# next_yearly_bill_start_on = (previous_bill.ending_date + timedelta(days=1))
|
||||
|
||||
# Store for bill generation. One bucket per day of month with a starting bill.
|
||||
# bucket is a reference here, no need to reassign.
|
||||
if next_yearly_bill_start_on:
|
||||
# We want to group orders by date but keep using datetimes.
|
||||
next_yearly_bill_start_on = next_yearly_bill_start_on.replace(
|
||||
minute=0, hour=0, second=0, microsecond=0)
|
||||
bucket = unpaid_orders['yearly'].get(next_yearly_bill_start_on)
|
||||
if bucket == None:
|
||||
unpaid_orders['yearly'][next_yearly_bill_start_on] = [order]
|
||||
else:
|
||||
unpaid_orders['yearly'][next_yearly_bill_start_on] = bucket + [order]
|
||||
else:
|
||||
if previous_bill == None or previous_bill.ending_date < ending_date:
|
||||
unpaid_orders['monthly_or_less'].append(order)
|
||||
# # Store for bill generation. One bucket per day of month with a starting bill.
|
||||
# # bucket is a reference here, no need to reassign.
|
||||
# if next_yearly_bill_start_on:
|
||||
# # We want to group orders by date but keep using datetimes.
|
||||
# next_yearly_bill_start_on = next_yearly_bill_start_on.replace(
|
||||
# minute=0, hour=0, second=0, microsecond=0)
|
||||
# bucket = unpaid_orders['yearly'].get(next_yearly_bill_start_on)
|
||||
# if bucket == None:
|
||||
# unpaid_orders['yearly'][next_yearly_bill_start_on] = [order]
|
||||
# else:
|
||||
# unpaid_orders['yearly'][next_yearly_bill_start_on] = bucket + [order]
|
||||
# else:
|
||||
# if previous_bill == None or previous_bill.ending_date < ending_date:
|
||||
# unpaid_orders['monthly_or_less'].append(order)
|
||||
|
||||
# Handle working month's billing.
|
||||
if len(unpaid_orders['monthly_or_less']) > 0:
|
||||
|
@ -586,25 +585,25 @@ class BillRecord():
|
|||
|
||||
# TODO: refactor this thing?
|
||||
# TODO: weekly
|
||||
if self.recurring_period == RecurringPeriod.PER_YEAR:
|
||||
# XXX: Should always be one => we do not bill for more than one year.
|
||||
# TODO: check billed_delta is ~365 days.
|
||||
return 1
|
||||
elif self.recurring_period == RecurringPeriod.PER_MONTH:
|
||||
days = ceil(billed_delta / timedelta(days=1))
|
||||
# if self.recurring_period == RecurringPeriod.PER_YEAR:
|
||||
# # XXX: Should always be one => we do not bill for more than one year.
|
||||
# # TODO: check billed_delta is ~365 days.
|
||||
# return 1
|
||||
# elif self.recurring_period == RecurringPeriod.PER_MONTH:
|
||||
# days = ceil(billed_delta / timedelta(days=1))
|
||||
|
||||
# Monthly bills always cover one single month.
|
||||
if (self.bill.starting_date.year != self.bill.starting_date.year or
|
||||
self.bill.starting_date.month != self.bill.ending_date.month):
|
||||
raise Exception('Bill {} covers more than one month. Cannot bill PER_MONTH.'.
|
||||
format(self.bill.uuid))
|
||||
# # Monthly bills always cover one single month.
|
||||
# if (self.bill.starting_date.year != self.bill.starting_date.year or
|
||||
# self.bill.starting_date.month != self.bill.ending_date.month):
|
||||
# raise Exception('Bill {} covers more than one month. Cannot bill PER_MONTH.'.
|
||||
# format(self.bill.uuid))
|
||||
|
||||
# XXX: minumal length of monthly order is to be enforced somewhere else.
|
||||
(_, days_in_month) = monthrange(
|
||||
self.bill.starting_date.year,
|
||||
self.bill.starting_date.month)
|
||||
return round(days / days_in_month, AMOUNT_DECIMALS)
|
||||
elif self.recurring_period == RecurringPeriod.PER_WEEK:
|
||||
# # XXX: minumal length of monthly order is to be enforced somewhere else.
|
||||
# (_, days_in_month) = monthrange(
|
||||
# self.bill.starting_date.year,
|
||||
# self.bill.starting_date.month)
|
||||
# return round(days / days_in_month, AMOUNT_DECIMALS)
|
||||
if self.recurring_period == RecurringPeriod.PER_WEEK:
|
||||
weeks = ceil(billed_delta / timedelta(week=1))
|
||||
return weeks
|
||||
elif self.recurring_period == RecurringPeriod.PER_DAY:
|
||||
|
@ -663,8 +662,7 @@ class Order(models.Model):
|
|||
blank=True)
|
||||
|
||||
recurring_period = models.CharField(max_length=32,
|
||||
choices = RecurringPeriod.choices,
|
||||
default = RecurringPeriod.PER_MONTH)
|
||||
choices = RecurringPeriod.choices, default = RecurringPeriod.PER_30D)
|
||||
|
||||
one_time_price = models.DecimalField(default=0.0,
|
||||
max_digits=AMOUNT_MAX_DIGITS,
|
||||
|
@ -712,8 +710,7 @@ class Order(models.Model):
|
|||
self.save()
|
||||
|
||||
def is_to_be_charged_in(year, month):
|
||||
if self.recurring_period == RecurringPeriod.PER_YEAR:
|
||||
pass
|
||||
pass
|
||||
|
||||
# Trigger initial bill generation at order creation.
|
||||
def save(self, *args, **kwargs):
|
||||
|
@ -771,7 +768,7 @@ class OrderTimothee(models.Model):
|
|||
|
||||
recurring_period = models.CharField(max_length=32,
|
||||
choices = RecurringPeriod.choices,
|
||||
default = RecurringPeriod.PER_MONTH)
|
||||
default = RecurringPeriod.PER_30D)
|
||||
|
||||
# Trigger initial bill generation at order creation.
|
||||
def save(self, *args, **kwargs):
|
||||
|
@ -873,7 +870,7 @@ class Product(UncloudModel):
|
|||
null=True)
|
||||
|
||||
# Default period for all products
|
||||
default_recurring_period = RecurringPeriod.PER_MONTH
|
||||
default_recurring_period = RecurringPeriod.PER_30D
|
||||
|
||||
# Used to save records.
|
||||
def save(self, *args, **kwargs):
|
||||
|
@ -966,26 +963,26 @@ class Product(UncloudModel):
|
|||
"""
|
||||
|
||||
|
||||
if self.default_recurring_period == RecurringPeriod.PER_YEAR:
|
||||
if requested_period == RecurringPeriod.PER_YEAR:
|
||||
if self.default_recurring_period == RecurringPeriod.PER_365D:
|
||||
if requested_period == RecurringPeriod.PER_365D:
|
||||
return self.recurring_price
|
||||
if requested_period == RecurringPeriod.PER_MONTH:
|
||||
if requested_period == RecurringPeriod.PER_30D:
|
||||
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:
|
||||
elif self.default_recurring_period == RecurringPeriod.PER_30D:
|
||||
if requested_period == RecurringPeriod.PER_365D:
|
||||
return self.recurring_price*11
|
||||
if requested_period == RecurringPeriod.PER_MONTH:
|
||||
if requested_period == RecurringPeriod.PER_30D:
|
||||
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:
|
||||
if requested_period == RecurringPeriod.PER_365D:
|
||||
return self.recurring_price*11*28
|
||||
if requested_period == RecurringPeriod.PER_MONTH:
|
||||
if requested_period == RecurringPeriod.PER_30D:
|
||||
return self.recurring_price*28
|
||||
if requested_period == RecurringPeriod.PER_DAY:
|
||||
return self.recurring_price
|
||||
|
|
|
@ -17,7 +17,7 @@ class MatrixServiceProduct(Product):
|
|||
domain = models.CharField(max_length=255, default='domain.tld')
|
||||
|
||||
# Default recurring price is PER_MONT, see Product class.
|
||||
def recurring_price(self, recurring_period=RecurringPeriod.PER_MONTH):
|
||||
def recurring_price(self, recurring_period=RecurringPeriod.PER_30D):
|
||||
return self.monthly_managment_fee
|
||||
|
||||
@staticmethod
|
||||
|
@ -28,7 +28,7 @@ class MatrixServiceProduct(Product):
|
|||
@staticmethod
|
||||
def allowed_recurring_periods():
|
||||
return list(filter(
|
||||
lambda pair: pair[0] in [RecurringPeriod.PER_MONTH],
|
||||
lambda pair: pair[0] in [RecurringPeriod.PER_30D],
|
||||
RecurringPeriod.choices))
|
||||
|
||||
@property
|
||||
|
|
|
@ -88,8 +88,8 @@ class VMProduct(Product):
|
|||
@staticmethod
|
||||
def allowed_recurring_periods():
|
||||
return list(filter(
|
||||
lambda pair: pair[0] in [RecurringPeriod.PER_YEAR,
|
||||
RecurringPeriod.PER_MONTH, RecurringPeriod.PER_HOUR],
|
||||
lambda pair: pair[0] in [RecurringPeriod.PER_365D,
|
||||
RecurringPeriod.PER_30D, RecurringPeriod.PER_HOUR],
|
||||
RecurringPeriod.choices))
|
||||
|
||||
def __str__(self):
|
||||
|
|
Loading…
Reference in a new issue