Files @ d360e880d993
Branch filter:

Location: symposion_app/registripe/views.py

Sachi King
Flake8 fixes
from registripe import forms
from registripe import models

from django.core.exceptions import ValidationError
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import user_passes_test
from django.db import transaction
from django.http import Http404
from django.http import HttpResponse
from django.shortcuts import redirect, render

from registrasion.controllers.credit_note import CreditNoteController
from registrasion.controllers.invoice import InvoiceController

from pinax.stripe import actions

from stripe.error import StripeError

from symposion.conference.models import Conference

CURRENCY = settings.INVOICE_CURRENCY
CONFERENCE_ID = settings.CONFERENCE_ID


def _staff_only(user):
    ''' Returns true if the user is staff. '''
    return user.is_staff


def pubkey_script(request):
    ''' Returns a JS snippet that sets the Stripe public key for Stripe.js. '''

    script_template = "Stripe.setPublishableKey('%s');"
    script = script_template % settings.PINAX_STRIPE_PUBLIC_KEY

    return HttpResponse(script, content_type="text/javascript")


def card(request, invoice_id, access_code=None):
    ''' View that shows and processes a Stripe CreditCardForm to pay the given
    invoice. Redirects back to the invoice once the invoice is fully paid.

    Arguments:
        invoice_id (castable to str): The invoice id for the invoice to pay.
        access_code (str): The optional access code for the invoice (for
            unauthenticated payment)

    '''

    form = forms.CreditCardForm(request.POST or None)

    inv = InvoiceController.for_id_or_404(str(invoice_id))

    if not inv.can_view(user=request.user, access_code=access_code):
        raise Http404()

    args = [inv.invoice.id]
    if access_code:
        args.append(access_code)
    to_invoice = redirect("invoice", *args)

    if inv.invoice.balance_due() <= 0:
        return to_invoice

    if request.POST and form.is_valid():
        try:
            inv.validate_allowed_to_pay()
            process_card(request, form, inv)
            return to_invoice
        except StripeError as e:
            form.add_error(None, ValidationError(e))
        except ValidationError as ve:
            form.add_error(None, ve)

    data = {
        "invoice": inv.invoice,
        "form": form,
    }

    return render(
        request, "registrasion/stripe/credit_card_payment.html", data
    )


@transaction.atomic
def process_card(request, form, inv):
    ''' Processes the given credit card form

    Arguments:
        request: the current request context
        form: a CreditCardForm
        inv: an InvoiceController
    '''

    conference = Conference.objects.get(id=CONFERENCE_ID)
    amount_to_pay = inv.invoice.balance_due()
    user = inv.invoice.user
    token = form.cleaned_data["stripe_token"]

    customer = actions.customers.get_customer_for_user(user)

    if not customer:
        customer = actions.customers.create(user)

    card = actions.sources.create_card(customer, token)

    description = "Payment for %s invoice #%s" % (
        conference.title, inv.invoice.id
    )

    charge = actions.charges.create(
        amount_to_pay,
        customer,
        source=card,
        currency=CURRENCY,
        description=description,
        capture=True,
    )

    receipt = charge.stripe_charge.id
    reference = "Paid with Stripe reference: " + receipt

    # Create the payment object
    models.StripePayment.objects.create(
        invoice=inv.invoice,
        reference=reference,
        amount=charge.amount,
        charge=charge,
    )

    inv.update_status()

    messages.success(request, "This invoice was successfully paid.")


@user_passes_test(_staff_only)
def refund(request, credit_note_id):
    ''' Allows staff to select a Stripe charge for the owner of the credit
    note, and refund the credit note into stripe. '''

    cn = CreditNoteController.for_id_or_404(str(credit_note_id))

    to_credit_note = redirect("credit_note", cn.credit_note.id)

    if not cn.credit_note.is_unclaimed:
        return to_credit_note

    form = forms.StripeRefundForm(
        request.POST or None,
        user=cn.credit_note.invoice.user,
        min_value=cn.credit_note.value,
    )

    if request.POST and form.is_valid():
        try:
            process_refund(cn, form)
            return to_credit_note
        except StripeError as se:
            form.add_error(None, ValidationError(se))

    data = {
        "credit_note": cn.credit_note,
        "form": form,
    }

    return render(
        request, "registrasion/stripe/refund.html", data
    )


def process_refund(cn, form):
    payment = form.cleaned_data["payment"]
    charge = payment.charge

    to_refund = cn.credit_note.value
    stripe_charge_id = charge.stripe_charge.id

    # Test that the given charge is allowed to be refunded.
    max_refund = actions.charges.calculate_refund_amount(charge)

    if max_refund < to_refund:
        raise ValidationError(
            "You must select a payment holding greater value than "
            "the credit note."
        )

    refund = actions.refunds.create(charge, to_refund) # noqa

    models.StripeCreditNoteRefund.objects.create(
        parent=cn.credit_note,
        charge=charge,
        reference="Refunded %s to Stripe charge %s" % (
            to_refund, stripe_charge_id
        )
    )