Continue to refactor for shifting logic into the order
This commit is contained in:
parent
077c665c53
commit
d8a7964fed
3 changed files with 161 additions and 91 deletions
|
@ -95,8 +95,8 @@ python manage.py migrate
|
|||
**** Add it to DNS as vpn-XXX.ungleich.ch
|
||||
**** Route a /40 network to its IPv6 address
|
||||
**** Install wireguard on it
|
||||
**** TODO Enable wireguard on boot
|
||||
**** TODO Create a new VPNPool on uncloud with
|
||||
**** TODO [#C] Enable wireguard on boot
|
||||
**** TODO [#C] Create a new VPNPool on uncloud with
|
||||
***** the network address (selecting from our existing pool)
|
||||
***** the network size (/...)
|
||||
***** the vpn host that provides the network (selecting the created VM)
|
||||
|
@ -210,3 +210,16 @@ VPNNetworks can be managed by all authenticated users.
|
|||
|
||||
*** Decision
|
||||
We use integers, because they are easy.
|
||||
|
||||
** Milestones :uncloud:
|
||||
*** 1.1 (cleanup 1)
|
||||
****
|
||||
*** 1.0 (initial release)
|
||||
**** TODO Initial Generic product support
|
||||
- Product
|
||||
***** TODO Recurring product support
|
||||
****** TODO Support replacing orders for updates
|
||||
****** TODO [#A] Finish split of bill creation
|
||||
****** TODO [#A] Test the new functions in the Order class
|
||||
***** TODO Generating bill for admins/staff
|
||||
-
|
||||
|
|
|
@ -372,24 +372,23 @@ class Order(models.Model):
|
|||
|
||||
return next_date
|
||||
|
||||
def get_ending_date_for_bill(bill):
|
||||
def get_ending_date_for_bill(self, bill):
|
||||
"""
|
||||
Determine the ending date given a specific bill
|
||||
"""
|
||||
|
||||
# If the order is quit, charge the final amount (?)
|
||||
if order.ending_date:
|
||||
this_ending_date = order.ending_date
|
||||
if self.ending_date:
|
||||
this_ending_date = self.ending_date
|
||||
else:
|
||||
if order.earliest_ending_date > bill.ending_date:
|
||||
this_ending_date = order.earliest_ending_date
|
||||
if self.earliest_ending_date > bill.ending_date:
|
||||
this_ending_date = self.earliest_ending_date
|
||||
else:
|
||||
this_ending_date = bill.ending_date
|
||||
|
||||
return this_ending_date
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def count_billed(self):
|
||||
"""
|
||||
|
@ -458,6 +457,74 @@ class Order(models.Model):
|
|||
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
|
||||
def create_bill_record(self, bill):
|
||||
br = None
|
||||
|
||||
if self.is_one_time:
|
||||
if self.billrecord_set.count() == 0:
|
||||
br = BillRecord.objects.create(bill=bill,
|
||||
order=self,
|
||||
starting_date=self.starting_date,
|
||||
ending_date=self.ending_date)
|
||||
else:
|
||||
br = BillRecord.objects.filter(bill=bill, order=self).first()
|
||||
if br:
|
||||
self.update_bill_record_for_recurring_order(br, bill)
|
||||
|
||||
else:
|
||||
br = self.create_new_bill_record_for_recurring_order(bill)
|
||||
|
||||
return br
|
||||
|
||||
def update_bill_record_for_recurring_order(self,
|
||||
bill_record,
|
||||
bill):
|
||||
"""
|
||||
Possibly update a bill record according to the information in the bill
|
||||
"""
|
||||
|
||||
# If the order has an ending date set, we might need to adjust the bill_record
|
||||
if self.ending_date:
|
||||
if bill_record_for_this_bill.ending_date != self.ending_date:
|
||||
bill_record_for_this_bill.ending_date = self.ending_date
|
||||
|
||||
else:
|
||||
# recurring, not terminated, should go until at least end of bill
|
||||
if bill_record_for_this_bill.ending_date < bill.ending_date:
|
||||
bill_record_for_this_bill.ending_date = bill.ending_date
|
||||
|
||||
bill_record_for_this_bill.save()
|
||||
|
||||
def create_new_bill_record_for_recurring_order(self, bill):
|
||||
"""
|
||||
Create a new bill record
|
||||
"""
|
||||
|
||||
last_bill_record = BillRecord.objects.filter(order=self).order_by('id').last()
|
||||
|
||||
starting_date=self.starting_date
|
||||
|
||||
if last_bill_record:
|
||||
# We already charged beyond the end of this bill's period
|
||||
if last_bill_record.ending_date >= bill.ending_date:
|
||||
return
|
||||
|
||||
# This order is terminated or replaced
|
||||
if self.ending_date:
|
||||
# And the last bill record already covered us -> nothing to be done anymore
|
||||
if last_bill_record.ending_date == self.ending_date:
|
||||
return
|
||||
|
||||
starting_date = start_after(last_bill_record.ending_date)
|
||||
|
||||
ending_date = self.get_ending_date_for_bill(bill)
|
||||
|
||||
return BillRecord.objects.create(bill=bill,
|
||||
order=self,
|
||||
starting_date=starting_date,
|
||||
ending_date=ending_date)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.description} (order={self.id})"
|
||||
|
||||
|
@ -509,34 +576,12 @@ class Bill(models.Model):
|
|||
@classmethod
|
||||
def create_bills_for_all_users(cls):
|
||||
"""
|
||||
Create bills for all users
|
||||
Create next bill for each user
|
||||
"""
|
||||
|
||||
for owner in get_user_model().objects.all():
|
||||
cls.create_next_bills_for_user(owner)
|
||||
|
||||
@classmethod
|
||||
def create_next_bill_for_user_address(cls,
|
||||
owner,
|
||||
billing_address,
|
||||
ending_date=None):
|
||||
|
||||
"""
|
||||
Check the existing orders of the billing address
|
||||
and generate a bill if there is at least one active order
|
||||
"""
|
||||
|
||||
all_orders = Order.objects.filter(owner=owner,
|
||||
billing_address=billing_address).order_by('id')
|
||||
|
||||
|
||||
# a bill. If there
|
||||
# for order in all_orders:
|
||||
# if order.is_one_time:
|
||||
# cls.create_one_time_record
|
||||
|
||||
# pass
|
||||
|
||||
@classmethod
|
||||
def create_next_bills_for_user(cls, owner, ending_date=None):
|
||||
"""
|
||||
|
@ -547,80 +592,93 @@ class Bill(models.Model):
|
|||
bills = []
|
||||
|
||||
for billing_address in BillingAddress.objects.filter(owner=owner):
|
||||
bills.append(cls.create_next_bill_for_user_address(owner, billing_address, ending_date))
|
||||
bills.append(cls.create_next_bill_for_user_address(billing_address, ending_date))
|
||||
|
||||
return bills
|
||||
|
||||
@classmethod
|
||||
def get_or_create_bill(cls, billing_address):
|
||||
last_bill = cls.objects.filter(billing_address=billing_address).order_by('id').last()
|
||||
|
||||
all_orders = Order.objects.filter(billing_address=billing_address).order_by('id')
|
||||
first_order = all_orders.first()
|
||||
|
||||
bill = None
|
||||
ending_date = None
|
||||
|
||||
# Get date & bill from previous bill, if it exists
|
||||
if last_bill:
|
||||
if not last_bill.is_final:
|
||||
bill = last_bill
|
||||
starting_date = last_bill.starting_date
|
||||
ending_date = bill.ending_date
|
||||
else:
|
||||
starting_date = last_bill.ending_date + datetime.timedelta(seconds=1)
|
||||
else:
|
||||
# Might be an idea to make this the start of the month, too
|
||||
if first_order:
|
||||
starting_date = first_order.starting_date
|
||||
else:
|
||||
starting_date = timezone.now()
|
||||
|
||||
if not ending_date:
|
||||
ending_date = end_of_month(starting_date)
|
||||
|
||||
if not bill:
|
||||
bill = cls.objects.create(
|
||||
owner=billing_address.owner,
|
||||
starting_date=starting_date,
|
||||
ending_date=ending_date,
|
||||
billing_address=billing_address)
|
||||
|
||||
|
||||
return bill
|
||||
|
||||
@classmethod
|
||||
def create_bill_records_for_recurring_orders(cls, bill):
|
||||
def create_next_bill_for_user_address(cls,
|
||||
billing_address,
|
||||
ending_date=None):
|
||||
|
||||
"""
|
||||
Create or update bill records for recurring orders for the
|
||||
given bill
|
||||
Create the next bill for a specific billing address of a user
|
||||
"""
|
||||
|
||||
owner = bill.owner
|
||||
billing_address = bill.billing_address
|
||||
owner = billing_address.owner
|
||||
|
||||
all_orders = Order.objects.filter(owner=owner,
|
||||
billing_address=billing_address).order_by('id').exclude(recurring_period=RecurringPeriod.ONE_TIME)
|
||||
billing_address=billing_address).order_by('id')
|
||||
|
||||
bill = cls.get_or_create_bill(billing_address)
|
||||
|
||||
for order in all_orders:
|
||||
bill_record_for_this_bill = BillRecord.objects.filter(bill=bill,
|
||||
order=order).first()
|
||||
if bill_record_for_this_bill:
|
||||
cls.update_bill_record_for_this_bill(bill_record_for_this_bill,
|
||||
order,
|
||||
bill)
|
||||
order.create_bill_record(bill)
|
||||
|
||||
else:
|
||||
cls.create_new_bill_record_for_this_bill(order, bill)
|
||||
return bill
|
||||
|
||||
# @classmethod
|
||||
# def create_bill_records_for_recurring_orders(cls, bill):
|
||||
# """
|
||||
# Create or update bill records for recurring orders for the
|
||||
# given bill
|
||||
# """
|
||||
|
||||
@staticmethod
|
||||
def create_new_bill_record_for_this_bill(order, bill):
|
||||
last_bill_record = BillRecord.objects.filter(order=order).order_by('id').last()
|
||||
# owner = bill.owner
|
||||
# billing_address = bill.billing_address
|
||||
|
||||
this_starting_date=order.starting_date
|
||||
# all_orders = Order.objects.filter(owner=owner,
|
||||
# billing_address=billing_address).order_by('id').exclude(recurring_period=RecurringPeriod.ONE_TIME)
|
||||
|
||||
if last_bill_record:
|
||||
if last_bill_record.ending_date >= bill.ending_date:
|
||||
return
|
||||
# for order in all_orders:
|
||||
# bill_record_for_this_bill = BillRecord.objects.filter(bill=bill,
|
||||
# order=order).first()
|
||||
# if bill_record_for_this_bill:
|
||||
# cls.update_bill_record_for_this_bill(bill_record_for_this_bill,
|
||||
# order,
|
||||
# bill)
|
||||
|
||||
if order.ending_date:
|
||||
if last_bill_record.ending_date == order.ending_date:
|
||||
return
|
||||
# else:
|
||||
# cls.create_new_bill_record_for_this_bill(order, bill)
|
||||
|
||||
this_starting_date = start_after(last_bill_record.ending_date)
|
||||
|
||||
|
||||
ending_date = order.get_ending_date_for_bill(bill)
|
||||
|
||||
return BillRecord.objects.create(bill=bill,
|
||||
order=order,
|
||||
starting_date=this_starting_date,
|
||||
ending_date=this_ending_date)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def update_bill_record_for_this_bill(bill_record,
|
||||
order,
|
||||
bill):
|
||||
|
||||
# we may need to adjust it, but let's do this logic another time
|
||||
|
||||
# If the order has an ending date set, we might need to adjust the bill_record
|
||||
if order.ending_date:
|
||||
if bill_record_for_this_bill.ending_date != order.ending_date:
|
||||
bill_record_for_this_bill.ending_date = order.ending_date
|
||||
|
||||
else:
|
||||
# recurring, not terminated, should go until at least end of bill
|
||||
if bill_record_for_this_bill.ending_date < bill.ending_date:
|
||||
bill_record_for_this_bill.ending_date = bill.ending_date
|
||||
|
||||
|
||||
bill_record_for_this_bill.save()
|
||||
|
||||
@classmethod
|
||||
def create_next_bill_for_user_address_old(cls,
|
||||
|
|
|
@ -269,7 +269,7 @@ class BillTestCase(TestCase):
|
|||
Ensure there is only 1 bill record per order
|
||||
"""
|
||||
|
||||
bill = Bill.create_next_bill_for_user_address(self.user, self.user_addr)
|
||||
bill = Bill.create_next_bill_for_user_address(self.user_addr)
|
||||
|
||||
self.assertEqual(self.one_time_order.billrecord_set.count(), 1)
|
||||
|
||||
|
@ -278,7 +278,7 @@ class BillTestCase(TestCase):
|
|||
Check the bill sum for a single one time order
|
||||
"""
|
||||
|
||||
bill = Bill.create_next_bill_for_user_address(self.user, self.user_addr)
|
||||
bill = Bill.create_next_bill_for_user_address(self.user_addr)
|
||||
self.assertEqual(bill.sum, self.order_meta[1]['price'])
|
||||
|
||||
|
||||
|
@ -287,8 +287,7 @@ class BillTestCase(TestCase):
|
|||
Ensure there is only 1 bill record per order
|
||||
"""
|
||||
|
||||
bill = Bill.create_next_bill_for_user_address(self.recurring_user,
|
||||
self.recurring_user_addr)
|
||||
bill = Bill.create_next_bill_for_user_address(self.recurring_user_addr)
|
||||
|
||||
self.assertEqual(self.recurring_order.billrecord_set.count(), 1)
|
||||
self.assertEqual(bill.billrecord_set.count(), 1)
|
||||
|
@ -301,7 +300,7 @@ class BillTestCase(TestCase):
|
|||
"""
|
||||
|
||||
for ending_date in self.bill_dates:
|
||||
b = Bill.create_next_bill_for_user_address(self.recurring_user, self.recurring_user_addr, ending_date)
|
||||
b = Bill.create_next_bill_for_user_address(self.recurring_user_addr, ending_date)
|
||||
b.close()
|
||||
|
||||
bill_count = Bill.objects.filter(owner=self.recurring_user).count()
|
||||
|
|
Loading…
Reference in a new issue