cleanup commit, introduction of onetimeprice

This commit is contained in:
Nico Schottelius 2022-01-30 10:11:22 +01:00
parent 686d2c2b1e
commit f08269640d
15 changed files with 141 additions and 240 deletions

View File

@ -57,11 +57,8 @@ machine. Use `kubectl get nodes` to verify minikube is up and running.
in ResourceOrders1 in ResourceOrders1
* Need to pass in the price for the selected timeframe [done] * Need to pass in the price for the selected timeframe [done]
* On submit * On submit
* List of * Create ProductOrder
* resources + values * Create ResourceOrder(s)
* Product
* Timeframe
* Confirm & create
#### 3.0.0 (2022-01-14) #### 3.0.0 (2022-01-14)

View File

@ -6,6 +6,7 @@ from .models import *
for m in [ for m in [
Currency, Currency,
Order, Order,
OneTimePrice,
PricePerTime, PricePerTime,
Product, Product,
ProductOrder, ProductOrder,

View File

@ -1,8 +1,8 @@
from django import forms from django import forms
class ProductOrderForm(forms.Form): class ProductOrderForm(forms.Form):
product = forms.SlugField(required=True) product = forms.SlugField(required=True, disabled=True)
timeframe = forms.SlugField(required=True) timeframe = forms.SlugField(required=True, disabled=True)
def __init__(self, resources, *args, **kwargs): def __init__(self, resources, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)

View File

@ -0,0 +1,75 @@
from django.core.management.base import BaseCommand
from app.models import *
class Command(BaseCommand):
help = 'Add test data'
# def add_arguments(self, parser):
#parser.add_argument('--username', type=str, required=True)
def handle(self, *args, **options):
currency, created = Currency.objects.get_or_create(defaults=
{
"slug": "CHF",
"name": "Swiss Franc",
"short_name": "CHF"
})
for timeframe in [ (3600, "1 hour", "1-hour"),
(86400, "1 day", "1-day"),
(7*86400, "7 days", "7-days"),
(30*86400, "30 days", "30-days"),
(365*86400, "365 days", "365 days") ]:
TimeFrame.objects.get_or_create(slug=timeframe[2],
defaults=
{
"name": timeframe[1],
"seconds": timeframe[0]
})
for ppt in [
("1-day", 1, currency),
("1-day", 2, currency),
("30-days", 10, currency), # Nextcloud
("30-days", 15, currency), # Gitea
("30-days", 35, currency), # Matrix
("30-days", 29, currency),
("30-days", 55, currency) ]:
tf = TimeFrame.objects.get(slug=ppt[0])
PricePerTime.objects.get_or_create(timeframe=tf,
value=ppt[1],
defaults=
{
"currency": currency
})
for res in [
("cpu-1", "CPU", "Core(s)", None, None),
("cpu-min-max", "CPU", "Core(s)", 1, 20),
("ram-1", "RAM", "GB", None, None),
("ram-min-max", "RAM", "GB", 1, 200),
("matrix-maintenance", "Matrix Maintenance Fee", "", 1, 1),
("nextcloud-maintenance", "Nextcloud Maintenance Fee", "", 1, 1),
("gitea-maintenance", "Gitea Maintenance Fee", "", 1, 1),
]:
Resource.objects.get_or_create(slug=res[0],
defaults=
{
"name": res[1],
"unit": res[2],
"minimum_units": res[3],
"maximum_units": res[4]
})
# Link to PPT -- later
# for ppt_res in res[5]:
# ppt = PricePerTime.objects.get(
for product in [
("matrix", "Matrix"),
("nextcloud", "Nextcloud"),
("gitea", "Gitea") ]:
Product.objects.get_or_create(slug=product[0],
defaults = { "name": product[1] })

View File

@ -1,4 +1,4 @@
# Generated by Django 4.0 on 2022-01-02 19:50 # Generated by Django 4.0 on 2022-01-16 16:44
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
@ -18,6 +18,7 @@ class Migration(migrations.Migration):
name='Currency', name='Currency',
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('slug', models.SlugField(null=True, unique=True)),
('name', models.CharField(max_length=128, unique=True)), ('name', models.CharField(max_length=128, unique=True)),
('short_name', models.CharField(max_length=3, unique=True)), ('short_name', models.CharField(max_length=3, unique=True)),
], ],
@ -26,7 +27,7 @@ class Migration(migrations.Migration):
name='PricePerTime', name='PricePerTime',
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('price', models.FloatField()), ('value', models.FloatField()),
('currency', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app.currency')), ('currency', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app.currency')),
], ],
), ),
@ -34,6 +35,7 @@ class Migration(migrations.Migration):
name='Product', name='Product',
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('slug', models.SlugField(null=True, unique=True)),
('name', models.CharField(max_length=128, unique=True)), ('name', models.CharField(max_length=128, unique=True)),
], ],
), ),
@ -41,8 +43,9 @@ class Migration(migrations.Migration):
name='Resource', name='Resource',
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=128, unique=True)), ('slug', models.SlugField(null=True, unique=True)),
('unit', models.CharField(max_length=128, unique=True)), ('name', models.CharField(max_length=128)),
('unit', models.CharField(max_length=128)),
('minimum_units', models.FloatField(blank=True, null=True)), ('minimum_units', models.FloatField(blank=True, null=True)),
('maximum_units', models.FloatField(blank=True, null=True)), ('maximum_units', models.FloatField(blank=True, null=True)),
('step_size', models.FloatField(default=1)), ('step_size', models.FloatField(default=1)),
@ -53,6 +56,7 @@ class Migration(migrations.Migration):
name='TimeFrame', name='TimeFrame',
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('slug', models.SlugField(null=True, unique=True)),
('name', models.CharField(max_length=128, unique=True)), ('name', models.CharField(max_length=128, unique=True)),
('seconds', models.IntegerField(blank=True, null=True)), ('seconds', models.IntegerField(blank=True, null=True)),
], ],
@ -63,7 +67,6 @@ class Migration(migrations.Migration):
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('value', models.FloatField()), ('value', models.FloatField()),
('resource', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app.resource')), ('resource', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app.resource')),
('timeframe', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app.timeframe')),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(
@ -72,12 +75,18 @@ class Migration(migrations.Migration):
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app.product')), ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app.product')),
('resources', models.ManyToManyField(to='app.ResourceOrder')), ('resources', models.ManyToManyField(to='app.ResourceOrder')),
('timeframe', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app.timeframe')),
], ],
), ),
migrations.AddField( migrations.AddField(
model_name='product', model_name='product',
name='resources', name='resources',
field=models.ManyToManyField(to='app.Resource'), field=models.ManyToManyField(blank=True, to='app.Resource'),
),
migrations.AddField(
model_name='product',
name='timeframes',
field=models.ManyToManyField(blank=True, to='app.TimeFrame'),
), ),
migrations.AddField( migrations.AddField(
model_name='pricepertime', model_name='pricepertime',
@ -95,4 +104,12 @@ class Migration(migrations.Migration):
('product', models.ManyToManyField(blank=True, to='app.ProductOrder')), ('product', models.ManyToManyField(blank=True, to='app.ProductOrder')),
], ],
), ),
migrations.CreateModel(
name='OneTimePrice',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('value', models.FloatField()),
('currency', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='app.currency')),
],
),
] ]

