Getting there!
This commit is contained in:
parent
326e9d70cd
commit
c45a3aa8c9
|
@ -1,7 +1,7 @@
|
|||
def current_order(request):
|
||||
if request.user.is_authenticated():
|
||||
order = None
|
||||
orders = request.user.orders.filter(finalized=False)
|
||||
orders = request.user.orders.filter(open__isnull=False)
|
||||
|
||||
if orders:
|
||||
order = orders[0]
|
||||
|
|
|
@ -2,10 +2,6 @@ from django import forms
|
|||
from .models import Order
|
||||
|
||||
|
||||
class CheckoutForm(forms.Form):
|
||||
# no fields here, just three submit buttons
|
||||
pass
|
||||
|
||||
class AddToOrderForm(forms.Form):
|
||||
quantity = forms.IntegerField()
|
||||
|
||||
|
|
27
shop/migrations/0004_auto_20160515_1604.py
Normal file
27
shop/migrations/0004_auto_20160515_1604.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.6 on 2016-05-15 16:04
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('shop', '0003_auto_20160513_0646'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='productcategory',
|
||||
name='slug',
|
||||
field=models.SlugField(default=''),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='product',
|
||||
name='category',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='products', to='shop.ProductCategory'),
|
||||
),
|
||||
]
|
21
shop/migrations/0005_product_slug.py
Normal file
21
shop/migrations/0005_product_slug.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.6 on 2016-05-15 16:14
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('shop', '0004_auto_20160515_1604'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='product',
|
||||
name='slug',
|
||||
field=models.SlugField(default=''),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
27
shop/migrations/0006_ensure_slugs.py
Normal file
27
shop/migrations/0006_ensure_slugs.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.6 on 2016-05-15 16:15
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def ensure_slugs(apps, schema_editor):
|
||||
ProductCategory = apps.get_model('shop', 'ProductCategory')
|
||||
Product = apps.get_model('shop', 'Product')
|
||||
|
||||
for category in ProductCategory.objects.all():
|
||||
category.save()
|
||||
|
||||
for product in Product.objects.all():
|
||||
product.save()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('shop', '0005_product_slug'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(ensure_slugs, migrations.RunPython.noop)
|
||||
]
|
28
shop/migrations/0007_auto_20160515_2157.py
Normal file
28
shop/migrations/0007_auto_20160515_2157.py
Normal file
|
@ -0,0 +1,28 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.6 on 2016-05-15 21:57
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('shop', '0006_ensure_slugs'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='order',
|
||||
name='open',
|
||||
field=models.NullBooleanField(default=True, help_text='Whether this order is open or not. "None" means closed.', verbose_name='Open?'),
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='order',
|
||||
name='finalized',
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='order',
|
||||
unique_together=set([('user', 'open')]),
|
||||
),
|
||||
]
|
|
@ -1,6 +1,7 @@
|
|||
from django.db import models
|
||||
from django.db.models.aggregates import Sum
|
||||
from django.contrib.postgres.fields import DateTimeRangeField, JSONField
|
||||
from django.utils.text import slugify
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils import timezone
|
||||
from bornhack.utils import CreatedUpdatedModel, UUIDModel
|
||||
|
@ -9,6 +10,9 @@ from .managers import ProductQuerySet
|
|||
|
||||
class Order(CreatedUpdatedModel):
|
||||
|
||||
class Meta:
|
||||
unique_together = ('user', 'open')
|
||||
|
||||
products = models.ManyToManyField(
|
||||
'shop.Product',
|
||||
through='shop.OrderProductRelation'
|
||||
|
@ -27,10 +31,10 @@ class Order(CreatedUpdatedModel):
|
|||
default=False,
|
||||
)
|
||||
|
||||
finalized = models.BooleanField(
|
||||
verbose_name=_('Finalized?'),
|
||||
help_text=_('Whether this order has been finalized.'),
|
||||
default=False,
|
||||
open = models.NullBooleanField(
|
||||
verbose_name=_('Open?'),
|
||||
help_text=_('Whether this order is open or not. "None" means closed.'),
|
||||
default=True,
|
||||
)
|
||||
|
||||
camp = models.ForeignKey(
|
||||
|
@ -44,6 +48,12 @@ class Order(CreatedUpdatedModel):
|
|||
BANK_TRANSFER = 'bank_transfer'
|
||||
|
||||
PAYMENT_METHODS = [
|
||||
CREDIT_CARD,
|
||||
BLOCKCHAIN,
|
||||
BANK_TRANSFER,
|
||||
]
|
||||
|
||||
PAYMENT_METHOD_CHOICES = [
|
||||
(CREDIT_CARD, 'Credit card'),
|
||||
(BLOCKCHAIN, 'Blockchain'),
|
||||
(BANK_TRANSFER, 'Bank transfer'),
|
||||
|
@ -51,7 +61,7 @@ class Order(CreatedUpdatedModel):
|
|||
|
||||
payment_method = models.CharField(
|
||||
max_length=50,
|
||||
choices=PAYMENT_METHODS,
|
||||
choices=PAYMENT_METHOD_CHOICES,
|
||||
default=BLOCKCHAIN
|
||||
)
|
||||
|
||||
|
@ -67,10 +77,15 @@ class ProductCategory(CreatedUpdatedModel, UUIDModel):
|
|||
verbose_name_plural = 'Product categories'
|
||||
|
||||
name = models.CharField(max_length=150)
|
||||
slug = models.SlugField()
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def save(self, **kwargs):
|
||||
self.slug = slugify(self.name)
|
||||
super(ProductCategory, self).save(**kwargs)
|
||||
|
||||
|
||||
class Product(CreatedUpdatedModel, UUIDModel):
|
||||
class Meta:
|
||||
|
@ -78,9 +93,13 @@ class Product(CreatedUpdatedModel, UUIDModel):
|
|||
verbose_name_plural = 'Products'
|
||||
ordering = ['available_in']
|
||||
|
||||
category = models.ForeignKey('shop.ProductCategory')
|
||||
category = models.ForeignKey(
|
||||
'shop.ProductCategory',
|
||||
related_name='products'
|
||||
)
|
||||
|
||||
name = models.CharField(max_length=150)
|
||||
slug = models.SlugField()
|
||||
|
||||
price = models.IntegerField(
|
||||
help_text=_('Price of the product (in DKK).')
|
||||
|
@ -103,6 +122,10 @@ class Product(CreatedUpdatedModel, UUIDModel):
|
|||
self.price,
|
||||
)
|
||||
|
||||
def save(self, **kwargs):
|
||||
self.slug = slugify(self.name)
|
||||
super(Product, self).save(**kwargs)
|
||||
|
||||
def is_available(self):
|
||||
now = timezone.now()
|
||||
return now in self.available_in
|
||||
|
@ -114,6 +137,10 @@ class OrderProductRelation(models.Model):
|
|||
quantity = models.PositiveIntegerField()
|
||||
handed_out = models.BooleanField(default=False)
|
||||
|
||||
@property
|
||||
def total(self):
|
||||
return self.product.price * self.quantity
|
||||
|
||||
|
||||
class EpayCallback(CreatedUpdatedModel, UUIDModel):
|
||||
class Meta:
|
||||
|
|
|
@ -1,7 +1,48 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load bootstrap3 %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<b>details for order {{ order.id }}</b>
|
||||
<h1>Order #{{ order.id }}</h1>
|
||||
|
||||
<table class="table table-bordered table-hover">
|
||||
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Name
|
||||
<th>
|
||||
Quantity
|
||||
<th>
|
||||
Price
|
||||
<th>
|
||||
Total
|
||||
|
||||
<tbody>
|
||||
{% for order_product in order.orderproductrelation_set.all %}
|
||||
<tr>
|
||||
<td>
|
||||
{{ order_product.product.name }}
|
||||
<td>
|
||||
{{ order_product.quantity }}
|
||||
<td>
|
||||
{{ order_product.product.price }}
|
||||
<td>
|
||||
{{ order_product.total }}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
{# TODO: Add total + VAT info #}
|
||||
|
||||
</table>
|
||||
|
||||
{% if order.open %}
|
||||
<form method="POST">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_button "Credit card" button_type="submit" button_class="btn-primary" name="payment_method" value="credit_card" %}
|
||||
{% bootstrap_button "Blockchain" button_type="submit" button_class="btn-primary" name="payment_method" value="blockchain" %}
|
||||
{% bootstrap_button "Bank transfer" button_type="submit" button_class="btn-primary" name="payment_method" value="bank_transfer" %}
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
||||
|
|
36
shop/templates/order_list.html
Normal file
36
shop/templates/order_list.html
Normal file
|
@ -0,0 +1,36 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load bootstrap3 %}
|
||||
|
||||
{% block content %}
|
||||
<h3>Orders</h3>
|
||||
<table class="table table-bordered table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Order ID</th>
|
||||
<th>Open?</th>
|
||||
<th>Paid?</th>
|
||||
<th>Delivered?</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for order in orders %}
|
||||
<tr {% if order.finalized and order.paid %}style="color: lightgreen"{% endif %}>
|
||||
<td>{{ order.id }}</td>
|
||||
<td>{{ order.finalized }}</td>
|
||||
<td>{{ order.paid }}</td>
|
||||
<td>?</td>
|
||||
<td>
|
||||
{% if order.finalized and not order.paid %}
|
||||
{% url 'shop:order_detail' pk=order.pk as order_detail_url %}
|
||||
{% url 'shop:order_cancel' pk=order.pk as order_cancel_url %}
|
||||
{% bootstrap_button "Pay order" href=order_detail_url button_class="btn-primary" %}
|
||||
{% bootstrap_button "Cancel order" href=order_cancel_url button_class="btn-primary" %}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
<form method="POST">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form form %}
|
||||
{% bootstrap_button "Add to order" button_type="submit" button_class="btn-primary" %}
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,73 +1,61 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load bootstrap3 %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h2>Shop</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
Categories:
|
||||
{% for category in categories %}
|
||||
<a href="{% url 'shop:index' %}?category={{category.slug}}"
|
||||
class="label label-{% if category.slug == current_category %}primary{% else %}default{% endif %}">
|
||||
{{category}}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="row">
|
||||
|
||||
{% for product in products %}
|
||||
|
||||
<a href="{% url 'shop:product_detail' slug=product.slug %}">
|
||||
<div class="col-sm-4 col-lg-4 col-md-4">
|
||||
<div class="thumbnail">
|
||||
<img src="http://placehold.it/320x200" alt="">
|
||||
<div class="caption">
|
||||
<h5>{{ product.category.name }}</h5>
|
||||
|
||||
<h4>
|
||||
{{ product.name }}
|
||||
</h4>
|
||||
|
||||
<h4>
|
||||
Price: {{ product.price }} DKK
|
||||
</h4>
|
||||
|
||||
<p>
|
||||
{{ product.description }}
|
||||
</p>
|
||||
|
||||
<small>
|
||||
<strong>Availability:</strong><br/>
|
||||
{{ product.available_in.lower|date:"Y-m-d H:i" }}
|
||||
{% if product.available_in.upper %}
|
||||
- {{ product.available_in.upper|date:"Y-m-d H:i" }}
|
||||
{% endif %}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
|
||||
<p class="lead">
|
||||
Here you can see your orders and available products in the shop.
|
||||
</p>
|
||||
<h3>Orders</h3>
|
||||
<table class="table table-bordered table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Order ID</th>
|
||||
<th>Open?</th>
|
||||
<th>Paid?</th>
|
||||
<th>Delivered?</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for order in orders %}
|
||||
<tr {% if order.finalized and order.paid %}style="color: lightgreen"{% endif %}>
|
||||
<td>{{ order.id }}</td>
|
||||
<td>{{ order.finalized }}</td>
|
||||
<td>{{ order.paid }}</td>
|
||||
<td>?</td>
|
||||
<td>
|
||||
{% if order.finalized and not order.paid %}
|
||||
{% url 'shop:order_detail' pk=order.id as order_detail_url %}
|
||||
{% url 'shop:order_cancel' pk=order.id as order_cancel_url %}
|
||||
{% bootstrap_button "Pay order" href=order_detail_url button_class="btn-primary" %}
|
||||
{% bootstrap_button "Cancel order" href=order_cancel_url button_class="btn-primary" %}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h3>Products</h3>
|
||||
<table class="table table-bordered table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Description</th>
|
||||
<th>Price</th>
|
||||
<th>Availability</th>
|
||||
<th>Buy</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for product in product_list %}
|
||||
<tr {% if not product.is_available %}style="color: lightgrey"{%endif%}>
|
||||
<td>{{ product.name }}</td>
|
||||
<td>{{ product.price }} DKK</td>
|
||||
<td>{{ product.available_in.lower }}
|
||||
{% if product.available_in.upper %}
|
||||
- {{ product.available_in.upper }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if product.is_available %}
|
||||
{% url 'shop:product_detail' pk=product.pk as product_detail_url %}
|
||||
{% bootstrap_button "Add to order" href=product_detail_url button_class="btn-primary" %}
|
||||
{% else %}
|
||||
N/A
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endblock %}
|
||||
|
|
|
@ -13,7 +13,8 @@ urlpatterns = [
|
|||
#name='epay_callback'
|
||||
#),
|
||||
url(r'^$', ShopIndexView.as_view(), name='index'),
|
||||
url(r'products/(?P<pk>[a-zA-Z0-9\-]+)/$', ProductDetailView.as_view(), name='product_detail'),
|
||||
url(r'products/(?P<slug>[-_\w+]+)/$', ProductDetailView.as_view(), name='product_detail'),
|
||||
url(r'orders/$', OrderListView.as_view(), name='order_list'),
|
||||
url(r'orders/(?P<pk>[0-9]+)/$', OrderDetailView.as_view(), name='order_detail'),
|
||||
url(r'orders/(?P<pk>[0-9]+)/checkout/$', CheckoutView.as_view(), name='checkout'),
|
||||
# url(r'orders/(?P<pk>[0-9]+)/checkout/$', CheckoutView.as_view(), name='checkout'),
|
||||
]
|
||||
|
|
221
shop/views.py
221
shop/views.py
|
@ -1,70 +1,60 @@
|
|||
import hashlib
|
||||
|
||||
from django.http import HttpResponseRedirect, Http404
|
||||
from django.views.generic import CreateView, TemplateView, ListView, DetailView, View, FormView
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.http import HttpResponse
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from django.db.models import Count, F
|
||||
from django.http import HttpResponseRedirect, Http404
|
||||
from django.views.generic import (
|
||||
TemplateView,
|
||||
ListView,
|
||||
DetailView,
|
||||
FormView,
|
||||
)
|
||||
|
||||
from .models import Order, Product, EpayCallback, EpayPayment, OrderProductRelation
|
||||
from .forms import CheckoutForm, AddToOrderForm
|
||||
from shop.models import (
|
||||
Order,
|
||||
Product,
|
||||
OrderProductRelation,
|
||||
ProductCategory,
|
||||
)
|
||||
from .forms import AddToOrderForm
|
||||
|
||||
|
||||
class ShopIndexView(ListView):
|
||||
model = Product
|
||||
template_name = "shop_index.html"
|
||||
context_object_name = 'products'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ShopIndexView, self).get_context_data(**kwargs)
|
||||
|
||||
if 'category' in self.request.GET:
|
||||
category = self.request.GET.get('category')
|
||||
context['products'] = context['products'].filter(
|
||||
category__slug=category
|
||||
)
|
||||
context['current_category'] = category
|
||||
context['categories'] = ProductCategory.objects.annotate(
|
||||
num_products=Count('products')
|
||||
).filter(
|
||||
num_products__gt=0
|
||||
)
|
||||
return context
|
||||
|
||||
|
||||
class OrderListView(LoginRequiredMixin, ListView):
|
||||
model = Order
|
||||
template_name = "order_list.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(OrderListView, self).get_context_data(**kwargs)
|
||||
context['orders'] = Order.objects.filter(user=self.request.user)
|
||||
return context
|
||||
|
||||
|
||||
class ProductDetailView(LoginRequiredMixin, FormView):
|
||||
model = Product
|
||||
template_name = 'product_detail.html'
|
||||
form_class = AddToOrderForm
|
||||
context_object_name = 'product'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.product = Product.objects.get(pk=kwargs.get('pk'))
|
||||
return self.render_to_response(self.get_context_data())
|
||||
|
||||
def form_valid(self, form):
|
||||
### do we have an open order?
|
||||
try:
|
||||
order = Order.objects.get(user=self.request.user, finalized=False)
|
||||
except Order.DoesNotExist:
|
||||
### no open order - open a new one
|
||||
order = Order.objects.create(user=request.user)
|
||||
|
||||
### get product from kwargs
|
||||
if self.product in order.products.all():
|
||||
### this product is already added to this order, increase count by one
|
||||
OrderProductRelation.objects.filter(product=self.product, order=order).update(quantity=F('quantity') + 1)
|
||||
else:
|
||||
order.products.add(self.product)
|
||||
|
||||
### done
|
||||
return super(ProductDetailView, self).form_valid(form)
|
||||
|
||||
|
||||
class OrderDetailView(LoginRequiredMixin, DetailView):
|
||||
model = Product
|
||||
template_name = 'order_detail.html'
|
||||
context_object_name = 'order'
|
||||
|
||||
|
||||
class CheckoutView(LoginRequiredMixin, FormView):
|
||||
"""
|
||||
Shows a summary of all products contained in an order,
|
||||
total price, VAT info, and a button to finalize order and go to payment
|
||||
"""
|
||||
model = Order
|
||||
template_name = 'checkout.html'
|
||||
form_class = CheckoutForm
|
||||
template_name = 'order_detail.html'
|
||||
context_object_name = 'order'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
|
@ -79,44 +69,97 @@ class CheckoutView(LoginRequiredMixin, FormView):
|
|||
messages.error(request, 'This order contains no products!')
|
||||
return HttpResponseRedirect('shop:order_detail')
|
||||
|
||||
return self.render_to_response(self.get_context_data())
|
||||
return super(OrderDetailView, self).get(request, *args, **kwargs)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
# mark order as finalized and redirect user to payment
|
||||
order = self.get_object()
|
||||
payment_method = request.POST.get('payment_method')
|
||||
|
||||
if payment_method in order.PAYMENT_METHODS:
|
||||
order.payment_method = payment_method
|
||||
else:
|
||||
# unknown submit button
|
||||
messages.error(self.request, 'Unknown submit button :(')
|
||||
return reverse_lazy(
|
||||
'shop:checkout',
|
||||
kwargs={'orderid': self.get_object.id}
|
||||
)
|
||||
|
||||
order.finalized = True
|
||||
|
||||
reverses = {
|
||||
Order.CREDIT_CARD: reverse_lazy(
|
||||
'shop:epay_form',
|
||||
kwargs={'orderid': order.id}
|
||||
),
|
||||
Order.BLOCKCHAIN: reverse_lazy(
|
||||
'shop:coinify_pay',
|
||||
kwargs={'orderid': order.id}
|
||||
),
|
||||
Order.BANK_TRANSFER: reverse_lazy(
|
||||
'shop:bank_transfer',
|
||||
kwargs={'orderid': order.id}
|
||||
)
|
||||
}
|
||||
|
||||
return HttpResponseRedirect(reverses[payment_method])
|
||||
|
||||
|
||||
class ProductDetailView(LoginRequiredMixin, FormView, DetailView):
|
||||
model = Product
|
||||
template_name = 'product_detail.html'
|
||||
form_class = AddToOrderForm
|
||||
context_object_name = 'product'
|
||||
|
||||
def form_valid(self, form):
|
||||
### mark order as finalized and redirect user to payment
|
||||
form.instance.finalized=True
|
||||
product = self.get_object()
|
||||
quantity = form.cleaned_data.get('quantity'),
|
||||
|
||||
### set payment_method based on submit button used
|
||||
if 'credit_card' in form.data:
|
||||
form.instance.payment_method=='credit_card'
|
||||
elif 'blockchain' in form.data:
|
||||
form.instance.payment_method=='blockchain'
|
||||
elif 'bank_transfer' in form.data:
|
||||
form.instance.payment_method=='bank_transfer'
|
||||
# do we have an open order?
|
||||
try:
|
||||
order = Order.objects.get(
|
||||
user=self.request.user,
|
||||
finalized=False
|
||||
)
|
||||
except Order.DoesNotExist:
|
||||
# no open order - open a new one
|
||||
order = Order.objects.create(user=self.request.user)
|
||||
|
||||
# get product from kwargs
|
||||
if product in order.products.all():
|
||||
# this product is already added to this order,
|
||||
# increase count by quantity
|
||||
OrderProductRelation.objects.filter(
|
||||
product=product,
|
||||
order=order
|
||||
).update(quantity=F('quantity') + quantity)
|
||||
else:
|
||||
### unknown submit button
|
||||
messages.error(request, 'Unknown submit button :(')
|
||||
return reverse('shop:checkout', kwargs={'orderid': self.get_object.id})
|
||||
order.products.add(product)
|
||||
|
||||
return super(CheckoutView, self).form_valid(form)
|
||||
messages.info(
|
||||
self.request,
|
||||
'{}x {} has been added to your order.'.format(
|
||||
quantity,
|
||||
product.name
|
||||
)
|
||||
)
|
||||
|
||||
# done
|
||||
return super(ProductDetailView, self).form_valid(form)
|
||||
|
||||
def get_success_url(self):
|
||||
if self.get_object.payment_method == 'credit_card':
|
||||
return reverse('shop:epay_form', kwargs={'orderid': self.get_object.id})
|
||||
elif self.get_object.payment_method == 'blockchain':
|
||||
return reverse('shop:coinify_pay', kwargs={'orderid': self.get_object.id})
|
||||
elif self.get_object.payment_method == 'bank_transfer':
|
||||
return reverse('shop:bank_transfer', kwargs={'orderid': self.get_object.id})
|
||||
else:
|
||||
### unknown payment method
|
||||
messages.error(request, 'Unknown payment method :(')
|
||||
return reverse('shop:checkout', kwargs={'orderid': self.get_object.id})
|
||||
return reverse_lazy(
|
||||
'shop:product_detail',
|
||||
kwargs={'slug': self.get_object().slug}
|
||||
)
|
||||
|
||||
|
||||
class CoinifyRedirectView(TemplateView):
|
||||
template_name = 'coinify_redirect.html'
|
||||
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
### validate a few things
|
||||
# validate a few things
|
||||
self.order = Order.objects.get(pk=kwargs.get('order_id'))
|
||||
if self.order.user != request.user:
|
||||
raise Http404("Order not found")
|
||||
|
@ -139,25 +182,37 @@ class CoinifyRedirectView(TemplateView):
|
|||
order = Order.objects.get(pk=kwargs.get('order_id'))
|
||||
context = super(CoinifyRedirectView, self).get_context_data(**kwargs)
|
||||
context['order'] = order
|
||||
|
||||
### Initiate coinify API and create invoice
|
||||
coinifyapi = CoinifyAPI(settings.COINIFY_API_KEY, settings.COINIFY_API_SECRET)
|
||||
|
||||
# Initiate coinify API and create invoice
|
||||
coinifyapi = CoinifyAPI(
|
||||
settings.COINIFY_API_KEY,
|
||||
settings.COINIFY_API_SECRET
|
||||
)
|
||||
response = coinifyapi.invoice_create(
|
||||
amount,
|
||||
currency,
|
||||
plugin_name='BornHack 2016 webshop',
|
||||
plugin_version='1.0',
|
||||
description='BornHack 2016 order id #%s' % order.id,
|
||||
callback_url=reverse('shop:coinfy_callback', kwargs={'orderid': order.id}),
|
||||
return_url=reverse('shop:order_paid', kwargs={'orderid': order.id}),
|
||||
callback_url=reverse(
|
||||
'shop:coinfy_callback',
|
||||
kwargs={'orderid': order.id}
|
||||
),
|
||||
return_url=reverse(
|
||||
'shop:order_paid',
|
||||
kwargs={'orderid': order.id}
|
||||
),
|
||||
)
|
||||
|
||||
if not response['success']:
|
||||
api_error = response['error']
|
||||
print "API error: %s (%s)" % (api_error['message'], api_error['code'] )
|
||||
print "API error: %s (%s)" % (
|
||||
api_error['message'],
|
||||
api_error['code']
|
||||
)
|
||||
|
||||
invoice = response['data']
|
||||
### change this to pass only needed data when we get that far
|
||||
# change this to pass only needed data when we get that far
|
||||
context['invoice'] = invoice
|
||||
return context
|
||||
|
||||
|
|
Loading…
Reference in a new issue