Files @ d360e880d993
Branch filter:

Location: symposion_app/registripe/views.py - annotation

Sachi King
Flake8 fixes
9719546bdaba
9719546bdaba
f932841cda09
8334d40fe931
8334d40fe931
8334d40fe931
abee9e3c6231
8334d40fe931
2d434432d90a
8334d40fe931
8334d40fe931
8334d40fe931
abee9e3c6231
8334d40fe931
8334d40fe931
8334d40fe931
abee9e3c6231
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
fd5754e679b3
6c87b9d08a2d
6c87b9d08a2d
6c87b9d08a2d
6c87b9d08a2d
6c87b9d08a2d
fd5754e679b3
fd5754e679b3
6c87b9d08a2d
6c87b9d08a2d
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
fd5754e679b3
8334d40fe931
8334d40fe931
7a7aa9587464
7a7aa9587464
7a7aa9587464
7a7aa9587464
8334d40fe931
6c87b9d08a2d
6c87b9d08a2d
6c87b9d08a2d
8334d40fe931
8334d40fe931
d360e880d993
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
fd5754e679b3
8334d40fe931
8334d40fe931
fd5754e679b3
8334d40fe931
8334d40fe931
fd5754e679b3
8334d40fe931
8334d40fe931
8334d40fe931
d360e880d993
8334d40fe931
8334d40fe931
8334d40fe931
26b249d48d94
26b249d48d94
26b249d48d94
4ba7f630e001
26b249d48d94
26b249d48d94
26b249d48d94
26b249d48d94
26b249d48d94
fd5754e679b3
fd5754e679b3
26b249d48d94
26b249d48d94
26b249d48d94
26b249d48d94
26b249d48d94
26b249d48d94
26b249d48d94
26b249d48d94
8334d40fe931
8334d40fe931
8334d40fe931
8334d40fe931
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
d360e880d993
abee9e3c6231
fd5754e679b3
abee9e3c6231
fd5754e679b3
abee9e3c6231
abee9e3c6231
abee9e3c6231
abee9e3c6231
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
        )
    )