View File

@ -1,28 +0,0 @@
# Generated by Django 4.0 on 2022-01-02 19:53
from django.db import migrations
def gen_timeframes(apps, schema_editor):
# We can't import the Person model directly as it may be a newer
# version than this migration expects. We use the historical version.
TimeFrame = apps.get_model('app', 'TimeFrame')
for timeframe in [ (3600, "1 hour"),
(86400, "1 day"),
(7*86400, "7 days"),
(30*86400, "30 days"),
(365*86400, "365 days") ]:
tf = TimeFrame(name=timeframe[1],
seconds=timeframe[0])
tf.save()
class Migration(migrations.Migration):
dependencies = [
('app', '0001_initial'),
]
operations = [
migrations.RunPython(gen_timeframes),
]

View File

@ -1,23 +0,0 @@
# Generated by Django 4.0 on 2022-01-02 20:04
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0002_auto_20220102_1953'),
]
operations = [
migrations.AlterField(
model_name='product',
name='resources',
field=models.ManyToManyField(blank=True, to='app.Resource'),
),
migrations.AlterField(
model_name='resource',
name='unit',
field=models.CharField(max_length=128),
),
]

View File

@ -1,19 +0,0 @@
# Generated by Django 4.0 on 2022-01-02 20:20
from django.db import migrations
def gen_currencies(apps, schema_editor):
Currency = apps.get_model('app', 'Currency')
Currency.objects.get_or_create(name="Swiss Franc",
short_name="CHF")
class Migration(migrations.Migration):
dependencies = [
('app', '0003_alter_product_resources_alter_resource_unit'),
]
operations = [
migrations.RunPython(gen_currencies),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.0 on 2022-01-14 22:20
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0004_auto_20220102_2020'),
]
operations = [
migrations.AddField(
model_name='product',
name='slug',
field=models.SlugField(null=True),
),
]

