views.py 5.6 KB
Newer Older
frekk's avatar
frekk committed
1
import uuid
frekk's avatar
frekk committed
2
from django.views.generic.base import RedirectView, View
3 4
from django.views.generic.detail import DetailView
from django.http import HttpResponse, HttpResponseRedirect, Http404
frekk's avatar
frekk committed
5
from django.core.exceptions import ObjectDoesNotExist
frekk's avatar
frekk committed
6 7
from django.contrib import messages
from django.conf import settings
frekk's avatar
frekk committed
8 9
from django.urls import reverse
from django.utils import timezone
frekk's avatar
frekk committed
10

frekk's avatar
frekk committed
11 12 13
from memberdb.views import MemberAccessMixin
from memberdb.models import Membership, MEMBERSHIP_TYPES

frekk's avatar
frekk committed
14 15
from .models import MembershipPayment, CardPayment
from . import payments
Felix von Perger's avatar
Felix von Perger committed
16
from .payments import try_capture_payment, log
frekk's avatar
frekk committed
17
from .dispense import get_item_price
frekk's avatar
frekk committed
18

frekk's avatar
frekk committed
19
class PaymentFormMixin:
frekk's avatar
frekk committed
20
    template_name = 'payment_form.html'
21
    context_object_name = 'payment'
frekk's avatar
frekk committed
22 23 24

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
frekk's avatar
frekk committed
25
        amount = "$%1.2f AUD" % (self.get_object().amount / 100.0)
frekk's avatar
frekk committed
26
        context.update({
frekk's avatar
frekk committed
27 28 29
            'app_id': payments.app_id,
            'loc_id': payments.loc_id,
            'amount': amount,
frekk's avatar
frekk committed
30 31 32
        })
        return context

frekk's avatar
frekk committed
33
    def payment_success(self, payment):
frekk's avatar
frekk committed
34 35
        payment.set_paid()
        messages.success(self.request, "Your payment of $%1.2f was successful." % (payment.amount / 100.0))
frekk's avatar
frekk committed
36

frekk's avatar
frekk committed
37
    def payment_error(self, payment):
frekk's avatar
frekk committed
38 39
        messages.error(self.request, "Your payment of $%1.2f was unsuccessful. Please try again later." % (payment.amount / 100.0))
        payment.delete()
frekk's avatar
frekk committed
40

frekk's avatar
frekk committed
41 42 43 44
    def post(self, request, *args, **kwargs):
        nonce = request.POST.get('nonce', None)
        card_payment = self.get_object()
        amount_aud = card_payment.amount / 100.0
frekk's avatar
frekk committed
45

frekk's avatar
frekk committed
46 47
        if (nonce is None or nonce == ""):
            messages.error(request, "Failed to collect card details. Please reload the page and submit again.")
48
            return self.get(request)
frekk's avatar
frekk committed
49

frekk's avatar
frekk committed
50
        if try_capture_payment(card_payment, nonce):
frekk's avatar
frekk committed
51
            self.payment_success(card_payment)
frekk's avatar
frekk committed
52
        else:
frekk's avatar
frekk committed
53
            self.payment_error(card_payment)
frekk's avatar
frekk committed
54

frekk's avatar
frekk committed
55 56 57
        # redirect to success URL, or redisplay the form with a success message if none is given
        return HttpResponseRedirect(self.get_completed_url())

frekk's avatar
frekk committed
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
class PaymentFormView(DetailView, PaymentFormMixin):
    """
    Handles the backend stuff for the Square payment form.
    See https://docs.connect.squareup.com/payments/sqpaymentform/setup
    Note: currently unused. see MembershipPaymentView
    """
    model = CardPayment
    slug_field = 'token'
    slug_url_kwarg = 'token'
    query_pk_and_slug = True

    def get_completed_url(self):
        return self.get_object().get_absolute_url()

class MembershipPaymentView(MemberAccessMixin, PaymentFormMixin, DetailView):
    """ displays the payment form appropriate for the given membership ID for the currently logged in member """

    def get_object(self):
        """ return the appropriate payment for the current membership, or None if no payment should be made """
        if self.request.member is None:
            raise Http404("no member record associated with current session")

        try:
            # find the membership record we are dealing with
            ms = Membership.objects.get(
                id = self.kwargs['pk'], # get the membership with the given ID
                member = self.request.member,
                date_paid__exact = None, # make sure membership itself is not marked as paid
            )

            # try to find a corresponding MembershipPayment record which has not been paid
            payment = MembershipPayment.objects.get(
                date_paid = None, # CardPayment.date_paid
                is_paid = False, # CardPayment.is_paid
                membership = ms, # MembershipPayment.membership
                membership__date_paid__exact = None, # MembershipPayment.membership.date_paid
            )
        except Membership.DoesNotExist as e:
            # no unpaid membership found, return
Felix von Perger's avatar
Felix von Perger committed
97
            log.warning("could not find unpaid membership with id %s" % self.kwargs['pk'])
frekk's avatar
frekk committed
98 99 100
            return None
        except MembershipPayment.DoesNotExist as e:
            # found an unpaid membership, but no payment record exists yet
Felix von Perger's avatar
Felix von Perger committed
101
            log.info("creating membership payment for membership id %s" % self.kwargs['pk'])
frekk's avatar
frekk committed
102 103
            return create_membership_payment(ms)
        return payment
frekk's avatar
frekk committed
104 105

    def dispatch(self, request, *args, **kwargs):
frekk's avatar
frekk committed
106
        self.request = request
frekk's avatar
frekk committed
107
        self.object = self.get_object()
frekk's avatar
frekk committed
108 109 110 111 112

        # don't produce the payment form if get_object() decides we don't have anything to do
        if (self.object is None):
            # the membership is already marked as paid and no CardPayment exists
            # so we add an error and redirect to member home
frekk's avatar
frekk committed
113 114 115 116 117 118 119 120 121 122 123 124 125 126
            messages.error(request, "Your membership is already paid. Check the cokelog (/home/other/coke/cokelog) for more details.")
            return HttpResponseRedirect(self.get_completed_url())
        else:
            return super().dispatch(request, *args, **kwargs)

    def payment_success(self, payment):
        ms = payment.membership
        ms.date_paid = timezone.now()
        ms.payment_method = 'online'
        ms.save()
        super().payment_success(payment)

    def get_completed_url(self):
        return reverse('memberdb:home')
frekk's avatar
frekk committed
127 128 129 130

def create_membership_payment(membership, commit=True):
    """ creates a MembershipPayment object for the given membership """
    # get the amount from dispense
Felix von Perger's avatar
Felix von Perger committed
131
    price = get_item_price(membership.get_dispense_item())
frekk's avatar
frekk committed
132 133
    if (price is None or price == 0):
        return None
Felix von Perger's avatar
Felix von Perger committed
134
    desc = membership.get_pretty_type()
frekk's avatar
frekk committed
135 136 137 138 139
    payment = MembershipPayment(description=desc, amount=price, membership=membership)

    if (commit):
        payment.save()
    return payment