forked from uncloud/uncloud
Revamp generate-bills logic to avoid overlapping
This commit is contained in:
parent
37ed126bc1
commit
adb57c55ca
1 changed files with 44 additions and 25 deletions
|
@ -1,48 +1,67 @@
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
from uncloud_auth.models import User
|
from uncloud_auth.models import User
|
||||||
from uncloud_pay.models import Order, Bill
|
from uncloud_pay.models import Order, Bill
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
|
BILL_PAYMENT_DELAY=timedelta(days=10)
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = 'Generate bills and charge customers if necessary.'
|
help = 'Generate bills and charge customers if necessary.'
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# TODO: check for existing bills
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
customers = User.objects.all()
|
users = User.objects.all()
|
||||||
print("Processing {} users.".format(customers.count()))
|
print("Processing {} users.".format(users.count()))
|
||||||
for customer in customers:
|
|
||||||
orders = Order.objects.filter(owner=customer)
|
|
||||||
|
|
||||||
# Pay all non-billed usage untill now.
|
for user in users:
|
||||||
bill_starting_date = timezone.now()
|
# Fetch all the orders of a customer.
|
||||||
bill_ending_date = timezone.now()
|
orders = Order.objects.filter(owner=user)
|
||||||
|
|
||||||
billed_orders = []
|
# Default values for next bill (if any). Only saved at the end of
|
||||||
|
# this method, if relevant.
|
||||||
|
next_bill = Bill(owner=user,
|
||||||
|
starting_date=timezone.now(), # Will be set to oldest unpaid order (means unpaid starting date).
|
||||||
|
ending_date=timezone.now(), # Bill covers everything until today.
|
||||||
|
due_date=timezone.now() + BILL_PAYMENT_DELAY)
|
||||||
|
|
||||||
|
unpaid_orders = [] # Store orders in need of a payment.
|
||||||
for order in orders:
|
for order in orders:
|
||||||
print(order)
|
# Only bill if there is an 'unpaid period' on an active order.
|
||||||
if True: # FIXME
|
# XXX: Assume everything before latest bill is paid. => might be dangerous.
|
||||||
billed_orders.append(order)
|
try:
|
||||||
|
previous_bill = order.bill.latest('ending_date')
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
previous_bill = None
|
||||||
|
|
||||||
# Update starting date if need be.
|
is_unpaid_period = True
|
||||||
if order.starting_date < bill_starting_date:
|
if order.ending_date and previous_bill != None:
|
||||||
bill_starting_date = order.starting_date
|
is_unpaid_period = previous_bill.ending_date < order.ending_date
|
||||||
|
|
||||||
if len(billed_orders) > 0:
|
if is_unpaid_period:
|
||||||
bill = Bill(owner=customer,
|
# Update bill starting date to match period.
|
||||||
starting_date=bill_starting_date,
|
if previous_bill == None:
|
||||||
ending_date=bill_starting_date,
|
next_bill.starting_date = order.starting_date
|
||||||
due_date=timezone.now() + timedelta(days=10))
|
elif previous_bill.ending_date < next_bill.starting_date:
|
||||||
bill.save()
|
next_bill.starting_date = previous_bill.ending_date
|
||||||
|
|
||||||
for order in billed_orders:
|
# Add order to bill
|
||||||
print(order)
|
unpaid_orders.append(order)
|
||||||
order.bill.add(bill)
|
|
||||||
|
|
||||||
print("Created bill {} for user {}".format(bill.uuid, customer.username))
|
# Save next_bill if it contains any unpaid product.
|
||||||
|
if len(unpaid_orders) > 0:
|
||||||
|
next_bill.save()
|
||||||
|
|
||||||
|
# It is not possible to register many-to-many relationship before
|
||||||
|
# the two end-objects are saved in database.
|
||||||
|
for order in unpaid_orders:
|
||||||
|
order.bill.add(next_bill)
|
||||||
|
|
||||||
|
print("Created bill {} for user {}".format(next_bill.uuid, user.username))
|
||||||
|
|
||||||
|
# We're done for this round :-)
|
||||||
print("=> Done.")
|
print("=> Done.")
|
||||||
|
|
Loading…
Reference in a new issue