View File

@ -1,28 +0,0 @@
# Generated by Django 4.0 on 2022-01-14 23:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0005_product_slug'),
]
operations = [
migrations.AddField(
model_name='resource',
name='slug',
field=models.SlugField(null=True, unique=True),
),
migrations.AlterField(
model_name='product',
name='slug',
field=models.SlugField(null=True, unique=True),
),
migrations.AlterField(
model_name='resource',
name='name',
field=models.CharField(max_length=128),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.0 on 2022-01-14 23:27
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0006_resource_slug_alter_product_slug_alter_resource_name'),
]
operations = [
migrations.AddField(
model_name='timeframe',
name='slug',
field=models.SlugField(null=True, unique=True),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.0 on 2022-01-14 23:28
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0007_timeframe_slug'),
]
operations = [
migrations.AddField(
model_name='currency',
name='slug',
field=models.SlugField(null=True, unique=True),
),
]

View File

@ -1,18 +0,0 @@
# Generated by Django 4.0 on 2022-01-14 23:38
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('app', '0008_currency_slug'),
]
operations = [
migrations.AddField(
model_name='product',
name='timeframes',
field=models.ManyToManyField(blank=True, to='app.TimeFrame'),
),
]

View File

@ -12,7 +12,6 @@ class Currency(models.Model):
def __str__(self): def __str__(self):
return f"{self.name} ({self.short_name})" return f"{self.name} ({self.short_name})"
class TimeFrame(models.Model): class TimeFrame(models.Model):
slug = models.SlugField(null=True, unique=True) slug = models.SlugField(null=True, unique=True)
name = models.CharField(max_length=128, unique=True) name = models.CharField(max_length=128, unique=True)
@ -38,13 +37,20 @@ class TimeFrame(models.Model):
#return "{} ({})".format(self.name, self.secs_to_name(self.seconds)) #return "{} ({})".format(self.name, self.secs_to_name(self.seconds))
return f"{self.name}" return f"{self.name}"
class PricePerTime(models.Model): class OneTimePrice(models.Model):
timeframe = models.ForeignKey(TimeFrame, on_delete=models.CASCADE) value = models.FloatField()
price = models.FloatField()
currency = models.ForeignKey(Currency, on_delete=models.CASCADE) currency = models.ForeignKey(Currency, on_delete=models.CASCADE)
def __str__(self): def __str__(self):
return f"{self.price} {self.currency.short_name}/{self.timeframe}" return f"{self.value} {self.currency.short_name}"
class PricePerTime(models.Model):
timeframe = models.ForeignKey(TimeFrame, on_delete=models.CASCADE)
value = models.FloatField()
currency = models.ForeignKey(Currency, on_delete=models.CASCADE)
def __str__(self):
return f"{self.value}{self.currency.short_name}/{self.timeframe}"
class Resource(models.Model): class Resource(models.Model):
slug = models.SlugField(null=True, unique=True) # primary identifier slug = models.SlugField(null=True, unique=True) # primary identifier
@ -52,7 +58,7 @@ class Resource(models.Model):
unit = models.CharField(max_length=128) # Count, GB unit = models.CharField(max_length=128) # Count, GB
minimum_units = models.FloatField(null=True, blank=True) # might have min minimum_units = models.FloatField(null=True, blank=True) # might have min
maximum_units = models.FloatField(null=True, blank=True) # might have max maximum_units = models.FloatField(null=True, blank=True) # might have max
step_size = models.FloatField(default=1) # might/must step size step_size = models.FloatField(default=1) # step size
price_per_time = models.ManyToManyField(PricePerTime, blank=True) price_per_time = models.ManyToManyField(PricePerTime, blank=True)
@ -66,11 +72,7 @@ class Resource(models.Model):
else: else:
maximum = "No maximum" maximum = "No maximum"
pricing = [] pricing = ", ".join([str(x) for x in self.price_per_time.all()])
for price in self.price_per_time.all():
pricing.append(f"{price.price}{price.currency.short_name}/{price.timeframe}")
pricing = ", ".join(pricing)
return f"{self.slug}: {minimum}-{maximum} (+/-){self.step_size} {self.unit} ({pricing})" return f"{self.slug}: {minimum}-{maximum} (+/-){self.step_size} {self.unit} ({pricing})"
@ -113,14 +115,11 @@ class Product(models.Model):
class ResourceOrder(models.Model): class ResourceOrder(models.Model):
""" """
Resources that have been ordered Resources that have been ordered
The timeframe should be in the ProductOrder, as it needs to be consistent
for all ordered resources
We need to record the selected value *and* potentially the We need to record the selected value *and* potentially the
calculated price calculated price
""" """
timeframe = models.ForeignKey(TimeFrame, on_delete=models.CASCADE)
value = models.FloatField() value = models.FloatField()
resource = models.ForeignKey(Resource, on_delete=models.CASCADE) resource = models.ForeignKey(Resource, on_delete=models.CASCADE)
@ -130,8 +129,13 @@ class ProductOrder(models.Model):
Describes a product a user bought Describes a product a user bought
""" """
product = models.ForeignKey(Product, on_delete=models.CASCADE) product = models.ForeignKey(Product, on_delete=models.CASCADE)
timeframe = models.ForeignKey(TimeFrame, on_delete=models.CASCADE)
resources = models.ManyToManyField(ResourceOrder) resources = models.ManyToManyField(ResourceOrder)
def __str__(self):
return f"Order of {self.product} / {self.timeframe}"
class Order(models.Model): class Order(models.Model):
owner = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, editable=False) owner = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, editable=False)

