Skip to content
This repository was archived by the owner on Jun 18, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions django-verdant/donations/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,27 @@
from donations.fields import CreditCardField, ExpiryDateField, VerificationValueField, EmptyValueAttrWidget


SINGLE = 's'
MONTHLY = 'm'
ANNUAL = 'a'

SUBSCRIPTION_CHOICES = (
(SINGLE, 'Single'),
(MONTHLY, 'Monthly'),
(ANNUAL, 'Annual'),
)


class DonationForm(forms.Form):
def __init__(self, *args, **kwargs):
show_subscription = kwargs.pop('show_subscription', False)
super(DonationForm, self).__init__(*args, **kwargs)
# the EmptyValueAttrWidget makes sure not to render the single use token on the page
self.fields['stripe_token'].widget = EmptyValueAttrWidget()
self.fields['name'].widget = forms.HiddenInput()
self.fields['name'].initial = "" # name on card is optional and set by javascript
if not show_subscription:
del self.fields['subscription']

required_css_class = 'required'

Expand All @@ -37,6 +51,8 @@ def __init__(self, *args, **kwargs):
email = forms.EmailField(required=True)
not_included_in_supporters_list = forms.BooleanField(label="Please tick this box if you do not wish to be included in our list of supporters", required=False, help_text="")

subscription = forms.ChoiceField(choices=SUBSCRIPTION_CHOICES, label="Please make my payment")

title = forms.CharField(required=True, max_length=255)
first_name = forms.CharField(required=True, max_length=255)
last_name = forms.CharField(required=True, max_length=255)
Expand Down Expand Up @@ -69,8 +85,9 @@ def __init__(self, *args, **kwargs):
# ("wendy_dagworthy_scholarship_fund", "Wendy Dagworthy Scholarship Fund"),
# ("in_memory_of_dorothy_kemp", "In memory of Dorothy Kemp"),
# ("college_greatest_need", "College’s greatest need"),
("rca_fund", "RCA Fund"),
), initial="rca_fund")
# ("rca_fund", "RCA Fund"),
("gen_rca", "GenerationRCA"),
), initial="gen_rca")

name = forms.CharField(required=False, max_length=255)
stripe_token = forms.CharField(required=False, max_length=255)
Expand Down
26 changes: 24 additions & 2 deletions django-verdant/donations/static/donations/js/donation.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,11 +162,33 @@ jQuery(function($) {
exp_year: $form.find('[data-stripe="exp-year"]').val(),
name: name
});
var newParams = {};

var ALLOWED_PARAMS = [
'number',
'exp_month',
'exp_year',
'name',
'address_line1',
'address_line2',
'address_city',
'address_state',
'address_zip',
'address_country',
];

// Filter out any values that are not used by Stripe API.
// https://stripe.com/docs/stripe-js/v2
$.each(params, function(key, value){
if ($.inArray(key, ALLOWED_PARAMS) !== -1) {
newParams[key] = value;
}
});

Stripe.createToken(params, stripeResponseHandler);
Stripe.createToken(newParams, stripeResponseHandler);
// Stripe.createToken($form[0], stripeResponseHandler);

// Prevent the form from submitting with the default action
return false;
});
});
});
2 changes: 2 additions & 0 deletions django-verdant/rca/help_text.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@
('rca.ContactUsPage', 'feed_image'): 'The image displayed in content feeds, such as the news carousel. Should be 16:9 ratio.',
('rca.DonationPage', 'payment_description'): 'This value will be stored along with each donation made on this page to help ditinguish them from donations on other pages.',
('rca.DonationPage', 'feed_image'): 'The image displayed in content feeds, such as the news carousel. Should be 16:9 ratio.',
('rca.DonationPage', 'annual_stripe_plan_id'): 'You need to fill this with the ID from the Stripe website.',
('rca.DonationPage', 'monthly_stripe_plan_id'): 'You need to fill this with the ID from the Stripe website.',
('rca.InnovationRCAProjectCreator', 'person'): "Choose an existing person's page, or enter a name manually below (which will not be linked).",
('rca.InnovationRCAProjectCreator', 'manual_person_name'): 'Only required if the creator has no page of their own to link to',
('rca.InnovationRCAProject', 'twitter_feed'): 'Replace the default Twitter feed by providing an alternative Twitter handle (without the @ symbol)',
Expand Down
25 changes: 25 additions & 0 deletions django-verdant/rca/migrations/0101_donationpage_stripe_plan_id.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.13 on 2018-11-20 19:53
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('rca', '0100_auto_20181024_1135'),
]

operations = [
migrations.AddField(
model_name='donationpage',
name='annual_stripe_plan_id',
field=models.CharField(blank=True, help_text=b'You need to fill this with the ID from the Stripe website.', max_length=255, verbose_name=b'annual Stripe plan ID'),
),
migrations.AddField(
model_name='donationpage',
name='monthly_stripe_plan_id',
field=models.CharField(blank=True, help_text=b'You need to fill this with the ID from the Stripe website.', max_length=255, verbose_name=b'monthly Stripe plan ID'),
),
]
63 changes: 48 additions & 15 deletions django-verdant/rca/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
from modelcluster.models import ClusterableModel
from taggit.models import TaggedItemBase, Tag

from donations.forms import DonationForm
from donations.forms import DonationForm, ANNUAL, MONTHLY, SINGLE
from donations.mail_admins import mail_exception, full_exc_info
import stripe

