forked from uncloud/uncloud
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
|
@ -86,4 +86,5 @@ urlpatterns = [
|
|||
description="uncloud API",
|
||||
version="1.0.0"
|
||||
), name='openapi-schema'),
|
||||
path('admin/', admin.site.urls),
|
||||
]
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
from uncloud_pay.models import Bill, Order, BillRecord, BillingAddress
|
||||
|
||||
class BillAdmin(admin.ModelAdmin):
|
||||
pass
|
||||
|
||||
admin.site.register(Bill, BillAdmin)
|
||||
|
||||
admin.site.register(Order)
|
||||
admin.site.register(BillRecord)
|
||||
admin.site.register(BillingAddress)
|
||||
|
|
55
uncloud_pay/migrations/0017_auto_20200621_1110.py
Normal file
55
uncloud_pay/migrations/0017_auto_20200621_1110.py
Normal file
|
@ -0,0 +1,55 @@
|
|||
# Generated by Django 3.0.6 on 2020-06-21 11:10
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('uncloud_pay', '0016_auto_20200523_2138'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='BillRecord',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('usage_count', models.IntegerField(default=1)),
|
||||
('creation_date', models.DateTimeField(auto_now_add=True)),
|
||||
('starting_date', models.DateTimeField()),
|
||||
('ending_date', models.DateTimeField()),
|
||||
('bill', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='uncloud_pay.Bill')),
|
||||
],
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='ordertimothee',
|
||||
name='bill',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='ordertimothee',
|
||||
name='billing_address',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='ordertimothee',
|
||||
name='owner',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='order',
|
||||
name='bill',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='order',
|
||||
name='one_time_price',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='order',
|
||||
name='recurring_price',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='BillNico',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='OrderTimothee',
|
||||
),
|
||||
]
|
25
uncloud_pay/migrations/0018_auto_20200621_1140.py
Normal file
25
uncloud_pay/migrations/0018_auto_20200621_1140.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
# Generated by Django 3.0.6 on 2020-06-21 11:40
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('uncloud_pay', '0017_auto_20200621_1110'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='bill',
|
||||
name='bill_records',
|
||||
field=models.ManyToManyField(through='uncloud_pay.BillRecord', to='uncloud_pay.Order'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='billrecord',
|
||||
name='order',
|
||||
field=models.ForeignKey(default=0, on_delete=django.db.models.deletion.CASCADE, to='uncloud_pay.Order'),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
23
uncloud_pay/migrations/0019_auto_20200621_1144.py
Normal file
23
uncloud_pay/migrations/0019_auto_20200621_1144.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 3.0.6 on 2020-06-21 11:44
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('uncloud_pay', '0018_auto_20200621_1140'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='bill',
|
||||
name='uuid',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='bill',
|
||||
name='id',
|
||||
field=models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
|
@ -223,11 +223,14 @@ class BillingAddress(models.Model):
|
|||
return addresses[0]
|
||||
|
||||
def __str__(self):
|
||||
return "{}, {}, {} {}, {}".format(
|
||||
return "{} - {}, {}, {} {}, {}".format(
|
||||
self.owner,
|
||||
self.name, self.street, self.postal_code, self.city,
|
||||
self.country)
|
||||
|
||||
# Populated with the import-vat-numbers django command.
|
||||
###
|
||||
# VAT
|
||||
|
||||
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…
Reference in a new issue