cleanup in shop/

This commit is contained in:
Stephan Telling 2018-03-04 15:38:40 +01:00
parent 139d2deff9
commit 488767b4f0
11 changed files with 70 additions and 69 deletions

View file

@ -40,6 +40,7 @@ def available_from(product):
return "None"
available_from.short_description = 'Available from'
def available_to(product):
if product.available_in.upper:
return product.available_in.upper.strftime("%c")

View file

@ -2,6 +2,7 @@ from django.apps import AppConfig
import logging
logger = logging.getLogger("bornhack.%s" % __name__)
class ShopConfig(AppConfig):
name = 'shop'

View file

@ -1,8 +1,9 @@
from vendor.coinify.coinify_api import CoinifyAPI
from vendor.coinify.coinify_callback import CoinifyCallback
from .models import CoinifyAPIRequest, CoinifyAPIInvoice, CoinifyAPICallback
from django.conf import settings
import json, logging
import json
import logging
import requests
logger = logging.getLogger("bornhack.%s" % __name__)
@ -34,7 +35,7 @@ def save_coinify_callback(request, order):
# now attempt to parse json
try:
parsed = json.loads(request.body.decode('utf-8'))
except Exception as E:
except Exception:
parsed = ''
# save this callback to db
@ -89,8 +90,8 @@ def handle_coinify_api_response(req, order):
if req.response['success']:
# save this new coinify invoice to the DB
coinifyinvoice = process_coinify_invoice_json(
invoicejson = req.response['data'],
order = order,
invoicejson=req.response['data'],
order=order,
)
return coinifyinvoice
else:

View file

@ -1,6 +1,3 @@
from django.conf import settings
def current_order(request):
if request.user.is_authenticated():
order = None
@ -11,5 +8,3 @@ def current_order(request):
return {'current_order': order}
return {}

View file

@ -1,6 +1,7 @@
import hashlib
from django.conf import settings
def calculate_epay_hash(order, request):
hashstring = (
'{merchant_number}{description}11{amount}DKK'
@ -10,9 +11,9 @@ def calculate_epay_hash(order, request):
description=order.description,
amount=order.total*100,
order_id=order.pk,
accept_url = order.get_epay_accept_url(request),
cancel_url = order.get_cancel_url(request),
callback_url = order.get_epay_callback_url(request),
accept_url=order.get_epay_accept_url(request),
cancel_url=order.get_cancel_url(request),
callback_url=order.get_epay_callback_url(request),
md5_secret=settings.EPAY_MD5_SECRET,
)
epay_hash = hashlib.md5(hashstring.encode('utf-8')).hexdigest()
@ -24,6 +25,7 @@ def validate_epay_callback(query):
for key, value in query.items():
if key != 'hash':
hashstring += value
hash = hashlib.md5((hashstring + settings.EPAY_MD5_SECRET).encode('utf-8')).hexdigest()
hash = hashlib.md5(
(hashstring + settings.EPAY_MD5_SECRET).encode('utf-8')
).hexdigest()
return hash == query['hash']

View file

@ -1,5 +1,4 @@
from django import forms
from .models import Order
class AddToOrderForm(forms.Form):

View file

@ -1,5 +1,3 @@
from psycopg2.extras import DateTimeTZRange
from django.db.models import QuerySet
from django.utils import timezone

View file

@ -1,8 +1,4 @@
import io
import logging
import hashlib
import base64
import qrcode
from django.conf import settings
from django.db import models
@ -202,7 +198,7 @@ class Order(CreatedUpdatedModel):
if request:
messages.success(request, "Created %s tickets of type: %s" % (order_product.quantity, order_product.product.ticket_type.name))
# and mark the OPR as handed_out=True
order_product.handed_out=True
order_product.handed_out = True
order_product.save()
self.save()
@ -210,8 +206,8 @@ class Order(CreatedUpdatedModel):
if not self.paid:
messages.error(request, "Order %s is not paid, so cannot mark it as refunded!" % self.pk)
else:
self.refunded=True
### delete any tickets related to this order
self.refunded = True
# delete any tickets related to this order
if self.tickets.all():
messages.success(request, "Order %s marked as refunded, deleting %s tickets..." % (self.pk, self.tickets.count()))
self.tickets.all().delete()
@ -259,7 +255,6 @@ class Order(CreatedUpdatedModel):
if not self.coinify_api_invoices.exists():
return False
coinifyinvoice = None
for tempinvoice in self.coinify_api_invoices.all():
# we already have a coinifyinvoice for this order, check if it expired
if not tempinvoice.expired:
@ -512,7 +507,7 @@ class CoinifyAPIInvoice(CreatedUpdatedModel):
@property
def expired(self):
return parse_datetime(self.invoicejson['expire_time']) < timezone.now()
return parse_datetime(self.invoicejson['expire_time']) < timezone.now()
class CoinifyAPICallback(CreatedUpdatedModel):

View file

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View file

@ -1,6 +1,5 @@
from django.conf.urls import url
from .views import *
from tickets.views import ShopTicketListView
urlpatterns = [
url(r'^$', ShopIndexView.as_view(), name='index'),

View file

@ -3,21 +3,23 @@ from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.urlresolvers import reverse, reverse_lazy
from django.db.models import Count, F
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseBadRequest, Http404
from django.http import (
HttpResponse,
HttpResponseRedirect,
HttpResponseBadRequest,
Http404
)
from django.shortcuts import get_object_or_404
from django.views.generic import (
View,
TemplateView,
ListView,
DetailView,
FormView,
UpdateView,
)
from django.views.generic.base import RedirectView
from django.views.generic.detail import SingleObjectMixin
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.utils.dateparse import parse_datetime
from django.utils import timezone
from shop.models import (
@ -27,24 +29,22 @@ from shop.models import (
ProductCategory,
EpayCallback,
EpayPayment,
CoinifyAPIInvoice,
CoinifyAPICallback,
CreditNote,
)
from .forms import AddToOrderForm
from .epay import calculate_epay_hash, validate_epay_callback
from collections import OrderedDict
from vendor.coinify.coinify_api import CoinifyAPI
from vendor.coinify.coinify_callback import CoinifyCallback
from .coinify import create_coinify_invoice, save_coinify_callback, process_coinify_invoice_json
import json, time
from .coinify import (
create_coinify_invoice,
save_coinify_callback,
process_coinify_invoice_json
)
import logging
logger = logging.getLogger("bornhack.%s" % __name__)
#################################################################################
### Mixins
# Mixins
class EnsureCreditNoteHasPDFMixin(SingleObjectMixin):
model = CreditNote
@ -92,7 +92,9 @@ class EnsureUnpaidOrderMixin(SingleObjectMixin):
def dispatch(self, request, *args, **kwargs):
if self.get_object().paid:
messages.error(request, "This order is already paid for!")
return HttpResponseRedirect(reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk}))
return HttpResponseRedirect(
reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk})
)
return super(EnsureUnpaidOrderMixin, self).dispatch(
request, *args, **kwargs
@ -105,7 +107,9 @@ class EnsurePaidOrderMixin(SingleObjectMixin):
def dispatch(self, request, *args, **kwargs):
if not self.get_object().paid:
messages.error(request, "This order is not paid for!")
return HttpResponseRedirect(reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk}))
return HttpResponseRedirect(
reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk})
)
return super(EnsurePaidOrderMixin, self).dispatch(
request, *args, **kwargs
@ -118,7 +122,9 @@ class EnsureClosedOrderMixin(SingleObjectMixin):
def dispatch(self, request, *args, **kwargs):
if self.get_object().open is not None:
messages.error(request, 'This order is still open!')
return HttpResponseRedirect(reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk}))
return HttpResponseRedirect(
reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk})
)
return super(EnsureClosedOrderMixin, self).dispatch(
request, *args, **kwargs
@ -160,15 +166,16 @@ class EnsureOrderHasInvoicePDFMixin(SingleObjectMixin):
def dispatch(self, request, *args, **kwargs):
if not self.get_object().invoice.pdf:
messages.error(request, "This order has no invoice yet!")
return HttpResponseRedirect(reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk}))
return HttpResponseRedirect(
reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk})
)
return super(EnsureOrderHasInvoicePDFMixin, self).dispatch(
request, *args, **kwargs
)
#################################################################################
### Shop views
# Shop views
class ShopIndexView(ListView):
model = Product
template_name = "shop_index.html"
@ -215,7 +222,7 @@ class ProductDetailView(FormView, DetailView):
def dispatch(self, request, *args, **kwargs):
if not self.get_object().category.public:
### this product is not publicly available
# this product is not publicly available
raise Http404("Product not found")
return super(ProductDetailView, self).dispatch(
@ -264,7 +271,9 @@ class ProductDetailView(FormView, DetailView):
return super(ProductDetailView, self).form_valid(form)
def get_success_url(self):
return Order.objects.get(user=self.request.user, open__isnull=False).get_absolute_url()
return Order.objects.get(
user=self.request.user, open__isnull=False
).get_absolute_url()
class OrderListView(LoginRequiredMixin, ListView):
@ -289,7 +298,9 @@ class OrderDetailView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureOrderH
if payment_method in order.PAYMENT_METHODS:
if not request.POST.get('accept_terms'):
messages.error(request, "You need to accept the general terms and conditions before you can continue!")
return HttpResponseRedirect(reverse_lazy('shop:order_detail', kwargs={'pk': order.pk}))
return HttpResponseRedirect(
reverse_lazy('shop:order_detail', kwargs={'pk': order.pk})
)
# Set payment method and mark the order as closed
order.payment_method = payment_method
@ -389,9 +400,7 @@ class OrderMarkAsPaidView(LoginRequiredMixin, SingleObjectMixin, View):
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
#################################################################################
### Epay views
# Epay views
class EpayFormView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUnpaidOrderMixin, EnsureClosedOrderMixin, EnsureOrderHasProductsMixin, DetailView):
model = Order
template_name = 'epay_form.html'
@ -435,18 +444,18 @@ class EpayCallbackView(SingleObjectMixin, View):
return HttpResponse(status=400)
if order.paid:
### this order is already paid, perhaps we are seeing a double callback?
# this order is already paid, perhaps we are seeing a double callback?
return HttpResponse('OK')
### epay callback is valid - has the order been paid in full?
# epay callback is valid - has the order been paid in full?
if int(query['amount']) == order.total * 100:
### create an EpayPayment object linking the callback to the order
# create an EpayPayment object linking the callback to the order
EpayPayment.objects.create(
order=order,
callback=callback,
txnid=query.get('txnid'),
)
### and mark order as paid (this will create tickets)
# and mark order as paid (this will create tickets)
order.mark_as_paid(request)
else:
logger.error("valid epay callback with wrong amount detected")
@ -464,15 +473,16 @@ class EpayThanksView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureClosedO
if request.GET:
# epay redirects the user back to our accepturl with a long
# and ugly querystring, redirect user to the clean url
return HttpResponseRedirect(reverse('shop:epay_thanks', kwargs={'pk': self.get_object().pk}))
return HttpResponseRedirect(
reverse('shop:epay_thanks', kwargs={'pk': self.get_object().pk})
)
return super(EpayThanksView, self).dispatch(
request, *args, **kwargs
)
#################################################################################
### Bank Transfer view
# Bank Transfer view
class BankTransferView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUnpaidOrderMixin, EnsureOrderHasProductsMixin, DetailView):
model = Order
@ -489,16 +499,14 @@ class BankTransferView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUnpai
return context
#################################################################################
### Cash payment view
# Cash payment view
class CashView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUnpaidOrderMixin, EnsureOrderHasProductsMixin, DetailView):
model = Order
template_name = 'cash.html'
#################################################################################
### Coinify views
# Coinify views
class CoinifyRedirectView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUnpaidOrderMixin, EnsureClosedOrderMixin, EnsureOrderHasProductsMixin, SingleObjectMixin, RedirectView):
model = Order
@ -511,7 +519,9 @@ class CoinifyRedirectView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUn
coinifyinvoice = create_coinify_invoice(order, request)
if not coinifyinvoice:
messages.error(request, "There was a problem with the payment provider. Please try again later")
return HttpResponseRedirect(reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk}))
return HttpResponseRedirect(
reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk})
)
return super(CoinifyRedirectView, self).dispatch(
request, *args, **kwargs
@ -544,14 +554,17 @@ class CoinifyCallbackView(SingleObjectMixin, View):
# attemt to validate the callbackc
if sdk.validate_callback(request.body, request.META['HTTP_X_COINIFY_CALLBACK_SIGNATURE']):
# mark callback as valid in db
callbackobject.valid=True
callbackobject.valid = True
callbackobject.save()
else:
logger.error("invalid coinify callback detected")
return HttpResponseBadRequest('something is fucky')
if callbackobject.payload['event'] == 'invoice_state_change' or callbackobject.payload['event'] == 'invoice_manual_resend':
coinifyinvoice = process_coinify_invoice_json(callbackobject.payload['data'], self.get_object())
process_coinify_invoice_json(
callbackobject.payload['data'],
self.get_object()
)
return HttpResponse('OK')
else:
logger.error("unsupported callback event %s" % callbackobject.payload['event'])