Continue to refactor for shifting logic into the order

This commit is contained in:
Nico Schottelius 2020-09-09 00:35:55 +02:00
parent 077c665c53
commit d8a7964fed
3 changed files with 161 additions and 91 deletions

View file

@ -95,8 +95,8 @@ python manage.py migrate
**** Add it to DNS as vpn-XXX.ungleich.ch **** Add it to DNS as vpn-XXX.ungleich.ch
**** Route a /40 network to its IPv6 address **** Route a /40 network to its IPv6 address
**** Install wireguard on it **** Install wireguard on it
**** TODO Enable wireguard on boot **** TODO [#C] Enable wireguard on boot
**** TODO Create a new VPNPool on uncloud with **** TODO [#C] Create a new VPNPool on uncloud with
***** the network address (selecting from our existing pool) ***** the network address (selecting from our existing pool)
***** the network size (/...) ***** the network size (/...)
***** the vpn host that provides the network (selecting the created VM) ***** the vpn host that provides the network (selecting the created VM)
@ -210,3 +210,16 @@ VPNNetworks can be managed by all authenticated users.
*** Decision *** Decision
We use integers, because they are easy. 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
-

View file

@ -372,24 +372,23 @@ class Order(models.Model):
return next_date 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 Determine the ending date given a specific bill
""" """
# If the order is quit, charge the final amount (?) # If the order is quit, charge the final amount (?)
if order.ending_date: if self.ending_date:
this_ending_date = order.ending_date this_ending_date = self.ending_date
else: else:
if order.earliest_ending_date > bill.ending_date: if self.earliest_ending_date > bill.ending_date:
this_ending_date = order.earliest_ending_date this_ending_date = self.earliest_ending_date
else: else:
this_ending_date = bill.ending_date this_ending_date = bill.ending_date
return this_ending_date return this_ending_date
@property @property
def count_billed(self): def count_billed(self):
""" """
@ -458,6 +457,74 @@ class Order(models.Model):
super().save(*args, **kwargs) 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): def __str__(self):
return f"{self.description} (order={self.id})" return f"{self.description} (order={self.id})"
@ -509,34 +576,12 @@ class Bill(models.Model):
@classmethod @classmethod
def create_bills_for_all_users(cls): 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(): for owner in get_user_model().objects.all():
cls.create_next_bills_for_user(owner) 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 @classmethod
def create_next_bills_for_user(cls, owner, ending_date=None): def create_next_bills_for_user(cls, owner, ending_date=None):
""" """
@ -547,80 +592,93 @@ class Bill(models.Model):
bills = [] bills = []
for billing_address in BillingAddress.objects.filter(owner=owner): 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 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 @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 Create the next bill for a specific billing address of a user
given bill
""" """
owner = bill.owner owner = billing_address.owner
billing_address = bill.billing_address
all_orders = Order.objects.filter(owner=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: for order in all_orders:
bill_record_for_this_bill = BillRecord.objects.filter(bill=bill, order.create_bill_record(bill)
order=order).first()
if bill_record_for_this_bill:
cls.update_bill_record_for_this_bill(bill_record_for_this_bill,
order,
bill)
else: return bill
cls.create_new_bill_record_for_this_bill(order, bill)
# @classmethod
# def create_bill_records_for_recurring_orders(cls, bill):
# """
# Create or update bill records for recurring orders for the
# given bill
# """
@staticmethod # owner = bill.owner
def create_new_bill_record_for_this_bill(order, bill): # billing_address = bill.billing_address
last_bill_record = BillRecord.objects.filter(order=order).order_by('id').last()
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: # for order in all_orders:
if last_bill_record.ending_date >= bill.ending_date: # bill_record_for_this_bill = BillRecord.objects.filter(bill=bill,
return # 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: # else:
if last_bill_record.ending_date == order.ending_date: # cls.create_new_bill_record_for_this_bill(order, bill)
return
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 @classmethod
def create_next_bill_for_user_address_old(cls, def create_next_bill_for_user_address_old(cls,

View file

@ -269,7 +269,7 @@ class BillTestCase(TestCase):
Ensure there is only 1 bill record per order 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) 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 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']) 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 Ensure there is only 1 bill record per order
""" """
bill = Bill.create_next_bill_for_user_address(self.recurring_user, bill = Bill.create_next_bill_for_user_address(self.recurring_user_addr)
self.recurring_user_addr)
self.assertEqual(self.recurring_order.billrecord_set.count(), 1) self.assertEqual(self.recurring_order.billrecord_set.count(), 1)
self.assertEqual(bill.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: 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() b.close()
bill_count = Bill.objects.filter(owner=self.recurring_user).count() bill_count = Bill.objects.filter(owner=self.recurring_user).count()