first bill generation works

Signed-off-by: Nico Schottelius <nico@nico-notebook.schottelius.org>
This commit is contained in:
Nico Schottelius 2020-08-09 00:37:27 +02:00
commit d7c0c40926
6 changed files with 136 additions and 65 deletions

View file

@ -382,9 +382,7 @@ class Bill(models.Model):
starting_date = models.DateTimeField(default=start_of_this_month)
ending_date = models.DateTimeField()
due_date = models.DateField(default=default_payment_delay)
# what is valid for? should this be "final"?
valid = models.BooleanField(default=True)
is_final = models.BooleanField(default=False)
class Meta:
constraints = [
@ -409,29 +407,36 @@ class Bill(models.Model):
all_orders = Order.objects.filter(owner=owner).order_by('id')
first_order = all_orders.first()
bill = None
ending_date = None
# Calculate the start date
# Get date & bill from previous bill
if last_bill:
# TODO: check that last bill is finished/closed, if not continue using it
starting_date = last_bill.end_date + datetime.timedelta(seconds=1)
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.end_date + datetime.timedelta(seconds=1)
else:
if first_order:
starting_date = first_order.starting_date
else:
starting_date = timezone.now()
ending_date = end_of_month(starting_date)
# FIXME above: maybe even use different date / active / open bill
bill, created = cls.objects.get_or_create(
owner=owner,
starting_date=starting_date,
ending_date=ending_date)
if not ending_date:
ending_date = end_of_month(starting_date)
# create new bill, if previous is closed/does not exist
if not bill:
bill = cls.objects.create(
owner=owner,
starting_date=starting_date,
ending_date=ending_date)
for order in all_orders:
# check if order needs to be billed
# check if order has previous billing record
if order.is_one_time:
if order.billrecord_set.count() == 0:
br = BillRecord.objects.create(bill=bill,
@ -447,6 +452,10 @@ class Bill(models.Model):
starting_date=starting_date,
ending_date=ending_date)
# Filtering ideas:
# If order is replaced, it should not be added anymore if it has been billed "last time"
# If order has ended and finally charged, do not charge anymore
return bill
@classmethod
@ -546,7 +555,7 @@ class BillRecord(models.Model):
@property
def sum(self):
return self.order.price * self.quantity
return self.order.price * Decimal(self.quantity)
def __str__(self):
return f"{self.bill}: {self.quantity} x {self.order}"
@ -575,34 +584,54 @@ class Product(UncloudModel):
# Default period for all products
default_recurring_period = RecurringPeriod.PER_30D
def create_order_at(self, when_to_start, *args, **kwargs):
def create_order_at(self, when_to_start=None, recurring_period=None):
billing_address = BillingAddress.get_address_for(self.owner)
order = Order.objects.create(owner=self.owner,
billing_address=billing_address,
starting_date=when_to_start,
one_time_price=self.one_time_price,
recurring_period=self.default_recurring_period,
recurring_price=self.recurring_price,
description=str(self))
if not billing_address:
raise ValidationError("Cannot order without a billing address")
def create_or_update_order(self, when_to_start=None):
if not when_to_start:
when_to_start = timezone.now()
if not recurring_period:
recurring_period = self.default_recurring_period
one_time_order = None
if self.one_time_price > 0:
one_time_order = Order.objects.create(owner=self.owner,
billing_address=billing_address,
starting_date=when_to_start,
price=self.one_time_price,
recurring_period=RecurringPeriod.ONE_TIME,
description=str(self))
if recurring_period != RecurringPeriod.ONE_TIME:
if one_time_order:
recurring_order = Order.objects.create(owner=self.owner,
billing_address=billing_address,
starting_date=when_to_start,
price=self.recurring_price,
recurring_period=recurring_period,
depends_on=one_time_order,
description=str(self))
else:
recurring_order = Order.objects.create(owner=self.owner,
billing_address=billing_address,
starting_date=when_to_start,
price=self.recurring_price,
recurring_period=recurring_period,
description=str(self))
def create_or_update_order(self, when_to_start=None, recurring_period=None):
if not when_to_start:
when_to_start = timezone.now()
if not self.order:
billing_address = BillingAddress.get_address_for(self.owner)
if not billing_address:
raise ValidationError("Cannot order without a billing address")
self.order = Order.objects.create(owner=self.owner,
billing_address=billing_address,
starting_date=when_to_start,
one_time_price=self.one_time_price,
recurring_period=self.default_recurring_period,
recurring_price=self.recurring_price,
description=str(self))
self.create_order_at(when_to_start, recurring_period)
else:
previous_order = self.order
@ -611,9 +640,8 @@ class Product(UncloudModel):
new_order = Order.objects.create(owner=self.owner,
billing_address=self.order.billing_address,
starting_date=when_to_start,
one_time_price=self.one_time_price,
recurring_period=self.default_recurring_period,
recurring_price=self.recurring_price,
price=self.recurring_price,
recurring_period=recurring_period,
description=str(self),
replaces=self.order)
@ -641,6 +669,14 @@ class Product(UncloudModel):
"""
return 0
@property
def is_recurring(self):
return self.recurring_price > 0
# on is_one_time as this should be has_one_time which is the same as > 0 again...
@property
def billing_address(self):
return self.order.billing_address