Skip to content
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
2 changes: 1 addition & 1 deletion paypal/standard/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class PayPalSettingsError(Exception):
SANDBOX_POSTBACK_ENDPOINT = "https://www.sandbox.paypal.com/cgi-bin/webscr"

# Images
IMAGE = getattr(settings, "PAYPAL_IMAGE", "http://images.paypal.com/images/x-click-but01.gif")
IMAGE = getattr(settings, "PAYPAL_IMAGE", "https://images.paypal.com/images/x-click-but01.gif")
SUBSCRIPTION_IMAGE = getattr(settings, "PAYPAL_SUBSCRIPTION_IMAGE", "https://www.paypal.com/en_US/i/btn/btn_subscribeCC_LG.gif")
DONATION_IMAGE = getattr(settings, "PAYPAL_DONATION_IMAGE", "https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif")
SANDBOX_IMAGE = getattr(settings, "PAYPAL_SANDBOX_IMAGE", "https://www.sandbox.paypal.com/en_US/i/btn/btn_buynowCC_LG.gif")
Expand Down
9 changes: 9 additions & 0 deletions paypal/standard/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ def __init__(self, button_type="buy", *args, **kwargs):
super(PayPalPaymentsForm, self).__init__(*args, **kwargs)
self.button_type = button_type

def smart_render(self):
"""Render for PayPal if not PAYPAL_DEBUG, for PayPay Sandbox if PAYPAL_DEBUG."""
return self.render() if not settings.PAYPAL_DEBUG else self.sandbox()

def render(self):
return mark_safe(u"""<form action="%s" method="post">
%s
Expand Down Expand Up @@ -217,3 +221,8 @@ class PayPalStandardBaseForm(forms.ModelForm):
next_payment_date = forms.DateTimeField(required=False, input_formats=PAYPAL_DATE_FORMAT)
subscr_date = forms.DateTimeField(required=False, input_formats=PAYPAL_DATE_FORMAT)
subscr_effective = forms.DateTimeField(required=False, input_formats=PAYPAL_DATE_FORMAT)
auction_closing_date = forms.DateTimeField(required=False, input_formats=PAYPAL_DATE_FORMAT)
case_creation_date = forms.DateTimeField(required=False, input_formats=PAYPAL_DATE_FORMAT)
# format not documented by PayPal, but empirically consistent
retry_at = forms.DateTimeField(required=False, input_formats=PAYPAL_DATE_FORMAT)

4 changes: 2 additions & 2 deletions paypal/standard/ipn/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class PayPalIPNAdmin(admin.ModelAdmin):
"__unicode__", "flag", "flag_info", "invoice", "custom",
"payment_status", "created_at"
]
search_fields = ["txn_id", "recurring_payment_id"]
search_fields = ["txn_id", "recurring_payment_id", "subscr_id"]


admin.site.register(PayPalIPN, PayPalIPNAdmin)
admin.site.register(PayPalIPN, PayPalIPNAdmin)
6 changes: 4 additions & 2 deletions paypal/standard/ipn/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def send_signals(self):
recurring_skipped.send(sender=self)
elif self.is_recurring_failed():
recurring_failed.send(sender=self)
# Subscription signals:
# Subscription signals:
else:
if self.is_subscription_cancellation():
subscription_cancel.send(sender=self)
Expand All @@ -51,4 +51,6 @@ def send_signals(self):
elif self.is_subscription_end_of_term():
subscription_eot.send(sender=self)
elif self.is_subscription_modified():
subscription_modify.send(sender=self)
subscription_modify.send(sender=self)
elif self.is_subscription_failed():
subscription_failed.send(sender=self)
5 changes: 4 additions & 1 deletion paypal/standard/ipn/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
# Sent when a subscription is created.
subscription_signup = Signal()

# Sent when a subscription's payment fails
subscription_failed = Signal()

# recurring_payment_profile_created
recurring_create = Signal()

Expand All @@ -34,4 +37,4 @@

recurring_skipped = Signal()

recurring_failed = Signal()
recurring_failed = Signal()
3 changes: 3 additions & 0 deletions paypal/standard/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@ def is_subscription_modified(self):
def is_subscription_signup(self):
return self.txn_type == "subscr_signup"

def is_subscription_failed(self):
return self.txn_type == "subscr_failed"

def is_recurring_create(self):
return self.txn_type == "recurring_payment_profile_created"

Expand Down
64 changes: 64 additions & 0 deletions paypal/standard/nvp/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Partial implementation of the NameValuePair interface of PayPal

# currently allows:
# * change status of subscription/recurring payment

import urllib
import urllib2
import urlparse

from django.conf import settings

base_params = {
'USER': settings.PAYPAL_API_USERNAME,
'PWD': settings.PAYPAL_API_PASSWORD,
'SIGNATURE': settings.PAYPAL_API_SIGNATURE,
'VERSION': '60.0'
}



class PayPalResponse:
def __init__(self, raw_data):
self.raw = raw_data
self.parse()

def parse(self):
self.params = urlparse.parse_qs(self.raw)


class RecurringSubscription:
def __init__(self, profileid):
self.profileid = profileid

def __unicode__(self):
return str(self.profileid)

def __str__(self):
return self.__unicode__()

def updateStatus(self, new_status):
"""Update the status of the recurring payment profile.

new_status is in { Cancel, Suspend, Reactivate }."""

if new_status not in ('Cancel', 'Suspend', 'Reactivate'):
raise ValueError("Invalid value '%s' for new_status. Must be in Cancel, Suspend, Reactivate." % new_status)

pars = {
'METHOD': 'ManageRecurringPaymentsProfileStatus',
'PROFILEID': self.profileid,
'ACTION': new_status
}

ok, params = self.issue_cmd(pars)
return ok

def issue_cmd(self, parameters):
parameters = dict(base_params.items() + parameters.items())
data = urllib.urlencode(parameters)
req = urllib2.Request(settings.PAYPAL_API_NVP_ENDPOINT, data, {})
resp = urllib2.urlopen(req).read()
resp_params = urlparse.parse_qs(resp)
return all([x.lower() == 'success' for x in resp_params['ACK']]), resp_params