Phase in admin, remove uuid from bills

This commit is contained in:
Nico Schottelius 2020-06-21 13:46:54 +02:00
commit 8decfe1b16
6 changed files with 246 additions and 117 deletions

View file

@ -223,11 +223,14 @@ class BillingAddress(models.Model):
return addresses[0]
def __str__(self):
return "{}, {}, {} {}, {}".format(
self.name, self.street, self.postal_code, self.city,
self.country)
return "{} - {}, {}, {} {}, {}".format(
self.owner,
self.name, self.street, self.postal_code, self.city,
self.country)
###
# VAT
# Populated with the import-vat-numbers django command.
class VATRate(models.Model):
start_date = models.DateField(blank=True, null=True)
stop_date = models.DateField(blank=True, null=True)
@ -250,115 +253,6 @@ class VATRate(models.Model):
logger.debug("Did not find VAT rate for %s, returning 0" % country_code)
return 0
class BillRecord(models.Model):
"""
Entry of a bill, dynamically generated from an order.
"""
bill = models.ForeignKey(Bill, on_delete=models.CASCADE)
# How many times the order has been used in this record
usage_count = models.IntegerField(default=1)
# The timeframe the bill record is for can (and probably often will) differ
# from the bill time
creation_date = models.DateTimeField(auto_now_add=True)
starting_date = models.DateTimeField()
ending_date = models.DateTimeField()
class Bill(models.Model):
""" FIXME:
Bill needs to be unique in the triple (owner, year, month)
"""
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
owner = models.ForeignKey(get_user_model(),
on_delete=models.CASCADE)
creation_date = models.DateTimeField(auto_now_add=True)
starting_date = models.DateTimeField()
ending_date = models.DateTimeField()
due_date = models.DateField()
valid = models.BooleanField(default=True)
# billing address and vat rate is the same for the whole bill
# @property
# def vat_rate(self):
# return Decimal(VATRate.get_for_country(self.bill.billing_address.country))
@classmethod
def create_all_bills(cls):
for owner in get_user_model().objects.all():
# mintime = time of first order
# maxtime = time of last order
# iterate month based through it
cls.assign_orders_to_bill(owner, year, month)
pass
def assign_orders_to_bill(self, owner, year, month):
"""
Generate a bill for the specific month of a user.
First handle all one time orders
FIXME:
- limit this to active users in the future! (2020-05-23)
"""
"""
Find all one time orders that have a starting date that falls into this month
recurring_period=RecurringPeriod.ONE_TIME,
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
# Create the initial bill record
# FIXME: maybe limit not even to starting/ending date, but to empty_bill record -- to be fixed in the future
# for order in Order.objects.filter(Q(starting_date__gte=self.starting_date),
# Q(starting_date__lte=self.ending_date),
# FIXME below: only check for active orders
# Ensure all orders of that owner have at least one bill record
for order in Order.objects.filter(owner=owner,
bill_records=None):
bill_record = BillRecord.objects.create(bill=self,
usage_count=1,
starting_date=order.starting_date,
ending_date=order.starting_date + timedelta(seconds=order.recurring_period))
# For each recurring order get the usage and bill it
for order in Order.objects.filter(~Q(recurring_period=RecurringPeriod.ONE_TIME),
Q(starting_date__lt=self.starting_date),
owner=owner):
if order.recurring_period > 0: # avoid div/0 - these are one time payments
# How much time will have passed by the end of the billing cycle
td = self.ending_date - order.starting_date
# How MANY times it will have been used by then
used_times = ceil(td / timedelta(seconds=order.recurring_period))
billed_times = len(order.bills)
# How many times it WAS billed -- can also be inferred from the bills that link to it!
if used_times > billed_times:
billing_times = used_times - billed_times
# ALSO REGISTER THE TIME PERIOD!
pass
###
# Orders.
@ -382,9 +276,9 @@ class Order(models.Model):
ending_date = models.DateTimeField(blank=True,
null=True)
bill_records = models.ManyToManyField(BillRecord,
editable=False,
blank=True)
# bill_records = models.ManyToManyField(BillRecord,
# editable=False,
# blank=True)
@property
def count_billed(self):
@ -512,6 +406,127 @@ class Order(models.Model):
self.recurring_price)
class Bill(models.Model):
""" FIXME:
Bill needs to be unique in the triple (owner, year, month)
"""
# uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
owner = models.ForeignKey(get_user_model(),
on_delete=models.CASCADE)
creation_date = models.DateTimeField(auto_now_add=True)
starting_date = models.DateTimeField()
ending_date = models.DateTimeField()
due_date = models.DateField()
valid = models.BooleanField(default=True)
# Mapping to BillRecords
# https://stackoverflow.com/questions/4443190/djangos-manytomany-relationship-with-additional-fields
bill_records = models.ManyToManyField(Order, through="BillRecord")
# billing address and vat rate is the same for the whole bill
# @property
# def vat_rate(self):
# return Decimal(VATRate.get_for_country(self.bill.billing_address.country))
def __str__(self):
return f"uc-{self.id}"
@classmethod
def create_all_bills(cls):
for owner in get_user_model().objects.all():
# mintime = time of first order
# maxtime = time of last order
# iterate month based through it
cls.assign_orders_to_bill(owner, year, month)
pass
def assign_orders_to_bill(self, owner, year, month):
"""
Generate a bill for the specific month of a user.
First handle all one time orders
FIXME:
- limit this to active users in the future! (2020-05-23)
"""
"""
Find all one time orders that have a starting date that falls into this month
recurring_period=RecurringPeriod.ONE_TIME,
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
# Create the initial bill record
# FIXME: maybe limit not even to starting/ending date, but to empty_bill record -- to be fixed in the future
# for order in Order.objects.filter(Q(starting_date__gte=self.starting_date),
# Q(starting_date__lte=self.ending_date),
# FIXME below: only check for active orders
# Ensure all orders of that owner have at least one bill record
for order in Order.objects.filter(owner=owner,
bill_records=None):
bill_record = BillRecord.objects.create(bill=self,
usage_count=1,
starting_date=order.starting_date,
ending_date=order.starting_date + timedelta(seconds=order.recurring_period))
# For each recurring order get the usage and bill it
for order in Order.objects.filter(~Q(recurring_period=RecurringPeriod.ONE_TIME),
Q(starting_date__lt=self.starting_date),
owner=owner):
if order.recurring_period > 0: # avoid div/0 - these are one time payments
# How much time will have passed by the end of the billing cycle
td = self.ending_date - order.starting_date
# How MANY times it will have been used by then
used_times = ceil(td / timedelta(seconds=order.recurring_period))
billed_times = len(order.bills)
# How many times it WAS billed -- can also be inferred from the bills that link to it!
if used_times > billed_times:
billing_times = used_times - billed_times
# ALSO REGISTER THE TIME PERIOD!
pass
class BillRecord(models.Model):
"""
Entry of a bill, dynamically generated from an order.
"""
bill = models.ForeignKey(Bill, on_delete=models.CASCADE)
order = models.ForeignKey(Order, on_delete=models.CASCADE)
# How many times the order has been used in this record
usage_count = models.IntegerField(default=1)
# The timeframe the bill record is for can (and probably often will) differ
# from the bill time
creation_date = models.DateTimeField(auto_now_add=True)
starting_date = models.DateTimeField()
ending_date = models.DateTimeField()
def __str__(self):
return f"{order.owner}"
class OrderRecord(models.Model):
"""
@ -523,6 +538,7 @@ class OrderRecord(models.Model):
"""
order = models.ForeignKey(Order, on_delete=models.CASCADE)
one_time_price = models.DecimalField(default=0.0,
max_digits=AMOUNT_MAX_DIGITS,
decimal_places=AMOUNT_DECIMALS,