Include BillRecords in the admin

This commit is contained in:
Nico Schottelius 2020-06-21 16:08:00 +02:00
parent 721472b416
commit 8a17ee6de5
4 changed files with 128 additions and 21 deletions

View file

@ -2,11 +2,13 @@ from django.contrib import admin
from uncloud_pay.models import Bill, Order, BillRecord, BillingAddress from uncloud_pay.models import Bill, Order, BillRecord, BillingAddress
class BillRecordInline(admin.TabularInline):
model = Bill.bill_records.through
class BillAdmin(admin.ModelAdmin): class BillAdmin(admin.ModelAdmin):
pass inlines = [ BillRecordInline ]
;
admin.site.register(Bill, BillAdmin) admin.site.register(Bill, BillAdmin)
admin.site.register(Order) admin.site.register(Order)
admin.site.register(BillRecord) admin.site.register(BillRecord)
admin.site.register(BillingAddress) admin.site.register(BillingAddress)

View file

@ -0,0 +1,40 @@
from django.core.management.base import BaseCommand
from django.contrib.auth import get_user_model
import datetime
from uncloud_pay.models import *
class Command(BaseCommand):
help = 'Bootstrap user (for testing)'
def add_arguments(self, parser):
parser.add_argument('username', type=str)
def handle(self, *args, **options):
user = get_user_model().objects.get(username=options['username'])
addr = BillingAddress.objects.get_or_create(
owner=user,
active=True,
defaults={'organization': 'ungleich',
'name': 'Nico Schottelius',
'street': 'Hauptstrasse 14',
'city': 'Luchsingen',
'postal_code': '8775',
'country': 'CH' }
)
bills = Bill.objects.filter(owner=user)
# not even one bill? create!
if bills:
bill = bills[0]
else:
bill = Bill.objects.create(owner=user)
# find any order that is associated to this bill
orders = Order.objects.filter(owner=user)
)
print(f"Addr: {addr}")
print(f"Bill: {bill}")

View file

@ -0,0 +1,33 @@
# Generated by Django 3.0.6 on 2020-06-21 13:35
from django.db import migrations, models
import uncloud_pay.models
class Migration(migrations.Migration):
dependencies = [
('uncloud_pay', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='bill',
name='due_date',
field=models.DateField(default=uncloud_pay.models.default_payment_delay),
),
migrations.AlterField(
model_name='bill',
name='ending_date',
field=models.DateTimeField(default=uncloud_pay.models.end_of_this_month),
),
migrations.AlterField(
model_name='bill',
name='starting_date',
field=models.DateTimeField(default=uncloud_pay.models.start_of_this_month),
),
migrations.AddConstraint(
model_name='bill',
constraint=models.UniqueConstraint(fields=('owner', 'starting_date', 'ending_date'), name='one_bill_per_month_per_user'),
),
]

View file

@ -10,7 +10,7 @@ import logging
from functools import reduce from functools import reduce
import itertools import itertools
from math import ceil from math import ceil
from datetime import timedelta import datetime
from calendar import monthrange from calendar import monthrange
from decimal import Decimal from decimal import Decimal
@ -23,11 +23,36 @@ from decimal import Decimal
import decimal import decimal
# Used to generate bill due dates. # Used to generate bill due dates.
BILL_PAYMENT_DELAY=timedelta(days=10) BILL_PAYMENT_DELAY=datetime.timedelta(days=10)
# Initialize logger. # Initialize logger.
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def start_of_month(a_day):
""" Returns first of the month of a given datetime object"""
return a_day.replace(day=1,hour=0,minute=0,second=0, microsecond=0)
def end_of_month(a_day):
""" Returns first of the month of a given datetime object"""
_, last_day = monthrange(a_day.year, a_day.month)
return a_day.replace(day=last_day,hour=23,minute=59,second=59, microsecond=0)
def start_of_this_month():
""" Returns first of this month"""
a_day = timezone.now()
return a_day.replace(day=1,hour=0,minute=0,second=0, microsecond=0)
def end_of_this_month():
""" Returns first of this month"""
a_day = timezone.now()
_, last_day = monthrange(a_day.year, a_day.month)
return a_day.replace(day=last_day,hour=23,minute=59,second=59, microsecond=0)
def default_payment_delay():
return timezone.now() + BILL_PAYMENT_DELAY
# See https://docs.djangoproject.com/en/dev/ref/models/fields/#field-choices-enum-types # See https://docs.djangoproject.com/en/dev/ref/models/fields/#field-choices-enum-types
class RecurringPeriod(models.IntegerChoices): class RecurringPeriod(models.IntegerChoices):
""" """
@ -390,34 +415,41 @@ class Order(models.Model):
description=description) description=description)
def __str__(self): def __str__(self):
return "{} created at {}, {}->{}, recurring period {}. One time price {}, recurring price {}".format( return f"Order {self.owner}-{self.id}"
self.id, self.creation_date,
self.starting_date, self.ending_date, # return "{} created at {}, {}->{}, recurring period {}. One time price {}, recurring price {}".format(
self.recurring_period, # self.id, self.creation_date,
self.one_time_price, # self.starting_date, self.ending_date,
self.recurring_price) # self.recurring_period,
# self.one_time_price,
# self.recurring_price)
class Bill(models.Model): class Bill(models.Model):
""" FIXME:
Bill needs to be unique in the triple (owner, year, month)
"""
owner = models.ForeignKey(get_user_model(), owner = models.ForeignKey(get_user_model(),
on_delete=models.CASCADE) on_delete=models.CASCADE)
creation_date = models.DateTimeField(auto_now_add=True) creation_date = models.DateTimeField(auto_now_add=True)
starting_date = models.DateTimeField() # FIXME: this is a race condition, if ending_date is evaluated
ending_date = models.DateTimeField() # in the next month the bill spawns two months!
due_date = models.DateField() starting_date = models.DateTimeField(default=start_of_this_month)
ending_date = models.DateTimeField(default=end_of_this_month)
due_date = models.DateField(default=default_payment_delay)
valid = models.BooleanField(default=True) valid = models.BooleanField(default=True)
# Mapping to BillRecords # Mapping to BillRecords
# https://stackoverflow.com/questions/4443190/djangos-manytomany-relationship-with-additional-fields # https://stackoverflow.com/questions/4443190/djangos-manytomany-relationship-with-additional-fields
bill_records = models.ManyToManyField(Order, through="BillRecord") bill_records = models.ManyToManyField(Order, through="BillRecord")
class Meta:
constraints = [
models.UniqueConstraint(fields=['owner',
'starting_date',
'ending_date' ],
name='one_bill_per_month_per_user')
]
# billing address and vat rate is the same for the whole bill # billing address and vat rate is the same for the whole bill
# @property # @property
# def vat_rate(self): # def vat_rate(self):
@ -425,7 +457,7 @@ class Bill(models.Model):
def __str__(self): def __str__(self):
return f"uc-{self.id}" return f"Bill {self.owner}-{self.id}"
@classmethod @classmethod
def create_all_bills(cls): def create_all_bills(cls):
@ -516,7 +548,7 @@ class BillRecord(models.Model):
ending_date = models.DateTimeField() ending_date = models.DateTimeField()
def __str__(self): def __str__(self):
return f"{order.owner}" return f"{self.bill}: {self.usage_count} x {self.order}"
class OrderRecord(models.Model): class OrderRecord(models.Model):