View File

@ -6,68 +6,45 @@ from django.views.generic.base import TemplateView
from django.views.generic.list import ListView from django.views.generic.list import ListView
from django.views.generic.detail import DetailView from django.views.generic.detail import DetailView
from django.http import HttpResponse
from .models import * from .models import *
from .forms import * from .forms import *
#class ProductOrderView(CreateView):
class ProductOrderView(FormView): class ProductOrderView(FormView):
form_class = ProductOrderForm form_class = ProductOrderForm
template_name = 'app/productorder_form.html' template_name = 'app/productorder_form.html'
success_url = '/' success_url = '/order/matrix/30-days/'
def get_form_kwargs(self): def get_form_kwargs(self):
kwargs = super().get_form_kwargs() kwargs = super().get_form_kwargs()
# print(self)
# print(self.request) # Set the product so the form can retrieve the resources
print(self.kwargs)
#context = self.get_context_data(**kwargs)
#kwargs['resources'] = self.request['object'].resources.all()
product = get_object_or_404(Product, slug=self.kwargs['product']) product = get_object_or_404(Product, slug=self.kwargs['product'])
kwargs['resources'] = product.resources.all() kwargs['resources'] = product.resources.all()
return kwargs return kwargs
def get_initial(self):
initial = super().get_initial()
initial['product'] = self.kwargs['product']
initial['timeframe'] = self.kwargs['timeframe']
return initial
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['product'] = get_object_or_404(Product, slug=self.kwargs['product']) context['product'] = get_object_or_404(Product, slug=self.kwargs['product'])
context['timeframe'] = get_object_or_404(TimeFrame, slug=self.kwargs['timeframe']) context['timeframe'] = get_object_or_404(TimeFrame, slug=self.kwargs['timeframe'])
# context['form'] = ProductOrderForm(
# context['product'].resources.all(),
# initial={'product': context['product'].slug,
# 'timeframe': context['timeframe'].slug}
# )
return context return context
# v2 def form_valid(self, form):
# def post(self, request, *args, **kwargs): print("We got a valid form, let's create the order")
# context = self.get_context_data() for f in form.fields:
# if context["form"].is_valid(): print(f)
# print("form good") print(form.cleaned_data)
# else: product = get_object_or_404(Product, slug=form.cleaned_data['product'])
# print("form not good") tf = get_object_or_404(TimeFrame, slug=form.cleaned_data['timeframe'])
# print(context["form"].errors) po = ProductOrder(product=product, timeframe=tf)
# return HttpResponse("All good") print(po)
return super().form_valid(form)
# v1
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['product'] = get_object_or_404(Product, slug=self.kwargs['product'])
# context['timeframe'] = get_object_or_404(TimeFrame, slug=self.kwargs['timeframe'])
# res_price = []
# for res in context['product'].resources.all():
# price = res.price_per_time.filter(timeframe=context['timeframe'])[0].price
# currency = res.price_per_time.filter(timeframe=context['timeframe'])[0].currency
# res_price.append((res, price, currency))
# context['res_price'] = res_price
# print(context)
# print(self.kwargs)
# return context
class ProductDetailView(DetailView): class ProductDetailView(DetailView):