Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
  • 5 commits
  • 4 files changed
  • 0 commit comments
  • 1 contributor
View
27 armstrong/apps/donations/forms.py
@@ -15,6 +15,12 @@
class BaseDonationForm(forms.Form):
+ """
+ Provides the basic fields common to all donation forms
+
+ This is meant to be overridden by the forms returned by a
+ ``Backend.get_form_class`` to provide specific implementations.
+ """
first_name = forms.CharField()
last_name = forms.CharField()
amount = forms.DecimalField(decimal_places=2)
@@ -117,6 +123,12 @@ def save(self, **kwargs):
class StripSensitiveFields(object):
+ """
+ Mixin for stripping sensitive information from an invalid form
+
+ This is meant to be used by a ``Form`` object and strips the fields
+ listed in ``fields_to_strip`` if ``is_valid`` fails.
+ """
fields_to_strip = []
def is_valid(self, *args, **kwargs):
@@ -148,11 +160,24 @@ class CreditCardDonationForm(StripSensitiveFields, BaseDonationForm):
fields_to_strip = ["card_number", "ccv_code", ]
def get_data_for_charge(self, donation, **kwargs):
+ """
+ Returns the data for charges
+
+ This is used to build a dictionary of data that can not be
+ retrieved directly from the ``Donation`` model.
+ """
raise NotImplementedError
class AuthorizeDonationForm(CreditCardDonationForm):
+ """
+ Represents a ``CreditCardDonationForm`` form for Authorize.net
+
+ This form is returned by the ``AuthorizeNetBackend.get_form_class``
+ and should not be accessed directly.
+ """
def get_data_for_charge(self, donation, recurring=False):
+ """Returns the data for charges"""
self.is_valid()
card_number = "card_num" if not recurring else "card_number"
data = {
@@ -172,12 +197,14 @@ def get_data_for_charge(self, donation, recurring=False):
class DonorForm(forms.ModelForm):
+ """Simple ``ModelForm`` for the ``Donor`` model"""
class Meta:
model = models.Donor
excludes = ("address", "mailing_address", )
class DonorAddressForm(forms.ModelForm):
+ """Simple ``ModelForm`` for the ``DonorAddress`` model"""
address = forms.CharField(widget=forms.Textarea)
class Meta:
View
19 armstrong/apps/donations/models.py
@@ -6,9 +6,7 @@
class DonorAddress(models.Model):
- """
- Address associated with a ``Donor``
- """
+ """Address associated with a ``Donor``"""
address = models.CharField(max_length=255)
city = models.CharField(max_length=20)
state = us.USStateField()
@@ -19,6 +17,12 @@ def __unicode__(self):
class Donor(models.Model):
+ """
+ Represents a ``Donor`` associated with a ``Donation``
+
+ This may or may not have an associated ``User`` with it, but
+ should have one or more ``Donation`` associated with it.
+ """
user = models.ForeignKey(User, blank=True, null=True)
first_name = models.CharField(max_length=250)
last_name = models.CharField(max_length=250)
@@ -43,6 +47,12 @@ def __unicode__(self):
class DonationType(models.Model):
+ """
+ Provides a mechanism for creating types of donations
+
+ Each ``DonationType`` has one or more ``DonationTypeOption`` which
+ contains the actual data (amount, length, number of repeats, and so on).
+ """
name = models.CharField(
max_length=100, help_text=_(u"Name of Donation Type")
)
@@ -52,6 +62,7 @@ def __unicode__(self):
class DonationTypeOption(models.Model):
+ """Provides specifics for a particular option of a ``DonationType``"""
donation_type = models.ForeignKey(DonationType, related_name="options")
amount = models.PositiveIntegerField(help_text=_(u"Amount to donate"))
length = models.PositiveIntegerField(default=1,
@@ -76,6 +87,7 @@ def __unicode__(self):
class PromoCode(models.Model):
+ """Codes that can be applied to a ``Donation`` to adjust its amount"""
code = models.CharField(max_length=20, unique=True)
amount = models.FloatField(
help_text=_("Percent discount: 0 is no discount, 100 if free")
@@ -90,6 +102,7 @@ def calculate(self, donation):
class Donation(models.Model):
+ """Model representing the actual donation"""
donor = models.ForeignKey(Donor)
donation_type = models.ForeignKey(DonationTypeOption, null=True,
blank=True)
View
45 armstrong/apps/donations/tests/views.py
@@ -8,7 +8,6 @@
import fudge
import os
import random
-from unittest import expectedFailure
from ._utils import TestCase
@@ -204,6 +203,50 @@ def test_form_is_valid_passes_kwargs_to_get_context_data(self):
fudge.verify()
+ def test_form_is_valid_passes_kwargs_to_purchase_failed(self):
+ donation, donation_form = self.random_donation_and_form
+ r = lambda: random.randint(100, 200)
+ random_kwargs = {
+ "slug%d" % r(): "foo-%d" % r(),
+ }
+
+ view = self.post_view
+ view.confirm = False
+ backends = self.get_backend_stub(successful=False)
+ backend_response = backends.get_backend().purchase()
+
+ purchase_failed = fudge.Fake()
+ purchase_failed.expects_call().with_args(backend_response,
+ **random_kwargs)
+
+ with fudge.patched_context(views, "backends", backends):
+ with fudge.patched_context(view, "purchase_failed",
+ purchase_failed):
+ view.form_is_valid(donation_form, **random_kwargs)
+
+ fudge.verify()
+
+ def test_purchase_failed_passes_kwargs_to_get_context_data(self):
+ backend_response = {
+ "reason": "Some Random Reason",
+ "response": "Some Random Response",
+ }
+ r = lambda: random.randint(100, 200)
+ random_kwargs = {
+ "slug%d" % r(): "foo-%d" % r(),
+ }
+
+ get_context_data = fudge.Fake()
+ (get_context_data.expects_call()
+ .with_args(**random_kwargs)
+ .returns({}))
+
+ view = self.post_view
+ with fudge.patched_context(view, "get_context_data", get_context_data):
+ view.purchase_failed(backend_response, **random_kwargs)
+
+ fudge.verify()
+
def form_is_valid_response(confirmed=False):
def outer(func):
View
10 armstrong/apps/donations/views.py
@@ -107,14 +107,14 @@ def form_is_valid(self, donation_form, **kwargs):
donation = donation_form.save()
response = backends.get_backend().purchase(donation, donation_form)
if not response["status"]:
- return self.purchase_failed(response)
+ return self.purchase_failed(response, **kwargs)
return HttpResponseRedirect(self.success_url)
- def purchase_failed(self, backend_response):
- context = {
+ def purchase_failed(self, backend_response, **kwargs):
+ context = self.get_context_data(**kwargs)
+ context.update({
"error_msg": "Unable to process payment",
"reason": backend_response["reason"],
"response": backend_response["response"],
- }
- context.update(self.get_context_data())
+ })
return self.render_to_response(context)

No commit comments for this range

Something went wrong with that request. Please try again.