Phase in admin, remove uuid from bills
This commit is contained in:
parent
662845128f
commit
8decfe1b16
6 changed files with 246 additions and 117 deletions
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue