forked from uncloud/uncloud
in between commit: html bug
- "range" is great in theory, but does not show actual nummber - "number" does not allow float Need to go back to text
This commit is contained in:
parent
8952ef0b3a
commit
1e69722f4b
9 changed files with 120 additions and 9 deletions
|
@ -26,6 +26,11 @@ machine. Use `kubectl get nodes` to verify minikube is up and running.
|
||||||
complete ones
|
complete ones
|
||||||
* resources are also timeframe bound
|
* resources are also timeframe bound
|
||||||
* name != unique (?)
|
* name != unique (?)
|
||||||
|
* how do we link?
|
||||||
|
* stays towards resource
|
||||||
|
* we only show resources which have price_per_time with one of
|
||||||
|
our timeframes
|
||||||
|
* And we filter out timeframes that don't have all resources
|
||||||
* Can we filter drop down in admin?
|
* Can we filter drop down in admin?
|
||||||
* yes: ModelAdmin.formfield_for_manytomany(db_field, request, **kwargs)¶
|
* yes: ModelAdmin.formfield_for_manytomany(db_field, request, **kwargs)¶
|
||||||
* resources should have a slug
|
* resources should have a slug
|
||||||
|
@ -40,7 +45,16 @@ machine. Use `kubectl get nodes` to verify minikube is up and running.
|
||||||
|
|
||||||
* Show products [done]
|
* Show products [done]
|
||||||
* Link to ProductOrderForm [done]
|
* Link to ProductOrderForm [done]
|
||||||
|
* Find suitable timeframes for a product [done]
|
||||||
* Continue to resources / add resources
|
* Continue to resources / add resources
|
||||||
|
* Need to list resources
|
||||||
|
* Need to create manytomany relations for each resource resolutling
|
||||||
|
in ResourceOrders
|
||||||
|
* On submit
|
||||||
|
* List of
|
||||||
|
* resources + values
|
||||||
|
* Product
|
||||||
|
* Timeframe
|
||||||
* Confirm & create
|
* Confirm & create
|
||||||
|
|
||||||
#### 3.0.0 (2022-01-14)
|
#### 3.0.0 (2022-01-14)
|
||||||
|
|
18
uncloud_v3/app/migrations/0007_timeframe_slug.py
Normal file
18
uncloud_v3/app/migrations/0007_timeframe_slug.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# 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),
|
||||||
|
),
|
||||||
|
]
|
18
uncloud_v3/app/migrations/0008_currency_slug.py
Normal file
18
uncloud_v3/app/migrations/0008_currency_slug.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# 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),
|
||||||
|
),
|
||||||
|
]
|
18
uncloud_v3/app/migrations/0009_product_timeframes.py
Normal file
18
uncloud_v3/app/migrations/0009_product_timeframes.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# 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'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -2,9 +2,10 @@ from django.db import models
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
class Currency(models.Model):
|
class Currency(models.Model):
|
||||||
|
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)
|
||||||
|
|
||||||
|
@ -13,6 +14,7 @@ class Currency(models.Model):
|
||||||
|
|
||||||
|
|
||||||
class TimeFrame(models.Model):
|
class TimeFrame(models.Model):
|
||||||
|
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(null=True, blank=True)
|
seconds = models.IntegerField(null=True, blank=True)
|
||||||
|
|
||||||
|
@ -70,7 +72,7 @@ class Resource(models.Model):
|
||||||
|
|
||||||
pricing = ", ".join(pricing)
|
pricing = ", ".join(pricing)
|
||||||
|
|
||||||
return f"{self.name}: {minimum}-{maximum} (+/-){self.step_size} {self.unit} ({pricing})"
|
return f"{self.slug}: {minimum}-{maximum} (+/-){self.step_size} {self.unit} ({pricing})"
|
||||||
|
|
||||||
class ResourceOrder(models.Model):
|
class ResourceOrder(models.Model):
|
||||||
"""
|
"""
|
||||||
|
@ -86,13 +88,29 @@ class Product(models.Model):
|
||||||
Describes a product a user can buy
|
Describes a product a user can buy
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = models.CharField(max_length=128, unique=True)
|
|
||||||
slug = models.SlugField(null=True, unique=True)
|
slug = models.SlugField(null=True, unique=True)
|
||||||
|
name = models.CharField(max_length=128, unique=True)
|
||||||
|
|
||||||
# textconfig = models.ManyToManyField(ProductTextConfiguration)
|
resources = models.ManyToManyField(Resource, blank=True) # List of REQUIRED resources
|
||||||
# textfieldconfig = models.ManyToManyField(ProductTextFieldConfiguration)
|
timeframes = models.ManyToManyField(TimeFrame, blank=True) # List of POSSIBLE timeframes
|
||||||
|
|
||||||
resources = models.ManyToManyField(Resource, blank=True)
|
def valid_timeframes(self):
|
||||||
|
"""
|
||||||
|
Return all timeframes that have all resources configured
|
||||||
|
"""
|
||||||
|
|
||||||
|
valid_tf = []
|
||||||
|
|
||||||
|
num_res = self.resources.all().count()
|
||||||
|
|
||||||
|
for tf in self.timeframes.all():
|
||||||
|
# Get all distinct source for this timeframe
|
||||||
|
res = self.resources.filter(price_per_time__timeframe=tf).distinct().count()
|
||||||
|
|
||||||
|
if res == num_res:
|
||||||
|
valid_tf.append(tf)
|
||||||
|
|
||||||
|
return valid_tf
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('product-detail', kwargs={'slug' : self.slug})
|
return reverse('product-detail', kwargs={'slug' : self.slug})
|
||||||
|
|
|
@ -7,4 +7,10 @@
|
||||||
<input type="submit" value="Buy">
|
<input type="submit" value="Buy">
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{% for tf in timeframes %}
|
||||||
|
<li><a href="{% url 'product-order-tf' object.slug tf.slug %}">{{ tf }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
HERE we show a link to <a href="{{ productorder }}">order</a>.
|
HERE we show a link to <a href="{{ productorder }}">order</a>.
|
||||||
|
|
|
@ -1,7 +1,23 @@
|
||||||
Ordering a {{ product }} instance
|
Ordering a {{ product }} instance for {{ timeframe }}
|
||||||
|
|
||||||
|
we are here?!
|
||||||
|
|
||||||
|
|
||||||
<form method="post" >
|
<form method="post" >
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form.as_p }}
|
{{ form.as_p }}
|
||||||
|
{% for res in product.resources.all %}
|
||||||
|
<li>
|
||||||
|
{% if res.minimum_units and res.maximum_units %}
|
||||||
|
<input type="range" id="{{res.slug}}" name="{{res.slug}}"
|
||||||
|
min="{{ res.minimum_units }}" max="{{ res.maximum_units
|
||||||
|
}}">
|
||||||
|
{% else %}
|
||||||
|
<input type="text" id="{{res.slug}}" name="{{res.slug}}">
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
<input type="submit" value="Next">
|
<input type="submit" value="Next">
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -16,6 +16,7 @@ class ProductOrderView(CreateView):
|
||||||
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'])
|
||||||
print(context)
|
print(context)
|
||||||
print(self.kwargs)
|
print(self.kwargs)
|
||||||
return context
|
return context
|
||||||
|
@ -27,6 +28,8 @@ class ProductDetailView(DetailView):
|
||||||
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['productorder'] = reverse('product-order', kwargs={'product': self.object.slug })
|
context['productorder'] = reverse('product-order', kwargs={'product': self.object.slug })
|
||||||
|
context['timeframes'] = context['product'].valid_timeframes()
|
||||||
|
print(context)
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ urlpatterns = [
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
path('order', appviews.ProductSelectView.as_view()),
|
path('order', appviews.ProductSelectView.as_view()),
|
||||||
path('order/<slug:product>/', appviews.ProductOrderView.as_view(), name='product-order'),
|
path('order/<slug:product>/', appviews.ProductOrderView.as_view(), name='product-order'),
|
||||||
path('order/<slug:product>/<slug:timeframe>/', appviews.ProductOrderView.as_view(), name='product-order'),
|
path('order/<slug:product>/<slug:timeframe>/', appviews.ProductOrderView.as_view(), name='product-order-tf'),
|
||||||
path('product/', appviews.ProductListView.as_view()),
|
path('product/', appviews.ProductListView.as_view()),
|
||||||
path('product/<slug:slug>/', appviews.ProductDetailView.as_view(), name='product-detail')
|
path('product/<slug:slug>/', appviews.ProductDetailView.as_view(), name='product-detail')
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue