More tests - and some blackness.

This commit is contained in:
Víðir Valberg Guðmundsson 2019-03-29 22:06:52 +01:00
parent e5e1443218
commit 4aad051c72
3 changed files with 280 additions and 178 deletions

View file

@ -3,10 +3,10 @@ from decimal import Decimal
register = template.Library()
@register.filter
def currency(value):
try:
return "{0:.2f} DKK".format(Decimal(value))
except ValueError:
return False

View file

@ -231,12 +231,12 @@ class TestOrderDetailView(TestCase):
self.client.force_login(self.user)
OrderProductRelationFactory(order=self.order)
orp = OrderProductRelationFactory(order=self.order)
opr = OrderProductRelationFactory(order=self.order)
order = orp.order
order = opr.order
data = self.base_form_data
data["remove_product"] = orp.pk
data["remove_product"] = opr.pk
response = self.client.post(self.path, data=data)
self.assertEquals(response.status_code, 200)
@ -248,12 +248,12 @@ class TestOrderDetailView(TestCase):
def test_remove_last_product_cancels_order(self):
self.client.force_login(self.user)
orp = OrderProductRelationFactory(order=self.order)
opr = OrderProductRelationFactory(order=self.order)
order = orp.order
order = opr.order
data = self.base_form_data
data["remove_product"] = orp.pk
data["remove_product"] = opr.pk
response = self.client.post(self.path, data=data)
self.assertEquals(response.status_code, 302)
@ -266,11 +266,11 @@ class TestOrderDetailView(TestCase):
def test_cancel_order(self):
self.client.force_login(self.user)
orp = OrderProductRelationFactory(order=self.order)
order = orp.order
opr = OrderProductRelationFactory(order=self.order)
order = opr.order
data = self.base_form_data
data["cancel_order"] = None
data["cancel_order"] = ""
response = self.client.post(self.path, data=data)
self.assertEquals(response.status_code, 302)
@ -280,6 +280,69 @@ class TestOrderDetailView(TestCase):
self.assertTrue(order.cancelled)
def test_incrementing_product_quantity(self):
self.client.force_login(self.user)
opr = OrderProductRelationFactory(order=self.order)
opr.product.stock_amount = 100
opr.product.save()
data = self.base_form_data
data["update_order"] = ""
data["form-0-id"] = opr.pk
data["form-0-quantity"] = 11
response = self.client.post(self.path, data=data)
opr.refresh_from_db()
self.assertEquals(response.status_code, 200)
self.assertEquals(opr.quantity, 11)
def test_incrementing_product_quantity_beyond_stock_fails(self):
self.client.force_login(self.user)
opr = OrderProductRelationFactory(order=self.order)
opr.product.stock_amount = 10
opr.product.save()
data = self.base_form_data
data["update_order"] = ""
data["form-0-id"] = opr.pk
data["form-0-quantity"] = 11
response = self.client.post(self.path, data=data)
self.assertEquals(response.status_code, 200)
self.assertIn("quantity", response.context["order_product_formset"].errors[0])
def test_terms_have_to_be_accepted(self):
self.client.force_login(self.user)
opr = OrderProductRelationFactory(order=self.order)
data = self.base_form_data
data["form-0-id"] = opr.pk
data["form-0-quantity"] = 11
data["payment_method"] = "bank_transfer"
response = self.client.post(self.path, data=data)
self.assertEquals(response.status_code, 200)
def test_accepted_terms_and_chosen_payment_method(self):
self.client.force_login(self.user)
opr = OrderProductRelationFactory(order=self.order)
data = self.base_form_data
data["form-0-id"] = opr.pk
data["form-0-quantity"] = 11
data["payment_method"] = "bank_transfer"
data["accept_terms"] = True
response = self.client.post(self.path, data=data)
self.assertEquals(response.status_code, 302)
self.assertRedirects(
response, reverse("shop:bank_transfer", kwargs={"pk": self.order.id})
)
class TestOrderListView(TestCase):
def test_order_list_view_as_logged_in(self):

View file

@ -9,19 +9,14 @@ from django.http import (
HttpResponse,
HttpResponseRedirect,
HttpResponseBadRequest,
Http404
Http404,
)
from django.shortcuts import get_object_or_404
from django.urls import reverse, reverse_lazy
from django.utils import timezone
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.views.generic import (
View,
ListView,
DetailView,
FormView,
)
from django.views.generic import View, ListView, DetailView, FormView
from django.views.generic.base import RedirectView
from django.views.generic.detail import SingleObjectMixin
@ -38,7 +33,7 @@ from vendor.coinify.coinify_callback import CoinifyCallback
from .coinify import (
create_coinify_invoice,
save_coinify_callback,
process_coinify_invoice_json
process_coinify_invoice_json,
)
from .epay import calculate_epay_hash, validate_epay_callback
from .forms import OrderProductRelationFormSet, OrderProductRelationForm
@ -53,7 +48,7 @@ class EnsureCreditNoteHasPDFMixin(SingleObjectMixin):
def dispatch(self, request, *args, **kwargs):
if not self.get_object().pdf:
messages.error(request, "This creditnote has no PDF yet!")
return HttpResponseRedirect(reverse_lazy('shop:creditnote_list'))
return HttpResponseRedirect(reverse_lazy("shop:creditnote_list"))
return super(EnsureCreditNoteHasPDFMixin, self).dispatch(
request, *args, **kwargs
@ -83,9 +78,7 @@ class EnsureUserOwnsOrderMixin(SingleObjectMixin):
if self.get_object().user != request.user:
raise Http404("Order not found")
return super(EnsureUserOwnsOrderMixin, self).dispatch(
request, *args, **kwargs
)
return super(EnsureUserOwnsOrderMixin, self).dispatch(request, *args, **kwargs)
class EnsureUnpaidOrderMixin(SingleObjectMixin):
@ -95,12 +88,10 @@ class EnsureUnpaidOrderMixin(SingleObjectMixin):
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})
reverse_lazy("shop:order_detail", kwargs={"pk": self.get_object().pk})
)
return super(EnsureUnpaidOrderMixin, self).dispatch(
request, *args, **kwargs
)
return super(EnsureUnpaidOrderMixin, self).dispatch(request, *args, **kwargs)
class EnsurePaidOrderMixin(SingleObjectMixin):
@ -110,12 +101,10 @@ class EnsurePaidOrderMixin(SingleObjectMixin):
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})
reverse_lazy("shop:order_detail", kwargs={"pk": self.get_object().pk})
)
return super(EnsurePaidOrderMixin, self).dispatch(
request, *args, **kwargs
)
return super(EnsurePaidOrderMixin, self).dispatch(request, *args, **kwargs)
class EnsureClosedOrderMixin(SingleObjectMixin):
@ -123,14 +112,12 @@ 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!')
messages.error(request, "This order is still open!")
return HttpResponseRedirect(
reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk})
reverse_lazy("shop:order_detail", kwargs={"pk": self.get_object().pk})
)
return super(EnsureClosedOrderMixin, self).dispatch(
request, *args, **kwargs
)
return super(EnsureClosedOrderMixin, self).dispatch(request, *args, **kwargs)
class EnsureOrderHasProductsMixin(SingleObjectMixin):
@ -138,8 +125,8 @@ class EnsureOrderHasProductsMixin(SingleObjectMixin):
def dispatch(self, request, *args, **kwargs):
if not self.get_object().products.count() > 0:
messages.error(request, 'This order has no products!')
return HttpResponseRedirect(reverse_lazy('shop:index'))
messages.error(request, "This order has no products!")
return HttpResponseRedirect(reverse_lazy("shop:index"))
return super(EnsureOrderHasProductsMixin, self).dispatch(
request, *args, **kwargs
@ -152,10 +139,9 @@ class EnsureOrderIsNotCancelledMixin(SingleObjectMixin):
def dispatch(self, request, *args, **kwargs):
if self.get_object().cancelled:
messages.error(
request,
'Order #{} is cancelled!'.format(self.get_object().id)
request, "Order #{} is cancelled!".format(self.get_object().id)
)
return HttpResponseRedirect(reverse_lazy('shop:index'))
return HttpResponseRedirect(reverse_lazy("shop:index"))
return super(EnsureOrderIsNotCancelledMixin, self).dispatch(
request, *args, **kwargs
@ -169,7 +155,7 @@ class EnsureOrderHasInvoicePDFMixin(SingleObjectMixin):
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})
reverse_lazy("shop:order_detail", kwargs={"pk": self.get_object().pk})
)
return super(EnsureOrderHasInvoicePDFMixin, self).dispatch(
@ -181,17 +167,17 @@ class EnsureOrderHasInvoicePDFMixin(SingleObjectMixin):
class ShopIndexView(ListView):
model = Product
template_name = "shop_index.html"
context_object_name = 'products'
context_object_name = "products"
def get_queryset(self):
queryset = super(ShopIndexView, self).get_queryset()
return queryset.available().order_by('category__name', 'price', 'name')
return queryset.available().order_by("category__name", "price", "name")
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')
if "category" in self.request.GET:
category = self.request.GET.get("category")
# is this a public category
try:
@ -202,41 +188,39 @@ class ShopIndexView(ListView):
raise Http404("Category not found")
# filter products by the chosen category
context['products'] = context['products'].filter(
category__slug=category
)
context['current_category'] = categoryobj
context['categories'] = ProductCategory.objects.annotate(
num_products=Count('products')
context["products"] = context["products"].filter(category__slug=category)
context["current_category"] = categoryobj
context["categories"] = ProductCategory.objects.annotate(
num_products=Count("products")
).filter(
num_products__gt=0,
public=True,
products__available_in__contains=timezone.now()
products__available_in__contains=timezone.now(),
)
return context
class ProductDetailView(FormView, DetailView):
model = Product
template_name = 'product_detail.html'
template_name = "product_detail.html"
form_class = OrderProductRelationForm
context_object_name = 'product'
context_object_name = "product"
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
if hasattr(self, 'opr'):
kwargs['instance'] = self.opr
if hasattr(self, "opr"):
kwargs["instance"] = self.opr
return kwargs
def get_initial(self):
if hasattr(self, 'opr'):
return {'quantity': self.opr.quantity}
if hasattr(self, "opr"):
return {"quantity": self.opr.quantity}
return None
def get_context_data(self, **kwargs):
# If the OrderProductRelation already exists it has a primary key in the database
if self.request.user.is_authenticated and self.opr.pk:
kwargs['already_in_order'] = True
kwargs["already_in_order"] = True
return super().get_context_data(**kwargs)
@ -252,32 +236,28 @@ class ProductDetailView(FormView, DetailView):
self.opr = OrderProductRelation.objects.get(
order__user=self.request.user,
order__open__isnull=False,
product=self.object
product=self.object,
)
except OrderProductRelation.DoesNotExist:
self.opr = OrderProductRelation(
product=self.get_object(),
quantity=1,
)
self.opr = OrderProductRelation(product=self.get_object(), quantity=1)
return super(ProductDetailView, self).dispatch(
request, *args, **kwargs
)
return super(ProductDetailView, self).dispatch(request, *args, **kwargs)
def form_valid(self, form):
opr = form.save(commit=False)
if not opr.pk:
opr.order, _ = Order.objects.get_or_create(user=self.request.user, open=True, cancelled=False)
opr.order, _ = Order.objects.get_or_create(
user=self.request.user, open=True, cancelled=False
)
opr.save()
messages.info(
self.request,
'{}x {} has been added to your order.'.format(
opr.quantity,
opr.product.name
)
"{}x {} has been added to your order.".format(
opr.quantity, opr.product.name
),
)
# done
@ -292,22 +272,28 @@ class ProductDetailView(FormView, DetailView):
class OrderListView(LoginRequiredMixin, ListView):
model = Order
template_name = "shop/order_list.html"
context_object_name = 'orders'
context_object_name = "orders"
def get_queryset(self):
queryset = super(OrderListView, self).get_queryset()
return queryset.filter(user=self.request.user).not_cancelled()
class OrderDetailView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureOrderHasProductsMixin, EnsureOrderIsNotCancelledMixin, DetailView):
class OrderDetailView(
LoginRequiredMixin,
EnsureUserOwnsOrderMixin,
EnsureOrderHasProductsMixin,
EnsureOrderIsNotCancelledMixin,
DetailView,
):
model = Order
template_name = 'shop/order_detail.html'
context_object_name = 'order'
template_name = "shop/order_detail.html"
context_object_name = "order"
def get_context_data(self, **kwargs):
if 'order_product_formset' not in kwargs:
kwargs['order_product_formset'] = OrderProductRelationFormSet(
queryset=OrderProductRelation.objects.filter(order=self.get_object()),
if "order_product_formset" not in kwargs:
kwargs["order_product_formset"] = OrderProductRelationFormSet(
queryset=OrderProductRelation.objects.filter(order=self.get_object())
)
return super().get_context_data(**kwargs)
@ -317,19 +303,19 @@ class OrderDetailView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureOrderH
order = self.object
# First check if the user is removing a product from the order.
product_remove = request.POST.get('remove_product')
product_remove = request.POST.get("remove_product")
if product_remove:
order.orderproductrelation_set.filter(pk=product_remove).delete()
if not order.products.count() > 0:
order.mark_as_cancelled()
messages.info(request, 'Order cancelled!')
return HttpResponseRedirect(reverse_lazy('shop:index'))
messages.info(request, "Order cancelled!")
return HttpResponseRedirect(reverse_lazy("shop:index"))
# Then see if the user is cancelling the order.
elif 'cancel_order' in request.POST:
elif "cancel_order" in request.POST:
order.mark_as_cancelled()
messages.info(request, 'Order cancelled!')
return HttpResponseRedirect(reverse_lazy('shop:index'))
messages.info(request, "Order cancelled!")
return HttpResponseRedirect(reverse_lazy("shop:index"))
# The user is not removing products or cancelling the order,
# so from now on we do stuff that require us to check stock.
@ -337,62 +323,58 @@ class OrderDetailView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureOrderH
# which product is not in stock if that is the case.
else:
formset = OrderProductRelationFormSet(
request.POST,
queryset=OrderProductRelation.objects.filter(order=order),
request.POST, queryset=OrderProductRelation.objects.filter(order=order)
)
# If the formset is not valid it means that we cannot fulfill the order, so return and inform the user.
if not formset.is_valid():
messages.error(
request,
"Some of the products you are ordering are out of stock. Review the order and try again."
"Some of the products you are ordering are out of stock. Review the order and try again.",
)
return self.render_to_response(
self.get_context_data(order_product_formset=formset)
)
# No stock issues, proceed to check if the user is updating the order.
if 'update_order' in request.POST:
if "update_order" in request.POST:
# We have already made sure the formset is valid, so just save it to update quantities.
formset.save()
order.customer_comment = request.POST.get('customer_comment') or ''
order.invoice_address = request.POST.get('invoice_address') or ''
order.customer_comment = request.POST.get("customer_comment") or ""
order.invoice_address = request.POST.get("invoice_address") or ""
order.save()
# Then at last see if the user is paying for the order.
payment_method = request.POST.get('payment_method')
payment_method = request.POST.get("payment_method")
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})
if not request.POST.get("accept_terms"):
messages.error(
request,
"You need to accept the general terms and conditions before you can continue!",
)
return self.render_to_response(
self.get_context_data(order_product_formset=formset)
)
# Set payment method and mark the order as closed
order.payment_method = payment_method
order.open = None
order.customer_comment = request.POST.get('customer_comment') or ''
order.invoice_address = request.POST.get('invoice_address') or ''
order.customer_comment = request.POST.get("customer_comment") or ""
order.invoice_address = request.POST.get("invoice_address") or ""
order.save()
reverses = {
Order.CREDIT_CARD: reverse_lazy(
'shop:epay_form',
kwargs={'pk': order.id}
"shop:epay_form", kwargs={"pk": order.id}
),
Order.BLOCKCHAIN: reverse_lazy(
'shop:coinify_pay',
kwargs={'pk': order.id}
"shop:coinify_pay", kwargs={"pk": order.id}
),
Order.BANK_TRANSFER: reverse_lazy(
'shop:bank_transfer',
kwargs={'pk': order.id}
"shop:bank_transfer", kwargs={"pk": order.id}
),
Order.CASH: reverse_lazy(
'shop:cash',
kwargs={'pk': order.id}
)
Order.CASH: reverse_lazy("shop:cash", kwargs={"pk": order.id}),
}
return HttpResponseRedirect(reverses[payment_method])
@ -400,12 +382,21 @@ class OrderDetailView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureOrderH
return super(OrderDetailView, self).get(request, *args, **kwargs)
class DownloadInvoiceView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsurePaidOrderMixin, EnsureOrderHasInvoicePDFMixin, SingleObjectMixin, View):
class DownloadInvoiceView(
LoginRequiredMixin,
EnsureUserOwnsOrderMixin,
EnsurePaidOrderMixin,
EnsureOrderHasInvoicePDFMixin,
SingleObjectMixin,
View,
):
model = Order
def get(self, request, *args, **kwargs):
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="%s"' % self.get_object().invoice.filename
response = HttpResponse(content_type="application/pdf")
response["Content-Disposition"] = (
'attachment; filename="%s"' % self.get_object().invoice.filename
)
response.write(self.get_object().invoice.pdf.read())
return response
@ -413,19 +404,27 @@ class DownloadInvoiceView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsurePa
class CreditNoteListView(LoginRequiredMixin, ListView):
model = CreditNote
template_name = "shop/creditnote_list.html"
context_object_name = 'creditnotes'
context_object_name = "creditnotes"
def get_queryset(self):
queryset = super().get_queryset()
return queryset.filter(user=self.request.user)
class DownloadCreditNoteView(LoginRequiredMixin, EnsureUserOwnsCreditNoteMixin, EnsureCreditNoteHasPDFMixin, SingleObjectMixin, View):
class DownloadCreditNoteView(
LoginRequiredMixin,
EnsureUserOwnsCreditNoteMixin,
EnsureCreditNoteHasPDFMixin,
SingleObjectMixin,
View,
):
model = CreditNote
def get(self, request, *args, **kwargs):
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="%s"' % self.get_object().filename
response = HttpResponse(content_type="application/pdf")
response["Content-Disposition"] = (
'attachment; filename="%s"' % self.get_object().filename
)
response.write(self.get_object().pdf.read())
return response
@ -436,31 +435,38 @@ class OrderMarkAsPaidView(LoginRequiredMixin, SingleObjectMixin, View):
def get(self, request, *args, **kwargs):
if not request.user.is_staff:
messages.error(request, 'You do not have permissions to do that.')
return HttpResponseRedirect(reverse_lazy('shop:index'))
messages.error(request, "You do not have permissions to do that.")
return HttpResponseRedirect(reverse_lazy("shop:index"))
else:
messages.success(request, 'The order has been marked as paid.')
messages.success(request, "The order has been marked as paid.")
order = self.get_object()
order.mark_as_paid()
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
return HttpResponseRedirect(request.META.get("HTTP_REFERER"))
# Epay views
class EpayFormView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUnpaidOrderMixin, EnsureClosedOrderMixin, EnsureOrderHasProductsMixin, DetailView):
class EpayFormView(
LoginRequiredMixin,
EnsureUserOwnsOrderMixin,
EnsureUnpaidOrderMixin,
EnsureClosedOrderMixin,
EnsureOrderHasProductsMixin,
DetailView,
):
model = Order
template_name = 'epay_form.html'
template_name = "epay_form.html"
def get_context_data(self, **kwargs):
order = self.get_object()
context = super(EpayFormView, self).get_context_data(**kwargs)
context['merchant_number'] = settings.EPAY_MERCHANT_NUMBER
context['description'] = order.description
context['amount'] = order.total * 100
context['order_id'] = order.pk
context['accept_url'] = order.get_epay_accept_url(self.request)
context['cancel_url'] = order.get_cancel_url(self.request)
context['callback_url'] = order.get_epay_callback_url(self.request)
context['epay_hash'] = calculate_epay_hash(order, self.request)
context["merchant_number"] = settings.EPAY_MERCHANT_NUMBER
context["description"] = order.description
context["amount"] = order.total * 100
context["order_id"] = order.pk
context["accept_url"] = order.get_epay_accept_url(self.request)
context["cancel_url"] = order.get_cancel_url(self.request)
context["callback_url"] = order.get_epay_callback_url(self.request)
context["epay_hash"] = calculate_epay_hash(order, self.request)
return context
@ -468,15 +474,13 @@ class EpayCallbackView(SingleObjectMixin, View):
model = Order
def get(self, request, *args, **kwargs):
callback = EpayCallback.objects.create(
payload=request.GET
)
callback = EpayCallback.objects.create(payload=request.GET)
if 'orderid' in request.GET:
if "orderid" in request.GET:
query = OrderedDict(
[tuple(x.split('=')) for x in request.META['QUERY_STRING'].split('&')]
[tuple(x.split("=")) for x in request.META["QUERY_STRING"].split("&")]
)
order = get_object_or_404(Order, pk=query.get('orderid'))
order = get_object_or_404(Order, pk=query.get("orderid"))
if order.pk != self.get_object().pk:
logger.error("bad epay callback, orders do not match!")
return HttpResponse(status=400)
@ -490,15 +494,13 @@ class EpayCallbackView(SingleObjectMixin, View):
if order.paid:
# this order is already paid, perhaps we are seeing a double callback?
return HttpResponse('OK')
return HttpResponse("OK")
# epay callback is valid - has the order been paid in full?
if int(query['amount']) == order.total * 100:
if int(query["amount"]) == order.total * 100:
# create an EpayPayment object linking the callback to the order
EpayPayment.objects.create(
order=order,
callback=callback,
txnid=query.get('txnid'),
order=order, callback=callback, txnid=query.get("txnid")
)
# and mark order as paid (this will create tickets)
order.mark_as_paid(request)
@ -507,53 +509,76 @@ class EpayCallbackView(SingleObjectMixin, View):
else:
return HttpResponse(status=400)
return HttpResponse('OK')
return HttpResponse("OK")
class EpayThanksView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureClosedOrderMixin, DetailView):
class EpayThanksView(
LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureClosedOrderMixin, DetailView
):
model = Order
template_name = 'epay_thanks.html'
template_name = "epay_thanks.html"
def dispatch(self, request, *args, **kwargs):
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})
reverse("shop:epay_thanks", kwargs={"pk": self.get_object().pk})
)
return super(EpayThanksView, self).dispatch(
request, *args, **kwargs
)
return super(EpayThanksView, self).dispatch(request, *args, **kwargs)
# Bank Transfer view
class BankTransferView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUnpaidOrderMixin, EnsureOrderHasProductsMixin, DetailView):
class BankTransferView(
LoginRequiredMixin,
EnsureUserOwnsOrderMixin,
EnsureUnpaidOrderMixin,
EnsureOrderHasProductsMixin,
DetailView,
):
model = Order
template_name = 'bank_transfer.html'
template_name = "bank_transfer.html"
def get_context_data(self, **kwargs):
context = super(BankTransferView, self).get_context_data(**kwargs)
context['iban'] = settings.BANKACCOUNT_IBAN
context['swiftbic'] = settings.BANKACCOUNT_SWIFTBIC
context['orderid'] = self.get_object().pk
context['regno'] = settings.BANKACCOUNT_REG
context['accountno'] = settings.BANKACCOUNT_ACCOUNT
context['total'] = self.get_object().total
context["iban"] = settings.BANKACCOUNT_IBAN
context["swiftbic"] = settings.BANKACCOUNT_SWIFTBIC
context["orderid"] = self.get_object().pk
context["regno"] = settings.BANKACCOUNT_REG
context["accountno"] = settings.BANKACCOUNT_ACCOUNT
context["total"] = self.get_object().total
return context
# Cash payment view
class CashView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUnpaidOrderMixin, EnsureOrderHasProductsMixin, DetailView):
class CashView(
LoginRequiredMixin,
EnsureUserOwnsOrderMixin,
EnsureUnpaidOrderMixin,
EnsureOrderHasProductsMixin,
DetailView,
):
model = Order
template_name = 'cash.html'
template_name = "cash.html"
# Coinify views
class CoinifyRedirectView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUnpaidOrderMixin, EnsureClosedOrderMixin, EnsureOrderHasProductsMixin, SingleObjectMixin, RedirectView):
class CoinifyRedirectView(
LoginRequiredMixin,
EnsureUserOwnsOrderMixin,
EnsureUnpaidOrderMixin,
EnsureClosedOrderMixin,
EnsureOrderHasProductsMixin,
SingleObjectMixin,
RedirectView,
):
model = Order
def dispatch(self, request, *args, **kwargs):
@ -563,17 +588,20 @@ class CoinifyRedirectView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUn
if not order.coinifyapiinvoice:
coinifyinvoice = create_coinify_invoice(order, request)
if not coinifyinvoice:
messages.error(request, "There was a problem with the payment provider. Please try again later")
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})
reverse_lazy(
"shop:order_detail", kwargs={"pk": self.get_object().pk}
)
)
return super(CoinifyRedirectView, self).dispatch(
request, *args, **kwargs
)
return super(CoinifyRedirectView, self).dispatch(request, *args, **kwargs)
def get_redirect_url(self, *args, **kwargs):
return self.get_object().coinifyapiinvoice.invoicejson['payment_url']
return self.get_object().coinifyapiinvoice.invoicejson["payment_url"]
class CoinifyCallbackView(SingleObjectMixin, View):
@ -590,34 +618,45 @@ class CoinifyCallbackView(SingleObjectMixin, View):
# do we have a json body?
if not callbackobject.payload:
# no, return an error
logger.error("unable to parse JSON body in callback for order %s" % callbackobject.order.id)
return HttpResponseBadRequest('unable to parse json')
logger.error(
"unable to parse JSON body in callback for order %s"
% callbackobject.order.id
)
return HttpResponseBadRequest("unable to parse json")
# initiate SDK
sdk = CoinifyCallback(settings.COINIFY_IPN_SECRET.encode('utf-8'))
sdk = CoinifyCallback(settings.COINIFY_IPN_SECRET.encode("utf-8"))
# attemt to validate the callbackc
if sdk.validate_callback(request.body, request.META['HTTP_X_COINIFY_CALLBACK_SIGNATURE']):
if sdk.validate_callback(
request.body, request.META["HTTP_X_COINIFY_CALLBACK_SIGNATURE"]
):
# mark callback as valid in db
callbackobject.valid = True
callbackobject.save()
else:
logger.error("invalid coinify callback detected")
return HttpResponseBadRequest('something is fucky')
return HttpResponseBadRequest("something is fucky")
if callbackobject.payload['event'] == 'invoice_state_change' or callbackobject.payload['event'] == 'invoice_manual_resend':
if (
callbackobject.payload["event"] == "invoice_state_change"
or callbackobject.payload["event"] == "invoice_manual_resend"
):
process_coinify_invoice_json(
invoicejson=callbackobject.payload['data'],
invoicejson=callbackobject.payload["data"],
order=self.get_object(),
request=request,
)
return HttpResponse('OK')
return HttpResponse("OK")
else:
logger.error("unsupported callback event %s" % callbackobject.payload['event'])
return HttpResponseBadRequest('unsupported event')
logger.error(
"unsupported callback event %s" % callbackobject.payload["event"]
)
return HttpResponseBadRequest("unsupported event")
class CoinifyThanksView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureClosedOrderMixin, DetailView):
class CoinifyThanksView(
LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureClosedOrderMixin, DetailView
):
model = Order
template_name = 'coinify_thanks.html'
template_name = "coinify_thanks.html"