Expand Down Expand Up @@ -5754,6 +5754,8 @@ class OEFormPage(Page, SocialFields):
class DonationPage(Page, SocialFields):
redirect_to_when_done = models.ForeignKey(Page, null=True, blank=False, on_delete=models.PROTECT, related_name='+', help_text=help_text('rca.DonationPage', 'redirect_to_when_done'))
payment_description = models.CharField(max_length=255, blank=True, help_text=help_text('rca.DonationPage', 'payment_description', default="This value will be stored along with each donation made on this page to help ditinguish them from donations on other pages."))
monthly_stripe_plan_id = models.CharField(max_length=255, blank=True, verbose_name='monthly Stripe plan ID', help_text=help_text('rca.DonationPage', 'monthly_stripe_plan_id'))
annual_stripe_plan_id = models.CharField(max_length=255, blank=True, verbose_name='annual Stripe plan ID', help_text=help_text('rca.DonationPage', 'annual_stripe_plan_id'))

# fields copied from StandrdPage
intro = RichTextField(help_text=help_text('rca.DonationPage', 'intro'), blank=True)
Expand All @@ -5775,9 +5777,14 @@ class Meta:

def serve(self, request):
stripe.api_key = settings.STRIPE_SECRET_KEY
form_kwargs = {}
if self.monthly_stripe_plan_id and self.annual_stripe_plan_id:
form_kwargs.update({
'show_subscription': True,
})

if request.method == "POST":
form = DonationForm(request.POST)
form = DonationForm(request.POST, **form_kwargs)
if form.is_valid():
error_metadata = ""
try:
Expand All @@ -5788,19 +5795,43 @@ def serve(self, request):
card=form.cleaned_data.get('stripe_token'),
email=metadata.get("email", "")
)
if 'subscription' not in form.fields or form.cleaned_data.get('subscription') == SINGLE:
# When exporting the payments from the dashboard
# the metadata field is not exported but the description is,
# so we duplicate the metadata there as well.
charge = stripe.Charge.create(
customer=customer.id,
amount=form.cleaned_data.get('amount'), # amount in cents (converted by the form)
currency="usd",
description=self.payment_description,
metadata=metadata,
)
else:
if form.cleaned_data.get('subscription') == MONTHLY:
plan_id = self.monthly_stripe_plan_id
elif form.cleaned_data.get('subscription') == ANNUAL:
plan_id = self.annual_stripe_plan_id
else:
# This should not happen.
raise RuntimeError(
'Subscription selected but Stripe plan IDs '
'are not configured.'
)

subscription = stripe.Subscription.create(
customer=customer.id,
items=[
{
'plan': plan_id,
# Make sure price of plan is a cent per
# unit.
'quantity': form.cleaned_data.get('amount'),
},
],
)

# When exporting the payments from the dashboard
# the metadata field is not exported but the description is,
# so we duplicate the metadata there as well.
charge = stripe.Charge.create(
customer=customer.id,
amount=form.cleaned_data.get('amount'), # amount in cents (converted by the form)
currency="usd",
description=self.payment_description,
metadata=metadata,
)
return HttpResponseRedirect(self.redirect_to_when_done.url)
except stripe.CardError, e:
except stripe.error.CardError, e:
# CardErrors are displayed to the user, but we notify admins as well
mail_exception(e, prefix=" [stripe] ", message=error_metadata)
logging.error("[stripe] " + error_metadata, exc_info=full_exc_info())
Expand All @@ -5813,8 +5844,8 @@ def serve(self, request):
messages.error(request, "There was a problem processing your payment. Please try again later.")
else:
towards = request.GET.get('to')
form = DonationForm(initial={'donation_for': towards})
form = DonationForm()
form = DonationForm(initial={'donation_for': towards}, **form_kwargs)
form = DonationForm(**form_kwargs)

return render(request, self.template, {
'self': self,
Expand All @@ -5831,6 +5862,8 @@ def serve(self, request):
MultiFieldPanel([
FieldPanel('payment_description', classname="full"),
PageChooserPanel('redirect_to_when_done'),
FieldPanel('annual_stripe_plan_id'),
FieldPanel('monthly_stripe_plan_id'),
], "Donation details")
# InlinePanel('carousel_items', label="Carousel content"),
# InlinePanel('related_links', label="Related links"),
Expand Down
5 changes: 4 additions & 1 deletion django-verdant/rca/templates/rca/donation_page.html
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ <h1 class="h1">{{ self.title }}</h1>
<ul>
{% with form.amounts as field %}{% include "rca/includes/field_as_li.html" %}{% endwith %}
{% with form.amount as field %}{% include "rca/includes/field_as_li.html" %}{% endwith %}
{% if form.subscription %}
{% with form.subscription as field %}{% include "rca/includes/field_as_li.html" %}{% endwith %}
{% endif %}

{% with form.donation_for as field %}{% include "rca/includes/field_as_li.html" %}{% endwith %}

Expand Down Expand Up @@ -131,4 +134,4 @@ <h4>Data Protection</h4>

{% block sidebar %}
{% include "rca/includes/sidebar.html" with showToday="true" showRelatedLinks="true" showAdverts="true" %}
{% endblock %}
{% endblock %}
2 changes: 1 addition & 1 deletion django-verdant/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ django-auth-ldap==1.2.6
Embedly==0.5.0
elasticsearch==1.4.0
psycopg2==2.7.4
stripe==1.9.8
stripe==2.12
tweepy==2.1
django-redis==4.3.0
django-widget-tweaks==1.3
Expand Down